aheinecke@404: /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik aheinecke@404: * Software engineering by Intevation GmbH aheinecke@404: * aheinecke@404: * This file is Free Software under the GNU GPL (v>=2) aheinecke@404: * and comes with ABSOLUTELY NO WARRANTY! aheinecke@404: * See LICENSE.txt for details. aheinecke@404: */ rrenkert@361: #include "createinstallerdialog.h" rrenkert@361: #include aheinecke@526: #include rrenkert@361: #include rrenkert@361: #include rrenkert@361: #include rrenkert@361: #include rrenkert@361: #include rrenkert@361: #include rrenkert@361: #include aheinecke@515: #include aheinecke@526: #include aheinecke@526: #include aheinecke@515: #include rrenkert@361: rrenkert@361: CreateInstallerDialog::CreateInstallerDialog(QMainWindow *parent) : aheinecke@516: QDialog(parent), aheinecke@516: mProgress(this) rrenkert@361: { aheinecke@515: QSettings settings; rrenkert@414: setWindowTitle(tr("Create binary installer")); rrenkert@361: setupGUI(); rrenkert@414: resize(500, 250); aheinecke@515: mCertFile->setText(settings.value("CodeSignCert", QString()).toString()); aheinecke@515: mBinaryFolder->setText(settings.value("LastBinaryFolder", QString()).toString()); aheinecke@515: mSaveFile->setText(settings.value("LastBinOutputFolder", QString()).toString()); aheinecke@516: aheinecke@516: connect(&mNSISProc, SIGNAL(finished(int, QProcess::ExitStatus)), aheinecke@516: this, SLOT(processFinished(int, QProcess::ExitStatus))); aheinecke@516: connect(&mNSISProc, SIGNAL(error(QProcess::ProcessError)), aheinecke@516: this, SLOT(processError(QProcess::ProcessError))); rrenkert@361: } rrenkert@361: rrenkert@361: void CreateInstallerDialog::setupGUI() rrenkert@361: { rrenkert@361: /* Top level layout / widgets */ rrenkert@361: QVBoxLayout *topLayout = new QVBoxLayout; rrenkert@414: QVBoxLayout *headerLayout = new QVBoxLayout; rrenkert@414: QHBoxLayout *headerSubLayout = new QHBoxLayout; rrenkert@428: QHBoxLayout *centerLayout = new QHBoxLayout; rrenkert@361: QHBoxLayout *bottomLayout = new QHBoxLayout; rrenkert@428: QVBoxLayout *labelLayout = new QVBoxLayout; rrenkert@428: QVBoxLayout *fieldLayout = new QVBoxLayout; rrenkert@428: QVBoxLayout *buttonLayout = new QVBoxLayout; rrenkert@361: rrenkert@414: QLabel *header = new QLabel("

" + tr("Create binary installer") + "

