diff options
Diffstat (limited to 'installerbuilder/installerbase/tabcontroller.cpp')
-rw-r--r-- | installerbuilder/installerbase/tabcontroller.cpp | 538 |
1 files changed, 538 insertions, 0 deletions
diff --git a/installerbuilder/installerbase/tabcontroller.cpp b/installerbuilder/installerbase/tabcontroller.cpp new file mode 100644 index 000000000..cd62296a8 --- /dev/null +++ b/installerbuilder/installerbase/tabcontroller.cpp @@ -0,0 +1,538 @@ +/************************************************************************** +** +** This file is part of Qt SDK** +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).* +** +** Contact: Nokia Corporation qt-info@nokia.com** +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please contact +** (qt-info@nokia.com). +** +**************************************************************************/ +#include "tabcontroller.h" + +#include "installerbasecommons.h" +#include "maintabwidget.h" + +#include <KDUpdater/Application> +#include <KDUpdater/UpdateFinder> +#include <KDUpdater/UpdateSourcesInfo> +#include <KDUpdater/PackagesInfo> + +#include <common/installersettings.h> +#include <common/utils.h> +#include <common/errors.h> + +#include <componentselectiondialog.h> +#include <getrepositoriesmetainfojob.h> +#include <qinstaller.h> +#include <qinstallercomponent.h> +#include <updater.h> +#include <qinstallergui.h> + +#include <QtCore/QDebug> +#include <QtCore/QHash> +#include <QtCore/QPointer> + +#include <QtGui/QDialog> +#include <QtGui/QProgressDialog> + +#include <QtScript/QScriptEngine> + +#include <QtXml/QDomDocument> +#include <QtXml/QDomElement> + +class TabController::Private +{ +public: + Private(); + ~Private(); + void preselectInstalledPackages(); + + QHash<QString, QString> m_params; + bool m_updaterInitialized; + bool m_packageManagerInitialized; + bool m_init; + QPointer<QInstaller::Gui> m_gui; + QScopedPointer <Updater> m_updater; + MainTabWidget* m_updaterGuiWidget; + QInstaller::Installer *m_installer; + KDUpdater::Application *m_app; + QString m_controlScript; + int m_Tab_Pos_Updater; + int m_Tab_Pos_PackageManager; + TabController::Status m_state; + bool m_repoReached; + bool m_repoUpdateNeeded; +}; + +TabController::Private::Private() + : + m_updaterInitialized(false), + m_packageManagerInitialized(false), + m_init(false), + m_gui(0), + m_updater(0), + m_updaterGuiWidget(0), + m_installer(0), + m_app(0), + m_Tab_Pos_Updater(0), + m_Tab_Pos_PackageManager(0), + m_state(SUCCESS), + m_repoReached(true), + m_repoUpdateNeeded(true) +{ +} + +TabController::Private::~Private() +{ + delete m_updaterGuiWidget; + delete m_gui; +} + +// the package manager should preselect the currently installed packages +void TabController::Private::preselectInstalledPackages() +{ + Q_ASSERT(m_installer->isPackageManager()); + + QList<QInstaller::Component*>::const_iterator it; + const QList<QInstaller::Component*> components = m_installer->components(true); + for (it = components.begin(); it != components.end(); ++it) { + QInstaller::Component* const comp = *it; + const bool selected = m_app->packagesInfo()->findPackageInfo(comp->name()) > -1; + comp->setSelected(selected, InstallerMode, Component::InitializeComponentTreeSelectMode); + comp->setEnabled(m_repoReached || selected); + } +} + +// -- TabController + +TabController::TabController(QObject *parent) + : QObject(parent) + , d(new Private) +{ +} + +TabController::~TabController() +{ + delete d; +} + +void TabController::setCurrentTab(int tab) +{ + if (!d->m_updaterGuiWidget) + return; + + d->m_updaterGuiWidget->setCurrentIndex((tab == PACKAGE_MANAGER_TAB) + ? d->m_Tab_Pos_PackageManager : d->m_Tab_Pos_Updater); + d->m_gui->callControlScriptMethod(QLatin1String((tab == PACKAGE_MANAGER_TAB) + ? "PackageManagerSelectedCallback" : "UpdaterSelectedCallback")); +} + +void TabController::setInstallerParams(const QHash<QString, QString> ¶ms) +{ + d->m_params = params; +} + +void TabController::setInstallerGui(QInstaller::Gui *gui) +{ + d->m_gui = gui; + connect(d->m_gui, SIGNAL(gotRestarted()), this, SLOT(restartWizard())); +} + +void TabController::setInstaller(QInstaller::Installer *installer) +{ + d->m_installer = installer; +} + +void TabController::setTabWidget(MainTabWidget *widget) +{ + d->m_updaterGuiWidget = widget; +} + +int TabController::initUpdater() +{ + init(UPDATER_TAB); + + d->m_updaterGuiWidget->show(); + d->m_updaterGuiWidget->setTabEnabled(d->m_Tab_Pos_PackageManager, false); + + if (d->m_repoUpdateNeeded) { + int result = checkRepositories(); + if (result != INST_SUCCESS) + return result; + } + + d->m_updaterInitialized = true; + d->m_updaterGuiWidget->setTabEnabled(d->m_Tab_Pos_PackageManager, true); + + return INST_SUCCESS; +} + +void TabController::setApplication(KDUpdater::Application *app) +{ + d->m_app = app; +} + +void TabController::setControlScript (const QString &script) +{ + d->m_controlScript = script; +} + +void TabController::init(Tabs curTab) +{ + if (d->m_updaterGuiWidget && !d->m_init) { + d->m_updater.reset(new Updater); + d->m_updater->setInstaller(d->m_installer); + + ComponentSelectionDialog* w = new ComponentSelectionDialog(d->m_installer); + d->m_updater->setUpdaterGui(w); + d->m_updater->init(); + d->m_Tab_Pos_Updater = d->m_updaterGuiWidget->addTab(w, QLatin1String("Updater")); + d->m_Tab_Pos_PackageManager = d->m_updaterGuiWidget->addTab(d->m_gui, + QLatin1String("Package manager")); + + if (d->m_updaterGuiWidget->widget(d->m_Tab_Pos_Updater)->layout()) + verbose() << " tab widget updater tab has layout " << std::endl; + + if (d->m_updaterGuiWidget->widget(d->m_Tab_Pos_PackageManager)->layout()) + verbose() << " tab widget package tab has layout " << std::endl; + + if (d->m_updaterGuiWidget->layout()) + verbose() << " tab has layout " << std::endl; + + if (curTab == PACKAGE_MANAGER_TAB) + d->m_updaterGuiWidget->setCurrentIndex(d->m_Tab_Pos_PackageManager); + + connect(d->m_updater.data(), SIGNAL(updateFinished(bool)), this, SLOT(updaterFinished(bool))); + connect(d->m_updater.data(), SIGNAL(updateFinished(bool)), w, SLOT(refreshDialog())); + connect(w, SIGNAL(rejected()), this, SLOT(updaterFinishedWithError())); + connect(w, SIGNAL(finished(int)), this, SLOT(updaterFinished(int))); + connect(this, SIGNAL(refresh()), w, SLOT(refreshDialog())); + connect(d->m_gui, SIGNAL(accepted()), this, SLOT(finished())); + connect(d->m_gui, SIGNAL(rejected()), this, SLOT(finished())); + connect(d->m_updaterGuiWidget, SIGNAL(currentChanged(int)), this, SLOT(changeCurrentTab(int))); + connect(d->m_updaterGuiWidget, SIGNAL(closeRequested()), this, SLOT(close()), + Qt::QueuedConnection); + connect(d->m_installer, SIGNAL(installationStarted()), this, SLOT(disableUpdaterTab())); + connect(d->m_installer, SIGNAL(uninstallationStarted()), this, SLOT(disableUpdaterTab())); + d->m_init = true; + d->m_updaterGuiWidget->setWindowTitle(d->m_installer->value(QLatin1String("MaintenanceTitle"))); + } +} + +void TabController::close() +{ + if (d->m_updaterGuiWidget && !d->m_gui.isNull()) + d->m_gui->cancelButtonClicked(); +} + +void TabController::disableUpdaterTab() +{ + d->m_updaterGuiWidget->setTabEnabled(d->m_Tab_Pos_Updater, false); +} + +void TabController::enableUpdaterTab() +{ + d->m_updaterGuiWidget->setTabEnabled(d->m_Tab_Pos_Updater, true); +} + +void TabController::restartWizard() +{ + enableUpdaterTab(); + d->m_installer->reset(d->m_params); + checkRepositories(); + + if (d->m_installer->isPackageManager()) + d->preselectInstalledPackages(); +} + +void TabController::finished() +{ + d->m_installer->writeUninstaller(); + d->m_updaterGuiWidget->setCloseWithoutWarning(true); + bool res = d->m_updaterGuiWidget->close(); + bool res2 = d->m_updaterGuiWidget->close(); + verbose() << " widget was closed ? : " << res << " " << res2 << std::endl; +} + +void TabController::updaterFinishedWithError() +{ + d->m_installer->writeUninstaller(); + d->m_state = CANCELED; + + if (d->m_updaterGuiWidget && !d->m_gui.isNull()) + d->m_gui->rejectWithoutPrompt(); + + finished(); +} + +TabController::Status TabController::getState() const +{ + return d->m_state; +} + +int TabController::checkRepositories() +{ + using namespace QInstaller; + + const bool isInstaller = d->m_installer->isInstaller(); + GetRepositoriesMetaInfoJob metaInfoJob(d->m_installer->settings().publicKey(), + d->m_installer->isPackageManager()); + if ((isInstaller && !d->m_installer->isOfflineOnly()) || (d->m_installer->isPackageManager())) + metaInfoJob.setRepositories(d->m_installer->settings().repositories()); + + GetMetaInfoProgressWidget *metaProgress = 0; + QScopedPointer<QProgressDialog> progressDialog(0); + if (isInstaller) { + metaProgress = new GetMetaInfoProgressWidget(d->m_gui->introductionPage()); + d->m_gui->introductionPage()->setWidget(metaProgress); + // disable the 'next' button while performing update + d->m_gui->introductionPage()->setComplete(false); + metaInfoJob.connect(&metaInfoJob, SIGNAL(infoMessage(KDJob*, QString)), metaProgress, + SLOT(message(KDJob*, QString))); + + // show the wizard-gui as early as possible + d->m_gui->connect(d->m_gui, SIGNAL(rejected()), &metaInfoJob, SLOT(doCancel()), + Qt::QueuedConnection); + d->m_gui->setWindowModality(Qt::WindowModal); + d->m_gui->show(); + } else { + progressDialog.reset(new QProgressDialog(d->m_updaterGuiWidget)); + progressDialog->setModal(true); + progressDialog->setLabelText(tr("Checking repository...")); + progressDialog->setRange(0, 0); + connect (progressDialog.data(), SIGNAL(canceled()), &metaInfoJob, SLOT(doCancel()), + Qt::QueuedConnection); + progressDialog->show(); + } + + if (d->m_updaterGuiWidget) { + d->m_updaterGuiWidget->setWindowModality(Qt::WindowModal); + d->m_updaterGuiWidget->show(); + } else { + d->m_gui->setWindowModality(Qt::WindowModal); + d->m_gui->show(); + } + + // start... + try { + metaInfoJob.setAutoDelete(false); + metaInfoJob.start(); + metaInfoJob.waitForFinished(); + d->m_repoReached = true; + } catch (const Error &e) { + MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("Unknown error"), tr("Unknown error"), e.message(), QMessageBox::Ok, + QMessageBox::Ok); + } + + if (metaInfoJob.isCanceled() || metaInfoJob.error() == KDJob::Canceled) + return INST_CANCELED; + + if (metaInfoJob.error() == GetRepositoriesMetaInfoJob::UserIgnoreError) { + d->m_repoReached = false; + } else if (metaInfoJob.error() != KDJob::NoError) { + MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("metaInfoJobError"), QObject::tr("Error"), metaInfoJob.errorString()); + return INST_FAILED; + } + + const QInstaller::TempDirDeleter tempDirDeleter(metaInfoJob.releaseTemporaryDirectories()); + const QStringList tempDirs = tempDirDeleter.paths(); + + foreach (const QString &i, tempDirs) { + if (i.isEmpty()) + continue; + verbose() << "addUpdateSource()" << QUrl::fromLocalFile(i) << std::endl; + const QString updatesXmlPath = i + QLatin1String("/Updates.xml"); + + QFile updatesFile(updatesXmlPath); + try { + openForRead(&updatesFile, updatesFile.fileName()); + } catch(const Error &e) { + MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("Open error"), tr("Error parsing Updates.xml"), e.message()); + return INST_FAILED; + } + + verbose() << "Path to Update.xml " << qPrintable(updatesXmlPath) << std::endl; + + QString err; + int line = 0; + int col = 0; + QDomDocument doc; + if (!doc.setContent(&updatesFile, &err, &line, &col)) { + MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("parseError"), tr("Error parsing Updates.xml"), + tr("Parse error in File %4 : %1 at line %2 col %3").arg(err, QString::number(line), + QString::number(col), updatesFile.fileName())); + return INST_FAILED; + } + + const QDomNode checksum = doc.documentElement().firstChildElement(QLatin1String("Checksum")); + if (!checksum.isNull()) { + const QDomElement checksumElem = checksum.toElement(); + d->m_installer->setTestChecksum(checksumElem.text() == QLatin1String("true")); + } + + verbose() << "addUpdateSource()" << QUrl::fromLocalFile(i) << std::endl; + const QString productName = d->m_installer->value(QLatin1String("ProductName")); + d->m_app->addUpdateSource(productName, productName, QString(), QUrl::fromLocalFile(i), 1); + } + + // The changes done above by adding update source don't count as modification that + // need to be saved cause they will be re-set on the next start anyway. This does + // prevent creating of xml files not needed atm. We can still set the modified + // state later once real things changed that we like to restore at the next startup. + d->m_app->updateSourcesInfo()->setModified(false); + + // create the packages info + KDUpdater::UpdateFinder* const updateFinder = new KDUpdater::UpdateFinder(d->m_app); + QObject::connect(updateFinder, SIGNAL(error(int, QString)), d->m_app, SLOT(printError(int, QString))); + updateFinder->setUpdateType(KDUpdater::PackageUpdate | KDUpdater::NewPackage); + updateFinder->run(); + + try { + // now create installable components + d->m_installer->createComponents(updateFinder->updates(), metaInfoJob); + } catch (const Error &e) { + MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("createComponentsError"), QObject::tr("Error"), e.message()); + } + + if (d->m_installer->status() == QInstaller::Installer::InstallerFailed) + return INST_FAILED; + + // we need at least one component else the installer makes no + // sense cause nothing can be installed. + if (isInstaller) + Q_ASSERT(!d->m_installer->components().isEmpty()); + d->m_repoUpdateNeeded = false; + + if (metaProgress) + metaProgress->close(); + emit refresh(); + + if (d->m_updaterGuiWidget) + d->m_updaterGuiWidget->setTabEnabled(d->m_Tab_Pos_Updater, d->m_repoReached); + + return INST_SUCCESS; +} + +void TabController::updaterFinished(bool error) +{ + if (d->m_installer->needsRestart()) + updaterFinishedWithError(); + else if (!error) + checkRepositories(); +} + +void TabController::updaterFinished(int val) +{ + if (val != QDialog::Accepted) { + if (d->m_updaterGuiWidget && !d->m_gui.isNull()) + d->m_gui->rejectWithoutPrompt(); + finished(); + } +} + +void TabController::canceled() +{ + d->m_installer->writeUninstaller(); + d->m_updaterGuiWidget->setCloseWithoutWarning(true); +} + +int TabController::initPackageManager() +{ + init(PACKAGE_MANAGER_TAB); + + if (d->m_updaterGuiWidget) + d->m_updaterGuiWidget->setTabEnabled(d->m_Tab_Pos_Updater, false); + + // this should called as early as possible, to handle checkRepositories error messageboxes for + // example + if (!d->m_controlScript.isEmpty()) { + verbose() << "Non-interactive installation using script: " << qPrintable(d->m_controlScript) + << std::endl; + d->m_gui->loadControlScript(d->m_controlScript); + QScriptEngine* engine = d->m_gui->controlScriptEngine(); + QScriptValue tabControllerValues = engine->newArray(); + + tabControllerValues.setProperty(QLatin1String("UPDATER"), + engine->newVariant(static_cast<int>(TabController::UPDATER_TAB))); + tabControllerValues.setProperty(QLatin1String("PACKAGE_MANAGER"), + engine->newVariant(static_cast<int>(TabController::PACKAGE_MANAGER_TAB))); + + tabControllerValues.setProperty(QLatin1String("UPDATER_TAB"), + engine->newVariant(static_cast<int>(TabController::UPDATER_TAB))); + tabControllerValues.setProperty(QLatin1String("PACKAGE_MANAGER_TAB"), + engine->newVariant(static_cast<int>(TabController::PACKAGE_MANAGER_TAB))); + + engine->globalObject().setProperty(QLatin1String("TabController"), tabControllerValues); + engine->globalObject().setProperty(QLatin1String("tabController"), engine->newQObject(this)); + if (d->m_updater && d->m_updater->updaterGui()) { + Q_ASSERT(d->m_updater->updaterGui()); + engine->globalObject().setProperty(QLatin1String("updaterGui"), + engine->newQObject(d->m_updater->updaterGui() )); + } + } + + if (d->m_repoUpdateNeeded) { + int result = checkRepositories(); + if (result != INST_SUCCESS && d->m_repoReached) + return result; + } + + // initialize the gui. + d->m_gui->init(); + + if (d->m_installer->isPackageManager()) + d->preselectInstalledPackages(); + + if (d->m_installer->isInstaller()) { + // everything done, enable the 'next' button + d->m_gui->introductionPage()->setComplete(true); + } + + d->m_packageManagerInitialized = true; + if (d->m_updaterGuiWidget) + d->m_updaterGuiWidget->setTabEnabled(d->m_Tab_Pos_Updater, true); + + setCurrentTab(PACKAGE_MANAGER_TAB); //calls callback + d->m_gui->triggerControlScriptForCurrentPage(); + + return INST_SUCCESS; +} + +void TabController::changeCurrentTab(int index) +{ + if (index == d->m_Tab_Pos_PackageManager) { + if (!d->m_packageManagerInitialized) + initPackageManager(); + } else { + if (!d->m_updaterInitialized) + initUpdater(); + } +} |