diff options
author | Tim Jenssen <tim.jenssen@digia.com> | 2013-08-26 12:24:11 +0200 |
---|---|---|
committer | Tim Jenssen <tim.jenssen@digia.com> | 2013-08-26 12:24:11 +0200 |
commit | d8d93f85d6362e8cfb24a076e3df0504cb93957f (patch) | |
tree | 898b5580dab6ce76d1fea05a723416bee2feeed6 /src/libs/installer | |
parent | cf7efd742ff29f932beb8f20b8b6e8ed4cac141b (diff) | |
parent | f84cbe8da86dac7daf75cacbb3b68127bdff761a (diff) |
Merge remote-tracking branch 'origin/1.4'
Change-Id: I9ee4395291754fd5a56555e1dd974df19ee39376
Diffstat (limited to 'src/libs/installer')
26 files changed, 557 insertions, 164 deletions
diff --git a/src/libs/installer/binaryformat.cpp b/src/libs/installer/binaryformat.cpp index c6562f333..1d257a1b4 100644 --- a/src/libs/installer/binaryformat.cpp +++ b/src/libs/installer/binaryformat.cpp @@ -853,7 +853,15 @@ BinaryContent BinaryContent::readAndRegisterFromBinary(const QString &path) */ BinaryContent BinaryContent::readFromApplicationFile() { +#ifdef Q_OS_MAC + // On Mac, data is always in a separate file so that the binary can be signed + QDir dataPath(QCoreApplication::applicationFilePath()); + dataPath.cdUp(); + dataPath.cd(QLatin1String("Resources")); + return BinaryContent::readFromBinary(dataPath.filePath(QLatin1String("installer.dat"))); +#else return BinaryContent::readFromBinary(QCoreApplication::applicationFilePath()); +#endif } /*! diff --git a/src/libs/installer/component.cpp b/src/libs/installer/component.cpp index 5889c67ce..0ac69aaf8 100644 --- a/src/libs/installer/component.cpp +++ b/src/libs/installer/component.cpp @@ -275,8 +275,8 @@ void Component::loadDataFromPackage(const Package &package) setValue(scDescription, package.data(scDescription).toString()); setValue(scDefault, package.data(scDefault).toString()); setValue(scAutoDependOn, package.data(scAutoDependOn).toString()); - setValue(scCompressedSize, QString::number(0)); - setValue(scUncompressedSize, QString::number(0)); + setValue(scCompressedSize, package.data(scCompressedSize).toString()); + setValue(scUncompressedSize, package.data(scUncompressedSize).toString()); setValue(scRemoteVersion, package.data(scRemoteVersion).toString()); setValue(scInheritVersion, package.data(scInheritVersion).toString()); setValue(scDependencies, package.data(scDependencies).toString()); @@ -948,7 +948,7 @@ bool Component::operationsCreatedSuccessfully() const return d->m_operationsCreatedSuccessfully; } -Operation *Component::createOperation(const QString &operation, const QString ¶meter1, +Operation *Component::createOperation(const QString &operationName, const QString ¶meter1, const QString ¶meter2, const QString ¶meter3, const QString ¶meter4, const QString ¶meter5, const QString ¶meter6, const QString ¶meter7, const QString ¶meter8, const QString ¶meter9, const QString ¶meter10) @@ -975,29 +975,29 @@ Operation *Component::createOperation(const QString &operation, const QString &p if (!parameter10.isNull()) arguments.append(parameter10); - return createOperation(operation, arguments); + return createOperation(operationName, arguments); } -Operation *Component::createOperation(const QString &operation, const QStringList ¶meters) +Operation *Component::createOperation(const QString &operationName, const QStringList ¶meters) { - Operation *op = KDUpdater::UpdateOperationFactory::instance().create(operation); - if (op == 0) { + Operation *operation = KDUpdater::UpdateOperationFactory::instance().create(operationName); + if (operation == 0) { const QMessageBox::StandardButton button = MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("OperationDoesNotExistError"), tr("Error"), tr("Error: Operation %1 does not exist") - .arg(operation), QMessageBox::Abort | QMessageBox::Ignore); + .arg(operationName), QMessageBox::Abort | QMessageBox::Ignore); if (button == QMessageBox::Abort) d->m_operationsCreatedSuccessfully = false; - return op; + return operation; } - if (op->name() == QLatin1String("Delete")) - op->setValue(QLatin1String("performUndo"), false); - op->setValue(QLatin1String("installer"), qVariantFromValue(d->m_core)); + if (operation->name() == QLatin1String("Delete")) + operation->setValue(QLatin1String("performUndo"), false); + operation->setValue(QLatin1String("installer"), qVariantFromValue(d->m_core)); - op->setArguments(d->m_core->replaceVariables(parameters)); - - return op; + operation->setArguments(d->m_core->replaceVariables(parameters)); + operation->setValue(QLatin1String("component"), name()); + return operation; } /*! @@ -1404,6 +1404,9 @@ void Component::updateModelData(const QString &key, const QString &data) if (key == scDisplayVersion) setData(data, LocalDisplayVersion); + if (key == scReleaseDate) + setData(data, ReleaseDate); + if (key == scUncompressedSize) { quint64 size = d->m_vars.value(scUncompressedSizeSum).toLongLong(); setData(humanReadableSize(size), UncompressedSize); diff --git a/src/libs/installer/component.h b/src/libs/installer/component.h index bf5ef4d18..eefe41ebb 100644 --- a/src/libs/installer/component.h +++ b/src/libs/installer/component.h @@ -233,13 +233,13 @@ private Q_SLOTS: private: void setLocalTempPath(const QString &tempPath); - Operation *createOperation(const QString &operation, const QString ¶meter1 = QString(), + Operation *createOperation(const QString &operationName, const QString ¶meter1 = QString(), const QString ¶meter2 = QString(), const QString ¶meter3 = QString(), const QString ¶meter4 = QString(), const QString ¶meter5 = QString(), const QString ¶meter6 = QString(), const QString ¶meter7 = QString(), const QString ¶meter8 = QString(), const QString ¶meter9 = QString(), const QString ¶meter10 = QString()); - Operation *createOperation(const QString &operation, const QStringList ¶meters); + Operation *createOperation(const QString &operationName, const QStringList ¶meters); private: QString validatorCallbackName; diff --git a/src/libs/installer/component_p.h b/src/libs/installer/component_p.h index 1f81ffd4d..1da9eee1a 100644 --- a/src/libs/installer/component_p.h +++ b/src/libs/installer/component_p.h @@ -99,14 +99,16 @@ class INSTALLER_EXPORT ComponentModelHelper public: enum Roles { LocalDisplayVersion = Qt::UserRole + 1, - RemoteDisplayVersion = LocalDisplayVersion + 1, - UncompressedSize = RemoteDisplayVersion + 1 + RemoteDisplayVersion, + ReleaseDate, + UncompressedSize }; enum Column { NameColumn = 0, InstalledVersionColumn, NewVersionColumn, + ReleaseDateColumn, UncompressedSizeColumn }; diff --git a/src/libs/installer/componentmodel.cpp b/src/libs/installer/componentmodel.cpp index f65611ffe..080e84d85 100644 --- a/src/libs/installer/componentmodel.cpp +++ b/src/libs/installer/componentmodel.cpp @@ -324,10 +324,17 @@ void ComponentModel::setRootComponents(QList<QInstaller::Component*> rootCompone m_uncheckable.clear(); m_indexByNameCache.clear(); - m_initialCheckedState.clear(); - m_currentCheckedState.clear(); + m_rootComponentList.clear(); m_modelState = DefaultChecked; + // Initialize these with an empty set for every possible state, cause we compare the hashes later in + // updateAndEmitModelState(). The comparison than might lead to wrong results if one of the checked + // states is absent initially. + m_initialCheckedState[Qt::Checked] = ComponentSet(); + m_initialCheckedState[Qt::Unchecked] = ComponentSet(); + m_initialCheckedState[Qt::PartiallyChecked] = ComponentSet(); + m_currentCheckedState = m_initialCheckedState; // both should be equal + // show virtual components only in case we run as updater or if the core engine is set to show them const bool showVirtuals = m_core->isUpdater() || m_core->virtualComponentsVisible(); foreach (Component *const component, rootComponents) { @@ -519,6 +526,10 @@ 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/extractarchiveoperation_p.h b/src/libs/installer/extractarchiveoperation_p.h index 44e75a949..4e0632830 100644 --- a/src/libs/installer/extractarchiveoperation_p.h +++ b/src/libs/installer/extractarchiveoperation_p.h @@ -117,9 +117,11 @@ public Q_SLOTS: case PackageManagerCore::Failure: state = E_FAIL; break; - case PackageManagerCore::Unfinished: // fall through - case PackageManagerCore::Success: - case PackageManagerCore::Running: + default: // fall through + // PackageManagerCore::Unfinished, PackageManagerCore::Success, PackageManagerCore::Running + // PackageManagerCore::ForceUpdate + + // already set //state = S_OK; break; } diff --git a/src/libs/installer/fsengineclient.cpp b/src/libs/installer/fsengineclient.cpp index 169b1e67b..2a7a8a5bd 100644 --- a/src/libs/installer/fsengineclient.cpp +++ b/src/libs/installer/fsengineclient.cpp @@ -44,6 +44,8 @@ #include "adminauthorization.h" #include "messageboxhandler.h" +#include <QElapsedTimer> + #include <QtCore/QCoreApplication> #include <QtCore/QMutex> #include <QtCore/QProcess> @@ -809,8 +811,14 @@ void FSEngineClientHandler::Private::maybeStartServer() } if (serverStarted) { - QTcpSocket s; // now wait for the socket to arrive - serverStarted = FSEngineClientHandler::instance().connect(&s); + QElapsedTimer t; + t.start(); + while (serverStarting && serverStarted + && t.elapsed() < 30000) { // 30 seconds ought to be enough for the app to start + QTcpSocket s; + if (FSEngineClientHandler::instance().connect(&s)) + serverStarting = false; + } } serverStarting = false; } diff --git a/src/libs/installer/getrepositoriesmetainfojob.cpp b/src/libs/installer/getrepositoriesmetainfojob.cpp index 99b7e4340..c4564e781 100644 --- a/src/libs/installer/getrepositoriesmetainfojob.cpp +++ b/src/libs/installer/getrepositoriesmetainfojob.cpp @@ -42,6 +42,7 @@ #include "getrepositoriesmetainfojob.h" #include "getrepositorymetainfojob.h" +#include "productkeycheck.h" #include "packagemanagercore_p.h" #include <QtCore/QDebug> @@ -52,12 +53,12 @@ using namespace QInstaller; // -- GetRepositoriesMetaInfoJob -GetRepositoriesMetaInfoJob::GetRepositoriesMetaInfoJob(PackageManagerCorePrivate *corePrivate) - : KDJob(corePrivate) +GetRepositoriesMetaInfoJob::GetRepositoriesMetaInfoJob(PackageManagerCore *core) + : KDJob(core) , m_canceled(false) , m_silentRetries(3) , m_haveIgnoredError(false) - , m_corePrivate(corePrivate) + , m_core(core) { setCapabilities(Cancelable); } @@ -118,10 +119,11 @@ bool GetRepositoriesMetaInfoJob::isCanceled() const void GetRepositoriesMetaInfoJob::doStart() { - if ((m_corePrivate->isInstaller() && !m_corePrivate->isOfflineOnly()) - || (m_corePrivate->isUpdater() || m_corePrivate->isPackageManager())) { - foreach (const Repository &repo, m_corePrivate->m_data.settings().repositories()) { - if (repo.isEnabled()) + if ((m_core->isInstaller() && !m_core->isOfflineOnly()) || (m_core->isUpdater() + || m_core->isPackageManager())) { + const ProductKeyCheck *const productKeyCheck = ProductKeyCheck::instance(m_core); + foreach (const Repository &repo, m_core->settings().repositories()) { + if (repo.isEnabled() && productKeyCheck->isValidRepository(repo)) m_repositories += repo; } } @@ -156,7 +158,7 @@ void GetRepositoriesMetaInfoJob::fetchNextRepo() return; } - m_job = new GetRepositoryMetaInfoJob(m_corePrivate, this); + m_job = new GetRepositoryMetaInfoJob(m_core, this); connect(m_job, SIGNAL(finished(KDJob*)), this, SLOT(jobFinished(KDJob*))); connect(m_job, SIGNAL(infoMessage(KDJob*, QString)), this, SIGNAL(infoMessage(KDJob*, QString))); diff --git a/src/libs/installer/getrepositoriesmetainfojob.h b/src/libs/installer/getrepositoriesmetainfojob.h index aa381e3a4..2cc53b82a 100644 --- a/src/libs/installer/getrepositoriesmetainfojob.h +++ b/src/libs/installer/getrepositoriesmetainfojob.h @@ -59,14 +59,14 @@ namespace KDUpdater { namespace QInstaller { class GetRepositoryMetaInfoJob; -class PackageManagerCorePrivate; +class PackageManagerCore; class INSTALLER_EXPORT GetRepositoriesMetaInfoJob : public KDJob { Q_OBJECT public: - explicit GetRepositoriesMetaInfoJob(PackageManagerCorePrivate *corePrivate); + explicit GetRepositoriesMetaInfoJob(PackageManagerCore *core); QStringList temporaryDirectories() const; QStringList releaseTemporaryDirectories() const; @@ -91,7 +91,7 @@ private: bool m_canceled; int m_silentRetries; bool m_haveIgnoredError; - PackageManagerCorePrivate *m_corePrivate; + PackageManagerCore *m_core; QString m_errorString; QList<Repository> m_repositories; diff --git a/src/libs/installer/getrepositorymetainfojob.cpp b/src/libs/installer/getrepositorymetainfojob.cpp index 6913a63e5..1c8d07525 100644 --- a/src/libs/installer/getrepositorymetainfojob.cpp +++ b/src/libs/installer/getrepositorymetainfojob.cpp @@ -111,14 +111,14 @@ private: // -- GetRepositoryMetaInfoJob -GetRepositoryMetaInfoJob::GetRepositoryMetaInfoJob(PackageManagerCorePrivate *corePrivate, QObject *parent) +GetRepositoryMetaInfoJob::GetRepositoryMetaInfoJob(PackageManagerCore *core, QObject *parent) : KDJob(parent) , m_canceled(false) , m_silentRetries(4) , m_retriesLeft(m_silentRetries) , m_downloader(0) , m_waitForDone(false) - , m_corePrivate(corePrivate) + , m_core(core) { setCapabilities(Cancelable); } @@ -331,12 +331,11 @@ void GetRepositoryMetaInfoJob::updatesXmlDownloadFinished() } if (!repositoryUpdates.isEmpty()) { - if (m_corePrivate->m_data.settings().updateDefaultRepositories(repositoryUpdates) - == Settings::UpdatesApplied) { - if (m_corePrivate->isUpdater() || m_corePrivate->isPackageManager()) - m_corePrivate->writeMaintenanceConfigFiles(); - finished(QInstaller::RepositoryUpdatesReceived, tr("Repository updates received.")); - return; + if (m_core->settings().updateDefaultRepositories(repositoryUpdates) == Settings::UpdatesApplied) { + if (m_core->isUpdater() || m_core->isPackageManager()) + m_core->writeMaintenanceConfigFiles(); + finished(QInstaller::RepositoryUpdatesReceived, tr("Repository updates received.")); + return; } } } @@ -538,26 +537,26 @@ void GetRepositoryMetaInfoJob::onAuthenticatorChanged(const QAuthenticator &auth const QString username = authenticator.user(); const QString password = authenticator.password(); if (username != m_repository.username() || password != m_repository.password()) { - QSet<Repository> repositories = m_corePrivate->m_data.settings().defaultRepositories(); + QSet<Repository> repositories = m_core->settings().defaultRepositories(); bool reposChanged = updateRepositories(&repositories, username, password); if (reposChanged) - m_corePrivate->m_data.settings().setDefaultRepositories(repositories); + m_core->settings().setDefaultRepositories(repositories); - repositories = m_corePrivate->m_data.settings().temporaryRepositories(); + repositories = m_core->settings().temporaryRepositories(); reposChanged |= updateRepositories(&repositories, username, password); if (reposChanged) { - m_corePrivate->m_data.settings().setTemporaryRepositories(repositories, - m_corePrivate->m_data.settings().hasReplacementRepos()); + m_core->settings().setTemporaryRepositories(repositories, + m_core->settings().hasReplacementRepos()); } - repositories = m_corePrivate->m_data.settings().userRepositories(); + repositories = m_core->settings().userRepositories(); reposChanged |= updateRepositories(&repositories, username, password); if (reposChanged) - m_corePrivate->m_data.settings().setUserRepositories(repositories); + m_core->settings().setUserRepositories(repositories); if (reposChanged) { - if (m_corePrivate->isUpdater() || m_corePrivate->isPackageManager()) - m_corePrivate->writeMaintenanceConfigFiles(); + if (m_core->isUpdater() || m_core->isPackageManager()) + m_core->writeMaintenanceConfigFiles(); finished(QInstaller::RepositoryUpdatesReceived, tr("Repository updates received.")); } } diff --git a/src/libs/installer/getrepositorymetainfojob.h b/src/libs/installer/getrepositorymetainfojob.h index 8601742a2..803f8b43f 100644 --- a/src/libs/installer/getrepositorymetainfojob.h +++ b/src/libs/installer/getrepositorymetainfojob.h @@ -61,7 +61,7 @@ namespace KDUpdater { namespace QInstaller { class GetRepositoriesMetaInfoJob; -class PackageManagerCorePrivate; +class PackageManagerCore; class INSTALLER_EXPORT GetRepositoryMetaInfoJob : public KDJob { @@ -70,7 +70,7 @@ class INSTALLER_EXPORT GetRepositoryMetaInfoJob : public KDJob friend class QInstaller::GetRepositoriesMetaInfoJob; public: - explicit GetRepositoryMetaInfoJob(PackageManagerCorePrivate *corePrivate, QObject *parent = 0); + explicit GetRepositoryMetaInfoJob(PackageManagerCore *core, QObject *parent = 0); ~GetRepositoryMetaInfoJob(); Repository repository() const; @@ -119,7 +119,7 @@ private: bool m_waitForDone; QThreadPool m_threadPool; - PackageManagerCorePrivate *m_corePrivate; + PackageManagerCore *m_core; }; } // namespace QInstaller diff --git a/src/libs/installer/graph.h b/src/libs/installer/graph.h new file mode 100644 index 000000000..59778a440 --- /dev/null +++ b/src/libs/installer/graph.h @@ -0,0 +1,158 @@ +/************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Installer Framework. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +**************************************************************************/ + +#ifndef GRAPH_H +#define GRAPH_H + +#include <QHash> +#include <QList> +#include <QPair> +#include <QSet> + +namespace QInstaller { + +template <class T> class Graph +{ +public: + inline Graph() {} + explicit Graph(const QList<T> &nodes) + { + addNodes(nodes); + } + + const QList<T> nodes() const + { + return m_graph.keys(); + } + + void addNode(const T &node) + { + m_graph.insert(node, QSet<T>()); + } + + void addNodes(const QList<T> &nodes) + { + foreach (const T &node, nodes) + addNode(node); + } + + QList<T> edges(const T &node) const + { + return m_graph.value(node).toList(); + } + + void addEdge(const T &node, const T &edge) + { + m_graph[node].insert(edge); + } + + void addEdges(const T &node, const QList<T> &edges) + { + foreach (const T &edge, edges) + addEdge(node, edge); + } + + bool hasCycle() const + { + return m_hasCycle; + } + + QPair<T, T> cycle() const + { + return m_cycle; + } + + QList<T> sort() const + { + QSet<T> visitedNodes; + QList<T> resolvedNodes; + + m_hasCycle = false; + m_cycle = qMakePair(T(), T()); + foreach (const T &node, nodes()) + visit(node, &resolvedNodes, &visitedNodes); + return resolvedNodes; + } + + QList<T> sortReverse() const + { + QList<T> result = sort(); + std::reverse(result.begin(), result.end()); + return result; + } + +private: + void visit(const T &node, QList<T> *const resolvedNodes, QSet<T> *const visitedNodes) const + { + if (m_hasCycle) + return; + + // if we visited this node already + if (visitedNodes->contains(node)) { + // and if the node is already in the ordered list + if (resolvedNodes->contains(node)) + return; + + m_hasCycle = true; + m_cycle.second = node; + return; // if not yet in the ordered list, we detected a cycle + } + + // mark this node as visited + visitedNodes->insert(node); + + m_cycle.first = node; + // recursively visit all adjacency + foreach (const T &adjacency, edges(node)) + visit(adjacency, resolvedNodes, visitedNodes); + + // append this node the the ordered list + resolvedNodes->append(node); + } + +private: + mutable bool m_hasCycle; + QHash<T, QSet<T> > m_graph; + mutable QPair<T,T> m_cycle; +}; + +} +#endif // GRAPH_H diff --git a/src/libs/installer/installer.pro b/src/libs/installer/installer.pro index 5ae0b1afb..a1631c4a3 100644 --- a/src/libs/installer/installer.pro +++ b/src/libs/installer/installer.pro @@ -100,7 +100,8 @@ HEADERS += packagemanagercore.h \ createlinkoperation.h \ packagemanagercoredata.h \ applyproductkeyoperation.h \ - globals.h + globals.h \ + graph.h SOURCES += packagemanagercore.cpp \ packagemanagercore_p.cpp \ diff --git a/src/libs/installer/installiconsoperation.cpp b/src/libs/installer/installiconsoperation.cpp index f46ab5315..dba6d644b 100644 --- a/src/libs/installer/installiconsoperation.cpp +++ b/src/libs/installer/installiconsoperation.cpp @@ -45,6 +45,7 @@ #include <QtCore/QDir> #include <QtCore/QDirIterator> +#include <QDebug> #if QT_VERSION >= 0x040600 # include <QProcessEnvironment> @@ -121,10 +122,6 @@ InstallIconsOperation::InstallIconsOperation() InstallIconsOperation::~InstallIconsOperation() { const QStringList backupFiles = value(QLatin1String("backupfiles")).toStringList(); - for (QStringList::const_iterator it = backupFiles.begin(); it != backupFiles.end(); it += 2) { - const QString& backup = *(it + 1); - deleteFileNowOrLater(backup); - } } void InstallIconsOperation::backup() @@ -164,8 +161,6 @@ bool InstallIconsOperation::performOperation() QDirIterator it(sourceDir.path(), QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); while (it.hasNext()) { - qApp->processEvents(); - const int status = core->status(); if (status == PackageManagerCore::Canceled || status == PackageManagerCore::Failure) return true; @@ -194,7 +189,7 @@ bool InstallIconsOperation::performOperation() if (QFile(target).exists()) { // first backup... - const QString backup = generateTemporaryFileName(target + QLatin1String("XXXXXX")); + const QString backup = generateTemporaryFileName(target); QFile bf(target); if (!bf.copy(backup)) { setError(UserDefinedError); @@ -251,12 +246,10 @@ bool InstallIconsOperation::performOperation() bool InstallIconsOperation::undoOperation() { - bool success = true; - + QStringList warningMessages; // first copy back all files to their origin const QStringList files = value(QLatin1String("files")).toStringList(); for (QStringList::const_iterator it = files.begin(); it != files.end(); it += 2) { - qApp->processEvents(); const QString& source = *it; const QString& target = *(it + 1); @@ -264,10 +257,11 @@ bool InstallIconsOperation::undoOperation() // first make sure the "source" path is valid QDir().mkpath(QFileInfo(source).absolutePath()); - // now copy target to source (feels weird, I know...) - success = QFile::copy(target, source) && success; - // and remove target - success = QFile::remove(target) && success; + QFile installedTarget(target); + if (installedTarget.exists() && !(installedTarget.copy(source) && installedTarget.remove())) { + warningMessages << QString::fromLatin1("Could not move file from '%1' to '%2', error: %3)").arg( + target, source, installedTarget.errorString()); + } } // then copy back and remove all backuped files @@ -278,11 +272,17 @@ bool InstallIconsOperation::undoOperation() // remove the target if (QFile::exists(target)) - success = deleteFileNowOrLater(target) && success; + deleteFileNowOrLater(target); // then copy the backup onto the target - success = QFile::copy(backup, target) && success; + if (!QFile::copy(backup, target)) { + warningMessages << QString::fromLatin1("Could not restore the backup '%1' to '%2'").arg( + backup, target); + } + // finally remove the backp - success = deleteFileNowOrLater(backup) && success; + if (!deleteFileNowOrLater(backup)) + warningMessages << QString::fromLatin1("Could not remove the backup '%1'").arg(backup); + } // then remove all directories created by us @@ -290,10 +290,19 @@ bool InstallIconsOperation::undoOperation() for (QStringList::const_iterator it = createdDirectories.begin(); it != createdDirectories.end(); ++it) { const QDir dir(*it); removeSystemGeneratedFiles(dir.absolutePath()); - success = QDir::root().rmdir(dir.path()); + if (dir.exists() && !QDir::root().rmdir(dir.path())) + warningMessages << QString::fromLatin1("Could not remove directory '%1'").arg(dir.path()); + } + + if (!warningMessages.isEmpty()) { + qWarning() << QString::fromLatin1("Undo of operation '%1' with arguments '%2' had some problems.").arg( + name(), arguments().join(QLatin1String(", "))); + foreach (const QString &message, warningMessages) { + qWarning() << message; + } } - return success; + return true; } bool InstallIconsOperation::testOperation() diff --git a/src/libs/installer/macreplaceinstallnamesoperation.cpp b/src/libs/installer/macreplaceinstallnamesoperation.cpp index 470c15b37..9ec553358 100644 --- a/src/libs/installer/macreplaceinstallnamesoperation.cpp +++ b/src/libs/installer/macreplaceinstallnamesoperation.cpp @@ -198,9 +198,8 @@ void MacReplaceInstallNamesOperation::relocateBinary(const MacBinaryInfo &info, // change framework ID only if dynamicLibId isn't only the filename, if it has no relative path ("@") - // and is not existing at the current looking for location if (!info.dynamicLibId.isEmpty() && (info.dynamicLibId != QFileInfo(info.fileName).fileName()) - && !info.dynamicLibId.contains(QLatin1String("@")) && !QFileInfo(info.dynamicLibId).exists()) { + && !info.dynamicLibId.contains(QLatin1String("@"))) { // error is set inside the execCommand method if (!execCommand(QLatin1String("install_name_tool"), QStringList(QLatin1String("-id")) << info.fileName << info.fileName)) { diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index 9543aca5e..c617dd239 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -192,12 +192,6 @@ */ /*! - \qmlsignal QInstaller::setRootComponents(list<Component> components) - - Triggered with the list of new root components (for example after an online update). -*/ - -/*! \qmlsignal QInstaller::startAllComponentsReset() Triggered when the list of components starts to get updated. @@ -206,9 +200,9 @@ */ /*! - \qmlsignal QInstaller::finishAllComponentsReset() + \qmlsignal QInstaller::finishAllComponentsReset(list<Component> rootComponents) - Triggered when the list of components has been updated. + Triggered when the list of new root components has been updated. \sa startAllComponentsReset */ @@ -220,9 +214,9 @@ */ /*! - \qmlsignal QInstaller::finishUpdaterComponentsReset() + \qmlsignal QInstaller::finishUpdaterComponentsReset(list<Component> componentsWithUpdates) - Triggered when components have been updated during a remote update. + Triggered when the list of available remote updates has been updated. */ /*! @@ -419,6 +413,11 @@ void PackageManagerCore::writeUninstaller() } } +void PackageManagerCore::writeMaintenanceConfigFiles() +{ + d->writeMaintenanceConfigFiles(); +} + void PackageManagerCore::reset(const QHash<QString, QString> ¶ms) { d->m_completeUninstall = false; @@ -814,9 +813,8 @@ bool PackageManagerCore::fetchLocalPackagesTree() updateDisplayVersions(scDisplayVersion); - emit finishAllComponentsReset(); + emit finishAllComponentsReset(d->m_rootComponents); d->setStatus(Success); - emit setRootComponents(d->m_rootComponents); return true; } @@ -889,9 +887,39 @@ bool PackageManagerCore::fetchRemotePackagesTree() return false; bool success = false; - if (!isUpdater()) + 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); } @@ -1315,6 +1343,8 @@ ComponentModel *PackageManagerCore::defaultComponentModel() const 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; } @@ -1325,6 +1355,8 @@ ComponentModel *PackageManagerCore::updaterComponentModel() const 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; } @@ -2141,8 +2173,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; } @@ -2192,7 +2223,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); @@ -2283,7 +2316,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. @@ -2292,8 +2325,7 @@ bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const return false; } - emit finishUpdaterComponentsReset(); - emit setRootComponents(d->m_updaterComponents); + emit finishUpdaterComponentsReset(d->m_updaterComponents); return true; } @@ -2346,7 +2378,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, @@ -2355,10 +2387,10 @@ 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(checkStateChanged(QInstaller::ComponentModel::ModelState)), this, SLOT(componentsToInstallNeedsRecalculation())); diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h index 712a5174c..20a3293fa 100644 --- a/src/libs/installer/packagemanagercore.h +++ b/src/libs/installer/packagemanagercore.h @@ -82,7 +82,8 @@ public: Failure = EXIT_FAILURE, Running, Canceled, - Unfinished + Unfinished, + ForceUpdate }; Status status() const; QString error() const; @@ -157,6 +158,8 @@ public: QStringList replaceVariables(const QStringList &str) const; void writeUninstaller(); + void writeMaintenanceConfigFiles(); + QString uninstallerName() const; QString installerBinaryPath() const; @@ -271,13 +274,12 @@ Q_SIGNALS: void finishButtonClicked(); void metaJobInfoMessage(const QString &message); - void setRootComponents(const QList<QInstaller::Component*> &components); void startAllComponentsReset(); - void finishAllComponentsReset(); + void finishAllComponentsReset(const QList<QInstaller::Component*> &rootComponents); void startUpdaterComponentsReset(); - void finishUpdaterComponentsReset(); + void finishUpdaterComponentsReset(const QList<QInstaller::Component*> &componentsWithUpdates); void installationStarted(); void installationInterrupted(); diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index 1728a85b2..f102d79ed 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -49,6 +49,7 @@ #include "fileutils.h" #include "fsengineclient.h" #include "globals.h" +#include "graph.h" #include "messageboxhandler.h" #include "packagemanagercore.h" #include "progresscoordinator.h" @@ -95,7 +96,8 @@ public: { if (!m_operation) return; - qDebug() << QString::fromLatin1("%1 operation: %2").arg(state, m_operation->name()); + qDebug() << QString::fromLatin1("%1 %2 operation: %3").arg(state, m_operation->value( + QLatin1String("component")).toString(), m_operation->name()); qDebug() << QString::fromLatin1("\t- arguments: %1").arg(m_operation->arguments() .join(QLatin1String(", "))); } @@ -379,7 +381,7 @@ bool PackageManagerCorePrivate::buildComponentTree(QHash<QString, Component*> &c std::sort(m_rootComponents.begin(), m_rootComponents.end(), Component::SortingPriorityGreaterThan()); } catch (const Error &error) { clearAllComponentLists(); - emit m_core->finishAllComponentsReset(); + emit m_core->finishAllComponentsReset(QList<QInstaller::Component*>()); setStatus(PackageManagerCore::Failure, error.message()); // TODO: make sure we remove all message boxes inside the library at some point. @@ -630,7 +632,7 @@ void PackageManagerCorePrivate::initialize(const QHash<QString, QString> ¶ms } if (!m_repoMetaInfoJob) { - m_repoMetaInfoJob = new GetRepositoriesMetaInfoJob(this); + m_repoMetaInfoJob = new GetRepositoriesMetaInfoJob(m_core); m_repoMetaInfoJob->setAutoDelete(false); connect(m_repoMetaInfoJob, SIGNAL(infoMessage(KDJob*, QString)), this, SLOT(infoMessage(KDJob*, QString))); @@ -1328,9 +1330,15 @@ void PackageManagerCorePrivate::writeUninstaller(OperationList performedOperatio #endif } + performedOperations = sortOperationsBasedOnComponentDependencies( + performedOperations); + + m_core->setValue(QLatin1String("installedOperationAreSorted"), QLatin1String("true")); + try { KDSaveFile file(dataFile + QLatin1String(".new")); openForWrite(&file, file.fileName()); + writeUninstallerBinaryData(&file, &input, performedOperations, layout); appendInt64(&file, MagicCookieDat); file.setPermissions(file.permissions() | QFile::WriteUser | QFile::ReadGroup @@ -1611,8 +1619,14 @@ bool PackageManagerCorePrivate::runPackageUpdater() OperationList nonRevertedOperations; QHash<QString, Component *> componentsByName; + // order the operations in the right component dependency order + // next loop will save the needed operations in reverse order for uninstallation + OperationList performedOperationsOld = m_performedOperationsOld; + if (m_core->value(QLatin1String("installedOperationAreSorted")) != QLatin1String("true")) + performedOperationsOld = sortOperationsBasedOnComponentDependencies(m_performedOperationsOld); + // build a list of undo operations based on the checked state of the component - foreach (Operation *operation, m_performedOperationsOld) { + foreach (Operation *operation, performedOperationsOld) { const QString &name = operation->value(QLatin1String("component")).toString(); Component *component = componentsByName.value(name, 0); if (!component) @@ -1663,6 +1677,7 @@ bool PackageManagerCorePrivate::runPackageUpdater() continue; } + // uninstallation should be in reverse order so prepend it here undoOperations.prepend(operation); updateAdminRights |= operation->value(QLatin1String("admin")).toBool(); } @@ -1864,7 +1879,6 @@ void PackageManagerCorePrivate::installComponent(Component *component, double pr // Remember that the operation was performed, that allows us to undo it if a following operation // fails or if this operation failed but still needs an undo call to cleanup. addPerformed(operation); - operation->setValue(QLatin1String("component"), component->name()); } if (becameAdmin) @@ -2017,22 +2031,18 @@ void PackageManagerCorePrivate::runUndoOperations(const OperationList &undoOpera const QString componentName = undoOperation->value(QLatin1String("component")).toString(); if (!componentName.isEmpty()) { - while (!ok && !ignoreError && m_core->status() != PackageManagerCore::Canceled) { - const QMessageBox::StandardButton button = - MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), - QLatin1String("installationErrorWithRetry"), tr("Installer Error"), - tr("Error during uninstallation process:\n%1").arg(undoOperation->errorString()), - QMessageBox::Retry | QMessageBox::Ignore, QMessageBox::Retry); - - if (button == QMessageBox::Retry) { - ok = performOperationThreaded(undoOperation, Undo); - } else if (button == QMessageBox::Ignore) { - ignoreError = true; - } - } - } - - if (!componentName.isEmpty()) { + while (!ok && !ignoreError && m_core->status() != PackageManagerCore::Canceled) { + const QMessageBox::StandardButton button = + MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("installationErrorWithRetry"), tr("Installer Error"), + tr("Error during uninstallation process:\n%1").arg(undoOperation->errorString()), + QMessageBox::Retry | QMessageBox::Ignore, QMessageBox::Retry); + + if (button == QMessageBox::Retry) + ok = performOperationThreaded(undoOperation, Undo); + else if (button == QMessageBox::Ignore) + ignoreError = true; + } Component *component = m_core->componentByName(componentName); if (!component) component = componentsToReplace().value(componentName).second; @@ -2359,6 +2369,37 @@ void PackageManagerCorePrivate::connectOperationCallMethodRequest(Operation *con } } +OperationList PackageManagerCorePrivate::sortOperationsBasedOnComponentDependencies(const OperationList &operationList) +{ + OperationList sortedOperations; + QHash<QString, OperationList> componentOperationHash; + + // sort component unrelated operations to the beginning + foreach (Operation *operation, operationList) { + const QString componentName = operation->value(QLatin1String("component")).toString(); + if (componentName.isEmpty()) + sortedOperations.append(operation); + else { + OperationList componentOperationList = componentOperationHash.value(componentName); + componentOperationList.append(operation); + componentOperationHash.insert(operation->value(QLatin1String("component")).toString(), + componentOperationList); + } + } + + // create the complete component graph + Graph<QString> componentGraph; + foreach (const Component* componentNode, m_core->availableComponents()) { + componentGraph.addNode(componentNode->name()); + componentGraph.addEdges(componentNode->name(), componentNode->dependencies()); + } + + foreach (const QString &componentName, componentGraph.sort()) + sortedOperations.append(componentOperationHash.value(componentName)); + + return sortedOperations; +} + void PackageManagerCorePrivate::handleMethodInvocationRequest(const QString &invokableMethodName) { QObject *obj = QObject::sender(); diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h index 11ed23230..d5bdc78fd 100644 --- a/src/libs/installer/packagemanagercore_p.h +++ b/src/libs/installer/packagemanagercore_p.h @@ -167,6 +167,7 @@ public: int countProgressOperations(const OperationList &operations); void connectOperationToInstaller(Operation *const operation, double progressOperationPartSize); void connectOperationCallMethodRequest(Operation *const operation); + OperationList sortOperationsBasedOnComponentDependencies(const OperationList &operationList); Operation *createOwnedOperation(const QString &type); Operation *takeOwnedOperation(Operation *operation); diff --git a/src/libs/installer/packagemanagercoredata.cpp b/src/libs/installer/packagemanagercoredata.cpp index efc83f520..2294a8086 100644 --- a/src/libs/installer/packagemanagercoredata.cpp +++ b/src/libs/installer/packagemanagercoredata.cpp @@ -57,6 +57,8 @@ PackageManagerCoreData::PackageManagerCoreData(const QHash<QString, QString> &va // in a script or... m_variables.insert(QLatin1String("rootDir"), QDir::rootPath()); m_variables.insert(QLatin1String("homeDir"), QDir::homePath()); + m_variables.insert(QLatin1String("RootDir"), QDir::rootPath()); + m_variables.insert(QLatin1String("HomeDir"), QDir::homePath()); m_variables.insert(scTargetConfigurationFile, QLatin1String("components.xml")); #ifdef Q_OS_WIN diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp index 10caed749..2db2a9e4a 100644 --- a/src/libs/installer/packagemanagergui.cpp +++ b/src/libs/installer/packagemanagergui.cpp @@ -299,20 +299,30 @@ QString PackageManagerGui::defaultButtonText(int wizardButton) const void PackageManagerGui::clickButton(int wb, int delay) { - if (QAbstractButton *b = button(static_cast<QWizard::WizardButton>(wb) )) { + // transform the FinishButton to CancelButton, because of the needed misuse of the + // CancelButton as a FinishButton to have some more control of closing the wizard + if (!m_core->isInstaller() && currentId() == PackageManagerCore::InstallationFinished && + wb == QWizard::FinishButton) { + wb = QWizard::CancelButton; + } + if (QAbstractButton *b = button(static_cast<QWizard::WizardButton>(wb) )) QTimer::singleShot(delay, b, SLOT(click())); - } else { + else qWarning() << "Button with type: " << d->buttonType(wb) << "not found!"; - } } bool PackageManagerGui::isButtonEnabled(int wb) { - if (QAbstractButton *b = button(static_cast<QWizard::WizardButton>(wb) )) { - return b->isEnabled(); - } else { - qWarning() << "Button with type: " << d->buttonType(wb) << "not found!"; + // transform the FinishButton to CancelButton, because of the needed misuse of the + // CancelButton as a FinishButton to have some more control of closing the wizard + if (!m_core->isInstaller() && currentId() == PackageManagerCore::InstallationFinished && + wb == QWizard::FinishButton) { + wb = QWizard::CancelButton; } + if (QAbstractButton *b = button(static_cast<QWizard::WizardButton>(wb) )) + return b->isEnabled(); + + qWarning() << "Button with type: " << d->buttonType(wb) << "not found!"; return false; } @@ -970,9 +980,9 @@ public: m_treeView->setObjectName(QLatin1String("ComponentsTreeView")); connect(m_allModel, SIGNAL(checkStateChanged(QInstaller::ComponentModel::ModelState)), this, - SLOT(onCheckStateChanged(QInstaller::ComponentModel::ModelState))); + SLOT(onModelStateChanged(QInstaller::ComponentModel::ModelState))); connect(m_updaterModel, SIGNAL(checkStateChanged(QInstaller::ComponentModel::ModelState)), this, - SLOT(onCheckStateChanged(QInstaller::ComponentModel::ModelState))); + SLOT(onModelStateChanged(QInstaller::ComponentModel::ModelState))); QHBoxLayout *hlayout = new QHBoxLayout; hlayout->addWidget(m_treeView, 3); @@ -1034,8 +1044,6 @@ public: { m_checkDefault->setVisible(m_core->isInstaller() || m_core->isPackageManager()); if (m_treeView->selectionModel()) { - disconnect(m_currentModel, SIGNAL(checkStateChanged(QModelIndex)), this, - SLOT(currentCheckedChanged(QModelIndex))); disconnect(m_treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(currentSelectedChanged(QModelIndex))); } @@ -1060,8 +1068,6 @@ public: hasChildren = m_currentModel->hasChildren(m_currentModel->index(row, 0)); m_treeView->setRootIsDecorated(hasChildren); - connect(m_currentModel, SIGNAL(checkStateChanged(QModelIndex)), this, - SLOT(currentCheckedChanged(QModelIndex))); connect(m_treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(currentSelectedChanged(QModelIndex))); @@ -1069,12 +1075,6 @@ public: } public slots: - void currentCheckedChanged(const QModelIndex ¤t) - { - if (m_treeView->selectionModel()->currentIndex() == current) - currentSelectedChanged(current); - } - void currentSelectedChanged(const QModelIndex ¤t) { if (!current.isValid()) @@ -1088,7 +1088,7 @@ public slots: if ((m_core->isUninstaller()) || (!component)) return; - if ((component->checkState() != Qt::Unchecked) && (component->updateUncompressedSize() > 0)) { + if (component->isSelected() && (component->value(scUncompressedSizeSum).toLongLong() > 0)) { m_sizeLabel->setText(ComponentSelectionPage::tr("This component " "will occupy approximately %1 on your hard disk drive.") .arg(humanReadableSize(component->value(scUncompressedSizeSum).toLongLong()))); @@ -1110,10 +1110,9 @@ public slots: m_currentModel->setCheckedState(ComponentModel::DefaultChecked); } - void onCheckStateChanged(QInstaller::ComponentModel::ModelState state) + void onModelStateChanged(QInstaller::ComponentModel::ModelState state) { - q->setModified(state != ComponentModel::DefaultChecked); - + q->setModified(state.testFlag(ComponentModel::DefaultChecked) == false); // If all components in the checked list are only checkable when run without forced installation, set // ComponentModel::AllUnchecked as well, as we cannot uncheck anything. Helps to keep the UI correct. if ((!m_core->noForceInstallation()) && (m_currentModel->checked() == m_currentModel->uncheckable())) @@ -1123,6 +1122,10 @@ public slots: m_checkAll->setEnabled(state.testFlag(ComponentModel::AllChecked) == false); m_uncheckAll->setEnabled(state.testFlag(ComponentModel::AllUnchecked) == false); m_checkDefault->setEnabled(state.testFlag(ComponentModel::DefaultChecked) == false); + + // update the current selected node (important to reflect possible sub-node changes) + if (m_treeView->selectionModel()) + currentSelectedChanged(m_treeView->selectionModel()->currentIndex()); } public: @@ -1233,7 +1236,7 @@ bool ComponentSelectionPage::isComplete() const { if (packageManagerCore()->isInstaller() || packageManagerCore()->isUpdater()) return d->m_currentModel->checked().count(); - return d->m_currentModel->checkedState() != ComponentModel::DefaultChecked; + return d->m_currentModel->checkedState().testFlag(ComponentModel::DefaultChecked) == false; } @@ -1836,6 +1839,13 @@ void FinishedPage::entering() m_commitButton = cancel; cancel->setEnabled(true); cancel->setVisible(true); + // we don't use the usual FinishButton so we need to connect the misused CancelButton + connect(cancel, SIGNAL(clicked()), gui(), SIGNAL(finishButtonClicked())); + connect(cancel, SIGNAL(clicked()), packageManagerCore(), SIGNAL(finishButtonClicked())); + // for the moment we don't want the rejected signal connected + disconnect(gui(), SIGNAL(rejected()), packageManagerCore(), SLOT(setCanceled())); + + connect(gui()->button(QWizard::CommitButton), SIGNAL(clicked()), this, SLOT(cleanupChangedConnects())); } setButtonText(QWizard::CommitButton, tr("Restart")); setButtonText(QWizard::CancelButton, gui()->defaultButtonText(QWizard::FinishButton)); @@ -1901,6 +1911,17 @@ void FinishedPage::handleFinishClicked() QProcess::startDetached(program, args); } +void FinishedPage::cleanupChangedConnects() +{ + if (QAbstractButton *cancel = gui()->button(QWizard::CancelButton)) { + // remove the workaround connect from entering page + disconnect(cancel, SIGNAL(clicked()), gui(), SIGNAL(finishButtonClicked())); + disconnect(cancel, SIGNAL(clicked()), packageManagerCore(), SIGNAL(finishButtonClicked())); + connect(gui(), SIGNAL(rejected()), packageManagerCore(), SLOT(setCanceled())); + + disconnect(gui()->button(QWizard::CommitButton), SIGNAL(clicked()), this, SLOT(cleanupChangedConnects())); + } +} // -- RestartPage diff --git a/src/libs/installer/packagemanagergui.h b/src/libs/installer/packagemanagergui.h index 37e5d6852..5c428bf87 100644 --- a/src/libs/installer/packagemanagergui.h +++ b/src/libs/installer/packagemanagergui.h @@ -403,6 +403,7 @@ public: public Q_SLOTS: void handleFinishClicked(); + void cleanupChangedConnects(); protected: void entering(); diff --git a/src/libs/installer/productkeycheck.cpp b/src/libs/installer/productkeycheck.cpp index fe1fd10af..a4af2b6d3 100644 --- a/src/libs/installer/productkeycheck.cpp +++ b/src/libs/installer/productkeycheck.cpp @@ -88,3 +88,10 @@ bool ProductKeyCheck::isValidLicenseTextFile(const QString &/*fileName*/) { return true; } + + +bool ProductKeyCheck::isValidRepository(const QInstaller::Repository &repository) const +{ + Q_UNUSED(repository) + return true; +}
\ No newline at end of file diff --git a/src/libs/installer/productkeycheck.h b/src/libs/installer/productkeycheck.h index d472d9288..6d72089e2 100644 --- a/src/libs/installer/productkeycheck.h +++ b/src/libs/installer/productkeycheck.h @@ -38,6 +38,7 @@ namespace QInstaller{ class PackageManagerCore; + class Repository; } class ProductKeyCheckPrivate; @@ -60,6 +61,9 @@ public: // to filter none valid licenses bool isValidLicenseTextFile(const QString &fileName); + // to filter repositories not matching the license + bool isValidRepository(const QInstaller::Repository &repository) const; + private: ProductKeyCheck(); ProductKeyCheckPrivate *const d; diff --git a/src/libs/installer/qtpatchoperation.cpp b/src/libs/installer/qtpatchoperation.cpp index 822d5e3a4..e9fbb65c5 100644 --- a/src/libs/installer/qtpatchoperation.cpp +++ b/src/libs/installer/qtpatchoperation.cpp @@ -254,19 +254,97 @@ bool QtPatchOperation::performOperation() } #ifdef Q_OS_MAC - // just try to patch here at the beginning to keep the unpatched qmake if mac install_names_tool fails - MacReplaceInstallNamesOperation operation; - operation.setArguments(QStringList() - //can not use the old path which is wrong in the webkit case - //<< QString::fromUtf8(oldQtPath) - << QLatin1String("/lib/Qt") // search string - << newQtPathStr + QLatin1String("/lib/Qt") //replace string - << newQtPathStr //where - ); - if (!operation.performOperation()) { - setError(operation.error()); - setErrorString(operation.errorString()); - return false; + // looking for /lib/Qt wasn't enough for all libs and frameworks, + // at the Qt4 case we had for example: /lib/libQtCLucene* and /lib/phonon* + // so now we find every possible replace string inside dynlib dependencies + // and we reduce it to few as possible search strings + QStringList possibleSearchStringList; + QDirIterator dirIterator(newQtPathStr + QLatin1String("/lib/")); + while (dirIterator.hasNext()) { + const QString possibleSearchString = QString(dirIterator.next()).remove(newQtPathStr); + const QFileInfo fileInfo = dirIterator.fileInfo(); + if (fileInfo.isSymLink()) + continue; + if (fileInfo.isDir()) { + if (possibleSearchString.endsWith(QLatin1String(".framework"))) + possibleSearchStringList.append(possibleSearchString); + else + continue; + } + if (possibleSearchString.endsWith(QLatin1String(".dylib"))) + possibleSearchStringList.append(possibleSearchString); + } + + // now we have this in possibleSearchStringList at Qt 4.8.6 +// "/lib/libQtCLucene.4.8.6.dylib" +// "/lib/libQtCLucene_debug.4.8.6.dylib" +// "/lib/phonon.framework" +// "/lib/QtCore.framework" +// "/lib/QtDeclarative.framework" +// "/lib/QtDesigner.framework" +// "/lib/QtDesignerComponents.framework" +// "/lib/QtGui.framework" +// "/lib/QtHelp.framework" +// "/lib/QtMultimedia.framework" +// "/lib/QtNetwork.framework" +// "/lib/QtOpenGL.framework" +// "/lib/QtScript.framework" +// "/lib/QtScriptTools.framework" +// "/lib/QtSql.framework" +// "/lib/QtSvg.framework" +// "/lib/QtTest.framework" +// "/lib/QtWebKit.framework" +// "/lib/QtXml.framework" +// "/lib/QtXmlPatterns.framework" + + // so then we reduce the possible filter strings as much as possible + QStringList searchStringList; + + // as the minimal search string use the subdirector lib + one letter from the name + int minFilterLength = QString(QLatin1String("/lib/")).length() + 1; + + while (!possibleSearchStringList.isEmpty()) { + QString firstSearchString = possibleSearchStringList.first(); + int filterLength = minFilterLength; + int lastFilterCount = 0; + QString lastFilterString; + // now filter as long as we find something more then 1 + for (; filterLength < firstSearchString.length(); ++filterLength) { + QString filterString(firstSearchString.left(filterLength)); + QStringList filteredStringList(possibleSearchStringList.filter(filterString)); + // found a valid filter + if (lastFilterCount > filteredStringList.count()) { + possibleSearchStringList = QList<QString>::fromSet(possibleSearchStringList.toSet() - + possibleSearchStringList.filter(lastFilterString).toSet()); + searchStringList.append(lastFilterString); + break; + } else if (lastFilterCount == 1){ //in case there is only one we can use the complete name + possibleSearchStringList = QList<QString>::fromSet(possibleSearchStringList.toSet() - + possibleSearchStringList.filter(firstSearchString).toSet()); + searchStringList.append(firstSearchString); + break; + } else { + lastFilterCount = possibleSearchStringList.filter(filterString).count(); + lastFilterString = filterString; + } + } + } + + // in the tested Qt 4.8.6 case we have searchStringList ("/lib/libQtCLucene", "/lib/Qt", "/lib/phonon") + foreach (const QString &searchString, searchStringList) { + MacReplaceInstallNamesOperation operation; + operation.setArguments(QStringList() + //can not use the old path which is wrong in the webkit case + //<< QString::fromUtf8(oldQtPath) + << searchString + << newQtPathStr + searchString //replace string + << newQtPathStr //where + ); + if (!operation.performOperation()) { + setError(operation.error()); + setErrorString(operation.errorString()); + return false; + } } #endif diff --git a/src/libs/installer/scriptengine.cpp b/src/libs/installer/scriptengine.cpp index 75a60dc15..e85ce9671 100644 --- a/src/libs/installer/scriptengine.cpp +++ b/src/libs/installer/scriptengine.cpp @@ -407,6 +407,8 @@ QScriptValue ScriptEngine::generateQInstallerObject() qinstaller.setProperty(QLatin1String("Failure"), PackageManagerCore::Failure); qinstaller.setProperty(QLatin1String("Running"), PackageManagerCore::Running); qinstaller.setProperty(QLatin1String("Canceled"), PackageManagerCore::Canceled); + qinstaller.setProperty(QLatin1String("Unfinished"), PackageManagerCore::Unfinished); + qinstaller.setProperty(QLatin1String("ForceUpdate"), PackageManagerCore::ForceUpdate); return qinstaller; } |