summaryrefslogtreecommitdiffstats
path: root/src/libs/installer/packagemanagergui.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/installer/packagemanagergui.cpp')
-rw-r--r--src/libs/installer/packagemanagergui.cpp1983
1 files changed, 1983 insertions, 0 deletions
diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp
new file mode 100644
index 000000000..0b96e2d94
--- /dev/null
+++ b/src/libs/installer/packagemanagergui.cpp
@@ -0,0 +1,1983 @@
+/**************************************************************************
+**
+** This file is part of Installer Framework
+**
+** Copyright (c) 2011-2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**************************************************************************/
+#include "packagemanagergui.h"
+
+#include "component.h"
+#include "componentmodel.h"
+#include "errors.h"
+#include "fileutils.h"
+#include "messageboxhandler.h"
+#include "packagemanagercore.h"
+#include "qinstallerglobal.h"
+#include "progresscoordinator.h"
+#include "performinstallationform.h"
+#include "settings.h"
+#include "utils.h"
+
+#include "kdsysinfo.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QDynamicPropertyChangeEvent>
+#include <QtCore/QPair>
+#include <QtCore/QProcess>
+#include <QtCore/QRegExp>
+#include <QtCore/QSettings>
+#include <QtCore/QTimer>
+
+#include <QtGui/QApplication>
+#include <QtGui/QCheckBox>
+#include <QtGui/QDesktopServices>
+#include <QtGui/QFileDialog>
+#include <QtGui/QGridLayout>
+#include <QtGui/QFormLayout>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QHeaderView>
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QListWidget>
+#include <QtGui/QListWidgetItem>
+#include <QtGui/QMessageBox>
+#include <QtGui/QProgressBar>
+#include <QtGui/QPushButton>
+#include <QtGui/QRadioButton>
+#include <QtGui/QTextBrowser>
+#include <QtGui/QTreeWidget>
+#include <QtGui/QTreeView>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QScrollBar>
+#include <QtGui/QShowEvent>
+
+#include <QtScript/QScriptEngine>
+
+using namespace KDUpdater;
+using namespace QInstaller;
+
+/*
+TRANSLATOR QInstaller::PackageManagerCore;
+*/
+/*
+TRANSLATOR QInstaller::PackageManagerGui
+*/
+/*
+TRANSLATOR QInstaller::PackageManagerPage
+*/
+/*
+TRANSLATOR QInstaller::IntroductionPage
+*/
+/*
+TRANSLATOR QInstaller::LicenseAgreementPage
+*/
+/*
+TRANSLATOR QInstaller::ComponentSelectionPage
+*/
+/*
+TRANSLATOR QInstaller::TargetDirectoryPage
+*/
+/*
+TRANSLATOR QInstaller::StartMenuDirectoryPage
+*/
+/*
+TRANSLATOR QInstaller::ReadyForInstallationPage
+*/
+/*
+TRANSLATOR QInstaller::PerformInstallationPage
+*/
+/*
+TRANSLATOR QInstaller::FinishedPage
+*/
+
+
+static QString humanReadableSize(quint64 intSize)
+{
+ QString unit;
+ double size;
+
+ if (intSize < 1024 * 1024) {
+ size = 1. + intSize / 1024.;
+ unit = QObject::tr("kB");
+ } else if (intSize < 1024 * 1024 * 1024) {
+ size = 1. + intSize / 1024. / 1024.;
+ unit = QObject::tr("MB");
+ } else {
+ size = 1. + intSize / 1024. / 1024. / 1024.;
+ unit = QObject::tr("GB");
+ }
+
+ size = qRound(size * 10) / 10.0;
+ return QString::fromLatin1("%L1 %2").arg(size, 0, 'g', 4).arg(unit);
+}
+
+
+class DynamicInstallerPage : public PackageManagerPage
+{
+public:
+ explicit DynamicInstallerPage(QWidget *widget, PackageManagerCore *core = 0)
+ : PackageManagerPage(core)
+ , m_widget(widget)
+ {
+ setObjectName(QLatin1String("Dynamic") + widget->objectName());
+ setPixmap(QWizard::LogoPixmap, logoPixmap());
+ setPixmap(QWizard::WatermarkPixmap, QPixmap());
+
+ setLayout(new QVBoxLayout);
+ setSubTitle(QString());
+ setTitle(widget->windowTitle());
+ m_widget->setProperty("complete", true);
+ m_widget->setProperty("final", false);
+ widget->installEventFilter(this);
+ layout()->addWidget(widget);
+ }
+
+ QWidget *widget() const
+ {
+ return m_widget;
+ }
+
+ bool isComplete() const
+ {
+ return m_widget->property("complete").toBool();
+ }
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *event)
+ {
+ if (obj == m_widget) {
+ switch(event->type()) {
+ case QEvent::WindowTitleChange:
+ setTitle(m_widget->windowTitle());
+ break;
+
+ case QEvent::DynamicPropertyChange:
+ emit completeChanged();
+ if (m_widget->property("final").toBool() != isFinalPage())
+ setFinalPage(m_widget->property("final").toBool());
+ break;
+
+ default:
+ break;
+ }
+ }
+ return PackageManagerPage::eventFilter(obj, event);
+ }
+
+private:
+ QWidget *const m_widget;
+};
+
+
+// -- PackageManagerGui::Private
+
+class PackageManagerGui::Private
+{
+public:
+ Private()
+ : m_modified(false)
+ , m_autoSwitchPage(true)
+ , m_showSettingsButton(false)
+ { }
+
+ bool m_modified;
+ bool m_autoSwitchPage;
+ bool m_showSettingsButton;
+ QMap<int, QWizardPage*> m_defaultPages;
+ QMap<int, QString> m_defaultButtonText;
+
+ QScriptValue m_controlScript;
+ QScriptEngine m_controlScriptEngine;
+};
+
+
+// -- PackageManagerGui
+
+QScriptEngine *PackageManagerGui::controlScriptEngine() const
+{
+ return &d->m_controlScriptEngine;
+}
+
+/*!
+ \class QInstaller::PackageManagerGui
+ Is the "gui" object in a none interactive installation
+*/
+PackageManagerGui::PackageManagerGui(PackageManagerCore *core, QWidget *parent)
+ : QWizard(parent)
+ , d(new Private)
+ , m_core(core)
+{
+ if (m_core->isInstaller())
+ setWindowTitle(tr("%1 Setup").arg(m_core->value(scTitle)));
+ else
+ setWindowTitle(tr("Maintain %1").arg(m_core->value(scTitle)));
+
+#ifndef Q_WS_MAC
+ setWindowIcon(QIcon(m_core->settings().icon()));
+#else
+ setPixmap(QWizard::BackgroundPixmap, m_core->settings().background());
+#endif
+#ifdef Q_OS_LINUX
+ setWizardStyle(QWizard::ModernStyle);
+ setSizeGripEnabled(true);
+#endif
+ setOption(QWizard::NoBackButtonOnStartPage);
+ setOption(QWizard::NoBackButtonOnLastPage);
+ setLayout(new QVBoxLayout(this));
+
+ connect(this, SIGNAL(rejected()), m_core, SLOT(setCanceled()));
+ connect(this, SIGNAL(interrupted()), m_core, SLOT(interrupt()));
+
+ // both queued to show the finished page once everything is done
+ connect(m_core, SIGNAL(installationFinished()), this, SLOT(showFinishedPage()), Qt::QueuedConnection);
+ connect(m_core, SIGNAL(uninstallationFinished()), this, SLOT(showFinishedPage()), Qt::QueuedConnection);
+
+ connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(slotCurrentPageChanged(int)));
+ connect(this, SIGNAL(currentIdChanged(int)), m_core, SIGNAL(currentPageChanged(int)));
+ connect(button(QWizard::FinishButton), SIGNAL(clicked()), this, SIGNAL(finishButtonClicked()));
+ connect(button(QWizard::FinishButton), SIGNAL(clicked()), m_core, SIGNAL(finishButtonClicked()));
+
+ // make sure the QUiLoader's retranslateUi is executed first, then the script
+ connect(this, SIGNAL(languageChanged()), m_core, SLOT(languageChanged()), Qt::QueuedConnection);
+ connect(this, SIGNAL(languageChanged()), this, SLOT(onLanguageChanged()), Qt::QueuedConnection);
+
+ connect(m_core, SIGNAL(wizardPageInsertionRequested(QWidget*, QInstaller::PackageManagerCore::WizardPage)),
+ this, SLOT(wizardPageInsertionRequested(QWidget*, QInstaller::PackageManagerCore::WizardPage)));
+ connect(m_core, SIGNAL(wizardPageRemovalRequested(QWidget*)),this,
+ SLOT(wizardPageRemovalRequested(QWidget*)));
+ connect(m_core, SIGNAL(wizardWidgetInsertionRequested(QWidget*, QInstaller::PackageManagerCore::WizardPage)),
+ this, SLOT(wizardWidgetInsertionRequested(QWidget*, QInstaller::PackageManagerCore::WizardPage)));
+ connect(m_core, SIGNAL(wizardWidgetRemovalRequested(QWidget*)), this,
+ SLOT(wizardWidgetRemovalRequested(QWidget*)));
+ connect(m_core, SIGNAL(wizardPageVisibilityChangeRequested(bool, int)), this,
+ SLOT(wizardPageVisibilityChangeRequested(bool, int)), Qt::QueuedConnection);
+
+ connect(m_core, SIGNAL(setAutomatedPageSwitchEnabled(bool)), this,
+ SLOT(setAutomatedPageSwitchEnabled(bool)));
+
+ connect(this, SIGNAL(customButtonClicked(int)), this, SLOT(customButtonClicked(int)));
+
+ for (int i = QWizard::BackButton; i < QWizard::CustomButton1; ++i)
+ d->m_defaultButtonText.insert(i, buttonText(QWizard::WizardButton(i)));
+
+#ifdef Q_WS_MAC
+ resize(sizeHint() * 1.25);
+#else
+ resize(sizeHint());
+#endif
+}
+
+PackageManagerGui::~PackageManagerGui()
+{
+ delete d;
+}
+
+void PackageManagerGui::setAutomatedPageSwitchEnabled(bool request)
+{
+ d->m_autoSwitchPage = request;
+}
+
+QString PackageManagerGui::defaultButtonText(int wizardButton) const
+{
+ return d->m_defaultButtonText.value(wizardButton);
+}
+
+void PackageManagerGui::clickButton(int wb, int delay)
+{
+ if (QAbstractButton *b = button(static_cast<QWizard::WizardButton>(wb) )) {
+ QTimer::singleShot(delay, b, SLOT(click()));
+ } else {
+ // TODO: we should probably abort immediately here (faulty test script)
+ qDebug() << "Button" << wb << "not found!";
+ }
+}
+
+/*!
+ Loads a script to perform the installation non-interactively.
+ @throws QInstaller::Error if the script is not readable/cannot be parsed
+*/
+void PackageManagerGui::loadControlScript(const QString &scriptPath)
+{
+ QFile file(scriptPath);
+ if (!file.open(QIODevice::ReadOnly)) {
+ throw Error(QObject::tr("Could not open the requested script file at %1: %2")
+ .arg(scriptPath, file.errorString()));
+ }
+
+ QScriptValue installerObject = d->m_controlScriptEngine.newQObject(m_core);
+ installerObject.setProperty(QLatin1String("componentByName"), d->m_controlScriptEngine
+ .newFunction(qInstallerComponentByName, 1));
+
+ d->m_controlScriptEngine.globalObject().setProperty(QLatin1String("installer"),
+ installerObject);
+ d->m_controlScriptEngine.globalObject().setProperty(QLatin1String("gui"),
+ d->m_controlScriptEngine.newQObject(this));
+ d->m_controlScriptEngine.globalObject().setProperty(QLatin1String("packagemanagergui"),
+ d->m_controlScriptEngine.newQObject(this));
+ registerMessageBox(&d->m_controlScriptEngine);
+
+#undef REGISTER_BUTTON
+#define REGISTER_BUTTON(x) buttons.setProperty(QLatin1String(#x), \
+ d->m_controlScriptEngine.newVariant(static_cast<int>(QWizard::x)));
+
+ QScriptValue buttons = d->m_controlScriptEngine.newArray();
+ REGISTER_BUTTON(BackButton)
+ REGISTER_BUTTON(NextButton)
+ REGISTER_BUTTON(CommitButton)
+ REGISTER_BUTTON(FinishButton)
+ REGISTER_BUTTON(CancelButton)
+ REGISTER_BUTTON(HelpButton)
+ REGISTER_BUTTON(CustomButton1)
+ REGISTER_BUTTON(CustomButton2)
+ REGISTER_BUTTON(CustomButton3)
+
+#undef REGISTER_BUTTON
+
+ d->m_controlScriptEngine.globalObject().setProperty(QLatin1String("buttons"), buttons);
+
+ d->m_controlScriptEngine.evaluate(QLatin1String(file.readAll()), scriptPath);
+ if (d->m_controlScriptEngine.hasUncaughtException()) {
+ throw Error(QObject::tr("Exception while loading the control script %1")
+ .arg(uncaughtExceptionString(&(d->m_controlScriptEngine)/*, scriptPath*/)));
+ }
+
+ QScriptValue comp = d->m_controlScriptEngine.evaluate(QLatin1String("Controller"));
+ if (d->m_controlScriptEngine.hasUncaughtException()) {
+ throw Error(QObject::tr("Exception while loading the control script %1")
+ .arg(uncaughtExceptionString(&(d->m_controlScriptEngine)/*, scriptPath*/)));
+ }
+
+ d->m_controlScript = comp;
+ d->m_controlScript.construct();
+
+ qDebug() << "Loaded control script" << scriptPath;
+}
+
+void PackageManagerGui::slotCurrentPageChanged(int id)
+{
+ QMetaObject::invokeMethod(this, "delayedControlScriptExecution", Qt::QueuedConnection,
+ Q_ARG(int, id));
+}
+
+void PackageManagerGui::callControlScriptMethod(const QString &methodName)
+{
+ if (!d->m_controlScript.isValid())
+ return;
+
+ QScriptValue method = d->m_controlScript.property(QLatin1String("prototype")).property(methodName);
+
+ if (!method.isValid()) {
+ qDebug() << "Control script callback" << methodName << "does not exist.";
+ return;
+ }
+
+ qDebug() << "Calling control script callback" << methodName;
+
+ method.call(d->m_controlScript);
+
+ if (d->m_controlScriptEngine.hasUncaughtException()) {
+ qCritical()
+ << uncaughtExceptionString(&(d->m_controlScriptEngine) /*, QLatin1String("control script")*/);
+ // TODO: handle error
+ }
+}
+
+void PackageManagerGui::delayedControlScriptExecution(int id)
+{
+ if (PackageManagerPage *const p = qobject_cast<PackageManagerPage*> (page(id)))
+ callControlScriptMethod(p->objectName() + QLatin1String("Callback"));
+}
+
+void PackageManagerGui::onLanguageChanged()
+{
+ d->m_defaultButtonText.clear();
+ for (int i = QWizard::BackButton; i < QWizard::CustomButton1; ++i)
+ d->m_defaultButtonText.insert(i, buttonText(QWizard::WizardButton(i)));
+}
+
+bool PackageManagerGui::event(QEvent *event)
+{
+ switch(event->type()) {
+ case QEvent::LanguageChange:
+ emit languageChanged();
+ break;
+ default:
+ break;
+ }
+ return QWizard::event(event);
+}
+
+void PackageManagerGui::showEvent(QShowEvent *event)
+{
+#ifndef Q_OS_LINUX
+ if (!event->spontaneous()) {
+ foreach (int id, pageIds()) {
+ const QString subTitle = page(id)->subTitle();
+ if (subTitle.isEmpty()) {
+ const QWizard::WizardStyle style = wizardStyle();
+ if ((style == QWizard::ClassicStyle || style == QWizard::ModernStyle))
+ page(id)->setSubTitle(QLatin1String(" ")); // otherwise the colors might screw up
+ }
+ }
+ }
+#endif
+ QWizard::showEvent(event);
+}
+
+void PackageManagerGui::wizardPageInsertionRequested(QWidget *widget,
+ QInstaller::PackageManagerCore::WizardPage page)
+{
+ // just in case it was already in there...
+ wizardPageRemovalRequested(widget);
+
+ int pageId = static_cast<int>(page) - 1;
+ while (QWizard::page(pageId) != 0)
+ --pageId;
+
+ // add it
+ setPage(pageId, new DynamicInstallerPage(widget, m_core));
+}
+
+void PackageManagerGui::wizardPageRemovalRequested(QWidget *widget)
+{
+ foreach (int pageId, pageIds()) {
+ DynamicInstallerPage *const dynamicPage = dynamic_cast<DynamicInstallerPage*>(page(pageId));
+ if (dynamicPage == 0)
+ continue;
+ if (dynamicPage->widget() != widget)
+ continue;
+ removePage(pageId);
+ d->m_defaultPages.remove(pageId);
+ }
+}
+
+void PackageManagerGui::wizardWidgetInsertionRequested(QWidget *widget,
+ QInstaller::PackageManagerCore::WizardPage page)
+{
+ Q_ASSERT(widget);
+ if (QWizardPage *const p = QWizard::page(page))
+ p->layout()->addWidget(widget);
+}
+
+void PackageManagerGui::wizardWidgetRemovalRequested(QWidget *widget)
+{
+ Q_ASSERT(widget);
+ widget->setParent(0);
+}
+
+void PackageManagerGui::wizardPageVisibilityChangeRequested(bool visible, int p)
+{
+ if (visible && page(p) == 0) {
+ setPage(p, d->m_defaultPages[p]);
+ } else if (!visible && page(p) != 0) {
+ d->m_defaultPages[p] = page(p);
+ removePage(p);
+ }
+}
+
+PackageManagerPage *PackageManagerGui::page(int pageId) const
+{
+ return qobject_cast<PackageManagerPage*> (QWizard::page(pageId));
+}
+
+QWidget *PackageManagerGui::pageWidgetByObjectName(const QString &name) const
+{
+ const QList<int> ids = pageIds();
+ foreach (const int i, ids) {
+ PackageManagerPage *const p = qobject_cast<PackageManagerPage*> (page(i));
+ if (p && p->objectName() == name) {
+ // For dynamic pages, return the contained widget (as read from the UI file), not the
+ // wrapper page
+ if (DynamicInstallerPage *dp = dynamic_cast<DynamicInstallerPage*>(p))
+ return dp->widget();
+ return p;
+ }
+ }
+ qDebug() << "No page found for object name" << name;
+ return 0;
+}
+
+QWidget *PackageManagerGui::currentPageWidget() const
+{
+ return currentPage();
+}
+
+void PackageManagerGui::cancelButtonClicked()
+{
+ if (currentId() != PackageManagerCore::Introduction
+ && currentId() != PackageManagerCore::InstallationFinished) {
+ PackageManagerPage *const page = qobject_cast<PackageManagerPage*> (currentPage());
+ if (page && page->isInterruptible() && m_core->status() != PackageManagerCore::Canceled
+ && m_core->status() != PackageManagerCore::Failure) {
+ const QMessageBox::StandardButton bt =
+ MessageBoxHandler::question(MessageBoxHandler::currentBestSuitParent(),
+ QLatin1String("cancelInstallation"), tr("Question"),
+ tr("Do you want to abort the %1 process?").arg(m_core->isUninstaller() ? tr("uninstallation")
+ : tr("installation")), QMessageBox::Yes | QMessageBox::No);
+ if (bt == QMessageBox::Yes)
+ emit interrupted();
+ } else {
+ QString app = tr("installer");
+ if (m_core->isUninstaller())
+ app = tr("uninstaller");
+ if (m_core->isUpdater() || m_core->isPackageManager())
+ app = tr("maintenance");
+
+ const QMessageBox::StandardButton bt =
+ MessageBoxHandler::question(MessageBoxHandler::currentBestSuitParent(),
+ QLatin1String("cancelInstallation"), tr("Question"),
+ tr("Do you want to quit the %1 application?").arg(app), QMessageBox::Yes | QMessageBox::No);
+ if (bt == QMessageBox::Yes)
+ QDialog::reject();
+ }
+ } else {
+ QDialog::reject();
+ }
+}
+
+void PackageManagerGui::rejectWithoutPrompt()
+{
+ m_core->setCanceled();
+ QDialog::reject();
+}
+
+void PackageManagerGui::reject()
+{
+ cancelButtonClicked();
+}
+
+void PackageManagerGui::setModified(bool value)
+{
+ d->m_modified = value;
+}
+
+void PackageManagerGui::showFinishedPage()
+{
+ qDebug() << "SHOW FINISHED PAGE";
+ if (d->m_autoSwitchPage)
+ next();
+ else
+ qobject_cast<QPushButton*>(button(QWizard::CancelButton))->setEnabled(false);
+}
+
+void PackageManagerGui::showSettingsButton(bool show)
+{
+ if (d->m_showSettingsButton == show)
+ return;
+
+ d->m_showSettingsButton = show;
+ setOption(QWizard::HaveCustomButton1, show);
+ setButtonText(QWizard::CustomButton1, tr("Settings"));
+
+ updateButtonLayout();
+}
+
+/*!
+ Force an update of our own button layout, needs to be called whenever a button option has been set.
+*/
+void PackageManagerGui::updateButtonLayout()
+{
+ QVector<QWizard::WizardButton> buttons(12, QWizard::NoButton);
+ if (options() & QWizard::HaveHelpButton)
+ buttons[(options() & QWizard::HelpButtonOnRight) ? 11 : 0] = QWizard::HelpButton;
+
+ buttons[1] = QWizard::Stretch;
+ if (options() & QWizard::HaveCustomButton1) {
+ buttons[1] = QWizard::CustomButton1;
+ buttons[2] = QWizard::Stretch;
+ }
+
+ if (options() & QWizard::HaveCustomButton2)
+ buttons[3] = QWizard::CustomButton2;
+
+ if (options() & QWizard::HaveCustomButton3)
+ buttons[4] = QWizard::CustomButton3;
+
+ if (!(options() & QWizard::NoCancelButton))
+ buttons[(options() & QWizard::CancelButtonOnLeft) ? 5 : 10] = QWizard::CancelButton;
+
+ buttons[6] = QWizard::BackButton;
+ buttons[7] = QWizard::NextButton;
+ buttons[8] = QWizard::CommitButton;
+ buttons[9] = QWizard::FinishButton;
+
+ setOption(QWizard::NoBackButtonOnLastPage, true);
+ setOption(QWizard::NoBackButtonOnStartPage, true);
+
+ setButtonLayout(buttons.toList());
+}
+
+void PackageManagerGui::setSettingsButtonEnabled(bool enabled)
+{
+ if (QAbstractButton *btn = button(QWizard::CustomButton1))
+ btn->setEnabled(enabled);
+}
+
+void PackageManagerGui::customButtonClicked(int which)
+{
+ if (QWizard::WizardButton(which) == QWizard::CustomButton1 && d->m_showSettingsButton)
+ emit settingsButtonClicked();
+}
+
+
+// -- PackageManagerPage
+
+PackageManagerPage::PackageManagerPage(PackageManagerCore *core)
+ : m_fresh(true)
+ , m_complete(true)
+ , m_core(core)
+{
+}
+
+PackageManagerCore *PackageManagerPage::packageManagerCore() const
+{
+ return m_core;
+}
+
+QVariantHash PackageManagerPage::elementsForPage(const QString &pageName) const
+{
+ const QVariant variant = m_core->settings().value(pageName);
+
+ QVariantHash hash;
+ if (variant.canConvert<QVariantHash>())
+ hash = variant.value<QVariantHash>();
+ return hash;
+}
+
+QString PackageManagerPage::titleForPage(const QString &pageName, const QString &value) const
+{
+ return titleFromHash(m_core->settings().titlesForPage(pageName), value);
+}
+
+QString PackageManagerPage::subTitleForPage(const QString &pageName, const QString &value) const
+{
+ return titleFromHash(m_core->settings().subTitlesForPage(pageName), value);
+}
+
+QString PackageManagerPage::titleFromHash(const QVariantHash &hash, const QString &value) const
+{
+ QString defaultValue = hash.value(QLatin1String("Default")).toString();
+ if (defaultValue.isEmpty())
+ defaultValue = value;
+
+ if (m_core->isUpdater())
+ return hash.value(QLatin1String("Updater"), defaultValue).toString();
+ if (m_core->isInstaller())
+ return hash.value(QLatin1String("Installer"), defaultValue).toString();
+ if (m_core->isPackageManager())
+ return hash.value(QLatin1String("PackageManager"), defaultValue).toString();
+ return hash.value(QLatin1String("Uninstaller"), defaultValue).toString();
+}
+
+QPixmap PackageManagerPage::watermarkPixmap() const
+{
+ return QPixmap(m_core->value(QLatin1String("WatermarkPixmap")));
+}
+
+QPixmap PackageManagerPage::logoPixmap() const
+{
+ return QPixmap(m_core->value(QLatin1String("LogoPixmap")));
+}
+
+QString PackageManagerPage::productName() const
+{
+ return m_core->value(QLatin1String("ProductName"));
+}
+
+bool PackageManagerPage::isComplete() const
+{
+ return m_complete;
+}
+
+void PackageManagerPage::setComplete(bool complete)
+{
+ m_complete = complete;
+ if (QWizard *w = wizard()) {
+ if (QAbstractButton *cancel = w->button(QWizard::CancelButton)) {
+ if (cancel->hasFocus()) {
+ if (QAbstractButton *next = w->button(QWizard::NextButton))
+ next->setFocus();
+ }
+ }
+ }
+ emit completeChanged();
+}
+
+void PackageManagerPage::insertWidget(QWidget *widget, const QString &siblingName, int offset)
+{
+ QWidget *sibling = findChild<QWidget *>(siblingName);
+ QWidget *parent = sibling ? sibling->parentWidget() : 0;
+ QLayout *layout = parent ? parent->layout() : 0;
+ QBoxLayout *blayout = qobject_cast<QBoxLayout *>(layout);
+
+ if (blayout) {
+ const int index = blayout->indexOf(sibling) + offset;
+ blayout->insertWidget(index, widget);
+ }
+}
+
+QWidget *PackageManagerPage::findWidget(const QString &objectName) const
+{
+ return findChild<QWidget*> (objectName);
+}
+
+/*!
+ \reimp
+ \Overwritten to support some kind of initializePage() in the case the wizard has been set
+ to QWizard::IndependentPages. If that option has been set, initializePage() would be only called
+ once. So we provide entering() and leaving() based on this overwritten function.
+*/
+void PackageManagerPage::setVisible(bool visible)
+{
+ QWizardPage::setVisible(visible);
+ qApp->processEvents();
+
+ if (m_fresh && !visible) {
+ // this is only hit once when the page gets added to the wizard
+ m_fresh = false;
+ return;
+ }
+
+ if (visible)
+ entering();
+ else
+ leaving();
+}
+
+int PackageManagerPage::nextId() const
+{
+ return QWizardPage::nextId();
+}
+
+
+// -- IntroductionPage
+
+IntroductionPage::IntroductionPage(PackageManagerCore *core)
+ : PackageManagerPage(core)
+ , m_widget(0)
+{
+ setObjectName(QLatin1String("IntroductionPage"));
+ setPixmap(QWizard::WatermarkPixmap, watermarkPixmap());
+ setSubTitle(subTitleForPage(QLatin1String("IntroductionPage")));
+ setTitle(titleForPage(QLatin1String("IntroductionPage"), tr("Setup - %1")).arg(productName()));
+
+ m_msgLabel = new QLabel(this);
+ m_msgLabel->setWordWrap(true);
+ m_msgLabel->setObjectName(QLatin1String("MessageLabel"));
+ const QVariantHash hash = elementsForPage(QLatin1String("IntroductionPage"));
+ m_msgLabel->setText(hash.value(QLatin1String("MessageLabel"), tr("Welcome to the %1 "
+ "Setup Wizard.")).toString().arg(productName()));
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ setLayout(layout);
+ layout->addWidget(m_msgLabel);
+ layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
+}
+
+void IntroductionPage::setWidget(QWidget *widget)
+{
+ if (m_widget) {
+ layout()->removeWidget(m_widget);
+ delete m_widget;
+ }
+ m_widget = widget;
+ if (m_widget)
+ static_cast<QVBoxLayout*>(layout())->addWidget(m_widget, 1);
+}
+
+void IntroductionPage::setText(const QString &text)
+{
+ m_msgLabel->setText(text);
+}
+
+
+// -- LicenseAgreementPage::ClickForwarder
+
+class LicenseAgreementPage::ClickForwarder : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit ClickForwarder(QAbstractButton *button)
+ : QObject(button)
+ , m_abstractButton(button) {}
+
+protected:
+ bool eventFilter(QObject *object, QEvent *event)
+ {
+ if (event->type() == QEvent::MouseButtonRelease) {
+ m_abstractButton->click();
+ return true;
+ }
+ // standard event processing
+ return QObject::eventFilter(object, event);
+ }
+private:
+ QAbstractButton *m_abstractButton;
+};
+
+
+// -- LicenseAgreementPage
+
+LicenseAgreementPage::LicenseAgreementPage(PackageManagerCore *core)
+ : PackageManagerPage(core)
+{
+ setPixmap(QWizard::LogoPixmap, logoPixmap());
+ setPixmap(QWizard::WatermarkPixmap, QPixmap());
+ setObjectName(QLatin1String("LicenseAgreementPage"));
+ setTitle(titleForPage(QLatin1String("LicenseAgreementPage"), tr("License Agreement")));
+ setSubTitle(subTitleForPage(QLatin1String("LicenseAgreementPage"), tr("Please read the following license "
+ "agreement(s). You must accept the terms contained in these agreement(s) before continuing with the "
+ "installation.")));
+
+ m_licenseListWidget = new QListWidget(this);
+ m_licenseListWidget->setObjectName(QLatin1String("LicenseListWidget"));
+ m_licenseListWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
+ connect(m_licenseListWidget, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
+ this, SLOT(currentItemChanged(QListWidgetItem *)));
+
+ m_textBrowser = new QTextBrowser(this);
+ m_textBrowser->setReadOnly(true);
+ m_textBrowser->setOpenLinks(false);
+ m_textBrowser->setOpenExternalLinks(true);
+ m_textBrowser->setObjectName(QLatin1String("LicenseTextBrowser"));
+ m_textBrowser->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
+ connect(m_textBrowser, SIGNAL(anchorClicked(QUrl)), this, SLOT(openLicenseUrl(QUrl)));
+
+ QHBoxLayout *licenseBoxLayout = new QHBoxLayout();
+ licenseBoxLayout->addWidget(m_licenseListWidget);
+ licenseBoxLayout->addWidget(m_textBrowser);
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->addLayout(licenseBoxLayout);
+
+ m_acceptRadioButton = new QRadioButton(this);
+ m_acceptRadioButton->setShortcut(QKeySequence(tr("Alt+A", "agree license")));
+ m_acceptRadioButton->setObjectName(QLatin1String("AcceptLicenseRadioButton"));
+ ClickForwarder *acceptClickForwarder = new ClickForwarder(m_acceptRadioButton);
+
+ QLabel *acceptLabel = new QLabel;
+ acceptLabel->setWordWrap(true);
+ acceptLabel->installEventFilter(acceptClickForwarder);
+ acceptLabel->setObjectName(QLatin1String("AcceptLicenseLabel"));
+ acceptLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
+ const QVariantHash hash = elementsForPage(QLatin1String("LicenseAgreementPage"));
+ acceptLabel->setText(hash.value(QLatin1String("AcceptLicenseLabel"), tr("I accept the licenses.")).toString());
+
+ m_rejectRadioButton = new QRadioButton(this);
+ ClickForwarder *rejectClickForwarder = new ClickForwarder(m_rejectRadioButton);
+ m_rejectRadioButton->setObjectName(QString::fromUtf8("RejectLicenseRadioButton"));
+ m_rejectRadioButton->setShortcut(QKeySequence(tr("Alt+D", "do not agree license")));
+
+ QLabel *rejectLabel = new QLabel;
+ rejectLabel->setWordWrap(true);
+ rejectLabel->installEventFilter(rejectClickForwarder);
+ rejectLabel->setObjectName(QLatin1String("RejectLicenseLabel"));
+ rejectLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
+ rejectLabel->setText(hash.value(QLatin1String("RejectLicenseLabel"), tr("I do not accept the licenses.")).toString());
+
+#if defined(Q_WS_X11) || defined(Q_WS_MAC)
+ QFont labelFont(font());
+ labelFont.setPixelSize(9);
+ acceptLabel->setFont(labelFont);
+ rejectLabel->setFont(labelFont);
+#endif
+
+ QGridLayout *gridLayout = new QGridLayout;
+ gridLayout->setColumnStretch(1, 1);
+ gridLayout->addWidget(m_acceptRadioButton, 0, 0);
+ gridLayout->addWidget(acceptLabel, 0, 1);
+ gridLayout->addWidget(m_rejectRadioButton, 1, 0);
+ gridLayout->addWidget(rejectLabel, 1, 1);
+ layout->addLayout(gridLayout);
+
+ connect(m_acceptRadioButton, SIGNAL(toggled(bool)), this, SIGNAL(completeChanged()));
+ connect(m_rejectRadioButton, SIGNAL(toggled(bool)), this, SIGNAL(completeChanged()));
+
+ m_rejectRadioButton->setChecked(true);
+}
+
+void LicenseAgreementPage::entering()
+{
+ m_licenseListWidget->clear();
+ m_textBrowser->setText(QString());
+ m_licenseListWidget->setVisible(false);
+
+ packageManagerCore()->calculateComponentsToInstall();
+ foreach (QInstaller::Component *component, packageManagerCore()->orderedComponentsToInstall())
+ addLicenseItem(component->licenses());
+
+ const int licenseCount = m_licenseListWidget->count();
+ if (licenseCount > 0) {
+ m_licenseListWidget->setVisible(licenseCount > 1);
+ m_licenseListWidget->setCurrentItem(m_licenseListWidget->item(0));
+ }
+}
+
+bool LicenseAgreementPage::isComplete() const
+{
+ return m_acceptRadioButton->isChecked();
+}
+
+void LicenseAgreementPage::openLicenseUrl(const QUrl &url)
+{
+ QDesktopServices::openUrl(url);
+}
+
+void LicenseAgreementPage::currentItemChanged(QListWidgetItem *current)
+{
+ if (current)
+ m_textBrowser->setText(current->data(Qt::UserRole).toString());
+}
+
+void LicenseAgreementPage::addLicenseItem(const QHash<QString, QPair<QString, QString> > &hash)
+{
+ for (QHash<QString, QPair<QString, QString> >::const_iterator it = hash.begin();
+ it != hash.end(); ++it) {
+ QListWidgetItem *item = new QListWidgetItem(it.key(), m_licenseListWidget);
+ item->setData(Qt::UserRole, it.value().second);
+ }
+}
+
+
+// -- ComponentSelectionPage::Private
+
+class ComponentSelectionPage::Private : public QObject
+{
+ Q_OBJECT
+
+public:
+ Private(ComponentSelectionPage *qq, PackageManagerCore *core)
+ : q(qq)
+ , m_core(core)
+ , m_treeView(new QTreeView(q))
+ , m_allModel(new ComponentModel(4, m_core))
+ , m_updaterModel(new ComponentModel(4, m_core))
+ {
+ m_treeView->setObjectName(QLatin1String("ComponentsTreeView"));
+ m_allModel->setObjectName(QLatin1String("AllComponentsModel"));
+ m_updaterModel->setObjectName(QLatin1String("UpdaterComponentsModel"));
+
+ int i = 0;
+ m_currentModel = m_allModel;
+ ComponentModel *list[] = { m_allModel, m_updaterModel, 0 };
+ while (ComponentModel *model = list[i++]) {
+ connect(model, SIGNAL(defaultCheckStateChanged(bool)), q, SLOT(setModified(bool)));
+ connect(model, SIGNAL(defaultCheckStateChanged(bool)), m_core,
+ SLOT(componentsToInstallNeedsRecalculation()));
+
+ model->setHeaderData(ComponentModelHelper::NameColumn, Qt::Horizontal, ComponentSelectionPage::tr("Component Name"));
+ model->setHeaderData(ComponentModelHelper::InstalledVersionColumn, Qt::Horizontal,
+ ComponentSelectionPage::tr("Installed Version"));
+ model->setHeaderData(ComponentModelHelper::NewVersionColumn, Qt::Horizontal, ComponentSelectionPage::tr("New Version"));
+ model->setHeaderData(ComponentModelHelper::UncompressedSizeColumn, Qt::Horizontal, ComponentSelectionPage::tr("Size"));
+ }
+
+ QHBoxLayout *hlayout = new QHBoxLayout;
+ hlayout->addWidget(m_treeView, 3);
+
+ m_descriptionLabel = new QLabel(q);
+ m_descriptionLabel->setWordWrap(true);
+ m_descriptionLabel->setObjectName(QLatin1String("ComponentDescriptionLabel"));
+
+ QVBoxLayout *vlayout = new QVBoxLayout;
+ vlayout->addWidget(m_descriptionLabel);
+
+ m_sizeLabel = new QLabel(q);
+ m_sizeLabel->setWordWrap(true);
+ vlayout->addWidget(m_sizeLabel);
+ m_sizeLabel->setObjectName(QLatin1String("ComponentSizeLabel"));
+
+ vlayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::MinimumExpanding,
+ QSizePolicy::MinimumExpanding));
+ hlayout->addLayout(vlayout, 2);
+
+ QVBoxLayout *layout = new QVBoxLayout(q);
+ layout->addLayout(hlayout, 1);
+
+ m_checkDefault = new QPushButton;
+ connect(m_checkDefault, SIGNAL(clicked()), this, SLOT(selectDefault()));
+ connect(m_allModel, SIGNAL(defaultCheckStateChanged(bool)), m_checkDefault, SLOT(setEnabled(bool)));
+ const QVariantHash hash = q->elementsForPage(QLatin1String("ComponentSelectionPage"));
+ if (m_core->isInstaller()) {
+ m_checkDefault->setObjectName(QLatin1String("SelectDefaultComponentsButton"));
+ m_checkDefault->setShortcut(QKeySequence(ComponentSelectionPage::tr("Alt+A", "select default components")));
+ m_checkDefault->setText(hash.value(QLatin1String("SelectDefaultComponentsButton"), ComponentSelectionPage::tr("Def&ault"))
+ .toString());
+ } else {
+ m_checkDefault->setEnabled(false);
+ m_checkDefault->setObjectName(QLatin1String("ResetComponentsButton"));
+ m_checkDefault->setShortcut(QKeySequence(ComponentSelectionPage::tr("Alt+R", "reset to already installed components")));
+ m_checkDefault->setText(hash.value(QLatin1String("ResetComponentsButton"), ComponentSelectionPage::tr("&Reset")).toString());
+ }
+ hlayout = new QHBoxLayout;
+ hlayout->addWidget(m_checkDefault);
+
+ m_checkAll = new QPushButton;
+ hlayout->addWidget(m_checkAll);
+ connect(m_checkAll, SIGNAL(clicked()), this, SLOT(selectAll()));
+ m_checkAll->setObjectName(QLatin1String("SelectAllComponentsButton"));
+ m_checkAll->setShortcut(QKeySequence(ComponentSelectionPage::tr("Alt+S", "select all components")));
+ m_checkAll->setText(hash.value(QLatin1String("SelectAllComponentsButton"), ComponentSelectionPage::tr("&Select All")).toString());
+
+ m_uncheckAll = new QPushButton;
+ hlayout->addWidget(m_uncheckAll);
+ connect(m_uncheckAll, SIGNAL(clicked()), this, SLOT(deselectAll()));
+ m_uncheckAll->setObjectName(QLatin1String("DeselectAllComponentsButton"));
+ m_uncheckAll->setShortcut(QKeySequence(ComponentSelectionPage::tr("Alt+D", "deselect all components")));
+ m_uncheckAll->setText(hash.value(QLatin1String("DeselectAllComponentsButton"), ComponentSelectionPage::tr("&Deselect All"))
+ .toString());
+
+ hlayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::MinimumExpanding,
+ QSizePolicy::MinimumExpanding));
+ layout->addLayout(hlayout);
+
+ connect(m_core, SIGNAL(finishAllComponentsReset()), this, SLOT(allComponentsChanged()),
+ Qt::QueuedConnection);
+ connect(m_core, SIGNAL(finishUpdaterComponentsReset()), this, SLOT(updaterComponentsChanged()),
+ Qt::QueuedConnection);
+ }
+
+ void updateTreeView()
+ {
+ m_checkDefault->setVisible(m_core->isInstaller() || m_core->isPackageManager());
+ if (m_treeView->selectionModel()) {
+ disconnect(m_treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
+ this, SLOT(currentChanged(QModelIndex)));
+ disconnect(m_currentModel, SIGNAL(checkStateChanged(QModelIndex)), this,
+ SLOT(currentChanged(QModelIndex)));
+ }
+
+ m_currentModel = m_core->isUpdater() ? m_updaterModel : m_allModel;
+ m_treeView->setModel(m_currentModel);
+ m_treeView->setExpanded(m_currentModel->index(0, 0), true);
+
+ if (m_core->isInstaller()) {
+ m_treeView->setHeaderHidden(true);
+ for (int i = 1; i < m_currentModel->columnCount(); ++i)
+ m_treeView->hideColumn(i);
+ } else {
+ m_treeView->header()->setStretchLastSection(true);
+ for (int i = 0; i < m_currentModel->columnCount(); ++i)
+ m_treeView->resizeColumnToContents(i);
+ }
+
+ bool hasChildren = false;
+ const int rowCount = m_currentModel->rowCount();
+ for (int row = 0; row < rowCount && !hasChildren; ++row)
+ hasChildren = m_currentModel->hasChildren(m_currentModel->index(row, 0));
+ m_treeView->setRootIsDecorated(hasChildren);
+
+ connect(m_treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
+ this, SLOT(currentChanged(QModelIndex)));
+ connect(m_currentModel, SIGNAL(checkStateChanged(QModelIndex)), this,
+ SLOT(currentChanged(QModelIndex)));
+
+ m_treeView->setCurrentIndex(m_currentModel->index(0, 0));
+ }
+
+public slots:
+ void currentChanged(const QModelIndex &current)
+ {
+ // if there is not selection or the current selected node didn't change, return
+ if (!current.isValid() || current != m_treeView->selectionModel()->currentIndex())
+ return;
+
+ m_descriptionLabel->setText(m_currentModel->data(m_currentModel->index(current.row(),
+ ComponentModelHelper::NameColumn, current.parent()), Qt::ToolTipRole).toString());
+
+ m_sizeLabel->clear();
+ if (!m_core->isUninstaller()) {
+ Component *component = m_currentModel->componentFromIndex(current);
+ if (component && component->updateUncompressedSize() > 0) {
+ const QVariantHash hash = q->elementsForPage(QLatin1String("ComponentSelectionPage"));
+ m_sizeLabel->setText(hash.value(QLatin1String("ComponentSizeLabel"),
+ ComponentSelectionPage::tr("This component will occupy approximately %1 on your hard disk drive.")).toString()
+ .arg(m_currentModel->data(m_currentModel->index(current.row(),
+ ComponentModelHelper::UncompressedSizeColumn, current.parent())).toString()));
+ }
+ }
+ }
+
+ void selectAll()
+ {
+ m_currentModel->selectAll();
+
+ m_checkAll->setEnabled(!m_currentModel->hasCheckedComponents());
+ m_uncheckAll->setEnabled(m_currentModel->hasCheckedComponents());
+ }
+
+ void deselectAll()
+ {
+ m_currentModel->deselectAll();
+
+ m_checkAll->setEnabled(m_currentModel->hasCheckedComponents());
+ m_uncheckAll->setEnabled(!m_currentModel->hasCheckedComponents());
+ }
+
+ void selectDefault()
+ {
+ m_currentModel->selectDefault();
+
+ // Do not apply special magic here to keep the enabled/ disabled state in sync with the checked
+ // components. We would need to implement the counter in the model, which has an unnecessary impact
+ // on the complexity and amount of code compared to what we gain in functionality.
+ m_checkAll->setEnabled(true);
+ m_uncheckAll->setEnabled(true);
+ }
+
+private slots:
+ void allComponentsChanged()
+ {
+ m_allModel->setRootComponents(m_core->rootComponents());
+ }
+
+ void updaterComponentsChanged()
+ {
+ m_updaterModel->setRootComponents(m_core->updaterComponents());
+ }
+
+public:
+ ComponentSelectionPage *q;
+ PackageManagerCore *m_core;
+ QTreeView *m_treeView;
+ ComponentModel *m_allModel;
+ ComponentModel *m_updaterModel;
+ ComponentModel *m_currentModel;
+ QLabel *m_sizeLabel;
+ QLabel *m_descriptionLabel;
+ QPushButton *m_checkAll;
+ QPushButton *m_uncheckAll;
+ QPushButton *m_checkDefault;
+};
+
+
+// -- ComponentSelectionPage
+
+/*!
+ \class QInstaller::ComponentSelectionPage
+ On this page the user can select and deselect what he wants to be installed.
+*/
+ComponentSelectionPage::ComponentSelectionPage(PackageManagerCore *core)
+ : PackageManagerPage(core)
+ , d(new Private(this, core))
+{
+ setPixmap(QWizard::LogoPixmap, logoPixmap());
+ setPixmap(QWizard::WatermarkPixmap, QPixmap());
+ setObjectName(QLatin1String("ComponentSelectionPage"));
+ setTitle(titleForPage(QLatin1String("ComponentSelectionPage"), tr("Select Components")));
+}
+
+ComponentSelectionPage::~ComponentSelectionPage()
+{
+ delete d;
+}
+
+void ComponentSelectionPage::entering()
+{
+ static const char *strings[] = {
+ QT_TR_NOOP("Please select the components you want to update."),
+ QT_TR_NOOP("Please select the components you want to install."),
+ QT_TR_NOOP("Please select the components you want to uninstall."),
+ QT_TR_NOOP("Select the components to install. Deselect installed components to uninstall them.")
+ };
+
+ int index = 0;
+ PackageManagerCore *core = packageManagerCore();
+ if (core->isInstaller()) index = 1;
+ if (core->isUninstaller()) index = 2;
+ if (core->isPackageManager()) index = 3;
+ setSubTitle(subTitleForPage(QLatin1String("ComponentSelectionPage"), tr(strings[index])));
+
+ d->updateTreeView();
+ setModified(isComplete());
+}
+
+void ComponentSelectionPage::showEvent(QShowEvent *event)
+{
+ // remove once we deprecate isSelected, setSelected etc...
+ if (!event->spontaneous())
+ packageManagerCore()->resetComponentsToUserCheckedState();
+ QWizardPage::showEvent(event);
+}
+
+void ComponentSelectionPage::selectAll()
+{
+ d->selectAll();
+}
+
+void ComponentSelectionPage::deselectAll()
+{
+ d->deselectAll();
+}
+
+void ComponentSelectionPage::selectDefault()
+{
+ if (packageManagerCore()->isInstaller())
+ d->selectDefault();
+}
+
+/*!
+ Selects the component with /a id in the component tree.
+*/
+void ComponentSelectionPage::selectComponent(const QString &id)
+{
+ const QModelIndex &idx = d->m_currentModel->indexFromComponentName(id);
+ if (idx.isValid())
+ d->m_currentModel->setData(idx, Qt::Checked, Qt::CheckStateRole);
+}
+
+/*!
+ Deselects the component with /a id in the component tree.
+*/
+void ComponentSelectionPage::deselectComponent(const QString &id)
+{
+ const QModelIndex &idx = d->m_currentModel->indexFromComponentName(id);
+ if (idx.isValid())
+ d->m_currentModel->setData(idx, Qt::Unchecked, Qt::CheckStateRole);
+}
+
+void ComponentSelectionPage::setModified(bool modified)
+{
+ setComplete(modified);
+}
+
+bool ComponentSelectionPage::isComplete() const
+{
+ if (packageManagerCore()->isInstaller() || packageManagerCore()->isUpdater())
+ return d->m_currentModel->hasCheckedComponents();
+ return !d->m_currentModel->defaultCheckState();
+}
+
+
+// -- TargetDirectoryPage
+
+TargetDirectoryPage::TargetDirectoryPage(PackageManagerCore *core)
+ : PackageManagerPage(core)
+{
+ setPixmap(QWizard::LogoPixmap, logoPixmap());
+ setPixmap(QWizard::WatermarkPixmap, QPixmap());
+ setObjectName(QLatin1String("TargetDirectoryPage"));
+ setSubTitle(subTitleForPage(QLatin1String("TargetDirectoryPage")));
+ setTitle(titleForPage(QLatin1String("TargetDirectoryPage"), tr("Installation Folder")));
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+
+ QLabel *msgLabel = new QLabel(this);
+ msgLabel->setWordWrap(true);
+ msgLabel->setObjectName(QLatin1String("MessageLabel"));
+ const QVariantHash hash = elementsForPage(QLatin1String("TargetDirectoryPage"));
+ msgLabel->setText(hash.value(QLatin1String("MessageLabel"), tr("Please specify the folder "
+ "where %1 will be installed.")).toString().arg(productName()));
+ layout->addWidget(msgLabel);
+
+ QHBoxLayout *hlayout = new QHBoxLayout;
+
+ m_lineEdit = new QLineEdit(this);
+ m_lineEdit->setObjectName(QLatin1String("TargetDirectoryLineEdit"));
+ connect(m_lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(completeChanged()));
+ hlayout->addWidget(m_lineEdit);
+
+ QPushButton *browseButton = new QPushButton(this);
+ browseButton->setObjectName(QLatin1String("BrowseDirectoryButton"));
+ connect(browseButton, SIGNAL(clicked()), this, SLOT(dirRequested()));
+ browseButton->setShortcut(QKeySequence(tr("Alt+R", "browse file system to choose a file")));
+ browseButton->setText(hash.value(QLatin1String("BrowseDirectoryButton"), tr("B&rowse..."))
+ .toString());
+ hlayout->addWidget(browseButton);
+
+ layout->addLayout(hlayout);
+ setLayout(layout);
+}
+
+QString TargetDirectoryPage::targetDir() const
+{
+ return m_lineEdit->text();
+}
+
+void TargetDirectoryPage::setTargetDir(const QString &dirName)
+{
+ m_lineEdit->setText(dirName);
+}
+
+void TargetDirectoryPage::initializePage()
+{
+ QString targetDir = packageManagerCore()->value(scTargetDir);
+ if (targetDir.isEmpty()) {
+ targetDir = QDir::homePath() + QDir::separator();
+ // prevent spaces in the default target directory
+ if (targetDir.contains(QLatin1Char(' ')))
+ targetDir = QDir::rootPath();
+ targetDir += productName().remove(QLatin1Char(' '));
+ }
+ m_lineEdit->setText(QDir::toNativeSeparators(QDir(targetDir).absolutePath()));
+
+ PackageManagerPage::initializePage();
+}
+
+bool TargetDirectoryPage::validatePage()
+{
+ const QVariantHash hash = elementsForPage(QLatin1String("TargetDirectoryPage"));
+ if (targetDir().isEmpty()) {
+ MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(),
+ QLatin1String("EmptyTargetDirectoryMessage"), tr("Error"), hash
+ .value(QLatin1String("EmptyTargetDirectoryMessage"), tr("The install directory cannot be "
+ "empty, please specify a valid folder.")).toString(), QMessageBox::Ok);
+ return false;
+ }
+
+ const QDir dir(targetDir());
+ // it exists, but is empty (might be created by the Browse button (getExistingDirectory)
+ if (dir.exists() && dir.entryList(QDir::NoDotAndDotDot).isEmpty())
+ return true;
+
+ if (dir.exists() && dir.isReadable()) {
+ // it exists, but is not empty
+ if (dir == QDir::root()) {
+ MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(),
+ QLatin1String("ForbiddenTargetDirectoryMessage"), tr("Error"), hash
+ .value(QLatin1String("ForbiddenTargetDirectoryMessage"), tr("As the install directory is "
+ "completely deleted, installing in %1 is forbidden.")).toString().arg(QDir::rootPath()),
+ QMessageBox::Ok);
+ return false;
+ }
+
+ if (!QVariant(packageManagerCore()->value(scRemoveTargetDir)).toBool())
+ return true;
+
+ return MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(),
+ QLatin1String("OverwriteTargetDirectoryMessage"), tr("Warning"), hash
+ .value(QLatin1String("OverwriteTargetDirectoryMessage"), tr("You have selected an existing, "
+ "non-empty folder for installation. Note that it will be completely wiped on uninstallation of "
+ "this application. It is not advisable to install into this folder as installation might fail. "
+ "Do you want to continue?")).toString(), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes;
+ }
+ return true;
+}
+
+void TargetDirectoryPage::entering()
+{
+}
+
+void TargetDirectoryPage::leaving()
+{
+ packageManagerCore()->setValue(scTargetDir, targetDir());
+}
+
+void TargetDirectoryPage::targetDirSelected()
+{
+}
+
+void TargetDirectoryPage::dirRequested()
+{
+ const QVariantHash hash = elementsForPage(QLatin1String("TargetDirectoryPage"));
+ const QString newDirName = QFileDialog::getExistingDirectory(this, hash
+ .value(QLatin1String("SelectInstallationFolderCaption"), tr("Select Installation Folder")).toString(),
+ targetDir());
+ if (newDirName.isEmpty() || newDirName == targetDir())
+ return;
+ m_lineEdit->setText(QDir::toNativeSeparators(newDirName));
+}
+
+
+// -- StartMenuDirectoryPage
+
+StartMenuDirectoryPage::StartMenuDirectoryPage(PackageManagerCore *core)
+ : PackageManagerPage(core)
+{
+ setPixmap(QWizard::LogoPixmap, logoPixmap());
+ setPixmap(QWizard::WatermarkPixmap, QPixmap());
+ setObjectName(QLatin1String("StartMenuDirectoryPage"));
+ setTitle(titleForPage(QLatin1String("StartMenuDirectoryPage"), tr("Start Menu shortcuts")));
+ setSubTitle(subTitleForPage(QLatin1String("StartMenuDirectoryPage"), tr("Select the Start Menu in which "
+ "you would like to create the program's shortcuts. You can also enter a name to create a new folder.")));
+
+ m_lineEdit = new QLineEdit(this);
+ m_lineEdit->setObjectName(QLatin1String("LineEdit"));
+
+ QString startMenuDir = core->value(scStartMenuDir);
+ if (startMenuDir.isEmpty())
+ startMenuDir = productName();
+ m_lineEdit->setText(startMenuDir);
+
+ // grab existing start menu folders
+ QSettings user(QLatin1String("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\"
+ "Explorer\\User Shell Folders"), QSettings::NativeFormat);
+ // User Shell Folders uses %USERPROFILE%
+ startMenuPath = replaceWindowsEnvironmentVariables(user.value(QLatin1String("Programs"), QString())
+ .toString());
+ core->setValue(QLatin1String("DesktopDir"), replaceWindowsEnvironmentVariables(user
+ .value(QLatin1String("Desktop")).toString()));
+
+ QDir dir(startMenuPath); // user only dirs
+ QStringList dirs = dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
+
+ if (core->value(QLatin1String("AllUsers")) == QLatin1String("true")) {
+ qDebug() << "AllUsers set. Using HKEY_LOCAL_MACHINE";
+ QSettings system(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\"
+ "Explorer\\Shell Folders"), QSettings::NativeFormat);
+ startMenuPath = system.value(QLatin1String("Common Programs"), QString()).toString();
+ core->setValue(QLatin1String("DesktopDir"),system.value(QLatin1String("Desktop")).toString());
+
+ dir.setPath(startMenuPath); // system only dirs
+ dirs += dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
+ }
+
+ qDebug() << "StartMenuPath: \t" << startMenuPath;
+ qDebug() << "DesktopDir: \t" << core->value(QLatin1String("DesktopDir"));
+
+ m_listWidget = new QListWidget(this);
+ if (!dirs.isEmpty()) {
+ dirs.removeDuplicates();
+ foreach (const QString &dir, dirs)
+ new QListWidgetItem(dir, m_listWidget);
+ }
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(m_lineEdit);
+ layout->addWidget(m_listWidget);
+
+ setLayout(layout);
+
+ connect(m_listWidget, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this,
+ SLOT(currentItemChanged(QListWidgetItem*)));
+}
+
+QString StartMenuDirectoryPage::startMenuDir() const
+{
+ return m_lineEdit->text();
+}
+
+void StartMenuDirectoryPage::setStartMenuDir(const QString &startMenuDir)
+{
+ m_lineEdit->setText(startMenuDir);
+}
+
+void StartMenuDirectoryPage::leaving()
+{
+ packageManagerCore()->setValue(scStartMenuDir, startMenuPath + QDir::separator() + startMenuDir());
+}
+
+void StartMenuDirectoryPage::currentItemChanged(QListWidgetItem *current)
+{
+ if (current) {
+ QString dir = current->data(Qt::DisplayRole).toString();
+ if (!dir.isEmpty())
+ dir += QDir::separator();
+ setStartMenuDir(dir + packageManagerCore()->value(scStartMenuDir));
+ }
+}
+
+
+// -- ReadyForInstallationPage
+
+ReadyForInstallationPage::ReadyForInstallationPage(PackageManagerCore *core)
+ : PackageManagerPage(core)
+ , m_msgLabel(new QLabel)
+{
+ setPixmap(QWizard::LogoPixmap, logoPixmap());
+ setPixmap(QWizard::WatermarkPixmap, QPixmap());
+ setObjectName(QLatin1String("ReadyForInstallationPage"));
+ setSubTitle(subTitleForPage(QLatin1String("ReadyForInstallationPage")));
+
+ QVBoxLayout *baseLayout = new QVBoxLayout();
+ baseLayout->setObjectName(QLatin1String("BaseLayout"));
+
+ QVBoxLayout *topLayout = new QVBoxLayout();
+ topLayout->setObjectName(QLatin1String("TopLayout"));
+
+ m_msgLabel->setWordWrap(true);
+ m_msgLabel->setObjectName(QLatin1String("MessageLabel"));
+ m_msgLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ topLayout->addWidget(m_msgLabel);
+ baseLayout->addLayout(topLayout);
+
+ m_taskDetailsButton = new QPushButton(tr("&Show Details"), this);
+ m_taskDetailsButton->setObjectName(QLatin1String("TaskDetailsButton"));
+ m_taskDetailsButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
+ connect(m_taskDetailsButton, SIGNAL(clicked()), this, SLOT(toggleDetails()));
+ topLayout->addWidget(m_taskDetailsButton);
+
+ QVBoxLayout *bottomLayout = new QVBoxLayout();
+ bottomLayout->setObjectName(QLatin1String("BottomLayout"));
+ bottomLayout->addStretch();
+
+ m_taskDetailsBrowser = new QTextBrowser(this);
+ m_taskDetailsBrowser->setReadOnly(true);
+ m_taskDetailsBrowser->setObjectName(QLatin1String("TaskDetailsBrowser"));
+ m_taskDetailsBrowser->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ m_taskDetailsBrowser->setVisible(false);
+ bottomLayout->addWidget(m_taskDetailsBrowser);
+ bottomLayout->setStretch(1, 10);
+ baseLayout->addLayout(bottomLayout);
+
+ setLayout(baseLayout);
+}
+
+
+/*!
+ \reimp
+*/
+void ReadyForInstallationPage::entering()
+{
+ setCommitPage(false);
+
+ if (packageManagerCore()->isUninstaller()) {
+ m_taskDetailsButton->setVisible(false);
+ m_taskDetailsBrowser->setVisible(false);
+ setButtonText(QWizard::CommitButton, tr("U&ninstall"));
+ setTitle(titleForPage(objectName(), tr("Ready to Uninstall")));
+ m_msgLabel->setText(tr("Setup is now ready to begin removing %1 from your computer.<br>"
+ "<font color=\"red\">The program dir %2 will be deleted completely</font>, "
+ "including all content in that directory!")
+ .arg(productName(), QDir::toNativeSeparators(QDir(packageManagerCore()->value(scTargetDir))
+ .absolutePath())));
+ setCommitPage(true);
+ return;
+ } else if (packageManagerCore()->isPackageManager() || packageManagerCore()->isUpdater()) {
+ setButtonText(QWizard::CommitButton, tr("U&pdate"));
+ setTitle(titleForPage(objectName(), tr("Ready to Update Packages")));
+ m_msgLabel->setText(tr("Setup is now ready to begin updating your installation."));
+ } else {
+ Q_ASSERT(packageManagerCore()->isInstaller());
+ setButtonText(QWizard::CommitButton, tr("&Install"));
+ setTitle(titleForPage(objectName(), tr("Ready to Install")));
+ m_msgLabel->setText(tr("Setup is now ready to begin installing %1 on your computer.")
+ .arg(productName()));
+ }
+
+ refreshTaskDetailsBrowser();
+
+ const VolumeInfo tempVolume = VolumeInfo::fromPath(QDir::tempPath());
+ const VolumeInfo targetVolume = VolumeInfo::fromPath(packageManagerCore()->value(scTargetDir));
+
+ const quint64 tempVolumeAvailableSize = tempVolume.availableSize();
+ const quint64 installVolumeAvailableSize = targetVolume.availableSize();
+
+ // at the moment there is no better way to check this
+ if (targetVolume.size() == 0 && installVolumeAvailableSize == 0) {
+ qDebug() << QString::fromLatin1("Could not determine available space on device. Volume descriptor: %1,"
+ "Mount path: %2. Continue silently.").arg(targetVolume.volumeDescriptor(), targetVolume.mountPath());
+ setCommitPage(true);
+ return; // TODO: Shouldn't this also disable the "Next" button?
+ }
+
+ const bool tempOnSameVolume = (targetVolume == tempVolume);
+ if (tempOnSameVolume) {
+ qDebug() << "Tmp and install folder are on the same volume. Volume mount point:" << targetVolume
+ .mountPath() << "Free space available:" << humanReadableSize(installVolumeAvailableSize);
+ } else {
+ qDebug() << "Tmp is on a different volume than the install folder. Tmp volume mount point:"
+ << tempVolume.mountPath() << "Free space available:" << humanReadableSize(tempVolumeAvailableSize)
+ << "Install volume mount point:" << targetVolume.mountPath() << "Free space "
+ "available:" << humanReadableSize(installVolumeAvailableSize);
+ }
+
+ const quint64 extraSpace = 256 * 1024 * 1024LL;
+ quint64 required(packageManagerCore()->requiredDiskSpace());
+ quint64 tempRequired(packageManagerCore()->requiredTemporaryDiskSpace());
+ if (required < extraSpace) {
+ required += 0.1 * required;
+ tempRequired += 0.1 * tempRequired;
+ } else {
+ required += extraSpace;
+ tempRequired += extraSpace;
+ }
+
+ quint64 repositorySize = 0;
+ const bool createLocalRepository = packageManagerCore()->createLocalRepositoryFromBinary();
+ if (createLocalRepository) {
+ repositorySize = QFile(QCoreApplication::applicationFilePath()).size();
+ required += repositorySize; // if we create a local repository, take that space into account as well
+ }
+
+ qDebug() << "Installation space required:" << humanReadableSize(required) << "Temporary space required:"
+ << humanReadableSize(tempRequired) << "Local repository size:" << humanReadableSize(repositorySize);
+
+ if (tempOnSameVolume && (installVolumeAvailableSize <= (required + tempRequired))) {
+ m_msgLabel->setText(tr("Not enough disk space to store temporary files and the installation! "
+ "Available space: %1, at least required %2.").arg(humanReadableSize(installVolumeAvailableSize),
+ humanReadableSize(required + tempRequired)));
+ return;
+ }
+
+ if (installVolumeAvailableSize < required) {
+ m_msgLabel->setText(tr("Not enough disk space to store all selected components! Available space: %1, "
+ "at least required: %2.").arg(humanReadableSize(installVolumeAvailableSize),
+ humanReadableSize(required)));
+ return;
+ }
+
+ if (tempVolumeAvailableSize < tempRequired) {
+ m_msgLabel->setText(tr("Not enough disk space to store temporary files! Available space: %1, at "
+ "least required: %2.").arg(humanReadableSize(tempVolumeAvailableSize),
+ humanReadableSize(tempRequired)));
+ return;
+ }
+
+ if (installVolumeAvailableSize - required < 0.01 * targetVolume.size()) {
+ // warn for less than 1% of the volume's space being free
+ m_msgLabel->setText(tr("The volume you selected for installation seems to have sufficient space for "
+ "installation, but there will be less than 1% of the volume's space available afterwards. %1")
+ .arg(m_msgLabel->text()));
+ } else if (installVolumeAvailableSize - required < 100 * 1024 * 1024LL) {
+ // warn for less than 100MB being free
+ m_msgLabel->setText(tr("The volume you selected for installation seems to have sufficient space for "
+ "installation, but there will be less than 100 MB available afterwards. %1")
+ .arg(m_msgLabel->text()));
+ }
+ setCommitPage(true);
+}
+
+void ReadyForInstallationPage::refreshTaskDetailsBrowser()
+{
+ QString htmlOutput;
+ QString lastInstallReason;
+ if (!packageManagerCore()->calculateComponentsToUninstall() ||
+ !packageManagerCore()->calculateComponentsToInstall()) {
+ htmlOutput.append(QString::fromLatin1("<h2><font color=\"red\">%1</font></h2><ul>")
+ .arg(tr("Can not resolve all dependencies!")));
+ //if we have a missing dependency or a recursion we can display it
+ if (!packageManagerCore()->componentsToInstallError().isEmpty()) {
+ htmlOutput.append(QString::fromLatin1("<li> %1 </li>").arg(
+ packageManagerCore()->componentsToInstallError()));
+ }
+ htmlOutput.append(QLatin1String("</ul>"));
+ m_taskDetailsBrowser->setHtml(htmlOutput);
+ if (!m_taskDetailsBrowser->isVisible())
+ toggleDetails();
+ setCommitPage(false);
+ return;
+ }
+
+ // In case of updater mode we don't uninstall components.
+ if (!packageManagerCore()->isUpdater()) {
+ QList<Component*> componentsToRemove = packageManagerCore()->componentsToUninstall();
+ if (!componentsToRemove.isEmpty()) {
+ htmlOutput.append(QString::fromLatin1("<h3>%1</h3><ul>").arg(tr("Components about to be removed.")));
+ foreach (Component *component, componentsToRemove)
+ htmlOutput.append(QString::fromLatin1("<li> %1 </li>").arg(component->name()));
+ htmlOutput.append(QLatin1String("</ul>"));
+ }
+ }
+
+ foreach (Component *component, packageManagerCore()->orderedComponentsToInstall()) {
+ const QString installReason = packageManagerCore()->installReason(component);
+ if (lastInstallReason != installReason) {
+ if (!lastInstallReason.isEmpty()) // means we had to close the previous list
+ htmlOutput.append(QLatin1String("</ul>"));
+ htmlOutput.append(QString::fromLatin1("<h3>%1</h3><ul>").arg(installReason));
+ lastInstallReason = installReason;
+ }
+ htmlOutput.append(QString::fromLatin1("<li> %1 </li>").arg(component->name()));
+ }
+ m_taskDetailsBrowser->setHtml(htmlOutput);
+}
+
+void ReadyForInstallationPage::toggleDetails()
+{
+ const bool visible = !m_taskDetailsBrowser->isVisible();
+ m_taskDetailsBrowser->setVisible(visible);
+ m_taskDetailsButton->setText(visible ? tr("&Hide Details") : tr("&Show Details"));
+}
+
+void ReadyForInstallationPage::leaving()
+{
+ setButtonText(QWizard::CommitButton, gui()->defaultButtonText(QWizard::CommitButton));
+}
+
+/*!
+ \reimp
+*/
+bool ReadyForInstallationPage::isComplete() const
+{
+ return isCommitPage();
+}
+
+
+// -- PerformInstallationPage
+
+/*!
+ \class QInstaller::PerformInstallationPage
+ On this page the user can see on a progress bar how far the current installation is.
+*/
+PerformInstallationPage::PerformInstallationPage(PackageManagerCore *core)
+ : PackageManagerPage(core)
+ , m_performInstallationForm(new PerformInstallationForm(this))
+{
+ setPixmap(QWizard::LogoPixmap, logoPixmap());
+ setPixmap(QWizard::WatermarkPixmap, QPixmap());
+ setObjectName(QLatin1String("PerformInstallationPage"));
+ setSubTitle(subTitleForPage(QLatin1String("PerformInstallationPage")));
+
+ m_performInstallationForm->setupUi(this);
+
+ connect(ProgressCoordinator::instance(), SIGNAL(detailTextChanged(QString)), m_performInstallationForm,
+ SLOT(appendProgressDetails(QString)));
+ connect(ProgressCoordinator::instance(), SIGNAL(detailTextResetNeeded()), m_performInstallationForm,
+ SLOT(clearDetailsBrowser()));
+ connect(m_performInstallationForm, SIGNAL(showDetailsChanged()), this, SLOT(toggleDetailsWereChanged()));
+
+ connect(core, SIGNAL(installationStarted()), this, SLOT(installationStarted()));
+ connect(core, SIGNAL(uninstallationStarted()), this, SLOT(installationStarted()));
+ connect(core, SIGNAL(installationFinished()), this, SLOT(installationFinished()));
+ connect(core, SIGNAL(uninstallationFinished()), this, SLOT(installationFinished()));
+ connect(core, SIGNAL(titleMessageChanged(QString)), this, SLOT(setTitleMessage(QString)));
+ connect(this, SIGNAL(setAutomatedPageSwitchEnabled(bool)), core,
+ SIGNAL(setAutomatedPageSwitchEnabled(bool)));
+
+ m_performInstallationForm->setDetailsWidgetVisible(true);
+}
+
+PerformInstallationPage::~PerformInstallationPage()
+{
+ delete m_performInstallationForm;
+}
+
+bool PerformInstallationPage::isAutoSwitching() const
+{
+ return !m_performInstallationForm->isShowingDetails();
+}
+
+// -- protected
+
+void PerformInstallationPage::entering()
+{
+ setComplete(false);
+ setCommitPage(true);
+
+ const QString productName = packageManagerCore()->value(QLatin1String("ProductName"));
+ if (packageManagerCore()->isUninstaller()) {
+ setButtonText(QWizard::CommitButton, tr("&Uninstall"));
+ setTitle(titleForPage(objectName(), tr("Uninstalling %1")).arg(productName));
+
+ QTimer::singleShot(30, packageManagerCore(), SLOT(runUninstaller()));
+ } else if (packageManagerCore()->isPackageManager() || packageManagerCore()->isUpdater()) {
+ setButtonText(QWizard::CommitButton, tr("&Update"));
+ setTitle(titleForPage(objectName(), tr("Updating components of %1")).arg(productName));
+
+ QTimer::singleShot(30, packageManagerCore(), SLOT(runPackageUpdater()));
+ } else {
+ setButtonText(QWizard::CommitButton, tr("&Install"));
+ setTitle(titleForPage(objectName(), tr("Installing %1")).arg(productName));
+
+ QTimer::singleShot(30, packageManagerCore(), SLOT(runInstaller()));
+ }
+
+ m_performInstallationForm->enableDetails();
+ emit setAutomatedPageSwitchEnabled(true);
+}
+
+void PerformInstallationPage::leaving()
+{
+ setButtonText(QWizard::CommitButton, gui()->defaultButtonText(QWizard::CommitButton));
+}
+
+// -- public slots
+
+void PerformInstallationPage::setTitleMessage(const QString &title)
+{
+ setTitle(title);
+}
+
+// -- private slots
+
+void PerformInstallationPage::installationStarted()
+{
+ m_performInstallationForm->startUpdateProgress();
+}
+
+void PerformInstallationPage::installationFinished()
+{
+ m_performInstallationForm->stopUpdateProgress();
+ if (!isAutoSwitching()) {
+ m_performInstallationForm->scrollDetailsToTheEnd();
+ m_performInstallationForm->setDetailsButtonEnabled(false);
+
+ setComplete(true);
+ setButtonText(QWizard::CommitButton, gui()->defaultButtonText(QWizard::NextButton));
+ }
+}
+
+void PerformInstallationPage::toggleDetailsWereChanged()
+{
+ emit setAutomatedPageSwitchEnabled(isAutoSwitching());
+}
+
+
+// -- FinishedPage
+
+FinishedPage::FinishedPage(PackageManagerCore *core)
+ : PackageManagerPage(core)
+ , m_commitButton(0)
+{
+ setObjectName(QLatin1String("FinishedPage"));
+ setPixmap(QWizard::WatermarkPixmap, watermarkPixmap());
+ setSubTitle(subTitleForPage(QLatin1String("FinishedPage")));
+ setTitle(titleForPage(QLatin1String("FinishedPage"), tr("Completing the %1 Wizard")).arg(productName()));
+
+ m_msgLabel = new QLabel(this);
+ m_msgLabel->setWordWrap(true);
+ m_msgLabel->setObjectName(QLatin1String("MessageLabel"));
+
+ const QVariantHash hash = elementsForPage(QLatin1String("FinishedPage"));
+#ifdef Q_WS_MAC
+ m_msgLabel->setText(hash.value(QLatin1String("MessageLabel"), tr("Click Done to exit the %1 "
+ "Wizard.")).toString().arg(productName()));
+#else
+ m_msgLabel->setText(hash.value(QLatin1String("MessageLabel"), tr("Click Finish to exit the "
+ "%1 Wizard.")).toString().arg(productName()));
+#endif
+
+ m_runItCheckBox = new QCheckBox(this);
+ m_runItCheckBox->setObjectName(QLatin1String("RunItCheckBox"));
+ m_runItCheckBox->setChecked(true);
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(m_msgLabel);
+ layout->addWidget(m_runItCheckBox);
+ setLayout(layout);
+}
+
+void FinishedPage::entering()
+{
+ if (m_commitButton) {
+ disconnect(m_commitButton, SIGNAL(clicked()), this, SLOT(handleFinishClicked()));
+ m_commitButton = 0;
+ }
+
+ setCommitPage(true);
+ if (packageManagerCore()->isUpdater() || packageManagerCore()->isPackageManager()) {
+#ifdef Q_WS_MAC
+ gui()->setOption(QWizard::NoCancelButton, false);
+#endif
+ if (QAbstractButton *cancel = gui()->button(QWizard::CancelButton)) {
+ m_commitButton = cancel;
+ cancel->setEnabled(true);
+ cancel->setVisible(true);
+ }
+ setButtonText(QWizard::CommitButton, tr("Restart"));
+ setButtonText(QWizard::CancelButton, gui()->defaultButtonText(QWizard::FinishButton));
+ } else {
+ if (packageManagerCore()->isInstaller())
+ m_commitButton = wizard()->button(QWizard::FinishButton);
+
+ gui()->setOption(QWizard::NoCancelButton, true);
+ if (QAbstractButton *cancel = gui()->button(QWizard::CancelButton))
+ cancel->setVisible(false);
+ }
+
+ gui()->updateButtonLayout();
+
+ if (m_commitButton) {
+ disconnect(m_commitButton, SIGNAL(clicked()), this, SLOT(handleFinishClicked()));
+ connect(m_commitButton, SIGNAL(clicked()), this, SLOT(handleFinishClicked()));
+ }
+
+ if (packageManagerCore()->status() == PackageManagerCore::Success) {
+ const QString finishedText = packageManagerCore()->value(QLatin1String("FinishedText"));
+ if (!finishedText.isEmpty())
+ m_msgLabel->setText(finishedText);
+
+ if (!packageManagerCore()->value(scRunProgram).isEmpty()) {
+ m_runItCheckBox->show();
+ m_runItCheckBox->setText(packageManagerCore()->value(scRunProgramDescription, tr("Run %1 now."))
+ .arg(productName()));
+ return; // job done
+ }
+ } else {
+ // TODO: how to handle this using the config.xml
+ setTitle(tr("The %1 Wizard failed.").arg(productName()));
+ }
+
+ m_runItCheckBox->hide();
+ m_runItCheckBox->setChecked(false);
+}
+
+void FinishedPage::leaving()
+{
+#ifdef Q_WS_MAC
+ gui()->setOption(QWizard::NoCancelButton, true);
+#endif
+
+ if (QAbstractButton *cancel = gui()->button(QWizard::CancelButton))
+ cancel->setVisible(false);
+ gui()->updateButtonLayout();
+
+ setButtonText(QWizard::CommitButton, gui()->defaultButtonText(QWizard::CommitButton));
+ setButtonText(QWizard::CancelButton, gui()->defaultButtonText(QWizard::CancelButton));
+}
+
+void FinishedPage::handleFinishClicked()
+{
+ const QString program = packageManagerCore()->replaceVariables(packageManagerCore()->value(scRunProgram));
+ if (!m_runItCheckBox->isChecked() || program.isEmpty())
+ return;
+
+ qDebug() << "starting" << program;
+ QProcess::startDetached(program);
+}
+
+
+// -- RestartPage
+
+RestartPage::RestartPage(PackageManagerCore *core)
+ : PackageManagerPage(core)
+{
+ setObjectName(QLatin1String("RestartPage"));
+ setPixmap(QWizard::WatermarkPixmap, watermarkPixmap());
+ setSubTitle(subTitleForPage(QLatin1String("RestartPage")));
+ setTitle(titleForPage(QLatin1String("RestartPage"), tr("Completing the %1 Setup Wizard"))
+ .arg(productName()));
+
+ setFinalPage(false);
+ setCommitPage(false);
+}
+
+int RestartPage::nextId() const
+{
+ return PackageManagerCore::Introduction;
+}
+
+void RestartPage::entering()
+{
+ if (!packageManagerCore()->needsRestart()) {
+ if (QAbstractButton *finish = wizard()->button(QWizard::FinishButton))
+ finish->setVisible(false);
+ QMetaObject::invokeMethod(this, "restart", Qt::QueuedConnection);
+ } else {
+ gui()->accept();
+ }
+}
+
+void RestartPage::leaving()
+{
+}
+
+#include "packagemanagergui.moc"
+#include "moc_packagemanagergui.cpp"