view ui/mainwindow.cpp @ 249:6a7eb102716d

Remove code duplication by unifying the certificatelist. You should now check for isInstallCert to determine wether this certificate should be installed or removed. Leaving the getInstallCertificates and getRemoveCertificates in place for compatibilty would have been easier to keep the tests stable.
author Andre Heinecke <aheinecke@intevation.de>
date Mon, 31 Mar 2014 08:06:17 +0000
parents f7176140d20d
children 1e112cf41e92
line wrap: on
line source
#include "mainwindow.h"

#include <QDebug>
#include <QMessageBox>
#include <QSystemTrayIcon>
#include <QAction>
#include <QDialog>
#include <QMenu>
#include <QApplication>
#include <QFile>
#include <QTimer>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGroupBox>
#include <QPushButton>
#include <QSplitter>
#include <QLabel>
#include <QImage>

// The amount of time in minutes stay silent if we have
// something to say
#define NAG_INTERVAL_MINUTES 2

#define SERVER_URL "https://files.kolab.org:443"
#define LIST_RESOURCE "/incoming/aheinecke/test"
#define SW_RESOURCE "/incoming/aheinecke/test"

#include "certificatelist.h"
#include "downloader.h"
#include "listupdatedialog.h"
#include "helpdialog.h"
#include "aboutdialog.h"
#include "statusdialog.h"

MainWindow::MainWindow() {
    createActions();
    createTrayIcon();
    createMenuBar();
    createContent();
    qRegisterMetaType<SSLConnection::ErrorCode>("SSLConnection::ErrorCode");

    connect(mTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
            this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));

    mMessageTimer = new QTimer(this);
    connect(mMessageTimer, SIGNAL(timeout()), this, SLOT(showMessage()));
    mMessageTimer->setInterval(NAG_INTERVAL_MINUTES * 60 * 1000);
    mMessageTimer->start();
    checkUpdates();
}

void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason)
{
    switch (reason) {
    case QSystemTrayIcon::Trigger:
    case QSystemTrayIcon::MiddleClick:
        showMessage();
        break;
    case QSystemTrayIcon::DoubleClick:
        // TODO show menu
        break;
    default:
        ;
    }
}

void MainWindow::messageClicked()
{
    if (mCurState == NewListAvailable) {
        ListUpdateDialog *listUpdateDialog = new ListUpdateDialog(this,
                mListToInstall);
        listUpdateDialog->show();
        qDebug() << "NewListAvailable";
    }
}

void MainWindow::showMessage()
{
    if (!mCurMessage.isEmpty()) {
        mTrayIcon->showMessage(QApplication::applicationName(), mCurMessage,
                               QSystemTrayIcon::Information, 5000);
        mMessageTimer->start(); // Restart the timer so that we don't spam
    }
}

void MainWindow::verifyAvailableData()
{
    QString listFileName = mSettings.value("List/available").toString();
    QString swFileName = mSettings.value("Software/available").toString();

    if (!listFileName.isEmpty()) {
        mListToInstall.readList(listFileName.toLocal8Bit().constData());
        if (!mListToInstall.isValid()) {
            mCurState = TransferError;
            // Probably a bug when Qt fileName is encoded and cFileName
            // fails because of this. This needs a unit test!
            // Maybe check that the file is in our data directory
            QFile::remove(listFileName);
            mSettings.remove("List/available");
            mSettings.remove("List/availableDate");
        }
    } else {
        // Make sure the available notation is also removed
        mSettings.remove("List/available");
        mSettings.remove("List/availableDate");
    }

    if (!swFileName.isEmpty()) {
        // TODO
    } else {
        mSettings.remove("Software/available");
        mSettings.remove("Software/availableDate");
    }
}