"); rrenkert@414: QLabel *description = new QLabel( aheinecke@515: tr("Create and sign a TrustBridge binary installer.")); rrenkert@414: headerSubLayout->insertSpacing(0, 40); rrenkert@414: headerSubLayout->addWidget(description); rrenkert@414: QFrame *headerSeparator = new QFrame(); rrenkert@414: headerSeparator->setFrameShape(QFrame::HLine); rrenkert@414: headerSeparator->setFrameShadow(QFrame::Sunken); rrenkert@414: headerLayout->addWidget(header); rrenkert@414: headerLayout->addLayout(headerSubLayout); rrenkert@414: headerLayout->addWidget(headerSeparator); rrenkert@428: headerLayout->insertSpacing(4, 10); rrenkert@361: aheinecke@515: QLabel *archiveLabel = new QLabel(tr("Select binary folder:")); aheinecke@515: QLabel *certLabel = new QLabel(tr("Select code signing certificate:")); rrenkert@428: QLabel *saveLabel = new QLabel(tr("Select output folder:")); rrenkert@428: labelLayout->addWidget(archiveLabel); rrenkert@428: labelLayout->addWidget(certLabel); rrenkert@428: labelLayout->addWidget(saveLabel); rrenkert@428: aheinecke@515: mBinaryFolder = new QLineEdit(); rrenkert@428: mCertFile = new QLineEdit(); rrenkert@428: mSaveFile = new QLineEdit(); aheinecke@515: fieldLayout->addWidget(mBinaryFolder); rrenkert@428: fieldLayout->addWidget(mCertFile); rrenkert@428: fieldLayout->addWidget(mSaveFile); rrenkert@428: rrenkert@361: QPushButton *archiveSelect = new QPushButton("..."); aheinecke@515: connect(archiveSelect, SIGNAL(clicked()), this, SLOT(openFolderSelect())); rrenkert@361: archiveSelect->setFixedWidth(30); rrenkert@361: QPushButton *certSelect = new QPushButton("..."); rrenkert@361: connect(certSelect, SIGNAL(clicked()), this, SLOT(openCertificateSelect())); rrenkert@361: certSelect->setFixedWidth(30); rrenkert@361: QPushButton *saveSelect = new QPushButton("..."); rrenkert@361: connect(saveSelect, SIGNAL(clicked()), this, SLOT(openSaveLocation())); rrenkert@361: saveSelect->setFixedWidth(30); rrenkert@428: buttonLayout->addWidget(archiveSelect); rrenkert@428: buttonLayout->addWidget(certSelect); rrenkert@428: buttonLayout->addWidget(saveSelect); rrenkert@361: rrenkert@428: centerLayout->addLayout(labelLayout); rrenkert@428: centerLayout->addLayout(fieldLayout); rrenkert@428: centerLayout->addLayout(buttonLayout); rrenkert@361: rrenkert@414: QPushButton *create = new QPushButton(tr("Create installer")); rrenkert@361: connect(create, SIGNAL(clicked()), this, SLOT(createInstaller())); rrenkert@414: QPushButton *cancel = new QPushButton(tr("Cancel")); rrenkert@414: connect(cancel, SIGNAL(clicked()), this, SLOT(close())); rrenkert@361: bottomLayout->insertStretch(0, 10); rrenkert@361: bottomLayout->addWidget(create); rrenkert@414: bottomLayout->addWidget(cancel); rrenkert@414: rrenkert@414: QFrame *bottomSeparator = new QFrame(); rrenkert@414: bottomSeparator->setFrameShape(QFrame::HLine); rrenkert@414: bottomSeparator->setFrameShadow(QFrame::Sunken); rrenkert@361: rrenkert@361: topLayout->addLayout(headerLayout); rrenkert@361: topLayout->addLayout(centerLayout); rrenkert@361: topLayout->insertStretch(2, 10); rrenkert@428: centerLayout->insertSpacing(3, 10); rrenkert@414: topLayout->addWidget(bottomSeparator); rrenkert@361: topLayout->addLayout(bottomLayout); rrenkert@361: rrenkert@361: setLayout(topLayout); rrenkert@361: aheinecke@516: mProgress.setWindowModality(Qt::WindowModal); aheinecke@516: mProgress.setLabelText(tr("Creating installer package...")); aheinecke@516: mProgress.setCancelButton(0); aheinecke@516: mProgress.setRange(0,0); aheinecke@516: mProgress.setMinimumDuration(0); aheinecke@516: rrenkert@361: return; rrenkert@361: } rrenkert@361: rrenkert@361: void CreateInstallerDialog::openCertificateSelect() rrenkert@361: { aheinecke@515: QSettings settings; rrenkert@361: QString certFile = QFileDialog::getOpenFileName( aheinecke@515: this, tr("Select certificate"), aheinecke@515: mCertFile->text().isEmpty() ? QDir::homePath() : mCertFile->text(), aheinecke@515: "*.pem *.der *.crt"); aheinecke@515: settings.setValue("CodeSignCert", certFile); rrenkert@361: mCertFile->setText(certFile); rrenkert@361: } rrenkert@361: aheinecke@515: void CreateInstallerDialog::openFolderSelect() rrenkert@361: { aheinecke@515: QSettings settings; aheinecke@515: QString archiveFolder = QFileDialog::getExistingDirectory( aheinecke@515: this, tr("Select binary folder"), aheinecke@515: mBinaryFolder->text().isEmpty() ? QDir::homePath() : mBinaryFolder->text()); aheinecke@515: mBinaryFolder->setText(archiveFolder); aheinecke@515: settings.setValue("LastBinaryFolder", archiveFolder); rrenkert@361: } rrenkert@361: rrenkert@361: void CreateInstallerDialog::openSaveLocation() rrenkert@361: { aheinecke@515: QSettings settings; rrenkert@361: QString saveFile = QFileDialog::getExistingDirectory( aheinecke@515: this, tr("Select target location"), aheinecke@515: mSaveFile->text().isEmpty() ? QDir::homePath() : mSaveFile->text()); rrenkert@361: mSaveFile->setText(saveFile); aheinecke@515: settings.setValue("LastBinOutputFolder", saveFile); aheinecke@515: } aheinecke@515: aheinecke@515: void CreateInstallerDialog::showErrorMessage(const QString &msg) aheinecke@515: { aheinecke@515: QMessageBox::warning(this, tr("Error!"), msg); rrenkert@361: } rrenkert@361: aheinecke@516: void CreateInstallerDialog::processFinished(int exitCode, QProcess::ExitStatus exitStatus) aheinecke@516: { aheinecke@526: FinishedDialog *fin = new FinishedDialog(0, tr("Created installer in %1.") aheinecke@526: .arg(mBinaryFolder->text()), mNSISProc.readAll(), false); aheinecke@518: qDebug() << "Finished: " << mNSISProc.readAll(); aheinecke@516: mProgress.cancel(); aheinecke@526: fin->show(); aheinecke@526: close(); aheinecke@516: } aheinecke@516: aheinecke@516: void CreateInstallerDialog::processError(QProcess::ProcessError error) aheinecke@516: { aheinecke@518: qDebug() << "Error: " << mNSISProc.readAll(); aheinecke@516: mProgress.cancel(); aheinecke@516: } aheinecke@516: rrenkert@361: void CreateInstallerDialog::createInstaller() rrenkert@361: { aheinecke@515: QDir binDir(mBinaryFolder->text()); aheinecke@516: QDir outDir(mSaveFile->text()); aheinecke@516: if (mBinaryFolder->text().isEmpty() || !binDir.exists()) { aheinecke@515: showErrorMessage(tr("Please select an existing input folder.")); aheinecke@516: return; aheinecke@515: } aheinecke@516: if (mCertFile->text().isEmpty()) { aheinecke@516: showErrorMessage(tr("Please select a codesigning certificate.")); aheinecke@516: return; aheinecke@516: } aheinecke@516: if (mSaveFile->text().isEmpty() || !outDir.exists()) { aheinecke@516: showErrorMessage(tr("Please select a output folder.")); aheinecke@516: return; aheinecke@516: } aheinecke@516: QSettings options(binDir.filePath("meta.ini"), QSettings::IniFormat); aheinecke@516: options.sync(); aheinecke@516: QStringList keys = options.allKeys(); aheinecke@516: if (options.status() != QSettings::NoError || keys.size() < 1) { aheinecke@516: showErrorMessage(tr("Folder %1 does not appear to contain a meta.ini") aheinecke@516: .arg(binDir.path())); aheinecke@516: return; aheinecke@516: } aheinecke@516: aheinecke@516: /* Copy windows directory contents to tmpdir */ aheinecke@516: QStringList arguments; aheinecke@516: mNSISProc.setProgram("makensis"); aheinecke@518: mNSISProc.setProcessChannelMode(QProcess::MergedChannels); aheinecke@516: mNSISProc.setWorkingDirectory(outDir.path()); aheinecke@537: #ifdef Q_OS_WIN aheinecke@537: arguments << QString::fromLatin1("/Dfiles_dir=") + binDir.path() + "/windows"; aheinecke@537: foreach (const QString &key, keys) { aheinecke@537: arguments << QString::fromLatin1("/D%1=%2").arg(key, aheinecke@537: options.value(key, QString()).toString()); aheinecke@537: } aheinecke@537: #else aheinecke@516: arguments << QString::fromLatin1("-Dfiles_dir=") + binDir.path() + "/windows"; aheinecke@516: foreach (const QString &key, keys) { aheinecke@518: arguments << QString::fromLatin1("-D%1=%2").arg(key, aheinecke@516: options.value(key, QString()).toString()); aheinecke@516: } aheinecke@537: #endif aheinecke@516: aheinecke@516: arguments << binDir.path() + "/trustbridge.nsi"; aheinecke@516: aheinecke@518: qDebug() << "Starting makensis with arguments: " << arguments; aheinecke@518: mNSISProc.setArguments(arguments); aheinecke@516: mNSISProc.start(); aheinecke@516: mProgress.show(); aheinecke@516: aheinecke@516: if (!mNSISProc.waitForStarted() || aheinecke@516: mNSISProc.state() == QProcess::NotRunning) { aheinecke@516: showErrorMessage(tr("Failed to start makensis.\n" aheinecke@516: "Please ensure that makensis is installed and in your PATH variable.")); aheinecke@516: } rrenkert@361: } aheinecke@526: aheinecke@526: FinishedDialog::FinishedDialog(QDialog *parent, aheinecke@526: QString msg, QString details, bool isErr): aheinecke@526: QDialog(parent) aheinecke@526: { aheinecke@526: QVBoxLayout *topLayout = new QVBoxLayout; aheinecke@526: QHBoxLayout *buttonLayout = new QHBoxLayout; aheinecke@526: QLabel *msgLabel = new QLabel; aheinecke@526: QTextEdit *detailsWindow = new QTextEdit; aheinecke@526: aheinecke@526: detailsWindow->insertPlainText(details); aheinecke@526: detailsWindow->setReadOnly(true); aheinecke@526: detailsWindow->hide(); aheinecke@526: aheinecke@526: if (!isErr) { aheinecke@526: setWindowTitle(tr("Success!")); aheinecke@526: msgLabel->setPixmap(QApplication::style()->standardIcon( aheinecke@526: QStyle::SP_MessageBoxInformation).pixmap(16, 16)); aheinecke@526: } else { aheinecke@526: setWindowTitle(tr("Error!")); aheinecke@526: msgLabel->setPixmap(QApplication::style()->standardIcon( aheinecke@526: QStyle::SP_MessageBoxCritical).pixmap(16, 16)); aheinecke@526: } aheinecke@526: msgLabel->setText(msg); aheinecke@526: aheinecke@526: topLayout->addWidget(msgLabel); aheinecke@526: topLayout->addWidget(detailsWindow); aheinecke@526: QPushButton *detailsBtn = new QPushButton(tr("Details")); aheinecke@526: connect(detailsBtn, SIGNAL(clicked()), detailsWindow, SLOT(show())); aheinecke@526: buttonLayout->addWidget(detailsBtn); aheinecke@526: aheinecke@526: QPushButton *okBtn = new QPushButton(tr("OK")); aheinecke@526: okBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_DialogOkButton)); aheinecke@526: connect(okBtn, SIGNAL(clicked()), this, SLOT(close())); aheinecke@526: buttonLayout->insertStretch(0, 100); aheinecke@526: buttonLayout->addWidget(okBtn); aheinecke@526: aheinecke@526: topLayout->addLayout(buttonLayout); aheinecke@526: setLayout(topLayout); aheinecke@526: } aheinecke@526: