view ui/mainwindow.cpp @ 289:9ad00a3255f4

Change cinst from stdin input to use arguments. As we have to execute this process on Windows over the shell a stdin / stdout communication is not really possible without some major hacks. So you now have to supply an instructions file and the path to the certificatelist as arguments when this process is called
author Andre Heinecke <aheinecke@intevation.de>
date Wed, 02 Apr 2014 13:52:02 +0000
parents 90432cb1f374
children 75f7288ad67b
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 <QSplitter>
#include <QLabel>
#include <QImage>
#include <QCheckBox>

// 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"
#include "certificateitemdelegate.h"
#include "separatoritemdelegate.h"

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

    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;

    // Layouts and Container
    QHBoxLayout *mainLayout = new QHBoxLayout;
    QVBoxLayout *infoLayout = new QVBoxLayout;
    QVBoxLayout *certLayout = new QVBoxLayout;
    QVBoxLayout *detailLayout = new QVBoxLayout;
    QHBoxLayout *headerLayout = new QHBoxLayout;
    QVBoxLayout *headerTextLayout = new QVBoxLayout;
    QVBoxLayout *toolLayout = new QVBoxLayout;
    QHBoxLayout *bottomLayout = new QHBoxLayout;

    // The certificate list
    QGroupBox *certBox = new QGroupBox(tr("Managed Certificates"));
    certificateList = new QListWidget;
    certificateList->setItemDelegate(new CertificateItemDelegate);
    connect(certificateList, SIGNAL(itemClicked(QListWidgetItem*)),
        this, SLOT(showDetails(QListWidgetItem*)));
    certLayout->addWidget(certificateList);
    certBox->setLayout(certLayout);

    // The header (icon, about text)
    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);

    // The settings.
    QCheckBox *autoUpdateOption = new QCheckBox(tr("autoupdate"));
    toolLayout->addWidget(autoUpdateOption);
//    connect(autoUpdateOption, SIGNAL(stateChanged()), this, SLOT(setAutoUpdate()));

    // The buttons.
    bottomLayout->setAlignment(Qt::AlignBottom);
    installButton = new QPushButton(tr("Install selected"));
    installButton->setFixedHeight(80);
    connect(installButton, SIGNAL(clicked()), this, SLOT(resizeButtons()));
    quitButton = new QPushButton(tr("Quit"));
    quitButton->setFixedHeight(20);
    connect(quitButton, SIGNAL(clicked()), qApp, SLOT(quit()));
    bottomLayout->insertStretch(0, 10);
    bottomLayout->addWidget(installButton);
    bottomLayout->setAlignment(installButton, Qt::AlignBottom);
    bottomLayout->addWidget(quitButton);
    bottomLayout->setAlignment(quitButton, Qt::AlignBottom);

    // The certificate details
    QGroupBox *detailBox = new QGroupBox(tr("Details"));
    certificateDetails = new QTextEdit;
    certificateDetails->setReadOnly(true);
    detailLayout->addWidget(certificateDetails);
    detailBox->setLayout(detailLayout);

    infoLayout->addSpacing(20);
    infoLayout->addLayout(headerLayout);
    infoLayout->addLayout(toolLayout);
    infoLayout->addWidget(detailBox);
    infoLayout->addLayout(bottomLayout);

    mainLayout->addWidget(certBox);
    mainLayout->addLayout(infoLayout);


    // 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();
    int i = 0;
    foreach (const Certificate &cert, mListToInstall.getCertificates()) {
        if (!cert.isValid()) {
            qWarning() << "Invalid certificate in list";
            continue;
        }
        QListWidgetItem* item = new QListWidgetItem(cert.shortDescription());
        SeparatorItemDelegate *separator = new SeparatorItemDelegate();
        item->setData(Qt::UserRole, cert.details());
        if (cert.isInstallCert()) {
            // This if statements is for testing! @TODO Remove this!
            if (i <= 2) {
                item->setData(Qt::UserRole + 1, Certificate::InstallOld);
                item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
                item->setCheckState(Qt::Checked);
            }
            else {
                item->setData(Qt::UserRole + 1, Certificate::InstallNew);
                item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
                item->setCheckState(Qt::Checked);
            }
            if (i == 3) {
                QListWidgetItem *sep = new QListWidgetItem("New certificates");
                certificateList->setItemDelegateForRow(i, separator);
                certificateList->addItem(sep);
                i++;
            }
        }
        else {
            // This if statements is for testing! @TODO Remove this!
            if (i > 35) {
                item->setData(Qt::UserRole + 1, Certificate::RemoveNew);
                item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
                item->setCheckState(Qt::Checked);
            }
            else {
                item->setData(Qt::UserRole + 1, Certificate::RemoveOld);
                item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
            }
        }
        certificateList->addItem(item);
        i++;
    }
}

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);
}

void MainWindow::resizeButtons()
{
    installButton->setFixedHeight(20);
    quitButton->setFixedHeight(80);
}

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