QTfrontend/ui/page/pagefeedback.cpp
branchwebgl
changeset 8444 75db7bb8dce8
parent 8340 46a9fde631f4
parent 8443 2debc9b9f917
child 8446 c18ba8726f5a
equal deleted inserted replaced
8340:46a9fde631f4 8444:75db7bb8dce8
     1 /*
       
     2  * Hedgewars, a free turn based strategy game
       
     3  * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License as published by
       
     7  * the Free Software Foundation; version 2 of the License
       
     8  *
       
     9  * This program is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12  * GNU General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU General Public License
       
    15  * along with this program; if not, write to the Free Software
       
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
       
    17  */
       
    18 
       
    19 #include <QHBoxLayout>
       
    20 #include <QLineEdit>
       
    21 #include <QTextBrowser>
       
    22 #include <QLabel>
       
    23 #include <QHttp>
       
    24 #include <QSysInfo>
       
    25 #include <QDebug>
       
    26 #include <QBuffer>
       
    27 #include <QApplication>
       
    28 #include <QDesktopWidget>
       
    29 #include <QNetworkReply>
       
    30 #include <QProcess>
       
    31 #include <QMessageBox>
       
    32 #include <QCheckBox>
       
    33 
       
    34 #include <string>
       
    35 
       
    36 #ifdef Q_WS_WIN
       
    37 #define WINVER 0x0500
       
    38 #include <windows.h>
       
    39 #else
       
    40 #include <unistd.h>
       
    41 #include <sys/types.h>
       
    42 #endif
       
    43 
       
    44 #ifdef Q_WS_MAC
       
    45 #include <sys/sysctl.h>
       
    46 #endif
       
    47 
       
    48 #include <stdint.h>
       
    49 
       
    50 #include "pagefeedback.h"
       
    51 #include "hwconsts.h"
       
    52 
       
    53 QLayout * PageFeedback::bodyLayoutDefinition()
       
    54 {
       
    55     QVBoxLayout * pageLayout = new QVBoxLayout();
       
    56     QHBoxLayout * summaryLayout = new QHBoxLayout();
       
    57     QHBoxLayout * emailLayout = new QHBoxLayout();
       
    58     QHBoxLayout * descriptionLayout = new QHBoxLayout();
       
    59     QHBoxLayout * combinedTopLayout = new QHBoxLayout();
       
    60     QHBoxLayout * systemLayout = new QHBoxLayout();
       
    61 
       
    62     info = new QLabel();
       
    63     info->setText(
       
    64         "<style type=\"text/css\">"
       
    65         "a { color: #fc0; }"
       
    66         "b { color: #0df; }"
       
    67         "</style>"
       
    68         "<div align=\"center\"><h1>Please give us feedback!</h1>"
       
    69         "<h3>We are always happy about suggestions, ideas, or bug reports.<h3>"
       
    70         "<h4>Your email address is optional, but we may want to contact you.<h4>"
       
    71         "</div>"
       
    72     );
       
    73     pageLayout->addWidget(info);
       
    74 
       
    75     QVBoxLayout * summaryEmailLayout = new QVBoxLayout();
       
    76 
       
    77     const int labelWidth = 90;
       
    78 
       
    79     label_email = new QLabel();
       
    80     label_email->setText(QLabel::tr("Your Email"));
       
    81     label_email->setFixedWidth(labelWidth);
       
    82     emailLayout->addWidget(label_email);
       
    83     email = new QLineEdit();
       
    84     emailLayout->addWidget(email);
       
    85     summaryEmailLayout->addLayout(emailLayout);
       
    86 
       
    87     label_summary = new QLabel();
       
    88     label_summary->setText(QLabel::tr("Summary"));
       
    89     label_summary->setFixedWidth(labelWidth);
       
    90     summaryLayout->addWidget(label_summary);
       
    91     summary = new QLineEdit();
       
    92     summaryLayout->addWidget(summary);
       
    93     summaryEmailLayout->addLayout(summaryLayout);
       
    94 
       
    95     combinedTopLayout->addLayout(summaryEmailLayout);
       
    96 
       
    97 
       
    98     CheckSendSpecs = new QCheckBox();
       
    99     CheckSendSpecs->setText(QLabel::tr("Send system information"));
       
   100     CheckSendSpecs->setChecked(true);
       
   101     systemLayout->addWidget(CheckSendSpecs);
       
   102     BtnViewInfo = addButton("View", systemLayout, 1, false);
       
   103     BtnViewInfo->setFixedSize(60, 30);
       
   104     connect(BtnViewInfo, SIGNAL(clicked()), this, SLOT(ShowSpecs()));
       
   105     combinedTopLayout->addLayout(systemLayout);
       
   106 
       
   107     combinedTopLayout->setStretch(0, 1);
       
   108     combinedTopLayout->insertSpacing(1, 20);
       
   109 
       
   110     pageLayout->addLayout(combinedTopLayout);
       
   111 
       
   112     label_description = new QLabel();
       
   113     label_description->setText(QLabel::tr("Description"));
       
   114     label_description->setFixedWidth(labelWidth);
       
   115     descriptionLayout->addWidget(label_description, 0, Qt::AlignTop);
       
   116     description = new QTextBrowser();
       
   117     description->setReadOnly(false);
       
   118     descriptionLayout->addWidget(description);
       
   119     pageLayout->addLayout(descriptionLayout);
       
   120 
       
   121     return pageLayout;
       
   122 }
       
   123 
       
   124 QNetworkAccessManager * PageFeedback::GetNetManager()
       
   125 {
       
   126     if (netManager) return netManager;
       
   127     netManager = new QNetworkAccessManager(this);
       
   128     connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(NetReply(QNetworkReply*)));
       
   129     return netManager;
       
   130 }
       
   131 
       
   132 void PageFeedback::LoadCaptchaImage()
       
   133 {
       
   134         QNetworkAccessManager *netManager = GetNetManager();
       
   135         QUrl captchaURL("http://hedgewars.org/feedback/?gencaptcha");
       
   136         QNetworkRequest req(captchaURL);
       
   137         genCaptchaRequest = netManager->get(req);
       
   138 }
       
   139 
       
   140 void PageFeedback::NetReply(QNetworkReply *reply)
       
   141 {
       
   142     if (reply == genCaptchaRequest)
       
   143     {
       
   144         if (reply->error() != QNetworkReply::NoError)
       
   145         {
       
   146             qDebug() << "Error generating captcha image: " << reply->errorString();
       
   147             ShowErrorMessage(QMessageBox::tr("Failed to generate captcha"));
       
   148             return;
       
   149         }
       
   150 
       
   151         bool okay;
       
   152         QByteArray body = reply->readAll();
       
   153         captchaID = QString(body).toInt(&okay);
       
   154 
       
   155         if (!okay)
       
   156         {
       
   157             qDebug() << "Failed to get captcha ID: " << body;
       
   158             ShowErrorMessage(QMessageBox::tr("Failed to generate captcha"));
       
   159             return;
       
   160         }
       
   161 
       
   162         QString url = "http://hedgewars.org/feedback/?captcha&id=";
       
   163         url += QString::number(captchaID);
       
   164 
       
   165         QNetworkAccessManager *netManager = GetNetManager();
       
   166         QUrl captchaURL(url);
       
   167         QNetworkRequest req(captchaURL);
       
   168         captchaImageRequest = netManager->get(req);
       
   169     }
       
   170     else if (reply == captchaImageRequest)
       
   171     {
       
   172         if (reply->error() != QNetworkReply::NoError)
       
   173         {
       
   174             qDebug() << "Error loading captcha image: " << reply->errorString();
       
   175             ShowErrorMessage(QMessageBox::tr("Failed to download captcha"));
       
   176             return;
       
   177         }
       
   178 
       
   179         QByteArray imageData = reply->readAll();
       
   180         QPixmap pixmap;
       
   181         pixmap.loadFromData(imageData);
       
   182         label_captcha->setPixmap(pixmap);
       
   183         captcha_code->setText("");
       
   184     }
       
   185 }
       
   186 
       
   187 QLayout * PageFeedback::footerLayoutDefinition()
       
   188 {
       
   189     QHBoxLayout * bottomLayout = new QHBoxLayout();
       
   190     QHBoxLayout * captchaLayout = new QHBoxLayout();
       
   191     QVBoxLayout * captchaInputLayout = new QVBoxLayout();
       
   192 
       
   193     label_captcha = new QLabel();
       
   194     label_captcha->setStyleSheet("border: 3px solid #ffcc00; border-radius: 4px");
       
   195     label_captcha->setText("<div style='width: 200px; height: 100px;'>loading<br>captcha</div>");
       
   196     captchaLayout->addWidget(label_captcha);
       
   197 
       
   198     label_captcha_input = new QLabel();
       
   199     label_captcha_input->setText(QLabel::tr("Type the security code:"));
       
   200     captchaInputLayout->addWidget(label_captcha_input);
       
   201     captchaInputLayout->setAlignment(label_captcha, Qt::AlignBottom);
       
   202     captcha_code = new QLineEdit();
       
   203     captcha_code->setFixedSize(165, 30);
       
   204     captchaInputLayout->addWidget(captcha_code);
       
   205     captchaInputLayout->setAlignment(captcha_code, Qt::AlignTop);
       
   206     captchaLayout->addLayout(captchaInputLayout);
       
   207     captchaLayout->setAlignment(captchaInputLayout, Qt::AlignLeft);
       
   208 
       
   209     captchaLayout->insertSpacing(-1, 40);
       
   210     bottomLayout->addLayout(captchaLayout);
       
   211 
       
   212     //TODO: create logo for send button
       
   213     BtnSend = addButton("Send Feedback", bottomLayout, 0, false);
       
   214     BtnSend->setFixedSize(120, 40);
       
   215 
       
   216     bottomLayout->setStretchFactor(captchaLayout, 0);
       
   217     bottomLayout->setStretchFactor(BtnSend, 1);
       
   218 
       
   219     return bottomLayout;
       
   220 }
       
   221 
       
   222 void PageFeedback::GenerateSpecs()
       
   223 {
       
   224     // Gather some information about the system and embed it into the report
       
   225     QDesktopWidget* screen = QApplication::desktop();
       
   226     QString os_version = "Operating system: ";
       
   227     QString qt_version = QString("Qt version: ") + QT_VERSION_STR + QString("\n");
       
   228     QString total_ram = "Total RAM: ";
       
   229     QString number_of_cores = "Number of cores: ";
       
   230     QString compiler_bits = "Compiler architecture: ";
       
   231     QString compiler_version = "Compiler version: ";
       
   232     QString kernel_line = "Kernel: ";
       
   233     QString screen_size = "Size of the screen(s): " +
       
   234         QString::number(screen->width()) + "x" + QString::number(screen->height()) + "\n";
       
   235     QString number_of_screens = "Number of screens: " + QString::number(screen->screenCount()) + "\n";
       
   236     std::string processor_name = "Processor: ";
       
   237 
       
   238     // platform specific code
       
   239 #ifdef Q_WS_MACX
       
   240     number_of_cores += QString::number(sysconf(_SC_NPROCESSORS_ONLN)) + "\n";
       
   241 
       
   242     uint64_t memsize;
       
   243     size_t len = sizeof(memsize);
       
   244     static int mib_s[2] = { CTL_HW, HW_MEMSIZE };
       
   245     if (sysctl (mib_s, 2, &memsize, &len, NULL, 0) == 0)
       
   246         total_ram += QString::number(memsize/1024/1024) + " MB\n";
       
   247     else
       
   248         total_ram += "Error getting total RAM information\n";
       
   249 
       
   250     int mib[] = {CTL_KERN, KERN_OSRELEASE};
       
   251     sysctl(mib, sizeof mib / sizeof(int), NULL, &len, NULL, 0);
       
   252 
       
   253     char *kernelVersion = (char *)malloc(sizeof(char)*len);
       
   254     sysctl(mib, sizeof mib / sizeof(int), kernelVersion, &len, NULL, 0);
       
   255 
       
   256     QString kernelVersionStr = QString(kernelVersion);
       
   257     free(kernelVersion);
       
   258     int major_version = kernelVersionStr.split(".").first().toUInt() - 4;
       
   259     int minor_version = kernelVersionStr.split(".").at(1).toUInt();
       
   260     os_version += QString("Mac OS X 10.%1.%2").arg(major_version).arg(minor_version) + " ";
       
   261 
       
   262     switch(major_version)
       
   263     {
       
   264         case 4:  os_version += "\"Tiger\"\n"; break;
       
   265         case 5:  os_version += "\"Leopard\"\n"; break;
       
   266         case 6:  os_version += "\"Snow Leopard\"\n"; break;
       
   267         case 7:  os_version += "\"Lion\"\n"; break;
       
   268         case 8:  os_version += "\"Mountain Lion\"\n"; break;
       
   269         default: os_version += "\"Unknown version\"\n"; break;
       
   270     }
       
   271 #endif
       
   272 #ifdef Q_WS_WIN
       
   273     SYSTEM_INFO sysinfo;
       
   274     GetSystemInfo(&sysinfo);
       
   275     number_of_cores += QString::number(sysinfo.dwNumberOfProcessors) + "\n";
       
   276     MEMORYSTATUSEX status;
       
   277     status.dwLength = sizeof(status);
       
   278     GlobalMemoryStatusEx(&status);
       
   279     total_ram += QString::number(status.ullTotalPhys);
       
   280 
       
   281     switch(QSysInfo::WinVersion())
       
   282     {
       
   283         case QSysInfo::WV_2000: os_version += "Windows 2000\n"; break;
       
   284         case QSysInfo::WV_XP: os_version += "Windows XP\n"; break;
       
   285         case QSysInfo::WV_VISTA: os_version += "Windows Vista\n"; break;
       
   286         case QSysInfo::WV_WINDOWS7: os_version += "Windows 7\n"; break;
       
   287         default: os_version += "Windows (Unknown version)\n"; break;
       
   288     }
       
   289     kernel_line += "Windows kernel\n";
       
   290 #endif
       
   291 #ifdef Q_WS_X11
       
   292     number_of_cores += QString::number(sysconf(_SC_NPROCESSORS_ONLN)) + "\n";
       
   293     long pages = sysconf(_SC_PHYS_PAGES),
       
   294 #ifndef Q_OS_FREEBSD
       
   295          available_pages = sysconf(_SC_AVPHYS_PAGES),
       
   296 #else
       
   297          available_pages = 0,
       
   298 #endif
       
   299          page_size = sysconf(_SC_PAGE_SIZE);
       
   300     total_ram += QString::number(pages * page_size) + "\n";
       
   301     os_version += "GNU/Linux or BSD\n";
       
   302 #endif
       
   303 
       
   304     // uname -a
       
   305 #if defined(Q_WS_X11) || defined(Q_WS_MACX)
       
   306     QProcess *process = new QProcess();
       
   307     QStringList arguments = QStringList("-a");
       
   308     process->start("uname", arguments);
       
   309     if (process->waitForFinished())
       
   310         kernel_line += QString(process->readAll());
       
   311     delete process;
       
   312 #endif
       
   313 
       
   314     // cpu info
       
   315     quint32 registers[4];
       
   316     quint32 i;
       
   317 
       
   318     i = 0x80000002;
       
   319     asm volatile
       
   320       ("cpuid" : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3])
       
   321        : "a" (i), "c" (0));
       
   322     processor_name += std::string((const char *)&registers[0], 4);
       
   323     processor_name += std::string((const char *)&registers[1], 4);
       
   324     processor_name += std::string((const char *)&registers[2], 4);
       
   325     processor_name += std::string((const char *)&registers[3], 4);
       
   326     i = 0x80000003;
       
   327     asm volatile
       
   328       ("cpuid" : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3])
       
   329        : "a" (i), "c" (0));
       
   330     processor_name += std::string((const char *)&registers[0], 4);
       
   331     processor_name += std::string((const char *)&registers[1], 4);
       
   332     processor_name += std::string((const char *)&registers[2], 4);
       
   333     processor_name += std::string((const char *)&registers[3], 4);
       
   334     i = 0x80000004;
       
   335     asm volatile
       
   336       ("cpuid" : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3])
       
   337        : "a" (i), "c" (0));
       
   338     processor_name += std::string((const char *)&registers[0], 4);
       
   339     processor_name += std::string((const char *)&registers[1], 4);
       
   340     processor_name += std::string((const char *)&registers[2], 4);
       
   341     processor_name += std::string((const char *)&registers[3], 3);
       
   342 
       
   343     // compiler
       
   344 #ifdef __GNUC__
       
   345     compiler_version += "GCC " + QString(__VERSION__) + "\n";
       
   346 #else
       
   347     compiler_version += "Unknown\n";
       
   348 #endif
       
   349 
       
   350     if(sizeof(void*) == 4)
       
   351         compiler_bits += "i386\n";
       
   352     else if(sizeof(void*) == 8)
       
   353         compiler_bits += "x86_64\n";
       
   354 
       
   355     // concat system info
       
   356     specs = qt_version
       
   357         + os_version
       
   358         + total_ram
       
   359         + screen_size
       
   360         + number_of_screens
       
   361         + QString::fromStdString(processor_name + "\n")
       
   362         + number_of_cores
       
   363         + compiler_version
       
   364         + compiler_bits
       
   365         + kernel_line;
       
   366 }
       
   367 
       
   368 void PageFeedback::connectSignals()
       
   369 {
       
   370     //TODO
       
   371 }
       
   372 
       
   373 void PageFeedback::ShowErrorMessage(const QString & msg)
       
   374 {
       
   375     QMessageBox msgMsg(this);
       
   376     msgMsg.setIcon(QMessageBox::Warning);
       
   377     msgMsg.setWindowTitle(QMessageBox::tr("Hedgewars - Error"));
       
   378     msgMsg.setText(msg);
       
   379     msgMsg.setWindowModality(Qt::WindowModal);
       
   380     msgMsg.exec();
       
   381 }
       
   382 
       
   383 void PageFeedback::ShowSpecs()
       
   384 {
       
   385     QMessageBox msgMsg(this);
       
   386     msgMsg.setIcon(QMessageBox::Information);
       
   387     msgMsg.setWindowTitle(QMessageBox::tr("System Information Preview"));
       
   388     msgMsg.setText(specs);
       
   389     msgMsg.setTextFormat(Qt::PlainText);
       
   390     msgMsg.setWindowModality(Qt::WindowModal);
       
   391     msgMsg.setStyleSheet("background: #0A0533;");
       
   392     msgMsg.exec();
       
   393 }
       
   394 
       
   395 PageFeedback::PageFeedback(QWidget* parent) : AbstractPage(parent)
       
   396 {
       
   397     initPage();
       
   398     netManager = NULL;
       
   399     GenerateSpecs();
       
   400 }