aheinecke@0: #include "mainwindow.h" aheinecke@0: aheinecke@0: #include aheinecke@0: #include aheinecke@0: #include aheinecke@0: #include aheinecke@0: #include aheinecke@0: #include aheinecke@2: #include aheinecke@16: #include aheinecke@19: #include rrenkert@187: #include rrenkert@187: #include rrenkert@187: #include rrenkert@187: #include rrenkert@189: #include rrenkert@205: #include rrenkert@205: #include rrenkert@250: #include aheinecke@19: aheinecke@19: // The amount of time in minutes stay silent if we have aheinecke@19: // something to say aheinecke@19: #define NAG_INTERVAL_MINUTES 2 aheinecke@0: aheinecke@72: #define SERVER_URL "https://files.kolab.org:443" aheinecke@72: #define LIST_RESOURCE "/incoming/aheinecke/test" aheinecke@72: #define SW_RESOURCE "/incoming/aheinecke/test" aheinecke@72: aheinecke@7: #include "certificatelist.h" aheinecke@10: #include "downloader.h" aheinecke@71: #include "listupdatedialog.h" rrenkert@191: #include "helpdialog.h" rrenkert@200: #include "aboutdialog.h" rrenkert@212: #include "statusdialog.h" aheinecke@7: aheinecke@0: MainWindow::MainWindow() { aheinecke@0: createActions(); aheinecke@0: createTrayIcon(); rrenkert@155: createMenuBar(); rrenkert@187: createContent(); aheinecke@45: qRegisterMetaType("SSLConnection::ErrorCode"); rrenkert@265: qRegisterMetaType("Certificate::Status"); aheinecke@0: aheinecke@0: connect(mTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), aheinecke@0: this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason))); aheinecke@19: aheinecke@19: mMessageTimer = new QTimer(this); aheinecke@19: connect(mMessageTimer, SIGNAL(timeout()), this, SLOT(showMessage())); aheinecke@19: mMessageTimer->setInterval(NAG_INTERVAL_MINUTES * 60 * 1000); aheinecke@19: mMessageTimer->start(); aheinecke@71: checkUpdates(); aheinecke@0: } aheinecke@0: aheinecke@0: void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) aheinecke@0: { aheinecke@0: switch (reason) { aheinecke@0: case QSystemTrayIcon::Trigger: aheinecke@0: case QSystemTrayIcon::MiddleClick: aheinecke@0: showMessage(); aheinecke@0: break; aheinecke@16: case QSystemTrayIcon::DoubleClick: aheinecke@16: // TODO show menu aheinecke@16: break; aheinecke@0: default: aheinecke@0: ; aheinecke@0: } aheinecke@0: } aheinecke@0: aheinecke@71: void MainWindow::messageClicked() aheinecke@71: { aheinecke@71: if (mCurState == NewListAvailable) { aheinecke@71: ListUpdateDialog *listUpdateDialog = new ListUpdateDialog(this, aheinecke@71: mListToInstall); aheinecke@71: listUpdateDialog->show(); aheinecke@71: qDebug() << "NewListAvailable"; aheinecke@71: } aheinecke@71: } aheinecke@71: aheinecke@0: void MainWindow::showMessage() aheinecke@0: { aheinecke@16: if (!mCurMessage.isEmpty()) { aheinecke@16: mTrayIcon->showMessage(QApplication::applicationName(), mCurMessage, aheinecke@16: QSystemTrayIcon::Information, 5000); aheinecke@19: mMessageTimer->start(); // Restart the timer so that we don't spam aheinecke@16: } aheinecke@0: } aheinecke@16: aheinecke@16: void MainWindow::verifyAvailableData() aheinecke@0: { aheinecke@16: QString listFileName = mSettings.value("List/available").toString(); aheinecke@16: QString swFileName = mSettings.value("Software/available").toString(); aheinecke@16: aheinecke@16: if (!listFileName.isEmpty()) { aheinecke@71: mListToInstall.readList(listFileName.toLocal8Bit().constData()); aheinecke@71: if (!mListToInstall.isValid()) { aheinecke@82: mCurState = TransferError; aheinecke@16: // Probably a bug when Qt fileName is encoded and cFileName aheinecke@16: // fails because of this. This needs a unit test! aheinecke@16: // Maybe check that the file is in our data directory aheinecke@16: QFile::remove(listFileName); aheinecke@16: mSettings.remove("List/available"); aheinecke@16: mSettings.remove("List/availableDate"); aheinecke@16: } aheinecke@16: } else { aheinecke@16: // Make sure the available notation is also removed aheinecke@16: mSettings.remove("List/available"); aheinecke@16: mSettings.remove("List/availableDate"); aheinecke@16: } aheinecke@16: aheinecke@16: if (!swFileName.isEmpty()) { aheinecke@16: // TODO aheinecke@16: } else { aheinecke@16: mSettings.remove("Software/available"); aheinecke@16: mSettings.remove("Software/availableDate"); aheinecke@16: } aheinecke@16: } aheinecke@16: aheinecke@16: void MainWindow::handleNewList(const QString& fileName, const QDateTime& modDate) { aheinecke@71: mSettings.setValue("List/available", fileName); aheinecke@71: mSettings.setValue("List/availableDate", modDate); aheinecke@16: aheinecke@71: verifyAvailableData(); aheinecke@71: if (!mListToInstall.isValid()) { aheinecke@71: /* Downloader provided invalid files */ aheinecke@71: /* TODO: Error count. Error handling. Otherwise aheinecke@71: * we can go into an endless loop here */ aheinecke@71: aheinecke@71: /* Retry the download again in 10 - 20 minutes */ aheinecke@71: QTimer::singleShot(600000 + (qrand() % 60000), this, SLOT(checkUpdates())); aheinecke@82: } else { aheinecke@82: mCurMessage = tr("An updated certificate list is available. Click here to install."); aheinecke@82: setState(NewListAvailable); aheinecke@82: showMessage(); rrenkert@189: loadCertificateList(); aheinecke@71: } aheinecke@16: } aheinecke@16: aheinecke@16: void MainWindow::handleNewSW(const QString& fileName, const QDateTime& modDate) { aheinecke@16: mCurMessage = tr("An update for %1 is available. Click here to install.").arg( aheinecke@16: QApplication::applicationName()); aheinecke@16: setState(NewSoftwareAvailable); aheinecke@16: mSettings.setValue("Software/available", fileName); aheinecke@16: mSettings.setValue("Software/availableDate", modDate); aheinecke@16: aheinecke@16: mSettings.sync(); aheinecke@16: showMessage(); aheinecke@16: } aheinecke@16: aheinecke@16: void MainWindow::checkUpdates() aheinecke@16: { aheinecke@16: verifyAvailableData(); aheinecke@16: aheinecke@17: QDateTime listInstalledLastMod = mSettings.value("List/installedDate").toDateTime(); aheinecke@17: QDateTime swInstalledLastMod = mSettings.value("Software/installedDate").toDateTime(); aheinecke@16: aheinecke@72: Downloader* downloader = new Downloader(this, aheinecke@72: QString::fromLatin1(SERVER_URL), aheinecke@72: QByteArray(), aheinecke@72: QDateTime::currentDateTime(), aheinecke@72: // swInstalledLastMod, aheinecke@72: listInstalledLastMod, aheinecke@72: QString::fromLatin1(SW_RESOURCE), aheinecke@72: QString::fromLatin1(LIST_RESOURCE)); aheinecke@17: aheinecke@16: connect(downloader, SIGNAL(newListAvailable(const QString&, const QDateTime&)), aheinecke@16: this, SLOT(handleNewList(const QString&, const QDateTime&))); aheinecke@16: connect(downloader, SIGNAL(newSoftwareAvailable(const QString&, const QDateTime&)), aheinecke@16: this, SLOT(handleNewSW(const QString&, const QDateTime&))); aheinecke@16: connect(downloader, SIGNAL(finished()), downloader, SLOT(deleteLater())); aheinecke@45: connect(downloader, SIGNAL(error(const QString &, SSLConnection::ErrorCode)), aheinecke@45: this, SLOT(downloaderError(const QString &, SSLConnection::ErrorCode))); aheinecke@10: downloader->start(); aheinecke@0: } aheinecke@0: aheinecke@16: aheinecke@45: void MainWindow::downloaderError(const QString &message, SSLConnection::ErrorCode error) aheinecke@16: { aheinecke@16: mCurMessage = message; andre@27: showMessage(); aheinecke@16: } aheinecke@16: aheinecke@16: aheinecke@0: void MainWindow::createActions() aheinecke@0: { aheinecke@0: mCheckUpdates = new QAction(tr("Check for Updates"), this); aheinecke@16: connect(mCheckUpdates, SIGNAL(triggered()), this, SLOT(checkUpdates())); aheinecke@2: mQuitAction = new QAction(tr("Quit"), this); aheinecke@2: connect(mQuitAction, SIGNAL(triggered()), qApp, SLOT(quit())); aheinecke@0: } aheinecke@0: aheinecke@0: void MainWindow::createTrayIcon() aheinecke@0: { aheinecke@11: QIcon trayImg(":/img/tray_22.png"); aheinecke@0: aheinecke@0: mTrayMenu = new QMenu(this); aheinecke@0: mTrayMenu->addAction(mCheckUpdates); aheinecke@2: mTrayMenu->addAction(mQuitAction); aheinecke@0: aheinecke@0: mTrayIcon = new QSystemTrayIcon(this); aheinecke@0: mTrayIcon->setContextMenu(mTrayMenu); aheinecke@0: aheinecke@0: mTrayIcon->setIcon(trayImg); aheinecke@0: setWindowIcon(trayImg); aheinecke@0: mTrayIcon->show(); aheinecke@0: mTrayIcon->setToolTip(tr("m13ui")); aheinecke@71: aheinecke@71: connect(mTrayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked())); aheinecke@0: } rrenkert@155: rrenkert@155: void MainWindow::createMenuBar() rrenkert@155: { rrenkert@155: mMenuBar = new QMenuBar(this); rrenkert@155: QMenu *mMenu = new QMenu(tr("Menu"), mMenuBar); rrenkert@155: mMenuBar->addMenu(mMenu); rrenkert@155: QAction *update = mMenu->addAction(tr("Force Update")); rrenkert@155: QAction *settings = mMenu->addAction(tr("Settings")); rrenkert@212: QAction *status = mMenu->addAction(tr("Statusdialog")); rrenkert@155: mMenu->addSeparator(); rrenkert@155: QAction *help = mMenu->addAction(tr("Help")); rrenkert@155: QAction *about = mMenu->addAction(tr("About")); rrenkert@155: mMenu->addSeparator(); rrenkert@155: QAction *quit = mMenu->addAction(tr("Quit")); rrenkert@155: connect(update, SIGNAL(triggered()), this, SLOT(checkUpdates())); rrenkert@155: connect(settings, SIGNAL(triggered()), this, SLOT(showSettings())); rrenkert@212: connect(status, SIGNAL(triggered()), this, SLOT(showStatus())); rrenkert@155: connect(help, SIGNAL(triggered()), this, SLOT(showHelp())); rrenkert@155: connect(about, SIGNAL(triggered()), this, SLOT(showAbout())); rrenkert@155: connect(quit, SIGNAL(triggered()), qApp, SLOT(quit())); rrenkert@155: setMenuBar(mMenuBar); rrenkert@155: } rrenkert@155: rrenkert@187: void MainWindow::createContent() rrenkert@187: { rrenkert@187: // Create a central widget containing the main layout. rrenkert@187: QWidget *base = new QWidget; rrenkert@187: rrenkert@250: // Layouts and Container rrenkert@250: QHBoxLayout *mainLayout = new QHBoxLayout; rrenkert@250: QVBoxLayout *infoLayout = new QVBoxLayout; rrenkert@250: QVBoxLayout *certLayout = new QVBoxLayout; rrenkert@205: QHBoxLayout *headerLayout = new QHBoxLayout; rrenkert@205: QVBoxLayout *headerTextLayout = new QVBoxLayout; rrenkert@250: QVBoxLayout *toolLayout = new QVBoxLayout; rrenkert@250: QHBoxLayout *toolButtonLayout = new QHBoxLayout; rrenkert@187: rrenkert@250: // The certificate list rrenkert@250: QGroupBox *certBox = new QGroupBox(tr("Managed Certificates")); rrenkert@250: certificateList = new QListWidget; rrenkert@250: connect(certificateList, SIGNAL(itemClicked(QListWidgetItem*)), rrenkert@250: this, SLOT(showDetails(QListWidgetItem*))); rrenkert@250: certLayout->addWidget(certificateList); rrenkert@250: certBox->setLayout(certLayout); rrenkert@250: rrenkert@250: // The header (icon, about text) rrenkert@205: QImage *logoImage = new QImage(":/img/logo.png"); rrenkert@205: QLabel *logo = new QLabel; rrenkert@205: logo->setBackgroundRole(QPalette::Base); rrenkert@205: logo->setPixmap(QPixmap::fromImage(*logoImage)); rrenkert@210: QLabel *title = new QLabel("

