diff options
Diffstat (limited to 'src/libs')
25 files changed, 578 insertions, 263 deletions
diff --git a/src/libs/7zip/7zip.pri b/src/libs/7zip/7zip.pri index c128d0397..823e3ab1d 100644 --- a/src/libs/7zip/7zip.pri +++ b/src/libs/7zip/7zip.pri @@ -3,6 +3,7 @@ win32 { INCLUDEPATH += $$7ZIP_BASE/C $$7ZIP_BASE/CPP DEFINES += WIN_LONG_PATH _UNICODE _NO_CRYPTO QMAKE_CXXFLAGS_RELEASE -= -Zc:strictStrings + QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO -= -Zc:strictStrings } unix { diff --git a/src/libs/installer/component.cpp b/src/libs/installer/component.cpp index 2d6836ed0..86388cc2e 100644 --- a/src/libs/installer/component.cpp +++ b/src/libs/installer/component.cpp @@ -72,7 +72,7 @@ static const QLatin1String scForcedInstallation("ForcedInstallation"); \qmltype component \inqmlmodule scripting - \brief The component type represents the current component that the Qt Script belongs to. + \brief Represents the current component that the Qt Script belongs to. A minimal valid script needs to contain a constructor, which can look like this: @@ -156,7 +156,7 @@ static const QLatin1String scForcedInstallation("ForcedInstallation"); /*! \qmlproperty stringlist component::autoDependencies - Returns the value of the \c <AutoDependsOn> tag in the package information file. + Returns the value of the \c <AutoDependOn> tag in the package information file. */ /*! @@ -342,8 +342,10 @@ quint64 Component::updateUncompressedSize() { quint64 size = 0; - if (installationRequested() || updateRequested()) + if (installAction() == ComponentModelHelper::Install + || installAction() == ComponentModelHelper::KeepInstalled) { size = d->m_vars.value(scUncompressedSize).toLongLong(); + } foreach (Component* comp, d->m_allChildComponents) size += comp->updateUncompressedSize(); @@ -534,8 +536,7 @@ void Component::loadTranslations(const QDir &directory, const QStringList &qms) { QDirIterator it(directory.path(), qms, QDir::Files); const QStringList translations = d->m_core->settings().translations(); - const QString uiLanguage = QLocale().uiLanguages().value(0, QLatin1String("en_us")) - .replace(QLatin1Char('-'), QLatin1Char('_')); + const QString uiLanguage = QLocale().uiLanguages().value(0, QLatin1String("en")); while (it.hasNext()) { const QString filename = it.next(); const QString basename = QFileInfo(filename).baseName(); @@ -583,6 +584,7 @@ void Component::loadUserInterfaces(const QDir &directory, const QStringList &uis throw Error(tr("Could not load the requested UI file '%1'. Error: %2").arg(it.fileName(), loader.errorString())); } + d->scriptEngine()->newQObject(widget); d->m_userInterfaces.insert(widget->objectName(), widget); } } diff --git a/src/libs/installer/component_p.cpp b/src/libs/installer/component_p.cpp index 4bcfbf5dc..18ba4b7b5 100644 --- a/src/libs/installer/component_p.cpp +++ b/src/libs/installer/component_p.cpp @@ -204,6 +204,16 @@ void ComponentModelHelper::setSelectable(bool selectable) changeFlags(selectable, Qt::ItemIsSelectable); } +ComponentModelHelper::InstallAction ComponentModelHelper::installAction() const +{ + return data(ComponentModelHelper::Action).value<ComponentModelHelper::InstallAction>(); +} + +void ComponentModelHelper::setInstallAction(ComponentModelHelper::InstallAction action) +{ + setData(QVariant::fromValue<ComponentModelHelper::InstallAction>(action), ComponentModelHelper::Action); +} + /*! Returns the item flags for the component. The item flags determine how the user can interact with the component. diff --git a/src/libs/installer/component_p.h b/src/libs/installer/component_p.h index 15834d1f2..87e067ba4 100644 --- a/src/libs/installer/component_p.h +++ b/src/libs/installer/component_p.h @@ -93,18 +93,28 @@ class INSTALLER_EXPORT ComponentModelHelper { public: enum Roles { - LocalDisplayVersion = Qt::UserRole + 1, + Action = Qt::UserRole + 1, + LocalDisplayVersion, RemoteDisplayVersion, ReleaseDate, UncompressedSize }; + enum InstallAction { + Install, + Uninstall, + KeepInstalled, + KeepUninstalled + }; + enum Column { NameColumn = 0, + ActionColumn, InstalledVersionColumn, NewVersionColumn, ReleaseDateColumn, - UncompressedSizeColumn + UncompressedSizeColumn, + LastColumn }; explicit ComponentModelHelper(); @@ -125,6 +135,9 @@ public: bool isSelectable() const; void setSelectable(bool selectable); + InstallAction installAction() const; + void setInstallAction(InstallAction action); + Qt::ItemFlags flags() const; void setFlags(Qt::ItemFlags flags); @@ -148,4 +161,6 @@ private: } // namespace QInstaller +Q_DECLARE_METATYPE(QInstaller::ComponentModelHelper::InstallAction) + #endif // COMPONENT_P_H diff --git a/src/libs/installer/componentchecker.cpp b/src/libs/installer/componentchecker.cpp index 5f07c74fd..64ce851a0 100644 --- a/src/libs/installer/componentchecker.cpp +++ b/src/libs/installer/componentchecker.cpp @@ -48,51 +48,68 @@ QStringList ComponentChecker::checkComponent(Component *component) const bool defaultPropertyValue = component->variables().value(scDefault).compare(scTrue, Qt::CaseInsensitive) == 0; if (!component->autoDependencies().isEmpty()) { if (component->forcedInstallation()) { - checkResult << tr("Component %1 specifies \"ForcedInstallation\" property " - "together with \"AutoDependOn\" list. This combination of states " - "may not work properly." - ).arg(component->name()); + checkResult << QString::fromLatin1("Component %1 specifies \"ForcedInstallation\" property " + "together with \"AutoDependOn\" list. This combination of states may not work properly.") + .arg(component->name()); } if (defaultPropertyScriptValue) { - checkResult << tr("Component %1 specifies script value for \"Default\" property " - "together with \"AutoDependOn\" list. This combination of states " - "may not work properly." - ).arg(component->name()); + checkResult << QString::fromLatin1("Component %1 specifies script value for \"Default\" " + "property together with \"AutoDependOn\" list. This combination of states may not " + "work properly.").arg(component->name()); } if (defaultPropertyValue) { - checkResult << tr("Component %1 specifies \"Default\" property " - "together with \"AutoDependOn\" list. This combination of states " - "may not work properly." - ).arg(component->name()); + checkResult << QString::fromLatin1("Component %1 specifies \"Default\" property together " + "with \"AutoDependOn\" list. This combination of states may not work properly.") + .arg(component->name()); } } if (component->packageManagerCore()->isInstaller()) { if (component->isTristate()) { if (defaultPropertyScriptValue) { - checkResult << tr("Component %1 specifies script value for \"Default\" property " - "while not being a leaf node. The \"Default\" property " - "will get a \"false\" value." - ).arg(component->name()); + checkResult << QString::fromLatin1("Component %1 specifies script value for \"Default\" " + "property while not being a leaf node. The \"Default\" property will get a " + "\"false\" value.").arg(component->name()); } if (defaultPropertyValue) { - checkResult << tr("Component %1 specifies \"Default\" property " - "while not being a leaf node. The \"Default\" property " - "will get a \"false\" value." - ).arg(component->name()); + checkResult << QString::fromLatin1("Component %1 specifies \"Default\" property " + "while not being a leaf node. The \"Default\" property will get a \"false\" value.") + .arg(component->name()); } } if (!component->isCheckable()) { if (defaultPropertyScriptValue) { - checkResult << tr("Component %1 specifies script value for \"Default\" property " - "while being not checkable. The \"Default\" property " - "will get a \"false\" value." - ).arg(component->name()); + checkResult << QString::fromLatin1("Component %1 specifies script value for \"Default\" " + "property while being not checkable. The \"Default\" property will get a \"false\" " + "value.").arg(component->name()); } if (defaultPropertyValue) { - checkResult << tr("Component %1 specifies \"Default\" property " - "while being not checkable. The \"Default\" property " - "will get a \"false\" value." - ).arg(component->name()); + checkResult << QString::fromLatin1("Component %1 specifies \"Default\" property " + "while being not checkable. The \"Default\" property will get a \"false\" value.") + .arg(component->name()); + } + } + if (component->childCount()) { + const QStringList autoDependencies = component->autoDependencies(); + if (!autoDependencies.isEmpty()) { + checkResult << QString::fromLatin1("Component %1 auto depends on other components " + "while having children components. This will not work properly.") + .arg(component->name()); + } + + // TODO: search also for components which autodepend on "component" + // (something like core->autodependees(component)) + + if (!component->dependencies().isEmpty()) { + checkResult << QString::fromLatin1("Component %1 depends on other components " + "while having children components. This will not work properly.") + .arg(component->name()); + } + + PackageManagerCore *core = component->packageManagerCore(); + if (!core->dependees(component).isEmpty()) { + checkResult << QString::fromLatin1("Other components depend on component %1 " + "which has children components. This will not work properly.") + .arg(component->name()); } } } diff --git a/src/libs/installer/componentmodel.cpp b/src/libs/installer/componentmodel.cpp index 4c4bda080..d2537dea0 100644 --- a/src/libs/installer/componentmodel.cpp +++ b/src/libs/installer/componentmodel.cpp @@ -36,6 +36,7 @@ #include "component.h" #include "packagemanagercore.h" +#include <QIcon> namespace QInstaller { @@ -71,6 +72,20 @@ namespace QInstaller { or unchecked, or some individual component's checked state has changed. */ +class IconCache +{ +public: + IconCache() { + } + + QIcon icon(ComponentModelHelper::InstallAction action) const { + return m_icons.value(action); + } +private: + QMap<ComponentModelHelper::InstallAction, QIcon> m_icons; +}; + +Q_GLOBAL_STATIC(IconCache, iconCache) /*! Constructs an component model with the given number of \a columns and \a core as parent. @@ -179,6 +194,25 @@ QVariant ComponentModel::data(const QModelIndex &index, int role) const if (index.column() > 0) { if (role == Qt::CheckStateRole) return QVariant(); + if (index.column() == ComponentModelHelper::ActionColumn) { + if (role == Qt::DecorationRole) + return iconCache->icon(component->installAction()); + if (role == Qt::ToolTipRole) { + switch (component->installAction()) { + case ComponentModelHelper::Install: + return tr("Component is marked for installation."); + case ComponentModelHelper::Uninstall: + return tr("Component is marked for uninstallation."); + case ComponentModelHelper::KeepInstalled: + return tr("Component is installed."); + case ComponentModelHelper::KeepUninstalled: + return tr("Component is not installed."); + default: + return QString(); + } + } + return QVariant(); + } if (role == Qt::EditRole || role == Qt::DisplayRole || role == Qt::ToolTipRole) return component->data(Qt::UserRole + index.column()); } @@ -202,6 +236,8 @@ bool ComponentModel::setData(const QModelIndex &index, const QVariant &value, in return false; if (role == Qt::CheckStateRole) { + if (index.column() != 0) + return false; ComponentSet nodes = component->childItems().toSet(); Qt::CheckState newValue = Qt::CheckState(value.toInt()); if (newValue == Qt::PartiallyChecked) { @@ -459,6 +495,15 @@ void ComponentModel::updateAndEmitModelState() } emit checkStateChanged(m_modelState); + + foreach (const Component *component, m_rootComponentList) { + emit dataChanged(indexFromComponentName(component->name()), + indexFromComponentName(component->name())); + QList<Component *> children = component->childItems(); + foreach (const Component *child, children) + emit dataChanged(indexFromComponentName(child->name()), + indexFromComponentName(child->name())); + } } void ComponentModel::collectComponents(Component *const component, const QModelIndex &parent) const @@ -470,15 +515,6 @@ void ComponentModel::collectComponents(Component *const component, const QModelI namespace ComponentModelPrivate { -struct NameGreaterThan -{ - bool operator() (const Component *lhs, const Component *rhs) const - { - return lhs->name() > rhs->name(); - } -}; - -// call it only for items with childern static Qt::CheckState verifyPartiallyChecked(Component *component) { bool anyChecked = false; @@ -514,22 +550,19 @@ static Qt::CheckState verifyPartiallyChecked(Component *component) QSet<QModelIndex> ComponentModel::updateCheckedState(const ComponentSet &components, Qt::CheckState state) { // get all parent nodes for the components we're going to update - ComponentSet nodes = components; - foreach (Component *const component, components) { - if (Component *parent = component->parentComponent()) { - nodes.insert(parent); - while (parent->parentComponent() != 0) { - parent = parent->parentComponent(); - nodes.insert(parent); - } + QMap<QString, Component *> sortedNodesMap; + foreach (Component *component, components) { + while (component && !sortedNodesMap.values(component->name()).contains(component)) { + sortedNodesMap.insertMulti(component->name(), component); + component = component->parentComponent(); } } QSet<QModelIndex> changed; - // sort the nodes, so we can start in descending order to check node and tri-state nodes properly - ComponentList sortedNodes = nodes.toList(); - std::sort(sortedNodes.begin(), sortedNodes.end(), ComponentModelPrivate::NameGreaterThan()); - foreach (Component *const node, sortedNodes) { + const ComponentList sortedNodes = sortedNodesMap.values(); + // we can start in descending order to check node and tri-state nodes properly + for (int i = sortedNodes.count(); i > 0; i--) { + Component * const node = sortedNodes.at(i - 1); if (!node->isCheckable()) continue; @@ -559,10 +592,6 @@ QSet<QModelIndex> ComponentModel::updateCheckedState(const ComponentSet &compone break; } } - - // update all nodes uncompressed size - foreach (Component *const node, m_rootComponentList) - node->updateUncompressedSize(); // this is a recursive call return changed; } diff --git a/src/libs/installer/createlocalrepositoryoperation.cpp b/src/libs/installer/createlocalrepositoryoperation.cpp index b2f7232d8..c53cebee6 100644 --- a/src/libs/installer/createlocalrepositoryoperation.cpp +++ b/src/libs/installer/createlocalrepositoryoperation.cpp @@ -291,7 +291,7 @@ bool CreateLocalRepositoryOperation::performOperation() if (!isOpen) // If we reach that point, either the resource was opened already. resource->close(); // or we did open it and have to close it again. } - emit progressChanged(.65f + ((double(i) / double(name.count())) * .25f)); + emit progressChanged(.65f + ((double(i) / double(names.count())) * .25f)); } } diff --git a/src/libs/installer/installercalculator.cpp b/src/libs/installer/installercalculator.cpp index e4773460d..10f7327db 100644 --- a/src/libs/installer/installercalculator.cpp +++ b/src/libs/installer/installercalculator.cpp @@ -101,9 +101,6 @@ QString InstallerCalculator::componentsToInstallError() const void InstallerCalculator::realAppendToInstallComponents(Component *component) { if (!component->isInstalled() || component->updateRequested()) { - // remove the checkState method if we don't use selected in scripts - component->setCheckState(Qt::Checked); - m_orderedComponentsToInstall.append(component); m_toInstallComponentIds.insert(component->name()); } diff --git a/src/libs/installer/messageboxhandler.cpp b/src/libs/installer/messageboxhandler.cpp index 266558d93..86e28eb39 100644 --- a/src/libs/installer/messageboxhandler.cpp +++ b/src/libs/installer/messageboxhandler.cpp @@ -44,7 +44,7 @@ \qmltype QMessageBox \inqmlmodule scripting - \brief The QMessageBox type provides a modal dialog for informing the user or asking the user + \brief Provides a modal dialog for informing the user or asking the user a question and receiving an answer. diff --git a/src/libs/installer/observer.cpp b/src/libs/installer/observer.cpp index cfb3d3c31..4bc6d6721 100644 --- a/src/libs/installer/observer.cpp +++ b/src/libs/installer/observer.cpp @@ -68,14 +68,15 @@ QString FileTaskObserver::progressText() const if (bytesReceived.endsWith(tmp)) bytesReceived.chop(tmp.length()); - progressText = bytesReceived + tr(" of ") + bytesToReceive; + progressText = tr("%1 of %2").arg(bytesReceived).arg(bytesToReceive); } else { if (m_bytesTransfered > 0) - progressText = QInstaller::humanReadableSize(m_bytesTransfered) + tr(" received."); + progressText = tr("%1 received.").arg(QInstaller::humanReadableSize(m_bytesTransfered)); } - progressText += QLatin1String(" (") + QInstaller::humanReadableSize(m_bytesPerSecond) + tr("/sec") - + QLatin1Char(')'); + if (!progressText.isEmpty()) + progressText += QLatin1Char(' '); + progressText += tr("(%1/sec)").arg(QInstaller::humanReadableSize(m_bytesPerSecond)); if (m_bytesToTransfer > 0 && m_bytesPerSecond > 0) { const qint64 time = (m_bytesToTransfer - m_bytesTransfered) / m_bytesPerSecond; @@ -86,22 +87,22 @@ QString FileTaskObserver::progressText() const QString days; if (d > 0) - days = QString::number(d) + (d < 2 ? tr(" day") : tr(" days")) + QLatin1String(", "); + days = tr("%n day(s), ", "", d); QString hours; if (h > 0) - hours = QString::number(h) + (h < 2 ? tr(" hour") : tr(" hours")) + QLatin1String(", "); + hours = tr("%n hour(s), ", "", h); QString minutes; if (m > 0) - minutes = QString::number(m) + (m < 2 ? tr(" minute") : tr(" minutes")); + minutes = tr("%n minute(s)", "", m); QString seconds; if (s >= 0 && minutes.isEmpty()) { s = (s <= 0 ? 1 : s); - seconds = QString::number(s) + (s < 2 ? tr(" second") : tr(" seconds")); + seconds = tr("%n second(s)", "", s); } - progressText += tr(" - ") + days + hours + minutes + seconds + tr(" remaining."); + progressText += tr(" - %1%2%3%4 remaining.").arg(days).arg(hours).arg(minutes).arg(seconds); } else { progressText += tr(" - unknown time remaining."); } diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index 960c2da93..8600dc114 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -83,7 +83,7 @@ \qmltype installer \inqmlmodule scripting - \brief The installer type provides access to core functionality of the Qt Installer Framework. + \brief Provides access to core functionality of the Qt Installer Framework. */ /*! @@ -424,7 +424,37 @@ void PackageManagerCore::cancelMetaInfoJob() */ void PackageManagerCore::componentsToInstallNeedsRecalculation() { - d->m_componentsToInstallCalculated = false; + d->clearInstallerCalculator(); + d->clearUninstallerCalculator(); + QList<Component*> selectedComponentsToInstall = componentsMarkedForInstallation(); + + d->m_componentsToInstallCalculated = + d->installerCalculator()->appendComponentsToInstall(selectedComponentsToInstall); + + QList<Component *> componentsToInstall = d->installerCalculator()->orderedComponentsToInstall(); + + QList<Component *> selectedComponentsToUninstall; + foreach (Component *component, components(ComponentType::All)) { + if (component->uninstallationRequested() && !selectedComponentsToInstall.contains(component)) + selectedComponentsToUninstall.append(component); + } + + d->uninstallerCalculator()->appendComponentsToUninstall(selectedComponentsToUninstall); + + QSet<Component *> componentsToUninstall = d->uninstallerCalculator()->componentsToUninstall(); + + foreach (Component *component, components(ComponentType::Root | ComponentType::Descendants)) + component->setInstallAction(component->isInstalled() + ? ComponentModelHelper::KeepInstalled + : ComponentModelHelper::KeepUninstalled); + foreach (Component *component, componentsToUninstall) + component->setInstallAction(ComponentModelHelper::Uninstall); + foreach (Component *component, componentsToInstall) + component->setInstallAction(ComponentModelHelper::Install); + + // update all nodes uncompressed size + foreach (Component *const component, components(ComponentType::Root)) + component->updateUncompressedSize(); // this is a recursive call } /*! @@ -468,15 +498,15 @@ void PackageManagerCore::setMessageBoxAutomaticAnswer(const QString &identifier, quint64 size(QInstaller::Component *component, const QString &value) { - if (!component->isSelected() || component->isInstalled()) - return quint64(0); - return component->value(value).toLongLong(); + if (component->installAction() == ComponentModelHelper::Install) + return component->value(value).toLongLong(); + return quint64(0); } /*! \qmlmethod float installer::requiredDiskSpace() - Returns the estimated amount of disk space in bytes required after installation. + Returns the additional estimated amount of disk space in bytes required after installation. \sa requiredTemporaryDiskSpace */ @@ -966,7 +996,7 @@ bool PackageManagerCore::fetchRemotePackagesTree() 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. - See \l{Wizard Pages} for the possible values of \a page. + See \l{Controller Scripting} for the possible values of \a page. Returns \c true if the operation succeeded. @@ -1035,7 +1065,7 @@ void PackageManagerCore::setValidatorForCustomPage(Component *component, const Q 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. - See \l{Wizard Pages} for the possible values of \a page. + See \l{Controller Scripting} for the possible values of \a page. \sa removeWizardPageItem, wizardWidgetInsertionRequested */ @@ -1235,6 +1265,30 @@ Component *PackageManagerCore::componentByName(const QString &name, const QList< return 0; } +QList<Component *> PackageManagerCore::componentsMarkedForInstallation() const +{ + QList<Component*> markedForInstallation; + const QList<Component*> relevant = components(ComponentType::Root | ComponentType::Descendants); + if (isUpdater()) { + foreach (Component *component, relevant) { + if (component->updateRequested()) + markedForInstallation.append(component); + } + } else { + // relevant means all components which are not replaced + foreach (Component *component, relevant) { + // ask for all components which will be installed to get all dependencies + // even dependencies which are changed without an increased version + if (component->installationRequested() + || (component->isInstalled() + && !component->uninstallationRequested())) { + markedForInstallation.append(component); + } + } + } + return markedForInstallation; +} + /*! \qmlmethod boolean installer::calculateComponentsToInstall() @@ -1248,28 +1302,11 @@ bool PackageManagerCore::calculateComponentsToInstall() const emit aboutCalculateComponentsToInstall(); if (!d->m_componentsToInstallCalculated) { d->clearInstallerCalculator(); - QList<Component*> componentsToInstall; - const QList<Component*> relevant = components(ComponentType::Root | ComponentType::Descendants); - if (isUpdater()) { - foreach (Component *component, relevant) { - if (component->updateRequested()) - componentsToInstall.append(component); - } - } else if (!isUpdater()) { - // relevant means all components which are not replaced - foreach (Component *component, relevant) { - // ask for all components which will be installed to get all dependencies - // even dependencies which are changed without an increased version - if (component->installationRequested() || (component->isInstalled() - && !component->uninstallationRequested())) { - componentsToInstall.append(component); - } - } - } + QList<Component*> selectedComponentsToInstall = componentsMarkedForInstallation(); d->storeCheckState(); d->m_componentsToInstallCalculated = - d->installerCalculator()->appendComponentsToInstall(componentsToInstall); + d->installerCalculator()->appendComponentsToInstall(selectedComponentsToInstall); } emit finishedCalculateComponentsToInstall(); return d->m_componentsToInstallCalculated; @@ -2441,11 +2478,13 @@ QString PackageManagerCore::findDisplayVersion(const QString &componentName, ComponentModel *PackageManagerCore::componentModel(PackageManagerCore *core, const QString &objectName) const { - ComponentModel *model = new ComponentModel(5, core); + ComponentModel *model = new ComponentModel(ComponentModelHelper::LastColumn, core); model->setObjectName(objectName); model->setHeaderData(ComponentModelHelper::NameColumn, Qt::Horizontal, ComponentModel::tr("Component Name")); + model->setHeaderData(ComponentModelHelper::ActionColumn, Qt::Horizontal, + ComponentModel::tr("Action")); model->setHeaderData(ComponentModelHelper::InstalledVersionColumn, Qt::Horizontal, ComponentModel::tr("Installed Version")); model->setHeaderData(ComponentModelHelper::NewVersionColumn, Qt::Horizontal, diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h index df7ac5557..fb16cc29c 100644 --- a/src/libs/installer/packagemanagercore.h +++ b/src/libs/installer/packagemanagercore.h @@ -329,6 +329,7 @@ private: QString findDisplayVersion(const QString &componentName, const QHash<QString, QInstaller::Component*> &components, const QString& versionKey, QHash<QString, bool> &visited); ComponentModel *componentModel(PackageManagerCore *core, const QString &objectName) const; + QList<Component *> componentsMarkedForInstallation() const; private: PackageManagerCorePrivate *const d; diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index ba28c6871..7735f280c 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -78,6 +78,9 @@ #include <qt_windows.h> #endif +#define QUOTE_(x) #x +#define QUOTE(x) QUOTE_(x) + namespace QInstaller { class OperationTracer @@ -433,17 +436,20 @@ ScriptEngine *PackageManagerCorePrivate::controlScriptEngine() const void PackageManagerCorePrivate::clearAllComponentLists() { - qDeleteAll(m_rootComponents); + QList<QInstaller::Component*> toDelete; + + toDelete << m_rootComponents; m_rootComponents.clear(); m_rootDependencyReplacements.clear(); const QList<QPair<Component*, Component*> > list = m_componentsToReplaceAllMode.values(); for (int i = 0; i < list.count(); ++i) - delete list.at(i).second; + toDelete << list.at(i).second; m_componentsToReplaceAllMode.clear(); m_componentsToInstallCalculated = false; + qDeleteAll(toDelete); cleanUpComponentEnvironment(); } @@ -460,8 +466,6 @@ void PackageManagerCorePrivate::clearUpdaterComponentLists() usedComponents.insert(list.at(i).second); } - qDeleteAll(usedComponents); - m_updaterComponents.clear(); m_updaterComponentsDeps.clear(); @@ -470,6 +474,7 @@ void PackageManagerCorePrivate::clearUpdaterComponentLists() m_componentsToReplaceUpdaterMode.clear(); m_componentsToInstallCalculated = false; + qDeleteAll(usedComponents); cleanUpComponentEnvironment(); } @@ -563,8 +568,7 @@ void PackageManagerCorePrivate::initialize(const QHash<QString, QString> ¶ms } if (isInstaller() || packagesInfo.applicationVersion().isEmpty()) { - // TODO: this seems to be wrong, we should ask for ProductVersion defaulting to applicationVersion... - packagesInfo.setApplicationVersion(m_data.settings().applicationVersion()); + packagesInfo.setApplicationVersion(QLatin1String(QUOTE(IFW_REPOSITORY_FORMAT_VERSION))); } if (isInstaller()) { @@ -1475,11 +1479,10 @@ bool PackageManagerCorePrivate::runInstaller() info.setFileName(componentsXmlPath()); // Clear the packages as we might install into an already existing installation folder. info.clearPackageInfoList(); - // also update the application name and version, might be set from a script as well + // also update the application name, might be set from a script as well info.setApplicationName(m_data.value(QLatin1String("ProductName"), m_data.settings().applicationName()).toString()); - info.setApplicationVersion(m_data.value(QLatin1String("ProductVersion"), - m_data.settings().applicationVersion()).toString()); + info.setApplicationVersion(QLatin1String(QUOTE(IFW_REPOSITORY_FORMAT_VERSION))); const int progressOperationCount = countProgressOperations(componentsToInstall) // add one more operation as we support progress @@ -1638,7 +1641,9 @@ bool PackageManagerCorePrivate::runPackageUpdater() } else if (isPackageManager()) { // We found the component, the component is still checked and the dependency solver did not // add the component as install dependency, keep it. - if (component && component->isSelected() && !componentsToInstall.contains(component)) { + if (component + && component->installAction() == ComponentModelHelper::KeepInstalled + && !componentsToInstall.contains(component)) { nonRevertedOperations.append(operation); continue; } @@ -2088,7 +2093,7 @@ LocalPackagesHash PackageManagerCorePrivate::localInstalledPackages() if (packagesInfo.applicationName().isEmpty()) packagesInfo.setApplicationName(m_data.settings().applicationName()); if (packagesInfo.applicationVersion().isEmpty()) - packagesInfo.setApplicationVersion(m_data.settings().applicationVersion()); + packagesInfo.setApplicationVersion(QLatin1String(QUOTE(IFW_REPOSITORY_FORMAT_VERSION))); } if (packagesInfo.error() != KDUpdater::PackagesInfo::NoError) diff --git a/src/libs/installer/packagemanagercoredata.cpp b/src/libs/installer/packagemanagercoredata.cpp index d8b6d3a28..3acc24a76 100644 --- a/src/libs/installer/packagemanagercoredata.cpp +++ b/src/libs/installer/packagemanagercoredata.cpp @@ -108,7 +108,7 @@ PackageManagerCoreData::PackageManagerCoreData(const QHash<QString, QString> &va // fill the variables defined in the settings m_variables.insert(QLatin1String("ProductName"), m_settings.applicationName()); - m_variables.insert(QLatin1String("ProductVersion"), m_settings.applicationVersion()); + m_variables.insert(QLatin1String("ProductVersion"), m_settings.version()); m_variables.insert(scTitle, m_settings.title()); m_variables.insert(scPublisher, m_settings.publisher()); m_variables.insert(QLatin1String("Url"), m_settings.url()); diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp index 5b9e7493a..46ba310ba 100644 --- a/src/libs/installer/packagemanagergui.cpp +++ b/src/libs/installer/packagemanagergui.cpp @@ -177,7 +177,8 @@ protected: void addPageAndProperties(ScriptEngine *engine) { - engine->addQObjectChildren(this); + engine->addToGlobalObject(this); + engine->addToGlobalObject(widget()); static const QStringList properties = QStringList() << QStringLiteral("final") << QStringLiteral("commit") << QStringLiteral("complete"); @@ -203,7 +204,8 @@ class PackageManagerGui::Private { public: Private() - : m_modified(false) + : m_currentId(-1) + , m_modified(false) , m_autoSwitchPage(true) , m_showSettingsButton(false) { @@ -225,7 +227,7 @@ public: QLatin1String("unknown button")); } - + int m_currentId; bool m_modified; bool m_autoSwitchPage; bool m_showSettingsButton; @@ -281,7 +283,7 @@ PackageManagerGui::PackageManagerGui(PackageManagerCore *core, QWidget *parent) connect(m_core, SIGNAL(uninstallationFinished()), this, SLOT(showFinishedPage()), Qt::QueuedConnection); - connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(executeControlScript(int))); + connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(currentPageChanged(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())); @@ -511,8 +513,8 @@ void PackageManagerGui::wizardPageRemovalRequested(QWidget *widget) continue; removePage(pageId); d->m_defaultPages.remove(pageId); - packageManagerCore()->controlScriptEngine()->removeQObjectChildren(dynamicPage); - packageManagerCore()->componentScriptEngine()->removeQObjectChildren(dynamicPage); + packageManagerCore()->controlScriptEngine()->removeFromGlobalObject(dynamicPage); + packageManagerCore()->componentScriptEngine()->removeFromGlobalObject(dynamicPage); } } @@ -522,8 +524,8 @@ void PackageManagerGui::wizardWidgetInsertionRequested(QWidget *widget, Q_ASSERT(widget); if (QWizardPage *const p = QWizard::page(page)) { p->layout()->addWidget(widget); - packageManagerCore()->controlScriptEngine()->addQObjectChildren(p); - packageManagerCore()->componentScriptEngine()->addQObjectChildren(p); + packageManagerCore()->controlScriptEngine()->addToGlobalObject(p); + packageManagerCore()->componentScriptEngine()->addToGlobalObject(p); } } @@ -531,8 +533,8 @@ void PackageManagerGui::wizardWidgetRemovalRequested(QWidget *widget) { Q_ASSERT(widget); widget->setParent(0); - packageManagerCore()->controlScriptEngine()->removeQObjectChildren(widget); - packageManagerCore()->componentScriptEngine()->removeQObjectChildren(widget); + packageManagerCore()->controlScriptEngine()->removeFromGlobalObject(widget); + packageManagerCore()->componentScriptEngine()->removeFromGlobalObject(widget); } void PackageManagerGui::wizardPageVisibilityChangeRequested(bool visible, int p) @@ -698,26 +700,6 @@ void PackageManagerGui::setSettingsButtonEnabled(bool enabled) btn->setEnabled(enabled); } -/** - Returns the first descendant of \a parent that has \a objectName as name. - - This method is meant to be invoked from script. - */ -QObject *PackageManagerGui::findChild(QObject *parent, const QString &objectName) -{ - return parent->findChild<QObject*>(objectName); -} - -/** - Returns all descendants of \a parent that have \a objectName as name. - - This method is meant to be invoked from script. - */ -QList<QObject *> PackageManagerGui::findChildren(QObject *parent, const QString &objectName) -{ - return parent->findChildren<QObject*>(objectName); -} - void PackageManagerGui::customButtonClicked(int which) { if (QWizard::WizardButton(which) == QWizard::CustomButton1 && d->m_showSettingsButton) @@ -735,12 +717,29 @@ void PackageManagerGui::dependsOnLocalInstallerBinary() } } +void PackageManagerGui::currentPageChanged(int newId) +{ + executeControlScript(newId); + + PackageManagerPage *oldPage = qobject_cast<PackageManagerPage *>(page(d->m_currentId)); + if (oldPage) { + oldPage->leaving(); + emit oldPage->left(); + } + + d->m_currentId = newId; + + PackageManagerPage *newPage = qobject_cast<PackageManagerPage *>(page(d->m_currentId)); + if (newPage) { + newPage->entering(); + emit newPage->entered(); + } +} // -- PackageManagerPage PackageManagerPage::PackageManagerPage(PackageManagerCore *core) - : m_fresh(true) - , m_complete(true) + : m_complete(true) , m_needsSettingsButton(false) , m_core(core) , validatorComponent(0) @@ -840,31 +839,6 @@ QWidget *PackageManagerPage::findWidget(const QString &objectName) const return findChild<QWidget*> (objectName); } -/*! - \internal - - Used 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 reimplemented function. -*/ -void PackageManagerPage::setVisible(bool visible) -{ - QWizardPage::setVisible(visible); - if (m_fresh && !visible) { - // this is only hit once when the page gets added to the wizard - m_fresh = false; - return; - } - - if (visible) { - entering(); - emit entered(); - } else { - leaving(); - emit left(); - } -} - int PackageManagerPage::nextId() const { const int next = QWizardPage::nextId(); // the page to show next @@ -1488,12 +1462,30 @@ public: m_treeView->setModel(m_currentModel); m_treeView->setExpanded(m_currentModel->index(0, 0), true); + const bool installActionColumnVisible = false; + if (!installActionColumnVisible) + m_treeView->hideColumn(ComponentModelHelper::ActionColumn); + if (m_core->isInstaller()) { m_treeView->setHeaderHidden(true); - for (int i = 1; i < m_currentModel->columnCount(); ++i) + for (int i = ComponentModelHelper::InstalledVersionColumn; i < m_currentModel->columnCount(); ++i) m_treeView->hideColumn(i); + + if (installActionColumnVisible) { + m_treeView->header()->setStretchLastSection(false); + m_treeView->header()->setSectionResizeMode( + ComponentModelHelper::NameColumn, QHeaderView::Stretch); + m_treeView->header()->setSectionResizeMode( + ComponentModelHelper::ActionColumn, QHeaderView::ResizeToContents); + } } else { m_treeView->header()->setStretchLastSection(true); + if (installActionColumnVisible) { + m_treeView->header()->setSectionResizeMode( + ComponentModelHelper::NameColumn, QHeaderView::Interactive); + m_treeView->header()->setSectionResizeMode( + ComponentModelHelper::ActionColumn, QHeaderView::Interactive); + } for (int i = 0; i < m_currentModel->columnCount(); ++i) m_treeView->resizeColumnToContents(i); } @@ -1797,10 +1789,8 @@ bool TargetDirectoryPage::validatePage() void TargetDirectoryPage::entering() { - if (QPushButton *const b = qobject_cast<QPushButton *>(gui()->button(QWizard::NextButton))) { + if (QPushButton *const b = qobject_cast<QPushButton *>(gui()->button(QWizard::NextButton))) b->setDefault(true); - b->setFocus(); - } } void TargetDirectoryPage::leaving() @@ -2103,7 +2093,7 @@ void ReadyForInstallationPage::entering() quint64 repositorySize = 0; const bool createLocalRepository = packageManagerCore()->createLocalRepositoryFromBinary(); - if (createLocalRepository) { + if (createLocalRepository && packageManagerCore()->isInstaller()) { repositorySize = QFile(QCoreApplication::applicationFilePath()).size(); // if we create a local repository, take that space into account as well required += repositorySize; @@ -2394,10 +2384,8 @@ void FinishedPage::entering() } else { if (packageManagerCore()->isInstaller()) { m_commitButton = wizard()->button(QWizard::FinishButton); - if (QPushButton *const b = qobject_cast<QPushButton *>(m_commitButton)) { + if (QPushButton *const b = qobject_cast<QPushButton *>(m_commitButton)) b->setDefault(true); - b->setFocus(); - } } gui()->setOption(QWizard::NoCancelButton, true); diff --git a/src/libs/installer/packagemanagergui.h b/src/libs/installer/packagemanagergui.h index f99d65593..11848b806 100644 --- a/src/libs/installer/packagemanagergui.h +++ b/src/libs/installer/packagemanagergui.h @@ -77,21 +77,18 @@ public: void loadControlScript(const QString& scriptPath); void callControlScriptMethod(const QString& methodName); - Q_INVOKABLE QWidget *pageById(int id) const; - Q_INVOKABLE QWidget *pageByObjectName(const QString &name) const; + QWidget *pageById(int id) const; + QWidget *pageByObjectName(const QString &name) const; - Q_INVOKABLE QWidget* currentPageWidget() const; - Q_INVOKABLE QWidget* pageWidgetByObjectName(const QString &name) const; + QWidget *currentPageWidget() const; + QWidget *pageWidgetByObjectName(const QString &name) const; - Q_INVOKABLE QString defaultButtonText(int wizardButton) const; - Q_INVOKABLE void clickButton(int wizardButton, int delayInMs = 0); - Q_INVOKABLE bool isButtonEnabled(int wizardButton); + QString defaultButtonText(int wizardButton) const; + void clickButton(int wizardButton, int delayInMs = 0); + bool isButtonEnabled(int wizardButton); - Q_INVOKABLE void showSettingsButton(bool show); - Q_INVOKABLE void setSettingsButtonEnabled(bool enable); - - Q_INVOKABLE QObject *findChild(QObject *parent, const QString &objectName); - Q_INVOKABLE QList<QObject*> findChildren(QObject *parent, const QString &objectName); + void showSettingsButton(bool show); + void setSettingsButtonEnabled(bool enable); void updateButtonLayout(); static QWizard::WizardStyle getStyle(const QString &name); @@ -116,7 +113,6 @@ protected Q_SLOTS: void wizardWidgetInsertionRequested(QWidget *widget, QInstaller::PackageManagerCore::WizardPage page); void wizardWidgetRemovalRequested(QWidget *widget); void wizardPageVisibilityChangeRequested(bool visible, int page); - void executeControlScript(int pageId); void setValidatorForCustomPageRequested(QInstaller::Component *component, const QString &name, const QString &callbackName); @@ -126,11 +122,13 @@ private Q_SLOTS: void onLanguageChanged(); void customButtonClicked(int which); void dependsOnLocalInstallerBinary(); + void currentPageChanged(int newId); protected: bool event(QEvent *event); void showEvent(QShowEvent *event); PackageManagerCore *packageManagerCore() const { return m_core; } + void executeControlScript(int pageId); private: class Private; @@ -182,22 +180,23 @@ protected: virtual void insertWidget(QWidget *widget, const QString &siblingName, int offset = 1); virtual QWidget *findWidget(const QString &objectName) const; - virtual void setVisible(bool visible); // reimp virtual int nextId() const; // reimp + // Used 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 currentPageChanged() signal. virtual void entering() {} // called on entering virtual void leaving() {} // called on leaving - bool isConstructing() const { return m_fresh; } - private: - bool m_fresh; bool m_complete; QString m_titleColor; bool m_needsSettingsButton; PackageManagerCore *m_core; QInstaller::Component *validatorComponent; + + friend class PackageManagerGui; }; diff --git a/src/libs/installer/remoteobject.h b/src/libs/installer/remoteobject.h index 2b6a3ab71..f47cd1367 100644 --- a/src/libs/installer/remoteobject.h +++ b/src/libs/installer/remoteobject.h @@ -97,7 +97,7 @@ public: while (m_socket->bytesAvailable() < size) { if (!m_socket->waitForReadyRead(30000)) { throw Error(tr("Could not read all data after sending command: %1. " - "Bytes expected: %2, Bytes received: %3. Error: %3").arg(name).arg(size) + "Bytes expected: %2, Bytes received: %3. Error: %4").arg(name).arg(size) .arg(m_socket->bytesAvailable()).arg(m_socket->errorString())); } } diff --git a/src/libs/installer/remoteserverconnection.cpp b/src/libs/installer/remoteserverconnection.cpp index 0a142c4be..591ca621e 100644 --- a/src/libs/installer/remoteserverconnection.cpp +++ b/src/libs/installer/remoteserverconnection.cpp @@ -187,7 +187,7 @@ void RemoteServerConnection::handleQProcess(const QString &command, QDataStream while (stream.device()->bytesAvailable() < size) { if (!stream.device()->waitForReadyRead(30000)) { throw Error(tr("Could not read all data after sending command: %1. " - "Bytes expected: %2, Bytes received: %3. Error: %3").arg(command).arg(size) + "Bytes expected: %2, Bytes received: %3. Error: %4").arg(command).arg(size) .arg(stream.device()->bytesAvailable()).arg(stream.device()->errorString())); } } @@ -297,7 +297,7 @@ void RemoteServerConnection::handleQSettings(const QString &command, QDataStream while (stream.device()->bytesAvailable() < size) { if (!stream.device()->waitForReadyRead(30000)) { throw Error(tr("Could not read all data after sending command: %1. " - "Bytes expected: %2, Bytes received: %3. Error: %3").arg(command).arg(size) + "Bytes expected: %2, Bytes received: %3. Error: %4").arg(command).arg(size) .arg(stream.device()->bytesAvailable()).arg(stream.device()->errorString())); } } @@ -388,7 +388,7 @@ void RemoteServerConnection::handleQFSFileEngine(const QString &command, QDataSt while (stream.device()->bytesAvailable() < size) { if (!stream.device()->waitForReadyRead(30000)) { throw Error(tr("Could not read all data after sending command: %1. " - "Bytes expected: %2, Bytes received: %3. Error: %3").arg(command).arg(size) + "Bytes expected: %2, Bytes received: %3. Error: %4").arg(command).arg(size) .arg(stream.device()->bytesAvailable()).arg(stream.device()->errorString())); } } diff --git a/src/libs/installer/scriptengine.cpp b/src/libs/installer/scriptengine.cpp index d15357e0d..fb67a1788 100644 --- a/src/libs/installer/scriptengine.cpp +++ b/src/libs/installer/scriptengine.cpp @@ -54,7 +54,7 @@ namespace QInstaller { /*! \qmltype console \inqmlmodule scripting - \brief The console type provides methods for logging and debugging. + \brief Provides methods for logging and debugging. */ /*! @@ -82,22 +82,37 @@ namespace QInstaller { /*! \qmltype buttons \inqmlmodule scripting + + \brief Provides buttons that can be used on installer pages. + + You can use a set of standard buttons and some custom buttons on the + installer pages. For more information about the buttons used by default on + each installer page, see \l {Controller Scripting}. */ /*! \qmlproperty enumeration buttons::QWizard - \list - \li buttons.BackButton - \li buttons.NextButton - \li buttons.CommitButton - \li buttons.FinishButton - \li buttons.CancelButton - \li buttons.HelpButton - \li buttons.CustomButton1 - \li buttons.CustomButton2 - \li buttons.CustomButton3 - \endlist + Specifies the buttons on an installer page. + + \value buttons.BackButton + The \uicontrol Back button (\uicontrol {Go Back} on OS X.) + \value buttons.NextButton + The \uicontrol Next button (\uicontrol Continue on OS X.) + \value buttons.CommitButton + The \uicontrol Commit button. + \value buttons.FinishButton + The \uicontrol Finish button (\uicontrol Done on OS X.) + \value buttons.CancelButton + The \uicontrol Cancel button. + \value buttons.HelpButton + The \uicontrol Help button. + \value buttons.CustomButton1 + A custom button. + \value buttons.CustomButton2 + A custom button. + \value buttons.CustomButton3 + A custom button. */ /*! @@ -145,7 +160,7 @@ namespace QInstaller { \qmltype QInstaller \inqmlmodule scripting - \brief The QInstaller type provides access to the installer status and pages from Qt Script. + \brief Provides access to the installer status and pages from Qt Script. */ /*! @@ -189,40 +204,139 @@ namespace QInstaller { */ /*! + \qmlsignal gui::interrupted() +*/ + +/*! + \qmlsignal gui::languageChanged() +*/ + +/*! + \qmlsignal gui::finishButtonClicked() +*/ + +/*! + \qmlsignal gui::gotRestarted() +*/ + +/*! + \qmlsignal gui::settingsButtonClicked(); +*/ + +GuiProxy::GuiProxy(ScriptEngine *engine, QObject *parent) : + QObject(parent), + m_engine(engine), + m_gui(0) +{ +} + +void GuiProxy::setPackageManagerGui(PackageManagerGui *gui) +{ + if (m_gui) { + disconnect(m_gui, &PackageManagerGui::interrupted, this, &GuiProxy::interrupted); + disconnect(m_gui, &PackageManagerGui::languageChanged, this, &GuiProxy::languageChanged); + disconnect(m_gui, &PackageManagerGui::finishButtonClicked, this, &GuiProxy::finishButtonClicked); + disconnect(m_gui, &PackageManagerGui::gotRestarted, this, &GuiProxy::gotRestarted); + disconnect(m_gui, &PackageManagerGui::settingsButtonClicked, this, &GuiProxy::settingsButtonClicked); + } + + m_gui = gui; + + if (m_gui) { + connect(m_gui, &PackageManagerGui::interrupted, this, &GuiProxy::interrupted); + connect(m_gui, &PackageManagerGui::languageChanged, this, &GuiProxy::languageChanged); + connect(m_gui, &PackageManagerGui::finishButtonClicked, this, &GuiProxy::finishButtonClicked); + connect(m_gui, &PackageManagerGui::gotRestarted, this, &GuiProxy::gotRestarted); + connect(m_gui, &PackageManagerGui::settingsButtonClicked, this, &GuiProxy::settingsButtonClicked); + } +} + +/*! \qmlmethod object gui::pageById(int id) */ +QJSValue GuiProxy::pageById(int id) const +{ + if (!m_gui) + return QJSValue(); + return m_engine->newQObject(m_gui->pageById(id)); +} /*! \qmlmethod object gui::pageByObjectName(string name) */ +QJSValue GuiProxy::pageByObjectName(const QString &name) const +{ + if (!m_gui) + return QJSValue(); + return m_engine->newQObject(m_gui->pageByObjectName(name)); +} /*! \qmlmethod object gui::currentPageWidget() */ +QJSValue GuiProxy::currentPageWidget() const +{ + if (!m_gui) + return QJSValue(); + return m_engine->newQObject(m_gui->currentPageWidget()); +} /*! \qmlmethod object gui::pageWidgetByObjectName(string name) */ +QJSValue GuiProxy::pageWidgetByObjectName(const QString &name) const +{ + if (!m_gui) + return QJSValue(); + return m_engine->newQObject(m_gui->pageWidgetByObjectName(name)); +} /*! \qmlmethod string gui::defaultButtonText(int wizardButton) */ +QString GuiProxy::defaultButtonText(int wizardButton) const +{ + if (!m_gui) + return QString(); + return m_gui->defaultButtonText(wizardButton); +} /*! \qmlmethod void gui::clickButton(int wizardButton, int delayInMs) */ +void GuiProxy::clickButton(int wizardButton, int delayInMs) +{ + if (m_gui) + m_gui->clickButton(wizardButton, delayInMs); +} /*! \qmlmethod boolean gui::isButtonEnabled(int wizardButton) */ +bool GuiProxy::isButtonEnabled(int wizardButton) +{ + if (!m_gui) + return false; + return m_gui->isButtonEnabled(wizardButton); +} /*! \qmlmethod void gui::showSettingsButton(boolean show) */ +void GuiProxy::showSettingsButton(bool show) +{ + if (m_gui) + m_gui->showSettingsButton(show); +} /*! \qmlmethod void gui::setSettingsButtonEnabled(boolean enable) */ +void GuiProxy::setSettingsButtonEnabled(bool enable) +{ + if (m_gui) + m_gui->setSettingsButtonEnabled(enable); +} /*! \qmlmethod object gui::findChild(object parent, string objectName) @@ -231,6 +345,10 @@ namespace QInstaller { \sa QObject::findChild */ +QJSValue GuiProxy::findChild(QObject *parent, const QString &objectName) +{ + return m_engine->newQObject(parent->findChild<QObject*>(objectName)); +} /*! \qmlmethod object[] gui::findChildren(object parent, string objectName) @@ -239,32 +357,66 @@ namespace QInstaller { \sa QObject::findChildren */ +QList<QJSValue> GuiProxy::findChildren(QObject *parent, const QString &objectName) +{ + QList<QJSValue> children; + foreach (QObject *child, parent->findChildren<QObject*>(objectName)) + children.append(m_engine->newQObject(child)); + return children; +} /*! - \qmlsignal gui::interrupted() + \qmlmethod void gui::cancelButtonClicked() */ +void GuiProxy::cancelButtonClicked() +{ + if (m_gui) + m_gui->cancelButtonClicked(); +} /*! - \qmlsignal gui::languageChanged() + \qmlmethod void gui::reject() */ +void GuiProxy::reject() +{ + if (m_gui) + m_gui->reject(); +} /*! - \qmlsignal gui::finishButtonClicked() + \qmlmethod void gui::rejectWithoutPrompt() */ +void GuiProxy::rejectWithoutPrompt() +{ + if (m_gui) + m_gui->rejectWithoutPrompt(); +} /*! - \qmlsignal gui::gotRestarted() + \qmlmethod void gui::showFinishedPage() */ +void GuiProxy::showFinishedPage() +{ + if (m_gui) + m_gui->showFinishedPage(); +} /*! - \qmlsignal gui::settingsButtonClicked(); + \qmlmethod void gui::setModified(boolean value) */ +void GuiProxy::setModified(bool value) +{ + if (m_gui) + m_gui->setModified(value); +} + /*! Constructs a script engine with \a core as parent. */ -ScriptEngine::ScriptEngine(PackageManagerCore *core) - : QObject(core) +ScriptEngine::ScriptEngine(PackageManagerCore *core) : + QObject(core), + m_guiProxy(new GuiProxy(this, this)) { QJSValue global = m_engine.globalObject(); global.setProperty(QLatin1String("console"), m_engine.newQObject(new ConsoleProxy)); @@ -304,24 +456,45 @@ ScriptEngine::ScriptEngine(PackageManagerCore *core) } else { global.setProperty(QLatin1String("installer"), m_engine.newQObject(new QObject)); } + global.setProperty(QLatin1String("gui"), m_engine.newQObject(m_guiProxy)); global.property(QLatin1String("installer")).setProperty(QLatin1String("componentByName"), proxy.property(QLatin1String("componentByName"))); } +/*! + Creates a JavaScript object that wraps the given QObject \a object. + + Signals and slots, properties and children of \a object are + available as properties of the created QJSValue. In addition some helper methods and properties + are added: + + findChild(), findChildren() recursively search for child objects with the given object name. + + Direct child objects are made accessible as properties under their respective object names. + */ QJSValue ScriptEngine::newQObject(QObject *object) { - QJSValue obj = m_engine.newQObject(object); + QJSValue jsValue = m_engine.newQObject(object); + QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership); // add findChild(), findChildren() methods known from QtScript QJSValue findChild = m_engine.evaluate( QLatin1String("(function() { return gui.findChild(this, arguments[0]); })")); QJSValue findChildren = m_engine.evaluate( QLatin1String("(function() { return gui.findChildren(this, arguments[0]); })")); - obj.setProperty(QLatin1String("findChild"), findChild); - obj.setProperty(QLatin1String("findChildren"), findChildren); + jsValue.setProperty(QLatin1String("findChild"), findChild); + jsValue.setProperty(QLatin1String("findChildren"), findChildren); + + // add all named children as properties + foreach (QObject *const child, object->children()) { + if (child->objectName().isEmpty()) + continue; + jsValue.setProperty(child->objectName(), m_engine.newQObject(child)); + newQObject(child); + } - return obj; + return jsValue; } QJSValue ScriptEngine::evaluate(const QString &program, const QString &fileName, int lineNumber) @@ -329,37 +502,24 @@ QJSValue ScriptEngine::evaluate(const QString &program, const QString &fileName, return m_engine.evaluate(program, fileName, lineNumber); } -void ScriptEngine::addQObjectChildren(QObject *root) +/*! + Registers QObject \a object in the engine, and makes it globally accessible under its object name. + */ +void ScriptEngine::addToGlobalObject(QObject *object) { - if ((!root) || root->objectName().isEmpty()) + if (!object || object->objectName().isEmpty()) return; - const QObjectList children = root->children(); - QJSValue jsParent = newQObject(root); - QQmlEngine::setObjectOwnership(root, QQmlEngine::CppOwnership); - m_engine.globalObject().setProperty(root->objectName(), jsParent); - - foreach (QObject *const child, children) { - if (child->objectName().isEmpty()) - continue; - QQmlEngine::setObjectOwnership(child, QQmlEngine::CppOwnership); - jsParent.setProperty(child->objectName(), m_engine.newQObject(child)); - addQObjectChildren(child); - } + QJSValue value = newQObject(object); + globalObject().setProperty(object->objectName(), value); } -void ScriptEngine::removeQObjectChildren(QObject *root) +/*! + Removes the \a object name from the global object. + */ +void ScriptEngine::removeFromGlobalObject(QObject *object) { - if ((!root) || root->objectName().isEmpty()) - return; - - const QObjectList children = root->children(); - m_engine.globalObject().deleteProperty(root->objectName()); - foreach (QObject *const child, children) { - if (child->objectName().isEmpty()) - continue; - m_engine.globalObject().deleteProperty(child->objectName()); - } + globalObject().deleteProperty(object->objectName()); } /*! @@ -445,8 +605,7 @@ QJSValue ScriptEngine::callScriptMethod(const QJSValue &scriptContext, const QSt void ScriptEngine::setGuiQObject(QObject *guiQObject) { - QQmlEngine::setObjectOwnership(guiQObject, QQmlEngine::CppOwnership); - m_engine.globalObject().setProperty(QLatin1String("gui"), m_engine.newQObject(guiQObject)); + m_guiProxy->setPackageManagerGui(qobject_cast<PackageManagerGui*>(guiQObject)); } diff --git a/src/libs/installer/scriptengine.h b/src/libs/installer/scriptengine.h index c4352d4ca..5b8a3a3ec 100644 --- a/src/libs/installer/scriptengine.h +++ b/src/libs/installer/scriptengine.h @@ -43,6 +43,7 @@ namespace QInstaller { class PackageManagerCore; +class GuiProxy; class INSTALLER_EXPORT ScriptEngine : public QObject { @@ -57,8 +58,8 @@ public: QJSValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1); - void addQObjectChildren(QObject *root); - void removeQObjectChildren(QObject *root); + void addToGlobalObject(QObject *object); + void removeFromGlobalObject(QObject *object); QJSValue loadInContext(const QString &context, const QString &fileName, const QString &scriptInjection = QString()); @@ -77,6 +78,7 @@ private: private: QJSEngine m_engine; QHash<QString, QStringList> m_callstack; + GuiProxy *m_guiProxy; }; } diff --git a/src/libs/installer/scriptengine_p.h b/src/libs/installer/scriptengine_p.h index d207130d7..696073703 100644 --- a/src/libs/installer/scriptengine_p.h +++ b/src/libs/installer/scriptengine_p.h @@ -37,6 +37,7 @@ #include "component.h" #include "packagemanagercore.h" +#include "packagemanagergui.h" #include <QDebug> #include <QDesktopServices> @@ -137,6 +138,50 @@ public slots: }; #endif +class GuiProxy : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(GuiProxy) + +public: + GuiProxy(ScriptEngine *engine, QObject *parent); + void setPackageManagerGui(PackageManagerGui *gui); + + Q_INVOKABLE QJSValue pageById(int id) const; + Q_INVOKABLE QJSValue pageByObjectName(const QString &name) const; + + Q_INVOKABLE QJSValue currentPageWidget() const; + Q_INVOKABLE QJSValue pageWidgetByObjectName(const QString &name) const; + + Q_INVOKABLE QString defaultButtonText(int wizardButton) const; + Q_INVOKABLE void clickButton(int wizardButton, int delayInMs = 0); + Q_INVOKABLE bool isButtonEnabled(int wizardButton); + + Q_INVOKABLE void showSettingsButton(bool show); + Q_INVOKABLE void setSettingsButtonEnabled(bool enable); + + Q_INVOKABLE QJSValue findChild(QObject *parent, const QString &objectName); + Q_INVOKABLE QList<QJSValue> findChildren(QObject *parent, const QString &objectName); + +signals: + void interrupted(); + void languageChanged(); + void finishButtonClicked(); + void gotRestarted(); + void settingsButtonClicked(); + +public slots: + void cancelButtonClicked(); + void reject(); + void rejectWithoutPrompt(); + void showFinishedPage(); + void setModified(bool value); + +private: + ScriptEngine *m_engine; + PackageManagerGui *m_gui; +}; + } // namespace QInstaller Q_DECLARE_METATYPE(QInstaller::ConsoleProxy*) diff --git a/src/libs/installer/settings.cpp b/src/libs/installer/settings.cpp index a225d4262..b591eed90 100644 --- a/src/libs/installer/settings.cpp +++ b/src/libs/installer/settings.cpp @@ -61,6 +61,7 @@ static const QLatin1String scMaintenanceToolIniFile("MaintenanceToolIniFile"); static const QLatin1String scRemoteRepositories("RemoteRepositories"); static const QLatin1String scDependsOnLocalInstallerBinary("DependsOnLocalInstallerBinary"); static const QLatin1String scTranslations("Translations"); +static const QLatin1String scCreateLocalRepository("CreateLocalRepository"); static const QLatin1String scFtpProxy("FtpProxy"); static const QLatin1String scHttpProxy("HttpProxy"); @@ -255,7 +256,8 @@ Settings Settings::fromFileAndPrefix(const QString &path, const QString &prefix, << scAllowSpaceInPath << scAllowNonAsciiCharacters << scWizardStyle << scTitleColor << scWizardDefaultWidth << scWizardDefaultHeight << scRepositorySettingsPageVisible << scTargetConfigurationFile - << scRemoteRepositories << scTranslations << QLatin1String(scControlScript); + << scRemoteRepositories << scTranslations << QLatin1String(scControlScript) + << scCreateLocalRepository; Settings s; s.d->m_data.insert(scPrefix, prefix); @@ -314,6 +316,8 @@ Settings Settings::fromFileAndPrefix(const QString &path, const QString &prefix, s.d->m_data.insert(scDependsOnLocalInstallerBinary, false); if (!s.d->m_data.contains(scRepositorySettingsPageVisible)) s.d->m_data.insert(scRepositorySettingsPageVisible, true); + if (!s.d->m_data.contains(scCreateLocalRepository)) + s.d->m_data.insert(scCreateLocalRepository, false); return s; } @@ -333,7 +337,7 @@ QString Settings::applicationName() const return d->m_data.value(scName).toString(); } -QString Settings::applicationVersion() const +QString Settings::version() const { return d->m_data.value(scVersion).toString(); } @@ -463,6 +467,11 @@ QString Settings::configurationFileName() const return d->m_data.value(scTargetConfigurationFile).toString(); } +bool Settings::createLocalRepository() const +{ + return d->m_data.value(scCreateLocalRepository).toBool(); +} + bool Settings::allowSpaceInPath() const { return d->m_data.value(scAllowSpaceInPath, false).toBool(); diff --git a/src/libs/installer/settings.h b/src/libs/installer/settings.h index a9cf08d85..ed60219b1 100644 --- a/src/libs/installer/settings.h +++ b/src/libs/installer/settings.h @@ -94,7 +94,7 @@ public: int wizardDefaultHeight() const; QString applicationName() const; - QString applicationVersion() const; + QString version() const; QString runProgram() const; QStringList runProgramArguments() const; @@ -111,6 +111,8 @@ public: QString configurationFileName() const; + bool createLocalRepository() const; + bool dependsOnLocalInstallerBinary() const; bool hasReplacementRepos() const; QSet<Repository> repositories() const; diff --git a/src/libs/installer/uninstallercalculator.cpp b/src/libs/installer/uninstallercalculator.cpp index 1b59fd42f..726ee735b 100644 --- a/src/libs/installer/uninstallercalculator.cpp +++ b/src/libs/installer/uninstallercalculator.cpp @@ -68,17 +68,11 @@ void UninstallerCalculator::appendComponentToUninstall(Component *component) foreach (Component *dependee, dependees) appendComponentToUninstall(dependee); - component->setCheckState(Qt::Unchecked); m_componentsToUninstall.insert(component); } void UninstallerCalculator::appendComponentsToUninstall(const QList<Component*> &components) { - if (components.isEmpty()) { - qDebug() << "components list is empty in" << Q_FUNC_INFO; - return; - } - foreach (Component *component, components) appendComponentToUninstall(component); diff --git a/src/libs/installer/utils.cpp b/src/libs/installer/utils.cpp index b8aa46324..2b1eab55c 100644 --- a/src/libs/installer/utils.cpp +++ b/src/libs/installer/utils.cpp @@ -390,7 +390,7 @@ QString QInstaller::windowsErrorString(int errorCode) LocalFree((HLOCAL) string); if (ret.isEmpty() && errorCode == ERROR_MOD_NOT_FOUND) - ret = QCoreApplication::tr("QInstaller", "The specified module could not be found."); + ret = QCoreApplication::translate("QInstaller", "The specified module could not be found."); ret.append(QLatin1String(" (0x")); ret.append(QString::number(uint(errorCode), 16).rightJustified(8, QLatin1Char('0'))); |