void MainWindow::handleNewList(const QString& fileName, const QDateTime& modDate) {
    mSettings.setValue("List/available", fileName);
    mSettings.setValue("List/availableDate", modDate);

    verifyAvailableData();
    if (!mListToInstall.isValid()) {
        /* Downloader provided invalid files */
        /* TODO: Error count. Error handling. Otherwise
         * we can go into an endless loop here */

        /* Retry the download again in 10 - 20 minutes */
        QTimer::singleShot(600000 + (qrand() % 60000), this, SLOT(checkUpdates()));
    } else {
        mCurMessage = tr("An updated certificate list is available. Click here to install.");
        setState(NewListAvailable);
        showMessage();
        loadCertificateList();
    }
}

void MainWindow::handleNewSW(const QString& fileName, const QDateTime& modDate) {
    mCurMessage = tr("An update for %1 is available. Click here to install.").arg(
                QApplication::applicationName());
    setState(NewSoftwareAvailable);
    mSettings.setValue("Software/available", fileName);
    mSettings.setValue("Software/availableDate", modDate);

    mSettings.sync();
    showMessage();
}

void MainWindow::checkUpdates()
{
    verifyAvailableData();

    QDateTime listInstalledLastMod = mSettings.value("List/installedDate").toDateTime();
    QDateTime swInstalledLastMod = mSettings.value("Software/installedDate").toDateTime();

    Downloader* downloader = new Downloader(this,
                                            QString::fromLatin1(SERVER_URL),
                                            QByteArray(),
                                            QDateTime::currentDateTime(),
//                                            swInstalledLastMod,
                                            listInstalledLastMod,
                                            QString::fromLatin1(SW_RESOURCE),
                                            QString::fromLatin1(LIST_RESOURCE));

    connect(downloader, SIGNAL(newListAvailable(const QString&, const QDateTime&)),
            this, SLOT(handleNewList(const QString&, const QDateTime&)));
    connect(downloader, SIGNAL(newSoftwareAvailable(const QString&, const QDateTime&)),
            this, SLOT(handleNewSW(const QString&, const QDateTime&)));
    connect(downloader, SIGNAL(finished()), downloader, SLOT(deleteLater()));
    connect(downloader, SIGNAL(error(const QString &, SSLConnection::ErrorCode)),
            this, SLOT(downloaderError(const QString &, SSLConnection::ErrorCode)));
    downloader->start();
}


void MainWindow::downloaderError(const QString &message, SSLConnection::ErrorCode error)
{
    mCurMessage = message;
    showMessage();
}


void MainWindow::createActions()
{
    mCheckUpdates = new QAction(tr("Check for Updates"), this);
    connect(mCheckUpdates, SIGNAL(triggered()), this, SLOT(checkUpdates()));
    mQuitAction = new QAction(tr("Quit"), this);
    connect(mQuitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
}

void MainWindow::createTrayIcon()
{
    QIcon trayImg(":/img/tray_22.png");

    mTrayMenu = new QMenu(this);
    mTrayMenu->addAction(mCheckUpdates);
    mTrayMenu->addAction(mQuitAction);

    mTrayIcon = new QSystemTrayIcon(this);
    mTrayIcon->setContextMenu(mTrayMenu);

    mTrayIcon->setIcon(trayImg);
    setWindowIcon(trayImg);
    mTrayIcon->show();
    mTrayIcon->setToolTip(tr("m13ui"));

    connect(mTrayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked()));
}

void MainWindow::createMenuBar()
{
    mMenuBar = new QMenuBar(this);
    QMenu *mMenu = new QMenu(tr("Menu"), mMenuBar);
    mMenuBar->addMenu(mMenu);
    QAction *update = mMenu->addAction(tr("Force Update"));
    QAction *settings = mMenu->addAction(tr("Settings"));
    QAction *status = mMenu->addAction(tr("Statusdialog"));
    mMenu->addSeparator();
    QAction *help = mMenu->addAction(tr("Help"));
    QAction *about = mMenu->addAction(tr("About"));
    mMenu->addSeparator();
    QAction *quit = mMenu->addAction(tr("Quit"));
    connect(update, SIGNAL(triggered()), this, SLOT(checkUpdates()));
    connect(settings, SIGNAL(triggered()), this, SLOT(showSettings()));
    connect(status, SIGNAL(triggered()), this, SLOT(showStatus()));
    connect(help, SIGNAL(triggered()), this, SLOT(showHelp()));
    connect(about, SIGNAL(triggered()), this, SLOT(showAbout()));
    connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
    setMenuBar(mMenuBar);
}