" + tr("Certificate Installer") + "

"); rrenkert@205: QLabel *subTitle = new QLabel("This Software installs and removes Certificates"); rrenkert@205: headerTextLayout->addWidget(title); rrenkert@205: headerTextLayout->addWidget(subTitle); rrenkert@205: headerLayout->addWidget(logo); rrenkert@205: headerLayout->addLayout(headerTextLayout); rrenkert@210: headerLayout->setStretch(0, 0); rrenkert@210: headerLayout->setStretch(1, 10); rrenkert@205: rrenkert@250: // The tools to update the certificate list/software and install rrenkert@250: // certificates. rrenkert@250: QCheckBox *autoUpdateOption = new QCheckBox(tr("autoupdate")); rrenkert@250: toolLayout->addWidget(autoUpdateOption); rrenkert@250: // connect(autoUpdateOption, SIGNAL(stateChanged()), this, SLOT(setAutoUpdate())); rrenkert@250: QPushButton *update = new QPushButton(tr("Search for Updates")); rrenkert@250: connect(update, SIGNAL(clicked()), this, SLOT(checkUpdates())); rrenkert@250: QPushButton *install = new QPushButton(tr("Install selected")); rrenkert@250: // connect(update, SIGNAL(clicked()), this, SLOT(installCertificates())); rrenkert@250: toolButtonLayout->addWidget(update); rrenkert@250: toolButtonLayout->addWidget(install); rrenkert@250: toolButtonLayout->insertStretch(2, 10); rrenkert@250: toolLayout->addLayout(toolButtonLayout); rrenkert@250: rrenkert@250: // The certificate details rrenkert@189: certificateDetails = new QTextEdit; rrenkert@189: certificateDetails->setReadOnly(true); rrenkert@187: rrenkert@250: infoLayout->addSpacing(20); rrenkert@250: infoLayout->addLayout(headerLayout); rrenkert@250: infoLayout->addLayout(toolLayout); rrenkert@250: infoLayout->addWidget(certificateDetails); rrenkert@250: rrenkert@187: mainLayout->addWidget(certBox); rrenkert@250: mainLayout->addLayout(infoLayout); rrenkert@250: rrenkert@187: rrenkert@187: // QMainWindow allready has a layout. All child layouts and widgets are rrenkert@187: // managed in the central widget. rrenkert@187: base->setLayout(mainLayout); rrenkert@187: setCentralWidget(base); rrenkert@187: } rrenkert@187: rrenkert@189: void MainWindow::loadCertificateList() rrenkert@189: { rrenkert@189: qDebug() << "display certificates"; rrenkert@189: certificateList->clear(); aheinecke@249: foreach (const Certificate &cert, mListToInstall.getCertificates()) { rrenkert@189: if (!cert.isValid()) { rrenkert@189: qWarning() << "Invalid certificate in list"; rrenkert@189: continue; rrenkert@189: } rrenkert@189: QListWidgetItem* item = new QListWidgetItem(cert.shortDescription()); rrenkert@189: item->setData(Qt::UserRole, cert.details()); aheinecke@249: QIcon *certIcon = cert.isInstallCert() ? new QIcon(":/img/list-add.png"): aheinecke@249: new QIcon(":/img/list-remove.png"); rrenkert@189: item->setIcon(*certIcon); rrenkert@189: certificateList->addItem(item); rrenkert@189: } rrenkert@189: } rrenkert@189: rrenkert@189: void MainWindow::showSettings() rrenkert@189: { rrenkert@155: qDebug() << "show settingsdialog"; rrenkert@155: } rrenkert@155: rrenkert@212: void MainWindow::showStatus() rrenkert@212: { rrenkert@212: qDebug() << "show settingsdialog"; rrenkert@212: StatusDialog *status = new StatusDialog(this); rrenkert@212: status->show(); rrenkert@212: } rrenkert@212: rrenkert@155: void MainWindow::showHelp() rrenkert@155: { rrenkert@155: qDebug() << "show helpdialog"; rrenkert@191: HelpDialog *help = new HelpDialog(this); rrenkert@191: help->show(); rrenkert@155: } rrenkert@155: rrenkert@155: void MainWindow::showAbout() rrenkert@155: { rrenkert@155: qDebug() << "show aboutdialog"; rrenkert@200: AboutDialog *about = new AboutDialog(this); rrenkert@200: about->show(); rrenkert@155: } rrenkert@187: rrenkert@189: void MainWindow::showDetails(QListWidgetItem *item) rrenkert@189: { rrenkert@189: qDebug() << "show details"; rrenkert@189: QString details = item->data(Qt::UserRole).toString(); rrenkert@210: details.append("\rInstalled: 1.1.1971\rRemoved: 1.1.1971"); rrenkert@189: certificateDetails->setPlainText(details); rrenkert@189: }