diff options
Diffstat (limited to 'src/libs/installer/packagemanagercore.cpp')
-rw-r--r-- | src/libs/installer/packagemanagercore.cpp | 944 |
1 files changed, 688 insertions, 256 deletions
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index cb957f9aa..fc1ecff02 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -39,6 +39,7 @@ ** **************************************************************************/ #include "packagemanagercore.h" +#include "packagemanagercore_p.h" #include "adminauthorization.h" #include "binaryformat.h" @@ -47,12 +48,11 @@ #include "downloadarchivesjob.h" #include "errors.h" #include "fsengineclient.h" +#include "globals.h" #include "getrepositoriesmetainfojob.h" #include "messageboxhandler.h" -#include "packagemanagercore_p.h" #include "packagemanagerproxyfactory.h" #include "progresscoordinator.h" -#include "qinstallerglobal.h" #include "qprocesswrapper.h" #include "qsettingswrapper.h" #include "settings.h" @@ -71,9 +71,6 @@ #include <QDesktopServices> #include <QFileDialog> -#include <QtScript/QScriptEngine> -#include <QtScript/QScriptContext> - #include "kdsysinfo.h" #include "kdupdaterupdateoperationfactory.h" @@ -85,30 +82,267 @@ # include <QStandardPaths> #endif +/*! + \qmltype QInstaller + \inqmlmodule scripting + + \brief Provides access to the installer from Qt Script. + + Use the \c installer object in the global namespace to access functionality of the installer. + + \section2 Wizard Pages + + The installer has various pre-defined pages that can be used to for example insert pages + in a certain place: + \list + \li QInstaller.Introduction + \li QInstaller.TargetDirectory + \li QInstaller.ComponentSelection + \li QInstaller.LicenseCheck + \li QInstaller.StartMenuSelection + \li QInstaller.ReadyForInstallation + \li QInstaller.PerformInstallation + \li QInstaller.InstallationFinished + \li QInstaller.End + \endlist +*/ + + +/*! + \qmlproperty enumeration QInstaller::status + + Status of the installer. + + Possible values are: + \list + \li QInstaller.Success (deprecated: QInstaller.InstallerSucceeded) + \li QInstaller.Failure (deprecated: QInstaller.InstallerFailed) + \li QInstaller.Running (deprecated: QInstaller.InstallerFailed) + \li QInstaller.Canceled (deprecated: QInstaller.CanceledByUser) + \li deprecated: QInstaller.InstallerUnfinished + \endlist +*/ + +/*! + \qmlsignal QInstaller::aboutCalculateComponentsToInstall() + + Emitted before the ordered list of components to install is calculated. +*/ + +/*! + \qmlsignal QInstaller::componentAdded(Component component) + + Emitted when a new root component has been added. + + \sa rootComponentsAdded, updaterComponentsAdded +*/ + +/*! + \qmlsignal QInstaller::rootComponentsAdded(list<Component> components) + + Emitted when a new list of root components has been added. + + \sa componentAdded, updaterComponentsAdded +*/ + +/*! + \qmlsignal QInstaller::updaterComponentsAdded(list<Component> components) + + Emitted when a new list of updater components has been added. + \sa componentAdded, rootComponentsAdded +*/ + +/*! + \qmlsignal QInstaller::componentsAboutToBeCleared() + + Deprecated, and not emitted any more. +*/ + +/*! + \qmlsignal QInstaller::valueChanged(string key, string value) + + Emitted whenever a value changes. + + \sa setValue +*/ + +/*! + \qmlsignal QInstaller::statusChanged(Status status) + + Emitted whenever the installer status changes. +*/ + +/*! + \qmlsignal QInstaller::currentPageChanged(int page) + + Emitted whenever the current page changes. +*/ + +/*! + \qmlsignal QInstaller::finishButtonClicked() + + Emitted when the user clicks the \uicontrol Finish button of the installer. +*/ + +/*! + \qmlsignal QInstaller::metaJobInfoMessage(string message) + + Triggered with informative updates of the communication with a remote repository. + This is only useful for debugging purposes. +*/ + +/*! + \qmlsignal QInstaller::startAllComponentsReset() + + Triggered when the list of components starts to get updated. + + \sa finishAllComponentsReset +*/ + +/*! + \qmlsignal QInstaller::finishAllComponentsReset(list<Component> rootComponents) + + Triggered when the list of new root components has been updated. + + \sa startAllComponentsReset +*/ + +/*! + \qmlsignal QInstaller::startUpdaterComponentsReset() + + Triggered when components start to get updated during a remote update. +*/ + +/*! + \qmlsignal QInstaller::finishUpdaterComponentsReset(list<Component> componentsWithUpdates) + + Triggered when the list of available remote updates has been updated. +*/ + +/*! + \qmlsignal QInstaller::installationStarted() + + Triggered when installation has started. + + \sa installationFinished installationInterrupted +*/ + +/*! + \qmlsignal QInstaller::installationInterrupted() + + Triggered when installation has been interrupted (cancelled). + + \sa interrupt installationStarted installationFinished +*/ + +/*! + \qmlsignal QInstaller::installationFinished() + + Triggered when installation has been finished. + + \sa installationStarted installationInterrupted +*/ + +/*! + \qmlsignal QInstaller::updateFinished() + + Triggered when an update has been finished. +*/ + +/*! + \qmlsignal QInstaller::uninstallationStarted() + + Triggered when uninstallation has started. + + \sa uninstallationFinished +*/ + +/*! + \qmlsignal QInstaller::uninstallationFinished() + + Triggered when uninstallation has been finished. + + \sa uninstallationStarted +*/ + +/*! + \qmlsignal QInstaller::titleMessageChanged(string title) + + Emitted when the text of the installer status (on the PerformInstallation page) changes to + \a title. +*/ + +/*! + \qmlsignal QInstaller::wizardPageInsertionRequested(Widget widget, WizardPage page) + + Emitted when a custom \a widget is about to be inserted into \a page by addWizardPage. +*/ + +/*! + \qmlsignal QInstaller::wizardPageRemovalRequested(Widget widget) + + Emitted when a \a widget is removed by removeWizardPage. +*/ + +/*! + \qmlsignal QInstaller::wizardWidgetInsertionRequested(Widget widget, WizardPage page) + + Emitted when a \a widget is inserted into \a page by addWizardPageItem. +*/ + +/*! + \qmlsignal QInstaller::wizardWidgetRemovalRequested(Widget widget) + + Emitted when a \a widget is removed by removeWizardPageItem. +*/ + +/*! + \qmlsignal QInstaller::wizardPageVisibilityChangeRequested(bool visible, int page) + + Emitted when the visibility of the page with id \a page changes to \a visible. + + \sa setDefaultPageVisible +*/ + +/*! + \qmlsignal QInstaller::setValidatorForCustomPageRequested(Componentcomponent, string name, + string callbackName) + + Triggered when setValidatorForCustomPage is called. +*/ + +/*! + \qmlsignal QInstaller::setAutomatedPageSwitchEnabled(bool request) + + Triggered when the automatic switching from PerformInstallation to InstallationFinished page + is enabled (\a request = \c true) or disabled (\a request = \c false). + + The automatic switching is disabled automatically when for example the user expands or unexpands + the \gui Details section of the PerformInstallation page. +*/ + +/*! + \qmlsignal QInstaller::coreNetworkSettingsChanged() + + Emitted when the network settings are changed. +*/ + +/*! + \qmlmethod list<Component> QInstaller::components() + + Returns the list of all components. +*/ + using namespace QInstaller; -static QMutex sModelMutex; +Q_GLOBAL_STATIC(QMutex, globalModelMutex); static QFont *sVirtualComponentsFont = 0; -static QMutex sVirtualComponentsFontMutex; +Q_GLOBAL_STATIC(QMutex, globalVirtualComponentsFontMutex); static bool sNoForceInstallation = false; static bool sVirtualComponentsVisible = false; static bool sCreateLocalRepositoryFromBinary = false; -static QScriptValue checkArguments(QScriptContext *context, int amin, int amax) -{ - if (context->argumentCount() < amin || context->argumentCount() > amax) { - if (amin != amax) { - return context->throwError(QObject::tr("Invalid arguments: %1 arguments given, %2 to " - "%3 expected.").arg(QString::number(context->argumentCount()), - QString::number(amin), QString::number(amax))); - } - return context->throwError(QObject::tr("Invalid arguments: %1 arguments given, %2 expected.") - .arg(QString::number(context->argumentCount()), QString::number(amin))); - } - return QScriptValue(); -} - static bool componentMatches(const Component *component, const QString &name, const QString &version = QString()) { @@ -131,12 +365,12 @@ Component *PackageManagerCore::subComponentByName(const QInstaller::PackageManag if (check != 0 && componentMatches(check, name, version)) return check; - if (installer->runMode() == AllMode) { + if (!installer->isUpdater()) { QList<Component*> rootComponents; if (check == 0) rootComponents = installer->rootComponents(); else - rootComponents = check->childComponents(false, AllMode); + rootComponents = check->childComponents(Component::DirectChildrenOnly); foreach (QInstaller::Component *component, rootComponents) { Component *const result = subComponentByName(installer, name, version, component); @@ -154,146 +388,6 @@ Component *PackageManagerCore::subComponentByName(const QInstaller::PackageManag return 0; } -/*! - Scriptable version of PackageManagerCore::componentByName(QString). - \sa PackageManagerCore::componentByName - */ -QScriptValue QInstaller::qInstallerComponentByName(QScriptContext *context, QScriptEngine *engine) -{ - const QScriptValue check = checkArguments(context, 1, 1); - if (check.isError()) - return check; - - // well... this is our "this" pointer - PackageManagerCore *const core = dynamic_cast<PackageManagerCore*>(engine->globalObject() - .property(QLatin1String("installer")).toQObject()); - - const QString name = context->argument(0).toString(); - return engine->newQObject(core->componentByName(name)); -} - -QScriptValue QInstaller::qDesktopServicesOpenUrl(QScriptContext *context, QScriptEngine *engine) -{ - Q_UNUSED(engine); - const QScriptValue check = checkArguments(context, 1, 1); - if (check.isError()) - return check; - QString url = context->argument(0).toString(); - url.replace(QLatin1String("\\\\"), QLatin1String("/")); - url.replace(QLatin1String("\\"), QLatin1String("/")); - return QDesktopServices::openUrl(QUrl::fromUserInput(url)); -} - -QScriptValue QInstaller::qDesktopServicesDisplayName(QScriptContext *context, QScriptEngine *engine) -{ - Q_UNUSED(engine); - const QScriptValue check = checkArguments(context, 1, 1); - if (check.isError()) - return check; - -#if QT_VERSION < 0x050000 - const QDesktopServices::StandardLocation location = - static_cast< QDesktopServices::StandardLocation >(context->argument(0).toInt32()); - return QDesktopServices::displayName(location); -#else - const QStandardPaths::StandardLocation location = - static_cast< QStandardPaths::StandardLocation >(context->argument(0).toInt32()); - return QStandardPaths::displayName(location); -#endif -} - -QScriptValue QInstaller::qDesktopServicesStorageLocation(QScriptContext *context, QScriptEngine *engine) -{ - Q_UNUSED(engine); - const QScriptValue check = checkArguments(context, 1, 1); - if (check.isError()) - return check; - -#if QT_VERSION < 0x050000 - const QDesktopServices::StandardLocation location = - static_cast< QDesktopServices::StandardLocation >(context->argument(0).toInt32()); - return QDesktopServices::storageLocation(location); -#else - const QStandardPaths::StandardLocation location = - static_cast< QStandardPaths::StandardLocation >(context->argument(0).toInt32()); - return QStandardPaths::writableLocation(location); -#endif -} - -QScriptValue QInstaller::qFileDialogGetExistingDirectory( QScriptContext *context, QScriptEngine *engine ) -{ - Q_UNUSED(engine); - const QScriptValue check = checkArguments(context, 0, 2); - if (check.isError()) - return check; - QString caption; - QString dir; - if (context->argumentCount() > 0) - caption = context->argument(0).toString(); - if (context->argumentCount() > 1) - dir = context->argument(1).toString(); - return QFileDialog::getExistingDirectory(0, caption, dir); -} - -QString QInstaller::uncaughtExceptionString(QScriptEngine *scriptEngine, const QString &context) -{ - QString error(QLatin1String("\n\n%1\n\nBacktrace:\n\t%2")); - if (!context.isEmpty()) - error.prepend(context); - - return error.arg(scriptEngine->uncaughtException().toString(), scriptEngine->uncaughtExceptionBacktrace() - .join(QLatin1String("\n\t"))); -} - - -/*! - \class QInstaller::PackageManagerCore - PackageManagerCore forms the core of the installation, update, maintenance and un-installation system. - */ - -/*! - \enum QInstaller::PackageManagerCore::WizardPage - WizardPage is used to number the different pages known to the Installer GUI. - */ - -/*! - \var QInstaller::PackageManagerCore::Introduction - I ntroduction page. - */ - -/*! - \var QInstaller::PackageManagerCore::LicenseCheck - License check page - */ -/*! - \var QInstaller::PackageManagerCore::TargetDirectory - Target directory selection page - */ -/*! - \var QInstaller::PackageManagerCore::ComponentSelection - %Component selection page - */ -/*! - \var QInstaller::PackageManagerCore::StartMenuSelection - Start menu directory selection page - Microsoft Windows only - */ -/*! - \var QInstaller::PackageManagerCore::ReadyForInstallation - "Ready for Installation" page - */ -/*! - \var QInstaller::PackageManagerCore::PerformInstallation - Page shown while performing the installation - */ -/*! - \var QInstaller::PackageManagerCore::InstallationFinished - Page shown when the installation was finished - */ -/*! - \var QInstaller::PackageManagerCore::End - Non-existing page - this value has to be used if you want to insert a page after \a InstallationFinished - */ - void PackageManagerCore::writeUninstaller() { if (d->m_needToWriteUninstaller) { @@ -319,17 +413,37 @@ void PackageManagerCore::writeUninstaller() } } +void PackageManagerCore::writeMaintenanceConfigFiles() +{ + d->writeMaintenanceConfigFiles(); +} + void PackageManagerCore::reset(const QHash<QString, QString> ¶ms) { d->m_completeUninstall = false; - d->m_forceRestart = false; + d->m_needsHardRestart = false; d->m_status = PackageManagerCore::Unfinished; d->m_installerBaseBinaryUnreplaced.clear(); d->initialize(params); } +void PackageManagerCore::setGuiObject(QObject *gui) +{ + if (gui == d->m_guiObject) + return; + d->m_guiObject = gui; + emit guiObjectChanged(gui); +} + +QObject *PackageManagerCore::guiObject() const +{ + return d->m_guiObject; +} + /*! + \qmlmethod void QInstaller::setCompleteUninstallation(bool complete) + Sets the uninstallation to be \a complete. If \a complete is false, only components deselected by the user will be uninstalled. This option applies only on uninstallation. */ @@ -338,27 +452,60 @@ void PackageManagerCore::setCompleteUninstallation(bool complete) d->m_completeUninstall = complete; } +/*! + \qmlmethod void QInstaller::cancelMetaInfoJob() + + Cancels the retrieval of meta information from a remote repository. + */ void PackageManagerCore::cancelMetaInfoJob() { if (d->m_repoMetaInfoJob) d->m_repoMetaInfoJob->cancel(); } +/*! + \qmlmethod void QInstaller::componentsToInstallNeedsRecalculation() + + Ensures that component dependencies are re-calculated. + */ void PackageManagerCore::componentsToInstallNeedsRecalculation() { d->m_componentsToInstallCalculated = false; } +/*! + \qmlmethod void QInstaller::autoAcceptMessageBoxes() + + Automatically accept all user message boxes. + + \sa autoRejectMessageBoxes, setMessageBoxAutomaticAnswer + */ void PackageManagerCore::autoAcceptMessageBoxes() { MessageBoxHandler::instance()->setDefaultAction(MessageBoxHandler::Accept); } +/*! + \qmlmethod void QInstaller::autoRejectMessageBoxes() + + Automatically reject all user message boxes. + + \sa autoAcceptMessageBoxes, setMessageBoxAutomaticAnswer + */ void PackageManagerCore::autoRejectMessageBoxes() { MessageBoxHandler::instance()->setDefaultAction(MessageBoxHandler::Reject); } +/*! + \qmlmethod void QInstaller::setMessageBoxAutomaticAnswer(string identifier, int button) + + Automatically close the message box with ID \a identifier as if the user had pressed \a button. + + This can be used for unattended (automatic) installations. + + \sa QMessageBox, autoAcceptMessageBoxes, autoRejectMessageBoxes + */ void PackageManagerCore::setMessageBoxAutomaticAnswer(const QString &identifier, int button) { MessageBoxHandler::instance()->setAutomaticAnswer(identifier, @@ -372,6 +519,13 @@ quint64 size(QInstaller::Component *component, const QString &value) return component->value(value).toLongLong(); } +/*! + \qmlmethod float QInstaller::requiredDiskSpace() + + Returns the estimated amount of disk space in bytes required after installation. + + \sa requiredTemporaryDiskSpace + */ quint64 PackageManagerCore::requiredDiskSpace() const { quint64 result = 0; @@ -382,6 +536,13 @@ quint64 PackageManagerCore::requiredDiskSpace() const return result; } +/*! + \qmlmethod float QInstaller::requiredTemporaryDiskSpace() + + Returns the estimated required disk space during installation in bytes. + + \sa requiredDiskSpace + */ quint64 PackageManagerCore::requiredTemporaryDiskSpace() const { quint64 result = 0; @@ -448,11 +609,17 @@ int PackageManagerCore::downloadNeededArchives(double partProgressSize) If a component marked as important was installed during update process true is returned. */ -bool PackageManagerCore::needsRestart() const +bool PackageManagerCore::needsHardRestart() const +{ + return d->m_needsHardRestart; +} + +void PackageManagerCore::setNeedsHardRestart(bool needsHardRestart) { - return d->m_forceRestart; + d->m_needsHardRestart = needsHardRestart; } + void PackageManagerCore::rollBackInstallation() { emit titleMessageChanged(tr("Cancelling the Installer")); @@ -487,7 +654,7 @@ void PackageManagerCore::rollBackInstallation() if (!componentName.isEmpty()) { Component *component = componentByName(componentName); if (!component) - component = d->componentsToReplace(runMode()).value(componentName).second; + component = d->componentsToReplace().value(componentName).second; if (component) { component->setUninstalled(); packages.removePackage(component->name()); @@ -510,12 +677,26 @@ void PackageManagerCore::rollBackInstallation() packages.writeToDisk(); } +/*! + \qmlmethod boolean Installer::isFileExtensionRegistered(string extension) + + Returns whether a file extension is already registered in the Windows registry. Returns \c false + on all other platforms. + */ bool PackageManagerCore::isFileExtensionRegistered(const QString &extension) const { QSettingsWrapper settings(QLatin1String("HKEY_CLASSES_ROOT"), QSettingsWrapper::NativeFormat); return settings.value(QString::fromLatin1(".%1/Default").arg(extension)).isValid(); } +/*! + \qmlmethod boolean QInstaller::fileExists(string filePath) + + Returns \c true if the \a filePath exists; otherwise returns \c false. + + \note If the file is a symlink that points to a non existing + file, \c false is returned. + */ bool PackageManagerCore::fileExists(const QString &filePath) const { return QFileInfo(filePath).exists(); @@ -530,6 +711,8 @@ bool PackageManagerCore::fileExists(const QString &filePath) const PackageManagerCore::PackageManagerCore() : d(new PackageManagerCorePrivate(this)) { + qRegisterMetaType<QInstaller::PackageManagerCore::Status>("QInstaller::PackageManagerCore::Status"); + qRegisterMetaType<QInstaller::PackageManagerCore::WizardPage>("QInstaller::PackageManagerCore::WizardPage"); } PackageManagerCore::PackageManagerCore(qint64 magicmaker, const OperationList &performedOperations) @@ -550,12 +733,16 @@ PackageManagerCore::~PackageManagerCore() QInstaller::VerboseWriter::instance()->setOutputStream(logFileName); } delete d; + + QMutexLocker _(globalVirtualComponentsFontMutex()); + delete sVirtualComponentsFont; + sVirtualComponentsFont = 0; } /* static */ QFont PackageManagerCore::virtualComponentsFont() { - QMutexLocker _(&sVirtualComponentsFontMutex); + QMutexLocker _(globalVirtualComponentsFontMutex()); if (!sVirtualComponentsFont) sVirtualComponentsFont = new QFont; return *sVirtualComponentsFont; @@ -564,7 +751,7 @@ QFont PackageManagerCore::virtualComponentsFont() /* static */ void PackageManagerCore::setVirtualComponentsFont(const QFont &font) { - QMutexLocker _(&sVirtualComponentsFontMutex); + QMutexLocker _(globalVirtualComponentsFontMutex()); if (sVirtualComponentsFont) delete sVirtualComponentsFont; sVirtualComponentsFont = new QFont(font); @@ -606,11 +793,6 @@ void PackageManagerCore::setCreateLocalRepositoryFromBinary(bool create) sCreateLocalRepositoryFromBinary = create; } -RunMode PackageManagerCore::runMode() const -{ - return isUpdater() ? UpdaterMode : AllMode; -} - bool PackageManagerCore::fetchLocalPackagesTree() { d->setStatus(Running); @@ -650,9 +832,8 @@ bool PackageManagerCore::fetchLocalPackagesTree() updateDisplayVersions(scDisplayVersion); - emit finishAllComponentsReset(); + emit finishAllComponentsReset(d->m_rootComponents); d->setStatus(Success); - emit setRootComponents(d->m_rootComponents); return true; } @@ -705,8 +886,8 @@ bool PackageManagerCore::fetchRemotePackagesTree() return false; } - if (!ProductKeyCheck::instance()->hasValidKey()) { - d->setStatus(Failure, ProductKeyCheck::instance()->lastErrorString()); + if (!ProductKeyCheck::instance(this)->hasValidKey()) { + d->setStatus(Failure, ProductKeyCheck::instance(this)->lastErrorString()); return false; } @@ -725,9 +906,39 @@ bool PackageManagerCore::fetchRemotePackagesTree() return false; bool success = false; - if (runMode() == AllMode) + if (!isUpdater()) { success = fetchAllPackages(packages, installedPackages); - else { + if (success && !d->statusCanceledOrFailed() && isPackageManager()) { + foreach (Package *const update, packages) { + if (update->data(scEssential, scFalse).toString().toLower() == scTrue) { + const QString name = update->data(scName).toString(); + if (!installedPackages.contains(name)) { + success = false; + break; // unusual, the maintenance tool should always be available + } + + const LocalPackage localPackage = installedPackages.value(name); + const QString updateVersion = update->data(scRemoteVersion).toString(); + if (KDUpdater::compareVersion(updateVersion, localPackage.version) <= 0) + break; // remote version equals or is less than the installed maintenance tool + + const QDate updateDate = update->data(scReleaseDate).toDate(); + if (localPackage.lastUpdateDate >= updateDate) + break; // remote release date equals or is less than the installed maintenance tool + + success = false; + break; // we found a newer version of the maintenance tool + } + } + + if (!success && !d->statusCanceledOrFailed()) { + updateDisplayVersions(scRemoteDisplayVersion); + d->setStatus(ForceUpdate, tr("There is an important update available, please run the " + "updater first.")); + return false; + } + } + } else { success = fetchUpdaterPackages(packages, installedPackages); } @@ -739,9 +950,16 @@ bool PackageManagerCore::fetchRemotePackagesTree() } /*! + \qmlmethod boolean QInstaller::addWizardPage(Component component, string name, int page) + Adds the widget with objectName() \a name registered by \a component as a new page into the installer's GUI wizard. The widget is added before \a page. - \a page has to be a value of \ref QInstaller::PackageManagerCore::WizardPage "WizardPage". + + See \l{Wizard Pages} for the possible values of \a page. + + Returns \c true if the operation succeeded. + + \sa removeWizardPage, setDefaultPageVisible */ bool PackageManagerCore::addWizardPage(Component *component, const QString &name, int page) { @@ -753,8 +971,14 @@ bool PackageManagerCore::addWizardPage(Component *component, const QString &name } /*! + \qmlmethod boolean QInstaller::removeWizardPage(Component component, string name) + Removes the widget with objectName() \a name previously added to the installer's wizard by \a component. + + Returns \c true if the operation succeeded. + + \sa addWizardPage, setDefaultPageVisible, wizardPageRemovalRequested */ bool PackageManagerCore::removeWizardPage(Component *component, const QString &name) { @@ -766,9 +990,15 @@ bool PackageManagerCore::removeWizardPage(Component *component, const QString &n } /*! + \qmlmethod boolean QInstaller::setDefaultPageVisible(int page, boolean visible) + Sets the visibility of the default page with id \a page to \a visible, i.e. removes or adds it from/to the wizard. This works only for pages which have been in the installer when it was started. + + Returns \c true. + + \sa addWizardPage, removeWizardPage */ bool PackageManagerCore::setDefaultPageVisible(int page, bool visible) { @@ -776,6 +1006,12 @@ bool PackageManagerCore::setDefaultPageVisible(int page, bool visible) return true; } +/*! + \qmlmethod void QInstaller::setValidatorForCustomPage(Component component, string name, + string callbackName) + + \sa setValidatorForCustomPageRequested + */ void PackageManagerCore::setValidatorForCustomPage(Component *component, const QString &name, const QString &callbackName) { @@ -783,9 +1019,14 @@ void PackageManagerCore::setValidatorForCustomPage(Component *component, const Q } /*! + \qmlmethod boolean QInstaller::addWizardPageItem(Component component, string name, int page) + Adds the widget with objectName() \a name registered by \a component as an GUI element into the installer's GUI wizard. The widget is added on \a page. - \a page has to be a value of \ref QInstaller::PackageManagerCore::WizardPage "WizardPage". + + See \l{Wizard Pages} for the possible values of \a page. + + \sa removeWizardPageItem, wizardWidgetInsertionRequested */ bool PackageManagerCore::addWizardPageItem(Component *component, const QString &name, int page) { @@ -797,8 +1038,12 @@ bool PackageManagerCore::addWizardPageItem(Component *component, const QString & } /*! + \qmlmethod boolean QInstaller::removeWizardPageItem(Component component, string name) + Removes the widget with objectName() \a name previously added to the installer's wizard by \a component. + + \sa addWizardPageItem */ bool PackageManagerCore::removeWizardPageItem(Component *component, const QString &name) { @@ -809,6 +1054,13 @@ bool PackageManagerCore::removeWizardPageItem(Component *component, const QStrin return false; } +/*! + \qmlmethod void QInstaller::addUserRepositories(stringlist repositories) + + Registers additional \a repositories. + + \sa setTemporaryRepositories + */ void PackageManagerCore::addUserRepositories(const QStringList &repositories) { QSet<Repository> repositorySet; @@ -819,8 +1071,12 @@ void PackageManagerCore::addUserRepositories(const QStringList &repositories) } /*! - Sets additional repository for this instance of the installer or updater. + \qmlmethod void QInstaller::setTemporaryRepositories(stringlist repositories, boolean replace) + + Sets additional \a repositories for this instance of the installer or updater. Will be removed after invoking it again. + + \sa addUserRepositories */ void PackageManagerCore::setTemporaryRepositories(const QStringList &repositories, bool replace) { @@ -847,6 +1103,16 @@ void PackageManagerCore::setTestChecksum(bool test) d->m_testChecksum = test; } +ScriptEngine *PackageManagerCore::componentScriptEngine() const +{ + return d->componentScriptEngine(); +} + +ScriptEngine *PackageManagerCore::controlScriptEngine() const +{ + return d->controlScriptEngine(); +} + /*! Returns the number of components in the list for installer and package manager mode. Might return 0 in case the engine has only been run in updater mode or no components have been fetched. @@ -886,6 +1152,8 @@ void PackageManagerCore::appendRootComponent(Component *component) } /*! + \qmlmethod int QInstaller::updaterComponentCount() + Returns the number of components in the list for updater mode. Might return 0 in case the engine has only been run in installer or package manager mode or no components have been fetched. */ @@ -934,13 +1202,15 @@ QList<Component*> PackageManagerCore::availableComponents() const QList<Component*> result = d->m_rootComponents; foreach (QInstaller::Component *component, d->m_rootComponents) - result += component->childComponents(true, AllMode); + result += component->childComponents(Component::Descendants); return result + d->m_rootDependencyReplacements; } /*! + \qmlmethod Component QInstaller::componentByName(string name) + Returns a component matching \a name. \a name can also contains a version requirement. - E.g. "com.nokia.sdk.qt" returns any component with that name, "com.nokia.sdk.qt->=4.5" requires + E.g. "org.qt-project.sdk.qt" returns any component with that name, "org.qt-project.sdk.qt->=4.5" requires the returned component to have at least version 4.5. If no component matches the requirement, 0 is returned. */ @@ -968,21 +1238,23 @@ bool PackageManagerCore::calculateComponentsToInstall() const if (!d->m_componentsToInstallCalculated) { d->clearComponentsToInstall(); QList<Component*> components; - if (runMode() == UpdaterMode) { + if (isUpdater()) { foreach (Component *component, updaterComponents()) { if (component->updateRequested()) components.append(component); } - } else if (runMode() == AllMode) { + } else if (!isUpdater()) { // relevant means all components which are not replaced QList<Component*> relevantComponents = rootComponents(); foreach (QInstaller::Component *component, rootComponents()) - relevantComponents += component->childComponents(true, AllMode); + relevantComponents += component->childComponents(Component::Descendants); foreach (Component *component, relevantComponents) { // ask for all components which will be installed to get all dependencies - // even dependencies wich are changed without an increased version - if (component->installationRequested() || (component->isInstalled() && !component->uninstallationRequested())) - components.append(component); + // even dependencies which are changed without an increased version + if (component->installationRequested() || (component->isInstalled() + && !component->uninstallationRequested())) { + components.append(component); + } } } @@ -1005,10 +1277,10 @@ QList<Component*> PackageManagerCore::orderedComponentsToInstall() const */ bool PackageManagerCore::calculateComponentsToUninstall() const { - if (runMode() == UpdaterMode) + if (isUpdater()) return true; - // hack to avoid removeing needed dependencies + // hack to avoid removing needed dependencies QSet<Component*> componentsToInstall = d->m_orderedComponentsToInstall.toSet(); QList<Component*> components; @@ -1046,7 +1318,7 @@ QString PackageManagerCore::installReason(Component *component) const } /*! - Returns a list of components that dependend on \a component. The list can be empty. Note: Auto + Returns a list of components that depend on \a component. The list can be empty. Note: Auto installed dependencies are not resolved. */ QList<Component*> PackageManagerCore::dependees(const Component *_component) const @@ -1090,21 +1362,25 @@ QList<Component*> PackageManagerCore::dependencies(const Component *component, Q ComponentModel *PackageManagerCore::defaultComponentModel() const { - QMutexLocker _(&sModelMutex); + QMutexLocker _(globalModelMutex()); if (!d->m_defaultModel) { d->m_defaultModel = componentModel(const_cast<PackageManagerCore*> (this), QLatin1String("AllComponentsModel")); } + connect(this, SIGNAL(finishAllComponentsReset(QList<QInstaller::Component*>)), d->m_defaultModel, + SLOT(setRootComponents(QList<QInstaller::Component*>))); return d->m_defaultModel; } ComponentModel *PackageManagerCore::updaterComponentModel() const { - QMutexLocker _(&sModelMutex); + QMutexLocker _(globalModelMutex()); if (!d->m_updaterModel) { d->m_updaterModel = componentModel(const_cast<PackageManagerCore*> (this), QLatin1String("UpdaterComponentsModel")); } + connect(this, SIGNAL(finishUpdaterComponentsReset(QList<QInstaller::Component*>)), d->m_updaterModel, + SLOT(setRootComponents(QList<QInstaller::Component*>))); return d->m_updaterModel; } @@ -1114,7 +1390,11 @@ Settings &PackageManagerCore::settings() const } /*! - This method tries to gain admin rights. On success, it returns true. + \qmlmethod boolean QInstaller::gainAdminRights() + + Tries to gain admin rights. On success, it returns \c true. + + \sa dropAdminRights */ bool PackageManagerCore::gainAdminRights() { @@ -1128,7 +1408,11 @@ bool PackageManagerCore::gainAdminRights() } /*! - This method drops gained admin rights. + \qmlmethod void QInstaller::dropAdminRights() + + Drops admin rights gained by gainAdminRights. + + \sa gainAdminRights */ void PackageManagerCore::dropAdminRights() { @@ -1136,7 +1420,9 @@ void PackageManagerCore::dropAdminRights() } /*! - Return true, if a process with \a name is running. On Windows, the comparison + \qmlmethod boolean QInstaller::isProcessRunning(string name) + + Returns true, if a process with \a name is running. On Windows, the comparison is case-insensitive. */ bool PackageManagerCore::isProcessRunning(const QString &name) const @@ -1145,8 +1431,11 @@ bool PackageManagerCore::isProcessRunning(const QString &name) const } /*! - Return true, if a process with \a absoluteFilePath could be killed or isn't running - Note: this is implemented in a semi blocking way (to keep the main thread to paint the UI) + \qmlmethod boolean QInstaller::killProcess(string absoluteFilePath) + + Returns true, if a process with \a absoluteFilePath could be killed or isn't running + + \note This is implemented in a semi blocking way (to keep the main thread to paint the UI). */ bool PackageManagerCore::killProcess(const QString &absoluteFilePath) const { @@ -1180,11 +1469,30 @@ bool PackageManagerCore::killProcess(const QString &absoluteFilePath) const } +/*! + \qmlmethod void QInstaller::setDependsOnLocalInstallerBinary() + + Makes sure the installer runs from a local drive. Otherwise the user will get an + appropriate error message. + + \note This only works on Windows. + + \sa localInstallerBinaryUsed +*/ + void PackageManagerCore::setDependsOnLocalInstallerBinary() { d->m_dependsOnLocalInstallerBinary = true; } +/*! + \qmlmethod boolean QInstaller::localInstallerBinaryUsed() + + Returns \c false if the installer is run on Windows, and the installer has been started from + a remote file system drive. Otherwise returns \c true. + + \sa setDependsOnLocalInstallerBinary +*/ bool PackageManagerCore::localInstallerBinaryUsed() { #ifdef Q_OS_WIN @@ -1194,14 +1502,20 @@ bool PackageManagerCore::localInstallerBinaryUsed() } /*! - Executes a program. + \qmlmethod array QInstaller::execute(string program, stringlist arguments = undefined, + string stdin = "") + + Starts the program \a program with the arguments \a arguments in a + new process and waits for it to finish. + + \a stdin is sent as standard input to the application. + + Returns an empty array if the program could not be executed, otherwise + the output of command as the first item, and the return code as the second. - \param program The program that should be executed. - \param arguments Optional list of arguments. - \param stdIn Optional stdin the program reads. - \return If the command could not be executed, an empty QList, otherwise the output of the - command as first item, the return code as second item. \note On Unix, the output is just the output to stdout, not to stderr. + + \sa executeDetached */ QList<QVariant> PackageManagerCore::execute(const QString &program, const QStringList &arguments, const QString &stdIn) const @@ -1234,12 +1548,24 @@ QList<QVariant> PackageManagerCore::execute(const QString &program, const QStrin } /*! - Executes a program. + \qmlmethod boolean QInstaller::executeDetached(string program, stringlist arguments = undefined, + string workingDirectory = "") + + Starts the program \a program with the arguments \a arguments in a + new process, and detaches from it. Returns \c true on success; + otherwise returns \c false. If the installer exits, the + detached process will continue to live. - \param program The program that should be executed. - \param arguments Optional list of arguments. - \param workingDirectory Optional working directory of the forked process. - \return If the command could not be executed, an false will be returned + \note Arguments that contain spaces are not passed to the + process as separate arguments. + + \b{Unix:} The started process will run in its own session and act + like a daemon. + + \b{Windows:} Arguments that contain spaces are wrapped in quotes. + The started process will run as a regular standalone process. + + The process will be started in the directory \a workingDirectory. */ bool PackageManagerCore::executeDetached(const QString &program, const QStringList &arguments, @@ -1259,16 +1585,20 @@ bool PackageManagerCore::executeDetached(const QString &program, const QStringLi /*! - Returns an environment variable. + \qmlmethod string QInstaller::environmentVariable(string name) + + Returns content of an environment variable \a name. An empty string is returned if the + environment variable is not set. */ QString PackageManagerCore::environmentVariable(const QString &name) const { + if (name.isEmpty()) + return QString(); + #ifdef Q_OS_WIN - const LPCWSTR n = (LPCWSTR) name.utf16(); - LPTSTR buff = (LPTSTR) malloc(4096 * sizeof(TCHAR)); - DWORD getenvret = GetEnvironmentVariable(n, buff, 4096); - QString value = getenvret != 0 ? QString::fromUtf16((const unsigned short *) buff) : QString(); - free(buff); + static TCHAR buffer[32767]; + DWORD size = GetEnvironmentVariable(LPCWSTR(name.utf16()), buffer, 32767); + QString value = QString::fromUtf16((const unsigned short *) buffer, size); if (value.isEmpty()) { static QLatin1String userEnvironmentRegistryPath("HKEY_CURRENT_USER\\Environment"); @@ -1281,14 +1611,14 @@ QString PackageManagerCore::environmentVariable(const QString &name) const } return value; #else - const char *pPath = name.isEmpty() ? 0 : getenv(name.toLatin1()); - return pPath ? QLatin1String(pPath) : QString(); + return QString::fromUtf8(qgetenv(name.toLatin1())); #endif } /*! + \qmlmethod boolean QInstaller::performOperation(string name, stringlist arguments) + Instantly performs an operation \a name with \a arguments. - \sa Component::addOperation */ bool PackageManagerCore::performOperation(const QString &name, const QStringList &arguments) { @@ -1306,7 +1636,9 @@ bool PackageManagerCore::performOperation(const QString &name, const QStringList } /*! - Returns true when \a version matches the \a requirement. + \qmlmethod boolean QInstaller::versionMatches(string version, string requirement) + + Returns \c true when \a version matches the \a requirement. \a requirement can be a fixed version number or it can be prefix by the comparators '>', '>=', '<', '<=' and '='. */ @@ -1333,10 +1665,15 @@ bool PackageManagerCore::versionMatches(const QString &version, const QString &r } /*! + \qmlmethod string QInstaller::findLibrary(string name, stringlist paths = []) + Finds a library named \a name in \a paths. If \a paths is empty, it gets filled with platform dependent default paths. - The resulting path is stored in \a library. + The resulting path is returned. + This method can be used by scripts to check external dependencies. + + \sa findPath */ QString PackageManagerCore::findLibrary(const QString &name, const QStringList &paths) { @@ -1362,9 +1699,14 @@ QString PackageManagerCore::findLibrary(const QString &name, const QStringList & } /*! + \qmlmethod string QInstaller::findPath(string name, stringlist paths = []) + Tries to find a file name \a name in one of \a paths. - The resulting path is stored in \a path. + The resulting path is returned. + This method can be used by scripts to check external dependencies. + + \sa findLibrary */ QString PackageManagerCore::findPath(const QString &name, const QStringList &paths) { @@ -1380,8 +1722,11 @@ QString PackageManagerCore::findPath(const QString &name, const QStringList &pat } /*! + \qmlmethod void QInstaller::setInstallerBaseBinary(string path) + Sets the "installerbase" binary to use when writing the package manager/uninstaller. Set this if an update to installerbase is available. + If not set, the executable segment of the running un/installer will be used. */ void PackageManagerCore::setInstallerBaseBinary(const QString &path) @@ -1390,8 +1735,12 @@ void PackageManagerCore::setInstallerBaseBinary(const QString &path) } /*! + \qmlmethod string QInstaller::value(string key, string defaultValue = "") + Returns the installer value for \a key. If \a key is not known to the system, \a defaultValue is returned. Additionally, on Windows, \a key can be a registry key. + + \sa setValue, containsValue, valueChanged */ QString PackageManagerCore::value(const QString &key, const QString &defaultValue) const { @@ -1399,7 +1748,11 @@ QString PackageManagerCore::value(const QString &key, const QString &defaultValu } /*! + \qmlmethod void QInstaller::setValue(string key, string value) + Sets the installer value for \a key to \a value. + + \sa value, containsValue, valueChanged */ void PackageManagerCore::setValue(const QString &key, const QString &value) { @@ -1409,18 +1762,38 @@ void PackageManagerCore::setValue(const QString &key, const QString &value) } /*! - Returns true, when the installer contains a value for \a key. + \qmlmethod boolean QInstaller::containsValue(string key) + + Returns \c true if the installer contains a value for \a key. + + \sa value, setValue, valueChanged */ bool PackageManagerCore::containsValue(const QString &key) const { return d->m_data.contains(key); } +/*! + \qmlmethod void QInstaller::setSharedFlag(string key, boolean value) + + Sets a shared flag with name \a key to \a value. This is one option + to share information between scripts. + + \sa sharedFlag +*/ void PackageManagerCore::setSharedFlag(const QString &key, bool value) { d->m_sharedFlags.insert(key, value); } +/*! + \qmlmethod boolean QInstaller::sharedFlag(string key) + + Returns shared flag with name \a key. This is one option + to share information between scripts. + + \sa setSharedFlag +*/ bool PackageManagerCore::sharedFlag(const QString &key) const { return d->m_sharedFlags.value(key, false); @@ -1447,7 +1820,7 @@ QString PackageManagerCore::error() const } /*! - Returns true if at least one complete installation/update was successful, even if the user cancelled the + Returns \c true if at least one complete installation/update was successful, even if the user cancelled the newest installation process. */ bool PackageManagerCore::finishedWithSuccess() const @@ -1455,12 +1828,24 @@ bool PackageManagerCore::finishedWithSuccess() const return d->m_status == PackageManagerCore::Success || d->m_needToWriteUninstaller; } +/*! + \qmlmethod void QInstaller::interrupt() + + Cancels an ongoing installation. + + \sa installationInterrupted + */ void PackageManagerCore::interrupt() { setCanceled(); emit installationInterrupted(); } +/*! + \qmlmethod void QInstaller::setCanceled() + + Cancels the installation. + */ void PackageManagerCore::setCanceled() { cancelMetaInfoJob(); @@ -1506,7 +1891,11 @@ QString PackageManagerCore::installerBinaryPath() const } /*! - Returns true when this is the installer running. + \qmlmethod boolean QInstaller::isInstaller() + + Returns \c true if executed in an install step. + + \sa isUninstaller, isUpdater, isPackageManager */ bool PackageManagerCore::isInstaller() const { @@ -1514,47 +1903,79 @@ bool PackageManagerCore::isInstaller() const } /*! - Returns true if this is an offline-only installer. + \qmlmethod boolean QInstaller::isOfflineOnly() + + Returns \c true if this is an offline-only installer. */ bool PackageManagerCore::isOfflineOnly() const { return d->isOfflineOnly(); } +/*! + \qmlmethod void QInstaller::setUninstaller() + + Forces an uninstaller context. + + \sa isUninstaller, setUpdater, setPackageManager +*/ void PackageManagerCore::setUninstaller() { d->m_magicBinaryMarker = QInstaller::MagicUninstallerMarker; } /*! - Returns true when this is the uninstaller running. + \qmlmethod boolean QInstaller::isUninstaller() + + Returns \c true if the script is executed in an uninstall context. + + \sa setUninstaller, isInstaller, isUpdater, isPackageManager */ bool PackageManagerCore::isUninstaller() const { return d->isUninstaller(); } +/*! + \qmlmethod void QInstaller::setUpdater() + + Forces an updater context. + + \sa isUpdater, setUninstaller, setPackageManager +*/ void PackageManagerCore::setUpdater() { d->m_magicBinaryMarker = QInstaller::MagicUpdaterMarker; } /*! - Returns true when this is neither an installer nor an uninstaller running. - Must be an updater, then. + \qmlmethod boolean QInstaller::isUpdater() + + Returns \c true if the script is executed in an updater context. + + \sa setUpdater, isInstaller, isUninstaller, isPackageManager */ bool PackageManagerCore::isUpdater() const { return d->isUpdater(); } +/*! + \qmlmethod void QInstaller::setPackageManager() + + Forces a package manager context. +*/ void PackageManagerCore::setPackageManager() { d->m_magicBinaryMarker = QInstaller::MagicPackageManagerMarker; } + /*! - Returns true when this is the package manager running. + \qmlmethod boolean QInstaller::isPackageManager() + + Returns \c true if the script is executed in a package manager context. + \sa setPackageManager, isInstaller, isUninstaller, isUpdater */ bool PackageManagerCore::isPackageManager() const { @@ -1562,7 +1983,9 @@ bool PackageManagerCore::isPackageManager() const } /*! - Runs the installer. Returns true on success, false otherwise. + \qmlmethod boolean QInstaller::runInstaller() + + Runs the installer. Returns \c true on success, \c false otherwise. */ bool PackageManagerCore::runInstaller() { @@ -1570,7 +1993,9 @@ bool PackageManagerCore::runInstaller() } /*! - Runs the uninstaller. Returns true on success, false otherwise. + \qmlmethod boolean QInstaller::runUninstaller() + + Runs the uninstaller. Returns \c true on success, \c false otherwise. */ bool PackageManagerCore::runUninstaller() { @@ -1578,7 +2003,9 @@ bool PackageManagerCore::runUninstaller() } /*! - Runs the package updater. Returns true on success, false otherwise. + \qmlmethod boolean QInstaller::runPackageUpdater() + + Runs the package updater. Returns \c true on success, \c false otherwise. */ bool PackageManagerCore::runPackageUpdater() { @@ -1586,7 +2013,8 @@ bool PackageManagerCore::runPackageUpdater() } /*! - \internal + \qmlmethod void QInstaller::languageChanged() + Calls languangeChanged on all components. */ void PackageManagerCore::languageChanged() @@ -1646,7 +2074,7 @@ bool PackageManagerCore::updateComponentData(struct Data &data, Component *compo // add downloadable archive from xml const QStringList downloadableArchives = data.package->data(scDownloadableArchives).toString() - .split(scCommaRegExp, QString::SkipEmptyParts); + .split(QInstaller::commaRegExp(), QString::SkipEmptyParts); if (component->isFromOnlineRepository()) { foreach (const QString downloadableArchive, downloadableArchives) @@ -1654,7 +2082,7 @@ bool PackageManagerCore::updateComponentData(struct Data &data, Component *compo } const QStringList componentsToReplace = data.package->data(scReplaces).toString() - .split(scCommaRegExp, QString::SkipEmptyParts); + .split(QInstaller::commaRegExp(), QString::SkipEmptyParts); if (!componentsToReplace.isEmpty()) { // Store the component (this is a component that replaces others) and all components that @@ -1711,14 +2139,14 @@ void PackageManagerCore::storeReplacedComponents(QHash<QString, Component *> &co qWarning() << componentName << "- Does not exist in the repositories anymore."; continue; } - if (!component && !d->componentsToReplace(data.runMode).contains(componentName)) { + if (!component && !d->componentsToReplace().contains(componentName)) { component = new Component(this); component->setValue(scName, componentName); } else { component->loadComponentScript(); - d->replacementDependencyComponents(data.runMode).append(component); + d->replacementDependencyComponents().append(component); } - d->componentsToReplace(data.runMode).insert(componentName, qMakePair(it.key(), component)); + d->componentsToReplace().insert(componentName, qMakePair(it.key(), component)); } } } @@ -1731,7 +2159,6 @@ bool PackageManagerCore::fetchAllPackages(const PackagesList &remotes, const Loc QHash<QString, QInstaller::Component*> components; Data data; - data.runMode = AllMode; data.components = &components; data.installedPackages = &locals; @@ -1762,8 +2189,7 @@ bool PackageManagerCore::fetchAllPackages(const PackagesList &remotes, const Loc if (!d->buildComponentTree(components, true)) return false; - emit finishAllComponentsReset(); - emit setRootComponents(d->m_rootComponents); + emit finishAllComponentsReset(d->m_rootComponents); return true; } @@ -1775,7 +2201,6 @@ bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const QHash<QString, QInstaller::Component *> components; Data data; - data.runMode = UpdaterMode; data.components = &components; data.installedPackages = &locals; @@ -1804,7 +2229,8 @@ bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const bool isValidUpdate = locals.contains(name); if (!isValidUpdate && !replaces.isEmpty()) { - const QStringList possibleNames = replaces.split(scCommaRegExp, QString::SkipEmptyParts); + const QStringList possibleNames = replaces.split(QInstaller::commaRegExp(), + QString::SkipEmptyParts); foreach (const QString &possibleName, possibleNames) { if (locals.contains(possibleName)) { isValidUpdate = true; @@ -1813,7 +2239,9 @@ bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const } } - if (!isValidUpdate) + // break if the update is not valid and if it's not the maintenance tool (we might get an update + // for the maintenance tool even if it's not currently installed - possible offline installation) + if (!isValidUpdate && (update->data(scEssential, scFalse).toString().toLower() == scFalse)) continue; // Update for not installed package found, skip it. const LocalPackage &localPackage = locals.value(name); @@ -1851,14 +2279,18 @@ bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const try { if (!components.isEmpty()) { - // load the scripts and append all components w/o parent to the direct list + // append all components w/o parent to the direct list + foreach (QInstaller::Component *component, components) { + appendUpdaterComponent(component); + } + + // after everything is set up, load the scripts foreach (QInstaller::Component *component, components) { if (d->statusCanceledOrFailed()) return false; component->loadComponentScript(); component->setCheckState(Qt::Checked); - appendUpdaterComponent(component); } // after everything is set up, check installed components @@ -1900,7 +2332,7 @@ bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const } } catch (const Error &error) { d->clearUpdaterComponentLists(); - emit finishUpdaterComponentsReset(); + emit finishUpdaterComponentsReset(QList<QInstaller::Component*>()); d->setStatus(Failure, error.message()); // TODO: make sure we remove all message boxes inside the library at some point. @@ -1909,8 +2341,7 @@ bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const return false; } - emit finishUpdaterComponentsReset(); - emit setRootComponents(d->m_updaterComponents); + emit finishUpdaterComponentsReset(d->m_updaterComponents); return true; } @@ -1963,7 +2394,7 @@ QString PackageManagerCore::findDisplayVersion(const QString &componentName, ComponentModel *PackageManagerCore::componentModel(PackageManagerCore *core, const QString &objectName) const { - ComponentModel *model = new ComponentModel(4, core); + ComponentModel *model = new ComponentModel(5, core); model->setObjectName(objectName); model->setHeaderData(ComponentModelHelper::NameColumn, Qt::Horizontal, @@ -1972,11 +2403,12 @@ ComponentModel *PackageManagerCore::componentModel(PackageManagerCore *core, con ComponentModel::tr("Installed Version")); model->setHeaderData(ComponentModelHelper::NewVersionColumn, Qt::Horizontal, ComponentModel::tr("New Version")); + model->setHeaderData(ComponentModelHelper::ReleaseDateColumn, Qt::Horizontal, + ComponentModel::tr("Release Date")); model->setHeaderData(ComponentModelHelper::UncompressedSizeColumn, Qt::Horizontal, ComponentModel::tr("Size")); - connect(this, SIGNAL(setRootComponents(QList<QInstaller::Component*>)), model, - SLOT(setRootComponents(QList<QInstaller::Component*>))); - connect(model, SIGNAL(defaultCheckStateChanged(bool)), this, SLOT(componentsToInstallNeedsRecalculation())); + connect(model, SIGNAL(checkStateChanged(QInstaller::ComponentModel::ModelState)), this, + SLOT(componentsToInstallNeedsRecalculation())); return model; } |