view ui/mainwindow.cpp @ 285:f23e0ccd5d14

Fix call to windows process. This now uses the correct parameters, emits the signals correctly as errors and waits for the process to finish instead of relying on NOASYNC which did not work for runas and also made it impossible to get the return code
author Andre Heinecke <aheinecke@intevation.de>
date Wed, 02 Apr 2014 13:45:57 +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/