void MainWindow::createContent()
{
    // Create a central widget containing the main layout.
    QWidget *base = new QWidget;

    QVBoxLayout *mainLayout = new QVBoxLayout;
    QHBoxLayout *headerLayout = new QHBoxLayout;
    QVBoxLayout *headerTextLayout = new QVBoxLayout;
    QHBoxLayout *certLayout = new QHBoxLayout;
    QHBoxLayout *bottomLayout = new QHBoxLayout;

    QImage *logoImage = new QImage(":/img/logo.png");
    QLabel *logo = new QLabel;
    logo->setBackgroundRole(QPalette::Base);
    logo->setPixmap(QPixmap::fromImage(*logoImage));
    QLabel *title = new QLabel("<h2>" + tr("Certificate Installer") + "</h2>");
    QLabel *subTitle = new QLabel("This Software installs and removes Certificates");
    headerTextLayout->addWidget(title);
    headerTextLayout->addWidget(subTitle);
    headerLayout->addWidget(logo);
    headerLayout->addLayout(headerTextLayout);
    headerLayout->setStretch(0, 0);
    headerLayout->setStretch(1, 10);

    QGroupBox *certBox = new QGroupBox(tr("Managed Certificates"));
    certificateList = new QListWidget;
    connect(certificateList, SIGNAL(itemClicked(QListWidgetItem*)),
        this, SLOT(showDetails(QListWidgetItem*)));
    certificateDetails = new QTextEdit;
    certificateDetails->setReadOnly(true);
    QSplitter *splitter = new QSplitter(certBox);
    splitter->addWidget(certificateList);
    splitter->addWidget(certificateDetails);
    certLayout->addWidget(splitter);
    certBox->setLayout(certLayout);

    QPushButton *update = new QPushButton("Search for Updates");
    connect(update, SIGNAL(clicked()), this, SLOT(checkUpdates()));
    bottomLayout->insertStretch(0, 10);
    bottomLayout->addWidget(update);
    mainLayout->addLayout(headerLayout);
    mainLayout->addWidget(certBox);
    mainLayout->addLayout(bottomLayout);
    mainLayout->setStretch(0, 0);
    mainLayout->setStretch(1, 10);

    // QMainWindow allready has a layout. All child layouts and widgets are
    // managed in the central widget.
    base->setLayout(mainLayout);
    setCentralWidget(base);
}

void MainWindow::loadCertificateList()
{
    qDebug() << "display certificates";
    certificateList->clear();
    foreach (const Certificate &cert, mListToInstall.getCertificates()) {
        if (!cert.isValid()) {
            qWarning() << "Invalid certificate in list";
            continue;
        }
        QListWidgetItem* item = new QListWidgetItem(cert.shortDescription());
        item->setData(Qt::UserRole, cert.details());
        QIcon *certIcon = cert.isInstallCert() ? new QIcon(":/img/list-add.png"):
                                                 new QIcon(":/img/list-remove.png");
        item->setIcon(*certIcon);
        certificateList->addItem(item);
    }
}

void MainWindow::showSettings()
{
    qDebug() << "show settingsdialog";
}

void MainWindow::showStatus()
{
    qDebug() << "show settingsdialog";
    StatusDialog *status = new StatusDialog(this);
    status->show();
}

void MainWindow::showHelp()
{
    qDebug() << "show helpdialog";
    HelpDialog *help = new HelpDialog(this);
    help->show();
}

void MainWindow::showAbout()
{
    qDebug() << "show aboutdialog";
    AboutDialog *about = new AboutDialog(this);
    about->show();
}

void MainWindow::showDetails(QListWidgetItem *item)
{
    qDebug() << "show details";
    QString details = item->data(Qt::UserRole).toString();
    details.append("\rInstalled: 1.1.1971\rRemoved: 1.1.1971");
    certificateDetails->setPlainText(details);
}

http://wald.intevation.org/projects/trustbridge/