summaryrefslogtreecommitdiffstats
path: root/src/sdk/installerbasecommons.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sdk/installerbasecommons.cpp')
-rw-r--r--src/sdk/installerbasecommons.cpp549
1 files changed, 549 insertions, 0 deletions
diff --git a/src/sdk/installerbasecommons.cpp b/src/sdk/installerbasecommons.cpp
new file mode 100644
index 000000000..5c22d9926
--- /dev/null
+++ b/src/sdk/installerbasecommons.cpp
@@ -0,0 +1,549 @@
+/**************************************************************************
+**
+** This file is part of Installer Framework
+**
+** Copyright (c) 2010-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 "installerbasecommons.h"
+
+#include <component.h>
+#include <messageboxhandler.h>
+#include <packagemanagercore.h>
+#include <settings.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTimer>
+
+#include <QtGui/QLabel>
+#include <QtGui/QProgressBar>
+#include <QtGui/QRadioButton>
+#include <QtGui/QStackedWidget>
+#include <QtGui/QVBoxLayout>
+
+using namespace QInstaller;
+
+
+// -- IntroductionPageImpl
+
+IntroductionPageImpl::IntroductionPageImpl(QInstaller::PackageManagerCore *core)
+ : QInstaller::IntroductionPage(core)
+ , m_updatesFetched(false)
+ , m_allPackagesFetched(false)
+{
+ QWidget *widget = new QWidget(this);
+ QVBoxLayout *layout = new QVBoxLayout(widget);
+
+ m_packageManager = new QRadioButton(tr("Package manager"), this);
+ layout->addWidget(m_packageManager);
+ m_packageManager->setChecked(core->isPackageManager());
+ connect(m_packageManager, SIGNAL(toggled(bool)), this, SLOT(setPackageManager(bool)));
+
+ m_updateComponents = new QRadioButton(tr("Update components"), this);
+ layout->addWidget(m_updateComponents);
+ m_updateComponents->setChecked(core->isUpdater());
+ connect(m_updateComponents, SIGNAL(toggled(bool)), this, SLOT(setUpdater(bool)));
+
+ m_removeAllComponents = new QRadioButton(tr("Remove all components"), this);
+ layout->addWidget(m_removeAllComponents);
+ m_removeAllComponents->setChecked(core->isUninstaller());
+ connect(m_removeAllComponents, SIGNAL(toggled(bool)), this, SLOT(setUninstaller(bool)));
+ connect(m_removeAllComponents, SIGNAL(toggled(bool)), core, SLOT(setCompleteUninstallation(bool)));
+
+ layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding));
+
+ m_label = new QLabel(this);
+ m_label->setWordWrap(true);
+ m_label->setText(tr("Retrieving information from remote installation sources..."));
+ layout->addWidget(m_label);
+
+ m_progressBar = new QProgressBar(this);
+ m_progressBar->setRange(0, 0);
+ layout->addWidget(m_progressBar);
+
+ layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding));
+
+ m_errorLabel = new QLabel(this);
+ m_errorLabel->setWordWrap(true);
+ layout->addWidget(m_errorLabel);
+
+ widget->setLayout(layout);
+ setWidget(widget);
+
+ core->setCompleteUninstallation(core->isUninstaller());
+
+ connect(core, SIGNAL(metaJobInfoMessage(QString)), this, SLOT(setMessage(QString)));
+ connect(core, SIGNAL(coreNetworkSettingsChanged()), this, SLOT(onCoreNetworkSettingsChanged()));
+}
+
+int IntroductionPageImpl::nextId() const
+{
+ if (packageManagerCore()->isUninstaller())
+ return PackageManagerCore::ReadyForInstallation;
+
+ if (packageManagerCore()->isUpdater() || packageManagerCore()->isPackageManager())
+ return PackageManagerCore::ComponentSelection;
+
+ return QInstaller::IntroductionPage::nextId();
+}
+
+bool IntroductionPageImpl::validatePage()
+{
+ PackageManagerCore *core = packageManagerCore();
+ if (core->isUninstaller())
+ return true;
+
+ setComplete(false);
+ gui()->setSettingsButtonEnabled(false);
+
+ const bool maintanence = core->isUpdater() || core->isPackageManager();
+ if (maintanence) {
+ showAll();
+ setMaintenanceToolsEnabled(false);
+ } else {
+ showMetaInfoUdate();
+ }
+
+ // fetch updater packages
+ if (core->isUpdater()) {
+ if (!m_updatesFetched) {
+ m_updatesFetched = core->fetchRemotePackagesTree();
+ if (!m_updatesFetched)
+ setErrorMessage(core->error());
+ }
+
+ callControlScript(QLatin1String("UpdaterSelectedCallback"));
+
+ if (m_updatesFetched) {
+ if (core->updaterComponents().count() <= 0)
+ setErrorMessage(QLatin1String("<b>") + tr("No updates available.") + QLatin1String("</b>"));
+ else
+ setComplete(true);
+ }
+ }
+
+ // fetch common packages
+ if (core->isInstaller() || core->isPackageManager()) {
+ bool localPackagesTreeFetched = false;
+ if (!m_allPackagesFetched) {
+ // first try to fetch the server side packages tree
+ m_allPackagesFetched = core->fetchRemotePackagesTree();
+ if (!m_allPackagesFetched) {
+ QString error = core->error();
+ if (core->isPackageManager()) {
+ // if that fails and we're in maintenance mode, try to fetch local installed tree
+ localPackagesTreeFetched = core->fetchLocalPackagesTree();
+ if (localPackagesTreeFetched) {
+ // if that succeeded, adjust error message
+ error = QLatin1String("<font color=\"red\">") + error + tr(" Only local package "
+ "management available.") + QLatin1String("</font>");
+ }
+ }
+ setErrorMessage(error);
+ }
+ }
+
+ callControlScript(QLatin1String("PackageManagerSelectedCallback"));
+
+ if (m_allPackagesFetched | localPackagesTreeFetched)
+ setComplete(true);
+ }
+
+ if (maintanence) {
+ showMaintenanceTools();
+ setMaintenanceToolsEnabled(true);
+ } else {
+ hideAll();
+ }
+ gui()->setSettingsButtonEnabled(true);
+
+ return isComplete();
+}
+
+void IntroductionPageImpl::showAll()
+{
+ showWidgets(true);
+}
+
+void IntroductionPageImpl::hideAll()
+{
+ showWidgets(false);
+}
+
+void IntroductionPageImpl::showMetaInfoUdate()
+{
+ showWidgets(false);
+ m_label->setVisible(true);
+ m_progressBar->setVisible(true);
+}
+
+void IntroductionPageImpl::showMaintenanceTools()
+{
+ showWidgets(true);
+ m_label->setVisible(false);
+ m_progressBar->setVisible(false);
+}
+
+void IntroductionPageImpl::setMaintenanceToolsEnabled(bool enable)
+{
+ m_packageManager->setEnabled(enable);
+ m_updateComponents->setEnabled(enable);
+ m_removeAllComponents->setEnabled(enable);
+}
+
+// -- public slots
+
+void IntroductionPageImpl::setMessage(const QString &msg)
+{
+ m_label->setText(msg);
+}
+
+void IntroductionPageImpl::setErrorMessage(const QString &error)
+{
+ QPalette palette;
+ const PackageManagerCore::Status s = packageManagerCore()->status();
+ if (s == PackageManagerCore::Failure || s == PackageManagerCore::Failure) {
+ palette.setColor(QPalette::WindowText, Qt::red);
+ } else {
+ palette.setColor(QPalette::WindowText, palette.color(QPalette::WindowText));
+ }
+
+ m_errorLabel->setText(error);
+ m_errorLabel->setPalette(palette);
+}
+
+void IntroductionPageImpl::callControlScript(const QString &callback)
+{
+ // Initialize the gui. Needs to be done after check repositories as only then the ui can handle
+ // hide of pages depending on the components.
+ gui()->init();
+ gui()->callControlScriptMethod(callback);
+}
+
+// -- private slots
+
+void IntroductionPageImpl::setUpdater(bool value)
+{
+ if (value) {
+ entering();
+ gui()->showSettingsButton(true);
+ packageManagerCore()->setUpdater();
+ emit packageManagerCoreTypeChanged();
+ }
+}
+
+void IntroductionPageImpl::setUninstaller(bool value)
+{
+ if (value) {
+ entering();
+ gui()->showSettingsButton(false);
+ packageManagerCore()->setUninstaller();
+ emit packageManagerCoreTypeChanged();
+ }
+}
+
+void IntroductionPageImpl::setPackageManager(bool value)
+{
+ if (value) {
+ entering();
+ gui()->showSettingsButton(true);
+ packageManagerCore()->setPackageManager();
+ emit packageManagerCoreTypeChanged();
+ }
+}
+
+void IntroductionPageImpl::onCoreNetworkSettingsChanged()
+{
+ // force a repaint of the ui as after the settings dialog has been closed and the wizard has been
+ // restarted, the "Next" button looks still disabled. TODO: figure out why this happens at all!
+ gui()->repaint();
+
+ m_updatesFetched = false;
+ m_allPackagesFetched = false;
+}
+
+// -- private
+
+void IntroductionPageImpl::entering()
+{
+ setComplete(true);
+ showWidgets(false);
+ setMessage(QString());
+ setErrorMessage(QString());
+ setButtonText(QWizard::CancelButton, tr("Quit"));
+
+ PackageManagerCore *core = packageManagerCore();
+ if (core->isUninstaller() ||core->isUpdater() || core->isPackageManager()) {
+ showMaintenanceTools();
+ setMaintenanceToolsEnabled(true);
+ }
+}
+
+void IntroductionPageImpl::leaving()
+{
+ // TODO: force repaint on next page, keeps unpainted after fetch
+ QTimer::singleShot(100, gui()->page(nextId()), SLOT(repaint()));
+ setButtonText(QWizard::CancelButton, gui()->defaultButtonText(QWizard::CancelButton));
+}
+
+void IntroductionPageImpl::showWidgets(bool show)
+{
+ m_label->setVisible(show);
+ m_progressBar->setVisible(show);
+ m_packageManager->setVisible(show);
+ m_updateComponents->setVisible(show);
+ m_removeAllComponents->setVisible(show);
+}
+
+
+// -- TargetDirectoryPageImpl
+
+/*!
+ A custom target directory selection based due to the no-space restriction...
+*/
+TargetDirectoryPageImpl::TargetDirectoryPageImpl(PackageManagerCore *core)
+ : TargetDirectoryPage(core)
+{
+ QPalette palette;
+ palette.setColor(QPalette::WindowText, Qt::red);
+
+ m_warningLabel = new QLabel(this);
+ m_warningLabel->setPalette(palette);
+
+ insertWidget(m_warningLabel, QLatin1String("MessageLabel"), 2);
+}
+
+QString TargetDirectoryPageImpl::targetDirWarning() const
+{
+ if (targetDir().isEmpty()) {
+ return TargetDirectoryPageImpl::tr("The installation path cannot be empty, please specify a valid "
+ "folder.");
+ }
+
+ if (QDir(targetDir()).isRelative()) {
+ return TargetDirectoryPageImpl::tr("The installation path cannot be relative, please specify an "
+ "absolute path.");
+ }
+
+ QString dir = targetDir();
+#ifdef Q_OS_WIN
+ // remove e.g. "c:"
+ dir = dir.mid(2);
+#endif
+ // check if there are not allowed characters in the target path
+ if (dir.contains(QRegExp(QLatin1String("[!@#$%^&*: ,;]")))) {
+ return TargetDirectoryPageImpl::tr("The installation path must not contain !@#$%^&*:,; or spaces, "
+ "please specify a valid folder.");
+ }
+
+ return QString();
+}
+
+bool TargetDirectoryPageImpl::isComplete() const
+{
+ m_warningLabel->setText(targetDirWarning());
+ return m_warningLabel->text().isEmpty();
+}
+
+bool TargetDirectoryPageImpl::askQuestion(const QString &identifier, const QString &message)
+{
+ QMessageBox::StandardButton bt =
+ MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), identifier,
+ TargetDirectoryPageImpl::tr("Warning"), message, QMessageBox::Yes | QMessageBox::No);
+ QTimer::singleShot(100, wizard()->page(nextId()), SLOT(repaint()));
+
+ return bt == QMessageBox::Yes;
+}
+
+bool TargetDirectoryPageImpl::failWithError(const QString &identifier, const QString &message)
+{
+ MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), identifier,
+ TargetDirectoryPageImpl::tr("Error"), message);
+ QTimer::singleShot(100, wizard()->page(nextId()), SLOT(repaint()));
+
+ return false;
+}
+
+bool TargetDirectoryPageImpl::validatePage()
+{
+ if (!isVisible())
+ return true;
+
+ const QString remove = packageManagerCore()->value(QLatin1String("RemoveTargetDir"));
+ if (!QVariant(remove).toBool())
+ return true;
+
+ const QString targetDir = this->targetDir();
+ if (!packageManagerCore()->settings().allowNoneAsciiCharacters()) {
+ for (int i = 0; i < targetDir.length(); ++i) {
+ if (targetDir.at(i).unicode() & 0xff80) {
+ return failWithError(QLatin1String("NonAsciiTarget"), tr("The path or installation directory "
+ "contains non ASCII characters. This is currently not supported! Please choose a different "
+ "path or installation directory."));
+ }
+ }
+ }
+
+ const QDir dir(targetDir);
+ // the directory exists and is empty...
+ if (dir.exists() && dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot).isEmpty())
+ return true;
+
+ const QFileInfo fi(targetDir);
+ if (fi.isDir()) {
+ if (dir == QDir::root() || dir == QDir::home()) {
+ return failWithError(QLatin1String("ForbiddenTargetDirectory"), tr("As the install directory "
+ "is completely deleted installing in %1 is forbidden.").arg(QDir::rootPath()));
+ }
+
+ QString fileName = packageManagerCore()->settings().uninstallerName();
+#if defined(Q_WS_MAC)
+ if (QFileInfo(QCoreApplication::applicationDirPath() + QLatin1String("/../..")).isBundle())
+ fileName += QLatin1String(".app/Contents/MacOS/") + fileName;
+#elif defined(Q_OS_WIN)
+ fileName += QLatin1String(".exe");
+#endif
+
+ QFileInfo fi2(targetDir + QDir::separator() + fileName);
+ if (fi2.exists()) {
+ return askQuestion(QLatin1String("OverwriteTargetDirectory"),
+ TargetDirectoryPageImpl::tr("The folder you selected exists already and contains an "
+ "installation.\nDo you want to overwrite it?"));
+ }
+
+ return askQuestion(QLatin1String("OverwriteTargetDirectory"),
+ tr("You have selected an existing, non-empty folder for installation.\nNote that it will be "
+ "completely wiped on uninstallation of this application.\nIt is not advisable to install into "
+ "this folder as installation might fail.\nDo you want to continue?"));
+ } else if (fi.isFile() || fi.isSymLink()) {
+ return failWithError(QLatin1String("WrongTargetDirectory"), tr("You have selected an existing file "
+ "or symlink, please choose a different target for installation."));
+ }
+ return true;
+}
+
+
+// -- InstallerGui
+
+InstallerGui::InstallerGui(PackageManagerCore *core)
+ : PackageManagerGui(core, 0)
+{
+ setPage(PackageManagerCore::Introduction, new IntroductionPageImpl(core));
+ setPage(PackageManagerCore::TargetDirectory, new TargetDirectoryPageImpl(core));
+ setPage(PackageManagerCore::ComponentSelection, new ComponentSelectionPage(core));
+ setPage(PackageManagerCore::LicenseCheck, new LicenseAgreementPage(core));
+#ifdef Q_OS_WIN
+ setPage(PackageManagerCore::StartMenuSelection, new StartMenuDirectoryPage(core));
+#endif
+ setPage(PackageManagerCore::ReadyForInstallation, new ReadyForInstallationPage(core));
+ setPage(PackageManagerCore::PerformInstallation, new PerformInstallationPage(core));
+ setPage(PackageManagerCore::InstallationFinished, new FinishedPage(core));
+
+ bool ok = false;
+ const int startPage = core->value(QLatin1String("GuiStartPage")).toInt(&ok);
+ if(ok)
+ setStartId(startPage);
+}
+
+void InstallerGui::init()
+{
+}
+
+int InstallerGui::nextId() const
+{
+ const int next = QWizard::nextId();
+ if (next == PackageManagerCore::LicenseCheck) {
+ PackageManagerCore *const core = packageManagerCore();
+ const int nextNextId = pageIds().value(pageIds().indexOf(next)+ 1, -1);
+ if (!core->isInstaller())
+ return nextNextId;
+
+ core->calculateComponentsToInstall();
+ foreach (Component* component, core->orderedComponentsToInstall()) {
+ if (!component->licenses().isEmpty())
+ return next;
+ }
+ return nextNextId;
+ }
+ return next;
+}
+
+
+// -- MaintenanceGui
+
+MaintenanceGui::MaintenanceGui(PackageManagerCore *core)
+ : PackageManagerGui(core, 0)
+{
+ IntroductionPageImpl *intro = new IntroductionPageImpl(core);
+ connect(intro, SIGNAL(packageManagerCoreTypeChanged()), this, SLOT(updateRestartPage()));
+
+ setPage(PackageManagerCore::Introduction, intro);
+ setPage(PackageManagerCore::ComponentSelection, new ComponentSelectionPage(core));
+ setPage(PackageManagerCore::LicenseCheck, new LicenseAgreementPage(core));
+ setPage(PackageManagerCore::ReadyForInstallation, new ReadyForInstallationPage(core));
+ setPage(PackageManagerCore::PerformInstallation, new PerformInstallationPage(core));
+ setPage(PackageManagerCore::InstallationFinished, new FinishedPage(core));
+
+ RestartPage *p = new RestartPage(core);
+ connect(p, SIGNAL(restart()), this, SIGNAL(gotRestarted()));
+ setPage(PackageManagerCore::InstallationFinished + 1, p);
+
+ if (core->isUninstaller())
+ wizardPageVisibilityChangeRequested(false, PackageManagerCore::InstallationFinished + 1);
+}
+
+void MaintenanceGui::init()
+{
+}
+
+int MaintenanceGui::nextId() const
+{
+ const int next = QWizard::nextId();
+ if (next == PackageManagerCore::LicenseCheck) {
+ PackageManagerCore *const core = packageManagerCore();
+ const int nextNextId = pageIds().value(pageIds().indexOf(next)+ 1, -1);
+ if (!core->isPackageManager() && !core->isUpdater())
+ return nextNextId;
+
+ core->calculateComponentsToInstall();
+ foreach (Component* component, core->orderedComponentsToInstall()) {
+ if (component->isInstalled())
+ continue;
+ if (!component->licenses().isEmpty())
+ return next;
+ }
+ return nextNextId;
+ }
+ return next;
+}
+
+void MaintenanceGui::updateRestartPage()
+{
+ wizardPageVisibilityChangeRequested((packageManagerCore()->isUninstaller() ? false : true),
+ PackageManagerCore::InstallationFinished + 1);
+}