diff options
Diffstat (limited to 'installerbuilder/libinstaller')
49 files changed, 5059 insertions, 3908 deletions
diff --git a/installerbuilder/libinstaller/3rdparty/p7zip_9.04/lib7z_facade.cpp b/installerbuilder/libinstaller/3rdparty/p7zip_9.04/lib7z_facade.cpp index 2ee6f8db2..22002bef6 100644 --- a/installerbuilder/libinstaller/3rdparty/p7zip_9.04/lib7z_facade.cpp +++ b/installerbuilder/libinstaller/3rdparty/p7zip_9.04/lib7z_facade.cpp @@ -24,14 +24,13 @@ #include "7zip/UI/Common/Extract.h" #include "7zip/UI/Common/Update.h" #include "7zip/UI/Common/ArchiveExtractCallback.h" +#include "7zip/UI/Common/LoadCodecs.h" +#include "7zip/UI/Common/PropIDUtils.h" #include "Windows/Defs.h" #include "Windows/Error.h" #include "Windows/FileDir.h" #include "Windows/FileName.h" - -#include "7zip/UI/Common/LoadCodecs.h" -#include "7zip/UI/Common/PropIDUtils.h" #include "Windows/PropVariant.h" #include "Windows/PropVariantConversions.h" diff --git a/installerbuilder/libinstaller/3rdparty/p7zip_9.04/lib7z_facade.h b/installerbuilder/libinstaller/3rdparty/p7zip_9.04/lib7z_facade.h index 670071866..2441e3d35 100644 --- a/installerbuilder/libinstaller/3rdparty/p7zip_9.04/lib7z_facade.h +++ b/installerbuilder/libinstaller/3rdparty/p7zip_9.04/lib7z_facade.h @@ -17,8 +17,10 @@ #include "../../installerbuilder/libinstaller/installer_global.h" +QT_BEGIN_NAMESPACE class QStringList; template <typename T> class QVector; +QT_END_NAMESPACE namespace Lib7z { diff --git a/installerbuilder/libinstaller/copydirectoryoperation.cpp b/installerbuilder/libinstaller/copydirectoryoperation.cpp index 49f9db99e..0a308b361 100644 --- a/installerbuilder/libinstaller/copydirectoryoperation.cpp +++ b/installerbuilder/libinstaller/copydirectoryoperation.cpp @@ -60,9 +60,11 @@ void CopyDirectoryOperation::letTheUiRunTillFinished(const QFuture<void> &future { if (!future.isFinished()) { QFutureWatcher<void> futureWatcher; - futureWatcher.setFuture(future); + QEventLoop loop; connect(&futureWatcher, SIGNAL(finished()), &loop, SLOT(quit()), Qt::QueuedConnection); + futureWatcher.setFuture(future); + if (!future.isFinished()) loop.exec(); } diff --git a/installerbuilder/libinstaller/extractarchiveoperation_p.h b/installerbuilder/libinstaller/extractarchiveoperation_p.h index e23b34dff..44a30f1c2 100644 --- a/installerbuilder/libinstaller/extractarchiveoperation_p.h +++ b/installerbuilder/libinstaller/extractarchiveoperation_p.h @@ -83,15 +83,15 @@ public Q_SLOTS: void statusChanged( QInstaller::Installer::Status status ) { switch( status ) { - case Installer::InstallerCanceledByUser: + case Installer::Canceled: state = E_ABORT; break; - case Installer::InstallerFailed: + case Installer::Failure: state = E_FAIL; break; - case Installer::InstallerUnfinished: // fall through - case Installer::InstallerSucceeded: - case Installer::InstallerRunning: + case Installer::Unfinished: // fall through + case Installer::Success: + case Installer::Running: //state = S_OK; break; } diff --git a/installerbuilder/libinstaller/fsengineclient.h b/installerbuilder/libinstaller/fsengineclient.h index 9065f3741..c84cb673e 100644 --- a/installerbuilder/libinstaller/fsengineclient.h +++ b/installerbuilder/libinstaller/fsengineclient.h @@ -32,9 +32,13 @@ #ifdef FSENGINE_TCP #include <QtNetwork/QHostAddress> +QT_BEGIN_NAMESPACE class QTcpSocket; +QT_END_NAMESPACE #else +QT_BEGIN_NAMESPACE class QLocalSocket; +QT_END_NAMESPACE #endif #include "installer_global.h" diff --git a/installerbuilder/libinstaller/getrepositoriesmetainfojob.cpp b/installerbuilder/libinstaller/getrepositoriesmetainfojob.cpp index 6c8b2f545..c02b65953 100644 --- a/installerbuilder/libinstaller/getrepositoriesmetainfojob.cpp +++ b/installerbuilder/libinstaller/getrepositoriesmetainfojob.cpp @@ -58,6 +58,7 @@ QList< Repository > GetRepositoriesMetaInfoJob::repositories() const void GetRepositoriesMetaInfoJob::setRepositories(const QList<Repository>& repos) { m_repositories = repos; + m_tmpRepositories = repos; } QStringList GetRepositoriesMetaInfoJob::temporaryDirectories() const @@ -119,18 +120,18 @@ void GetRepositoriesMetaInfoJob::fetchNextRepo() emitFinished(); return; } - if (m_repositories.isEmpty()) { + + if (m_tmpRepositories.isEmpty()) { if (m_haveIgnoredError) emitFinishedWithError(UserIgnoreError, m_errorString); else emitFinished(); return; } - const Repository r = m_repositories.back(); - m_repositories.pop_back(); + m_job = new GetRepositoryMetaInfoJob(m_publicKey, m_packageManager, this); - m_job->setRepository(r); m_job->setSilentRetries(silentRetries()); + m_job->setRepository(m_tmpRepositories.takeLast()); connect(m_job, SIGNAL(finished(KDJob*)), this, SLOT(jobFinished(KDJob*))); m_job->start(); } @@ -144,6 +145,7 @@ void GetRepositoriesMetaInfoJob::jobFinished(KDJob* j) { const GetRepositoryMetaInfoJob* const job = qobject_cast<const GetRepositoryMetaInfoJob*>(j); assert(job); + if(job->error() != KDJob::NoError && !job->temporaryDirectory().isEmpty()) { try { removeDirectory(job->temporaryDirectory()); diff --git a/installerbuilder/libinstaller/getrepositoriesmetainfojob.h b/installerbuilder/libinstaller/getrepositoriesmetainfojob.h index 4391dc151..0573e0e06 100644 --- a/installerbuilder/libinstaller/getrepositoriesmetainfojob.h +++ b/installerbuilder/libinstaller/getrepositoriesmetainfojob.h @@ -52,14 +52,14 @@ class INSTALLER_EXPORT GetRepositoriesMetaInfoJob : public KDJob public: enum Error { - UserIgnoreError=KDJob::UserDefinedError + 1 + UserIgnoreError = KDJob::UserDefinedError + 1 }; explicit GetRepositoriesMetaInfoJob(const QByteArray &publicKey, bool packageManager = false, QObject *parent = 0); - QList< Repository > repositories() const; - void setRepositories(const QList<Repository> &repos); + QList<Repository> repositories() const; + void setRepositories(const QList<Repository> &repositories); QStringList temporaryDirectories() const; QStringList releaseTemporaryDirectories() const; @@ -87,6 +87,7 @@ private: int m_silentRetries; bool m_packageManager; QList<Repository> m_repositories; + QList<Repository> m_tmpRepositories; QHash<QString, Repository> m_repositoryByTemporaryDirectory; bool m_haveIgnoredError; QString m_errorString; diff --git a/installerbuilder/libinstaller/globalsettingsoperation.h b/installerbuilder/libinstaller/globalsettingsoperation.h index a8eab3473..693273d39 100644 --- a/installerbuilder/libinstaller/globalsettingsoperation.h +++ b/installerbuilder/libinstaller/globalsettingsoperation.h @@ -29,7 +29,6 @@ #include <KDUpdater/UpdateOperation> class QSettingsWrapper; -class QStringList; namespace QInstaller { diff --git a/installerbuilder/libinstaller/installationprogressdialog.h b/installerbuilder/libinstaller/installationprogressdialog.h index 5523b28f3..712a7794a 100644 --- a/installerbuilder/libinstaller/installationprogressdialog.h +++ b/installerbuilder/libinstaller/installationprogressdialog.h @@ -28,26 +28,34 @@ #include <QtGui/QDialog> +QT_BEGIN_NAMESPACE class QDialogButtonBox; +QT_END_NAMESPACE namespace QInstaller { class PerformInstallationForm; -class InstallationProgressDialog : public QDialog{ +class InstallationProgressDialog : public QDialog +{ Q_OBJECT + public: explicit InstallationProgressDialog( QWidget* parent=0 ); ~InstallationProgressDialog(); //bool isShowingDetails() const; + Q_SIGNALS: void canceled(); private Q_SLOTS: void finished(); + private: PerformInstallationForm *m_performInstallationForm; QDialogButtonBox* m_dialogBtns; }; -} //namespace QInstaller + +} // namespace QInstaller + #endif diff --git a/installerbuilder/libinstaller/installer_global.h b/installerbuilder/libinstaller/installer_global.h index 691cfe26e..1da1013bf 100644 --- a/installerbuilder/libinstaller/installer_global.h +++ b/installerbuilder/libinstaller/installer_global.h @@ -38,14 +38,4 @@ #define INSTALLER_EXPORT #endif -namespace QInstaller { - enum RunModes - { - UpdaterMode, - InstallerMode, - AllMode //this is a kind of doesn't matter mode - }; - //Q_ENUMS(InstallerMode) -} - #endif //INSTALLER_GLOBAL_H diff --git a/installerbuilder/libinstaller/installiconsoperation.cpp b/installerbuilder/libinstaller/installiconsoperation.cpp index c847b0343..eaf9e32a7 100644 --- a/installerbuilder/libinstaller/installiconsoperation.cpp +++ b/installerbuilder/libinstaller/installiconsoperation.cpp @@ -179,7 +179,7 @@ bool InstallIconsOperation::performOperation() qApp->processEvents(); const int status = installer->status(); - if( status == Installer::InstallerCanceledByUser || status == Installer::InstallerFailed ) + if( status == Installer::Canceled || status == Installer::Failure ) return true; const QString source = it.next(); diff --git a/installerbuilder/libinstaller/kdmmappedfileiodevice.h b/installerbuilder/libinstaller/kdmmappedfileiodevice.h index 06aa18819..d4c5e51d5 100644 --- a/installerbuilder/libinstaller/kdmmappedfileiodevice.h +++ b/installerbuilder/libinstaller/kdmmappedfileiodevice.h @@ -30,10 +30,14 @@ #include "installer_global.h" +QT_BEGIN_NAMESPACE class QFile; +QT_END_NAMESPACE -class INSTALLER_EXPORT KDMMappedFileIODevice : public QIODevice { +class INSTALLER_EXPORT KDMMappedFileIODevice : public QIODevice +{ Q_OBJECT + public: KDMMappedFileIODevice( QFile* file, qint64 offset, qint64 length, QObject* parent=0 ); KDMMappedFileIODevice( const QString& filename, qint64 offset, qint64 length, QObject* parent=0 ); diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdbytesize.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdbytesize.h index cc8f5a770..d5735632c 100644 --- a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdbytesize.h +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdbytesize.h @@ -45,7 +45,10 @@ KDTOOLSCORE_EXPORT KDByteSize operator*( const KDByteSize& lhs, int rhs ); KDTOOLS_MAKE_RELATION_OPERATORS( KDByteSize, static inline ) +QT_BEGIN_NAMESPACE class QDebug; +QT_END_NAMESPACE + KDTOOLSCORE_EXPORT QDebug operator<<( QDebug dbg, const KDByteSize& size ); #endif diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile.h index cecbc5cbd..3334f385f 100644 --- a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile.h +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdlockfile.h @@ -25,7 +25,9 @@ #include <pimpl_ptr.h> +QT_BEGIN_NAMESPACE class QString; +QT_END_NAMESPACE class KDTOOLSCORE_EXPORT KDLockFile { diff --git a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo.h b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo.h index 2324ccfc8..44d1cc71d 100644 --- a/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo.h +++ b/installerbuilder/libinstaller/kdtools/KDToolsCore/kdsysinfo.h @@ -106,7 +106,9 @@ public: static QList< ProcessInfo > runningProcesses(); }; +QT_BEGIN_NAMESPACE class QDebug; +QT_END_NAMESPACE QDebug operator<<( QDebug dbg, KDSysInfo::OperatingSystemType type ); QDebug operator<<( QDebug dbg, KDSysInfo::ArchitectureType type ); diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/environment.h b/installerbuilder/libinstaller/kdtools/KDUpdater/environment.h index 001afbbc2..7d6169314 100644 --- a/installerbuilder/libinstaller/kdtools/KDUpdater/environment.h +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/environment.h @@ -5,8 +5,10 @@ #include <QString> +QT_BEGIN_NAMESPACE class QProcess; class QProcessEnvironment; +QT_END_NAMESPACE namespace KDUpdater { diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterapplication.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterapplication.h index 3970236d3..1d0fca6d9 100644 --- a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterapplication.h +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterapplication.h @@ -26,7 +26,9 @@ #include "kdupdater.h" #include <QObject> +QT_BEGIN_NAMESPACE class QUrl; +QT_END_NAMESPACE namespace KDUpdater { @@ -34,7 +36,8 @@ namespace KDUpdater class SignatureVerifier; class UpdateSourcesInfo; - class ConfigurationInterface { + class ConfigurationInterface + { public: virtual ~ConfigurationInterface(); virtual QVariant value( const QString& key ) const = 0; diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatercrypto.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatercrypto.h index 15d0011a0..4d94c89fb 100644 --- a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatercrypto.h +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatercrypto.h @@ -25,10 +25,12 @@ #include "kdupdater.h" +#include <KDToolsCore/pimpl_ptr.h> + +QT_BEGIN_NAMESPACE class QByteArray; class QIODevice; - -#include <KDToolsCore/pimpl_ptr.h> +QT_END_NAMESPACE /** * Class that provides cryptographic functionality like signing and verifying diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloader_p.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloader_p.h index 516bc3c3d..841e48c03 100644 --- a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloader_p.h +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloader_p.h @@ -29,7 +29,9 @@ #include <QtCore/QCryptographicHash> #include <QtNetwork/QNetworkReply> +QT_BEGIN_NAMESPACE class QIODevice; +QT_END_NAMESPACE // these classes are not a part of the public API diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloaderfactory.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloaderfactory.h index b4c284640..7afc3e35e 100644 --- a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloaderfactory.h +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterfiledownloaderfactory.h @@ -30,7 +30,9 @@ #include <QtCore/QStringList> #include <QtCore/QUrl> +QT_BEGIN_NAMESPACE class QObject; +QT_END_NAMESPACE namespace KDUpdater { diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationresult.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationresult.h index 5319d35f3..6d426c820 100644 --- a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationresult.h +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationresult.h @@ -28,7 +28,9 @@ #include <QtCore/QMetaType> #include <QtCore/QSharedDataPointer> +QT_BEGIN_NAMESPACE class QString; +QT_END_NAMESPACE namespace KDUpdater { class KDTOOLS_UPDATER_EXPORT SignatureVerificationResult { diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationrunnable.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationrunnable.h index afc201bea..bbad15381 100644 --- a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationrunnable.h +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverificationrunnable.h @@ -27,10 +27,12 @@ #include <QtCore/QGenericArgument> #include <QtCore/QRunnable> +QT_BEGIN_NAMESPACE class QByteArray; class QIODevice; class QObject; template <typename T> class QVector; +QT_END_NAMESPACE namespace KDUpdater { class SignatureVerifier; diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverifier.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverifier.h index dfb8cbddb..ef1da8ae3 100644 --- a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverifier.h +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdatersignatureverifier.h @@ -25,9 +25,11 @@ #include "kdupdater.h" +QT_BEGIN_NAMESPACE class QByteArray; class QIODevice; class QString; +QT_END_NAMESPACE namespace KDUpdater { diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufcompresscommon_p.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufcompresscommon_p.h index 65f6ea5cb..6501735f1 100644 --- a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufcompresscommon_p.h +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufcompresscommon_p.h @@ -31,8 +31,10 @@ #include <QtCore/QByteArray> #include <QtCore/QVector> +QT_BEGIN_NAMESPACE class QCryptographicHash; class QDataStream; +QT_END_NAMESPACE namespace KDUpdater { diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufuncompressor_p.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufuncompressor_p.h index 5800887fc..61c5cca78 100644 --- a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufuncompressor_p.h +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterufuncompressor_p.h @@ -27,7 +27,9 @@ #include <QtCore/QCoreApplication> +QT_BEGIN_NAMESPACE class QString; +QT_END_NAMESPACE namespace KDUpdater { diff --git a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatefinder.h b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatefinder.h index 14ebb9c97..e472f42e0 100644 --- a/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatefinder.h +++ b/installerbuilder/libinstaller/kdtools/KDUpdater/kdupdaterupdatefinder.h @@ -28,7 +28,9 @@ #include <QList> #include <QMap> +QT_BEGIN_NAMESPACE class QUrl; +QT_END_NAMESPACE namespace KDUpdater { diff --git a/installerbuilder/libinstaller/libinstaller.pro b/installerbuilder/libinstaller/libinstaller.pro index c5f71fbc4..04832f902 100644 --- a/installerbuilder/libinstaller/libinstaller.pro +++ b/installerbuilder/libinstaller/libinstaller.pro @@ -32,6 +32,7 @@ include(kdtools/KDToolsCore/KDToolsCore.pri) include(kdtools/KDUpdater/KDUpdater.pri) HEADERS += $$PWD/qinstaller.h \ + $$PWD/qinstaller_p.h \ $$PWD/qinstallergui.h \ ../common/binaryformat.h \ ../common/binaryformatengine.h \ @@ -93,9 +94,11 @@ HEADERS += $$PWD/qinstaller.h \ performinstallationform.h \ messageboxhandler.h \ getrepositoriesmetainfojob.h \ - licenseoperation.h + licenseoperation.h \ + qinstallercomponent_p.h SOURCES += $$PWD/qinstaller.cpp \ + $$PWD/qinstaller_p.cpp \ $$PWD/qinstallergui.cpp \ ../common/binaryformat.cpp \ ../common/binaryformatengine.cpp \ @@ -154,7 +157,8 @@ SOURCES += $$PWD/qinstaller.cpp \ performinstallationform.cpp \ messageboxhandler.cpp \ getrepositoriesmetainfojob.cpp \ - licenseoperation.cpp + licenseoperation.cpp \ + qinstallercomponent_p.cpp macx { HEADERS += macrelocateqt.h \ diff --git a/installerbuilder/libinstaller/messageboxhandler.cpp b/installerbuilder/libinstaller/messageboxhandler.cpp index 2428843cd..5e4c21f76 100644 --- a/installerbuilder/libinstaller/messageboxhandler.cpp +++ b/installerbuilder/libinstaller/messageboxhandler.cpp @@ -36,6 +36,8 @@ #include <QScriptValue> #include <QScriptEngine> #include <QDebug> +#include <QPushButton> +#include <QDialogButtonBox> QScriptValue QInstaller::registerMessageBox( QScriptEngine* scriptEngine ) { QScriptValue messageBox = scriptEngine->newQObject(MessageBoxHandler::instance()); @@ -140,6 +142,39 @@ QWidget* MessageBoxHandler::currentBestSuitParent() return qApp->activeWindow(); } +// taken from Qt +static QMessageBox::StandardButton showNewMessageBox(QWidget *parent, QMessageBox::Icon icon, + const QString& title, const QString& text, QMessageBox::StandardButtons buttons, + QMessageBox::StandardButton defaultButton) +{ + QMessageBox msgBox(icon, title, text, QMessageBox::NoButton, parent); + QDialogButtonBox *buttonBox = msgBox.findChild<QDialogButtonBox*>(); + Q_ASSERT(buttonBox != 0); + + uint mask = QMessageBox::FirstButton; + while (mask <= QMessageBox::LastButton) { + uint sb = buttons & mask; + mask <<= 1; + if (!sb) + continue; + QPushButton *button = msgBox.addButton((QMessageBox::StandardButton)sb); + // Choose the first accept role as the default + if (msgBox.defaultButton()) + continue; + if ((defaultButton == QMessageBox::NoButton + && buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) + || (defaultButton != QMessageBox::NoButton && sb == uint(defaultButton))) { + msgBox.setDefaultButton(button); + } + } +#if defined(Q_WS_MAC) + msgBox.setWindowModality(Qt::WindowModal); +#endif + if (msgBox.exec() == -1) + return QMessageBox::Cancel; + return msgBox.standardButton(msgBox.clickedButton()); +} + QMessageBox::StandardButton MessageBoxHandler::showMessageBox(MessageType messageType, QWidget* parent, const QString& identifier, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton button) const { @@ -152,13 +187,13 @@ QMessageBox::StandardButton MessageBoxHandler::showMessageBox(MessageType messag qDebug() << QString(QLatin1String("create message box with identifier: '%1'")).arg(identifier); switch( messageType ) { case criticalType: - return QMessageBox::critical( parent, title, text, buttons, button ); + return showNewMessageBox( parent, QMessageBox::Critical, title, text, buttons, button ); case informationType: - return QMessageBox::information( parent, title, text, buttons, button ); + return showNewMessageBox( parent, QMessageBox::Information, title, text, buttons, button ); case questionType: - return QMessageBox::question( parent, title, text, buttons, button ); + return showNewMessageBox( parent, QMessageBox::Question, title, text, buttons, button ); case warningType: - return QMessageBox::warning( parent, title, text, buttons, button ); + return showNewMessageBox( parent, QMessageBox::Warning, title, text, buttons, button ); } } else diff --git a/installerbuilder/libinstaller/messageboxhandler.h b/installerbuilder/libinstaller/messageboxhandler.h index 43e4ac93d..e591e6490 100644 --- a/installerbuilder/libinstaller/messageboxhandler.h +++ b/installerbuilder/libinstaller/messageboxhandler.h @@ -33,8 +33,6 @@ #include <QMessageBox> #include <QHash> -class QString; - namespace QInstaller { QScriptValue registerMessageBox( QScriptEngine* scriptEngine ); diff --git a/installerbuilder/libinstaller/performinstallationform.h b/installerbuilder/libinstaller/performinstallationform.h index 35f894a46..9a17fa73a 100644 --- a/installerbuilder/libinstaller/performinstallationform.h +++ b/installerbuilder/libinstaller/performinstallationform.h @@ -30,11 +30,13 @@ class LazyPlainTextEdit; +QT_BEGIN_NAMESPACE class QWidget; class QPushButton; class QProgressBar; class QLabel; class QTimer; +QT_END_NAMESPACE namespace QInstaller { diff --git a/installerbuilder/libinstaller/progresscoordinator.cpp b/installerbuilder/libinstaller/progresscoordinator.cpp index e0cc9ff1f..a38086a13 100644 --- a/installerbuilder/libinstaller/progresscoordinator.cpp +++ b/installerbuilder/libinstaller/progresscoordinator.cpp @@ -37,11 +37,12 @@ using namespace QInstaller; +QT_BEGIN_NAMESPACE uint qHash(QPointer<QObject> key) { return qHash(key.data()); } - +QT_END_NAMESPACE ProgressCoordninator::ProgressCoordninator(QObject *parent) : QObject(parent), diff --git a/installerbuilder/libinstaller/qinstaller.cpp b/installerbuilder/libinstaller/qinstaller.cpp index cd94403cc..9259ad150 100644 --- a/installerbuilder/libinstaller/qinstaller.cpp +++ b/installerbuilder/libinstaller/qinstaller.cpp @@ -31,67 +31,29 @@ ** **************************************************************************/ #include "qinstaller.h" -#include "qinstallergui.h" -#include "qinstallerglobal.h" -#include "qinstallercomponent.h" + +#include "adminauthorization.h" +#include "common/binaryformat.h" +#include "common/errors.h" +#include "common/installersettings.h" +#include "common/utils.h" #include "downloadarchivesjob.h" +#include "fsengineclient.h" #include "getrepositoriesmetainfojob.h" -#include "adminauthorization.h" #include "messageboxhandler.h" #include "progresscoordinator.h" +#include "qinstaller_p.h" +#include "qinstallercomponent.h" +#include "qinstallerglobal.h" -#include "common/installersettings.h" -#include "common/binaryformat.h" -#include "common/utils.h" - -#include "fsengineclient.h" -#include "fsengineserver.h" - -#include <QtCore/QBuffer> -#include <QtCore/QCoreApplication> -#include <QtCore/QDateTime> -#include <QtCore/QDir> -#include <QtCore/QDirIterator> -#include <QtCore/QFile> -#include <QtCore/QFileInfo> -#include <QtCore/QHash> -#include <QtCore/QLocale> -#include <QtCore/QPointer> -#include <QtCore/QProcess> -#include <QtCore/QResource> -#include <QtCore/QSettings> -#include <QtCore/QVector> #include <QtCore/QTemporaryFile> -#include <QtCore/QTranslator> -#include <QtCore/QUrl> -#include <QtCore/QThread> -#include <QtCore/QSet> + #include <QtGui/QDesktopServices> -#include <QtGui/QMessageBox> -#include <QtUiTools/QUiLoader> + #include <QtScript/QScriptEngine> #include <QtScript/QScriptContext> -#include <QtScript/QScriptContextInfo> -#include <QFuture> -#include <QFutureWatcher> -#include <QtConcurrentRun> -#include <KDUpdater/KDUpdater> -#include <KDUpdater/Application> -#include <KDUpdater/PackagesInfo> - -#include <KDToolsCore/KDSaveFile> #include <KDToolsCore/KDSysInfo> -#include <KDToolsCore/KDSelfRestarter> - -#include "common/errors.h" -#include "common/fileutils.h" - -#include <cassert> -#include <cerrno> -#include <functional> -#include <memory> -#include <algorithm> #ifdef Q_OS_WIN #include "qt_windows.h" @@ -99,47 +61,6 @@ using namespace QInstaller; -namespace { - enum OperationType { - Backup, - Perform, - Undo - }; - - static bool runOperation(KDUpdater::UpdateOperation *op, OperationType type) { - switch (type) - { - case(Backup): - op->backup(); - return true; - case (Perform): - return op->performOperation(); - case (Undo) : - return op->undoOperation(); - } - Q_ASSERT(!"unexpected operation type"); - return false; - } - - template <typename T> - void letTheUiRunTillFinished(const QFuture<T>& f) { - QFutureWatcher<T> futureWatcher; - futureWatcher.setFuture(f); - QEventLoop loop; - loop.connect(&futureWatcher, SIGNAL(finished()), SLOT(quit()), Qt::QueuedConnection); - if (!f.isFinished()) - loop.exec(); - } - -} - -static bool performOperationThreaded(KDUpdater::UpdateOperation *op, OperationType type=Perform) -{ - QFuture<bool> future = QtConcurrent::run(runOperation, op, type); - letTheUiRunTillFinished(future); - return future.result(); -} - static QScriptValue checkArguments(QScriptContext* context, int amin, int amax) { if (context->argumentCount() < amin || context->argumentCount() > amax) { @@ -154,44 +75,6 @@ static QScriptValue checkArguments(QScriptContext* context, int amin, int amax) return QScriptValue(); } -#ifdef Q_WS_WIN -static void deferredRename(const QString& oldName, const QString& newName, bool restart = false) -{ - QString batchfile; - - QStringList arguments; - arguments << QDir::toNativeSeparators(batchfile) - << QDir::toNativeSeparators(oldName) - << QDir::toNativeSeparators(QFileInfo(oldName).dir().absoluteFilePath(newName)); - - { - QTemporaryFile f(QDir::temp().absoluteFilePath(QLatin1String("deferredrenameXXXXXX.vbs"))); - openForWrite(&f, f.fileName()); - f.setAutoRemove(false); - - batchfile = f.fileName(); - - QTextStream batch(&f); - batch << "Set fso = WScript.CreateObject(\"Scripting.FileSystemObject\")\n"; - batch << "Set tmp = WScript.CreateObject(\"WScript.Shell\")\n"; - batch << QString::fromLatin1("file = \"%1\"\n").arg(arguments[2]); - batch << "on error resume next\n"; - - batch << "while fso.FileExists(file)\n"; - batch << " fso.DeleteFile(file)\n"; - batch << " WScript.Sleep(1000)\n"; - batch << "wend\n"; - batch << QString::fromLatin1("fso.MoveFile \"%1\", file\n").arg(arguments[1]); - if (restart) - batch << QString::fromLatin1("tmp.exec \"%1 --updater\"\n").arg(arguments[2]); - batch << "fso.DeleteFile(WScript.ScriptFullName)\n"; - } - - QProcess::startDetached(QLatin1String("cscript"), QStringList() << QLatin1String("//Nologo") - << QDir::toNativeSeparators(batchfile)); -} -#endif // Q_WS_WIN - /*! Appends \a comp preceded by its dependencies to \a components. Makes sure components contains every component only once. @@ -210,8 +93,8 @@ static void appendComponentAndMissingDependencies(QList<Component*>& components, } /*! - Scriptable version of Installer::componentByName(QString). - \sa Installer::componentByName + Scriptable version of Installer::componentByName(QString). + \sa Installer::componentByName */ QScriptValue QInstaller::qInstallerComponentByName(QScriptContext* context, QScriptEngine* engine) { @@ -325,211 +208,6 @@ QString QInstaller::uncaughtExceptionString(QScriptEngine *scriptEngine/*, const Non-existing page - this value has to be used if you want to insert a page after \a InstallationFinished */ -/*! - Initializes the created FSEngineClientHandler instance \a handler. - \internal - */ -static void initEngineHandler(FSEngineClientHandler* handler) -{ -#ifdef FSENGINE_TCP - const int port = 30000 + qrand() % 1000; - handler->init(port); - handler->setStartServerCommand(qApp->applicationFilePath(), QStringList() - << QLatin1String("--startserver") << QString::number(port) << handler->authorizationKey(), - true); -#else - const QString name = QInstaller::generateTemporaryFileName(); - handler->init(name); - handler->setStartServerCommand(qApp->applicationFilePath(), QStringList() - << QLatin1String("--startserver") << name << handler->authorizationKey(), true); -#endif -} - - - -/*! - Creates and initializes a FSEngineClientHandler -> makes us get admin rights for QFile - operations. - \internal - */ -static FSEngineClientHandler* createEngineClientHandler() -{ - static FSEngineClientHandler* clientHandlerInstance = 0; - if (clientHandlerInstance == 0) - { - clientHandlerInstance = new FSEngineClientHandler; - initEngineHandler(clientHandlerInstance); - } - return clientHandlerInstance; -} - - -// -- Installer::Private - - -class QInstaller::Installer::Private : public QObject -{ - Q_OBJECT; - -private: - Installer* const q; - -public: - explicit Private(Installer *q, qint64 magicmaker, - QVector<KDUpdater::UpdateOperation*> performedOperations); - ~Private(); - - void initialize(); - - bool statusCanceledOrFailed() const; - void setStatus(Installer::Status); - - void writeUninstaller(QVector<KDUpdater::UpdateOperation*> performedOperations); - QString targetDir() const { return q->value(QLatin1String("TargetDir")); } - - QString configurationFileName() const { - return q->value(QLatin1String("TargetConfigurationFile"), - QString::fromLatin1("components.xml")); - } - - QString componentsXmlPath() const - { - return QDir::toNativeSeparators(QDir(QDir::cleanPath(targetDir())) - .absoluteFilePath(configurationFileName())); - } - - QString localComponentsXmlPath() const - { - const QString &appDirPath = QCoreApplication::applicationDirPath(); - if (QFileInfo(appDirPath + QLatin1String("/../..")).isBundle()) { - return QDir::toNativeSeparators(QFileInfo(QDir::cleanPath(appDirPath - + QLatin1String("/../../../") + configurationFileName())).absoluteFilePath()); - } - return componentsXmlPath(); - } - - void runInstaller(); - void runUninstaller(); - void runPackageUpdater(); - void deleteUninstaller(); - QString uninstallerName() const; - QString replaceVariables(const QString &str) const; - QByteArray replaceVariables(const QByteArray &str) const; - QString registerPath() const; - void registerInstaller(); - void unregisterInstaller(); - QString installerBinaryPath() const; - bool isInstaller() const; - bool isUninstaller() const; - bool isPackageManager() const; - Installer *installer() const { return q; } - KDUpdater::UpdateOperation* createOwnedOperation(const QString& type); - void readUninstallerIniFile(const QString& targetDir); - void stopProcessesForUpdates(const QList<Component*>& components); - int countProgressOperations(const QList<Component*>& components); - int countProgressOperations(const QList<KDUpdater::UpdateOperation*>& operations); - void connectOperationToInstaller(KDUpdater::UpdateOperation* const operation, - double progressOperationPartSize); - void registerPathesForUninstallation(const QList<QPair<QString, bool> > &pathesForUninstallation, - const QString& componentName); - - void addPerformed(KDUpdater::UpdateOperation* op) { - m_performedOperationsCurrentSession.push_back(op); - } - - void commitSessionOperations() { - m_performedOperationsOld += m_performedOperationsCurrentSession; - m_performedOperationsCurrentSession.clear(); - } - -signals: - void installationStarted(); - void installationFinished(); - void uninstallationStarted(); - void uninstallationFinished(); - -public: - TempDirDeleter tempDirDeleter; - - FSEngineClientHandler* const engineClientHandler; - - QHash<QString, QString> m_vars; - QHash<QString, bool> m_sharedFlags; - Installer::Status m_status; - - bool packageManagingMode; - bool m_completeUninstall; - - qint64 m_firstComponentStart; - qint64 m_componentsCount; - qint64 m_componentOffsetTableStart; - - qint64 m_firstComponentDictStart; - qint64 m_componentsDictCount; - qint64 m_componentDictOffsetTableStart; - - qint64 m_globalDictOffset; - qint64 m_magicInstallerMarker; - - KDUpdater::Application * m_app; - - //this is a Hack, we don't need this in the refactor branch - QList< QPointer<QInstaller::Component> > componentDeleteList; - - // Owned. Indexed by component name - QList<Component*> m_rootComponents; - QHash<QString, Component*> m_componentHash; - - QList<Component*> m_updaterComponents; - QList<Component*> m_packageManagerComponents; - - //a hack to get the will be replaced components extra - QList<QInstaller::Component*> willBeReplacedComponents; - - QList<KDUpdater::UpdateOperation*> ownedOperations; - QVector<KDUpdater::UpdateOperation*> m_performedOperationsOld; - QVector<KDUpdater::UpdateOperation*> m_performedOperationsCurrentSession; - InstallerSettings m_settings; - QString installerBaseBinaryUnreplaced; - bool linearComponentList; - bool m_launchedAsRoot; - int m_silentRetries; - bool m_forceRestart; - bool m_needToWriteUninstaller; - bool m_testChecksum; -}; - -Installer::Private::Private(Installer *q, qint64 magicmaker, - QVector<KDUpdater::UpdateOperation*> performedOperations) - : q(q), - engineClientHandler(createEngineClientHandler()), - m_status(Installer::InstallerUnfinished), - packageManagingMode(false), - m_completeUninstall(false), - m_magicInstallerMarker(magicmaker),//? magicmaker : MagicInstallerMarker), - m_performedOperationsOld(performedOperations), - linearComponentList(false), - m_launchedAsRoot(AdminAuthorization::hasAdminRights()), - m_silentRetries(3), - m_forceRestart (false), - m_needToWriteUninstaller(false), - m_testChecksum(false) -{ - connect(this, SIGNAL(installationStarted()), q, SIGNAL(installationStarted())); - connect(this, SIGNAL(installationFinished()), q, SIGNAL(installationFinished())); - connect(this, SIGNAL(uninstallationStarted()), q, SIGNAL(uninstallationStarted())); - connect(this, SIGNAL(uninstallationFinished()), q, SIGNAL(uninstallationFinished())); - verbose() << "has admin rights ? : " << engineClientHandler->isActive() << std::endl; -} - -Installer::Private::~Private() -{ - qDeleteAll(componentDeleteList); - componentDeleteList.clear(); - - qDeleteAll(m_performedOperationsOld); - qDeleteAll(m_performedOperationsCurrentSession); -} KDUpdater::Application& Installer::updaterApplication() const { @@ -577,728 +255,22 @@ void Installer::reset(const QHash<QString, QString> ¶ms) { d->m_completeUninstall = false; d->m_forceRestart = false; - d->m_status = Installer::InstallerUnfinished; - d->installerBaseBinaryUnreplaced.clear(); + d->m_status = Installer::Unfinished; + d->m_installerBaseBinaryUnreplaced.clear(); d->m_vars.clear(); d->m_vars = params; d->initialize(); } -void Installer::Private::initialize() -{ - try { - m_settings = InstallerSettings::fromFileAndPrefix( - QLatin1String(":/metadata/installer-config/config.xml"), - QLatin1String(":/metadata/installer-config/")); - } catch (const Error &e) { - qCritical("Could not parse Config: %s", qPrintable(e.message())); - //TODO try better error handling - return; - } - - // first set some common variables that may used e.g. as placeholder - // in some of the settings variables or in a script or... - m_vars.insert(QLatin1String("rootDir"), QDir::rootPath()); - m_vars.insert(QLatin1String("homeDir"), QDir::homePath()); - -#ifdef Q_WS_WIN - m_vars.insert(QLatin1String("os"), QLatin1String("win")); -#elif defined(Q_WS_MAC) - m_vars.insert(QLatin1String("os"), QLatin1String("mac")); -#elif defined(Q_WS_X11) - m_vars.insert(QLatin1String("os"), QLatin1String("x11")); -#elif defined(Q_WS_QWS) - m_vars.insert(QLatin1String("os"), QLatin1String("Qtopia")); -#else - //TODO add more platforms as needed... -#endif - - // fill the variables defined in the settings - m_vars.insert(QLatin1String("ProductName"), m_settings.applicationName()); - m_vars.insert(QLatin1String("ProductVersion"), m_settings.applicationVersion()); - m_vars.insert(QLatin1String("Title"), m_settings.title()); - m_vars.insert(QLatin1String("MaintenanceTitle"), m_settings.maintenanceTitle()); - m_vars.insert(QLatin1String("Publisher"), m_settings.publisher()); - m_vars.insert(QLatin1String("Url"), m_settings.url()); - m_vars.insert(QLatin1String("StartMenuDir"), m_settings.startMenuDir()); - - m_vars.insert(QLatin1String("LogoPixmap"), m_settings.logo()); - m_vars.insert(QLatin1String("LogoSmallPixmap"), m_settings.logoSmall()); - m_vars.insert(QLatin1String("WatermarkPixmap"), m_settings.watermark()); - - m_vars.insert(QLatin1String("TargetConfigurationFile"), m_settings.configurationFileName()); - m_vars.insert(QLatin1String("RunProgram"), replaceVariables(m_settings.runProgram())); - const QString desc = m_settings.runProgramDescription(); - if (!desc.isEmpty()) - m_vars.insert(QLatin1String("RunProgramDescription"), desc); -#ifdef Q_WS_X11 - if (m_launchedAsRoot) - m_vars.insert(QLatin1String("TargetDir"), replaceVariables(m_settings.adminTargetDir())); - else -#endif - m_vars.insert(QLatin1String("TargetDir"), replaceVariables(m_settings.targetDir())); - m_vars.insert(QLatin1String("RemoveTargetDir"), replaceVariables(m_settings.removeTargetDir())); - - QSettings creatorSettings(QSettings::IniFormat, QSettings::UserScope, QLatin1String("Nokia"), - QLatin1String("QtCreator")); - QFileInfo info(creatorSettings.fileName()); - if (info.exists()) - m_vars.insert(QLatin1String("QtCreatorSettingsFile"), info.absoluteFilePath()); - - if (!q->isInstaller()) { -#ifdef Q_WS_MAC - readUninstallerIniFile(QCoreApplication::applicationDirPath() + QLatin1String("/../../..")); -#else - readUninstallerIniFile(QCoreApplication::applicationDirPath()); -#endif - } - - connect(this, SIGNAL(installationStarted()), ProgressCoordninator::instance(), SLOT(reset())); - connect(this, SIGNAL(uninstallationStarted()), ProgressCoordninator::instance(), SLOT(reset())); -} - /*! - * Sets the uninstallation to be \a complete. If \a complete is false, only components deselected - * by the user will be uninstalled. - * This option applies only on uninstallation. + Sets the uninstallation to be \a complete. If \a complete is false, only components deselected + by the user will be uninstalled. + This option applies only on uninstallation. */ void Installer::setCompleteUninstallation(bool complete) { d->m_completeUninstall = complete; - d->packageManagingMode = !d->m_completeUninstall; -} - -QString Installer::Private::installerBinaryPath() const -{ - return qApp->applicationFilePath(); -} - -bool Installer::Private::isInstaller() const -{ - return m_magicInstallerMarker == MagicInstallerMarker; -} - -bool Installer::Private::isUninstaller() const -{ - return m_magicInstallerMarker == MagicUninstallerMarker && !packageManagingMode; -} - -bool Installer::Private::isPackageManager() const -{ - return m_magicInstallerMarker == MagicUninstallerMarker && packageManagingMode; -} - -bool Installer::Private::statusCanceledOrFailed() const -{ - return m_status == Installer::InstallerCanceledByUser - || m_status == Installer::InstallerFailed; -} - -void Installer::Private::setStatus(Installer::Status status) -{ - if (m_status != status) { - m_status = status; - emit q->statusChanged(m_status); - } -} - -QString Installer::Private::replaceVariables(const QString &str) const -{ - static const QChar at = QLatin1Char('@'); - QString res; - int pos = 0; - while (true) { - const int pos1 = str.indexOf(at, pos); - if (pos1 == -1) - break; - const int pos2 = str.indexOf(at, pos1 + 1); - if (pos2 == -1) - break; - res += str.mid(pos, pos1 - pos); - const QString name = str.mid(pos1 + 1, pos2 - pos1 - 1); - res += q->value(name); - pos = pos2 + 1; - } - res += str.mid(pos); - return res; -} - -QByteArray Installer::Private::replaceVariables(const QByteArray &ba) const -{ - static const QChar at = QLatin1Char('@'); - QByteArray res; - int pos = 0; - while (true) { - const int pos1 = ba.indexOf(at, pos); - if (pos1 == -1) - break; - const int pos2 = ba.indexOf(at, pos1 + 1); - if (pos2 == -1) - break; - res += ba.mid(pos, pos1 - pos); - const QString name = QString::fromLocal8Bit(ba.mid(pos1 + 1, pos2 - pos1 - 1)); - res += q->value(name).toLocal8Bit(); - pos = pos2 + 1; - } - res += ba.mid(pos); - return res; -} - -/*! - Creates an update operation owned by the installer, not by any component. - \internal - */ -KDUpdater::UpdateOperation* Installer::Private::createOwnedOperation(const QString &type) -{ - KDUpdater::UpdateOperation* const op = KDUpdater::UpdateOperationFactory::instance().create(type); - ownedOperations.push_back(op); - return op; -} - -QString Installer::Private::uninstallerName() const -{ - QString filename = m_settings.uninstallerName(); -#if defined(Q_WS_MAC) - if (QFileInfo(QCoreApplication::applicationDirPath() + QLatin1String("/../..")).isBundle()) - filename += QLatin1String(".app/Contents/MacOS/") + filename; -#elif defined(Q_OS_WIN) - filename += QLatin1String(".exe"); -#endif - return QString::fromLatin1("%1/%2").arg(targetDir()).arg(filename); -} - -void Installer::Private::readUninstallerIniFile(const QString &targetDir) -{ - const QString iniPath = targetDir + QLatin1Char('/') + m_settings.uninstallerIniFile(); - QSettings cfg(iniPath, QSettings::IniFormat); - const QVariantHash vars = cfg.value(QLatin1String("Variables")).toHash(); - QHash<QString, QVariant>::ConstIterator it = vars.constBegin(); - while (it != vars.constEnd()) { - m_vars.insert(it.key(), it.value().toString()); - ++it; - } -} - -/*! - Copied from QInstaller with some adjustments - Return true, if a process with \a name is running. On Windows, the comparision is case-insensitive. -*/ -static bool isProcessRunning(const QString& name, const QList<KDSysInfo::ProcessInfo> &processes) -{ - QList<KDSysInfo::ProcessInfo>::const_iterator it; - for (it = processes.constBegin(); it != processes.constEnd(); ++it) { - if (it->name.isEmpty()) - continue; - -#ifndef Q_WS_WIN - if (it->name == name) - return true; - const QFileInfo fi(it->name); - if (fi.fileName() == name || fi.baseName() == name) - return true; -#else - if (it->name.toLower() == name.toLower()) - return true; - if (it->name.toLower() == QDir::toNativeSeparators(name.toLower())) - return true; - const QFileInfo fi(it->name); - if (fi.fileName().toLower() == name.toLower() || fi.baseName().toLower() == name.toLower()) - return true; -#endif - } - return false; -} - -static QStringList checkRunningProcessesFromList(const QStringList &processList) -{ - const QList<KDSysInfo::ProcessInfo> allProcesses = KDSysInfo::runningProcesses(); - QStringList stillRunningProcesses; - foreach (const QString &process, processList) { - if (!process.isEmpty() && isProcessRunning(process, allProcesses)) { - stillRunningProcesses.append(process); - } - } - return stillRunningProcesses; -} - -void Installer::Private::stopProcessesForUpdates(const QList<Component*> &components) -{ - QStringList processList; - foreach (const Component* const i, components) - processList << q->replaceVariables(i->stopProcessForUpdateRequests()); - - qSort(processList); - processList.erase(std::unique(processList.begin(), processList.end()), processList.end()); - if (processList.isEmpty()) - return; - - while (true) { - const QStringList processes = checkRunningProcessesFromList(processList); - if (processes.isEmpty()) - return; - - const QMessageBox::StandardButton button = - MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), - QLatin1String("stopProcessesForUpdates"), tr("Stop Processes"), tr("These processes " - "should be stopped to continue:\n\n%1").arg(QDir::toNativeSeparators(processes - .join(QLatin1String("\n")))), QMessageBox::Retry | QMessageBox::Ignore - | QMessageBox::Cancel, QMessageBox::Retry); - if (button == QMessageBox::Ignore) - return; - if (button == QMessageBox::Cancel) { - q->setCanceled(); - throw Error(tr("Installation canceled by user")); - } - } -} - -int Installer::Private::countProgressOperations(const QList<KDUpdater::UpdateOperation*> &operations) -{ - int operationCount = 0; - QList<KDUpdater::UpdateOperation*>::const_iterator oIt; - for (oIt = operations.constBegin(); oIt != operations.constEnd(); oIt++) { - KDUpdater::UpdateOperation* const operation = *oIt; - QObject* const operationObject = dynamic_cast< QObject* >(operation); - if (operationObject != 0) { - const QMetaObject* const mo = operationObject->metaObject(); - if (mo->indexOfSignal(QMetaObject::normalizedSignature("progressChanged(double)")) > -1) - operationCount++; - } - } - return operationCount; -} - -int Installer::Private::countProgressOperations(const QList<Component*> &components) -{ - int operationCount = 0; - for (QList<Component*>::const_iterator It = components.begin(); It != components.end(); ++It) - operationCount = operationCount + countProgressOperations((*It)->operations()); - - return operationCount; -} - -void Installer::Private::connectOperationToInstaller(KDUpdater::UpdateOperation* const operation, - double progressOperationPartSize) -{ - Q_ASSERT(progressOperationPartSize); - QObject* const operationObject = dynamic_cast< QObject* >(operation); - if (operationObject != 0) { - const QMetaObject* const mo = operationObject->metaObject(); - if (mo->indexOfSignal(QMetaObject::normalizedSignature("outputTextChanged(QString)")) > -1) { - connect(operationObject, SIGNAL(outputTextChanged(QString)), - ProgressCoordninator::instance(), SLOT(emitDetailTextChanged(QString))); - } - - if (mo->indexOfSlot(QMetaObject::normalizedSignature("cancelOperation()")) > -1) - connect(q, SIGNAL(installationInterrupted()), operationObject, SLOT(cancelOperation())); - - if (mo->indexOfSignal(QMetaObject::normalizedSignature("progressChanged(double)")) > -1) { - ProgressCoordninator::instance()->registerPartProgress(operationObject, - SIGNAL(progressChanged(double)), progressOperationPartSize); - } - } -} - -/*! - This creates fake operations which remove stuff which was registered for uninstallation afterwards -*/ -void Installer::Private::registerPathesForUninstallation( - const QList<QPair<QString, bool> > &pathesForUninstallation, const QString &componentName) -{ - if (pathesForUninstallation.isEmpty()) - return; - - QList<QPair<QString, bool> >::const_iterator it; - for (it = pathesForUninstallation.begin(); it != pathesForUninstallation.end(); ++it) { - const QString path = replaceVariables(it->first); - const bool wipe = it->second; - const QFileInfo fi(path); - - // create a copy operation with the file as target -> it will get deleted on undo - KDUpdater::UpdateOperation* const op = createOwnedOperation(QLatin1String(fi.isDir() - ? "Mkdir" : "Copy")); - if (fi.isDir()) { - op->setValue(QLatin1String("createddir"), fi.absoluteFilePath()); - op->setValue(QLatin1String("forceremoval"), wipe ? QLatin1String("true") - : QLatin1String("false")); - } - op->setArguments(fi.isDir() ? QStringList() << fi.absoluteFilePath() - : QStringList() << QString() << fi.absoluteFilePath()); - op->setValue(QLatin1String("component"), componentName); - addPerformed(op); - - // get recursive afterwards - if (fi.isDir() && !wipe) { - QDirIterator dirIt(path, QDir::Hidden | QDir::AllEntries | QDir::System - | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); - while (dirIt.hasNext()) { - dirIt.next(); - const QFileInfo fi = dirIt.fileInfo(); - if (fi.isDir()) { - // create an mkdir operation with the dir as target -> it will get deleted on undo - KDUpdater::UpdateOperation* const op = createOwnedOperation(QLatin1String("Mkdir")); - op->setArguments(QStringList() << fi.absoluteFilePath()); - op->setValue(QLatin1String("createddir"), fi.absoluteFilePath()); - op->setValue(QLatin1String("component"), componentName); - addPerformed(op); - } else { - // create a copy operation with the file as target -> it will get deleted on undo - KDUpdater::UpdateOperation* const op = createOwnedOperation(QLatin1String("Copy")); - op->setArguments(QStringList() << QString() << fi.absoluteFilePath()); - op->setValue(QLatin1String("component"), componentName); - addPerformed(op); - } - } - } - } -} - -void Installer::Private::writeUninstaller(QVector<KDUpdater::UpdateOperation*> performedOperations) -{ - bool gainedAdminRights = false; - QTemporaryFile tempAdminFile(targetDir() + QString::fromLatin1("/testjsfdjlkdsjflkdsjfldsjlfds") - + QString::number(qrand() % 1000)); - if (!tempAdminFile.open() || !tempAdminFile.isWritable()) { - q->gainAdminRights(); - gainedAdminRights = true; - } - - verbose() << "QInstaller::Installer::Private::writeUninstaller uninstaller=" << uninstallerName() - << std::endl; - - // create the directory containing the uninstaller (like a bundle structor, on Mac...) - KDUpdater::UpdateOperation* op = createOwnedOperation(QLatin1String("Mkdir")); - op->setArguments(QStringList() << QFileInfo(uninstallerName()).path()); - performOperationThreaded(op, Backup); - performOperationThreaded(op); - performedOperations.push_back(op); - - { - // write current state (variables) to the uninstaller ini file - const QString iniPath = targetDir() + QLatin1Char('/') + m_settings.uninstallerIniFile(); - QSettings cfg(iniPath, QSettings::IniFormat); - QVariantHash vars; - QHash<QString, QString>::ConstIterator it = m_vars.constBegin(); - while (it != m_vars.constEnd()) { - const QString &key = it.key(); - if (key != QLatin1String("RunProgramDescription") && key != QLatin1String("RunProgram")) - vars.insert(key, it.value()); - ++it; - } - cfg.setValue(QLatin1String("Variables"), vars); - cfg.sync(); - if (cfg.status() != QSettings::NoError) { - const QString reason = cfg.status() == QSettings::AccessError ? tr("Access error") - : tr("Format error"); - throw Error(tr("Could not write installer configuration to %1: %2").arg(iniPath, reason)); - } - } - -#ifdef Q_WS_MAC - // if it is a bundle, we need some stuff in it... - if (isInstaller() - && QFileInfo(QCoreApplication::applicationDirPath() + QLatin1String("/../..")).isBundle()) { - op = createOwnedOperation(QLatin1String("Copy")); - op->setArguments(QStringList() << (QCoreApplication::applicationDirPath() - + QLatin1String("/../PkgInfo")) << (QFileInfo(uninstallerName()).path() - + QLatin1String("/../PkgInfo"))); - performOperationThreaded(op, Backup); - performOperationThreaded(op); - - op = createOwnedOperation(QLatin1String("Copy")); - op->setArguments(QStringList() << (QCoreApplication::applicationDirPath() - + QLatin1String("/../Info.plist")) << (QFileInfo(uninstallerName()).path() - + QLatin1String("/../Info.plist"))); - performOperationThreaded(op, Backup); - performOperationThreaded(op); - - verbose() << "Checking for qt_menu.nib" << std::endl; - QString sourceDirName = QCoreApplication::applicationDirPath() - + QLatin1String("/../Resources/qt_menu.nib"); - if (QFileInfo(sourceDirName).exists()) { - verbose() << "qt_menu.nib has been found. Isn't it great?" << std::endl; - QString targetDirName = QFileInfo(QFileInfo(uninstallerName()).path() - + QLatin1String("/../Resources/qt_menu.nib")).absoluteFilePath(); - - // IFW has been built with a static Cocoa Qt. The app bundle must contain the qt_menu.nib. - // ### use the CopyDirectory operation in 1.1 - op = createOwnedOperation(QLatin1String("Mkdir")); - op->setArguments(QStringList() << targetDirName); - if (!op->performOperation()) { - verbose() << "ERROR in Mkdir operation: " << op->errorString() << std::endl; - } - - QDir sourceDir(sourceDirName); - foreach (const QString &filename, sourceDir.entryList(QDir::Files)) { - QString src = sourceDirName + QLatin1String("/") + filename; - QString dst = targetDirName + QLatin1String("/") + filename; - op = createOwnedOperation(QLatin1String("Copy")); - op->setArguments(QStringList() << src << dst); - if (!op->performOperation()) - verbose() << "ERROR in Copy operation: copy " << src << " to " << dst << std::endl - << "error message: " << op->errorString() << std::endl; - } - } - - // patch the Info.plist while copying it - QFile sourcePlist(QCoreApplication::applicationDirPath() + QLatin1String("/../Info.plist")); - openForRead(&sourcePlist, sourcePlist.fileName()); - QFile targetPlist(QFileInfo(uninstallerName()).path() + QLatin1String("/../Info.plist")); - openForWrite(&targetPlist, targetPlist.fileName()); - - QTextStream in(&sourcePlist); - QTextStream out(&targetPlist); - - while (!in.atEnd()) - { - QString line = in.readLine(); - line = line.replace(QLatin1String("<string>") - + QFileInfo(QCoreApplication::applicationFilePath()).baseName() - + QLatin1String("</string>"), QLatin1String("<string>") - + QFileInfo(uninstallerName()).baseName() + QLatin1String("</string>")); - out << line << endl; - } - - op = createOwnedOperation(QLatin1String("Mkdir")); - op->setArguments(QStringList() << (QFileInfo(QFileInfo(uninstallerName()).path()).path() - + QLatin1String("/Resources"))); - performOperationThreaded(op, Backup); - performOperationThreaded(op); - - const QString icon = QFileInfo(QCoreApplication::applicationFilePath()).baseName() - + QLatin1String(".icns"); - op = createOwnedOperation(QLatin1String("Copy")); - op->setArguments(QStringList() << (QCoreApplication::applicationDirPath() - + QLatin1String("/../Resources/") + icon) << (QFileInfo(uninstallerName()).path() - + QLatin1String("/../Resources/") + icon)); - performOperationThreaded(op, Backup); - performOperationThreaded(op); - - // finally, copy everything within Frameworks and plugins - if (QDir(QCoreApplication::applicationDirPath() + QLatin1String("/../Frameworks")).exists()) { - copyDirectoryContents(QCoreApplication::applicationDirPath() - + QLatin1String("/../Frameworks"), QFileInfo(uninstallerName()).path() - + QLatin1String("/../Frameworks")); - } - - if (QDir(QCoreApplication::applicationDirPath() + QLatin1String("/../plugins")).exists()) { - copyDirectoryContents(QCoreApplication::applicationDirPath() - + QLatin1String("/../plugins"), QFileInfo(uninstallerName()).path() - + QLatin1String("/../plugins")); - } - } -#endif - - QFile in; - if (isInstaller() || isUninstaller() || isPackageManager()) - in.setFileName(installerBinaryPath()); - else - in.setFileName(uninstallerName()); // we're the updater - - const QString installerBaseBinary = q->replaceVariables(installerBaseBinaryUnreplaced); - if (!installerBaseBinary.isEmpty()) - verbose() << "Got a replacement installer base binary: " << installerBaseBinary << std::endl; - - const bool haveSeparateExec = QFile::exists(installerBaseBinary) && !installerBaseBinary.isEmpty(); - verbose() << "Need to restart after exit: " << haveSeparateExec << " " - << qPrintable(installerBaseBinary) << std::endl; - -#ifdef Q_WS_WIN - KDSaveFile out(uninstallerName() + QLatin1String(".org")); -#else - KDSaveFile out(uninstallerName()); -#endif - - try { - ifVerbose("CREATING UNINSTALLER " << performedOperations.size()); - - QFile* execIn = ∈ - qint64 execSize = 0; - QFile ibbIn; - if (haveSeparateExec) { - ibbIn.setFileName(installerBaseBinary); - openForRead(&ibbIn, ibbIn.fileName()); - execIn = &ibbIn; - execSize = ibbIn.size(); - } - - openForRead(&in, in.fileName()); - openForWrite(&out, out.fileName()); - - const qint64 magicCookiePos = findMagicCookie(&in); - if (magicCookiePos < 0) { - throw Error(QObject::tr("Can not find the magic cookie in file %1. Are you sure this " - "is a valid installer?").arg(installerBinaryPath())); - } - - if (!in.seek(magicCookiePos - 7 * sizeof(qint64))) { - throw Error(QObject::tr("Failed to seek in file %1: %2").arg(installerBinaryPath(), - in.errorString())); - } - - qint64 resourceStart = retrieveInt64(&in); - const qint64 resourceLength = retrieveInt64(&in); - Q_ASSERT(resourceLength >= 0); - const qint64 _operationsStart = retrieveInt64(&in); - Q_UNUSED(_operationsStart); - Q_ASSERT(_operationsStart >= 0); - const qint64 _operationsLength = retrieveInt64(&in); - Q_UNUSED(_operationsLength); - Q_ASSERT(_operationsLength >= 0); - const qint64 count = retrieveInt64(&in); // atm always "1" - Q_ASSERT(count == 1); // we have just 1 resource atm - const qint64 dataBlockSize = retrieveInt64(&in); - const qint64 dataBlockStart = magicCookiePos + sizeof(qint64) - dataBlockSize; - resourceStart += dataBlockStart; - if (!haveSeparateExec) - execSize = dataBlockStart; - - // consider size difference between old and new installerbase executable (if updated) - const qint64 newResourceStart = execSize; - const qint64 magicmarker = retrieveInt64(&in); - Q_UNUSED(magicmarker); - Q_ASSERT(magicmarker == MagicInstallerMarker || magicmarker == MagicUninstallerMarker); - - - - if (!execIn->seek(0)) { - throw Error(QObject::tr("Failed to seek in file %1: %2").arg(execIn->fileName(), - execIn->errorString())); - } - appendData(&out, execIn, execSize); - - // copy the first few bytes to take the executable+resources over to the uninstaller. - if (! in.seek(resourceStart)) { - throw Error(QObject::tr("Failed to seek in file %1: %2").arg(in.fileName(), - in.errorString())); - } - Q_ASSERT(in.pos() == resourceStart && out.pos() == execSize); - - appendData(&out, &in, resourceLength); - const qint64 uninstallerDataBlockStart = out.pos(); - // compared to the installer we do not have component data but details about - // the performed operations during the installation to allow to undo them. - const qint64 operationsStart = out.pos(); - appendInt64(&out, performedOperations.count()); - foreach (KDUpdater::UpdateOperation *op, performedOperations) { - // the installer can't be put into XML, remove it first - op->clearValue(QLatin1String("installer")); - - appendString(&out, op->name()); - appendString(&out, op->toXml().toString()); - - // for the ui not to get blocked - qApp->processEvents(); - } - appendInt64(&out, performedOperations.count()); - const qint64 operationsEnd = out.pos(); - - // we dont save any component-indexes. - const qint64 numComponents = 0; - appendInt64(&out, numComponents); // for the indexes - // we dont save any components. - const qint64 compIndexStart = out.pos(); - appendInt64(&out, numComponents); // and 2 times number of components, - appendInt64(&out, numComponents); // one before and one after the components - const qint64 compIndexEnd = out.pos(); - - appendInt64Range(&out, Range<qint64>::fromStartAndEnd(compIndexStart, compIndexEnd) - .moved(-uninstallerDataBlockStart)); - appendInt64Range(&out, Range<qint64>::fromStartAndLength(newResourceStart, resourceLength) - .moved(-uninstallerDataBlockStart)); - appendInt64Range(&out, Range<qint64>::fromStartAndEnd(operationsStart, operationsEnd) - .moved(-uninstallerDataBlockStart)); - appendInt64(&out, count); - //data block size, from end of .exe to end of file - appendInt64(&out, out.pos() + 3 * sizeof(qint64) - uninstallerDataBlockStart); - appendInt64(&out, MagicUninstallerMarker); - appendInt64(&out, MagicCookie); - - out.setPermissions(out.permissions() | QFile::WriteUser | QFile::ReadGroup | QFile::ReadOther - | QFile::ExeOther | QFile::ExeGroup | QFile::ExeUser); - - if (!out.commit(KDSaveFile::OverwriteExistingFile)) { - throw Error(tr("Could not write uninstaller to %1: %2").arg(uninstallerName(), - out.errorString())); - } - - //delete the installerbase binary temporarily installed for the uninstaller update - if (haveSeparateExec) { - QFile tmp(installerBaseBinary); - // Is there anything more sensible we can do with this error? I think not. - // It's not serious enough for throwing/aborting. - if (!tmp.remove()) { - verbose() << "Could not remove installerbase binary (" << installerBaseBinary - << ") after updating the uninstaller: " << tmp.errorString() << std::endl; - } - installerBaseBinaryUnreplaced.clear(); - } - -#ifdef Q_WS_WIN - deferredRename(out.fileName(), QFileInfo(uninstallerName()).fileName(), - haveSeparateExec && !isInstaller()); -#else - verbose() << " preparing restart " << std::endl; - if (haveSeparateExec && !isInstaller()) - KDSelfRestarter::setRestartOnQuit(true); -#endif - } catch (const Error &err) { - setStatus(InstallerFailed); - if (gainedAdminRights) - q->dropAdminRights(); - m_needToWriteUninstaller = false; - throw err; - } - - if (gainedAdminRights) - q->dropAdminRights(); - - commitSessionOperations(); - - m_needToWriteUninstaller = false; -} - -QString Installer::Private::registerPath() const -{ - QString productName = m_vars.value(QLatin1String("ProductName")); - if (productName.isEmpty()) - throw Error(tr("ProductName should be set")); - - QString path = QLatin1String("HKEY_CURRENT_USER"); - if (m_vars.value(QLatin1String("AllUsers")) == QLatin1String("true")) - path = QLatin1String("HKEY_LOCAL_MACHINE"); - - return path + QLatin1String("\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\") - + productName; -} - -void Installer::Private::registerInstaller() -{ -#ifdef Q_OS_WIN - QSettings settings(registerPath(), QSettings::NativeFormat); - settings.setValue(QLatin1String("DisplayName"), m_vars.value(QLatin1String("ProductName"))); - settings.setValue(QLatin1String("DisplayVersion"), m_vars.value(QLatin1String("ProductVersion"))); - const QString uninstaller = QDir::toNativeSeparators(uninstallerName()); - settings.setValue(QLatin1String("DisplayIcon"), uninstaller); - settings.setValue(QLatin1String("Publisher"), m_vars.value(QLatin1String("Publisher"))); - settings.setValue(QLatin1String("UrlInfoAbout"), m_vars.value(QLatin1String("Url"))); - settings.setValue(QLatin1String("Comments"), m_vars.value(QLatin1String("Title"))); - settings.setValue(QLatin1String("InstallDate"), QDateTime::currentDateTime().toString()); - settings.setValue(QLatin1String("InstallLocation"), QDir::toNativeSeparators(targetDir())); - settings.setValue(QLatin1String("UninstallString"), uninstaller); - settings.setValue(QLatin1String("ModifyPath"), uninstaller + QLatin1String(" --manage-packages")); - settings.setValue(QLatin1String("EstimatedSize"), QFileInfo(installerBinaryPath()).size()); - settings.setValue(QLatin1String("NoModify"), 1); // TODO: set to 0 and support modify - settings.setValue(QLatin1String("NoRepair"), 1); -#endif -} - -void Installer::Private::unregisterInstaller() -{ -#ifdef Q_OS_WIN - QSettings settings(registerPath(), QSettings::NativeFormat); - settings.remove(QString()); -#endif + d->m_packageManagingMode = !d->m_completeUninstall; } void Installer::autoAcceptMessageBoxes() @@ -1319,7 +291,7 @@ void Installer::setMessageBoxAutomaticAnswer(const QString &identifier, int butt void Installer::installSelectedComponents() { - d->setStatus(InstallerRunning); + d->setStatus(Installer::Running); // download double downloadPartProgressSize = double(1)/3; @@ -1350,19 +322,20 @@ void Installer::installSelectedComponents() Component* const currentComponent = *it; ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("\nRemoving the old " "version of: %1").arg(currentComponent->name())); - if (isUpdater() && currentComponent->removeBeforeUpdate()) { + if ((isUpdater() || isPackageManager()) && currentComponent->removeBeforeUpdate()) { QString replacesAsString = currentComponent->value(QLatin1String("Replaces")); QStringList possibleNames(replacesAsString.split(QLatin1String(","), QString::SkipEmptyParts)); possibleNames.append(currentComponent->name()); + // undo all operations done by this component upon installation for (int i = d->m_performedOperationsOld.count() - 1; i >= 0; --i) { KDUpdater::UpdateOperation* const op = d->m_performedOperationsOld[i]; if (!possibleNames.contains(op->value(QLatin1String("component")).toString())) continue; - const bool becameAdmin = !d->engineClientHandler->isActive() + const bool becameAdmin = !d->m_FSEngineClientHandler->isActive() && op->value(QLatin1String("admin")).toBool() && gainAdminRights(); - performOperationThreaded(op, Undo); + InstallerPrivate::performOperationThreaded(op, InstallerPrivate::Undo); if (becameAdmin) dropAdminRights(); d->m_performedOperationsOld.remove(i); @@ -1381,40 +354,39 @@ void Installer::installSelectedComponents() d->m_needToWriteUninstaller = true; } - d->setStatus(InstallerSucceeded); + d->setStatus(Installer::Success); ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("\nUpdate finished!")); emit updateFinished(); } +quint64 size(QInstaller::Component *component, const QString &value) +{ + if (!component->isSelected()) + return quint64(0); + if (component->value(QLatin1String("PreviousState")) == QLatin1String("Installed")) + return quint64(0); + return component->value(value).toLongLong(); +} + quint64 Installer::requiredDiskSpace() const { quint64 result = 0; - QList<Component*>::const_iterator it; - const QList<Component*> availableComponents = components(true); - for (it = availableComponents.begin(); it != availableComponents.end(); ++it) { - Component* const comp = *it; - if (!comp->isSelected()) - continue; - if (comp->value(QLatin1String("PreviousState")) == QLatin1String("Installed")) - continue; - result += comp->value(QLatin1String("UncompressedSize")).toLongLong(); - } + + const QList<Component*> availableComponents = components(true, runMode()); + foreach (QInstaller::Component *component, availableComponents) + result += size(component, QLatin1String("UncompressedSize")); + return result; } quint64 Installer::requiredTemporaryDiskSpace() const { quint64 result = 0; - QList<Component*>::const_iterator it; - const QList<Component*> availableComponents = components(true); - for (it = availableComponents.begin(); it != availableComponents.end(); ++it) { - Component* const comp = *it; - if (!comp->isSelected()) - continue; - if (comp->value(QLatin1String("PreviousState")) == QLatin1String("Installed")) - continue; - result += comp->value(QLatin1String("CompressedSize")).toLongLong(); - } + + const QList<Component*> availableComponents = components(true, runMode()); + foreach (QInstaller::Component *component, availableComponents) + result += size(component, QLatin1String("CompressedSize")); + return result; } @@ -1435,7 +407,7 @@ int Installer::downloadNeededArchives(RunModes runMode, double partProgressSize) if (!comp->isSelected(runMode)) continue; if (comp->value(QLatin1String("PreviousState")) == QLatin1String("Installed") - && runMode == InstallerMode) { + && runMode == AllMode) { continue; } appendComponentAndMissingDependencies(neededComponents, comp); @@ -1460,7 +432,8 @@ int Installer::downloadNeededArchives(RunModes runMode, double partProgressSize) ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("\nDownloading packages...")); // don't have it on the stack, since it keeps the temporary files - DownloadArchivesJob* const archivesJob = new DownloadArchivesJob(d->m_settings.publicKey(), this); + DownloadArchivesJob* const archivesJob = + new DownloadArchivesJob(d->m_installerSettings->publicKey(), this); archivesJob->setArchivesToDownload(archivesToDownload); archivesJob->setAutoDelete(false); connect(archivesJob, SIGNAL(outputTextChanged(QString)), ProgressCoordninator::instance(), @@ -1490,7 +463,7 @@ void Installer::installComponent(Component* comp, double progressOperationSize) { Q_ASSERT(progressOperationSize); - d->setStatus(InstallerRunning); + d->setStatus(Installer::Running); const QList<KDUpdater::UpdateOperation*> operations = comp->operations(); // show only component which are doing something, MinimumProgress is only for progress @@ -1513,30 +486,30 @@ void Installer::installComponent(Component* comp, double progressOperationSize) d->connectOperationToInstaller(operation, progressOperationSize); // maybe this operations wants us to be admin... - const bool becameAdmin = !d->engineClientHandler->isActive() + const bool becameAdmin = !d->m_FSEngineClientHandler->isActive() && operation->value(QLatin1String("admin")).toBool() && gainAdminRights(); // perform the operation if (becameAdmin) verbose() << operation->name() << " as admin: " << becameAdmin << std::endl; // allow the operation to backup stuff before performing the operation - performOperationThreaded(operation, Backup); + InstallerPrivate::performOperationThreaded(operation, InstallerPrivate::Backup); bool ignoreError = false; - bool ok = performOperationThreaded(operation); - while (!ok && !ignoreError && status() != InstallerCanceledByUser) { + bool ok = InstallerPrivate::performOperationThreaded(operation); + while (!ok && !ignoreError && status() != Installer::Canceled) { verbose() << QString(QLatin1String("operation '%1' with arguments: '%2' failed: %3")) .arg(operation->name(), operation->arguments().join(QLatin1String("; ")), operation->errorString()) << std::endl;; const QMessageBox::StandardButton button = MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), QLatin1String("installationErrorWithRetry"), tr("Installer Error"), - tr("Error during installation process(%1):\n%2").arg(comp->name(), - operation->errorString()), + tr("Error during installation process (%1):\n%2").arg(comp->name(), + operation->errorString()), QMessageBox::Retry | QMessageBox::Ignore | QMessageBox::Cancel, QMessageBox::Retry); if (button == QMessageBox::Retry) - ok = performOperationThreaded(operation); + ok = InstallerPrivate::performOperationThreaded(operation); else if (button == QMessageBox::Ignore) ignoreError = true; else if (button == QMessageBox::Cancel) @@ -1625,9 +598,9 @@ void Installer::rollBackInstallation() KDUpdater::UpdateOperation* const operation = d->m_performedOperationsCurrentSession.last(); d->m_performedOperationsCurrentSession.pop_back(); - const bool becameAdmin = !d->engineClientHandler->isActive() + const bool becameAdmin = !d->m_FSEngineClientHandler->isActive() && operation->value(QLatin1String("admin")).toBool() && gainAdminRights(); - performOperationThreaded(operation, Undo); + InstallerPrivate::performOperationThreaded(operation, InstallerPrivate::Undo); if (becameAdmin) dropAdminRights(); } catch(const Error &e) { @@ -1639,595 +612,347 @@ void Installer::rollBackInstallation() } } -void Installer::Private::runInstaller() +bool Installer::isFileExtensionRegistered(const QString& extension) const { - try { - setStatus(InstallerRunning); - emit installationStarted(); //resets also the ProgressCoordninator - - //to have some progress for writeUninstaller - ProgressCoordninator::instance()->addReservePercentagePoints(1); - - const QString target = targetDir(); - if (target.isEmpty()) - throw Error(tr("Variable 'TargetDir' not set.")); - - // add the operation to create the target directory - bool installToAdminDirectory = false; - if (!QDir(target).exists()) { - QScopedPointer<KDUpdater::UpdateOperation> mkdirOp(createOwnedOperation(QLatin1String("Mkdir"))); - mkdirOp->setValue(QLatin1String("forceremoval"), true); - Q_ASSERT(mkdirOp.data()); - mkdirOp->setArguments(QStringList() << target); - performOperationThreaded(mkdirOp.data(), Backup); - if (!performOperationThreaded(mkdirOp.data())) { - // if we cannot create the target dir, we try to activate the admin rights - installToAdminDirectory = true; - if (!q->gainAdminRights() || !performOperationThreaded(mkdirOp.data())) - throw Error(mkdirOp->errorString()); - } - QString remove = q->value(QLatin1String("RemoveTargetDir")); - if (QVariant(remove).toBool()) - addPerformed(mkdirOp.take()); - } else { - QTemporaryFile tempAdminFile(target + QLatin1String("/adminrights")); - if (!tempAdminFile.open() || !tempAdminFile.isWritable()) - installToAdminDirectory = q->gainAdminRights(); - } - - // to show that there was some work - ProgressCoordninator::instance()->addManualPercentagePoints(1); - - ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("Preparing the installation...")); - const QList<Component*> componentsToInstall = q->calculateComponentOrder(); - verbose() << "Install size: " << componentsToInstall.size() << " components" << std::endl; - - // check if we need admin rights and ask before the action happens - for (QList<Component*>::const_iterator it = componentsToInstall.begin(); - it != componentsToInstall.end() && !installToAdminDirectory; ++it) { - Component* const component = *it; - bool requiredAdmin = false; - - if (component->value(QLatin1String("RequiresAdminRights"), - QLatin1String("false")) == QLatin1String("true")) { - requiredAdmin = q->gainAdminRights(); - } - - if (requiredAdmin) { - q->dropAdminRights(); - break; - } - } - - const double downloadPartProgressSize = double(1) / 3; - double componentsInstallPartProgressSize = double(2) / 3; - const int downloadedArchivesCount = q->downloadNeededArchives(InstallerMode, - downloadPartProgressSize); - - //if there was no download we have the whole progress for installing components - if (!downloadedArchivesCount) { - //componentsInstallPartProgressSize + downloadPartProgressSize; - componentsInstallPartProgressSize = double(1); - } - - // put the installed packages info into the target dir - KDUpdater::PackagesInfo* const packages = m_app->packagesInfo(); - packages->setFileName(componentsXmlPath()); - packages->setApplicationName(m_settings.applicationName()); - packages->setApplicationVersion(m_settings.applicationVersion()); - - stopProcessesForUpdates(componentsToInstall); - - const int progressOperationCount = countProgressOperations(componentsToInstall); - double progressOperationSize = componentsInstallPartProgressSize / progressOperationCount; - - QList<Component*>::const_iterator it; - for (it = componentsToInstall.begin(); it != componentsToInstall.end(); ++it) - q->installComponent(*it, progressOperationSize); - - registerInstaller(); - - emit q->titleMessageChanged(tr("Creating Uninstaller")); - - m_app->packagesInfo()->writeToDisk(); - writeUninstaller(m_performedOperationsOld + m_performedOperationsCurrentSession); - - //this is the reserved one from the beginning - ProgressCoordninator::instance()->addManualPercentagePoints(1); - - setStatus(InstallerSucceeded); - ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("\nInstallation finished!")); - - emit installationFinished(); + QSettings settings(QLatin1String("HKEY_CLASSES_ROOT"), QSettings::NativeFormat); + return settings.value(QString::fromLatin1(".%1/Default").arg(extension)).isValid(); +} - // disable the FSEngineClientHandler afterwards - engineClientHandler->setActive(false); - } catch (const Error &err) { - if (q->status() != InstallerCanceledByUser) { - setStatus(InstallerFailed); - verbose() << "INSTALLER FAILED: " << err.message() << std::endl; - MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), - QLatin1String("installationError"), tr("Error"), err.message()); - verbose() << "ROLLING BACK operations=" << m_performedOperationsCurrentSession.count() - << std::endl; - } - q->rollBackInstallation(); +// -- QInstaller - ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("Installation aborted")); - emit installationFinished(); +Installer::Installer(qint64 magicmaker, + const QVector<KDUpdater::UpdateOperation*>& performedOperations) + : d(new InstallerPrivate(this, magicmaker, performedOperations)) +{ + qRegisterMetaType< QInstaller::Installer::Status >("QInstaller::Installer::Status"); + qRegisterMetaType< QInstaller::Installer::WizardPage >("QInstaller::Installer::WizardPage"); - // disable the FSEngineClientHandler afterwards - engineClientHandler->setActive(false); - throw; - } + d->initialize(); } -void Installer::Private::deleteUninstaller() +Installer::~Installer() { -#ifdef Q_OS_WIN - // Since Windows does not support that the uninstaller deletes itself we have to go with a - // rather dirty hack. What we do is to create a batchfile that will try to remove the uninstaller - // once per second. Then we start that batchfile detached, finished our job and close outself. - // Once that's done the batchfile will succeed in deleting our uninstall.exe and, if the - // installation directory was created but us and if it's empty after the uninstall, deletes - // the installation-directory. - const QString batchfile = QDir::toNativeSeparators(QFileInfo(QDir::tempPath(), - QLatin1String("uninstall.vbs")).absoluteFilePath()); - QFile f(batchfile); - if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) - throw Error(tr("Cannot prepare uninstall")); - - QTextStream batch(&f); - batch << "Set fso = WScript.CreateObject(\"Scripting.FileSystemObject\")\n"; - batch << "file = WScript.Arguments.Item(0)\n"; - batch << "folderpath = WScript.Arguments.Item(1)\n"; - batch << "Set folder = fso.GetFolder(folderpath)\n"; - batch << "on error resume next\n"; - - batch << "while fso.FileExists(file)\n"; - batch << " fso.DeleteFile(file)\n"; - batch << " WScript.Sleep(1000)\n"; - batch << "wend\n"; -// batch << "if folder.SubFolders.Count = 0 and folder.Files.Count = 0 then\n"; - batch << " Set folder = Nothing\n"; - batch << " fso.DeleteFolder folderpath, true\n"; -// batch << "end if\n"; - batch << "fso.DeleteFile(WScript.ScriptFullName)\n"; - - f.close(); - - QStringList arguments; - arguments << QLatin1String("//Nologo") << batchfile; // execute the batchfile - arguments << QDir::toNativeSeparators(QFileInfo(installerBinaryPath()).absoluteFilePath()); - if (!m_performedOperationsOld.isEmpty()) { - const KDUpdater::UpdateOperation* const op = m_performedOperationsOld.first(); - if (op->name() == QLatin1String("Mkdir")) // the target directory name - arguments << QDir::toNativeSeparators(QFileInfo(op->arguments().first()).absoluteFilePath()); - } - - if (!QProcess::startDetached(QLatin1String("cscript"), arguments, QDir::rootPath())) - throw Error(tr("Cannot start uninstall")); -#else - // every other platform has no problem if we just delete ourself now - QFile uninstaller(QFileInfo(installerBinaryPath()).absoluteFilePath()); - uninstaller.remove(); -#ifdef Q_WS_MAC - const QLatin1String cdUp("/../../.."); - if (QFileInfo(QFileInfo(installerBinaryPath() + cdUp).absoluteFilePath()).isBundle()) { - removeDirectoryThreaded(QFileInfo(installerBinaryPath() + cdUp).absoluteFilePath()); - QFile::remove(QFileInfo(installerBinaryPath() + cdUp).absolutePath() - + QLatin1String("/") + configurationFileName()); - } - else -#endif -#endif - { - // finally remove the components.xml, since it still exists now - QFile::remove(QFileInfo(installerBinaryPath()).absolutePath() + QLatin1String("/") + configurationFileName()); + if (!isUninstaller() && !(isInstaller() && status() == Installer::Canceled)) { + QDir targetDir(value(QLatin1String("TargetDir"))); + QString logFileName = targetDir.absoluteFilePath(value(QLatin1String("LogFileName"), + QLatin1String("InstallationLog.txt"))); + QInstaller::VerboseWriter::instance()->setOutputStream(logFileName); } + + d->m_FSEngineClientHandler->setActive(false); + delete d; } -bool Installer::isFileExtensionRegistered(const QString& extension) const +RunModes Installer::runMode() const { - QSettings settings(QLatin1String("HKEY_CLASSES_ROOT"), QSettings::NativeFormat); - return settings.value(QString::fromLatin1(".%1/Default").arg(extension)).isValid(); + return isUpdater() ? UpdaterMode : AllMode; } -void Installer::Private::runPackageUpdater() +/*! + Returns a hash containing the installed package name and it's associated package information. If + the application is runing in installer mode or the local components file could not be parsed, the + hash is empty. +*/ +QHash<QString, KDUpdater::PackageInfo> Installer::localInstalledPackages() { - try { - if (m_completeUninstall) { - // well... I guess we would call that an uninstall, no? :-) - packageManagingMode = !m_completeUninstall; - runUninstaller(); - return; + QHash<QString, KDUpdater::PackageInfo> installedPackages; + + if (!isInstaller()) { + KDUpdater::PackagesInfo &packagesInfo = *d->m_app->packagesInfo(); + if (!setAndParseLocalComponentsFile(packagesInfo)) { + verbose() << tr("Could not parse local components xml file: %1") + .arg(d->localComponentsXmlPath()); + return installedPackages; } + packagesInfo.setApplicationName(d->m_installerSettings->applicationName()); + packagesInfo.setApplicationVersion(d->m_installerSettings->applicationVersion()); - setStatus(InstallerRunning); - emit installationStarted(); //resets also the ProgressCoordninator + foreach (const KDUpdater::PackageInfo &info, packagesInfo.packageInfos()) + installedPackages.insert(info.name, info); + } - //to have some progress for the cleanup/write component.xml step - ProgressCoordninator::instance()->addReservePercentagePoints(1); + return installedPackages; +} - if (!QFileInfo(installerBinaryPath()).isWritable()) - q->gainAdminRights(); +GetRepositoriesMetaInfoJob* Installer::fetchMetaInformation(const QInstaller::InstallerSettings &settings) +{ + GetRepositoriesMetaInfoJob *metaInfoJob = new GetRepositoriesMetaInfoJob(settings.publicKey(), false); + if ((isInstaller() && !isOfflineOnly()) || (isUpdater() || isPackageManager())) + metaInfoJob->setRepositories(settings.repositories()); - KDUpdater::PackagesInfo* const packages = m_app->packagesInfo(); - packages->setFileName(componentsXmlPath()); - packages->setApplicationName(m_settings.applicationName()); - packages->setApplicationVersion(m_settings.applicationVersion()); + connect (metaInfoJob, SIGNAL(infoMessage(KDJob*, QString)), this, + SIGNAL(metaJobInfoMessage(KDJob*, QString))); + connect (this, SIGNAL(cancelMetaInfoJob()), metaInfoJob, SLOT(doCancel()), + Qt::QueuedConnection); - const QString packagesXml = componentsXmlPath(); - if (!QFile(packagesXml).open(QIODevice::Append)) - q->gainAdminRights(); + try { + metaInfoJob->setAutoDelete(false); + metaInfoJob->start(); + metaInfoJob->waitForFinished(); + } catch (Error &error) { + verbose() << tr("Could not retrieve meta information: %1").arg(error.message()) << std::endl; + } - // first check, if we need admin rights for the installation part - QList<Component*>::const_iterator it; - QList<Component*> availableComponents = q->components(true, InstallerMode); - for (it = availableComponents.begin(); it != availableComponents.end(); ++it) { - // check if we need admin rights and ask before the action happens - Component* const currentComponent = *it; - if (!currentComponent->isSelected(InstallerMode)) - continue; + return metaInfoJob; +} - // we only need the uninstalled components - if (currentComponent->value(QLatin1String("PreviousState")) == QLatin1String("Installed")) - continue; +bool Installer::addUpdateResourcesFrom(GetRepositoriesMetaInfoJob *metaInfoJob, const InstallerSettings &settings, + bool parseChecksum) +{ + const QString &appName = settings.applicationName(); + const QStringList tempDirs = metaInfoJob->temporaryDirectories(); + foreach (const QString &tmpDir, tempDirs) { + if (tmpDir.isEmpty()) + continue; - bool requiredAdmin = false; - if (currentComponent->value(QLatin1String("RequiresAdminRights"), - QLatin1String("false")) == QLatin1String("true")) { - requiredAdmin = q->gainAdminRights(); + if (parseChecksum) { + const QString updatesXmlPath = tmpDir + QLatin1String("/Updates.xml"); + QFile updatesFile(updatesXmlPath); + try { + openForRead(&updatesFile, updatesFile.fileName()); + } catch(const Error &e) { + verbose() << tr("Error opening Updates.xml: ") << e.message() << std::endl; + return false; } - if (requiredAdmin) { - q->dropAdminRights(); - break; + int line = 0; + int column = 0; + QString error; + QDomDocument doc; + if (!doc.setContent(&updatesFile, &error, &line, &column)) { + verbose() << tr("Parse error in File %4 : %1 at line %2 col %3").arg(error, + QString::number(line), QString::number(column), updatesFile.fileName()) << std::endl; + return false; } - } - - //to have 1/5 for undoOperationProgressSize and 2/5 for componentsInstallPartProgressSize - const double downloadPartProgressSize = double(2) / 5; - // following, we download the needed archives - q->downloadNeededArchives(InstallerMode, downloadPartProgressSize); - - ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("Removing deselected components...")); - QVector< KDUpdater::UpdateOperation* > nonRevertedOperations; - - QList<KDUpdater::UpdateOperation*> undoOperations; - for (int i = m_performedOperationsOld.count() - 1; i >= 0; --i) { - KDUpdater::UpdateOperation* const currentOperation = m_performedOperationsOld[i]; - - const QString componentName = currentOperation->value(QLatin1String("component")).toString(); - Component* comp = q->componentByName(componentName); - // if we're _not_ removing everything an this component is still selected, -> next - if (comp == 0 || comp->isSelected()) { - nonRevertedOperations.push_front(currentOperation); - continue; + const QDomNode checksum = doc.documentElement().firstChildElement(QLatin1String("Checksum")); + if (!checksum.isNull()) { + const QDomElement checksumElem = checksum.toElement(); + setTestChecksum(checksumElem.text().toLower() == QLatin1String("true")); } - undoOperations.append(currentOperation); - } - - double undoOperationProgressSize = 0; - int progressUndoOperationCount = 0; - double progressUndoOperationSize = 0; - double componentsInstallPartProgressSize = double(2) / 5; - if (undoOperations.count() > 0) { - componentsInstallPartProgressSize = double(2) / 5; - undoOperationProgressSize = double(1) / 5; - progressUndoOperationCount = countProgressOperations(undoOperations); - progressUndoOperationSize = undoOperationProgressSize / progressUndoOperationCount; - } else { - componentsInstallPartProgressSize = double(3) / 5; } + d->m_app->addUpdateSource(appName, appName, QString(), QUrl::fromLocalFile(tmpDir), 1); + } + d->m_app->updateSourcesInfo()->setModified(false); - QSet<Component*> uninstalledComponents; - foreach (KDUpdater::UpdateOperation* const currentOperation, undoOperations) { - if (statusCanceledOrFailed()) - throw Error(tr("Installation canceled by user")); - connectOperationToInstaller(currentOperation, progressUndoOperationSize); - - const QString componentName = currentOperation->value(QLatin1String("component")).toString(); - Component* comp = q->componentByName(componentName); - - verbose() << "undo operation=" << currentOperation->name() << std::endl; - uninstalledComponents |= comp; - - const bool becameAdmin = !engineClientHandler->isActive() - && currentOperation->value(QLatin1String("admin")).toBool() && q->gainAdminRights(); - - bool ignoreError = false; - performOperationThreaded(currentOperation, Undo); - bool ok = currentOperation->error() == KDUpdater::UpdateOperation::NoError - || componentName == QLatin1String(""); - while (!ok && !ignoreError && q->status() != InstallerCanceledByUser) { - verbose() << QString(QLatin1String("operation '%1' with arguments: '%2' failed: %3")) - .arg(currentOperation->name(), currentOperation->arguments() - .join(QLatin1String("; ")), currentOperation->errorString()) << std::endl;; - - const QMessageBox::StandardButton button = - MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), - QLatin1String("installationErrorWithRetry"), tr("Installer Error"), - tr("Error during installation process(%1):\n%2").arg(componentName, - currentOperation->errorString()), - QMessageBox::Retry | QMessageBox::Ignore, QMessageBox::Retry); - - if (button == QMessageBox::Retry) { - performOperationThreaded(currentOperation, Undo); - ok = currentOperation->error() == KDUpdater::UpdateOperation::NoError; - } - else if (button == QMessageBox::Ignore) - ignoreError = true; - } + return true; +} - if (becameAdmin) - q->dropAdminRights(); +bool Installer::fetchAllPackages() +{ + if (isUninstaller() || isUpdater()) + return false; - delete currentOperation; - } + QHash<QString, KDUpdater::PackageInfo> installedPackages = localInstalledPackages(); - const QList<Component*> allComponents = q->components(true, InstallerMode); - foreach (Component *comp, allComponents) { - if (!comp->isSelected()) - uninstalledComponents |= comp; - } + QScopedPointer <GetRepositoriesMetaInfoJob> metaInfoJob(fetchMetaInformation(*d->m_installerSettings)); + if (metaInfoJob->isCanceled() || metaInfoJob->error() != KDJob::NoError) { + verbose() << tr("Could not retrieve components: %1").arg(metaInfoJob->errorString()) << std::endl; + if (isInstaller()) + return false; + } - QSet<Component*>::const_iterator it2; - for (it2 = uninstalledComponents.begin(); it2 != uninstalledComponents.end(); ++it2) { - packages->removePackage((*it2)->name()); - (*it2)->setValue(QLatin1String("CurrentState"), QLatin1String("Uninstalled")); + if (!metaInfoJob->temporaryDirectories().isEmpty()) { + if (!addUpdateResourcesFrom(metaInfoJob.data(), *d->m_installerSettings, true)) { + verbose() << tr("Could not add temorary upade source information.") << std::endl; + return false; } + } - // these are all operations left: those which were not reverted - m_performedOperationsOld = nonRevertedOperations; - - //write components.xml in case the user cancels the update - packages->writeToDisk(); - ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("Preparing the installation...")); - - const QList<Component*> componentsToInstall = q->calculateComponentOrder(); + if (d->m_app->updateSourcesInfo()->updateSourceInfoCount() == 0) { + verbose() << tr("Could not find any update source information.") << std::endl; + return false; + } - verbose() << "Install size: " << componentsToInstall.size() << " components " << std::endl; + KDUpdater::UpdateFinder updateFinder(d->m_app); + updateFinder.setUpdateType(KDUpdater::PackageUpdate | KDUpdater::NewPackage); + updateFinder.run(); - stopProcessesForUpdates(componentsToInstall); + const QList<KDUpdater::Update*> &packages = updateFinder.updates(); + if (packages.isEmpty()) { + verbose() << tr("Could not retrieve components: %1").arg(updateFinder.errorString()); + return false; + } - int progressOperationCount = countProgressOperations(componentsToInstall); - double progressOperationSize = componentsInstallPartProgressSize / progressOperationCount; + emit startAllComponentsReset(); - for (it = componentsToInstall.begin(); it != componentsToInstall.end(); ++it) - q->installComponent(*it, progressOperationSize); + qDeleteAll(d->m_rootComponents); + d->m_rootComponents.clear(); - packages->writeToDisk(); + QMap<QString, QInstaller::Component*> components; + foreach (KDUpdater::Update *package, packages) { + const QString name = package->data(QLatin1String("Name")).toString(); + if (components.contains(name)) { + qCritical("Could not register component! Component with identifier %s already registered.", + qPrintable(name)); + continue; + } - emit q->titleMessageChanged(tr("Creating Uninstaller")); + QScopedPointer<QInstaller::Component> component(new QInstaller::Component(package, this)); - commitSessionOperations(); //end session, move ops to "old" - m_needToWriteUninstaller = true; + QString state = QLatin1String("Uninstalled"); + if (installedPackages.contains(name)) { + state = QLatin1String("Installed"); + component->setSelected(true, AllMode, Component::InitializeComponentTreeSelectMode); + component->setValue(QLatin1String("InstalledVersion"), installedPackages.value(name).version); + } + component->setValue(QLatin1String("CurrentState"), state); + component->setValue(QLatin1String("PreviousState"), state); - //this is the reserved one from the beginning - ProgressCoordninator::instance()->addManualPercentagePoints(1); + const QString &localPath = component->localTempPath(); + if (isVerbose()) { + static QString lastLocalPath; + if (lastLocalPath != localPath) + verbose() << "Url is : " << localPath << std::endl; + lastLocalPath = localPath; + } + component->setRepositoryUrl(metaInfoJob->repositoryForTemporaryDirectory(localPath).url()); - setStatus(InstallerSucceeded); - ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("\nInstallation finished!")); - emit installationFinished(); + components.insert(name, component.take()); + } - // disable the FSEngineClientHandler afterwards - engineClientHandler->setActive(false); - } catch(const Error &err) { - if (q->status() != InstallerCanceledByUser) { - setStatus(InstallerFailed); - verbose() << "INSTALLER FAILED: " << err.message() << std::endl; - MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), - QLatin1String("installationError"), tr("Error"), err.message()); - verbose() << "ROLLING BACK operations=" << m_performedOperationsCurrentSession.count() - << std::endl; + // now append all components to their respective parents + QMap<QString, QInstaller::Component*>::const_iterator it; + for (it = components.begin(); it != components.end(); ++it) { + QString id = it.key(); + QInstaller::Component *component = it.value(); + while (!id.isEmpty() && component->parentComponent() == 0) { + id = id.section(QLatin1Char('.'), 0, -2); + if (components.contains(id)) + components[id]->appendComponent(component); } + } + + // append all components w/o parent to the direct list + foreach (QInstaller::Component *component, components) { + if (component->parentComponent() == 0) + appendRootComponent(component, AllMode); + } - q->rollBackInstallation(); + // after everything is set up, load the scripts + foreach (QInstaller::Component *component, components) + component->loadComponentScript(); - ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("Installation aborted")); - emit installationFinished(); + emit rootComponentsAdded(d->m_rootComponents); + emit finishAllComponentsReset(); - // disable the FSEngineClientHandler afterwards - engineClientHandler->setActive(false); - throw; - } + return true; } -void Installer::Private::runUninstaller() +bool Installer::fetchUpdaterPackages() { - try { - emit uninstallationStarted(); - - if (!QFileInfo(installerBinaryPath()).isWritable()) - q->gainAdminRights(); + if (!isUpdater()) + return false; - const QString packagesXml = componentsXmlPath(); - if (!QFile(packagesXml).open(QIODevice::Append)) - q->gainAdminRights(); + QHash<QString, KDUpdater::PackageInfo> installedPackages = localInstalledPackages(); - KDUpdater::PackagesInfo* const packages = m_app->packagesInfo(); - packages->setFileName(componentsXmlPath()); - packages->setApplicationName(m_settings.applicationName()); - packages->setApplicationVersion(m_settings.applicationVersion()); + QScopedPointer <GetRepositoriesMetaInfoJob> metaInfoJob(fetchMetaInformation(*d->m_installerSettings)); + if (metaInfoJob->isCanceled() || metaInfoJob->error() != KDJob::NoError) { + verbose() << tr("Could not retrieve updates: %1").arg(metaInfoJob->errorString()) << std::endl; + return false; + } - // iterate over all components - if they're all marked for uninstall, it's a complete uninstall - const QList<Component*> allComponents = q->components(true); - bool allMarkedForUninstall = true; + if (!metaInfoJob->temporaryDirectories().isEmpty()) { + if (!addUpdateResourcesFrom(metaInfoJob.data(), *d->m_installerSettings, true)) { + verbose() << tr("Could not add temorary upade source information.") << std::endl; + return false; + } + } - QList<KDUpdater::UpdateOperation*> uninstallOperations; - QVector<KDUpdater::UpdateOperation*> nonRevertedOperations; + if (d->m_app->updateSourcesInfo()->updateSourceInfoCount() == 0) { + verbose() << tr("Could not find any update source information.") << std::endl; + return false; + } - // just rollback all operations done before - for (int i = m_performedOperationsOld.count() - 1; i >= 0; --i) { - KDUpdater::UpdateOperation* const operation = m_performedOperationsOld[i]; + KDUpdater::UpdateFinder updateFinder(d->m_app); + updateFinder.setUpdateType(KDUpdater::PackageUpdate | KDUpdater::NewPackage); + updateFinder.run(); - const QString componentName = operation->value(QLatin1String("component")).toString(); - const Component* const comp = q->componentByName(componentName); + const QList<KDUpdater::Update*> &updates = updateFinder.updates(); + if (updates.isEmpty()) { + verbose() << tr("Could not retrieve updates: %1").arg(updateFinder.errorString()); + return false; + } - // if we're _not_ removing everything an this component is still selected, -> next - if (!m_completeUninstall && (comp == 0 || !comp->isSelected())) { - nonRevertedOperations.push_front(operation); - continue; - } - uninstallOperations.append(operation); - } + emit startUpdaterComponentsReset(); - const int progressUninstallOperationCount = countProgressOperations(uninstallOperations); - const double progressUninstallOperationSize = double(1) / progressUninstallOperationCount; - - foreach (KDUpdater::UpdateOperation* const currentOperation, uninstallOperations) { - if (statusCanceledOrFailed()) - throw Error(tr("Installation canceled by user")); - - connectOperationToInstaller(currentOperation, progressUninstallOperationSize); - verbose() << "undo operation=" << currentOperation->name() << std::endl; - - const QString componentName = currentOperation->value(QLatin1String("component")).toString(); - - const bool becameAdmin = !engineClientHandler->isActive() - && currentOperation->value(QLatin1String("admin")).toBool() && q->gainAdminRights(); - - bool ignoreError = false; - performOperationThreaded(currentOperation, Undo); - bool ok = currentOperation->error() == KDUpdater::UpdateOperation::NoError - || componentName == QLatin1String(""); - while (!ok && !ignoreError && q->status() != InstallerCanceledByUser) { - verbose() << QString(QLatin1String("operation '%1' with arguments: '%2' failed: %3")) - .arg(currentOperation->name(), currentOperation->arguments() - .join(QLatin1String("; ")), currentOperation->errorString()) << std::endl;; - const QMessageBox::StandardButton button = - MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), - QLatin1String("installationErrorWithRetry"), tr("Installer Error"), - tr("Error during installation process(%1):\n%2").arg(componentName, - currentOperation->errorString()), - QMessageBox::Retry | QMessageBox::Ignore, QMessageBox::Retry); - - if (button == QMessageBox::Retry) { - performOperationThreaded(currentOperation, Undo); - ok = currentOperation->error() == KDUpdater::UpdateOperation::NoError; - } else if (button == QMessageBox::Ignore) - ignoreError = true; - } + qDeleteAll(d->m_updaterComponents); + d->m_updaterComponents.clear(); - if (becameAdmin) - q->dropAdminRights(); + bool importantUpdates = false; + QMap<QString, QInstaller::Component*> components; + foreach (KDUpdater::Update * const update, updates) { + const QString isNew = update->data(QLatin1String("NewComponent")).toString(); + if (isNew.toLower() != QLatin1String("true")) + continue; - if (!m_completeUninstall) - delete currentOperation; + const QString name = update->data(QLatin1String("Name")).toString(); + if (components.contains(name)) { + qCritical("Could not register component! Component with identifier %s already registered.", + qPrintable(name)); + continue; } - if (!m_completeUninstall) { - QList<Component*>::const_iterator it; - for (it = allComponents.begin(); it != allComponents.end(); ++it) { - Component* const comp = *it; - if (comp->isSelected()) { - allMarkedForUninstall = false; - } else { - packages->removePackage(comp->name()); - comp->setValue(QLatin1String("CurrentState"), QLatin1String("Uninstalled")); - } - } - m_completeUninstall = m_completeUninstall || allMarkedForUninstall; - packageManagingMode = ! m_completeUninstall; + if (!installedPackages.contains(name)) { + verbose() << tr("Update for not installed package found, will skip it.") << std::endl; + continue; } - const QString startMenuDir = m_vars.value(QLatin1String("StartMenuDir")); - if (!startMenuDir.isEmpty()) { - errno = 0; - if (!QDir().rmdir(startMenuDir)) { - verbose() << "Could not remove " << startMenuDir << " : " - << QLatin1String(strerror(errno)) << std::endl; - } else { - verbose() << "Startmenu dir not set" << std::endl; - } - } + const KDUpdater::PackageInfo &info = installedPackages.value(name); + const QString updateVersion = update->data(QLatin1String("Version")).toString(); + if (KDUpdater::compareVersion(updateVersion, info.version) <= 0) + continue; - if (m_completeUninstall) { - // this will also delete the TargetDir on Windows - deleteUninstaller(); - QList<Component*>::const_iterator it; - for (it = allComponents.begin(); it != allComponents.end(); ++it) { - packages->removePackage((*it)->name()); - (*it)->setValue(QLatin1String("CurrentState"), QLatin1String("Uninstalled")); - } - QString remove = q->value(QLatin1String("RemoveTargetDir")); - if(QVariant(remove).toBool()) - { - // on !Windows, we need to remove TargetDir manually - packageManagingMode = ! m_completeUninstall; - verbose() << "Complete Uninstallation is chosen" << std::endl; - const QString target = targetDir(); - if (!target.isEmpty()) { - if (engineClientHandler->isServerRunning() && !engineClientHandler->isActive()) { - // we were root at least once, so we remove the target dir as root - q->gainAdminRights(); - removeDirectoryThreaded(target, true); - q->dropAdminRights(); - } else { - removeDirectoryThreaded(target, true); - } - } - } + // It is quite possible that we may have already installed the update. Lets check the last + // update date of the package and the release date of the update. This way we can compare and + // figure out if the update has been installed or not. + const QDate updateDate = update->data(QLatin1String("ReleaseDate")).toDate(); + if (info.lastUpdateDate > updateDate) + continue; - unregisterInstaller(); - m_needToWriteUninstaller = false; - } else { - // rewrite the uninstaller with the operation we did not undo - writeUninstaller(nonRevertedOperations); - } + QScopedPointer<QInstaller::Component> component(new QInstaller::Component(update, this)); - setStatus(InstallerSucceeded); - ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("\nDeinstallation finished")); + component->setValue(QLatin1String("InstalledVersion"), info.version); + component->setValue(QLatin1String("CurrentState"), QLatin1String("Installed")); + component->setValue(QLatin1String("PreviousState"), QLatin1String("Installed")); - engineClientHandler->setActive(false); - } catch (const Error &err) { - if (q->status() != InstallerCanceledByUser) { - setStatus(InstallerFailed); - verbose() << "INSTALLER FAILED: " << err.message() << std::endl; - MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), - QLatin1String("installationError"), tr("Error"), err.message()); - verbose() << "ROLLING BACK operations=" << m_performedOperationsCurrentSession.count() - << std::endl; + const QString &localPath = component->localTempPath(); + if (isVerbose()) { + static QString lastLocalPath; + if (lastLocalPath != localPath) + verbose() << "Url is : " << localPath << std::endl; + lastLocalPath = localPath; } + component->setRepositoryUrl(metaInfoJob->repositoryForTemporaryDirectory(localPath).url()); - ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("Installation aborted")); - emit installationFinished(); - - // disable the FSEngineClientHandler afterwards - engineClientHandler->setActive(false); - throw; + components.insert(name, component.take()); } - emit uninstallationFinished(); -} - - -// -- QInstaller + // remove all unimportant components + QList<QInstaller::Component*> updaterComponents = components.values(); + if (importantUpdates) { + for (int i = updaterComponents.count() - 1; i >= 0; --i) { + const QString important = updaterComponents.at(i)->value(QLatin1String("Important")); + if (important.toLower() == QLatin1String ("false") || important.isEmpty()) { + delete updaterComponents[i]; + updaterComponents.removeAt(i); + } + } + } -Installer::Installer(qint64 magicmaker, - const QVector<KDUpdater::UpdateOperation*>& performedOperations) - : d(new Private(this, magicmaker, performedOperations)) -{ - qRegisterMetaType< QInstaller::Installer::Status >("QInstaller::Installer::Status"); - qRegisterMetaType< QInstaller::Installer::WizardPage >("QInstaller::Installer::WizardPage"); + // append all components w/o parent to the direct list + foreach (QInstaller::Component *component, updaterComponents) + appendRootComponent(component, UpdaterMode); - d->initialize(); -} + // after everything is set up, load the scripts + foreach (QInstaller::Component *component, updaterComponents) + component->loadComponentScript(); -Installer::~Installer() -{ - if (!isUninstaller() && !(isInstaller() && status() == InstallerCanceledByUser)) { - QDir targetDir(value(QLatin1String("TargetDir"))); - QString logFileName = targetDir.absoluteFilePath(value(QLatin1String("LogFileName"), - QLatin1String("InstallationLog.txt"))); - QInstaller::VerboseWriter::instance()->setOutputStream(logFileName); - } + emit updaterComponentsAdded(d->m_updaterComponents); + emit finishUpdaterComponentsReset(); - d->engineClientHandler->setActive(false); - delete d; + return true; } /*! @@ -2297,7 +1022,8 @@ bool Installer::removeWizardPageItem(Component *component, const QString &name) void Installer::setRemoteRepositories(const QList<Repository> &repositories) { - GetRepositoriesMetaInfoJob metaInfoJob(d->m_settings.publicKey(), isPackageManager()); + GetRepositoriesMetaInfoJob metaInfoJob(d->m_installerSettings->publicKey(), + (isPackageManager() || isUpdater())); metaInfoJob.setRepositories(repositories); // start... @@ -2314,11 +1040,11 @@ void Installer::setRemoteRepositories(const QList<Repository> &repositories) KDUpdater::Application &updaterApp = *d->m_app; const QStringList tempDirs = metaInfoJob.temporaryDirectories(); - d->tempDirDeleter.add(tempDirs); + d->m_tempDirDeleter->add(tempDirs); foreach (const QString &tmpDir, tempDirs) { if (tmpDir.isEmpty()) continue; - const QString &applicationName = d->m_settings.applicationName(); + const QString &applicationName = d->m_installerSettings->applicationName(); updaterApp.addUpdateSource(applicationName, applicationName, QString(), QUrl::fromLocalFile(tmpDir), 1); } @@ -2332,7 +1058,7 @@ void Installer::setRemoteRepositories(const QList<Repository> &repositories) // The changes done above by adding update source don't count as modification that // need to be saved cause they will be re-set on the next start anyway. This does // prevent creating of xml files not needed atm. We can still set the modified - // state later once real things changed that we like to restore at the next startup. + // state later once real things changed that we like to restore at the next startup. updaterApp.updateSourcesInfo()->setModified(false); // create the packages info @@ -2351,23 +1077,23 @@ void Installer::setRemoteRepositories(const QList<Repository> &repositories) */ void Installer::setTemporaryRepositories(const QList<Repository> &repositories, bool replace) { - d->m_settings.setTemporaryRepositories(repositories, replace); + d->m_installerSettings->setTemporaryRepositories(repositories, replace); } /*! - Defines if the downloader should try to download sha1 checksums for archives + checks if the downloader should try to download sha1 checksums for archives */ -void Installer::setTestChecksum(bool test) +bool Installer::testChecksum() const { - d->m_testChecksum = test; + return d->m_testChecksum; } /*! - checks if the downloader should try to download sha1 checksums for archives + Defines if the downloader should try to download sha1 checksums for archives */ -bool Installer::testChecksum() +void Installer::setTestChecksum(bool test) { - return d->m_testChecksum; + d->m_testChecksum = test; } /*! @@ -2378,6 +1104,8 @@ void Installer::createComponentsV2(const QList<KDUpdater::Update*> &updates, { verbose() << "entered create components V2 in installer" << std::endl; + QHash<QString, KDUpdater::PackageInfo> alreadyInstalledPackagesHash = localInstalledPackages(); + emit componentsAboutToBeCleared(); qDeleteAll(d->m_componentHash); @@ -2386,22 +1114,6 @@ void Installer::createComponentsV2(const QList<KDUpdater::Update*> &updates, d->m_componentHash.clear(); QStringList importantUpdates; - KDUpdater::Application &updaterApp = *d->m_app; - KDUpdater::PackagesInfo &packagesInfo = *updaterApp.packagesInfo(); - - if (isUninstaller() || isPackageManager()) { - //reads all installed components from components.xml - if (!setAndParseLocalComponentsFile(packagesInfo)) - return; - packagesInfo.setApplicationName(d->m_settings.applicationName()); - packagesInfo.setApplicationVersion(d->m_settings.applicationVersion()); - } - - QHash<QString, KDUpdater::PackageInfo> alreadyInstalledPackagesHash; - foreach (const KDUpdater::PackageInfo &info, packagesInfo.packageInfos()) { - alreadyInstalledPackagesHash.insert(info.name, info); - } - QStringList globalUnNeededList; QList<Component*> componentsToSelectInPackagemanager; foreach (KDUpdater::Update * const update, updates) { @@ -2422,9 +1134,10 @@ void Installer::createComponentsV2(const QList<KDUpdater::Update*> &updates, possibleInstalledNameList.append(replaceList); globalUnNeededList.append(replaceList); } - if (alreadyInstalledPackagesHash.contains(name)) { + + if (alreadyInstalledPackagesHash.contains(name)) possibleInstalledNameList.append(name); - } + foreach(const QString &possibleName, possibleInstalledNameList) { if (alreadyInstalledPackagesHash.contains(possibleName)) { if (!installedVersion.isEmpty()) { @@ -2438,9 +1151,13 @@ void Installer::createComponentsV2(const QList<KDUpdater::Update*> &updates, alreadyInstalledPackagesHash.remove(name); } - component->setLocalTempPath(QInstaller::pathFromUrl(update->sourceInfo().url)); - const Repository currentUsedRepository = metaInfoJob.repositoryForTemporaryDirectory( - component->localTempPath()); + const QString localPath = QInstaller::pathFromUrl(update->sourceInfo().url); + static QString lastLocalPath; + if (lastLocalPath != localPath) + verbose() << "Url is : " << localPath << std::endl; + lastLocalPath = localPath; + + const Repository currentUsedRepository = metaInfoJob.repositoryForTemporaryDirectory(localPath); component->setRepositoryUrl(currentUsedRepository.url()); // the package manager should preselect the currently installed packages @@ -2505,7 +1222,7 @@ void Installer::createComponentsV2(const QList<KDUpdater::Update*> &updates, // select all components in the package manager model foreach (QInstaller::Component* const i, componentsToSelectInPackagemanager) - i->setSelected(true, InstallerMode, Component::InitializeComponentTreeSelectMode); + i->setSelected(true, AllMode, Component::InitializeComponentTreeSelectMode); //signals for the qinstallermodel emit rootComponentsAdded(d->m_rootComponents); @@ -2533,11 +1250,11 @@ void Installer::createComponents(const QList<KDUpdater::Update*> &updates, KDUpdater::Application &updaterApp = *d->m_app; KDUpdater::PackagesInfo &packagesInfo = *updaterApp.packagesInfo(); - if (isUninstaller() || isPackageManager()) { + if (isUninstaller() || isPackageManager() || isUpdater()) { if (!setAndParseLocalComponentsFile(packagesInfo)) return; - packagesInfo.setApplicationName(d->m_settings.applicationName()); - packagesInfo.setApplicationVersion(d->m_settings.applicationVersion()); + packagesInfo.setApplicationName(d->m_installerSettings->applicationName()); + packagesInfo.setApplicationVersion(d->m_installerSettings->applicationVersion()); } bool containsImportantUpdates = false; @@ -2618,7 +1335,7 @@ void Installer::createComponents(const QList<KDUpdater::Update*> &updates, component->loadDataFromUpdate(update); component->setValue(QLatin1String("InstalledVersion"), installedVersion); const Repository currentUsedRepository = metaInfoJob.repositoryForTemporaryDirectory( - QInstaller::pathFromUrl(update->sourceInfo().url)); + QInstaller::pathFromUrl(update->sourceInfo().url)); component->setRepositoryUrl(currentUsedRepository.url()); bool isUpdate = true; @@ -2669,7 +1386,7 @@ void Installer::createComponents(const QList<KDUpdater::Update*> &updates, const QString script = update->data(QLatin1String("Script")).toString(); if (!script.isEmpty()) { scripts.insert(component.data(), QString::fromLatin1("%1/%2/%3").arg( - QInstaller::pathFromUrl(update->sourceInfo().url), newComponentName, script)); + QInstaller::pathFromUrl(update->sourceInfo().url), newComponentName, script)); } Component *tmpComponent = component.data(); @@ -2688,7 +1405,7 @@ void Installer::createComponents(const QList<KDUpdater::Update*> &updates, components.insert(newComponentName, component.data()); } - if (isPackageManager() && (isUpdate || newPackageForUpdater)) { + if ((isPackageManager() || isUpdater()) && (isUpdate || newPackageForUpdater)) { if (update->data(QLatin1String("Important")).toBool()) containsImportantUpdates = true; componentsToSelectUpdater.append(tmpComponent); @@ -2715,7 +1432,7 @@ void Installer::createComponents(const QList<KDUpdater::Update*> &updates, // now append all components to their respective parents QMap<QString, QInstaller::Component*>::const_iterator it; - for (it = components.begin(); !d->linearComponentList && it != components.end(); ++it) { + for (it = components.begin(); !d->m_linearComponentList && it != components.end(); ++it) { QInstaller::Component* const comp = *it; QString id = it.key(); if (globalUnNeededList.contains(id)) @@ -2735,8 +1452,11 @@ void Installer::createComponents(const QList<KDUpdater::Update*> &updates, d->willBeReplacedComponents.append(yeahComponent); continue; //we don't want to append the unneeded components } - if (d->linearComponentList || (*it)->parentComponent() == 0) - appendComponent(*it); + if (d->m_linearComponentList || (*it)->parentComponent() == 0) { + d->m_componentHash.insert((*it)->name(), *it); + // TODO: fix this (d->m_linearComponentList ? UpdaterMode : AllMode) + appendRootComponent(*it, d->m_linearComponentList ? UpdaterMode : AllMode); + } } // after everything is set up, load the scripts @@ -2755,60 +1475,59 @@ void Installer::createComponents(const QList<KDUpdater::Update*> &updates, i->setSelected(true, UpdaterMode, Component::InitializeComponentTreeSelectMode); // select all components in the package manager model - foreach (QInstaller::Component* const i, componentsToSelectInstaller) { - i->setSelected(true, InstallerMode, Component::InitializeComponentTreeSelectMode); - } + foreach (QInstaller::Component* const i, componentsToSelectInstaller) + i->setSelected(true, AllMode, Component::InitializeComponentTreeSelectMode); emit updaterComponentsAdded(d->m_packageManagerComponents); emit rootComponentsAdded(d->m_rootComponents); } -void Installer::appendComponent(Component *component) +/*! + Appends a new root components \a component based on the current run mode \a runMode to the + installers internal lists of components. +*/ +void Installer::appendRootComponent(Component *component, RunModes runMode) { - d->m_rootComponents.append(component); - d->m_componentHash[component->name()] = component; + if (runMode == AllMode) + d->m_rootComponents.append(component); + else + d->m_updaterComponents.append(component); emit componentAdded(component); } -int Installer::componentCount(RunModes runMode) const +/*! + Returns the number of components in the list depending on the run mode \a runMode. +*/ +int Installer::rootComponentCount(RunModes runMode) const { if (runMode == UpdaterMode) - return d->m_packageManagerComponents.size(); + return d->m_updaterComponents.size(); return d->m_rootComponents.size(); } -Component *Installer::component(int i, RunModes runMode) const +/*! + Returns the component at index position i in the components list. i must be a valid index + position in the list (i.e., 0 <= i < rootComponentCount(...)). +*/ +Component *Installer::rootComponent(int i, RunModes runMode) const { if (runMode == UpdaterMode) - return d->m_packageManagerComponents.at(i); - return d->m_rootComponents.at(i); -} - -Component *Installer::component(const QString &name) const -{ - return d->m_componentHash.contains(name) ? d->m_componentHash[name] : 0; + return d->m_updaterComponents.value(i, 0); + return d->m_rootComponents.value(i, 0); } QList<Component*> Installer::components(bool recursive, RunModes runMode) const { if (runMode == UpdaterMode) - return d->m_packageManagerComponents; + return d->m_updaterComponents; if (!recursive) return d->m_rootComponents; QList<Component*> result; - QList<Component*>::const_iterator it; - for (it = d->m_rootComponents.begin(); it != d->m_rootComponents.end(); ++it) { - result.push_back(*it); - result += (*it)->components(true); - } - - if (runMode == AllMode) { - for (it = d->m_updaterComponents.begin(); it != d->m_updaterComponents.end(); ++it) { - result.push_back(*it); - result += (*it)->components(false); - } + foreach (QInstaller::Component *component, d->m_rootComponents) { + result.push_back(component); + result += component->childComponents(true); } return result; @@ -2819,22 +1538,20 @@ QList<Component*> Installer::componentsToInstall(bool recursive, bool sort, RunM QList<Component*> availableComponents = components(recursive, runMode); if (sort) { std::sort(availableComponents.begin(), availableComponents.end(), - Component::PriorityLessThan()); + Component::InstallPriorityLessThan()); } - QList<Component*>::const_iterator it; QList<Component*> componentsToInstall; - for (it = availableComponents.begin(); it != availableComponents.end(); ++it) { - Component* const comp = *it; - if (!comp->isSelected(runMode)) + foreach (QInstaller::Component *component, availableComponents) { + if (!component->isSelected(runMode)) continue; // it was already installed before, so don't add it - if (comp->value(QLatin1String("PreviousState")) == QLatin1String("Installed") - && runMode == InstallerMode) // TODO: is the last condition right ???? + if (component->value(QLatin1String("PreviousState")) == QLatin1String("Installed") + && runMode == AllMode) // TODO: is the last condition right ???? continue; - appendComponentAndMissingDependencies(componentsToInstall, comp); + appendComponentAndMissingDependencies(componentsToInstall, component); } return componentsToInstall; @@ -2858,17 +1575,18 @@ static Component* subComponentByName(const Installer *installer, const QString & if (check != 0 && componentMatches(check, name, version)) return check; - const QList<Component*> comps = check == 0 ? installer->components() : check->components(); - for (QList<Component*>::const_iterator it = comps.begin(); it != comps.end(); ++it) { - Component* const result = subComponentByName(installer, name, version, *it); + const QList<Component*> rootComponents = + check == 0 ? installer->components(false, AllMode) : check->childComponents(); + foreach (QInstaller::Component* component, rootComponents) { + Component* const result = subComponentByName(installer, name, version, component); if (result != 0) return result; } - const QList<Component*> uocomps = - check == 0 ? installer->components(false, UpdaterMode) : check->components(false, UpdaterMode); - for (QList<Component*>::const_iterator it = uocomps.begin(); it != uocomps.end(); ++it) { - Component* const result = subComponentByName(installer, name, version, *it); + const QList<Component*> updaterComponents = check == 0 + ? installer->components(false, UpdaterMode) : check->childComponents(false, UpdaterMode); + foreach (QInstaller::Component* component, updaterComponents) { + Component* const result = subComponentByName(installer, name, version, component); if (result != 0) return result; } @@ -2876,14 +1594,14 @@ static Component* subComponentByName(const Installer *installer, const QString & return 0; } -void Installer::setLinearComponentList(bool showlinear) +bool Installer::hasLinearComponentList() const { - d->linearComponentList = showlinear; + return d->m_linearComponentList; } -bool Installer::hasLinearComponentList() const +void Installer::setLinearComponentList(bool showlinear) { - return d->linearComponentList; + d->m_linearComponentList = showlinear; } /*! @@ -2900,13 +1618,6 @@ Component* Installer::componentByName(const QString &name) const return subComponentByName(this, name.section(QLatin1Char('-'), 0, 0), version); } - QHash< QString, QInstaller::Component* >::ConstIterator it = d->m_componentHash.constFind(name); - Component * comp = 0; - if (it != d->m_componentHash.constEnd()) - comp = *it; - if (d->m_updaterComponents.contains(comp)) - return comp; - return subComponentByName(this, name); } @@ -2939,7 +1650,7 @@ QList<Component*> Installer::dependees(const Component *component) const InstallerSettings Installer::settings() const { - return d->m_settings; + return *d->m_installerSettings; } /*! @@ -2980,7 +1691,7 @@ QList<Component*> Installer::missingDependencies(const Component *component) con const QString name = containsVersionString ? it->section(dash, 0, 0) : *it; bool installed = false; - const QList<Component*> compList = components(true); + QList<Component*> compList = components(true, AllMode); foreach (const Component* comp, compList) { if (!name.isEmpty() && comp->name() == name && !version.isEmpty()) { if (Installer::versionMatches(comp->value(QLatin1String("InstalledVersion")), version)) @@ -2990,7 +1701,8 @@ QList<Component*> Installer::missingDependencies(const Component *component) con } } - foreach (const Component *comp, d->m_updaterComponents) { + compList = components(true, UpdaterMode); + foreach (const Component *comp, d->m_updaterComponents) { if (!name.isEmpty() && comp->name() == name && !version.isEmpty()) { if (Installer::versionMatches(comp->value(QLatin1String("InstalledVersion")), version)) installed = true; @@ -3015,8 +1727,8 @@ bool Installer::gainAdminRights() if (AdminAuthorization::hasAdminRights()) return true; - d->engineClientHandler->setActive(true); - if (!d->engineClientHandler->isActive()) + d->m_FSEngineClientHandler->setActive(true); + if (!d->m_FSEngineClientHandler->isActive()) throw Error(QObject::tr("Error while elevating access rights.")); return true; } @@ -3026,32 +1738,16 @@ bool Installer::gainAdminRights() */ void Installer::dropAdminRights() { - d->engineClientHandler->setActive(false); + d->m_FSEngineClientHandler->setActive(false); } /*! - Return true, if a process with \a name is running. On Windows, the comparision is case-insensitive. + Return true, if a process with \a name is running. On Windows, the comparision + is case-insensitive. */ bool Installer::isProcessRunning(const QString &name) const { - QList<KDSysInfo::ProcessInfo>::const_iterator it; - const QList<KDSysInfo::ProcessInfo> processes = KDSysInfo::runningProcesses(); - for (it = processes.begin(); it != processes.end(); ++it) { -#ifndef Q_WS_WIN - if (it->name == name) - return true; - const QFileInfo fi(it->name); - if (fi.fileName() == name || fi.baseName() == name) - return true; -#else - if (it->name.toLower() == name.toLower()) - return true; - const QFileInfo fi(it->name); - if (fi.fileName().toLower() == name.toLower() || fi.baseName().toLower() == name.toLower()) - return true; -#endif - } - return false; + return InstallerPrivate::isProcessRunning(name, KDSysInfo::runningProcesses()); } /*! @@ -3116,8 +1812,8 @@ bool Installer::performOperation(const QString &name, const QStringList &argumen op->setArguments(arguments); op->backup(); - if (!performOperationThreaded(op.data())) { - performOperationThreaded(op.data(), Undo); + if (!InstallerPrivate::performOperationThreaded(op.data())) { + InstallerPrivate::performOperationThreaded(op.data(), InstallerPrivate::Undo); return false; } return true; @@ -3161,26 +1857,18 @@ QString Installer::findLibrary(const QString &name, const QStringList &pathes) QStringList findPathes = pathes; #if defined(Q_WS_WIN) return findPath(QString::fromLatin1("%1.lib").arg(name), findPathes); -#elif defined(Q_WS_MAC) +#else if (findPathes.isEmpty()) { findPathes.push_back(QLatin1String("/lib")); findPathes.push_back(QLatin1String("/usr/lib")); findPathes.push_back(QLatin1String("/usr/local/lib")); findPathes.push_back(QLatin1String("/opt/local/lib")); } - +#if defined(Q_WS_MAC) const QString dynamic = findPath(QString::fromLatin1("lib%1.dylib").arg(name), findPathes); - if (!dynamic.isEmpty()) - return dynamic; - return findPath(QString::fromLatin1("lib%1.a").arg(name), findPathes); #else - if (findPathes.isEmpty()) { - findPathes.push_back(QLatin1String("/lib")); - findPathes.push_back(QLatin1String("/usr/lib")); - findPathes.push_back(QLatin1String("/usr/local/lib")); - findPathes.push_back(QLatin1String("/opt/local/lib")); - } const QString dynamic = findPath(QString::fromLatin1("lib%1.so*").arg(name), findPathes); +#endif if (!dynamic.isEmpty()) return dynamic; return findPath(QString::fromLatin1("lib%1.a").arg(name), findPathes); @@ -3213,7 +1901,7 @@ QString Installer::findPath(const QString &name, const QStringList &pathes) void Installer::setInstallerBaseBinary(const QString &path) { d->m_forceRestart = true; - d->installerBaseBinaryUnreplaced = path; + d->m_installerBaseBinaryUnreplaced = path; } /*! @@ -3236,8 +1924,7 @@ QString Installer::value(const QString &key, const QString &defaultValue) const const QString dir = d->m_vars.value(key, defaultValue); if (dir.startsWith(QLatin1String("~/"))) return QDir::home().absoluteFilePath(dir.mid(2)); - else - return dir; + return dir; } #endif return d->m_vars.value(key, defaultValue); @@ -3283,9 +1970,9 @@ void Installer::setVerbose(bool on) QInstaller::setVerbose(on); } -int Installer::status() const +Installer::Status Installer::status() const { - return d->m_status; + return Installer::Status(d->m_status); } /*! returns true if at least one complete installation/update @@ -3294,19 +1981,19 @@ int Installer::status() const */ bool Installer::finishedWithSuccess() const { - return (d->m_status == InstallerSucceeded) || d->m_needToWriteUninstaller; + return (d->m_status == Installer::Success) || d->m_needToWriteUninstaller; } void Installer::interrupt() { verbose() << "INTERRUPT INSTALLER" << std::endl; - d->setStatus(InstallerCanceledByUser); + d->setStatus(Installer::Canceled); emit installationInterrupted(); } void Installer::setCanceled() { - d->setStatus(InstallerCanceledByUser); + d->setStatus(Installer::Canceled); } /*! @@ -3359,43 +2046,52 @@ bool Installer::isInstaller() const } /*! - Returns true when this is the uninstaller running. + Returns true if this is an offline-only installer. */ -bool Installer::isUninstaller() const +bool Installer::isOfflineOnly() const { - return d->isUninstaller(); + QSettings confInternal(QLatin1String(":/config/config-internal.ini"), QSettings::IniFormat); + return confInternal.value(QLatin1String("offlineOnly")).toBool(); +} + +void Installer::setUninstaller() +{ + d->m_magicBinaryMarker = QInstaller::MagicUninstallerMarker; } /*! - Returns true when this is the package manager running. + Returns true when this is the uninstaller running. */ -bool Installer::isPackageManager() const +bool Installer::isUninstaller() const { - return d->isPackageManager(); + return d->isUninstaller(); } +void Installer::setUpdater() +{ + d->m_magicBinaryMarker = QInstaller::MagicUpdaterMarker; +} /*! - Returns true if this is an offline-only installer. + Returns true when this is neither an installer nor an uninstaller running. + Must be an updater, then. */ -bool Installer::isOfflineOnly() const +bool Installer::isUpdater() const { - QSettings confInternal(QLatin1String(":/config/config-internal.ini"), QSettings::IniFormat); - return confInternal.value(QLatin1String("offlineOnly")).toBool(); + return d->isUpdater(); } void Installer::setPackageManager() { - d->packageManagingMode = true; + d->m_magicBinaryMarker = QInstaller::MagicPackageManagerMarker; } /*! - Returns thrue when this is neither an installer nor an uninstaller running. - Must be an updater, then. + Returns true when this is the package manager running. */ -bool Installer::isUpdater() const +bool Installer::isPackageManager() const { - return !d->isInstaller() && !d->isUninstaller(); + return d->isPackageManager(); } /*! @@ -3443,7 +2139,7 @@ bool Installer::runPackageUpdater() */ void Installer::languageChanged() { - const QList<Component*> comps = components(true); + const QList<Component*> comps = components(true, runMode()); foreach (Component* component, comps) component->languageChanged(); } @@ -3488,7 +2184,7 @@ bool Installer::setAndParseLocalComponentsFile(KDUpdater::PackagesInfo &packages --silentRetries; } else { Status status = handleComponentsFileSetOrParseError(localComponentsXml); - if (status == InstallerCanceledByUser) + if (status == Installer::Canceled) return false; } packagesInfo.setFileName(localComponentsXml); @@ -3500,7 +2196,7 @@ bool Installer::setAndParseLocalComponentsFile(KDUpdater::PackagesInfo &packages --silentRetries; } else { Status status = handleComponentsFileSetOrParseError(localComponentsXml); - if (status == InstallerCanceledByUser) + if (status == Installer::Canceled) return false; } packagesInfo.setFileName(localComponentsXml); @@ -3518,7 +2214,7 @@ bool Installer::setAndParseLocalComponentsFile(KDUpdater::PackagesInfo &packages } Status status = handleComponentsFileSetOrParseError(componentFileInfo.fileName(), packagesInfo.errorString(), retry); - if (status == InstallerCanceledByUser) + if (status == Installer::Canceled) return false; } packagesInfo.setFileName(localComponentsXml); @@ -3541,10 +2237,8 @@ Installer::Status Installer::handleComponentsFileSetOrParseError(const QString & buttons); if (button == QMessageBox::Cancel) { - d->m_status = InstallerFailed; - return InstallerCanceledByUser; + d->m_status = Installer::Failure; + return Installer::Canceled; } - return InstallerUnfinished; + return Installer::Unfinished; } - -#include "qinstaller.moc" diff --git a/installerbuilder/libinstaller/qinstaller.h b/installerbuilder/libinstaller/qinstaller.h index 85820b4a3..3a2a56502 100644 --- a/installerbuilder/libinstaller/qinstaller.h +++ b/installerbuilder/libinstaller/qinstaller.h @@ -26,6 +26,11 @@ #ifndef QINSTALLER_H #define QINSTALLER_H +#include "common/repository.h" +#include "qinstallerglobal.h" + +#include <KDUpdater/KDUpdater> + #include <QtCore/QAbstractItemModel> #include <QtCore/QObject> #include <QtCore/QStringList> @@ -37,10 +42,6 @@ #include <QtScript/QScriptable> #include <QtScript/QScriptValue> -#include "common/repository.h" - -#include "installer_global.h" - namespace KDUpdater { class Application; class PackagesInfo; @@ -48,9 +49,11 @@ namespace KDUpdater { class UpdateOperation; } +QT_BEGIN_NAMESPACE class QDir; class QFile; class QIODevice; +QT_END_NAMESPACE class KDJob; @@ -63,6 +66,7 @@ namespace QInstaller { class Component; class GetRepositoriesMetaInfoJob; +class InstallerPrivate; class InstallerSettings; class MessageBoxHandler; @@ -70,8 +74,8 @@ class INSTALLER_EXPORT Installer : public QObject { Q_OBJECT - Q_PROPERTY(int status READ status NOTIFY statusChanged) Q_ENUMS(Status WizardPage) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) public: explicit Installer(qint64 magicmaker = 0, @@ -79,9 +83,16 @@ public: = QVector< KDUpdater::UpdateOperation*>()); ~Installer(); - void writeUninstaller(); + QHash<QString, KDUpdater::PackageInfo> localInstalledPackages(); + GetRepositoriesMetaInfoJob* fetchMetaInformation(const InstallerSettings &settings); + bool addUpdateResourcesFrom(GetRepositoriesMetaInfoJob *metaInfoJob, const InstallerSettings &settings, + bool parseChecksum); + + bool fetchAllPackages(); + bool fetchUpdaterPackages(); bool run(); + RunModes runMode() const; void reset(const QHash<QString, QString> ¶ms); Q_INVOKABLE QList<QVariant> execute(const QString &program, @@ -103,19 +114,19 @@ public: Q_INVOKABLE bool containsValue(const QString &key) const; //a way to have global flags share able from a component script to another one - Q_INVOKABLE void setSharedFlag(const QString &key, bool value = true); Q_INVOKABLE bool sharedFlag(const QString &key) const; + Q_INVOKABLE void setSharedFlag(const QString &key, bool value = true); QString replaceVariables(const QString &str) const; - QStringList replaceVariables(const QStringList &str) const; QByteArray replaceVariables(const QByteArray &str) const; - QString installerBinaryPath() const; - QString uninstallerName() const; + QStringList replaceVariables(const QStringList &str) const; - bool isRemoteRepositoryMetaInfoRetrieved() const; + void writeUninstaller(); + QString uninstallerName() const; + QString installerBinaryPath() const; + bool testChecksum() const; void setTestChecksum(bool test); - bool testChecksum(); KDUpdater::Application &updaterApplication() const; void setUpdaterApplication(KDUpdater::Application *app); @@ -136,13 +147,13 @@ public: public: // component handling - void appendComponent(Component *components); - int componentCount(RunModes runMode = InstallerMode) const; - Component *component(int i, RunModes runMode = InstallerMode) const; - Component *component(const QString &name) const; - QList<Component*> components(bool recursive = false, RunModes runMode = InstallerMode) const; + int rootComponentCount(RunModes runMode = AllMode) const; + void appendRootComponent(Component *components, RunModes runMode = AllMode); + Component *rootComponent(int i, RunModes runMode = AllMode) const; + + QList<Component*> components(bool recursive = false, RunModes runMode = AllMode) const; QList<Component*> componentsToInstall(bool recursive = false, bool sort = true, - RunModes runMode = InstallerMode) const; + RunModes runMode = AllMode) const; Component *componentByName(const QString &identifier) const; QList<Component*> dependencies(const Component *component, @@ -152,12 +163,16 @@ public: // convenience Q_INVOKABLE bool isInstaller() const; + Q_INVOKABLE bool isOfflineOnly() const; + + Q_INVOKABLE void setUninstaller(); Q_INVOKABLE bool isUninstaller() const; + + Q_INVOKABLE void setUpdater(); Q_INVOKABLE bool isUpdater() const; - Q_INVOKABLE bool isPackageManager() const; - Q_INVOKABLE bool isOfflineOnly() const; - void setPackageManager(); + Q_INVOKABLE void setPackageManager(); + Q_INVOKABLE bool isPackageManager() const; bool isVerbose() const; void setVerbose(bool on); @@ -174,13 +189,13 @@ public: // status enum Status { - InstallerUnfinished, - InstallerCanceledByUser, - InstallerRunning, - InstallerFailed, - InstallerSucceeded, + Success = EXIT_SUCCESS, + Failure = EXIT_FAILURE, + Running, + Canceled, + Unfinished }; - int status() const; + Status status() const; enum WizardPage { Introduction = 0x1000, @@ -204,14 +219,14 @@ public: void rollBackInstallation(); int downloadNeededArchives(RunModes runMode, double partProgressSize/* = double(1)/3 */); - QList<Component*> calculateComponentOrder(RunModes runMode = InstallerMode) const; + QList<Component*> calculateComponentOrder(RunModes runMode = AllMode) const; void installComponent(Component *comp, double progressOperationSize); - void setLinearComponentList(bool showlinear); bool hasLinearComponentList() const; + void setLinearComponentList(bool showlinear); - bool finishedWithSuccess() const; bool needsRestart() const; + bool finishedWithSuccess() const; public Q_SLOTS: bool runInstaller(); @@ -233,6 +248,14 @@ Q_SIGNALS: void currentPageChanged(int page); void finishButtonClicked(); + void cancelMetaInfoJob(); + void metaJobInfoMessage(KDJob* job, const QString &message); + + void startAllComponentsReset(); + void finishAllComponentsReset(); + + void startUpdaterComponentsReset(); + void finishUpdaterComponentsReset(); void installationStarted(); void installationInterrupted(); @@ -256,9 +279,8 @@ private: const QString &arg2 = QString(), bool withRetry = true); private: - class Private; - Private* const d; - friend class Component; + InstallerPrivate* const d; + friend class InstallerPrivate; }; } diff --git a/installerbuilder/libinstaller/qinstaller_p.cpp b/installerbuilder/libinstaller/qinstaller_p.cpp new file mode 100644 index 000000000..d4ef12496 --- /dev/null +++ b/installerbuilder/libinstaller/qinstaller_p.cpp @@ -0,0 +1,1511 @@ +/************************************************************************** +** +** This file is part of Qt SDK** +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).* +** +** Contact: Nokia Corporation qt-info@nokia.com** +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception version +** 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you are unsure which license is appropriate for your use, please contact +** (qt-info@nokia.com). +** +**************************************************************************/ +#include "qinstaller_p.h" + +#include "adminauthorization.h" +#include "common/binaryformat.h" +#include "common/errors.h" +#include "common/fileutils.h" +#include "common/installersettings.h" +#include "common/utils.h" +#include "fsengineclient.h" +#include "messageboxhandler.h" +#include "progresscoordinator.h" +#include "qinstaller.h" +#include "qinstallercomponent.h" + +#include <KDToolsCore/KDSaveFile> +#include <KDToolsCore/KDSelfRestarter> + +#include <KDUpdater/KDUpdater> + +#include <QtCore/QtConcurrentRun> +#include <QtCore/QCoreApplication> +#include <QtCore/QDir> +#include <QtCore/QDirIterator> +#include <QtCore/QFuture> +#include <QtCore/QFutureWatcher> +#include <QtCore/QTemporaryFile> + +#include <errno.h> + +namespace QInstaller { + +static bool runOperation(KDUpdater::UpdateOperation *op, InstallerPrivate::OperationType type) +{ + switch (type) { + case InstallerPrivate::Backup: + op->backup(); + return true; + case InstallerPrivate::Perform: + return op->performOperation(); + case InstallerPrivate::Undo: + return op->undoOperation(); + default: + Q_ASSERT(!"unexpected operation type"); + } + return false; +} + +template <typename T> +void letTheUiRunTillFinished(const QFuture<T>& f) +{ + QFutureWatcher<T> futureWatcher; + + QEventLoop loop; + loop.connect(&futureWatcher, SIGNAL(finished()), SLOT(quit()), Qt::QueuedConnection); + futureWatcher.setFuture(f); + + if (!f.isFinished()) + loop.exec(); +} + +/*! + \internal + Initializes the created FSEngineClientHandler instance \a handler. +*/ +static void initEngineHandler(/*QInstaller::*/FSEngineClientHandler *handler) +{ +#ifdef FSENGINE_TCP + const int port = 30000 + qrand() % 1000; + handler->init(port); + handler->setStartServerCommand(QCoreApplication::applicationFilePath(), QStringList() + << QLatin1String("--startserver") << QString::number(port) << handler->authorizationKey(), + true); +#else + const QString name = QInstaller::generateTemporaryFileName(); + handler->init(name); + handler->setStartServerCommand(qApp->applicationFilePath(), QStringList() + << QLatin1String("--startserver") << name << handler->authorizationKey(), true); +#endif +} + +/*! + \internal + Creates and initializes a FSEngineClientHandler -> makes us get admin rights for QFile operations +*/ +static /*QInstaller::*/FSEngineClientHandler* createEngineClientHandler() +{ + static FSEngineClientHandler* clientHandlerInstance = 0; + if (clientHandlerInstance == 0) { + clientHandlerInstance = new FSEngineClientHandler; + initEngineHandler(clientHandlerInstance); + } + return clientHandlerInstance; +} + +static QStringList checkRunningProcessesFromList(const QStringList &processList) +{ + const QList<KDSysInfo::ProcessInfo> allProcesses = KDSysInfo::runningProcesses(); + QStringList stillRunningProcesses; + foreach (const QString &process, processList) { + if (!process.isEmpty() && InstallerPrivate::isProcessRunning(process, allProcesses)) + stillRunningProcesses.append(process); + } + return stillRunningProcesses; +} + +#ifdef Q_WS_WIN +static void deferredRename(const QString &oldName, const QString &newName, bool restart = false) +{ + QString batchfile; + + QStringList arguments; + arguments << QDir::toNativeSeparators(batchfile) << QDir::toNativeSeparators(oldName) + << QDir::toNativeSeparators(QFileInfo(oldName).dir().absoluteFilePath(newName)); + + { + QTemporaryFile f(QDir::temp().absoluteFilePath(QLatin1String("deferredrenameXXXXXX.vbs"))); + openForWrite(&f, f.fileName()); + f.setAutoRemove(false); + + batchfile = f.fileName(); + + QTextStream batch(&f); + batch << "Set fso = WScript.CreateObject(\"Scripting.FileSystemObject\")\n"; + batch << "Set tmp = WScript.CreateObject(\"WScript.Shell\")\n"; + batch << QString::fromLatin1("file = \"%1\"\n").arg(arguments[2]); + batch << "on error resume next\n"; + + batch << "while fso.FileExists(file)\n"; + batch << " fso.DeleteFile(file)\n"; + batch << " WScript.Sleep(1000)\n"; + batch << "wend\n"; + batch << QString::fromLatin1("fso.MoveFile \"%1\", file\n").arg(arguments[1]); + if (restart) + batch << QString::fromLatin1("tmp.exec \"%1 --updater\"\n").arg(arguments[2]); + batch << "fso.DeleteFile(WScript.ScriptFullName)\n"; + } + + QProcess::startDetached(QLatin1String("cscript"), QStringList() << QLatin1String("//Nologo") + << QDir::toNativeSeparators(batchfile)); +} +#endif // Q_WS_WIN + + +// -- InstallerPrivate + + +InstallerPrivate::InstallerPrivate(Installer *installer, qint64 magicInstallerMaker, + const QVector<KDUpdater::UpdateOperation*> &performedOperations) + : m_app(0) + , m_tempDirDeleter(new TempDirDeleter()) + , m_installerSettings(0) + , m_FSEngineClientHandler(createEngineClientHandler()) + , m_status(Installer::Unfinished) + , m_forceRestart(false) + , m_silentRetries(3) + , m_testChecksum(false) + , m_launchedAsRoot(AdminAuthorization::hasAdminRights()) + , m_completeUninstall(false) + , m_packageManagingMode(false) + , m_linearComponentList(false) + , m_needToWriteUninstaller(false) + , m_performedOperationsOld(performedOperations) + , q(installer) + , m_magicBinaryMarker(magicInstallerMaker) +{ + connect(this, SIGNAL(installationStarted()), q, SIGNAL(installationStarted())); + connect(this, SIGNAL(installationFinished()), q, SIGNAL(installationFinished())); + connect(this, SIGNAL(uninstallationStarted()), q, SIGNAL(uninstallationStarted())); + connect(this, SIGNAL(uninstallationFinished()), q, SIGNAL(uninstallationFinished())); +} + +InstallerPrivate::~InstallerPrivate() +{ + qDeleteAll(m_rootComponents); + qDeleteAll(m_updaterComponents); + qDeleteAll(m_performedOperationsOld); + qDeleteAll(m_performedOperationsCurrentSession); + + delete m_tempDirDeleter; + delete m_installerSettings; + delete m_FSEngineClientHandler; +} + +/*! + Return true, if a process with \a name is running. On Windows, comparision is case-insensitive. +*/ +/* static */ +bool InstallerPrivate::isProcessRunning(const QString &name, + const QList<KDSysInfo::ProcessInfo> &processes) +{ + QList<KDSysInfo::ProcessInfo>::const_iterator it; + for (it = processes.constBegin(); it != processes.constEnd(); ++it) { + if (it->name.isEmpty()) + continue; + +#ifndef Q_WS_WIN + if (it->name == name) + return true; + const QFileInfo fi(it->name); + if (fi.fileName() == name || fi.baseName() == name) + return true; +#else + if (it->name.toLower() == name.toLower()) + return true; + if (it->name.toLower() == QDir::toNativeSeparators(name.toLower())) + return true; + const QFileInfo fi(it->name); + if (fi.fileName().toLower() == name.toLower() || fi.baseName().toLower() == name.toLower()) + return true; +#endif + } + return false; +} + +/* static */ +bool InstallerPrivate::performOperationThreaded(KDUpdater::UpdateOperation *op, + InstallerPrivate::OperationType type) +{ + QFuture<bool> future = QtConcurrent::run(runOperation, op, type); + letTheUiRunTillFinished(future); + return future.result(); +} + +QString InstallerPrivate::targetDir() const +{ + return q->value(QLatin1String("TargetDir")); +} + +QString InstallerPrivate::configurationFileName() const +{ + return q->value(QLatin1String("TargetConfigurationFile"), QString::fromLatin1("components.xml")); +} + +QString InstallerPrivate::componentsXmlPath() const +{ + return QDir::toNativeSeparators(QDir(QDir::cleanPath(targetDir())) + .absoluteFilePath(configurationFileName())); +} + +QString InstallerPrivate::localComponentsXmlPath() const +{ + const QString &appDirPath = QCoreApplication::applicationDirPath(); + if (QFileInfo(appDirPath + QLatin1String("/../..")).isBundle()) { + return QDir::toNativeSeparators(QFileInfo(QDir::cleanPath(appDirPath + + QLatin1String("/../../../") + configurationFileName())).absoluteFilePath()); + } + return componentsXmlPath(); +} + +void InstallerPrivate::initialize() +{ + try { + m_installerSettings = new InstallerSettings(InstallerSettings::fromFileAndPrefix( + QLatin1String(":/metadata/installer-config/config.xml"), + QLatin1String(":/metadata/installer-config/"))); + } catch (const Error &e) { + qCritical("Could not parse Config: %s", qPrintable(e.message())); + //TODO try better error handling + return; + } + + // first set some common variables that may used e.g. as placeholder + // in some of the settings variables or in a script or... + m_vars.insert(QLatin1String("rootDir"), QDir::rootPath()); + m_vars.insert(QLatin1String("homeDir"), QDir::homePath()); + +#ifdef Q_WS_WIN + m_vars.insert(QLatin1String("os"), QLatin1String("win")); +#elif defined(Q_WS_MAC) + m_vars.insert(QLatin1String("os"), QLatin1String("mac")); +#elif defined(Q_WS_X11) + m_vars.insert(QLatin1String("os"), QLatin1String("x11")); +#elif defined(Q_WS_QWS) + m_vars.insert(QLatin1String("os"), QLatin1String("Qtopia")); +#else + //TODO add more platforms as needed... +#endif + + // fill the variables defined in the settings + m_vars.insert(QLatin1String("ProductName"), m_installerSettings->applicationName()); + m_vars.insert(QLatin1String("ProductVersion"), m_installerSettings->applicationVersion()); + m_vars.insert(QLatin1String("Title"), m_installerSettings->title()); + m_vars.insert(QLatin1String("MaintenanceTitle"), m_installerSettings->maintenanceTitle()); + m_vars.insert(QLatin1String("Publisher"), m_installerSettings->publisher()); + m_vars.insert(QLatin1String("Url"), m_installerSettings->url()); + m_vars.insert(QLatin1String("StartMenuDir"), m_installerSettings->startMenuDir()); + + m_vars.insert(QLatin1String("TargetConfigurationFile"), m_installerSettings->configurationFileName()); + m_vars.insert(QLatin1String("LogoPixmap"), m_installerSettings->logo()); + m_vars.insert(QLatin1String("LogoSmallPixmap"), m_installerSettings->logoSmall()); + m_vars.insert(QLatin1String("WatermarkPixmap"), m_installerSettings->watermark()); + + m_vars.insert(QLatin1String("RunProgram"), replaceVariables(m_installerSettings->runProgram())); + const QString desc = m_installerSettings->runProgramDescription(); + if (!desc.isEmpty()) + m_vars.insert(QLatin1String("RunProgramDescription"), desc); +#ifdef Q_WS_X11 + if (m_launchedAsRoot) + m_vars.insert(QLatin1String("TargetDir"), replaceVariables(m_installerSettings->adminTargetDir())); + else +#endif + m_vars.insert(QLatin1String("TargetDir"), replaceVariables(m_installerSettings->targetDir())); + m_vars.insert(QLatin1String("RemoveTargetDir"), replaceVariables(m_installerSettings->removeTargetDir())); + + QSettings creatorSettings(QSettings::IniFormat, QSettings::UserScope, QLatin1String("Nokia"), + QLatin1String("QtCreator")); + QFileInfo info(creatorSettings.fileName()); + if (info.exists()) + m_vars.insert(QLatin1String("QtCreatorSettingsFile"), info.absoluteFilePath()); + + if (!q->isInstaller()) { +#ifdef Q_WS_MAC + readUninstallerIniFile(QCoreApplication::applicationDirPath() + QLatin1String("/../../..")); +#else + readUninstallerIniFile(QCoreApplication::applicationDirPath()); +#endif + } + + connect(this, SIGNAL(installationStarted()), ProgressCoordninator::instance(), SLOT(reset())); + connect(this, SIGNAL(uninstallationStarted()), ProgressCoordninator::instance(), SLOT(reset())); +} + +QString InstallerPrivate::installerBinaryPath() const +{ + return qApp->applicationFilePath(); +} + +bool InstallerPrivate::isInstaller() const +{ + return m_magicBinaryMarker == MagicInstallerMarker; +} + +bool InstallerPrivate::isUninstaller() const +{ + return m_magicBinaryMarker == MagicUninstallerMarker; +} + +bool InstallerPrivate::isUpdater() const +{ + return m_magicBinaryMarker == MagicUpdaterMarker; +} + +bool InstallerPrivate::isPackageManager() const +{ + return m_magicBinaryMarker == MagicPackageManagerMarker; +} + +bool InstallerPrivate::statusCanceledOrFailed() const +{ + return m_status == Installer::Canceled + || m_status == Installer::Failure; +} + +void InstallerPrivate::setStatus(int status) +{ + if (m_status != status) { + m_status = status; + emit q->statusChanged(Installer::Status(m_status)); + } +} + +QString InstallerPrivate::replaceVariables(const QString &str) const +{ + static const QChar at = QLatin1Char('@'); + QString res; + int pos = 0; + while (true) { + const int pos1 = str.indexOf(at, pos); + if (pos1 == -1) + break; + const int pos2 = str.indexOf(at, pos1 + 1); + if (pos2 == -1) + break; + res += str.mid(pos, pos1 - pos); + const QString name = str.mid(pos1 + 1, pos2 - pos1 - 1); + res += q->value(name); + pos = pos2 + 1; + } + res += str.mid(pos); + return res; +} + +QByteArray InstallerPrivate::replaceVariables(const QByteArray &ba) const +{ + static const QChar at = QLatin1Char('@'); + QByteArray res; + int pos = 0; + while (true) { + const int pos1 = ba.indexOf(at, pos); + if (pos1 == -1) + break; + const int pos2 = ba.indexOf(at, pos1 + 1); + if (pos2 == -1) + break; + res += ba.mid(pos, pos1 - pos); + const QString name = QString::fromLocal8Bit(ba.mid(pos1 + 1, pos2 - pos1 - 1)); + res += q->value(name).toLocal8Bit(); + pos = pos2 + 1; + } + res += ba.mid(pos); + return res; +} + +/*! + Creates an update operation owned by the installer, not by any component. + \internal + */ +KDUpdater::UpdateOperation* InstallerPrivate::createOwnedOperation(const QString &type) +{ + KDUpdater::UpdateOperation* const op = KDUpdater::UpdateOperationFactory::instance().create(type); + ownedOperations.push_back(op); + return op; +} + +QString InstallerPrivate::uninstallerName() const +{ + QString filename = m_installerSettings->uninstallerName(); +#if defined(Q_WS_MAC) + if (QFileInfo(QCoreApplication::applicationDirPath() + QLatin1String("/../..")).isBundle()) + filename += QLatin1String(".app/Contents/MacOS/") + filename; +#elif defined(Q_OS_WIN) + filename += QLatin1String(".exe"); +#endif + return QString::fromLatin1("%1/%2").arg(targetDir()).arg(filename); +} + +void InstallerPrivate::readUninstallerIniFile(const QString &targetDir) +{ + const QString iniPath = targetDir + QLatin1Char('/') + m_installerSettings->uninstallerIniFile(); + QSettings cfg(iniPath, QSettings::IniFormat); + const QVariantHash vars = cfg.value(QLatin1String("Variables")).toHash(); + QHash<QString, QVariant>::ConstIterator it = vars.constBegin(); + while (it != vars.constEnd()) { + m_vars.insert(it.key(), it.value().toString()); + ++it; + } +} + +void InstallerPrivate::stopProcessesForUpdates(const QList<Component*> &components) +{ + QStringList processList; + foreach (const Component* const i, components) + processList << q->replaceVariables(i->stopProcessForUpdateRequests()); + + qSort(processList); + processList.erase(std::unique(processList.begin(), processList.end()), processList.end()); + if (processList.isEmpty()) + return; + + while (true) { + const QList<KDSysInfo::ProcessInfo> allProcesses = KDSysInfo::runningProcesses(); + const QStringList processes = checkRunningProcessesFromList(processList); + if (processes.isEmpty()) + return; + + const QMessageBox::StandardButton button = + MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("stopProcessesForUpdates"), tr("Stop Processes"), tr("These processes " + "should be stopped to continue:\n\n%1").arg(QDir::toNativeSeparators(processes + .join(QLatin1String("\n")))), QMessageBox::Retry | QMessageBox::Ignore + | QMessageBox::Cancel, QMessageBox::Retry); + if (button == QMessageBox::Ignore) + return; + if (button == QMessageBox::Cancel) { + q->setCanceled(); + throw Error(tr("Installation canceled by user")); + } + } +} + +int InstallerPrivate::countProgressOperations(const QList<KDUpdater::UpdateOperation*> &operations) +{ + int operationCount = 0; + QList<KDUpdater::UpdateOperation*>::const_iterator oIt; + for (oIt = operations.constBegin(); oIt != operations.constEnd(); oIt++) { + KDUpdater::UpdateOperation* const operation = *oIt; + QObject* const operationObject = dynamic_cast< QObject* >(operation); + if (operationObject != 0) { + const QMetaObject* const mo = operationObject->metaObject(); + if (mo->indexOfSignal(QMetaObject::normalizedSignature("progressChanged(double)")) > -1) + operationCount++; + } + } + return operationCount; +} + +int InstallerPrivate::countProgressOperations(const QList<Component*> &components) +{ + int operationCount = 0; + for (QList<Component*>::const_iterator It = components.begin(); It != components.end(); ++It) + operationCount = operationCount + countProgressOperations((*It)->operations()); + + return operationCount; +} + +void InstallerPrivate::connectOperationToInstaller(KDUpdater::UpdateOperation* const operation, + double progressOperationPartSize) +{ + Q_ASSERT(progressOperationPartSize); + QObject* const operationObject = dynamic_cast< QObject* >(operation); + if (operationObject != 0) { + const QMetaObject* const mo = operationObject->metaObject(); + if (mo->indexOfSignal(QMetaObject::normalizedSignature("outputTextChanged(QString)")) > -1) { + connect(operationObject, SIGNAL(outputTextChanged(QString)), + ProgressCoordninator::instance(), SLOT(emitDetailTextChanged(QString))); + } + + if (mo->indexOfSlot(QMetaObject::normalizedSignature("cancelOperation()")) > -1) + connect(q, SIGNAL(installationInterrupted()), operationObject, SLOT(cancelOperation())); + + if (mo->indexOfSignal(QMetaObject::normalizedSignature("progressChanged(double)")) > -1) { + ProgressCoordninator::instance()->registerPartProgress(operationObject, + SIGNAL(progressChanged(double)), progressOperationPartSize); + } + } +} + +KDUpdater::UpdateOperation* InstallerPrivate::createPathOperation(const QFileInfo &fileInfo, + const QString &componentName) +{ + const bool isDir = fileInfo.isDir(); + // create an operation with the dir/ file as target, it will get deleted on undo + KDUpdater::UpdateOperation *op = createOwnedOperation(QLatin1String(isDir + ? "Mkdir" : "Copy")); + if (isDir) + op->setValue(QLatin1String("createddir"), fileInfo.absoluteFilePath()); + op->setValue(QLatin1String("component"), componentName); + op->setArguments(isDir ? QStringList() << fileInfo.absoluteFilePath() + : QStringList() << QString() << fileInfo.absoluteFilePath()); + return op; +} + +/*! + This creates fake operations which remove stuff which was registered for uninstallation afterwards +*/ +void InstallerPrivate::registerPathesForUninstallation( + const QList<QPair<QString, bool> > &pathesForUninstallation, const QString &componentName) +{ + if (pathesForUninstallation.isEmpty()) + return; + + QList<QPair<QString, bool> >::const_iterator it; + for (it = pathesForUninstallation.begin(); it != pathesForUninstallation.end(); ++it) { + const bool wipe = it->second; + const QString path = replaceVariables(it->first); + + const QFileInfo fi(path); + // create a copy operation with the file as target -> it will get deleted on undo + KDUpdater::UpdateOperation* const op = createPathOperation(fi, componentName); + if (fi.isDir()) { + op->setValue(QLatin1String("forceremoval"), wipe ? QLatin1String("true") + : QLatin1String("false")); + } + addPerformed(op); + + // get recursive afterwards + if (fi.isDir() && !wipe) { + QDirIterator dirIt(path, QDir::Hidden | QDir::AllEntries | QDir::System + | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + while (dirIt.hasNext()) { + dirIt.next(); + addPerformed(createPathOperation(dirIt.fileInfo(), componentName)); + } + } + } +} + +void InstallerPrivate::writeUninstaller(QVector<KDUpdater::UpdateOperation*> performedOperations) +{ + bool gainedAdminRights = false; + QTemporaryFile tempAdminFile(targetDir() + QString::fromLatin1("/testjsfdjlkdsjflkdsjfldsjlfds") + + QString::number(qrand() % 1000)); + if (!tempAdminFile.open() || !tempAdminFile.isWritable()) { + q->gainAdminRights(); + gainedAdminRights = true; + } + + verbose() << "QInstaller::InstallerPrivate::writeUninstaller uninstaller=" << uninstallerName() + << std::endl; + + // create the directory containing the uninstaller (like a bundle structor, on Mac...) + KDUpdater::UpdateOperation* op = createOwnedOperation(QLatin1String("Mkdir")); + op->setArguments(QStringList() << QFileInfo(uninstallerName()).path()); + performOperationThreaded(op, Backup); + performOperationThreaded(op); + performedOperations.push_back(op); + + { + // write current state (variables) to the uninstaller ini file + const QString iniPath = targetDir() + QLatin1Char('/') + + m_installerSettings->uninstallerIniFile(); + QSettings cfg(iniPath, QSettings::IniFormat); + QVariantHash vars; + QHash<QString, QString>::ConstIterator it = m_vars.constBegin(); + while (it != m_vars.constEnd()) { + const QString &key = it.key(); + if (key != QLatin1String("RunProgramDescription") && key != QLatin1String("RunProgram")) + vars.insert(key, it.value()); + ++it; + } + cfg.setValue(QLatin1String("Variables"), vars); + cfg.sync(); + if (cfg.status() != QSettings::NoError) { + const QString reason = cfg.status() == QSettings::AccessError ? tr("Access error") + : tr("Format error"); + throw Error(tr("Could not write installer configuration to %1: %2").arg(iniPath, reason)); + } + } + +#ifdef Q_WS_MAC + // if it is a bundle, we need some stuff in it... + if (isInstaller() + && QFileInfo(QCoreApplication::applicationDirPath() + QLatin1String("/../..")).isBundle()) { + op = createOwnedOperation(QLatin1String("Copy")); + op->setArguments(QStringList() << (QCoreApplication::applicationDirPath() + + QLatin1String("/../PkgInfo")) << (QFileInfo(uninstallerName()).path() + + QLatin1String("/../PkgInfo"))); + performOperationThreaded(op, Backup); + performOperationThreaded(op); + + op = createOwnedOperation(QLatin1String("Copy")); + op->setArguments(QStringList() << (QCoreApplication::applicationDirPath() + + QLatin1String("/../Info.plist")) << (QFileInfo(uninstallerName()).path() + + QLatin1String("/../Info.plist"))); + performOperationThreaded(op, Backup); + performOperationThreaded(op); + + verbose() << "Checking for qt_menu.nib" << std::endl; + QString sourceDirName = QCoreApplication::applicationDirPath() + + QLatin1String("/../Resources/qt_menu.nib"); + if (QFileInfo(sourceDirName).exists()) { + verbose() << "qt_menu.nib has been found. Isn't it great?" << std::endl; + QString targetDirName = QFileInfo(QFileInfo(uninstallerName()).path() + + QLatin1String("/../Resources/qt_menu.nib")).absoluteFilePath(); + + // IFW has been built with a static Cocoa Qt. The app bundle must contain the qt_menu.nib. + // ### use the CopyDirectory operation in 1.1 + op = createOwnedOperation(QLatin1String("Mkdir")); + op->setArguments(QStringList() << targetDirName); + if (!op->performOperation()) { + verbose() << "ERROR in Mkdir operation: " << op->errorString() << std::endl; + } + + QDir sourceDir(sourceDirName); + foreach (const QString &filename, sourceDir.entryList(QDir::Files)) { + QString src = sourceDirName + QLatin1String("/") + filename; + QString dst = targetDirName + QLatin1String("/") + filename; + op = createOwnedOperation(QLatin1String("Copy")); + op->setArguments(QStringList() << src << dst); + if (!op->performOperation()) + verbose() << "ERROR in Copy operation: copy " << src << " to " << dst << std::endl + << "error message: " << op->errorString() << std::endl; + } + } + + // patch the Info.plist while copying it + QFile sourcePlist(QCoreApplication::applicationDirPath() + QLatin1String("/../Info.plist")); + openForRead(&sourcePlist, sourcePlist.fileName()); + QFile targetPlist(QFileInfo(uninstallerName()).path() + QLatin1String("/../Info.plist")); + openForWrite(&targetPlist, targetPlist.fileName()); + + QTextStream in(&sourcePlist); + QTextStream out(&targetPlist); + + while (!in.atEnd()) + { + QString line = in.readLine(); + line = line.replace(QLatin1String("<string>") + + QFileInfo(QCoreApplication::applicationFilePath()).baseName() + + QLatin1String("</string>"), QLatin1String("<string>") + + QFileInfo(uninstallerName()).baseName() + QLatin1String("</string>")); + out << line << endl; + } + + op = createOwnedOperation(QLatin1String("Mkdir")); + op->setArguments(QStringList() << (QFileInfo(QFileInfo(uninstallerName()).path()).path() + + QLatin1String("/Resources"))); + performOperationThreaded(op, Backup); + performOperationThreaded(op); + + const QString icon = QFileInfo(QCoreApplication::applicationFilePath()).baseName() + + QLatin1String(".icns"); + op = createOwnedOperation(QLatin1String("Copy")); + op->setArguments(QStringList() << (QCoreApplication::applicationDirPath() + + QLatin1String("/../Resources/") + icon) << (QFileInfo(uninstallerName()).path() + + QLatin1String("/../Resources/") + icon)); + performOperationThreaded(op, Backup); + performOperationThreaded(op); + + // finally, copy everything within Frameworks and plugins + if (QDir(QCoreApplication::applicationDirPath() + QLatin1String("/../Frameworks")).exists()) { + copyDirectoryContents(QCoreApplication::applicationDirPath() + + QLatin1String("/../Frameworks"), QFileInfo(uninstallerName()).path() + + QLatin1String("/../Frameworks")); + } + + if (QDir(QCoreApplication::applicationDirPath() + QLatin1String("/../plugins")).exists()) { + copyDirectoryContents(QCoreApplication::applicationDirPath() + + QLatin1String("/../plugins"), QFileInfo(uninstallerName()).path() + + QLatin1String("/../plugins")); + } + } +#endif + + QFile in; + if (isInstaller() || isUninstaller() || isPackageManager()) + in.setFileName(installerBinaryPath()); + else + in.setFileName(uninstallerName()); // we're the updater + + const QString installerBaseBinary = q->replaceVariables(m_installerBaseBinaryUnreplaced); + if (!installerBaseBinary.isEmpty()) + verbose() << "Got a replacement installer base binary: " << installerBaseBinary << std::endl; + + const bool haveSeparateExec = QFile::exists(installerBaseBinary) && !installerBaseBinary.isEmpty(); + verbose() << "Need to restart after exit: " << haveSeparateExec << " " + << qPrintable(installerBaseBinary) << std::endl; + +#ifdef Q_WS_WIN + KDSaveFile out(uninstallerName() + QLatin1String(".org")); +#else + KDSaveFile out(uninstallerName()); +#endif + + try { + verbose() << "CREATING UNINSTALLER " << performedOperations.size() << std::endl; + + QFile* execIn = ∈ + qint64 execSize = 0; + QFile ibbIn; + if (haveSeparateExec) { + ibbIn.setFileName(installerBaseBinary); + openForRead(&ibbIn, ibbIn.fileName()); + execIn = &ibbIn; + execSize = ibbIn.size(); + } + + openForRead(&in, in.fileName()); + openForWrite(&out, out.fileName()); + + const qint64 magicCookiePos = findMagicCookie(&in); + if (magicCookiePos < 0) { + throw Error(QObject::tr("Can not find the magic cookie in file %1. Are you sure this " + "is a valid installer?").arg(installerBinaryPath())); + } + + if (!in.seek(magicCookiePos - 7 * sizeof(qint64))) { + throw Error(QObject::tr("Failed to seek in file %1: %2").arg(installerBinaryPath(), + in.errorString())); + } + + qint64 resourceStart = retrieveInt64(&in); + const qint64 resourceLength = retrieveInt64(&in); + Q_ASSERT(resourceLength >= 0); + const qint64 _operationsStart = retrieveInt64(&in); + Q_UNUSED(_operationsStart); + Q_ASSERT(_operationsStart >= 0); + const qint64 _operationsLength = retrieveInt64(&in); + Q_UNUSED(_operationsLength); + Q_ASSERT(_operationsLength >= 0); + const qint64 count = retrieveInt64(&in); // atm always "1" + Q_ASSERT(count == 1); // we have just 1 resource atm + const qint64 dataBlockSize = retrieveInt64(&in); + const qint64 dataBlockStart = magicCookiePos + sizeof(qint64) - dataBlockSize; + resourceStart += dataBlockStart; + if (!haveSeparateExec) + execSize = dataBlockStart; + + // consider size difference between old and new installerbase executable (if updated) + const qint64 newResourceStart = execSize; + const qint64 magicmarker = retrieveInt64(&in); + Q_UNUSED(magicmarker); + Q_ASSERT(magicmarker == MagicInstallerMarker || magicmarker == MagicUninstallerMarker); + + + + if (!execIn->seek(0)) { + throw Error(QObject::tr("Failed to seek in file %1: %2").arg(execIn->fileName(), + execIn->errorString())); + } + appendData(&out, execIn, execSize); + + // copy the first few bytes to take the executable+resources over to the uninstaller. + if (! in.seek(resourceStart)) { + throw Error(QObject::tr("Failed to seek in file %1: %2").arg(in.fileName(), + in.errorString())); + } + Q_ASSERT(in.pos() == resourceStart && out.pos() == execSize); + + appendData(&out, &in, resourceLength); + const qint64 uninstallerDataBlockStart = out.pos(); + // compared to the installer we do not have component data but details about + // the performed operations during the installation to allow to undo them. + const qint64 operationsStart = out.pos(); + appendInt64(&out, performedOperations.count()); + foreach (KDUpdater::UpdateOperation *op, performedOperations) { + // the installer can't be put into XML, remove it first + op->clearValue(QLatin1String("installer")); + + appendString(&out, op->name()); + appendString(&out, op->toXml().toString()); + + // for the ui not to get blocked + qApp->processEvents(); + } + appendInt64(&out, performedOperations.count()); + const qint64 operationsEnd = out.pos(); + + // we dont save any component-indexes. + const qint64 numComponents = 0; + appendInt64(&out, numComponents); // for the indexes + // we dont save any components. + const qint64 compIndexStart = out.pos(); + appendInt64(&out, numComponents); // and 2 times number of components, + appendInt64(&out, numComponents); // one before and one after the components + const qint64 compIndexEnd = out.pos(); + + appendInt64Range(&out, Range<qint64>::fromStartAndEnd(compIndexStart, compIndexEnd) + .moved(-uninstallerDataBlockStart)); + appendInt64Range(&out, Range<qint64>::fromStartAndLength(newResourceStart, resourceLength) + .moved(-uninstallerDataBlockStart)); + appendInt64Range(&out, Range<qint64>::fromStartAndEnd(operationsStart, operationsEnd) + .moved(-uninstallerDataBlockStart)); + appendInt64(&out, count); + //data block size, from end of .exe to end of file + appendInt64(&out, out.pos() + 3 * sizeof(qint64) - uninstallerDataBlockStart); + appendInt64(&out, MagicUninstallerMarker); + appendInt64(&out, MagicCookie); + + out.setPermissions(out.permissions() | QFile::WriteUser | QFile::ReadGroup | QFile::ReadOther + | QFile::ExeOther | QFile::ExeGroup | QFile::ExeUser); + + if (!out.commit(KDSaveFile::OverwriteExistingFile)) { + throw Error(tr("Could not write uninstaller to %1: %2").arg(uninstallerName(), + out.errorString())); + } + + //delete the installerbase binary temporarily installed for the uninstaller update + if (haveSeparateExec) { + QFile tmp(installerBaseBinary); + // Is there anything more sensible we can do with this error? I think not. + // It's not serious enough for throwing/aborting. + if (!tmp.remove()) { + verbose() << "Could not remove installerbase binary (" << installerBaseBinary + << ") after updating the uninstaller: " << tmp.errorString() << std::endl; + } + m_installerBaseBinaryUnreplaced.clear(); + } + +#ifdef Q_WS_WIN + deferredRename(out.fileName(), QFileInfo(uninstallerName()).fileName(), + haveSeparateExec && !isInstaller()); +#else + verbose() << " preparing restart " << std::endl; + if (haveSeparateExec && !isInstaller()) + KDSelfRestarter::setRestartOnQuit(true); +#endif + } catch (const Error &err) { + setStatus(Installer::Failure); + if (gainedAdminRights) + q->dropAdminRights(); + m_needToWriteUninstaller = false; + throw err; + } + + if (gainedAdminRights) + q->dropAdminRights(); + + commitSessionOperations(); + + m_needToWriteUninstaller = false; +} + +QString InstallerPrivate::registerPath() const +{ +#ifdef Q_OS_WIN + QString productName = m_vars.value(QLatin1String("ProductName")); + if (productName.isEmpty()) + throw Error(tr("ProductName should be set")); + + QString path = QLatin1String("HKEY_CURRENT_USER"); + if (m_vars.value(QLatin1String("AllUsers")) == QLatin1String("true")) + path = QLatin1String("HKEY_LOCAL_MACHINE"); + + return path + QLatin1String("\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\") + + productName; +#else + return QString(); +#endif +} + +void InstallerPrivate::registerUninstaller() +{ +#ifdef Q_OS_WIN + QSettings settings(registerPath(), QSettings::NativeFormat); + settings.setValue(QLatin1String("DisplayName"), m_vars.value(QLatin1String("ProductName"))); + settings.setValue(QLatin1String("DisplayVersion"), m_vars.value(QLatin1String("ProductVersion"))); + const QString uninstaller = QDir::toNativeSeparators(uninstallerName()); + settings.setValue(QLatin1String("DisplayIcon"), uninstaller); + settings.setValue(QLatin1String("Publisher"), m_vars.value(QLatin1String("Publisher"))); + settings.setValue(QLatin1String("UrlInfoAbout"), m_vars.value(QLatin1String("Url"))); + settings.setValue(QLatin1String("Comments"), m_vars.value(QLatin1String("Title"))); + settings.setValue(QLatin1String("InstallDate"), QDateTime::currentDateTime().toString()); + settings.setValue(QLatin1String("InstallLocation"), QDir::toNativeSeparators(targetDir())); + settings.setValue(QLatin1String("UninstallString"), uninstaller); + settings.setValue(QLatin1String("ModifyPath"), uninstaller + QLatin1String(" --manage-packages")); + settings.setValue(QLatin1String("EstimatedSize"), QFileInfo(installerBinaryPath()).size()); + settings.setValue(QLatin1String("NoModify"), 1); // TODO: set to 0 and support modify + settings.setValue(QLatin1String("NoRepair"), 1); +#endif +} + +void InstallerPrivate::unregisterUninstaller() +{ +#ifdef Q_OS_WIN + QSettings settings(registerPath(), QSettings::NativeFormat); + settings.remove(QString()); +#endif +} + +void InstallerPrivate::runInstaller() +{ + try { + setStatus(Installer::Running); + emit installationStarted(); //resets also the ProgressCoordninator + + //to have some progress for writeUninstaller + ProgressCoordninator::instance()->addReservePercentagePoints(1); + + const QString target = targetDir(); + if (target.isEmpty()) + throw Error(tr("Variable 'TargetDir' not set.")); + + // add the operation to create the target directory + bool installToAdminDirectory = false; + if (!QDir(target).exists()) { + QScopedPointer<KDUpdater::UpdateOperation> mkdirOp(createOwnedOperation(QLatin1String("Mkdir"))); + mkdirOp->setValue(QLatin1String("forceremoval"), true); + Q_ASSERT(mkdirOp.data()); + mkdirOp->setArguments(QStringList() << target); + performOperationThreaded(mkdirOp.data(), Backup); + if (!performOperationThreaded(mkdirOp.data())) { + // if we cannot create the target dir, we try to activate the admin rights + installToAdminDirectory = true; + if (!q->gainAdminRights() || !performOperationThreaded(mkdirOp.data())) + throw Error(mkdirOp->errorString()); + } + QString remove = q->value(QLatin1String("RemoveTargetDir")); + if (QVariant(remove).toBool()) + addPerformed(mkdirOp.take()); + } else { + QTemporaryFile tempAdminFile(target + QLatin1String("/adminrights")); + if (!tempAdminFile.open() || !tempAdminFile.isWritable()) + installToAdminDirectory = q->gainAdminRights(); + } + + // to show that there was some work + ProgressCoordninator::instance()->addManualPercentagePoints(1); + + ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("Preparing the installation...")); + const QList<Component*> componentsToInstall = q->calculateComponentOrder(); + verbose() << "Install size: " << componentsToInstall.size() << " components" << std::endl; + + // check if we need admin rights and ask before the action happens + for (QList<Component*>::const_iterator it = componentsToInstall.begin(); + it != componentsToInstall.end() && !installToAdminDirectory; ++it) { + Component* const component = *it; + bool requiredAdmin = false; + + if (component->value(QLatin1String("RequiresAdminRights"), + QLatin1String("false")) == QLatin1String("true")) { + requiredAdmin = q->gainAdminRights(); + } + + if (requiredAdmin) { + q->dropAdminRights(); + break; + } + } + + const double downloadPartProgressSize = double(1) / 3; + double componentsInstallPartProgressSize = double(2) / 3; + const int downloadedArchivesCount = q->downloadNeededArchives(AllMode, + downloadPartProgressSize); + + //if there was no download we have the whole progress for installing components + if (!downloadedArchivesCount) { + //componentsInstallPartProgressSize + downloadPartProgressSize; + componentsInstallPartProgressSize = double(1); + } + + // put the installed packages info into the target dir + KDUpdater::PackagesInfo* const packages = m_app->packagesInfo(); + packages->setFileName(componentsXmlPath()); + packages->setApplicationName(m_installerSettings->applicationName()); + packages->setApplicationVersion(m_installerSettings->applicationVersion()); + + stopProcessesForUpdates(componentsToInstall); + + const int progressOperationCount = countProgressOperations(componentsToInstall); + double progressOperationSize = componentsInstallPartProgressSize / progressOperationCount; + + QList<Component*>::const_iterator it; + for (it = componentsToInstall.begin(); it != componentsToInstall.end(); ++it) + q->installComponent(*it, progressOperationSize); + + + emit q->titleMessageChanged(tr("Creating Uninstaller")); + + m_app->packagesInfo()->writeToDisk(); + + writeUninstaller(m_performedOperationsOld + m_performedOperationsCurrentSession); + registerUninstaller(); + + //this is the reserved one from the beginning + ProgressCoordninator::instance()->addManualPercentagePoints(1); + + setStatus(Installer::Success); + ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("\nInstallation finished!")); + + emit installationFinished(); + + // disable the FSEngineClientHandler afterwards + m_FSEngineClientHandler->setActive(false); + } catch (const Error &err) { + if (q->status() != Installer::Canceled) { + setStatus(Installer::Failure); + verbose() << "INSTALLER FAILED: " << err.message() << std::endl; + MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("installationError"), tr("Error"), err.message()); + verbose() << "ROLLING BACK operations=" << m_performedOperationsCurrentSession.count() + << std::endl; + } + + q->rollBackInstallation(); + + ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("Installation aborted")); + emit installationFinished(); + + // disable the FSEngineClientHandler afterwards + m_FSEngineClientHandler->setActive(false); + throw; + } +} + +void InstallerPrivate::deleteUninstaller() +{ +#ifdef Q_OS_WIN + // Since Windows does not support that the uninstaller deletes itself we have to go with a + // rather dirty hack. What we do is to create a batchfile that will try to remove the uninstaller + // once per second. Then we start that batchfile detached, finished our job and close outself. + // Once that's done the batchfile will succeed in deleting our uninstall.exe and, if the + // installation directory was created but us and if it's empty after the uninstall, deletes + // the installation-directory. + const QString batchfile = QDir::toNativeSeparators(QFileInfo(QDir::tempPath(), + QLatin1String("uninstall.vbs")).absoluteFilePath()); + QFile f(batchfile); + if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) + throw Error(tr("Cannot prepare uninstall")); + + QTextStream batch(&f); + batch << "Set fso = WScript.CreateObject(\"Scripting.FileSystemObject\")\n"; + batch << "file = WScript.Arguments.Item(0)\n"; + batch << "folderpath = WScript.Arguments.Item(1)\n"; + batch << "Set folder = fso.GetFolder(folderpath)\n"; + batch << "on error resume next\n"; + + batch << "while fso.FileExists(file)\n"; + batch << " fso.DeleteFile(file)\n"; + batch << " WScript.Sleep(1000)\n"; + batch << "wend\n"; +// batch << "if folder.SubFolders.Count = 0 and folder.Files.Count = 0 then\n"; + batch << " Set folder = Nothing\n"; + batch << " fso.DeleteFolder folderpath, true\n"; +// batch << "end if\n"; + batch << "fso.DeleteFile(WScript.ScriptFullName)\n"; + + f.close(); + + QStringList arguments; + arguments << QLatin1String("//Nologo") << batchfile; // execute the batchfile + arguments << QDir::toNativeSeparators(QFileInfo(installerBinaryPath()).absoluteFilePath()); + if (!m_performedOperationsOld.isEmpty()) { + const KDUpdater::UpdateOperation* const op = m_performedOperationsOld.first(); + if (op->name() == QLatin1String("Mkdir")) // the target directory name + arguments << QDir::toNativeSeparators(QFileInfo(op->arguments().first()).absoluteFilePath()); + } + + if (!QProcess::startDetached(QLatin1String("cscript"), arguments, QDir::rootPath())) + throw Error(tr("Cannot start uninstall")); +#else + // every other platform has no problem if we just delete ourself now + QFile uninstaller(QFileInfo(installerBinaryPath()).absoluteFilePath()); + uninstaller.remove(); +#ifdef Q_WS_MAC + const QLatin1String cdUp("/../../.."); + if (QFileInfo(QFileInfo(installerBinaryPath() + cdUp).absoluteFilePath()).isBundle()) { + removeDirectoryThreaded(QFileInfo(installerBinaryPath() + cdUp).absoluteFilePath()); + QFile::remove(QFileInfo(installerBinaryPath() + cdUp).absolutePath() + + QLatin1String("/") + configurationFileName()); + } + else +#endif +#endif + { + // finally remove the components.xml, since it still exists now + QFile::remove(QFileInfo(installerBinaryPath()).absolutePath() + QLatin1String("/") + + configurationFileName()); + } +} + +void InstallerPrivate::runPackageUpdater() +{ + try { + if (m_completeUninstall) { + // well... I guess we would call that an uninstall, no? :-) + m_packageManagingMode = !m_completeUninstall; + runUninstaller(); + return; + } + + setStatus(Installer::Running); + emit installationStarted(); //resets also the ProgressCoordninator + + //to have some progress for the cleanup/write component.xml step + ProgressCoordninator::instance()->addReservePercentagePoints(1); + + if (!QFileInfo(installerBinaryPath()).isWritable()) + q->gainAdminRights(); + + KDUpdater::PackagesInfo* const packages = m_app->packagesInfo(); + packages->setFileName(componentsXmlPath()); + packages->setApplicationName(m_installerSettings->applicationName()); + packages->setApplicationVersion(m_installerSettings->applicationVersion()); + + const QString packagesXml = componentsXmlPath(); + if (!QFile(packagesXml).open(QIODevice::Append)) + q->gainAdminRights(); + + // first check, if we need admin rights for the installation part + QList<Component*>::const_iterator it; + QList<Component*> availableComponents = q->components(true, AllMode); + for (it = availableComponents.begin(); it != availableComponents.end(); ++it) { + // check if we need admin rights and ask before the action happens + Component* const currentComponent = *it; + if (!currentComponent->isSelected(AllMode)) + continue; + + // we only need the uninstalled components + if (currentComponent->value(QLatin1String("PreviousState")) == QLatin1String("Installed")) + continue; + + bool requiredAdmin = false; + if (currentComponent->value(QLatin1String("RequiresAdminRights"), + QLatin1String("false")) == QLatin1String("true")) { + requiredAdmin = q->gainAdminRights(); + } + + if (requiredAdmin) { + q->dropAdminRights(); + break; + } + } + + //to have 1/5 for undoOperationProgressSize and 2/5 for componentsInstallPartProgressSize + const double downloadPartProgressSize = double(2) / 5; + // following, we download the needed archives + q->downloadNeededArchives(AllMode, downloadPartProgressSize); + + ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("Removing deselected components...")); + QVector< KDUpdater::UpdateOperation* > nonRevertedOperations; + + QList<KDUpdater::UpdateOperation*> undoOperations; + for (int i = m_performedOperationsOld.count() - 1; i >= 0; --i) { + KDUpdater::UpdateOperation* const currentOperation = m_performedOperationsOld[i]; + + const QString componentName = currentOperation->value(QLatin1String("component")).toString(); + Component* comp = q->componentByName(componentName); + + // if we're _not_ removing everything an this component is still selected, -> next + if (comp == 0 || comp->isSelected()) { + nonRevertedOperations.push_front(currentOperation); + continue; + } + undoOperations.append(currentOperation); + } + + double undoOperationProgressSize = 0; + int progressUndoOperationCount = 0; + double progressUndoOperationSize = 0; + double componentsInstallPartProgressSize = double(2) / 5; + if (undoOperations.count() > 0) { + componentsInstallPartProgressSize = double(2) / 5; + undoOperationProgressSize = double(1) / 5; + progressUndoOperationCount = countProgressOperations(undoOperations); + progressUndoOperationSize = undoOperationProgressSize / progressUndoOperationCount; + } else { + componentsInstallPartProgressSize = double(3) / 5; + } + + QSet<Component*> uninstalledComponents; + foreach (KDUpdater::UpdateOperation* const currentOperation, undoOperations) { + if (statusCanceledOrFailed()) + throw Error(tr("Installation canceled by user")); + connectOperationToInstaller(currentOperation, progressUndoOperationSize); + + const QString componentName = currentOperation->value(QLatin1String("component")).toString(); + Component* comp = q->componentByName(componentName); + + verbose() << "undo operation=" << currentOperation->name() << std::endl; + uninstalledComponents |= comp; + + const bool becameAdmin = !m_FSEngineClientHandler->isActive() + && currentOperation->value(QLatin1String("admin")).toBool() && q->gainAdminRights(); + + bool ignoreError = false; + performOperationThreaded(currentOperation, Undo); + bool ok = currentOperation->error() == KDUpdater::UpdateOperation::NoError + || componentName == QLatin1String(""); + while (!ok && !ignoreError && q->status() != Installer::Canceled) { + verbose() << QString(QLatin1String("operation '%1' with arguments: '%2' failed: %3")) + .arg(currentOperation->name(), currentOperation->arguments() + .join(QLatin1String("; ")), currentOperation->errorString()) << std::endl;; + + const QMessageBox::StandardButton button = + MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("installationErrorWithRetry"), tr("Installer Error"), + tr("Error during installation process:\n%1").arg(currentOperation->errorString()), + QMessageBox::Retry | QMessageBox::Ignore, QMessageBox::Retry); + + if (button == QMessageBox::Retry) { + performOperationThreaded(currentOperation, Undo); + ok = currentOperation->error() == KDUpdater::UpdateOperation::NoError; + } + else if (button == QMessageBox::Ignore) + ignoreError = true; + } + + if (becameAdmin) + q->dropAdminRights(); + + delete currentOperation; + } + + const QList<Component*> allComponents = q->components(true, AllMode); + foreach (Component *comp, allComponents) { + if (!comp->isSelected()) + uninstalledComponents |= comp; + } + + QSet<Component*>::const_iterator it2; + for (it2 = uninstalledComponents.begin(); it2 != uninstalledComponents.end(); ++it2) { + packages->removePackage((*it2)->name()); + (*it2)->setValue(QLatin1String("CurrentState"), QLatin1String("Uninstalled")); + } + + // these are all operations left: those which were not reverted + m_performedOperationsOld = nonRevertedOperations; + + //write components.xml in case the user cancels the update + packages->writeToDisk(); + ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("Preparing the installation...")); + + const QList<Component*> componentsToInstall = q->calculateComponentOrder(); + + verbose() << "Install size: " << componentsToInstall.size() << " components " << std::endl; + + stopProcessesForUpdates(componentsToInstall); + + int progressOperationCount = countProgressOperations(componentsToInstall); + double progressOperationSize = componentsInstallPartProgressSize / progressOperationCount; + + for (it = componentsToInstall.begin(); it != componentsToInstall.end(); ++it) + q->installComponent(*it, progressOperationSize); + + packages->writeToDisk(); + + emit q->titleMessageChanged(tr("Creating Uninstaller")); + + commitSessionOperations(); //end session, move ops to "old" + m_needToWriteUninstaller = true; + + //this is the reserved one from the beginning + ProgressCoordninator::instance()->addManualPercentagePoints(1); + + setStatus(Installer::Success); + ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("\nInstallation finished!")); + emit installationFinished(); + + // disable the FSEngineClientHandler afterwards + m_FSEngineClientHandler->setActive(false); + } catch(const Error &err) { + if (q->status() != Installer::Canceled) { + setStatus(Installer::Failure); + verbose() << "INSTALLER FAILED: " << err.message() << std::endl; + MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("installationError"), tr("Error"), err.message()); + verbose() << "ROLLING BACK operations=" << m_performedOperationsCurrentSession.count() + << std::endl; + } + + q->rollBackInstallation(); + + ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("Installation aborted")); + emit installationFinished(); + + // disable the FSEngineClientHandler afterwards + m_FSEngineClientHandler->setActive(false); + throw; + } +} + +void InstallerPrivate::runUninstaller() +{ + try { + emit uninstallationStarted(); + + if (!QFileInfo(installerBinaryPath()).isWritable()) + q->gainAdminRights(); + + const QString packagesXml = componentsXmlPath(); + if (!QFile(packagesXml).open(QIODevice::Append)) + q->gainAdminRights(); + + KDUpdater::PackagesInfo* const packages = m_app->packagesInfo(); + packages->setFileName(componentsXmlPath()); + packages->setApplicationName(m_installerSettings->applicationName()); + packages->setApplicationVersion(m_installerSettings->applicationVersion()); + + // iterate over all components - if they're all marked for uninstall, it's a complete uninstall + bool allMarkedForUninstall = true; + + QList<KDUpdater::UpdateOperation*> uninstallOperations; + QVector<KDUpdater::UpdateOperation*> nonRevertedOperations; + + // just rollback all operations done before + for (int i = m_performedOperationsOld.count() - 1; i >= 0; --i) { + KDUpdater::UpdateOperation* const operation = m_performedOperationsOld[i]; + + const QString componentName = operation->value(QLatin1String("component")).toString(); + const Component* const comp = q->componentByName(componentName); + + // if we're _not_ removing everything an this component is still selected, -> next + if (!m_completeUninstall && (comp == 0 || !comp->isSelected())) { + nonRevertedOperations.push_front(operation); + continue; + } + uninstallOperations.append(operation); + } + + const int progressUninstallOperationCount = countProgressOperations(uninstallOperations); + const double progressUninstallOperationSize = double(1) / progressUninstallOperationCount; + + foreach (KDUpdater::UpdateOperation* const currentOperation, uninstallOperations) { + if (statusCanceledOrFailed()) + throw Error(tr("Installation canceled by user")); + + connectOperationToInstaller(currentOperation, progressUninstallOperationSize); + verbose() << "undo operation=" << currentOperation->name() << std::endl; + + const QString componentName = currentOperation->value(QLatin1String("component")).toString(); + + const bool becameAdmin = !m_FSEngineClientHandler->isActive() + && currentOperation->value(QLatin1String("admin")).toBool() && q->gainAdminRights(); + + bool ignoreError = false; + performOperationThreaded(currentOperation, Undo); + bool ok = currentOperation->error() == KDUpdater::UpdateOperation::NoError + || componentName == QLatin1String(""); + while (!ok && !ignoreError && q->status() != Installer::Canceled) { + verbose() << QString(QLatin1String("operation '%1' with arguments: '%2' failed: %3")) + .arg(currentOperation->name(), currentOperation->arguments() + .join(QLatin1String("; ")), currentOperation->errorString()) << std::endl;; + const QMessageBox::StandardButton button = + MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("installationErrorWithRetry"), tr("Installer Error"), + tr("Error during installation process:\n%1").arg(currentOperation->errorString()), + QMessageBox::Retry | QMessageBox::Ignore, QMessageBox::Retry); + + if (button == QMessageBox::Retry) { + performOperationThreaded(currentOperation, Undo); + ok = currentOperation->error() == KDUpdater::UpdateOperation::NoError; + } else if (button == QMessageBox::Ignore) + ignoreError = true; + } + + if (becameAdmin) + q->dropAdminRights(); + + if (!m_completeUninstall) + delete currentOperation; + } + + const QList<Component*> allComponents = q->components(true, AllMode); + if (!m_completeUninstall) { + QList<Component*>::const_iterator it; + for (it = allComponents.begin(); it != allComponents.end(); ++it) { + Component* const comp = *it; + if (comp->isSelected()) { + allMarkedForUninstall = false; + } else { + packages->removePackage(comp->name()); + comp->setValue(QLatin1String("CurrentState"), QLatin1String("Uninstalled")); + } + } + m_completeUninstall = m_completeUninstall || allMarkedForUninstall; + m_packageManagingMode = ! m_completeUninstall; + } + + const QString startMenuDir = m_vars.value(QLatin1String("StartMenuDir")); + if (!startMenuDir.isEmpty()) { + errno = 0; + if (!QDir().rmdir(startMenuDir)) { + verbose() << "Could not remove " << startMenuDir << " : " + << QLatin1String(strerror(errno)) << std::endl; + } else { + verbose() << "Startmenu dir not set" << std::endl; + } + } + + if (m_completeUninstall) { + // this will also delete the TargetDir on Windows + deleteUninstaller(); + QList<Component*>::const_iterator it; + for (it = allComponents.begin(); it != allComponents.end(); ++it) { + packages->removePackage((*it)->name()); + (*it)->setValue(QLatin1String("CurrentState"), QLatin1String("Uninstalled")); + } + + QString remove = q->value(QLatin1String("RemoveTargetDir")); + if (QVariant(remove).toBool()) { + // on !Windows, we need to remove TargetDir manually + m_packageManagingMode = ! m_completeUninstall; + verbose() << "Complete Uninstallation is chosen" << std::endl; + const QString target = targetDir(); + if (!target.isEmpty()) { + if (m_FSEngineClientHandler->isServerRunning() && !m_FSEngineClientHandler->isActive()) { + // we were root at least once, so we remove the target dir as root + q->gainAdminRights(); + removeDirectoryThreaded(target, true); + q->dropAdminRights(); + } else { + removeDirectoryThreaded(target, true); + } + } + } + + unregisterUninstaller(); + m_needToWriteUninstaller = false; + } else { + // rewrite the uninstaller with the operation we did not undo + writeUninstaller(nonRevertedOperations); + } + + setStatus(Installer::Success); + ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("\nDeinstallation finished")); + + m_FSEngineClientHandler->setActive(false); + } catch (const Error &err) { + if (q->status() != Installer::Canceled) { + setStatus(Installer::Failure); + verbose() << "INSTALLER FAILED: " << err.message() << std::endl; + MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("installationError"), tr("Error"), err.message()); + verbose() << "ROLLING BACK operations=" << m_performedOperationsCurrentSession.count() + << std::endl; + } + + ProgressCoordninator::instance()->emitLabelAndDetailTextChanged(tr("Installation aborted")); + emit installationFinished(); + + // disable the FSEngineClientHandler afterwards + m_FSEngineClientHandler->setActive(false); + throw; + } + emit uninstallationFinished(); +} + +} // QInstaller diff --git a/installerbuilder/libinstaller/qinstaller_p.h b/installerbuilder/libinstaller/qinstaller_p.h new file mode 100644 index 000000000..d6361b838 --- /dev/null +++ b/installerbuilder/libinstaller/qinstaller_p.h @@ -0,0 +1,197 @@ +/************************************************************************** +** +** This file is part of Qt SDK** +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).* +** +** Contact: Nokia Corporation qt-info@nokia.com** +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception version +** 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you are unsure which license is appropriate for your use, please contact +** (qt-info@nokia.com). +** +**************************************************************************/ +#ifndef QINSTALLER_P_H +#define QINSTALLER_P_H + +#include <KDToolsCore/KDSysInfo> + +#include <QtCore/QHash> +#include <QtCore/QObject> +#include <QtCore/QPair> +#include <QtCore/QPointer> +#include <QtCore/QVector> + +class FSEngineClientHandler; +QT_FORWARD_DECLARE_CLASS(QFileInfo) + +namespace KDUpdater { + class Application; + class UpdateOperation; +} + +namespace QInstaller { + +class Component; +class Installer; +class InstallerSettings; +class TempDirDeleter; + +class InstallerPrivate : public QObject +{ + Q_OBJECT; + friend class Installer; + +public: + enum OperationType { + Backup, + Perform, + Undo + }; + + explicit InstallerPrivate(Installer *q, qint64 magicInstallerMaker, + const QVector<KDUpdater::UpdateOperation*> &performedOperations); + ~InstallerPrivate(); + + static bool isProcessRunning(const QString &name, + const QList<KDSysInfo::ProcessInfo> &processes); + + static bool performOperationThreaded(KDUpdater::UpdateOperation *op, + InstallerPrivate::OperationType type = InstallerPrivate::Perform); + + void initialize(); + + void setStatus(int status); + bool statusCanceledOrFailed() const; + + QString targetDir() const; + QString registerPath() const; + + void deleteUninstaller(); + void registerUninstaller(); + void unregisterUninstaller(); + + QString uninstallerName() const; + QString installerBinaryPath() const; + void readUninstallerIniFile(const QString &targetDir); + void writeUninstaller(QVector<KDUpdater::UpdateOperation*> performedOperations); + + QString configurationFileName() const; + QString componentsXmlPath() const; + QString localComponentsXmlPath() const; + + Installer *installer() const { return q; } + + void runInstaller(); + bool isInstaller() const; + + void runUninstaller(); + bool isUninstaller() const; + + void runUpdater(); + bool isUpdater() const; + + void runPackageUpdater(); + bool isPackageManager() const; + + QString replaceVariables(const QString &str) const; + QByteArray replaceVariables(const QByteArray &str) const; + + KDUpdater::UpdateOperation* createOwnedOperation(const QString &type); + void stopProcessesForUpdates(const QList<Component*> &components); + int countProgressOperations(const QList<Component*> &components); + int countProgressOperations(const QList<KDUpdater::UpdateOperation*> &operations); + void connectOperationToInstaller(KDUpdater::UpdateOperation* const operation, + double progressOperationPartSize); + + KDUpdater::UpdateOperation* createPathOperation(const QFileInfo &fileInfo, + const QString &componentName); + void registerPathesForUninstallation(const QList<QPair<QString, bool> > &pathesForUninstallation, + const QString &componentName); + + void addPerformed(KDUpdater::UpdateOperation* op) { + m_performedOperationsCurrentSession.push_back(op); + } + + void commitSessionOperations() { + m_performedOperationsOld += m_performedOperationsCurrentSession; + m_performedOperationsCurrentSession.clear(); + } + +signals: + void installationStarted(); + void installationFinished(); + void uninstallationStarted(); + void uninstallationFinished(); + +public: + KDUpdater::Application *m_app; + TempDirDeleter *m_tempDirDeleter; + InstallerSettings *m_installerSettings; + FSEngineClientHandler *m_FSEngineClientHandler; + + int m_status; + bool m_forceRestart; + int m_silentRetries; + bool m_testChecksum; + bool m_launchedAsRoot; + bool m_completeUninstall; + bool m_packageManagingMode; + bool m_linearComponentList; + bool m_needToWriteUninstaller; + QHash<QString, QString> m_vars; + QHash<QString, bool> m_sharedFlags; + QString m_installerBaseBinaryUnreplaced; + + qint64 m_globalDictOffset; + + qint64 m_componentsCount; + qint64 m_firstComponentStart; + qint64 m_componentOffsetTableStart; + + qint64 m_componentsDictCount; + qint64 m_firstComponentDictStart; + qint64 m_componentDictOffsetTableStart; + + QList<Component*> m_rootComponents; + QHash<QString, Component*> m_componentHash; + + QList<Component*> m_updaterComponents; + QList<Component*> m_packageManagerComponents; + + //a hack to get the will be replaced components extra + QList<QInstaller::Component*> willBeReplacedComponents; + //this is a Hack, we don't need this in the refactor branch + QList< QPointer<QInstaller::Component> > componentDeleteList; + + QList<KDUpdater::UpdateOperation*> ownedOperations; + QVector<KDUpdater::UpdateOperation*> m_performedOperationsOld; + QVector<KDUpdater::UpdateOperation*> m_performedOperationsCurrentSession; + +private: + Installer *q; + qint64 m_magicBinaryMarker; +}; + +} // QInstaller + +#endif // QINSTALLER_P_H diff --git a/installerbuilder/libinstaller/qinstallercomponent.cpp b/installerbuilder/libinstaller/qinstallercomponent.cpp index 6ebdd1e89..aacfa4ea2 100644 --- a/installerbuilder/libinstaller/qinstallercomponent.cpp +++ b/installerbuilder/libinstaller/qinstallercomponent.cpp @@ -31,13 +31,16 @@ ** **************************************************************************/ #include "qinstallercomponent.h" -#include "qinstallerglobal.h" -#include "messageboxhandler.h" #include "common/errors.h" #include "common/fileutils.h" - +#include "common/utils.h" +#include "fsengineclient.h" #include "lib7z_facade.h" +#include "qinstaller.h" +#include "qinstallercomponent_p.h" +#include "qinstallerglobal.h" +#include "messageboxhandler.h" #include <KDUpdater/Update> #include <KDUpdater/UpdateSourcesInfo> @@ -45,214 +48,101 @@ #include <KDUpdater/UpdateOperationFactory> #include <KDUpdater/PackagesInfo> -#include <QApplication> -#include <QDesktopServices> -#include <QDir> -#include <QDirIterator> -#include <QHash> -#include <QMessageBox> -#include <QtCore/QPair> -#include <QScriptEngine> -#include <QScriptValue> -#include <QTextStream> -#include <QTranslator> -#include <QUiLoader> - -#include <memory> +#include <QtCore/QDirIterator> +#include <QtCore/QTranslator> -#include "common/utils.h" -#include "fsengineclient.h" +#include <QtGui/QApplication> + +#include <QtUiTools/QUiLoader> using namespace QInstaller; +static const QLatin1String skName("Name"); +static const QLatin1String skDisplayName("DisplayName"); +static const QLatin1String skDescription("Description"); +static const QLatin1String skCompressedSize("CompressedSize"); +static const QLatin1String skUncompressedSize("UncompressedSize"); +static const QLatin1String skVersion("Version"); +static const QLatin1String skDependencies("Dependencies"); +static const QLatin1String skReleaseDate("ReleaseDate"); +static const QLatin1String skReplaces("Replaces"); +static const QLatin1String skVirtual("Virtual"); +static const QLatin1String skSortingPriority("SortingPriority"); +static const QLatin1String skInstallPriority("InstallPriority"); +static const QLatin1String skAutoSelectOn("AutoSelectOn"); +static const QLatin1String skImportant("Important"); +static const QLatin1String skForcedInstallation("ForcedInstallation"); +static const QLatin1String skUpdateText("UpdateText"); +static const QLatin1String skRequiresAdminRights("RequiresAdminRights"); +static const QLatin1String skNewComponent("NewComponent"); +static const QLatin1String skScript("Script"); + /* -TRANSLATOR QInstaller::Component + TRANSLATOR QInstaller::Component */ /*! - \class QInstaller::Component - Component describes a component within the installer. + \class QInstaller::Component + Component describes a component within the installer. */ -class QInstaller::Component::Private -{ - QInstaller::Component* const q; -public: - Private( Installer* installer, QInstaller::Component* qq ) - : q( qq ), - m_installer( installer ), - m_parent( 0 ), - m_offsetInInstaller( 0 ), - autoCreateOperations( true ), - operationsCreated( false ), - removeBeforeUpdate( true ), - enabled( true ), - isCheckedFromUpdater( false ), - m_newlyInstalled ( false ), - operationsCreatedSuccessfully( true ), - minimumProgressOperation(0), - m_licenseOperation(0) - { - } - - static QMap< const Component*, Qt::CheckState > cachedCheckStates; - - Installer *m_installer; - QHash<QString,QString> m_vars; - QList< Component* > m_components; - QList< KDUpdater::UpdateOperation* > operations; - - QList< QPair< QString, bool > > pathesForUninstallation; - - QMap< QString, QWidget* > userInterfaces; - - QUrl repositoryUrl; - QString localTempPath; - QStringList downloadableArchives; - QStringList stopProcessForUpdateRequests; - - Component* m_parent; - - // filled before intaller runs - qint64 m_offsetInInstaller; - - bool autoCreateOperations; - bool operationsCreated; - - bool removeBeforeUpdate; - - bool enabled; - bool isCheckedFromUpdater; - - bool m_newlyInstalled; - - bool operationsCreatedSuccessfully; - - QScriptEngine scriptEngine; - QScriptValue scriptComponent; - - QHash< QString, bool > unexistingScriptMethods; - - void init(); - void setSelectedOnComponentList(const QList<Component*> &componentList, - bool selected, RunModes runMode, SelectMode selectMode); - KDUpdater::UpdateOperation* minimumProgressOperation; - - // < display name, < file name, file content > > - QHash<QString, QPair<QString, QString> > m_licenses; - KDUpdater::UpdateOperation *m_licenseOperation; -}; - -QMap< const Component*, Qt::CheckState > Component::Private::cachedCheckStates; - -void Component::Private::init() +/*! + Constructor. Creates a new Component inside of \a installer. +*/ +Component::Component(Installer *installer) + : d(new ComponentPrivate(installer, this)) { - // register translation stuff - scriptEngine.installTranslatorFunctions(); - - // register QMessageBox::StandardButton enum in the script connection - registerMessageBox( &scriptEngine ); - - // register QDesktopServices in the script cennoction - QScriptValue desktopServices = scriptEngine.newArray(); - desktopServices.setProperty( QLatin1String( "DesktopLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::DesktopLocation ) ) ); - desktopServices.setProperty( QLatin1String( "DocumentsLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::DocumentsLocation ) ) ); - desktopServices.setProperty( QLatin1String( "FontsLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::FontsLocation ) ) ); - desktopServices.setProperty( QLatin1String( "ApplicationsLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::ApplicationsLocation ) ) ); - desktopServices.setProperty( QLatin1String( "MusicLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::MusicLocation ) ) ); - desktopServices.setProperty( QLatin1String( "MoviesLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::MoviesLocation ) ) ); - desktopServices.setProperty( QLatin1String( "PicturesLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::PicturesLocation ) ) ); - desktopServices.setProperty( QLatin1String( "TempLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::TempLocation ) ) ); - desktopServices.setProperty( QLatin1String( "HomeLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::HomeLocation ) ) ); - desktopServices.setProperty( QLatin1String( "DataLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::DataLocation ) ) ); - desktopServices.setProperty( QLatin1String( "CacheLocation" ), scriptEngine.newVariant( static_cast< int >( QDesktopServices::CacheLocation ) ) ); - - desktopServices.setProperty( QLatin1String( "openUrl" ), scriptEngine.newFunction( qDesktopServicesOpenUrl ) ); - desktopServices.setProperty( QLatin1String( "displayName" ), scriptEngine.newFunction( qDesktopServicesDisplayName ) ); - desktopServices.setProperty( QLatin1String( "storageLocation" ), scriptEngine.newFunction( qDesktopServicesStorageLocation ) ); - scriptEngine.globalObject().setProperty( QLatin1String( "QDesktopServices" ), desktopServices ); - - // register ::WizardPage enum in the script connection - QScriptValue qinstaller = scriptEngine.newArray(); - qinstaller.setProperty( QLatin1String( "Introduction" ), scriptEngine.newVariant( static_cast< int >( Installer::Introduction ) ) ); - qinstaller.setProperty( QLatin1String( "LicenseCheck" ), scriptEngine.newVariant( static_cast< int >( Installer::LicenseCheck ) ) ); - qinstaller.setProperty( QLatin1String( "TargetDirectory" ), scriptEngine.newVariant( static_cast< int >( Installer::TargetDirectory ) ) ); - qinstaller.setProperty( QLatin1String( "ComponentSelection" ), scriptEngine.newVariant( static_cast< int >( Installer::ComponentSelection ) ) ); - qinstaller.setProperty( QLatin1String( "StartMenuSelection" ), scriptEngine.newVariant( static_cast< int >( Installer::StartMenuSelection ) ) ); - qinstaller.setProperty( QLatin1String( "ReadyForInstallation" ), scriptEngine.newVariant( static_cast< int >( Installer::ReadyForInstallation ) ) ); - qinstaller.setProperty( QLatin1String( "PerformInstallation" ), scriptEngine.newVariant( static_cast< int >( Installer::PerformInstallation ) ) ); - qinstaller.setProperty( QLatin1String( "InstallationFinished" ), scriptEngine.newVariant( static_cast< int >( Installer::InstallationFinished ) ) ); - qinstaller.setProperty( QLatin1String( "End" ), scriptEngine.newVariant( static_cast< int >( Installer::End ) ) ); - - // register ::Status enum in the script connection - qinstaller.setProperty( QLatin1String( "InstallerUnfinished" ), scriptEngine.newVariant( static_cast< int >( Installer::InstallerUnfinished ) ) ); - qinstaller.setProperty( QLatin1String( "InstallerCanceledByUser" ), scriptEngine.newVariant( static_cast< int >( Installer::InstallerCanceledByUser ) ) ); - qinstaller.setProperty( QLatin1String( "InstallerFailed" ), scriptEngine.newVariant( static_cast< int >( Installer::InstallerFailed ) ) ); - qinstaller.setProperty( QLatin1String( "InstallerSucceeded" ), scriptEngine.newVariant( static_cast< int >( Installer::InstallerSucceeded ) ) ); - - scriptEngine.globalObject().setProperty( QLatin1String( "QInstaller" ), qinstaller ); - - scriptEngine.globalObject().setProperty( QLatin1String( "component" ), scriptEngine.newQObject( q ) ); - QScriptValue installerObject = scriptEngine.newQObject( m_installer ); - installerObject.setProperty( QLatin1String( "componentByName" ), scriptEngine.newFunction( qInstallerComponentByName, 1 ) ); - scriptEngine.globalObject().setProperty( QLatin1String( "installer" ), installerObject ); + d->init(); + setPrivate(d); } -void Component::Private::setSelectedOnComponentList(const QList<Component*> &componentList, - bool selected, RunModes runMode, SelectMode selectMode) +Component::Component(KDUpdater::Update* update, Installer* installer) + : d(new ComponentPrivate(installer, this)) { - for( QList< Component* >::const_iterator it = componentList.begin(); it != componentList.end(); ++it ) - { - Component* const comp = *it; - if( !comp->isSelected( runMode ) ) - comp->setSelected( selected, runMode, selectMode ); - } -} + Q_ASSERT(update); -/*! - Constructor. Creates a new Component inside of \a installer. -*/ -Component::Component(Installer *installer) - : d(new Component::Private( installer, this ) ) -{ d->init(); + setPrivate(d); + loadDataFromUpdate(update); } /*! - Destroys the Component. + Destroys the Component. */ Component::~Component() { - if( parentComponent() != 0 ) - d->m_parent->d->m_components.removeAll( this ); + if (parentComponent() != 0) + d->m_parent->d->m_components.removeAll(this); if (!d->m_newlyInstalled) qDeleteAll(d->operations); - qDeleteAll( d->m_components ); + qDeleteAll(d->m_components); delete d; } //package info is that what is saved inside the packagemanager on harddisk void Component::loadDataFromPackageInfo(const KDUpdater::PackageInfo &packageInfo) { - setValue(QLatin1String("Name"), packageInfo.name); - setValue(QLatin1String("DisplayName"), packageInfo.title); - setValue(QLatin1String("Description"), packageInfo.description); - setValue(QLatin1String("UncompressedSize"), - QString::number(packageInfo.uncompressedSize)); - setValue(QLatin1String("Version"), packageInfo.version); - setValue(QLatin1String("Virtual"), - packageInfo.virtualComp ? QLatin1String ("true") : QLatin1String ("false")); + setValue(skName, packageInfo.name); + setValue(skDisplayName, packageInfo.title); + setValue(skDescription, packageInfo.description); + setValue(skUncompressedSize, QString::number(packageInfo.uncompressedSize)); + setValue(skVersion, packageInfo.version); + setValue(skVirtual, packageInfo.virtualComp ? QLatin1String ("true") : QLatin1String ("false")); + QString dependstr = QLatin1String(""); foreach (const QString& val, packageInfo.dependencies) - dependstr += val + QLatin1String(","); + dependstr += val + QLatin1String(","); + if (packageInfo.dependencies.count() > 0) dependstr.chop(1); - setValue(QLatin1String("Dependencies"), dependstr); - if (packageInfo.forcedInstallation) - setValue(QLatin1String("ForcedInstallation"), - packageInfo.forcedInstallation ? QLatin1String ("true") : QLatin1String ("false")); + setValue(skDependencies, dependstr); + + if (packageInfo.forcedInstallation) { + setValue(skForcedInstallation, + packageInfo.forcedInstallation ? QLatin1String ("true") : QLatin1String ("false")); + } } //update means it is the packageinfo from server @@ -261,147 +151,112 @@ void Component::loadDataFromUpdate(KDUpdater::Update* update) Q_ASSERT(update); Q_ASSERT(!update->name().isEmpty()); - setValue(QLatin1String("Name"), - update->data(QLatin1String("Name")).toString()); - setValue(QLatin1String("DisplayName"), - update->data(QLatin1String("DisplayName")).toString()); - setValue(QLatin1String("Description"), - update->data( QLatin1String("Description")).toString()); - setValue(QLatin1String("UncompressedSize"), - QString::number(update->uncompressedSize())); - setValue(QLatin1String("Version"), - update->data(QLatin1String("Version")).toString()); - setValue(QLatin1String("ReleaseDate"), - update->data(QLatin1String("ReleaseDate")).toString()); - setValue(QLatin1String("Dependencies"), - update->data(QLatin1String("Dependencies")).toString()); - setValue(QLatin1String("Replaces"), - update->data(QLatin1String("Replaces")).toString()); - setValue(QLatin1String("Virtual"), - update->data(QLatin1String("Virtual")).toString()); - setValue(QLatin1String("SortingPriority"), - update->data(QLatin1String("SortingPriority")).toString()); - setValue(QLatin1String("InstallPriority"), - update->data(QLatin1String("InstallPriority")).toString()); - setValue(QLatin1String("AutoSelectOn"), - update->data(QLatin1String("AutoSelectOn")).toString()); - setValue(QLatin1String("Important"), - update->data(QLatin1String("Important")).toString()); - + setValue(skName, update->data(skName).toString()); + setValue(skDisplayName, update->data(skDisplayName).toString()); + setValue(skDescription, update->data(skDescription).toString()); + setValue(skCompressedSize, QString::number(update->compressedSize())); + setValue(skUncompressedSize, QString::number(update->uncompressedSize())); + setValue(skVersion, update->data(skVersion).toString()); + setValue(skDependencies, update->data(skDependencies).toString()); + setValue(skVirtual, update->data(skVirtual).toString()); + setValue(skSortingPriority, update->data(skSortingPriority).toString()); + setValue(skInstallPriority, update->data(skInstallPriority).toString()); + setValue(skAutoSelectOn, update->data(skAutoSelectOn).toString()); + + setValue(skImportant, update->data(skImportant).toString()); + setValue(skUpdateText, update->data(skUpdateText).toString()); + setValue(skNewComponent, update->data(skNewComponent).toString()); + setValue(skRequiresAdminRights, update->data(skRequiresAdminRights).toString()); + + setValue(skScript, update->data(skScript).toString()); + setValue(skReplaces, update->data(skReplaces).toString()); + setValue(skReleaseDate, update->data(skReleaseDate).toString()); + + QString forced = update->data(skForcedInstallation).toString(); if (qApp->arguments().contains(QLatin1String("--no-force-installations"))) - setValue(QLatin1String("ForcedInstallation"), QLatin1String("false")); - else - setValue(QLatin1String("ForcedInstallation"), - update->data(QLatin1String("ForcedInstallation")).toString()); - - setValue(QLatin1String("UpdateText"), - update->data(QLatin1String("UpdateText")).toString()); - setValue(QLatin1String("RequiresAdminRights"), - update->data(QLatin1String("RequiresAdminRights")).toString()); - setValue(QLatin1String("NewComponent"), - update->data(QLatin1String("NewComponent")).toString()); - setValue(QLatin1String("Script"), - update->data(QLatin1String("Script")).toString()); - - const QString localPath = QInstaller::pathFromUrl(update->sourceInfo().url); - - //TODO: move this verbose output for the url to a location - //where we don't need to check that is a newer url(so it would be better where the updates - //are created) - static QString lastLocalPath; - if (lastLocalPath != localPath) - verbose() << "Url is : " << localPath << std::endl; - lastLocalPath = localPath; + forced = QLatin1String("false"); + setValue(skForcedInstallation, forced); + setLocalTempPath(QInstaller::pathFromUrl(update->sourceInfo().url)); const QStringList uis = update->data(QLatin1String("UserInterfaces")).toString() .split(QString::fromLatin1(","), QString::SkipEmptyParts); - if (!uis.isEmpty()) { - verbose() << "Loading User Interface definitions for component " << name() << std::endl; - loadUserInterfaces(QDir(QString::fromLatin1("%1/%2").arg(localPath, name())), uis); - } + if (!uis.isEmpty()) + loadUserInterfaces(QDir(QString::fromLatin1("%1/%2").arg(localTempPath(), name())), uis); const QStringList qms = update->data(QLatin1String("Translations")).toString() .split(QString::fromLatin1(","), QString::SkipEmptyParts); - if (!qms.isEmpty()) { - verbose() << "Loading translations for component " << name() << std::endl; - loadTranslations(QDir(QString::fromLatin1("%1/%2").arg(localPath, name())), qms); - } + if (!qms.isEmpty()) + loadTranslations(QDir(QString::fromLatin1("%1/%2").arg(localTempPath(), name())), qms); QHash<QString, QVariant> licenseHash = update->data(QLatin1String("Licenses")).toHash(); - if (!licenseHash.isEmpty()) { - verbose() << "Loading licenses for component " << name() << std::endl; - loadLicenses(QString::fromLatin1("%1/%2/").arg(localPath, name()), licenseHash); - } - + if (!licenseHash.isEmpty()) + loadLicenses(QString::fromLatin1("%1/%2/").arg(localTempPath(), name()), licenseHash); } void Component::updateState(const bool selected) { setValue(QLatin1String("PreviousState"), selected ? QLatin1String("Installed") : QLatin1String("Uninstalled")); - setValue(QLatin1String("CurrentState"), - value(QLatin1String("PreviousState"))); + setValue(QLatin1String("CurrentState"), value(QLatin1String("PreviousState"))); } - - void Component::markAsPerformedInstallation() { d->m_newlyInstalled = true; } /*! - \property Component::removeBeforeUpdate - Specifies wheter this component gets removed by the installer system before it gets updated. - Get this property's value by using %removeBeforeUpdate(), and set it - using %setRemoveBeforeUpdate(). The default value is true. - */ + \property Component::removeBeforeUpdate + Specifies wheter this component gets removed by the installer system before it gets updated. + Get this property's value by using %removeBeforeUpdate(), and set it + using %setRemoveBeforeUpdate(). The default value is true. +*/ bool Component::removeBeforeUpdate() const { return d->removeBeforeUpdate; } -void Component::setRemoveBeforeUpdate( bool removeBeforeUpdate ) +void Component::setRemoveBeforeUpdate(bool removeBeforeUpdate) { d->removeBeforeUpdate = removeBeforeUpdate; } QList<Component*> Component::dependees() const { - return d->m_installer->dependees( this ); + return d->m_installer->dependees(this); } /* - Returns a key/value based hash of all variables set for this component. - */ + Returns a key/value based hash of all variables set for this component. +*/ QHash<QString,QString> Component::variables() const { return d->m_vars; } /*! - Returns the value of variable name \a key. If \a key is not known yet, \a defaultValue is returned. - */ -QString Component::value(const QString &key, - const QString &defaultValue) const + Returns the value of variable name \a key. + If \a key is not known yet, \a defaultValue is returned. +*/ +QString Component::value(const QString &key, const QString &defaultValue) const { return d->m_vars.value(key, defaultValue); } /*! - Sets the value of the variable with \a key to \a value. + Sets the value of the variable with \a key to \a value. */ void Component::setValue(const QString &key, const QString &value) { - if( d->m_vars[ key ] == value ) + if (d->m_vars[key] == value) return; - d->m_vars[ key ] = value; - emit valueChanged( key, value ); + d->m_vars[key] = value; + emit valueChanged(key, value); } /*! - Returnst the installer this component belongs to. + Returnst the installer this component belongs to. */ Installer* Component::installer() const { @@ -409,101 +264,102 @@ Installer* Component::installer() const } /*! - Returns the parent of this component. If this component is com.nokia.sdk.qt, its - parent is com.nokia.sdk, as far as this exists. - */ -Component* Component::parentComponent( RunModes runMode ) const + Returns the parent of this component. If this component is com.nokia.sdk.qt, its + parent is com.nokia.sdk, as far as this exists. +*/ +Component* Component::parentComponent(RunModes runMode) const { - if ( runMode == UpdaterMode ) + if (runMode == UpdaterMode) return 0; - else - return d->m_parent; + return d->m_parent; } /*! Appends \a component as a child of this component. If \a component already has a parent, it is removed from the previous parent. - */ -void Component::appendComponent( Component* component ) +*/ +void Component::appendComponent(Component* component) { - d->m_components.append( component ); - if( component->parentComponent() != 0 ) - component->d->m_parent->d->m_components.removeAll( component ); + d->m_components.append(component); + if (component->parentComponent() != 0) + component->d->m_parent->d->m_components.removeAll(component); component->d->m_parent = this; } /*! - Returns a list of child components. If \a recursive is set to true, the returned list - contains not only the direct children, but all ancestors. - */ -QList< Component* > Component::components( bool recursive, RunModes runMode ) const -{ - if ( runMode == UpdaterMode ) - return QList < Component* >(); - if( !recursive ) + Returns a list of child components. If \a recursive is set to true, the returned list + contains not only the direct children, but all ancestors. +*/ +QList<Component*> Component::childComponents(bool recursive, RunModes runMode) const +{ + if (runMode == UpdaterMode) + return QList<Component*>(); + + if (!recursive) return d->m_components; - QList< Component* > result; - for( QList< Component* >::const_iterator it = d->m_components.begin(); it != d->m_components.end(); ++it ) - { - result.append( *it ); - result += (*it)->components( true ); + QList<Component*> result; + foreach (Component *component, d->m_components) { + result.append(component); + result += component->childComponents(true); } return result; } /*! - Contains this component's name (unique identifier). - */ + Contains this component's name (unique identifier). +*/ QString Component::name() const { - return value( QLatin1String( "Name" ) ); + return value(skName); } /*! - Contains this component's display name (as visible to the user). - */ + Contains this component's display name (as visible to the user). +*/ QString Component::displayName() const { - return value( QLatin1String( "DisplayName" ) ); + return value(skDisplayName); } void Component::loadComponentScript() { - const QString script = value(QLatin1String("Script")); - if (!localTempPath().isEmpty() && !script.isEmpty()) { - loadComponentScript(QString::fromLatin1("%1/%2/%3").arg( - d->localTempPath, name(), script)); - } + const QString script = value(skScript); + if (!localTempPath().isEmpty() && !script.isEmpty()) + loadComponentScript(QString::fromLatin1("%1/%2/%3").arg(localTempPath(), name(), script)); } /*! - Loads the script at \a fileName into this component's script engine. - The installer and all its components as well as other useful stuff are being exported into the script. - Read \link componentscripting Component Scripting \endlink for details. - \throws Error when either the script at \a fileName couldn't be opened, or the QScriptEngine couldn't evaluate the script. - */ -void Component::loadComponentScript( const QString& fileName ) -{ - QFile file( fileName ); - if( !file.open( QIODevice::ReadOnly ) ) - throw Error( QObject::tr( "Could not open the requested script file at %1: %2" ).arg( fileName, file.errorString() ) ); - d->scriptEngine.evaluate( QLatin1String( file.readAll() ), fileName ); - if( d->scriptEngine.hasUncaughtException() ) { - throw Error( QObject::tr( "Exception while loading the component script %1" ) - .arg(uncaughtExceptionString(&(d->scriptEngine)/*, QFileInfo(file).absoluteFilePath()*/)) ); + Loads the script at \a fileName into this component's script engine. The installer and all its + components as well as other useful stuff are being exported into the script. + Read \link componentscripting Component Scripting \endlink for details. + \throws Error when either the script at \a fileName couldn't be opened, or the QScriptEngine + couldn't evaluate the script. +*/ +void Component::loadComponentScript(const QString &fileName) +{ + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) { + throw Error(QObject::tr("Could not open the requested script file at %1: %2").arg(fileName, + file.errorString())); } - const QList< Component* > components = d->m_installer->components( true ); - QScriptValue comps = d->scriptEngine.newArray( components.count() ); - for( int i = 0; i < components.count(); ++i ) { - comps.setProperty( i, d->scriptEngine.newQObject( components[ i ] ) ); + d->scriptEngine.evaluate(QLatin1String(file.readAll()), fileName); + if (d->scriptEngine.hasUncaughtException()) { + throw Error(QObject::tr("Exception while loading the component script %1") + .arg(uncaughtExceptionString(&(d->scriptEngine)/*, QFileInfo(file).absoluteFilePath()*/))); } - d->scriptEngine.globalObject().property( QLatin1String( "installer" ) ).setProperty( QLatin1String( "components" ), comps ); - QScriptValue comp = d->scriptEngine.evaluate( QLatin1String( "Component" ) ); - if( !d->scriptEngine.hasUncaughtException() ) - { + const QList<Component*> components = d->m_installer->components(true, d->m_installer->runMode()); + QScriptValue comps = d->scriptEngine.newArray(components.count()); + for (int i = 0; i < components.count(); ++i) + comps.setProperty(i, d->scriptEngine.newQObject(components[i])); + + d->scriptEngine.globalObject().property(QLatin1String("installer")) + .setProperty(QLatin1String("components"), comps); + + QScriptValue comp = d->scriptEngine.evaluate(QLatin1String("Component")); + if (!d->scriptEngine.hasUncaughtException()) { d->scriptComponent = comp; d->scriptComponent.construct(); } @@ -513,89 +369,91 @@ void Component::loadComponentScript( const QString& fileName ) } /*! - \internal - Calls the script method \link retranslateUi() \endlink, if any. This is done whenever a QTranslator file is being loaded. - */ + \internal + Calls the script method \link retranslateUi() \endlink, if any. This is done whenever a + QTranslator file is being loaded. +*/ void Component::languageChanged() { - callScriptMethod( QLatin1String( "retranslateUi" ) ); + callScriptMethod(QLatin1String("retranslateUi")); } /*! - Tries to call the method with \a name within the script and returns the result. - If the method doesn't exist, an invalid result is returned. If the method has an uncaught exception, its string - representation is thrown as an Error exception. - \note The method is not called, if the current script context is the same method, to avoid infinite recursion. - */ -QScriptValue Component::callScriptMethod( const QString& methodName, const QScriptValueList& arguments ) -{ - if( !d->unexistingScriptMethods.value( methodName, true ) ) + Tries to call the method with \a name within the script and returns the result. If the method + doesn't exist, an invalid result is returned. If the method has an uncaught exception, its + string representation is thrown as an Error exception. + + \note The method is not called, if the current script context is the same method, to avoid + infinite recursion. +*/ +QScriptValue Component::callScriptMethod(const QString &methodName, const QScriptValueList& arguments) +{ + if (!d->unexistingScriptMethods.value(methodName, true)) return QScriptValue(); // don't allow such a recursion - if( d->scriptEngine.currentContext()->backtrace().first().startsWith( methodName ) ) + if (d->scriptEngine.currentContext()->backtrace().first().startsWith(methodName)) return QScriptValue(); - QScriptValue method = d->scriptComponent.property( QString::fromLatin1( "prototype" ) ).property( methodName ); - - if( !method.isValid() ) // this marks the method to be called not any longer - d->unexistingScriptMethods[ methodName ] = false; - - const QScriptValue result = method.call( d->scriptComponent, arguments ); + QScriptValue method = d->scriptComponent.property(QString::fromLatin1("prototype")) + .property(methodName); + if (!method.isValid()) // this marks the method to be called not any longer + d->unexistingScriptMethods[methodName] = false; - if( !result.isValid() ) + const QScriptValue result = method.call(d->scriptComponent, arguments); + if (!result.isValid()) return result; - if( d->scriptEngine.hasUncaughtException() ) - throw Error( uncaughtExceptionString(&(d->scriptEngine)/*, name()*/) ); + if (d->scriptEngine.hasUncaughtException()) + throw Error(uncaughtExceptionString(&(d->scriptEngine)/*, name()*/)); return result; } /*! - Loads the translations matching the name filters \a qms inside \a directory. - Only translations with a \link QFileInfo::baseName() baseName \endlink matching the - current locales \link QLocale::name() name \endlink are loaded. - Read \ref componenttranslation for details. - */ -void Component::loadTranslations( const QDir& directory, const QStringList& qms ) -{ - QDirIterator it( directory.path(), qms, QDir::Files ); - while( it.hasNext() ) - { + Loads the translations matching the name filters \a qms inside \a directory. Only translations + with a \link QFileInfo::baseName() baseName \endlink matching the current locales \link + QLocale::name() name \endlink are loaded. + Read \ref componenttranslation for details. +*/ +void Component::loadTranslations(const QDir& directory, const QStringList& qms) +{ + QDirIterator it(directory.path(), qms, QDir::Files); + while (it.hasNext()) { const QString filename = it.next(); - if( QFileInfo( filename ).baseName().toLower() != QLocale().name().toLower() ) + if (QFileInfo(filename).baseName().toLower() != QLocale().name().toLower()) continue; - std::auto_ptr<QTranslator> translator( new QTranslator( this ) ); - if( !translator->load( filename ) ) - throw Error( tr( "Could not open the requested translation file at %1" ).arg( filename ) ); - qApp->installTranslator( translator.release() ); + QScopedPointer<QTranslator> translator(new QTranslator(this)); + if (!translator->load(filename)) + throw Error(tr("Could not open the requested translation file at %1").arg(filename)); + qApp->installTranslator(translator.take()); } } /*! - Loads the user interface files matching the name filters \a uis inside \a directory. - The loaded interface can be accessed via userInterfaces by using the class name set in the ui file. - Read \ref componentuserinterfaces for details. - */ -void Component::loadUserInterfaces( const QDir& directory, const QStringList& uis ) + Loads the user interface files matching the name filters \a uis inside \a directory. The loaded + interface can be accessed via userInterfaces by using the class name set in the ui file. + Read \ref componentuserinterfaces for details. +*/ +void Component::loadUserInterfaces(const QDir& directory, const QStringList& uis) { - if( QApplication::type() == QApplication::Tty ) + if (QApplication::type() == QApplication::Tty) return; - QDirIterator it( directory.path(), uis, QDir::Files ); - while( it.hasNext() ) - { - QFile file( it.next() ); - if( !file.open( QIODevice::ReadOnly ) ) - throw Error( tr( "Could not open the requested UI file at %1: %2" ).arg( it.fileName(), file.errorString() ) ); + QDirIterator it(directory.path(), uis, QDir::Files); + while (it.hasNext()) { + QFile file(it.next()); + if (!file.open(QIODevice::ReadOnly)) { + throw Error(tr("Could not open the requested UI file at %1: %2").arg(it.fileName(), + file.errorString())); + } static QUiLoader loader; - loader.setTranslationEnabled( true ); - loader.setLanguageChangeEnabled( true ); - QWidget* const w = loader.load( &file ); - d->userInterfaces[ w->objectName() ] = w; + loader.setTranslationEnabled(true); + loader.setLanguageChangeEnabled(true); + QWidget* const w = loader.load(&file); + d->userInterfaces[w->objectName()] = w; } } @@ -606,8 +464,8 @@ void Component::loadLicenses(const QString &directory, const QHash<QString, QVar for (it = licenseHash.begin(); it != licenseHash.end(); ++it) { const QString &fileName = it.value().toString(); QFile file(directory + fileName); - if(!file.open(QIODevice::ReadOnly)) { - throw Error(tr("Could not open the requested license file at %1: %2" ).arg(fileName, + if (!file.open(QIODevice::ReadOnly)) { + throw Error(tr("Could not open the requested license file at %1: %2").arg(fileName, file.errorString())); } d->m_licenses.insert(it.key(), qMakePair(fileName, QTextStream(&file).readAll())); @@ -615,8 +473,8 @@ void Component::loadLicenses(const QString &directory, const QHash<QString, QVar } /*! - Contains a list of all user interface class names known to this component. - */ + Contains a list of all user interface class names known to this component. +*/ QStringList Component::userInterfaces() const { return d->userInterfaces.keys(); @@ -628,220 +486,225 @@ QHash<QString, QPair<QString, QString> > Component::licenses() const } /*! - Returns the QWidget created for class \a name. - */ -QWidget* Component::userInterface( const QString& name ) const + Returns the QWidget created for class \a name. +*/ +QWidget* Component::userInterface(const QString &name) const { - return d->userInterfaces.value( name ); + return d->userInterfaces.value(name); } /*! - Creates all operations needed to install this component's \a path. - \a path is a full qualified filename including the component's name. - This metods gets called from Component::createOperationsForArchive. - You can override this method by providing a method with the same name in the component script. - \note If you call this method from a script, it won't call the scripts method with the same name. - \note RSA signature files are omitted by this method. + Creates all operations needed to install this component's \a path. \a path is a full qualified + filename including the component's name. This metods gets called from + Component::createOperationsForArchive. You can override this method by providing a method with + the same name in the component script. + + \note RSA signature files are omitted by this method. + \note If you call this method from a script, it won't call the scripts method with the same name. - The default implemention is recursively creating Copy and Mkdir operations for all files - and folders within \a path. - */ -void Component::createOperationsForPath( const QString& path ) + The default implemention is recursively creating Copy and Mkdir operations for all files + and folders within \a path. +*/ +void Component::createOperationsForPath(const QString &path) { - const QFileInfo fi( path ); + const QFileInfo fi(path); // don't copy over a signature - if( fi.suffix() == QLatin1String( "sig" ) && QFileInfo( fi.dir(), fi.completeBaseName() ).exists() ) + if (fi.suffix() == QLatin1String("sig") && QFileInfo(fi.dir(), fi.completeBaseName()).exists()) return; // the script can override this method - if( callScriptMethod( QLatin1String( "createOperationsForPath" ), QScriptValueList() << path ).isValid() ) + if (callScriptMethod(QLatin1String("createOperationsForPath"), QScriptValueList() << path).isValid()) return; - static const QString zipPrefix = QString::fromLatin1( "7z://installer://" ); - static const QString prefix = QString::fromLatin1( "installer://" ); QString target; - if ( path.startsWith( zipPrefix ) ) { // if the path is an archive, remove the archive file name from the target path - target = path.mid( zipPrefix.length() + name().length() + 1 ); // + 1 for the / - const int nextSlash = target.indexOf( QLatin1Char('/') ); - if ( nextSlash != -1 ) - target = target.mid( nextSlash ); + static const QString zipPrefix = QString::fromLatin1("7z://installer://"); + // if the path is an archive, remove the archive file name from the target path + if (path.startsWith(zipPrefix)) { + target = path.mid(zipPrefix.length() + name().length() + 1); // + 1 for the / + const int nextSlash = target.indexOf(QLatin1Char('/')); + if (nextSlash != -1) + target = target.mid(nextSlash); else target.clear(); target.prepend(QLatin1String("@TargetDir@")); + } else { + static const QString prefix = QString::fromLatin1("installer://"); + target = QString::fromLatin1("@TargetDir@%1").arg(path.mid(prefix.length() + name().length())); } - else - target = QString::fromLatin1( "@TargetDir@%1" ).arg( path.mid( prefix.length() + name().length() ) ); - static const QString copy = QString::fromLatin1( "Copy" ); - static const QString mkdir = QString::fromLatin1( "Mkdir" ); - if( fi.isFile() ) - { - addOperation( copy, fi.filePath(), target ); - } - else if( fi.isDir() ) - { + + if (fi.isFile()) { + static const QString copy = QString::fromLatin1("Copy"); + addOperation(copy, fi.filePath(), target); + } else if (fi.isDir()) { qApp->processEvents(); - addOperation( mkdir, target ); - QDirIterator it( fi.filePath() ); - while( it.hasNext() ) - createOperationsForPath( it.next() ); - } + static const QString mkdir = QString::fromLatin1("Mkdir"); + addOperation(mkdir, target); + QDirIterator it(fi.filePath()); + while (it.hasNext()) + createOperationsForPath(it.next()); + } } /*! - Creates all operations needed to install this component's \a archive. - This metods gets called from Component::createOperations. - You can override this method by providing a method with the same name in the component script. - \note If you call this method from a script, it won't call the scripts method with the same name. - - The default implementation calls createOperationsForPath for everything contained in the archive. - If \a archive is a compressed archive known to the installer system, an Extract operation is created, instead. - */ -void Component::createOperationsForArchive( const QString& archive ) + Creates all operations needed to install this component's \a archive. This metods gets called + from Component::createOperations. You can override this method by providing a method with the + same name in the component script. + + \note If you call this method from a script, it won't call the scripts method with the same name. + + The default implementation calls createOperationsForPath for everything contained in the archive. + If \a archive is a compressed archive known to the installer system, an Extract operation is + created, instead. +*/ +void Component::createOperationsForArchive(const QString &archive) { // the script can override this method - if( callScriptMethod( QLatin1String( "createOperationsForArchive" ), QScriptValueList() << archive ).isValid() ) + if (callScriptMethod(QLatin1String("createOperationsForArchive"), QScriptValueList() << archive).isValid()) return; - const QFileInfo fi( QString::fromLatin1( "installer://%1/%2").arg( name(), archive ) ); - const bool isZip = Lib7z::isSupportedArchive( fi.filePath() ); + const QFileInfo fi(QString::fromLatin1("installer://%1/%2").arg(name(), archive)); + const bool isZip = Lib7z::isSupportedArchive(fi.filePath()); - if( !isZip ) - createOperationsForPath( fi.filePath() ); - else + if (isZip) { // archives get completely extracted per default (if the script isn't doing other stuff) - addOperation( QLatin1String( "Extract" ), fi.filePath(), QLatin1String( "@TargetDir@" ) ); + addOperation(QLatin1String("Extract"), fi.filePath(), QLatin1String("@TargetDir@")); + } else { + createOperationsForPath(fi.filePath()); + } } /*! - Creates all operations needed to install this component. - You can override this method by providing a method with the same name in the component script. - \note If you call this method from a script, it won't call the scripts method with the same name. - - The default implementation calls createOperationsForArchive for all archives in this component. + Creates all operations needed to install this component. + You can override this method by providing a method with the same name in the component script. + + \note If you call this method from a script, it won't call the scripts method with the same name. + + The default implementation calls createOperationsForArchive for all archives in this component. */ void Component::createOperations() { // the script can override this method - if( callScriptMethod( QLatin1String( "createOperations" ) ).isValid() ) - { + if (callScriptMethod(QLatin1String("createOperations")).isValid()) { d->operationsCreated = true; return; } - const QDir dir( QString::fromLatin1( "installer://%1/" ).arg( name() ) ); - const QStringList archives = dir.entryList(); - for( QStringList::const_iterator it = archives.begin(); it != archives.end(); ++it ) - createOperationsForArchive( *it ); + foreach (const QString &archive, archives()) + createOperationsForArchive(archive); d->operationsCreated = true; } /*! - Registers the file or directory at \a path for being removed when this component gets uninstalled. - In case of a directory, this will be recursive. - If \a wipe is set to true, the directory will also be deleted if it contains changes done by the user - after installation. + Registers the file or directory at \a path for being removed when this component gets uninstalled. + In case of a directory, this will be recursive. If \a wipe is set to true, the directory will + also be deleted if it contains changes done by the user after installation. */ -void Component::registerPathForUninstallation( const QString& path, bool wipe ) +void Component::registerPathForUninstallation(const QString &path, bool wipe) { - d->pathesForUninstallation.append( qMakePair( path, wipe ) ); + d->pathesForUninstallation.append(qMakePair(path, wipe)); } /*! - Returns the list of pathes previously registered for uninstallation with #registerPathForUninstallation. + Returns the list of pathes previously registered for uninstallation with + #registerPathForUninstallation. */ -QList< QPair< QString, bool > > Component::pathesForUninstallation() const +QList<QPair<QString, bool> > Component::pathesForUninstallation() const { return d->pathesForUninstallation; } /*! - Contains the names of all archives known to this component. This does not contain archives added - with #addDownloadableArchive. - */ + Contains the names of all archives known to this component. This does not contain archives added + with #addDownloadableArchive. +*/ QStringList Component::archives() const { - return QDir( QString::fromLatin1( "installer://%1/" ).arg( name() ) ).entryList(); + return QDir(QString::fromLatin1("installer://%1/").arg(name())).entryList(); } /*! - Adds the archive \a path to this component. This can only be called when this component was downloaded from - an online repository. When adding \a path, it will be downloaded from the repository when the installation starts. - Read \ref sec_repogen for details. - \sa fromOnlineRepository - */ -void Component::addDownloadableArchive( const QString& path ) -{ - Q_ASSERT( isFromOnlineRepository() ); - const QString versionPrefix = value( QLatin1String( "Version" ) ); + Adds the archive \a path to this component. This can only be called when this component was + downloaded from an online repository. When adding \a path, it will be downloaded from the + repository when the installation starts. + + Read \ref sec_repogen for details. \sa fromOnlineRepository +*/ +void Component::addDownloadableArchive(const QString &path) +{ + Q_ASSERT(isFromOnlineRepository()); + + const QString versionPrefix = value(skVersion); verbose() << "addDownloadable " << path << std::endl; - d->downloadableArchives.append( versionPrefix + path ); + d->downloadableArchives.append(versionPrefix + path); } - + /*! - Removes the archive \a path previously added via addDownloadableArchive from this component. This can oly be - called when this component was downloaded from an online repository. Read \ref sec_repogen for details. - */ -void Component::removeDownloadableArchive( const QString& path ) + Removes the archive \a path previously added via addDownloadableArchive from this component. + This can oly be called when this component was downloaded from an online repository. + + Read \ref sec_repogen for details. +*/ +void Component::removeDownloadableArchive(const QString &path) { - Q_ASSERT( isFromOnlineRepository() ); - d->downloadableArchives.removeAll( path ); + Q_ASSERT(isFromOnlineRepository()); + d->downloadableArchives.removeAll(path); } /*! - Returns the archives to be downloaded from the online repository before installation. - */ + Returns the archives to be downloaded from the online repository before installation. +*/ QStringList Component::downloadableArchives() const { return d->downloadableArchives; } /*! - * Adds a request for quitting the process @p process before installing/updating/uninstalling the - * component. - */ -void Component::addStopProcessForUpdateRequest( const QString& process ) + Adds a request for quitting the process @p process before installing/updating/uninstalling the + component. +*/ +void Component::addStopProcessForUpdateRequest(const QString &process) { - d->stopProcessForUpdateRequests.append( process ); + d->stopProcessForUpdateRequests.append(process); } /*! -* Removes the request for quitting the process @p process again. + Removes the request for quitting the process @p process again. */ -void Component::removeStopProcessForUpdateRequest( const QString& process ) +void Component::removeStopProcessForUpdateRequest(const QString &process) { - d->stopProcessForUpdateRequests.removeAll( process ); + d->stopProcessForUpdateRequests.removeAll(process); } /*! -* Convenience: Add/remove request depending on @p requested (add if @p true, remove if @p false). + Convenience: Add/remove request depending on @p requested (add if @p true, remove if @p false). */ -void Component::setStopProcessForUpdateRequest( const QString& process, bool requested ) +void Component::setStopProcessForUpdateRequest(const QString &process, bool requested) { - if ( requested ) - addStopProcessForUpdateRequest( process ); + if (requested) + addStopProcessForUpdateRequest(process); else - removeStopProcessForUpdateRequest( process ); + removeStopProcessForUpdateRequest(process); } /*! - * The list of processes this component needs to be closed before installing/updating/uninstalling - */ + The list of processes this component needs to be closed before installing/updating/uninstalling +*/ QStringList Component::stopProcessForUpdateRequests() const { return d->stopProcessForUpdateRequests; } /*! - Returns the operations needed to install this component. If autoCreateOperations is true, createOperations - is called, if no operations have been auto-created yet. - */ -QList< KDUpdater::UpdateOperation* > Component::operations() const + Returns the operations needed to install this component. If autoCreateOperations is true, + createOperations is called, if no operations have been auto-created yet. +*/ +QList<KDUpdater::UpdateOperation*> Component::operations() const { if (d->autoCreateOperations && !d->operationsCreated) { - const_cast< Component* >( this )->createOperations(); + const_cast<Component*>(this)->createOperations(); if (!d->minimumProgressOperation) { d->minimumProgressOperation = KDUpdater::UpdateOperationFactory::instance() @@ -867,23 +730,23 @@ QList< KDUpdater::UpdateOperation* > Component::operations() const } /*! - Adds \a operation to the list of operations needed to install this component. - */ -void Component::addOperation( KDUpdater::UpdateOperation* operation ) + Adds \a operation to the list of operations needed to install this component. +*/ +void Component::addOperation(KDUpdater::UpdateOperation* operation) { - d->operations.append( operation ); - if( FSEngineClientHandler::instance()->isActive() ) - operation->setValue( QLatin1String( "admin" ), true ); + d->operations.append(operation); + if (FSEngineClientHandler::instance()->isActive()) + operation->setValue(QLatin1String("admin"), true); } /*! - Adds \a operation to the list of operations needed to install this component. \a operation - is executed with elevated rights. - */ -void Component::addElevatedOperation( KDUpdater::UpdateOperation* operation ) + Adds \a operation to the list of operations needed to install this component. \a operation + is executed with elevated rights. +*/ +void Component::addElevatedOperation(KDUpdater::UpdateOperation* operation) { - addOperation( operation ); - operation->setValue( QLatin1String( "admin" ), true ); + addOperation(operation); + operation->setValue(QLatin1String("admin"), true); } bool Component::operationsCreatedSuccessfully() const @@ -891,322 +754,306 @@ bool Component::operationsCreatedSuccessfully() const return d->operationsCreatedSuccessfully; } -/*! - Creates and adds an installation operation for \a operation. Add any number of \a parameter1, \a parameter2, \a parameter3, \a parameter4, \a parameter5 and \a parameter6 - The contents of the parameters get variables like "@TargetDir@" replaced with their values, if contained. - \sa installeroperations - */ -bool Component::addOperation( const QString& operation, const QString& parameter1, const QString& parameter2, const QString& parameter3, const QString& parameter4, const QString& parameter5, const QString& parameter6, const QString& parameter7, const QString& parameter8, const QString& parameter9, const QString& parameter10 ) -{ - KDUpdater::UpdateOperation* const op = KDUpdater::UpdateOperationFactory::instance().create( operation ); - if( op == 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 ); - if ( button == QMessageBox::Abort ) - { +KDUpdater::UpdateOperation* Component::createOperation(const QString &operation, + 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) +{ + KDUpdater::UpdateOperation* op = KDUpdater::UpdateOperationFactory::instance().create(operation); + if (op == 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); + if (button == QMessageBox::Abort) d->operationsCreatedSuccessfully = false; - } - return false; + return op; } - if ( op->name() == QLatin1String( "Delete" ) ) - op->setValue( QLatin1String( "performUndo" ), false ); - op->setValue( QLatin1String( "installer" ), qVariantFromValue( d->m_installer ) ); - + + if (op->name() == QLatin1String("Delete")) + op->setValue(QLatin1String("performUndo"), false); + op->setValue(QLatin1String("installer"), qVariantFromValue(d->m_installer)); + QStringList arguments; - if( !parameter1.isNull() ) - arguments.append( parameter1 ); - if( !parameter2.isNull() ) - arguments.append( parameter2 ); - if( !parameter3.isNull() ) - arguments.append( parameter3 ); - if( !parameter4.isNull() ) - arguments.append( parameter4 ); - if( !parameter5.isNull() ) - arguments.append( parameter5 ); - if( !parameter6.isNull() ) - arguments.append( parameter6 ); - if( !parameter7.isNull() ) - arguments.append( parameter7 ); - if( !parameter8.isNull() ) - arguments.append( parameter8 ); - if( !parameter9.isNull() ) - arguments.append( parameter9 ); - if( !parameter10.isNull() ) - arguments.append( parameter10 ); - op->setArguments( d->m_installer->replaceVariables( arguments ) ); - - addOperation( op ); - - return true; + if (!parameter1.isNull()) + arguments.append(parameter1); + if (!parameter2.isNull()) + arguments.append(parameter2); + if (!parameter3.isNull()) + arguments.append(parameter3); + if (!parameter4.isNull()) + arguments.append(parameter4); + if (!parameter5.isNull()) + arguments.append(parameter5); + if (!parameter6.isNull()) + arguments.append(parameter6); + if (!parameter7.isNull()) + arguments.append(parameter7); + if (!parameter8.isNull()) + arguments.append(parameter8); + if (!parameter9.isNull()) + arguments.append(parameter9); + if (!parameter10.isNull()) + arguments.append(parameter10); + op->setArguments(d->m_installer->replaceVariables(arguments)); + + return op; } - /*! - Creates and adds an installation operation for \a operation. Add any number of \a parameter1, \a parameter2, \a parameter3, \a parameter4, \a parameter5 and \a parameter6 - The contents of the parameters get variables like "@TargetDir@" replaced with their values, if contained. \a operation is executed with - elevated rights. - \sa installeroperations - */ -bool Component::addElevatedOperation( const QString& operation, const QString& parameter1, const QString& parameter2, const QString& parameter3, const QString& parameter4, const QString& parameter5, const QString& parameter6, const QString& parameter7, const QString& parameter8, const QString& parameter9, const QString& parameter10 ) -{ - KDUpdater::UpdateOperation* const op = KDUpdater::UpdateOperationFactory::instance().create( operation ); - if( op == 0 ) - return false; - - op->setValue( QLatin1String( "installer" ), qVariantFromValue( d->m_installer ) ); - - QStringList arguments; - if( !parameter1.isNull() ) - arguments.append( parameter1 ); - if( !parameter2.isNull() ) - arguments.append( parameter2 ); - if( !parameter3.isNull() ) - arguments.append( parameter3 ); - if( !parameter4.isNull() ) - arguments.append( parameter4 ); - if( !parameter5.isNull() ) - arguments.append( parameter5 ); - if( !parameter6.isNull() ) - arguments.append( parameter6 ); - if( !parameter7.isNull() ) - arguments.append( parameter7 ); - if( !parameter8.isNull() ) - arguments.append( parameter8 ); - if( !parameter9.isNull() ) - arguments.append( parameter9 ); - if( !parameter10.isNull() ) - arguments.append( parameter10 ); - op->setArguments( d->m_installer->replaceVariables( arguments ) ); - - addElevatedOperation( op ); - - return true; + Creates and adds an installation operation for \a operation. Add any number of \a parameter1, + \a parameter2, \a parameter3, \a parameter4, \a parameter5 and \a parameter6. The contents of + the parameters get variables like "@TargetDir@" replaced with their values, if contained. + \sa installeroperations +*/ +bool Component::addOperation(const QString &operation, 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) +{ + if (KDUpdater::UpdateOperation *op = createOperation(operation, parameter1, parameter2, + parameter3, parameter4, parameter5, parameter6, parameter7, parameter8, parameter9, + parameter10)) { + addOperation(op); + return true; + } + + return false; } +/*! + Creates and adds an installation operation for \a operation. Add any number of \a parameter1, + \a parameter2, \a parameter3, \a parameter4, \a parameter5 and \a parameter6. The contents of + the parameters get variables like "@TargetDir@" replaced with their values, if contained. + \a operation is executed with elevated rights. + \sa installeroperations +*/ +bool Component::addElevatedOperation(const QString &operation, 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) +{ + if (KDUpdater::UpdateOperation *op = createOperation(operation, parameter1, parameter2, + parameter3, parameter4, parameter5, parameter6, parameter7, parameter8, parameter9, + parameter10)) { + addElevatedOperation(op); + return true; + } + + return false; +} /*! - Specifies wheter operations should be automatically created when the installation starts. This would be done by calling #createOperations. - If you set this to false, it's completely up to the component's script to create all operations. - */ + Specifies wheter operations should be automatically created when the installation starts. This + would be done by calling #createOperations. If you set this to false, it's completely up to the + component's script to create all operations. +*/ bool Component::autoCreateOperations() const { return d->autoCreateOperations; } -void Component::setAutoCreateOperations( bool autoCreateOperations ) +void Component::setAutoCreateOperations(bool autoCreateOperations) { d->autoCreateOperations = autoCreateOperations; } -Qt::CheckState Component::checkState( RunModes runMode ) const -{ - if ( runMode == UpdaterMode ) - return d->isCheckedFromUpdater ? Qt::Checked : Qt::Unchecked; - const QMap< const Component*, Qt::CheckState >::const_iterator it = Private::cachedCheckStates.find( this ); - if( it != Private::cachedCheckStates.end() ) - return *it; - const Qt::CheckState state = componentCheckState( this, runMode ); - Private::cachedCheckStates[ this ] = state; - return state; -} +//Qt::CheckState Component::checkState(RunModes runMode) const +//{ +// if (runMode == UpdaterMode) +// return d->isCheckedFromUpdater ? Qt::Checked : Qt::Unchecked; +// +// const QMap<const Component*, Qt::CheckState>::const_iterator it = +// ComponentPrivate::cachedCheckStates.find(this); +// if (it != ComponentPrivate::cachedCheckStates.end()) +// return *it; +// +// const Qt::CheckState state = componentCheckState(this, runMode); +// ComponentPrivate::cachedCheckStates[this] = state; +// return state; +//} /*! - \property Component::selected - Specifies wheter this component is selected for installation. - Get this property's value by using %isSelected(), and set it - using %setSelected(). - */ -bool Component::isSelected( RunModes runMode ) const -{ - const Qt::CheckState state = checkState( runMode ); + \property Component::selected + Specifies wheter this component is selected for installation. Get this property's value by using + %isSelected(), and set it using %setSelected(). +*/ +bool Component::isSelected(RunModes runMode) const +{ + const Qt::CheckState state = checkState(); + // const Qt::CheckState state = checkState(runMode); return state != Qt::Unchecked; } -//SelectMode means: -//NormalSelectMode - dependency errors and selectionChanged SIGNAL are emitted -//InitializeComponentTreeSelectMode - no dependency errors(maybe some components are not ready initialized), -// no selectionChanged SIGNAL needed and no recursion +/*! + SelectMode means: + NormalSelectMode - dependency errors and selectionChanged SIGNAL are emitted + + InitializeComponentTreeSelectMode - no dependency errors(maybe some components are not ready + initialized), no selectionChanged SIGNAL needed and no recursion +*/ void Component::setSelected(bool selected, RunModes runMode, SelectMode selectMode) { - if ( runMode == UpdaterMode ) - { + if (runMode == UpdaterMode) { verbose() << "Update selection" << std::endl; QStringList missingNames; - d->m_installer->dependencies( this, &missingNames ); + d->m_installer->dependencies(this, &missingNames); - if ( !missingNames.isEmpty() ) - { - const QString missingPackages = missingNames.join( QLatin1String( " " ) ); - if ( selectMode == NormalSelectMode ) { + if (!missingNames.isEmpty()) { + const QString missingPackages = missingNames.join(QLatin1String(" ")); + if (selectMode == NormalSelectMode) { MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), - QLatin1String( "DependenciesMissingError" ), tr( "Dependencies Missing" ), - tr( "The following required packages could not be found : %1!" ).arg( missingPackages ), - QMessageBox::Ok ); + QLatin1String("DependenciesMissingError"), tr("Dependencies Missing"), + tr("The following required packages could not be found : %1!") + .arg(missingPackages), QMessageBox::Ok); } verbose() << "Error occured missing dependencies" << missingPackages << std::endl; return; } else { verbose() << "No Error occured" << std::endl; } - const Qt::CheckState previousState = checkState( UpdaterMode ); + + const Qt::CheckState previousState = checkState(); + // const Qt::CheckState previousState = checkState(UpdaterMode); const Qt::CheckState newState = selected ? Qt::Checked : Qt::Unchecked; d->isCheckedFromUpdater = selected; + // we have to select all dependees as well - if ( selected ) - { + if (selected) { verbose() << "Update selected for " << name() <<std::endl; - const QList< Component* > dependees = d->m_installer->missingDependencies( this ); + const QList<Component*> dependees = d->m_installer->missingDependencies(this); d->setSelectedOnComponentList(dependees, true, runMode, selectMode); } - if( !selected ) - { + + if (!selected) { // if it got deselected, we have to deselect all dependees as well verbose() << "Update deselected" << name() << std::endl; - const QList< Component* > dependees = d->m_installer->dependees( this ); + const QList<Component*> dependees = d->m_installer->dependees(this); d->setSelectedOnComponentList(dependees, false, runMode, selectMode); } - //we need selectedChanged even it is not in the NormalSelectMode to check the running processes from script side - //for installpart it is working because we are selecting the components in the script as well - //TODO: change this ^ behaviour in scripts and code - if( /*selectMode == NormalSelectMode && */newState != previousState ) - QMetaObject::invokeMethod( this, "selectedChanged", Qt::QueuedConnection, Q_ARG( bool, newState == Qt::Checked ) ); + // we need selectedChanged even it is not in the NormalSelectMode to check the running + // processes from script side for installpart it is working because we are selecting the + // components in the script as well + //TODO: change this ^ behaviour in scripts and code + if (newState != previousState) { + QMetaObject::invokeMethod(this, "selectedChanged", Qt::QueuedConnection, + Q_ARG(bool, newState == Qt::Checked)); + } } else { - QMap< Component*, Qt::CheckState > previousStates; - const QList< Component* > allComponents = d->m_installer->components( true ); - for( QList< Component* >::const_iterator it = allComponents.begin(); it != allComponents.end(); ++it ) - previousStates[ *it ] = (*it)->checkState(); + QMap<Component*, Qt::CheckState> previousStates; + const QList<Component*> allComponents = d->m_installer->components(true, AllMode); + foreach (Component *component, allComponents) + previousStates[component] = component->checkState(); - setValue( QString::fromLatin1( "WantedState" ), selected ? QString::fromLatin1( "Installed" ) : QString::fromLatin1( "Uninstalled" ) ); - Private::cachedCheckStates.clear(); + setValue(QString::fromLatin1("WantedState"), + selected ? QString::fromLatin1("Installed") : QString::fromLatin1("Uninstalled")); + ComponentPrivate::cachedCheckStates.clear(); - if ( selected ) - { + if (selected) { verbose() << "Update selected for " << name() << std::endl; - const QList< Component* > dependees = d->m_installer->missingDependencies( this ); + const QList<Component*> dependees = d->m_installer->missingDependencies(this); d->setSelectedOnComponentList(dependees, true, runMode, selectMode); } - if( !selected ) - { + if (!selected) { // if it got deselected, we have to deselect all dependees as well - const QList< Component* > dependees = d->m_installer->dependees( this ); + const QList<Component*> dependees = d->m_installer->dependees(this); d->setSelectedOnComponentList(dependees, false, runMode, selectMode); } // and all children - if ( selectMode == NormalSelectMode ) - { - const QList< Component* > children = components( true ); - for( QList< Component* >::const_iterator it = children.begin(); it != children.end(); ++it ) - { - Component* const comp = *it; - comp->setValue( QString::fromLatin1( "WantedState" ), selected ? QString::fromLatin1( "Installed" ) : QString::fromLatin1( "Uninstalled" ) ); + if (selectMode == NormalSelectMode) { + const QList<Component*> children = childComponents(true); + foreach (Component *child, children) { + child->setValue(QString::fromLatin1("WantedState"), + selected ? QString::fromLatin1("Installed") : QString::fromLatin1("Uninstalled")); } //now all needed components are selected so we can emit the signals - for( QList< Component* >::const_iterator it = allComponents.begin(); it != allComponents.end(); ++it ) - { - const Qt::CheckState newCheckState = (*it)->checkState(); - if( previousStates[ *it ] != newCheckState ) - QMetaObject::invokeMethod( *it, "selectedChanged", Qt::QueuedConnection, Q_ARG( bool, newCheckState == Qt::Checked ) ); - //emit (*it)->selectedChanged( state == Qt::Checked ); + foreach (Component *component, allComponents) { + const Qt::CheckState newCheckState = component->checkState(); + if (previousStates[component] != newCheckState) { + QMetaObject::invokeMethod(component, "selectedChanged", Qt::QueuedConnection, + Q_ARG(bool, newCheckState == Qt::Checked)); + } } } } } /*! - * Contains this component dependencies. - * Read \ref componentdependencies for details. - */ + Contains this component dependencies. + Read \ref componentdependencies for details. +*/ QStringList Component::dependencies() const { - return value( QLatin1String( "Dependencies" ) ).split( QLatin1Char( ',' ) ); + return value(skDependencies).split(QLatin1Char(',')); } /*! - * Determines if the component is installed - */ + Determines if the component is installed +*/ bool Component::isInstalled() const { - return QLatin1String( "Installed" ) == value( QLatin1String( "CurrentState" ) ); + return QLatin1String("Installed") == value(QLatin1String("CurrentState")); } /*! - * Determines if the user wants to install the component - */ + Determines if the user wants to install the component +*/ bool Component::installationRequested() const { - return ( QLatin1String( "Installed" ) == value( QLatin1String( "WantedState" ) ) && ( !isInstalled() || isSelected( UpdaterMode ) ) ); + return (QLatin1String("Installed") == value(QLatin1String("WantedState")) + && (!isInstalled() || isSelected(UpdaterMode))); } /*! - * Determines if the user wants to install the component - */ + Determines if the user wants to install the component +*/ bool Component::uninstallationRequested() const { - return QLatin1String( "Uninstalled" ) == value( QLatin1String( "WantedState" ) ) && isInstalled(); + return QLatin1String("Uninstalled") == value(QLatin1String("WantedState")) && isInstalled(); } /*! - * Determines if the component was installed recently - */ + Determines if the component was installed recently +*/ bool Component::wasInstalled() const { - return QLatin1String( "Uninstalled" ) == value( QLatin1String( "PreviousState" ) ) && isInstalled(); + return QLatin1String("Uninstalled") == value(QLatin1String("PreviousState")) && isInstalled(); } /*! - * Determines if the component was removed recently - */ + Determines if the component was removed recently +*/ bool Component::wasUninstalled() const { - return QLatin1String( "Installed" ) == value( QLatin1String( "PreviousState" ) ) && !isInstalled(); + return QLatin1String("Installed") == value(QLatin1String("PreviousState")) && !isInstalled(); } /*! - * Determines if the components installations status can be changed. - */ -bool Component::isEnabled() const -{ - return d->enabled; -} -/*! - * Enables oder disables ability to change the components installations status. - */ -void Component::setEnabled( bool enabled ) -{ - d->enabled = enabled; -} + \property Component::fromOnlineRepository -/*! - * \property Component::fromOnlineRepository - * Determines wheter this component has been loaded from an online repository. - * Get this property's value by usinng %isFromOnlineRepository. - * \sa addDownloadableArchive - */ + Determines wheter this component has been loaded from an online repository. Get this property's + value by usinng %isFromOnlineRepository. \sa addDownloadableArchive +*/ bool Component::isFromOnlineRepository() const { return !repositoryUrl().isEmpty(); } /*! - * Contains the repository Url this component is downloaded from. - * When this component is not downloaded from an online repository, returns an empty #QUrl. - */ + Contains the repository Url this component is downloaded from. + When this component is not downloaded from an online repository, returns an empty #QUrl. +*/ QUrl Component::repositoryUrl() const { return d->repositoryUrl; } /*! - \internal - Sets this components #repositoryUrl. + Sets this components #repositoryUrl. */ -void Component::setRepositoryUrl( const QUrl& url ) +void Component::setRepositoryUrl(const QUrl& url) { d->repositoryUrl = url; } diff --git a/installerbuilder/libinstaller/qinstallercomponent.h b/installerbuilder/libinstaller/qinstallercomponent.h index dda43f5b0..82d85699b 100644 --- a/installerbuilder/libinstaller/qinstallercomponent.h +++ b/installerbuilder/libinstaller/qinstallercomponent.h @@ -1,38 +1,41 @@ /************************************************************************** ** -** This file is part of Qt SDK** +* *This file is part of Qt SDK** ** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).* +* *Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).* ** -** Contact: Nokia Corporation qt-info@nokia.com** +* *Contact: Nokia Corporation qt-info@nokia.com** ** -** GNU Lesser General Public License Usage +* *GNU Lesser General Public License Usage ** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +* *This file may be used under the terms of the GNU Lesser General Public +* *License version 2.1 as published by the Free Software Foundation and +* *appearing in the file LICENSE.LGPL included in the packaging of this file. +* *Please review the following information to ensure the GNU Lesser General +* *Public License version 2.1 requirements will be met: +* *http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception version -** 1.1, included in the file LGPL_EXCEPTION.txt in this package. +* *In addition, as a special exception, Nokia gives you certain additional +* *rights. These rights are described in the Nokia Qt LGPL Exception version +* *1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** If you are unsure which license is appropriate for your use, please contact -** (qt-info@nokia.com). +* *If you are unsure which license is appropriate for your use, please contact +* *(qt-info@nokia.com). ** **************************************************************************/ #ifndef QINSTALLER_COMPONENT_H #define QINSTALLER_COMPONENT_H -#include <QObject> -#include <QScriptable> -#include <QUrl> +#include "qinstallerglobal.h" +#include "qinstallercomponent_p.h" -#include "qinstaller.h" // friend QInstaller::Private +#include <QtCore/QDir> +#include <QtCore/QMetaType> +#include <QtCore/QObject> +#include <QtCore/QUrl> -class QDir; +#include <QtScript/QScriptable> +#include <QtScript/QScriptValueList> namespace KDUpdater { class Update; @@ -41,168 +44,184 @@ namespace KDUpdater { } namespace QInstaller { - class Installer; -class INSTALLER_EXPORT Component : public QObject, public QScriptable +class INSTALLER_EXPORT Component : public QObject, public QScriptable, public ComponentModelHelper { Q_OBJECT - Q_PROPERTY( QString name READ name ) - Q_PROPERTY( QString displayName READ displayName ) - Q_PROPERTY( bool selected READ isSelected WRITE setSelected ) - Q_PROPERTY( bool autoCreateOperations READ autoCreateOperations WRITE setAutoCreateOperations ) - Q_PROPERTY( QStringList archives READ archives ) - Q_PROPERTY( QStringList userInterfaces READ userInterfaces ) - Q_PROPERTY( QStringList dependencies READ dependencies ) - Q_PROPERTY( bool fromOnlineRepository READ isFromOnlineRepository ) - Q_PROPERTY( QUrl repositoryUrl READ repositoryUrl ) - Q_PROPERTY( bool removeBeforeUpdate READ removeBeforeUpdate WRITE setRemoveBeforeUpdate ) - Q_PROPERTY( bool installed READ isInstalled ) - Q_PROPERTY( bool enabled READ isEnabled WRITE setEnabled) + Q_DISABLE_COPY(Component); + + Q_PROPERTY(QString name READ name) + Q_PROPERTY(QString displayName READ displayName) + Q_PROPERTY(bool selected READ isSelected WRITE setSelected) + Q_PROPERTY(bool autoCreateOperations READ autoCreateOperations WRITE setAutoCreateOperations) + Q_PROPERTY(QStringList archives READ archives) + Q_PROPERTY(QStringList userInterfaces READ userInterfaces) + Q_PROPERTY(QStringList dependencies READ dependencies) + Q_PROPERTY(bool fromOnlineRepository READ isFromOnlineRepository) + Q_PROPERTY(QUrl repositoryUrl READ repositoryUrl) + Q_PROPERTY(bool removeBeforeUpdate READ removeBeforeUpdate WRITE setRemoveBeforeUpdate) + Q_PROPERTY(bool installed READ isInstalled) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) public: - enum SelectMode{NormalSelectMode, InitializeComponentTreeSelectMode}; - explicit Component( Installer *installer ); + explicit Component(Installer *installer); + explicit Component(KDUpdater::Update *update, Installer *installer); ~Component(); - void loadDataFromPackageInfo(const KDUpdater::PackageInfo &packageInfo); - void loadDataFromUpdate(KDUpdater::Update* update); + enum SelectMode { + NormalSelectMode, + InitializeComponentTreeSelectMode + }; - //TODO: remove this, it makes no sense - void updateState(const bool selected); + struct IsVirtual + { + bool operator() (const Component *comp) const + { + return comp->value(QLatin1String("Virtual"), QLatin1String("false")) + .toLower() == QLatin1String("true"); + } + }; - struct PriorityLessThan + struct InstallPriorityLessThan { - bool operator()( const Component* lhs, const Component* rhs ) + bool operator() (const Component *lhs, const Component *rhs) { - return lhs->value( QLatin1String( "InstallPriority" ) ).toInt() < rhs->value( QLatin1String( "InstallPriority" ) ).toInt(); + const QLatin1String priority("InstallPriority"); + return lhs->value(priority).toInt() < rhs->value(priority).toInt(); } }; - Q_INVOKABLE void setValue(const QString &key, const QString &value); - Q_INVOKABLE QString value(const QString &key, - const QString &defaultValue = QString()) const; + struct SortingPriorityLessThan + { + bool operator() (const Component *lhs, const Component *rhs) const + { + const QLatin1String priority("SortingPriority"); + return lhs->value(priority).toInt() < rhs->value(priority).toInt(); + } + }; + + void loadDataFromPackageInfo(const KDUpdater::PackageInfo &packageInfo); + void loadDataFromUpdate(KDUpdater::Update* update); + + //TODO: remove this, it makes no sense + void updateState(const bool selected); + QHash<QString, QString> variables() const; + Q_INVOKABLE void setValue(const QString &key, const QString &value); + Q_INVOKABLE QString value(const QString &key, const QString &defaultValue = QString()) const; QStringList archives() const; + Installer *installer() const; - Installer* installer() const; - Component* parentComponent( RunModes runMode = InstallerMode ) const; - void appendComponent( Component* component ); - QList<Component*> components( bool recursive = false, RunModes runMode = InstallerMode ) const; + void appendComponent(Component *component); + Component *parentComponent(RunModes runMode = AllMode) const; + QList<Component*> childComponents(bool recursive = false, RunModes runMode = AllMode) const; void loadComponentScript(); //move this to private - void loadComponentScript( const QString& fileName ); - void loadTranslations( const QDir& directory, const QStringList& qms ); - void loadUserInterfaces( const QDir& directory, const QStringList& uis ); + void loadComponentScript(const QString &fileName); + void loadTranslations(const QDir &directory, const QStringList &qms); + void loadUserInterfaces(const QDir &directory, const QStringList &uis); void loadLicenses(const QString &directory, const QHash<QString, QVariant> &hash); void markAsPerformedInstallation(); QStringList userInterfaces() const; QHash<QString, QPair<QString, QString> > licenses() const; - Q_INVOKABLE QWidget* userInterface( const QString& name ) const; + Q_INVOKABLE QWidget *userInterface(const QString &name) const; Q_INVOKABLE virtual void createOperations(); - Q_INVOKABLE virtual void createOperationsForArchive( const QString& archive ); - Q_INVOKABLE virtual void createOperationsForPath( const QString& path ); - - Q_INVOKABLE void registerPathForUninstallation( const QString& path, bool wipe = false ); - Q_INVOKABLE QList< QPair< QString, bool > > pathesForUninstallation() const; - - QList< KDUpdater::UpdateOperation* > operations() const; - void addOperation( KDUpdater::UpdateOperation* operation ); - void addElevatedOperation( KDUpdater::UpdateOperation* operation ); - Q_INVOKABLE bool addOperation( const QString& operation, const QString& parameter1 = QString(), - const QString& parameter2 = QString(), - const QString& parameter3 = QString(), - const QString& parameter4 = QString(), - const QString& parameter5 = QString(), - const QString& parameter6 = QString(), - const QString& parameter7 = QString(), - const QString& parameter8 = QString(), - const QString& parameter9 = QString(), - const QString& parameter10 = QString() ); - - Q_INVOKABLE bool addElevatedOperation( const QString& operation, const QString& parameter1 = QString(), - const QString& parameter2 = QString(), - const QString& parameter3 = QString(), - const QString& parameter4 = QString(), - const QString& parameter5 = QString(), - const QString& parameter6 = QString(), - const QString& parameter7 = QString(), - const QString& parameter8 = QString(), - const QString& parameter9 = QString(), - const QString& parameter10 = QString() ); - - - Q_INVOKABLE void addDownloadableArchive( const QString& path ); - Q_INVOKABLE void removeDownloadableArchive( const QString& path ); + Q_INVOKABLE virtual void createOperationsForArchive(const QString &archive); + Q_INVOKABLE virtual void createOperationsForPath(const QString &path); + + Q_INVOKABLE QList<QPair<QString, bool> > pathesForUninstallation() const; + Q_INVOKABLE void registerPathForUninstallation(const QString &path, bool wipe = false); + + QList<KDUpdater::UpdateOperation*> operations() const; + + void addOperation(KDUpdater::UpdateOperation *operation); + Q_INVOKABLE bool addOperation(const QString &operation, 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()); + + void addElevatedOperation(KDUpdater::UpdateOperation *operation); + Q_INVOKABLE bool addElevatedOperation(const QString &operation, + 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()); QStringList downloadableArchives() const; - - Q_INVOKABLE void addStopProcessForUpdateRequest( const QString& process ); - Q_INVOKABLE void removeStopProcessForUpdateRequest( const QString& process ); - Q_INVOKABLE void setStopProcessForUpdateRequest( const QString& process, bool requested ); + Q_INVOKABLE void addDownloadableArchive(const QString &path); + Q_INVOKABLE void removeDownloadableArchive(const QString &path); QStringList stopProcessForUpdateRequests() const; + Q_INVOKABLE void addStopProcessForUpdateRequest(const QString &process); + Q_INVOKABLE void removeStopProcessForUpdateRequest(const QString &process); + Q_INVOKABLE void setStopProcessForUpdateRequest(const QString &process, bool requested); QString name() const; QString displayName() const; QUrl repositoryUrl() const; - void setRepositoryUrl( const QUrl& url ); - QString localTempPath() const; - void setLocalTempPath(const QString &tempPath); - - bool removeBeforeUpdate() const; - void setRemoveBeforeUpdate( bool removeBeforeUpdate ); + void setRepositoryUrl(const QUrl &url); - Q_INVOKABLE bool isFromOnlineRepository() const; + bool removeBeforeUpdate() const; + void setRemoveBeforeUpdate(bool removeBeforeUpdate); QStringList dependencies() const; + QList<Component*> dependees() const; + + void languageChanged(); + QString localTempPath() const; bool autoCreateOperations() const; - bool isSelected( RunModes runMode = InstallerMode ) const; + bool operationsCreatedSuccessfully() const; + Q_INVOKABLE bool isInstalled() const; Q_INVOKABLE bool installationRequested() const; Q_INVOKABLE bool uninstallationRequested() const; Q_INVOKABLE bool wasInstalled() const; Q_INVOKABLE bool wasUninstalled() const; - bool isEnabled() const; - void setEnabled( bool enabled ); - - bool operationsCreatedSuccessfully() const; - - Qt::CheckState checkState( RunModes runMode = InstallerMode ) const; - - void languageChanged(); + Q_INVOKABLE bool isFromOnlineRepository() const; - QList<Component*> dependees() const; + // TODO: remove the selected stuff + bool isSelected(RunModes runMode = AllMode) const; + //Qt::CheckState checkState(RunModes runMode) const; - friend class ::QInstaller::Installer; - friend class ::QInstaller::Installer::Private; +public Q_SLOTS: + void setAutoCreateOperations(bool autoCreateOperations); + void setSelected(bool selected, RunModes runMode = AllMode, SelectMode selectMode = NormalSelectMode); Q_SIGNALS: - void valueChanged( const QString& key, const QString& value ); - void selectedChanged( bool selected ); void loaded(); - -public Q_SLOTS: - void setAutoCreateOperations( bool autoCreateOperations ); - void setSelected(bool selected, RunModes runMode = InstallerMode, SelectMode selectMode = NormalSelectMode ); + void selectedChanged(bool selected); + void valueChanged(const QString &key, const QString &value); protected: - QScriptValue callScriptMethod( const QString& name, const QScriptValueList& parameters = QScriptValueList() ); + QScriptValue callScriptMethod(const QString &name, + const QScriptValueList ¶meters = QScriptValueList()); private: - Q_DISABLE_COPY(Component); - class Private; - Private* const d; + void setLocalTempPath(const QString &tempPath); + + KDUpdater::UpdateOperation *createOperation(const QString &operation, + 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()); + +private: + ComponentPrivate *d; }; -} +} // namespace QInstaller -Q_DECLARE_METATYPE( QInstaller::Component* ); +Q_DECLARE_METATYPE(QInstaller::Component*); #endif // QINSTALLER_COMPONENT_H diff --git a/installerbuilder/libinstaller/qinstallercomponent_p.cpp b/installerbuilder/libinstaller/qinstallercomponent_p.cpp new file mode 100644 index 000000000..11774083c --- /dev/null +++ b/installerbuilder/libinstaller/qinstallercomponent_p.cpp @@ -0,0 +1,247 @@ +/************************************************************************** +** +** This file is part of Qt SDK** +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).* +** +** Contact: Nokia Corporation qt-info@nokia.com** +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception version +** 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you are unsure which license is appropriate for your use, please contact +** (qt-info@nokia.com). +** +**************************************************************************/ +#include "qinstallercomponent_p.h" + +#include "messageboxhandler.h" +#include "qinstaller.h" +#include "qinstallercomponent.h" + +#include <QtGui/QApplication> +#include <QtGui/QDesktopServices> + +namespace QInstaller { + +QMap<const Component*, Qt::CheckState> ComponentPrivate::cachedCheckStates; + +ComponentPrivate::ComponentPrivate(Installer* installer, Component* qq) + : q(qq), + m_flags(Qt::ItemIsEnabled | Qt::ItemIsSelectable| Qt::ItemIsUserCheckable), + m_checkState(Qt::Unchecked), + m_installer(installer), + m_parent(0), + m_offsetInInstaller(0), + autoCreateOperations(true), + operationsCreated(false), + removeBeforeUpdate(true), + isCheckedFromUpdater(false), + m_newlyInstalled (false), + operationsCreatedSuccessfully(true), + minimumProgressOperation(0), + m_licenseOperation(0) +{ +} + +void ComponentPrivate::init() +{ + // register translation stuff + scriptEngine.installTranslatorFunctions(); + + // register QMessageBox::StandardButton enum in the script connection + registerMessageBox(&scriptEngine); + + // register QDesktopServices in the script connection + QScriptValue desktopServices = scriptEngine.newArray(); + desktopServices.setProperty(QLatin1String("DesktopLocation"), scriptEngine.newVariant(static_cast< int >(QDesktopServices::DesktopLocation))); + desktopServices.setProperty(QLatin1String("DocumentsLocation"), scriptEngine.newVariant(static_cast< int >(QDesktopServices::DocumentsLocation))); + desktopServices.setProperty(QLatin1String("FontsLocation"), scriptEngine.newVariant(static_cast< int >(QDesktopServices::FontsLocation))); + desktopServices.setProperty(QLatin1String("ApplicationsLocation"), scriptEngine.newVariant(static_cast< int >(QDesktopServices::ApplicationsLocation))); + desktopServices.setProperty(QLatin1String("MusicLocation"), scriptEngine.newVariant(static_cast< int >(QDesktopServices::MusicLocation))); + desktopServices.setProperty(QLatin1String("MoviesLocation"), scriptEngine.newVariant(static_cast< int >(QDesktopServices::MoviesLocation))); + desktopServices.setProperty(QLatin1String("PicturesLocation"), scriptEngine.newVariant(static_cast< int >(QDesktopServices::PicturesLocation))); + desktopServices.setProperty(QLatin1String("TempLocation"), scriptEngine.newVariant(static_cast< int >(QDesktopServices::TempLocation))); + desktopServices.setProperty(QLatin1String("HomeLocation"), scriptEngine.newVariant(static_cast< int >(QDesktopServices::HomeLocation))); + desktopServices.setProperty(QLatin1String("DataLocation"), scriptEngine.newVariant(static_cast< int >(QDesktopServices::DataLocation))); + desktopServices.setProperty(QLatin1String("CacheLocation"), scriptEngine.newVariant(static_cast< int >(QDesktopServices::CacheLocation))); + + desktopServices.setProperty(QLatin1String("openUrl"), scriptEngine.newFunction(qDesktopServicesOpenUrl)); + desktopServices.setProperty(QLatin1String("displayName"), scriptEngine.newFunction(qDesktopServicesDisplayName)); + desktopServices.setProperty(QLatin1String("storageLocation"), scriptEngine.newFunction(qDesktopServicesStorageLocation)); + scriptEngine.globalObject().setProperty(QLatin1String("QDesktopServices"), desktopServices); + + // register ::WizardPage enum in the script connection + QScriptValue qinstaller = scriptEngine.newArray(); + qinstaller.setProperty(QLatin1String("Introduction"), scriptEngine.newVariant(static_cast< int >(Installer::Introduction))); + qinstaller.setProperty(QLatin1String("LicenseCheck"), scriptEngine.newVariant(static_cast< int >(Installer::LicenseCheck))); + qinstaller.setProperty(QLatin1String("TargetDirectory"), scriptEngine.newVariant(static_cast< int >(Installer::TargetDirectory))); + qinstaller.setProperty(QLatin1String("ComponentSelection"), scriptEngine.newVariant(static_cast< int >(Installer::ComponentSelection))); + qinstaller.setProperty(QLatin1String("StartMenuSelection"), scriptEngine.newVariant(static_cast< int >(Installer::StartMenuSelection))); + qinstaller.setProperty(QLatin1String("ReadyForInstallation"), scriptEngine.newVariant(static_cast< int >(Installer::ReadyForInstallation))); + qinstaller.setProperty(QLatin1String("PerformInstallation"), scriptEngine.newVariant(static_cast< int >(Installer::PerformInstallation))); + qinstaller.setProperty(QLatin1String("InstallationFinished"), scriptEngine.newVariant(static_cast< int >(Installer::InstallationFinished))); + qinstaller.setProperty(QLatin1String("End"), scriptEngine.newVariant(static_cast< int >(Installer::End))); + + // register ::Status enum in the script connection + qinstaller.setProperty(QLatin1String("InstallerSuccess"), scriptEngine.newVariant(static_cast< int >(Installer::Success))); + qinstaller.setProperty(QLatin1String("InstallerSucceeded"), scriptEngine.newVariant(static_cast< int >(Installer::Success))); + qinstaller.setProperty(QLatin1String("InstallerFailed"), scriptEngine.newVariant(static_cast< int >(Installer::Failure))); + qinstaller.setProperty(QLatin1String("InstallerFailure"), scriptEngine.newVariant(static_cast< int >(Installer::Failure))); + qinstaller.setProperty(QLatin1String("InstallerRunning"), scriptEngine.newVariant(static_cast< int >(Installer::Running))); + qinstaller.setProperty(QLatin1String("InstallerCanceled"), scriptEngine.newVariant(static_cast< int >(Installer::Canceled))); + qinstaller.setProperty(QLatin1String("InstallerCanceledByUser"), scriptEngine.newVariant(static_cast< int >(Installer::Canceled))); + qinstaller.setProperty(QLatin1String("InstallerUnfinished"), scriptEngine.newVariant(static_cast< int >(Installer::Unfinished))); + + + scriptEngine.globalObject().setProperty(QLatin1String("QInstaller"), qinstaller); + scriptEngine.globalObject().setProperty(QLatin1String("component"), scriptEngine.newQObject(q)); + QScriptValue installerObject = scriptEngine.newQObject(m_installer); + installerObject.setProperty(QLatin1String("componentByName"), scriptEngine.newFunction(qInstallerComponentByName, 1)); + scriptEngine.globalObject().setProperty(QLatin1String("installer"), installerObject); +} + +void ComponentPrivate::setSelectedOnComponentList(const QList<Component*> &componentList, + bool selected, RunModes runMode, int selectMode) +{ + foreach (Component *component, componentList) { + if (!component->isSelected(runMode)) { + // TODO: fix this or remove + //component->setSelected(selected, runMode, selectMode); + } + } +} + + +// -- ComponentModelHelper + +ComponentModelHelper::ComponentModelHelper() +{ +} + +ComponentModelHelper::~ComponentModelHelper() +{ +} + +/*! + Returns the number of child components. +*/ +int ComponentModelHelper::childCount() const +{ + return m_componentPrivate->m_components.count(); +} + +/*! + Returns the index of this component as seen from it's parent. +*/ +int ComponentModelHelper::indexInParent() const +{ + if (Component *parent = m_componentPrivate->m_parent->parentComponent()) + return parent->childComponents().indexOf(m_componentPrivate->m_parent); + return 0; +} + +/*! + Returns the component at index position in the list. Index must be a valid position in + the list (i.e., index >= 0 && index < childCount()). Otherwise it returns 0. +*/ +Component* ComponentModelHelper::childAt(int index) const +{ + if (index >= 0 && index < childCount()) + return m_componentPrivate->m_components.value(index, 0); + return 0; +} + +/*! + Determines if the components installations status can be changed. +*/ +bool ComponentModelHelper::isEnabled() const +{ + return (flags() & Qt::ItemIsEnabled) != 0; +} +/*! + Enables oder disables ability to change the components installations status. +*/ +void ComponentModelHelper::setEnabled(bool enabled) +{ + changeFlags(enabled, Qt::ItemIsEnabled); +} + +bool ComponentModelHelper::isTristate() const +{ + return (flags() & Qt::ItemIsTristate) != 0; +} + +void ComponentModelHelper::setTristate(bool tristate) +{ + changeFlags(tristate, Qt::ItemIsTristate); +} + +bool ComponentModelHelper::isCheckable() const +{ + return (flags() & Qt::ItemIsUserCheckable) != 0; +} + +void ComponentModelHelper::setCheckable(bool checkable) +{ + changeFlags(checkable, Qt::ItemIsUserCheckable); +} + +bool ComponentModelHelper::isSelectable() const +{ + return (flags() & Qt::ItemIsSelectable) != 0; +} + +void ComponentModelHelper::setSelectable(bool selectable) +{ + changeFlags(selectable, Qt::ItemIsSelectable); +} + +Qt::ItemFlags ComponentModelHelper::flags() const +{ + return m_componentPrivate->m_flags; +} + +void ComponentModelHelper::setFlags(Qt::ItemFlags flags) +{ + m_componentPrivate->m_flags = flags; +} + +Qt::CheckState ComponentModelHelper::checkState() const +{ + return m_componentPrivate->m_checkState; +} + +void ComponentModelHelper::setCheckState(Qt::CheckState state) +{ + m_componentPrivate->m_checkState = state; +} + +void ComponentModelHelper::setPrivate(ComponentPrivate *componentPrivate) +{ + m_componentPrivate = componentPrivate; +} + +void ComponentModelHelper::changeFlags(bool enable, Qt::ItemFlags itemFlags) +{ + setFlags(enable ? flags() |= itemFlags : flags() &= ~itemFlags); +} + +} // namespace QInstaller diff --git a/installerbuilder/libinstaller/qinstallercomponent_p.h b/installerbuilder/libinstaller/qinstallercomponent_p.h new file mode 100644 index 000000000..0c2fcddce --- /dev/null +++ b/installerbuilder/libinstaller/qinstallercomponent_p.h @@ -0,0 +1,153 @@ +/************************************************************************** +** +** This file is part of Qt SDK** +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).* +** +** Contact: Nokia Corporation qt-info@nokia.com** +** +** No Commercial Usage +** +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception version +** 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you are unsure which license is appropriate for your use, please contact +** (qt-info@nokia.com). +** +**************************************************************************/ +#ifndef QINSTALLER_COMPONENT_P_H +#define QINSTALLER_COMPONENT_P_H + +#include "qinstallerglobal.h" + +#include <QtCore/QUrl> +#include <QtCore/QStringList> + +#include <QtScript/QScriptEngine> + +namespace KDUpdater { + class UpdateOperation; +} + +namespace QInstaller { +class Component; +class Installer; + +class ComponentPrivate +{ + QInstaller::Component* const q; + +public: + explicit ComponentPrivate(Installer* installer, Component* qq); + + void init(); + void setSelectedOnComponentList(const QList<Component*> &componentList, + bool selected, RunModes runMode, int selectMode); + + Qt::ItemFlags m_flags; + Qt::CheckState m_checkState; + + static QMap<const Component*, Qt::CheckState> cachedCheckStates; + + Installer *m_installer; + QHash<QString, QString> m_vars; + QList<Component*> m_components; + QList<KDUpdater::UpdateOperation* > operations; + + QList<QPair<QString, bool> > pathesForUninstallation; + + QMap<QString, QWidget*> userInterfaces; + + QUrl repositoryUrl; + QString localTempPath; + QStringList downloadableArchives; + QStringList stopProcessForUpdateRequests; + + Component* m_parent; + + // filled before intaller runs + qint64 m_offsetInInstaller; + + bool autoCreateOperations; + bool operationsCreated; + + bool removeBeforeUpdate; + + bool isCheckedFromUpdater; + + bool m_newlyInstalled; + + bool operationsCreatedSuccessfully; + + QScriptEngine scriptEngine; + QScriptValue scriptComponent; + + QHash<QString, bool> unexistingScriptMethods; + + KDUpdater::UpdateOperation* minimumProgressOperation; + + // < display name, < file name, file content > > + QHash<QString, QPair<QString, QString> > m_licenses; + KDUpdater::UpdateOperation *m_licenseOperation; +}; + + +// -- ComponentModelHelper + +class ComponentModelHelper +{ +public: + explicit ComponentModelHelper(); + ~ComponentModelHelper(); + + int childCount() const; + int indexInParent() const; + Component* childAt(int index) const; + + bool isEnabled() const; + void setEnabled(bool enabled); + + bool isTristate() const; + void setTristate(bool tristate); + + bool isCheckable() const; + void setCheckable(bool checkable); + + bool isSelectable() const; + void setSelectable(bool selectable); + + Qt::ItemFlags flags() const; + void setFlags(Qt::ItemFlags flags); + + Qt::CheckState checkState() const; + void setCheckState(Qt::CheckState state); + +protected: + void setPrivate(ComponentPrivate *componentPrivate); + +private: + void changeFlags(bool enable, Qt::ItemFlags itemFlags); + +private: + ComponentPrivate *m_componentPrivate; +}; + + +} // namespace QInstaller + +#endif // QINSTALLER_COMPONENT_P_H diff --git a/installerbuilder/libinstaller/qinstallercomponentmodel.cpp b/installerbuilder/libinstaller/qinstallercomponentmodel.cpp index 9bca06a36..f040e1279 100644 --- a/installerbuilder/libinstaller/qinstallercomponentmodel.cpp +++ b/installerbuilder/libinstaller/qinstallercomponentmodel.cpp @@ -32,168 +32,408 @@ **************************************************************************/ #include "qinstallercomponentmodel.h" -#include <algorithm> - +#include "common/utils.h" +#include "qinstaller.h" #include "qinstallercomponent.h" #include "qinstallerglobal.h" -#include "common/utils.h" +#include <QtScript/QScriptEngine> -#include <QApplication> -#include <QFont> -#include <QScriptEngine> +#include <algorithm> using namespace QInstaller; -struct ComponentIsVirtual +static QFont s_virtualComponentsFont; + +InstallerComponentModel::InstallerComponentModel(int columns, Installer *parent) + : QAbstractItemModel(parent) + , m_columns(columns) + , m_installer(parent) + , m_headerComponent(0) +{ +} + +InstallerComponentModel::~InstallerComponentModel() +{ +} + +int InstallerComponentModel::rowCount(const QModelIndex &parent) const +{ + if (Component *component = componentFromIndex(parent)) + return component->childCount(); + return 0; +} + +int InstallerComponentModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_columns; +} + +QModelIndex InstallerComponentModel::parent(const QModelIndex &child) const +{ + if (!child.isValid()) + return QModelIndex(); + + if (Component *childComponent = componentFromIndex(child)) { + if (Component *parent = childComponent->parentComponent()) { + if (parent != m_headerComponent) + return createIndex(parent->indexInParent(), 0, parent); + } + } + return QModelIndex(); +} + +QModelIndex InstallerComponentModel::index(int row, int column, const QModelIndex &parent) const { - bool operator()( const Component* comp ) const - { - return comp->value( QLatin1String( "Virtual" ), QLatin1String( "false" ) ).toLower() == QLatin1String( "true" ); + if (parent.isValid() && column >= columnCount(parent)) + return QModelIndex(); + + if (Component *parentComponent = componentFromIndex(parent)) { + if (Component *childComponent = parentComponent->childAt(row)) + return createIndex(row, column, childComponent); } -}; + return QModelIndex(); +} -struct ComponentPriorityLessThan +QVariant InstallerComponentModel::data(const QModelIndex &index, int role) const { - bool operator()( const Component* lhs, const Component* rhs ) const - { - return lhs->value( QLatin1String( "SortingPriority" ) ).toInt() < - rhs->value( QLatin1String( "SortingPriority" ) ).toInt(); + if (!index.isValid()) + return QVariant(); + + if (Component *component = componentFromIndex(index)) { + switch (index.column()) { + case NameColumn: { + switch (role) { + case Qt::EditRole: + case Qt::DisplayRole: + return component->displayName(); + case Qt::CheckStateRole: + return component->checkState(); + case Qt::ToolTipRole: { + return component->value(QLatin1String("Description")) + + QLatin1String("<br><br> Update Info: ") + + component->value(QLatin1String ("UpdateText")); + } + case Qt::FontRole:{ + return component->value(QLatin1String("Virtual")).toLower() + == QLatin1String("true") ? virtualComponentsFont() : QFont(); + } + default: + return QVariant(); + } + } break; + + case VersionColumn: { + if (role == Qt::DisplayRole) + return component->value(QLatin1String("Version")); + } break; + + case InstalledVersionColumn: { + if (role == Qt::DisplayRole) + return component->value(QLatin1String("InstalledVersion")); + } break; + + case SizeColumn: { + if (role == Qt::DisplayRole) { + double size = component->value(QLatin1String("UncompressedSize")).toDouble(); + if (size < 10000.0) + return tr("%L1 Bytes").arg(size); + size /= 1024.0; + if (size < 10000.0) + return tr("%L1 kB").arg(size, 0, 'f', 1); + size /= 1024.0; + if (size < 10000.0) + return tr("%L1 MB").arg(size, 0, 'f', 1); + size /= 1024.0; + return tr("%L1 GB").arg(size, 0, 'f', 1); + } + } break; + } } -}; + return QVariant(); +} + +bool InstallerComponentModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid()) + return false; + + Component *component = componentFromIndex(index); + if (!component || component == m_headerComponent) + return false; + + switch (role) { + case Qt::CheckStateRole: { + component->setCheckState(Qt::CheckState(value.toInt())); + } break; + default: + return false; + } + + return true; +} + +QVariant InstallerComponentModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + switch (section) { + case NameColumn: + return tr("Name"); + case InstalledVersionColumn: + return tr("Installed Version"); + case VersionColumn: + return tr("New Version"); + case SizeColumn: + return tr("Size"); + default: + return QAbstractItemModel::headerData(section, orientation, role); + } + } + return QAbstractItemModel::headerData(section, orientation, role); +} + +bool InstallerComponentModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, + int role) +{ + // TODO: implement + return true; +} + +Qt::ItemFlags InstallerComponentModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return m_headerComponent->flags(); + + if (Component *component = componentFromIndex(index)) + return component->flags(); + + return Qt::ItemIsEnabled | Qt::ItemIsSelectable| Qt::ItemIsUserCheckable; +} + +void InstallerComponentModel::setRootComponents(QList<Component*> rootComponents) +{ + beginResetModel(); + + m_cache.clear(); + // delete m_headerComponent; + + m_headerComponent = new Component(0); + foreach (Component *component, rootComponents) + m_headerComponent->appendComponent(component); + + const QModelIndex &root = index(0,0, QModelIndex()); + setupCache(root); + m_cache.insert(static_cast<Component*> (root.internalPointer()), root); + + endResetModel(); +} + +void InstallerComponentModel::appendRootComponents(QList<Component*> rootComponents) +{ + // TODO: implement +} + +QModelIndex InstallerComponentModel::indexFromComponent(Component *component) const +{ + return m_cache.value(component, QModelIndex()); +} + +Component* InstallerComponentModel::componentFromIndex(const QModelIndex &index) const +{ + if (index.isValid()) + return static_cast<Component*>(index.internalPointer()); + return m_headerComponent; +} + +QFont InstallerComponentModel::virtualComponentsFont() +{ + return s_virtualComponentsFont; +} + +void InstallerComponentModel::setVirtualComponentsFont(const QFont &font) +{ + s_virtualComponentsFont = font; +} + +void InstallerComponentModel::setupCache(const QModelIndex &parent) +{ + const QModelIndexList &list = collectComponents(parent); + foreach (const QModelIndex &index, list) + m_cache.insert(componentFromIndex(index), index); +} -bool checkCompleteUninstallation( const QInstaller::Component* component ) +QModelIndexList InstallerComponentModel::collectComponents(const QModelIndex &parent) const +{ + QModelIndexList list; + for (int i = rowCount(parent) - 1; i >= 0 ; --i) { + const QModelIndex &next = index(i, 0, parent); + if (Component *component = componentFromIndex(next)) { + verbose() << "Name: " << component->name() << ", Children: " + << component->childCount() << std::endl; + if (component->childCount() > 0) + list += collectComponents(next); + } + list.append(next); + } + return list; +} + + + + + + + + +bool checkCompleteUninstallation(const Component *component) { - const QList< QInstaller::Component* > components = component->components( true ); bool nonSelected = true; - Q_FOREACH( const QInstaller::Component* comp, components ) - { - if ( comp->isSelected() ) + const QList<Component*> components = component->childComponents(true); + foreach (const Component *comp, components) { + if (comp->isSelected()) nonSelected = false; - if ( !checkCompleteUninstallation( comp ) ) + if (!checkCompleteUninstallation(comp)) nonSelected = false; } return nonSelected; } -bool checkWorkRequest( const QInstaller::Component* component ) +bool checkWorkRequest(const Component *component) { //first check the component itself QString componentName = component->name(); - QString wantedState = component->value( QLatin1String( "WantedState" ) ); - QString currentState = component->value( QLatin1String( "CurrentState" ) ); - if (!wantedState.isEmpty() && !currentState.isEmpty() && wantedState != currentState ) { - verbose() << QLatin1String("request work for ") << componentName << QString(QLatin1String(" because WantedState(%1)!=CurrentState(%2)")).arg(wantedState, currentState)<<std::endl; + QString wantedState = component->value(QLatin1String("WantedState")); + QString currentState = component->value(QLatin1String("CurrentState")); + if (!wantedState.isEmpty() && !currentState.isEmpty() && wantedState != currentState) { + verbose() << QLatin1String("request work for ") << componentName + << QString::fromLatin1(" because WantedState(%1) != CurrentState(%2)").arg(wantedState, + currentState) << std::endl; return true; } //now checkWorkRequest for all childs - const QList< QInstaller::Component* > components = component->components( true ); - Q_FOREACH( const QInstaller::Component* currentComponent, components ) - { - if ( checkWorkRequest( currentComponent ) ) + const QList<Component*> components = component->childComponents(true); + foreach (const Component *component, components) { + if (checkWorkRequest(component)) return true; } return false; } -ComponentModel::ComponentModel( Installer* parent, RunModes runMode ) - : QAbstractItemModel( parent ), m_runMode( runMode ) + +// -- ComponentModel + +ComponentModel::ComponentModel(Installer *installer, RunModes runMode) + : QAbstractItemModel(installer) + , m_runMode(runMode) { + connect(installer, SIGNAL(startAllComponentsReset()), this, SLOT(clear())); + connect(installer, SIGNAL(rootComponentsAdded(QList<QInstaller::Component*>)), + this, SLOT(addRootComponents(QList<QInstaller::Component*>))); + + connect(installer, SIGNAL(startUpdaterComponentsReset()), this, SLOT(clear())); + connect(installer, SIGNAL(updaterComponentsAdded(QList<QInstaller::Component*>)), + this, SLOT(addRootComponents(QList<QInstaller::Component*>))); + + connect(installer, SIGNAL(componentAdded(QInstaller::Component*)), this, + SLOT(componentAdded(QInstaller::Component*))); +} - if ( runMode == InstallerMode ) - connect( parent, SIGNAL( rootComponentsAdded( QList< QInstaller::Component* > ) ), this, SLOT( addRootComponents(QList< QInstaller::Component* > ) ) ); - else - connect( parent, SIGNAL( updaterComponentsAdded( QList< QInstaller::Component* > ) ), this, SLOT( addRootComponents(QList< QInstaller::Component* > ) ) ); - connect( parent, SIGNAL( componentsAboutToBeCleared() ), this, SLOT( clear() ) ); - connect( parent, SIGNAL( componentAdded( QInstaller::Component* ) ), this, SLOT( componentAdded( QInstaller::Component* ) ) ); +ComponentModel::~ComponentModel() +{ } -void ComponentModel::addRootComponents( QList< Component* > rootComponents ) +void ComponentModel::addRootComponents(QList<Component*> rootComponents) { beginResetModel(); + bool requestWork = false; - Q_FOREACH( Component* currentRootComponent, rootComponents ) - { - if ( !m_components.contains( currentRootComponent ) ) - m_components.push_back( currentRootComponent ); - if ( checkWorkRequest( currentRootComponent ) ) { + foreach (Component *component, rootComponents) { + if (!m_components.contains(component)) + m_components.push_back(component); + + if (checkWorkRequest(component)) { requestWork = true; break; } } + endResetModel(); - emit workRequested( requestWork ); + emit workRequested(requestWork); } + void ComponentModel::clear() { beginResetModel(); + m_components.clear(); - seenComponents.clear(); + m_seenComponents.clear(); endResetModel(); } -ComponentModel::~ComponentModel() +void ComponentModel::setRunMode(RunModes runMode) { + m_runMode = runMode; } -void ComponentModel::selectedChanged( bool checked ) +void ComponentModel::selectedChanged(bool checked) { - Q_UNUSED( checked ) - Component *comp = dynamic_cast<Component*>( QObject::sender() ); - Q_ASSERT( comp ); + Q_UNUSED(checked) + Component *comp = qobject_cast<Component*>(QObject::sender()); + Q_ASSERT(comp); + bool requestWork = false; - Q_FOREACH( Component *c, comp->components( false, m_runMode ) ) { - if( !seenComponents.contains( c ) ) - { - connect( c, SIGNAL( selectedChanged( bool ) ), this, SLOT( selectedChanged( bool ) ) ); - seenComponents.push_back( c ); - } + foreach (Component *component, comp->childComponents(false, m_runMode)) { + if (!m_seenComponents.contains(component)) { + m_seenComponents.push_back(component); + connect(component, SIGNAL(selectedChanged(bool)), this, SLOT(selectedChanged(bool))); + } } - Q_FOREACH( const Component * currentComponent, m_components ) - { - if ( checkWorkRequest( currentComponent ) ) { + + foreach (const Component *component, m_components) { + if (checkWorkRequest(component)) { requestWork = true; break; } } - emit workRequested( requestWork ); - emit dataChanged( this->index( 0, 0 ), QModelIndex() ); + + emit workRequested(requestWork); + emit dataChanged(index(0, 0), QModelIndex()); } -void ComponentModel::componentAdded( Component* comp ) +void ComponentModel::componentAdded(QInstaller::Component *comp) { - Q_UNUSED( comp ) + Q_UNUSED(comp) reset(); } /*! \reimpl */ -QModelIndex ComponentModel::index( int row, int column, const QModelIndex& parent ) const +QModelIndex ComponentModel::index(int row, int column, const QModelIndex &parent) const { - if( row < 0 || row >= rowCount( parent ) ) + if (row < 0 || row >= rowCount(parent)) return QModelIndex(); - if( column < 0 || column >= columnCount( parent ) ) + if (column < 0 || column >= columnCount(parent)) return QModelIndex(); - QList< Component* > components = !parent.isValid() ? m_components - : reinterpret_cast< Component* >( parent.internalPointer() )->components( false, m_runMode ); + QList<Component*> components = !parent.isValid() ? m_components + : reinterpret_cast<Component*>(parent.internalPointer())->childComponents(false, m_runMode); // don't count virtual components - if( !virtualComponentsVisible() && m_runMode == InstallerMode ) - components.erase( std::remove_if( components.begin(), components.end(), ComponentIsVirtual() ), components.end() ); + if (!virtualComponentsVisible() && m_runMode == AllMode) { + components.erase(std::remove_if(components.begin(), components.end(), Component::IsVirtual()), + components.end()); + } // sort by priority - std::sort( components.begin(), components.end(), ComponentPriorityLessThan() ); + std::sort(components.begin(), components.end(), Component::SortingPriorityLessThan()); - Component* const comp = components[ row ]; - - QModelIndex index = createIndex( row, column, comp ); - - if( !seenComponents.contains( comp ) ) - { - connect( comp, SIGNAL( selectedChanged( bool ) ), this, SLOT( selectedChanged( bool ) ) ); - seenComponents.push_back( comp ); + Component *const component = components[row]; + QModelIndex index = createIndex(row, column, component); + if (!m_seenComponents.contains(component)) { + connect(component, SIGNAL(selectedChanged(bool)), this, SLOT(selectedChanged(bool))); + m_seenComponents.push_back(component); } return index; @@ -202,273 +442,300 @@ QModelIndex ComponentModel::index( int row, int column, const QModelIndex& paren /*! \reimpl */ -QModelIndex ComponentModel::parent( const QModelIndex& index ) const +QModelIndex ComponentModel::parent(const QModelIndex &index) const { - if( !index.isValid() ) + if (!index.isValid()) return QModelIndex(); - const Component* const component = reinterpret_cast< Component* >( index.internalPointer() ); - Component* const parentComponent = component->parentComponent( m_runMode ); - if( parentComponent == 0 ) + + const Component *const component = reinterpret_cast<Component*>(index.internalPointer()); + Component *const parentComponent = component->parentComponent(m_runMode); + if (parentComponent == 0) return QModelIndex(); - QList< Component* > parentSiblings = parentComponent->parentComponent() == 0 ? m_components - : parentComponent->parentComponent()->components( false, m_runMode ); + + QList<Component*> parentSiblings = parentComponent->parentComponent() == 0 ? m_components + : parentComponent->parentComponent()->childComponents(false, m_runMode); // don't count virtual components - if( !virtualComponentsVisible() && m_runMode == InstallerMode ) - parentSiblings.erase( std::remove_if( parentSiblings.begin(), parentSiblings.end(), ComponentIsVirtual() ), parentSiblings.end() ); + if (!virtualComponentsVisible() && m_runMode == AllMode) { + parentSiblings.erase(std::remove_if(parentSiblings.begin(), parentSiblings.end(), + Component::IsVirtual()), parentSiblings.end()); + } // sort by priority - std::sort( parentSiblings.begin(), parentSiblings.end(), ComponentPriorityLessThan() ); + std::sort(parentSiblings.begin(), parentSiblings.end(), Component::SortingPriorityLessThan()); - return createIndex( parentSiblings.indexOf( parentComponent ), 0, parentComponent ); + return createIndex(parentSiblings.indexOf(parentComponent), 0, parentComponent); } /*! \reimpl */ -int ComponentModel::columnCount( const QModelIndex& parent ) const +int ComponentModel::columnCount(const QModelIndex &parent) const { - Q_UNUSED( parent ); + Q_UNUSED(parent); return 4; } /*! \reimpl */ -int ComponentModel::rowCount( const QModelIndex& parent ) const +int ComponentModel::rowCount(const QModelIndex &parent) const { - if( parent.column() > 0 ) + if (parent.column() > 0) return 0; - QList< Component* > components = !parent.isValid() ? m_components - : reinterpret_cast< Component* >( parent.internalPointer() )->components( false, m_runMode ); - + QList<Component*> components = !parent.isValid() ? m_components + : reinterpret_cast<Component*>(parent.internalPointer())->childComponents(false, m_runMode); // don't count virtual components - if( !virtualComponentsVisible() && m_runMode == InstallerMode ) - components.erase( std::remove_if( components.begin(), components.end(), ComponentIsVirtual() ), components.end() ); - + if (!virtualComponentsVisible() && m_runMode == AllMode) { + components.erase(std::remove_if (components.begin(), components.end(), Component::IsVirtual()), + components.end()); + } return components.count(); } /*! \reimpl */ -Qt::ItemFlags ComponentModel::flags( const QModelIndex& index ) const +Qt::ItemFlags ComponentModel::flags(const QModelIndex &index) const { - Qt::ItemFlags result = QAbstractItemModel::flags( index ); - if ( !index.isValid() ) + Qt::ItemFlags result = QAbstractItemModel::flags(index); + if (!index.isValid()) return result; - const Component* const component = reinterpret_cast< Component* >( index.internalPointer() ); - const bool forcedInstallation = QVariant( component->value( QLatin1String( "ForcedInstallation" ) ) ).toBool(); + + const Component *const component = reinterpret_cast<Component*>(index.internalPointer()); + const bool forcedInstallation = QVariant(component->value(QLatin1String("ForcedInstallation"))).toBool(); if (m_runMode == UpdaterMode || !forcedInstallation) result |= Qt::ItemIsUserCheckable; - if ( !component->isEnabled() ) + + if (!component->isEnabled()) result &= Qt::ItemIsDropEnabled; - if (m_runMode == InstallerMode && forcedInstallation) { - result &= ~Qt::ItemIsEnabled; //now it should look like a disabled item + + if (m_runMode == AllMode && forcedInstallation) { + //now it should look like a disabled item + result &= ~Qt::ItemIsEnabled; } + return result; } /*! \reimpl */ -bool ComponentModel::setData( const QModelIndex& index, const QVariant& data, int role ) +bool ComponentModel::setData(const QModelIndex &index, const QVariant &data, int role) { - if( !index.isValid() ) + if (!index.isValid()) return false; - Component* const component = reinterpret_cast< Component* >( index.internalPointer() ); - switch( role ) - { + switch (role) { case Qt::CheckStateRole: { - if( !( flags( index ) & Qt::ItemIsUserCheckable ) ) + if (!(flags(index) & Qt::ItemIsUserCheckable)) return false; - const bool check = data.toInt() == Qt::Checked; - component->setSelected( check, m_runMode ); + + Component *const component = reinterpret_cast<Component*>(index.internalPointer()); + component->setSelected(data.toInt() == Qt::Checked, m_runMode); + bool requestWork = false; bool nonSelected = true; - Q_FOREACH( const QInstaller::Component* currentComponent, m_components ) - { - if ( checkWorkRequest( currentComponent ) ) { + + foreach (const Component *currentComponent, m_components) { + if (checkWorkRequest(currentComponent)) requestWork |= true; - } - if ( currentComponent->isSelected() ) + + if (currentComponent->isSelected()) nonSelected = false; - if ( !checkCompleteUninstallation( currentComponent ) ) + + if (!checkCompleteUninstallation(currentComponent)) nonSelected = false; } - if ( m_runMode == InstallerMode ) - { - Installer* installer = dynamic_cast< Installer* > ( QObject::parent() ); - installer->setCompleteUninstallation( nonSelected ); + + if (m_runMode == AllMode) { + Installer *installer = qobject_cast< Installer*> (QObject::parent()); + installer->setCompleteUninstallation(nonSelected); } - emit workRequested( requestWork ); + + emit workRequested(requestWork); return true; } + default: return false; } + + return false; } -Qt::CheckState QInstaller::componentCheckState( const Component* component, RunModes runMode ) +Qt::CheckState QInstaller::componentCheckState(const Component *component, RunModes runMode) { - if( QVariant( component->value( QLatin1String( "ForcedInstallation" ) ) ).toBool() ) + if (QVariant(component->value(QLatin1String("ForcedInstallation"))).toBool()) return Qt::Checked; - QString autoSelect = component->value( QLatin1String( "AutoSelectOn" ) ); + QString autoSelect = component->value(QLatin1String("AutoSelectOn")); // check the auto select expression - if( !autoSelect.isEmpty() ) - { + if (!autoSelect.isEmpty()) { QScriptEngine engine; - const QList< Component* > components = component->installer()->components( true, runMode ); - for( QList< Component* >::const_iterator it = components.begin(); it != components.end(); ++it ) - { - const Component* const c = *it; - if( c == component ) + // TODO: check why we use the function from QInstaller instead of Component + const QList<Component*> children = component->installer()->components(true, runMode); + foreach (Component *child, children) { + if (child == component) continue; - QString name = c->name(); - name.replace( QLatin1String( "." ), QLatin1String( "___" ) ); - engine.evaluate( QString::fromLatin1( "%1 = %2;" ).arg( name, QVariant( c ->isSelected() ).toString() ) ); + + QString name = child->name(); + name.replace(QLatin1String("."), QLatin1String("___")); + engine.evaluate(QString::fromLatin1("%1 = %2;").arg(name, + QVariant(child ->isSelected()).toString())); } - autoSelect.replace( QLatin1String( "." ), QLatin1String( "___" ) ); - if( engine.evaluate( autoSelect ).toBool() ) + + autoSelect.replace(QLatin1String("."), QLatin1String("___")); + if (engine.evaluate(autoSelect).toBool()) return Qt::Checked; } // if one of our dependees is checked, we are checked - const QList< Component* > dependees = component->dependees(); - for( QList< Component* >::const_iterator it = dependees.begin(); it != dependees.end(); ++it ) - { - if( *it == component ) - { + const QList<Component*> dependees = component->dependees(); + foreach (Component *dependent, dependees) { + if (dependent == component) { verbose() << "Infinite loop in dependencies detected, bailing out..." << std::endl; return Qt::Unchecked; } - const Qt::CheckState state = (*it)->checkState(); - if( state == Qt::Checked ) + + const Qt::CheckState state = dependent->checkState(); + if (state == Qt::Checked) return state; } // if the component has children then we need to check if all children are selected // to set the state to either checked if all children are selected or to unchecked // if no children are selected or otherwise to partially checked. + // TODO: check why we use the function from Component instead of QInstaller + QList<Component*> children = component->childComponents(true, runMode); + // don't count virtual components + children.erase(std::remove_if(children.begin(), children.end(), Component::IsVirtual()), children.end()); + bool foundChecked = false; bool foundUnchecked = false; - QList< Component* > children = component->components( true, runMode ); - // don't count virtual components - children.erase( std::remove_if( children.begin(), children.end(), ComponentIsVirtual() ), children.end() ); - if( !children.isEmpty() ) - { - for( QList< Component* >::const_iterator it = children.begin(); it != children.end(); ++it ) - { - const Qt::CheckState state = (*it)->checkState(); + if (!children.isEmpty()) { + foreach (Component *child, children) { + const Qt::CheckState state = child->checkState(); foundChecked = foundChecked || state == Qt::Checked || state == Qt::PartiallyChecked; foundUnchecked = foundUnchecked || state == Qt::Unchecked; } - if( foundChecked && foundUnchecked ) + + if (foundChecked && foundUnchecked) return Qt::PartiallyChecked; - else if( foundChecked && ! foundUnchecked ) + + if (foundChecked && ! foundUnchecked) return Qt::Checked; - else if( foundUnchecked && ! foundChecked ) + + if (foundUnchecked && ! foundChecked) return Qt::Unchecked; - //else fall through } // explicitely selected - if( component->value( QString::fromLatin1( "WantedState" ) ) == QString::fromLatin1( "Installed" ) ) + if (component->value(QString::fromLatin1("WantedState")) == QString::fromLatin1("Installed")) return Qt::Checked; // explicitely unselected - else if ( component->value( QString::fromLatin1( "WantedState" ) ) == QString::fromLatin1( "Uninstalled" ) ) + else if (component->value(QString::fromLatin1("WantedState")) == QString::fromLatin1("Uninstalled")) return Qt::Unchecked; // no decision made, use the predefined: - const QString suggestedState = component->value( QString::fromLatin1( "SuggestedState" ) ); - if( suggestedState == QString::fromLatin1( "Installed" ) ) + const QString suggestedState = component->value(QString::fromLatin1("SuggestedState")); + if (suggestedState == QString::fromLatin1("Installed")) return Qt::Checked; + return Qt::Unchecked; } /*! \reimp */ -QVariant ComponentModel::data( const QModelIndex& index, int role ) const +QVariant ComponentModel::data(const QModelIndex &index, int role) const { - if( !index.isValid() ) + if (!index.isValid()) return QVariant(); - Component* const component = reinterpret_cast< Component* >( index.internalPointer() ); + Component *const component = reinterpret_cast<Component*>(index.internalPointer()); - switch( index.column() ) - { + switch (index.column()) { case NameColumn: - switch( role ) + switch (role) { case Qt::EditRole: case Qt::DisplayRole: return component->displayName(); case Qt::CheckStateRole: - return component->checkState( m_runMode ); - case Qt::ToolTipRole: - return component->value( QString::fromLatin1( "Description" ) ) + QLatin1String( "<br><br> Update Info: " ) + component->value( QLatin1String ( "UpdateText" ) ) ; - case Qt::FontRole: - return component->value( QLatin1String( "Virtual" ), QLatin1String( "false" ) ).toLower() == QLatin1String( "true" ) ? virtualComponentsFont() : QFont(); + return component->checkState(); + // return component->checkState(m_runMode); + case Qt::ToolTipRole: { + return component->value(QString::fromLatin1("Description")) + + QLatin1String("<br><br> Update Info: ") + component->value(QLatin1String ("UpdateText")); + } + case Qt::FontRole:{ + return component->value(QLatin1String("Virtual"), + QLatin1String("false")).toLower() == QLatin1String("true") ? virtualComponentsFont() : QFont(); + } case ComponentRole: - return qVariantFromValue( component ); + return qVariantFromValue(component); case IdRole: return component->name(); default: return QVariant(); } + case VersionColumn: - if( role == Qt::DisplayRole ) - return component->value( QLatin1String( "Version" ) ); + if (role == Qt::DisplayRole) + return component->value(QLatin1String("Version")); break; + case InstalledVersionColumn: - if( role == Qt::DisplayRole ) - return component->value( QLatin1String( "InstalledVersion" ) ); + if (role == Qt::DisplayRole) + return component->value(QLatin1String("InstalledVersion")); break; + case SizeColumn: - if( role == Qt::DisplayRole ) - { - double size = component->value( QLatin1String( "UncompressedSize" ) ).toDouble(); - if( size < 10000.0 ) - return tr( "%L1 Bytes" ).arg( size ); + if (role == Qt::DisplayRole) { + double size = component->value(QLatin1String("UncompressedSize")).toDouble(); + if (size < 10000.0) + return tr("%L1 Bytes").arg(size); size /= 1024.0; - if( size < 10000.0 ) - return tr( "%L1 kB" ).arg( size, 0, 'f', 1 ); + if (size < 10000.0) + return tr("%L1 kB").arg(size, 0, 'f', 1); size /= 1024.0; - if( size < 10000.0 ) - return tr( "%L1 MB" ).arg( size, 0, 'f', 1 ); + if (size < 10000.0) + return tr("%L1 MB").arg(size, 0, 'f', 1); size /= 1024.0; - return tr( "%L1 GB" ).arg( size, 0, 'f', 1 ); + return tr("%L1 GB").arg(size, 0, 'f', 1); } break; } + return QVariant(); } /*! \reimp */ -QVariant ComponentModel::headerData( int section, Qt::Orientation orientation, int role ) const +QVariant ComponentModel::headerData(int section, Qt::Orientation orientation, int role) const { - if( orientation != Qt::Horizontal || role != Qt::DisplayRole ) - return QAbstractItemModel::headerData( section, orientation, role ); + if (orientation != Qt::Horizontal || role != Qt::DisplayRole) + return QAbstractItemModel::headerData(section, orientation, role); - switch( section ) - { + switch (section) { case NameColumn: - return tr( "Name" ); + return tr("Name"); + case InstalledVersionColumn: - return tr( "Installed Version" ); + return tr("Installed Version"); + case VersionColumn: - return tr( "New Version" ); + return tr("New Version"); + case SizeColumn: - return tr( "Size" ); + return tr("Size"); + default: - return QAbstractItemModel::headerData( section, orientation, role ); + return QAbstractItemModel::headerData(section, orientation, role); } } @@ -479,42 +746,39 @@ bool ComponentModel::virtualComponentsVisible() return s_virtualComponentsVisible; } -void ComponentModel::setVirtualComponentsVisible( bool visible ) +void ComponentModel::setVirtualComponentsVisible(bool visible) { s_virtualComponentsVisible = visible; } -static QFont s_virtualComponentsFont; - QFont ComponentModel::virtualComponentsFont() { return s_virtualComponentsFont; } -void ComponentModel::setVirtualComponentsFont( const QFont& f ) +void ComponentModel::setVirtualComponentsFont(const QFont &f) { s_virtualComponentsFont = f; } -QModelIndex ComponentModel::findComponent( const QString& id ) const +QModelIndex ComponentModel::findComponent(const QString &id) const { - QModelIndex idx = index( 0, NameColumn ); - while ( idx.isValid() && idx.data( IdRole ).toString() != id ) { - if ( rowCount( idx ) > 0 ) { - idx = idx.child( 0, NameColumn ); + QModelIndex idx = index(0, NameColumn); + while (idx.isValid() && idx.data(IdRole).toString() != id) { + if (rowCount(idx) > 0) { + idx = idx.child(0, NameColumn); continue; } bool foundNext = false; - - while ( !foundNext ) { + while (!foundNext) { const int oldRow = idx.row(); idx = idx.parent(); - const int rc = rowCount( idx ); - if ( oldRow < rc - 1 ) { - idx = index( oldRow + 1, NameColumn, idx ); + const int rc = rowCount(idx); + if (oldRow < rc - 1) { + idx = index(oldRow + 1, NameColumn, idx); foundNext = true; - } else if ( !idx.isValid() ) + } else if (!idx.isValid()) return idx; } } diff --git a/installerbuilder/libinstaller/qinstallercomponentmodel.h b/installerbuilder/libinstaller/qinstallercomponentmodel.h index bad7a4271..22214c738 100644 --- a/installerbuilder/libinstaller/qinstallercomponentmodel.h +++ b/installerbuilder/libinstaller/qinstallercomponentmodel.h @@ -26,70 +26,127 @@ #ifndef QINSTALLER_COMPONENTMODEL_H #define QINSTALLER_COMPONENTMODEL_H -#include <QAbstractItemModel> -#include <QList> +#include "qinstallerglobal.h" -#include "installer_global.h" +#include <QtCore/QAbstractItemModel> +#include <QtCore/QList> namespace QInstaller { -class Installer; class Component; +class Installer; + +typedef QMap<Component*, QPersistentModelIndex> ComponentModelIndexCache; + +class INSTALLER_EXPORT InstallerComponentModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + + enum Column { + NameColumn = 0, + InstalledVersionColumn, + VersionColumn, + SizeColumn + }; + + explicit InstallerComponentModel(int columns, Installer *parent = 0); + ~InstallerComponentModel(); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + + QModelIndex parent(const QModelIndex &child) const; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, + int role = Qt::EditRole); + + Qt::ItemFlags flags(const QModelIndex &index) const; + + void setRootComponents(QList<Component*> rootComponents); + void appendRootComponents(QList<Component*> rootComponents); + + QModelIndex indexFromComponent(Component *component) const; + Component* componentFromIndex(const QModelIndex &index) const; + + static QFont virtualComponentsFont(); + static void setVirtualComponentsFont(const QFont &font); + +private: + void setupCache(const QModelIndex &parent); + QModelIndexList collectComponents(const QModelIndex &parent) const; + +private: + int m_columns; + ComponentModelIndexCache m_cache; + + Installer *m_installer; + Component *m_headerComponent; +}; class INSTALLER_EXPORT ComponentModel : public QAbstractItemModel { Q_OBJECT + public: enum Role { - ComponentRole=Qt::UserRole, + ComponentRole = Qt::UserRole, IdRole }; enum Column { - NameColumn=0, + NameColumn = 0, InstalledVersionColumn, VersionColumn, SizeColumn }; - explicit ComponentModel( Installer* parent, RunModes runMode = InstallerMode); + explicit ComponentModel(Installer *parent, RunModes runMode = AllMode); ~ComponentModel(); - QModelIndex index( int row, int column, const QModelIndex& parent = QModelIndex() ) const; - QModelIndex parent( const QModelIndex& index ) const; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; - int columnCount( const QModelIndex& parent = QModelIndex() ) const; - int rowCount( const QModelIndex& parent = QModelIndex() ) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; - Qt::ItemFlags flags( const QModelIndex& index ) const; + Qt::ItemFlags flags(const QModelIndex &index) const; - bool setData( const QModelIndex& index, const QVariant& data, int role = Qt::CheckStateRole ); - QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const; - QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; + bool setData(const QModelIndex &index, const QVariant &data, int role = Qt::CheckStateRole); + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; static bool virtualComponentsVisible(); - static void setVirtualComponentsVisible( bool visible ); - + static void setVirtualComponentsVisible(bool visible); + static QFont virtualComponentsFont(); - static void setVirtualComponentsFont( const QFont& f ); + static void setVirtualComponentsFont(const QFont &f); - QModelIndex findComponent( const QString& id ) const; -Q_SIGNALS: - void workRequested( bool value ); + QModelIndex findComponent(const QString &id) const; public Q_SLOTS: - void addRootComponents(QList< QInstaller::Component* > components ); void clear(); + void setRunMode(RunModes runMode); + void addRootComponents(QList<QInstaller::Component*> components); + +Q_SIGNALS: + void workRequested(bool value); private Q_SLOTS: - void componentAdded( QInstaller::Component* comp ); - void selectedChanged( bool checked ); + void selectedChanged(bool checked); + void componentAdded(QInstaller::Component* comp); private: - mutable QList< Component* > seenComponents; - QList< Component* > m_components; RunModes m_runMode; + QList<Component*> m_components; + mutable QList<Component*> m_seenComponents; }; -} +} // namespace QInstaller #endif // QINSTALLER_COMPONENTMODEL_H diff --git a/installerbuilder/libinstaller/qinstallerglobal.h b/installerbuilder/libinstaller/qinstallerglobal.h index 4f23af95f..734a83f49 100644 --- a/installerbuilder/libinstaller/qinstallerglobal.h +++ b/installerbuilder/libinstaller/qinstallerglobal.h @@ -31,17 +31,23 @@ #include <QtGlobal> #include <qnamespace.h> -#define ifVerbose(s) if (!installer()->isVerbose()) {} else { qDebug() << s; } - +QT_BEGIN_NAMESPACE class QIODevice; class QFile; template <typename T> class QList; class QScriptContext; class QScriptEngine; class QScriptValue; +QT_END_NAMESPACE namespace QInstaller { +enum INSTALLER_EXPORT RunModes +{ + AllMode, + UpdaterMode +}; + class Component; #if 0 @@ -69,7 +75,7 @@ static void appendFileData(QIODevice *out, const QString &fileName) QScriptValue qInstallerComponentByName( QScriptContext* context, QScriptEngine* engine ); - Qt::CheckState componentCheckState( const Component* component, RunModes runMode = InstallerMode ); + Qt::CheckState componentCheckState( const Component* component, RunModes runMode = AllMode ); QString uncaughtExceptionString(QScriptEngine *scriptEngine/*, const QString &context*/); } diff --git a/installerbuilder/libinstaller/qinstallergui.cpp b/installerbuilder/libinstaller/qinstallergui.cpp index a3c25dcb1..aa3159a8d 100644 --- a/installerbuilder/libinstaller/qinstallergui.cpp +++ b/installerbuilder/libinstaller/qinstallergui.cpp @@ -30,7 +30,6 @@ ** (qt-info@nokia.com). ** **************************************************************************/ - #include "qinstallergui.h" #include "qinstaller.h" @@ -121,20 +120,20 @@ TRANSLATOR QInstaller::FinishedPage class DynamicInstallerPage : public Page { public: - explicit DynamicInstallerPage( QWidget* widget, Installer* parent = 0 ) - : Page( parent ), - m_widget( widget ) + explicit DynamicInstallerPage(QWidget* widget, Installer* parent = 0) + : Page(parent) + , m_widget(widget) { - setObjectName( QLatin1String("Dynamic") + widget->objectName() ); + setObjectName(QLatin1String("Dynamic") + widget->objectName()); setPixmap(QWizard::LogoPixmap, logoPixmap()); setPixmap(QWizard::WatermarkPixmap, QPixmap()); - setLayout( new QVBoxLayout ); - setTitle( widget->windowTitle() ); - m_widget->setProperty( "complete", true ); - m_widget->setProperty( "final", false ); - widget->installEventFilter( this ); - layout()->addWidget( widget ); + setLayout(new QVBoxLayout); + setTitle(widget->windowTitle()); + m_widget->setProperty("complete", true); + m_widget->setProperty("final", false); + widget->installEventFilter(this); + layout()->addWidget(widget); } QWidget* widget() const @@ -144,51 +143,44 @@ public: bool isComplete() const { - return m_widget->property( "complete" ).toBool(); + return m_widget->property("complete").toBool(); } protected: - bool eventFilter( QObject* obj, QEvent* event ) + bool eventFilter(QObject* obj, QEvent* event) { - if( obj == m_widget ) - { - switch( event->type() ) - { + if (obj == m_widget) { + switch(event->type()) { case QEvent::WindowTitleChange: - setTitle( m_widget->windowTitle() ); + setTitle(m_widget->windowTitle()); break; + case QEvent::DynamicPropertyChange: emit completeChanged(); - if( m_widget->property( "final" ).toBool() != isFinalPage() ) - setFinalPage( m_widget->property( "final" ).toBool() ); + if (m_widget->property("final").toBool() != isFinalPage()) + setFinalPage(m_widget->property("final").toBool()); break; + default: break; } } - return Page::eventFilter( obj, event ); + return Page::eventFilter(obj, event); } private: QWidget* const m_widget; }; -//////////////////////////////////////////////////////////////////// -// -// Gui -// -//////////////////////////////////////////////////////////////////// +// -- Gui::Private class Gui::Private { public: Private() - : autoSwitchPage(true), - modified( false ) - { - - } + : autoSwitchPage(true) + , modified(false) { } QScriptEngine controlScriptEngine; QScriptValue controlScript; @@ -196,88 +188,86 @@ public: bool modified; }; + +// -- Gui + QScriptEngine* Gui::controlScriptEngine() const { return &d->controlScriptEngine; } /*! - \class QInstaller::Gui - Is the "gui" object in a none interactive installation - */ - + \class QInstaller::Gui + Is the "gui" object in a none interactive installation +*/ Gui::Gui(Installer *installer, QWidget *parent) : QWizard(parent) - , m_installer( installer ) - , d( new Private ) - , m_introPage( new IntroductionPage( installer ) ) + , m_installer(installer) + , d(new Private) { - if ( installer->isInstaller() ) - setWindowTitle(tr("%1 Setup").arg(m_installer->value(QLatin1String( "Title" ) ) ) ); + if (installer->isInstaller()) + setWindowTitle(tr("%1 Setup").arg(m_installer->value(QLatin1String("Title")))); else - setWindowTitle(tr("%1").arg(m_installer->value(QLatin1String( "maintenanceTitle") ) ) ); + setWindowTitle(tr("%1").arg(m_installer->value(QLatin1String("maintenanceTitle")))); #ifndef Q_WS_MAC - setWindowIcon( QIcon( m_installer->settings().icon() ) ); - setWizardStyle( QWizard::ModernStyle ); + setWindowIcon(QIcon(m_installer->settings().icon())); + setWizardStyle(QWizard::ModernStyle); #else - setPixmap( QWizard::BackgroundPixmap, m_installer->settings().background() ); + setPixmap(QWizard::BackgroundPixmap, m_installer->settings().background()); #endif setOption(QWizard::NoBackButtonOnStartPage); setOption(QWizard::NoBackButtonOnLastPage); -// setOption(QWizard::IndependentPages); - setLayout( new QVBoxLayout( this ) ); - if ( installer->isInstaller() ) - setPage( Installer::Introduction, m_introPage ); + setLayout(new QVBoxLayout(this)); connect(this, SIGNAL(interrupted()), installer, SLOT(interrupt())); - connect(this, SIGNAL(rejected()), installer, SLOT(setCanceled()) ); - // both queued to show the finished page once everything is done + connect(this, SIGNAL(rejected()), installer, SLOT(setCanceled())); + // both queued to show the finished page once everything is done connect(installer, SIGNAL(installationFinished()), this, SLOT(showFinishedPage()), Qt::QueuedConnection); connect(installer, SIGNAL(uninstallationFinished()), this, SLOT(showFinishedPage()), Qt::QueuedConnection); - connect( this, SIGNAL( currentIdChanged( int ) ), this, SLOT( slotCurrentPageChanged( int ) ) ); - connect( this, SIGNAL( currentIdChanged( int ) ), m_installer, SIGNAL( currentPageChanged( int ) ) ); - connect( button( QWizard::FinishButton ), SIGNAL( clicked() ), this, SIGNAL( finishButtonClicked() ) ); - connect( this, SIGNAL( finishButtonClicked() ), installer, SIGNAL( finishButtonClicked() ) ); + connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(slotCurrentPageChanged(int))); + connect(this, SIGNAL(currentIdChanged(int)), m_installer, SIGNAL(currentPageChanged(int))); + connect(button(QWizard::FinishButton), SIGNAL(clicked()), this, SIGNAL(finishButtonClicked())); + connect(this, SIGNAL(finishButtonClicked()), installer, SIGNAL(finishButtonClicked())); // make sure the QUiLoader's retranslateUi is executed first, then the script - connect( this, SIGNAL( languageChanged() ), - installer, SLOT( languageChanged() ), Qt::QueuedConnection ); - - connect( installer, SIGNAL( wizardPageInsertionRequested( QWidget*, Installer::WizardPage ) ), - this, SLOT( wizardPageInsertionRequested( QWidget*, Installer::WizardPage ) ) ); - connect( installer, SIGNAL( wizardPageRemovalRequested( QWidget* ) ), - this, SLOT( wizardPageRemovalRequested( QWidget* ) ) ); - connect( installer, SIGNAL( wizardWidgetInsertionRequested( QWidget*, Installer::WizardPage ) ), - this, SLOT( wizardWidgetInsertionRequested( QWidget*, Installer::WizardPage ) ) ); - connect( installer, SIGNAL( wizardWidgetRemovalRequested( QWidget* ) ), - this, SLOT( wizardWidgetRemovalRequested( QWidget* ) ) ); - connect( installer, SIGNAL( wizardPageVisibilityChangeRequested( bool, int ) ), - this, SLOT( wizardPageVisibilityChangeRequested( bool, int ) ), Qt::QueuedConnection ); - - connect( installer, SIGNAL( setAutomatedPageSwitchEnabled( bool ) ), - this, SLOT( setAutomatedPageSwitchEnabled( bool ) ) ); + connect(this, SIGNAL(languageChanged()), + installer, SLOT(languageChanged()), Qt::QueuedConnection); + + connect(installer, SIGNAL(wizardPageInsertionRequested(QWidget*, Installer::WizardPage)), + this, SLOT(wizardPageInsertionRequested(QWidget*, Installer::WizardPage))); + connect(installer, SIGNAL(wizardPageRemovalRequested(QWidget*)), + this, SLOT(wizardPageRemovalRequested(QWidget*))); + connect(installer, SIGNAL(wizardWidgetInsertionRequested(QWidget*, Installer::WizardPage)), + this, SLOT(wizardWidgetInsertionRequested(QWidget*, Installer::WizardPage))); + connect(installer, SIGNAL(wizardWidgetRemovalRequested(QWidget*)), + this, SLOT(wizardWidgetRemovalRequested(QWidget*))); + connect(installer, SIGNAL(wizardPageVisibilityChangeRequested(bool, int)), + this, SLOT(wizardPageVisibilityChangeRequested(bool, int)), Qt::QueuedConnection); + + connect(installer, SIGNAL(setAutomatedPageSwitchEnabled(bool)), + this, SLOT(setAutomatedPageSwitchEnabled(bool))); #ifdef Q_WS_MAC - setButtonText( QWizard::BackButton, tr( "Go Back" ) ); - setButtonText( QWizard::NextButton, tr( "Continue" ) ); - setButtonText( QWizard::FinishButton, tr( "Done" ) ); + setButtonText(QWizard::BackButton, tr("Go Back")); + setButtonText(QWizard::NextButton, tr("Continue")); + setButtonText(QWizard::FinishButton, tr("Done")); #else - setButtonText( QWizard::BackButton, tr( "Back" ) ); - setButtonText( QWizard::NextButton, tr( "Next" ) ); - setButtonText( QWizard::FinishButton, tr( "Finish" ) ); + setButtonText(QWizard::BackButton, tr("Back")); + setButtonText(QWizard::NextButton, tr("Next")); + setButtonText(QWizard::FinishButton, tr("Finish")); #endif - setButtonText( QWizard::CancelButton, tr( "Cancel" ) ); + setButtonText(QWizard::CancelButton, tr("Cancel")); - dynamic_cast< QPushButton* >( button( QWizard::NextButton ) )->setDefault( true ); + dynamic_cast<QPushButton*>(button(QWizard::NextButton))->setDefault(true); #ifdef Q_WS_MAC - resize( sizeHint() * 1.25 ); + resize(sizeHint() * 1.25); #else - resize( sizeHint() ); + resize(sizeHint()); #endif } @@ -286,65 +276,68 @@ Gui::~Gui() delete d; } -void Gui::setAutomatedPageSwitchEnabled( bool request ) +void Gui::setAutomatedPageSwitchEnabled(bool request) { d->autoSwitchPage = request; } - -void Gui::clickButton( int wb, int delay ) +void Gui::clickButton(int wb, int delay) { - if ( QAbstractButton* b = button( static_cast<QWizard::WizardButton>( wb ) ) ) - QTimer::singleShot( delay, b, SLOT(click()) ); - else { + if (QAbstractButton* b = button(static_cast<QWizard::WizardButton>(wb) )) { + QTimer::singleShot(delay, b, SLOT(click())); + } else { //TODO we should probably abort immediately here (faulty test script) verbose() << "Button " << wb << " not found!" << std::endl; } } /*! - * Loads a script to perform the installation non-interactively. - * - * @throws QInstaller::Error if the script is not readable/cannot be parsed - */ -void Gui::loadControlScript( const QString& scriptPath ) + Loads a script to perform the installation non-interactively. + @throws QInstaller::Error if the script is not readable/cannot be parsed +*/ +void Gui::loadControlScript(const QString& scriptPath) { - QFile file( scriptPath ); - if( !file.open( QIODevice::ReadOnly ) ) - throw Error( QObject::tr( "Could not open the requested script file at %1: %2" ).arg( scriptPath, file.errorString() ) ); + QFile file(scriptPath); + if (!file.open(QIODevice::ReadOnly)) { + throw Error(QObject::tr("Could not open the requested script file at %1: %2") + .arg(scriptPath, file.errorString())); + } - d->controlScriptEngine.globalObject().setProperty( QLatin1String( "installer" ), d->controlScriptEngine.newQObject( m_installer ) ); - d->controlScriptEngine.globalObject().setProperty( QLatin1String( "gui" ), d->controlScriptEngine.newQObject( this ) ); - registerMessageBox( &d->controlScriptEngine ); + d->controlScriptEngine.globalObject().setProperty(QLatin1String("installer"), + d->controlScriptEngine.newQObject(m_installer)); + d->controlScriptEngine.globalObject().setProperty(QLatin1String("gui"), + d->controlScriptEngine.newQObject(this)); + registerMessageBox(&d->controlScriptEngine); #undef REGISTER_BUTTON -#define REGISTER_BUTTON(x) buttons.setProperty( QLatin1String( #x ), d->controlScriptEngine.newVariant( static_cast<int>( QWizard::x ) ) ); +#define REGISTER_BUTTON(x) buttons.setProperty(QLatin1String(#x), \ + d->controlScriptEngine.newVariant(static_cast<int>(QWizard::x))); QScriptValue buttons = d->controlScriptEngine.newArray(); - REGISTER_BUTTON( BackButton ) - REGISTER_BUTTON( NextButton ) - REGISTER_BUTTON( CommitButton ) - REGISTER_BUTTON( FinishButton ) - REGISTER_BUTTON( CancelButton ) - REGISTER_BUTTON( HelpButton ) - REGISTER_BUTTON( CustomButton1 ) - REGISTER_BUTTON( CustomButton2 ) - REGISTER_BUTTON( CustomButton3 ) + REGISTER_BUTTON(BackButton) + REGISTER_BUTTON(NextButton) + REGISTER_BUTTON(CommitButton) + REGISTER_BUTTON(FinishButton) + REGISTER_BUTTON(CancelButton) + REGISTER_BUTTON(HelpButton) + REGISTER_BUTTON(CustomButton1) + REGISTER_BUTTON(CustomButton2) + REGISTER_BUTTON(CustomButton3) #undef REGISTER_BUTTON - d->controlScriptEngine.globalObject().setProperty( QLatin1String( "buttons" ), buttons ); + d->controlScriptEngine.globalObject().setProperty(QLatin1String("buttons"), buttons); - d->controlScriptEngine.evaluate( QLatin1String( file.readAll() ), scriptPath ); - if( d->controlScriptEngine.hasUncaughtException() ) { - throw Error( QObject::tr( "Exception while loading the control script %1" ) - .arg(uncaughtExceptionString(&(d->controlScriptEngine)/*, scriptPath*/)) ); + d->controlScriptEngine.evaluate(QLatin1String(file.readAll()), scriptPath); + if (d->controlScriptEngine.hasUncaughtException()) { + throw Error(QObject::tr("Exception while loading the control script %1") + .arg(uncaughtExceptionString(&(d->controlScriptEngine)/*, scriptPath*/))); } - QScriptValue comp = d->controlScriptEngine.evaluate( QLatin1String( "Controller" ) ); - if( d->controlScriptEngine.hasUncaughtException() ) { - throw Error( QObject::tr( "Exception while loading the control script %1" ) - .arg(uncaughtExceptionString(&(d->controlScriptEngine)/*, scriptPath*/)) ); + QScriptValue comp = d->controlScriptEngine.evaluate(QLatin1String("Controller")); + if (d->controlScriptEngine.hasUncaughtException()) { + throw Error(QObject::tr("Exception while loading the control script %1") + .arg(uncaughtExceptionString(&(d->controlScriptEngine)/*, scriptPath*/))); } d->controlScript = comp; @@ -355,126 +348,122 @@ void Gui::loadControlScript( const QString& scriptPath ) void Gui::triggerControlScriptForCurrentPage() { - slotCurrentPageChanged( currentId() ); + slotCurrentPageChanged(currentId()); } -void Gui::slotCurrentPageChanged( int id ) +void Gui::slotCurrentPageChanged(int id) { - QMetaObject::invokeMethod( this, "delayedControlScriptExecution", Qt::QueuedConnection, Q_ARG( int, id ) ); + QMetaObject::invokeMethod(this, "delayedControlScriptExecution", Qt::QueuedConnection, + Q_ARG(int, id)); } -void Gui::callControlScriptMethod( const QString& methodName ) +void Gui::callControlScriptMethod(const QString& methodName) { - QScriptValue method = d->controlScript.property( QLatin1String( "prototype" ) ).property( methodName ); + QScriptValue method = d->controlScript.property(QLatin1String("prototype")).property(methodName); - if ( !method.isValid() ) { - verbose() << "Control script callback " << qPrintable(methodName) << " does not exist." << std::endl; + if (!method.isValid()) { + verbose() << "Control script callback " << qPrintable(methodName) << " does not exist." + << std::endl; return; } verbose() << "Calling control script callback " << qPrintable(methodName) << std::endl; - method.call( d->controlScript ); + method.call(d->controlScript); - if( d->controlScriptEngine.hasUncaughtException() ) - qCritical() << uncaughtExceptionString(&(d->controlScriptEngine)/*, QLatin1String("control script")*/); - //TODO handle error -} - -void Gui::delayedControlScriptExecution( int id ) -{ - Page* const p = qobject_cast<Page*>( page( id ) ); - if ( !p ) - return; - const QString methodName = p->objectName() + QLatin1String("Callback"); - callControlScriptMethod( methodName ); + if (d->controlScriptEngine.hasUncaughtException()) { + qCritical() << uncaughtExceptionString(&(d->controlScriptEngine) + /*, QLatin1String("control script")*/); + //TODO handle error + } } - -IntroductionPage* Gui::introductionPage() const +void Gui::delayedControlScriptExecution(int id) { - return m_introPage; + if (Page* const p = qobject_cast<Page*>(page(id))) { + const QString methodName = p->objectName() + QLatin1String("Callback"); + callControlScriptMethod(methodName); + } } -bool Gui::event( QEvent* event ) +bool Gui::event(QEvent* event) { - switch( event->type() ) - { + switch(event->type()) { case QEvent::LanguageChange: emit languageChanged(); break; default: break; } - return QWizard::event( event ); + return QWizard::event(event); } -void Gui::wizardPageInsertionRequested( QWidget* widget, Installer::WizardPage page ) +void Gui::wizardPageInsertionRequested(QWidget* widget, Installer::WizardPage page) { // just in case it was already in there... - wizardPageRemovalRequested( widget ); + wizardPageRemovalRequested(widget); // now find a suitable ID lower than page - int p = static_cast< int >( page ) - 1; - while( QWizard::page( p ) != 0 ) + int p = static_cast<int>(page) - 1; + while (QWizard::page(p) != 0) --p; - // ad it - setPage( p, new DynamicInstallerPage( widget, m_installer ) ); + // add it + setPage(p, new DynamicInstallerPage(widget, m_installer)); } -void Gui::wizardPageRemovalRequested( QWidget* widget ) +void Gui::wizardPageRemovalRequested(QWidget* widget) { - const QList< int > pages = pageIds(); - for( QList< int >::const_iterator it = pages.begin(); it != pages.end(); ++it ) - { - QWizardPage* const p = page( *it ); - DynamicInstallerPage* const dynamicPage = dynamic_cast< DynamicInstallerPage* >( p ); - if( dynamicPage == 0 ) + const QList<int> pages = pageIds(); + for (QList<int>::const_iterator it = pages.begin(); it != pages.end(); ++it) { + QWizardPage* const p = page(*it); + DynamicInstallerPage* const dynamicPage = dynamic_cast<DynamicInstallerPage*>(p); + if (dynamicPage == 0) continue; - if( dynamicPage->widget() != widget ) + if (dynamicPage->widget() != widget) continue; - removePage( *it ); + removePage(*it); } } -void Gui::wizardWidgetInsertionRequested( QWidget* widget, Installer::WizardPage page ) +void Gui::wizardWidgetInsertionRequested(QWidget* widget, Installer::WizardPage page) { Q_ASSERT(widget); - QWizardPage* const p = QWizard::page( page ); - if (p) - p->layout()->addWidget( widget ); + if (QWizardPage* const p = QWizard::page(page)) + p->layout()->addWidget(widget); } -void Gui::wizardWidgetRemovalRequested( QWidget* widget ) +void Gui::wizardWidgetRemovalRequested(QWidget* widget) { Q_ASSERT(widget); - widget->setParent( 0 ); + widget->setParent(0); } -void Gui::wizardPageVisibilityChangeRequested( bool visible, int p ) +void Gui::wizardPageVisibilityChangeRequested(bool visible, int p) { - if( visible && page( p ) == 0 ) - { - setPage( p, defaultPages[ p ] ); - } - else if( !visible && page( p ) != 0 ) - { - defaultPages[ p ] = page( p ); - removePage( p ); + if (visible && page(p) == 0) { + setPage(p, defaultPages[p]); + } else if (!visible && page(p) != 0) { + defaultPages[p] = page(p); + removePage(p); } } -QWidget* Gui::pageWidgetByObjectName( const QString& name ) const +Page* Gui::page(int pageId) const +{ + return qobject_cast<Page*>(QWizard::page(pageId)); +} + +QWidget* Gui::pageWidgetByObjectName(const QString& name) const { const QList<int> ids = pageIds(); - Q_FOREACH( const int i, ids ) { - Page* const p = qobject_cast<Page*>( page( i ) ); - if ( p && p->objectName() == name ) { - // For dynamic pages, return the contained widget (as read from the UI file), not the wrapper page - if ( DynamicInstallerPage* dp = dynamic_cast<DynamicInstallerPage*>( p ) ) + foreach (const int i, ids) { + Page* const p = qobject_cast<Page*>(page(i)); + if (p && p->objectName() == name) { + // For dynamic pages, return the contained widget (as read from the UI file), not the + // wrapper page + if (DynamicInstallerPage* dp = dynamic_cast<DynamicInstallerPage*>(p)) return dp->widget(); - else - return p; + return p; } } verbose() << "No page found for object name " << name << std::endl; @@ -489,36 +478,37 @@ QWidget* Gui::currentPageWidget() const void Gui::cancelButtonClicked() { const bool doIgnore = m_installer->isInstaller() - ? m_installer->status() == Installer::InstallerCanceledByUser || m_installer->status() == Installer::InstallerSucceeded - : m_installer->status() == Installer::InstallerCanceledByUser; + ? m_installer->status() == Installer::Canceled + || m_installer->status() == Installer::Success + : m_installer->status() == Installer::Canceled; //if the user canceled (all modes) or the installation is finished (installer mode only), ignore //clicks on cancel. - if ( doIgnore ) + if (doIgnore) return; //close the manager without asking if nothing was modified, always ask for the installer - if ( !m_installer->isInstaller() && !d->modified ) { + if (!m_installer->isInstaller() && !d->modified) { QDialog::reject(); return; } - Page* const page = qobject_cast< Page* >( currentPage() ); + Page* const page = qobject_cast<Page*>(currentPage()); verbose() << "CANCEL CLICKED" << currentPage() << page << std::endl; if (page && page->isInterruptible()) { - const QMessageBox::StandardButton bt = MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), - QLatin1String("cancelInstallation"), - tr("Warning"), - tr("Do you want to abort the %1 process?").arg( m_installer->isUninstaller() ? tr( "uninstallation" ) : tr( "installation" ) ), - QMessageBox::Yes | QMessageBox::No); + const QMessageBox::StandardButton bt = + MessageBoxHandler::question(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("cancelInstallation"), tr("Question"), + tr("Do you want to abort the %1 process?").arg(m_installer->isUninstaller() + ? tr("uninstallation") : tr("installation")), QMessageBox::Yes | QMessageBox::No); if (bt == QMessageBox::Yes) emit interrupted(); } else { - const QMessageBox::StandardButton bt = MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(), - QLatin1String("cancelInstallation"), - tr("Warning"), - tr("Do you want to abort the %1 application?").arg( m_installer->isUninstaller() ? tr( "uninstaller" ) : tr( "installer" ) ), - QMessageBox::Yes | QMessageBox::No); + const QMessageBox::StandardButton bt = + MessageBoxHandler::question(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("cancelInstallation"), tr("Question"), + tr("Do you want to abort the %1 application?").arg(m_installer->isUninstaller() + ? tr("uninstaller") : tr("installer")), QMessageBox::Yes | QMessageBox::No); if (bt == QMessageBox::Yes) QDialog::reject(); } @@ -534,7 +524,8 @@ void Gui::reject() { cancelButtonClicked(); } -void Gui::setModified( bool value ) + +void Gui::setModified(bool value) { d->modified = value; } @@ -542,23 +533,22 @@ void Gui::setModified( bool value ) void Gui::showFinishedPage() { verbose() << "SHOW FINISHED PAGE" << std::endl; - if (d->autoSwitchPage){ + if (d->autoSwitchPage) next(); - }else{ - dynamic_cast< QPushButton* >( button( QWizard::CancelButton ) )->setEnabled( false ); - } + else + dynamic_cast< QPushButton*>(button(QWizard::CancelButton))->setEnabled(false); } -//////////////////////////////////////////////////////////////////// -// -// Page -// -//////////////////////////////////////////////////////////////////// + +// -- Page Page::Page(Installer *installer) - : m_installer(installer), m_fresh(true), m_complete(true) + : m_installer(installer) + , m_fresh(true) + , m_complete(true) { - setSubTitle( QLatin1String( " " ) ); // otherwise the colors will screw up + // otherwise the colors will screw up + setSubTitle(QLatin1String(" ")); } Installer *Page::installer() const @@ -568,17 +558,17 @@ Installer *Page::installer() const QPixmap Page::watermarkPixmap() const { - return QPixmap(m_installer->value( QLatin1String( "WatermarkPixmap" ) ) ); + return QPixmap(m_installer->value(QLatin1String("WatermarkPixmap"))); } QPixmap Page::logoPixmap() const { - return QPixmap(m_installer->value( QLatin1String( "LogoPixmap" ) ) ); + return QPixmap(m_installer->value(QLatin1String("LogoPixmap"))); } QString Page::productName() const { - return m_installer->value( QLatin1String( "ProductName" ) ); + return m_installer->value(QLatin1String("ProductName")); } bool Page::isComplete() const @@ -590,24 +580,23 @@ void Page::setComplete(bool complete) { m_complete = complete; emit completeChanged(); - if( wizard() == 0 ) + if (wizard() == 0) return; - if( wizard()->button( QWizard::CancelButton ) == 0 ) + if (wizard()->button(QWizard::CancelButton) == 0) return; - if( wizard()->button( QWizard::NextButton ) == 0 ) + if (wizard()->button(QWizard::NextButton) == 0) return; - if( wizard()->button( QWizard::CancelButton )->hasFocus() ) - wizard()->button( QWizard::NextButton )->setFocus(); + if (wizard()->button(QWizard::CancelButton)->hasFocus()) + wizard()->button(QWizard::NextButton)->setFocus(); } -void Page::insertWidget(QWidget *widget, const QString &siblingName, - int offset) +void Page::insertWidget(QWidget *widget, const QString &siblingName, int offset) { QWidget *sibling = findChild<QWidget *>(siblingName); QWidget *parent = sibling ? sibling->parentWidget() : 0; QLayout *layout = parent ? parent->layout() : 0; QBoxLayout *blayout = qobject_cast<QBoxLayout *>(layout); - //qDebug() << "FOUND: " << sibling << parent << layout << blayout; + if (blayout) { int index = blayout->indexOf(sibling) + offset; blayout->insertWidget(index, widget); @@ -619,16 +608,23 @@ QWidget *Page::findWidget(const QString &objectName) const return findChild<QWidget *>(objectName); } +/*! + \reimp + \Overwritten 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 overwritten function. +*/ void Page::setVisible(bool visible) { QWizardPage::setVisible(visible); qApp->processEvents(); - //qDebug() << "VISIBLE: " << visible << objectName() << installer(); + if (m_fresh && !visible) { - //qDebug() << "SUPRESSED..."; + // this is only hit once when the page gets added to the wizard m_fresh = false; return; } + if (visible) entering(); else @@ -637,33 +633,31 @@ void Page::setVisible(bool visible) int Page::nextId() const { - //qDebug() << "NEXTID"; return QWizardPage::nextId(); } -//////////////////////////////////////////////////////////////////// -// -// QInstallerIntroductionPage -// -//////////////////////////////////////////////////////////////////// + +// -- QInstallerIntroductionPage IntroductionPage::IntroductionPage(Installer *inst) - : Page(inst), m_widget(0) + : Page(inst) + , m_widget(0) { - setObjectName( QLatin1String( "IntroductionPage" ) ); + setObjectName(QLatin1String("IntroductionPage")); setTitle(tr("Setup - %1").arg(productName())); setPixmap(QWizard::WatermarkPixmap, watermarkPixmap()); setSubTitle(QString()); m_msgLabel = new QLabel(this); - m_msgLabel->setObjectName( QLatin1String( "MessageLabel" ) ); + m_msgLabel->setObjectName(QLatin1String("MessageLabel")); m_msgLabel->setWordWrap(true); m_msgLabel->setText(tr("Welcome to the %1 Setup Wizard.") .arg(productName())); - QVBoxLayout *layout = new QVBoxLayout( this ); + QVBoxLayout *layout = new QVBoxLayout(this); setLayout(layout); - layout->addWidget( m_msgLabel ); + layout->addWidget(m_msgLabel); + layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); } void IntroductionPage::setText(const QString &text) @@ -673,38 +667,35 @@ void IntroductionPage::setText(const QString &text) void IntroductionPage::setWidget(QWidget *w) { - if(m_widget) { + if (m_widget) { layout()->removeWidget(m_widget); delete m_widget; } m_widget = w; - if(m_widget) { + if (m_widget) static_cast<QVBoxLayout*>(layout())->addWidget(m_widget, 1); - } } -//////////////////////////////////////////////////////////////////// -// -// LicenseAgreementPage -// -//////////////////////////////////////////////////////////////////// + +// -- LicenseAgreementPage LicenseAgreementPage::LicenseAgreementPage(Installer *inst) : Page(inst) { setTitle(tr("License Agreement")); + setSubTitle(tr("Please read the following license agreement(s). You must accept the terms contained " + "in these agreement(s) before continuing with the installation.")); + setPixmap(QWizard::LogoPixmap, logoPixmap()); setPixmap(QWizard::WatermarkPixmap, QPixmap()); setObjectName(QLatin1String("LicenseAgreementPage")); - QLabel *msgLabel = new QLabel(tr("Please read the following license agreement(s). You must " - "accept the terms contained in these agreement(s) before continuing with the installation.")); - msgLabel->setWordWrap(true); - +#if !defined(Q_WS_MAC) QGroupBox *licenseBox = new QGroupBox(this); licenseBox->setObjectName(QString::fromUtf8("licenseBox")); +#endif - m_licenseListWidget = new QListWidget(licenseBox); + m_licenseListWidget = new QListWidget(this); connect(m_licenseListWidget, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, SLOT(currentItemChanged(QListWidgetItem *))); @@ -712,20 +703,28 @@ LicenseAgreementPage::LicenseAgreementPage(Installer *inst) sizePolicy.setHeightForWidth(m_licenseListWidget->sizePolicy().hasHeightForWidth()); m_licenseListWidget->setSizePolicy(sizePolicy); - m_textBrowser = new QTextBrowser(licenseBox); + m_textBrowser = new QTextBrowser(this); m_textBrowser->setReadOnly(true); - m_textBrowser->setOpenExternalLinks(true); m_textBrowser->setOpenLinks(false); + m_textBrowser->setOpenExternalLinks(true); connect(m_textBrowser, SIGNAL(anchorClicked(QUrl)), this, SLOT(openLicenseUrl(QUrl))); QSizePolicy sizePolicy2(QSizePolicy::Minimum, QSizePolicy::Expanding); sizePolicy2.setHeightForWidth(m_textBrowser->sizePolicy().hasHeightForWidth()); m_textBrowser->setSizePolicy(sizePolicy2); - QHBoxLayout *licenseBoxLayout = new QHBoxLayout(licenseBox); + QHBoxLayout *licenseBoxLayout = new QHBoxLayout(); licenseBoxLayout->addWidget(m_licenseListWidget); licenseBoxLayout->addWidget(m_textBrowser); + QVBoxLayout *layout = new QVBoxLayout(this); +#if !defined(Q_WS_MAC) + layout->addWidget(licenseBox); + licenseBox->setLayout(licenseBoxLayout); +#else + layout->addLayout(licenseBoxLayout); +#endif + m_acceptRadioButton = new QRadioButton(this); m_acceptRadioButton->setShortcut(QKeySequence(tr("Alt+A", "agree license"))); QLabel *acceptLabel = new QLabel(tr("I h<u>a</u>ve read and agree to the following terms contained in " @@ -757,7 +756,6 @@ LicenseAgreementPage::LicenseAgreementPage(Installer *inst) QFont labelFont(font()); labelFont.setPixelSize(9); - msgLabel->setFont(labelFont); acceptLabel->setFont(labelFont); rejectLabel->setFont(labelFont); #endif @@ -768,28 +766,25 @@ LicenseAgreementPage::LicenseAgreementPage(Installer *inst) gridLayout->addWidget(acceptLabel, 0, 1); gridLayout->addWidget(m_rejectRadioButton, 1, 0); gridLayout->addWidget(rejectLabel, 1, 1); - - QVBoxLayout *layout = new QVBoxLayout(this); - layout->addWidget(msgLabel); - layout->addWidget(licenseBox); layout->addLayout(gridLayout); - connect(m_acceptRadioButton, SIGNAL(toggled(bool)), this, - SIGNAL(completeChanged())); - connect(m_rejectRadioButton, SIGNAL(toggled(bool)), this, - SIGNAL(completeChanged())); + connect(m_acceptRadioButton, SIGNAL(toggled(bool)), this, SIGNAL(completeChanged())); + connect(m_rejectRadioButton, SIGNAL(toggled(bool)), this, SIGNAL(completeChanged())); m_rejectRadioButton->setChecked(true); } -void LicenseAgreementPage::initializePage() +void LicenseAgreementPage::entering() { m_licenseListWidget->clear(); m_textBrowser->setText(QLatin1String("")); - // TODO: this needs to be fixed once we support several root components + RunModes runMode = installer()->runMode(); + QList<QInstaller::Component*> components = installer()->components(false, runMode); + QInstaller::Component *rootComponent = 0; - foreach (QInstaller::Component* root, installer()->components()) { + // TODO: this needs to be fixed once we support several root components + foreach (QInstaller::Component* root, components) { if (root->isInstalled()) continue; @@ -800,7 +795,7 @@ void LicenseAgreementPage::initializePage() } } - QList<QInstaller::Component*> components = installer()->componentsToInstall(true); + components = installer()->componentsToInstall(true, true, runMode); foreach (QInstaller::Component* component, components) { if (rootComponent != component && !component->isInstalled()) addLicenseItem(component->licenses()); @@ -835,24 +830,24 @@ void LicenseAgreementPage::addLicenseItem(const QHash<QString, QPair<QString, QS } } -//////////////////////////////////////////////////////////////////// -// -// ComponentSelectionPage -// -//////////////////////////////////////////////////////////////////// -inline QString unitSizeText(const qint64 size) { +// -- ComponentSelectionPage + +inline QString unitSizeText(const qint64 size) +{ if (size < 10000) return QString::number(size) + QLatin1Char(' ') + ComponentSelectionPage::tr("Bytes"); + if (size < 1024 * 10000) return QString::number(size / 1024) + QLatin1Char(' ') + ComponentSelectionPage::tr("kBytes"); + return QString::number(size / 1024 / 1024) + QLatin1Char(' ') + ComponentSelectionPage::tr("MBytes"); } static QString niceSizeText(const QString &str) { const qint64 size = str.toLongLong(); - if( size == 0 ) + if (size == 0) return QString(); QString msg = ComponentSelectionPage::tr( @@ -860,247 +855,297 @@ static QString niceSizeText(const QString &str) return msg.arg(unitSizeText(size)); } + +// -- ComponentSelectionPage::Private + class ComponentSelectionPage::Private : public QObject { Q_OBJECT public: Private(ComponentSelectionPage *qq, Installer *installer) - : q( qq ), - wasshown( false ), - modified( false ), - connected( false ), - m_model( new ComponentModel( installer ) ), - m_installer( installer ), - m_treeView( new QTreeView( q ) ) + : q(qq), + wasshown(false), + modified(false), + connected(false), + m_model(new ComponentModel(installer, installer->runMode())), + m_installer(installer), + m_treeView(new QTreeView(q)) { - m_treeView->setObjectName( QLatin1String( "TreeView" ) ); - m_treeView->setMouseTracking(true); - m_treeView->setHeaderHidden( true ); + m_treeView->setModel(m_model); + m_treeView->setObjectName(QLatin1String("ComponentTreeView")); - m_treeView->setModel( m_model ); - for( int i = 1; i < m_treeView->model()->columnCount(); ++i ) - m_treeView->setColumnHidden( i, true ); + QHBoxLayout *hlayout = new QHBoxLayout; + hlayout->addWidget(m_treeView, 3); m_descriptionLabel = new QLabel(q); m_descriptionLabel->setWordWrap(true); + m_descriptionLabel->setObjectName(QLatin1String("ComponentDescriptionLabel")); - m_sizeLabel = new QLabel(q); - m_sizeLabel->setWordWrap(true); - - QVBoxLayout *layout = new QVBoxLayout( q ); - if( !installer->isInstaller() ) - { - QRadioButton* const uninstallAll = new QRadioButton( tr( "Remove all components" ) ); - uninstallAll->setObjectName( QLatin1String("uninstallAllComponentsRB") ); - QRadioButton* const keepChecked = new QRadioButton( installer->isUninstaller() ? tr( "Keep selected components" ) : tr( "Install selected components" ) ); - keepChecked->setObjectName( QLatin1String("keepSelectedComponentsRB") ); - layout->addWidget( uninstallAll ); - layout->addWidget( keepChecked ); - connect( uninstallAll, SIGNAL( toggled( bool ) ), m_treeView, SLOT( setDisabled( bool ) ) ); - connect( uninstallAll, SIGNAL( toggled( bool ) ), m_descriptionLabel, SLOT( setDisabled( bool ) ) ); - connect( uninstallAll, SIGNAL( toggled( bool ) ), m_installer, SLOT( setCompleteUninstallation( bool ) ) ); - connect( uninstallAll, SIGNAL( toggled( bool ) ), q, SIGNAL( completeChanged() ), Qt::QueuedConnection ); - connect( uninstallAll, SIGNAL( toggled( bool ) ), this, SLOT( fullUninstallToggled( bool ) ), Qt::QueuedConnection ); - uninstallAll->setChecked( installer->isUninstaller() ); - keepChecked->setChecked( installer->isPackageManager() ); - m_installer->setCompleteUninstallation( installer->isUninstaller() ); - } - //layout->addWidget(msgLabel); - QHBoxLayout *hlayout = new QHBoxLayout; - hlayout->addWidget(m_treeView, 3); QVBoxLayout *vlayout = new QVBoxLayout; vlayout->addWidget(m_descriptionLabel); + + m_sizeLabel = new QLabel(q); + m_sizeLabel->setWordWrap(true); vlayout->addWidget(m_sizeLabel); - vlayout->addSpacerItem(new QSpacerItem(1, 1, - QSizePolicy::MinimumExpanding, + m_sizeLabel->setObjectName(QLatin1String("ComponentSizeLabel")); + + vlayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding)); hlayout->addLayout(vlayout, 2); + + QVBoxLayout *layout = new QVBoxLayout(q); + layout->addLayout(hlayout, 1); + + QPushButton *button; + hlayout = new QHBoxLayout; + if (m_installer->isInstaller()) { + hlayout->addWidget(button = new QPushButton(tr("Default"))); + connect(button, SIGNAL(clicked()), this, SLOT(selectDefault())); + } + hlayout->addWidget(button = new QPushButton(tr("Select All"))); + connect(button, SIGNAL(clicked()), this, SLOT(selectAll())); + hlayout->addWidget(button = new QPushButton(tr("Deselect All"))); + connect(button, SIGNAL(clicked()), this, SLOT(deselectAll())); + hlayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::MinimumExpanding, + QSizePolicy::MinimumExpanding)); layout->addLayout(hlayout); - connect( m_treeView->selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), - this, SLOT( selectionChanged() ) ); + connect(m_model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), q, + SIGNAL(completeChanged()), Qt::QueuedConnection); + connect(m_model, SIGNAL(modelReset()), this, SLOT(modelWasReseted()), + Qt::QueuedConnection); - connect( m_treeView->model(), SIGNAL( dataChanged( QModelIndex, QModelIndex ) ), - q, SIGNAL( completeChanged() ), Qt::QueuedConnection ); + connect(m_installer, SIGNAL(finishAllComponentsReset()), this, SLOT(componentsChanged()), + Qt::QueuedConnection); + connect(m_installer, SIGNAL(finishUpdaterComponentsReset()), this, SLOT(componentsChanged()), + Qt::QueuedConnection); + + connect(m_treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), + this, SLOT(selectionChanged())); } -protected Q_SLOTS: +public slots: void selectionChanged() { + m_sizeLabel->clear(); + m_descriptionLabel->clear(); + const QModelIndex index = m_treeView->currentIndex(); - if( !index.isValid() ) - { - m_descriptionLabel->clear(); - m_sizeLabel->clear(); - return; + if (index.isValid()) { + m_descriptionLabel->setText(m_model->data(m_model->index(index.row(), + ComponentModel::NameColumn, index.parent()), Qt::ToolTipRole).toString()); + if (m_installer->isUpdater() || m_installer->isPackageManager()) { + m_sizeLabel->setText(tr("This component will occupy approximately %1 on your " + "harddisk.").arg(m_model->data(m_model->index(index.row(), + ComponentModel::SizeColumn, index.parent())).toString())); + } else if (m_installer->isInstaller()) { + if (Component *c = index.data(Qt::UserRole).value<Component*>()) + m_sizeLabel->setText(niceSizeText(c->value(QLatin1String("UncompressedSize")))); + } } - - m_descriptionLabel->setText( index.data( Qt::ToolTipRole ).toString() ); - if( !m_installer->isUninstaller() ) - m_sizeLabel->setText( niceSizeText( qVariantValue< Component* >( index.data( Qt::UserRole ) )->value( QString::fromLatin1( "UncompressedSize" ) ) ) ); } - void fullUninstallToggled( bool value ) + + void selectAll() { - if ( value ) - { - emit workRequested( value ); - q->setModified( value ); + if (!m_installer->isUpdater()) { + QList<Component*> components = m_installer->components(false, AllMode); + foreach (Component *comp, components) + comp->setSelected(true, AllMode); + } else { + selectDefault(); } - else - { - const QModelIndex index = m_model->index( 0, 0 ); - const QVariant data = m_model->data( index, Qt::CheckStateRole ); - m_model->setData( index, data, Qt::CheckStateRole ); + } + + void deselectAll() + { + select(false, m_installer->runMode()); + } + + void selectDefault() + { + RunModes runMode = m_installer->runMode(); + select(false, runMode); // TODO: remove after we have reworked dependency handling + select(true, runMode); + } + + void modelWasReseted() + { + wasshown = true; + if (m_installer->isUpdater()) { + m_treeView->header()->resizeSection(0, 150); + m_treeView->header()->setStretchLastSection(true); + for (int i = 0; i < m_treeView->model()->columnCount(); ++i) + m_treeView->resizeColumnToContents(i); + } else { + m_treeView->setHeaderHidden(true); + for (int i = 1; i < m_treeView->model()->columnCount(); ++i) + m_treeView->setColumnHidden(i, true); } + + bool hasChildren = false; + const int rowCount = m_model->rowCount(); + for (int row = 0; row < rowCount && !hasChildren; ++row) + hasChildren = m_model->hasChildren(m_model->index(row, 0)); + + m_treeView->setRootIsDecorated(hasChildren); + m_treeView->setCurrentIndex(m_model->index(0, 0)); + m_treeView->setExpanded(m_model->index(0, 0), true); } -Q_SIGNALS: - void workRequested( bool ); + void componentsChanged() + { + m_model->clear(); + m_model->setRunMode(m_installer->runMode()); + m_model->addRootComponents(m_installer->components(false, m_installer->runMode())); + } + +private: + void select(bool select, RunModes runMode) + { + QList<Component*> components = m_installer->components(false, runMode); + foreach (Component *comp, components) + comp->setSelected(select, runMode); + } public: ComponentSelectionPage* const q; - + bool wasshown; bool modified; bool connected; - ComponentModel* const m_model; + ComponentModel *m_model; Installer* const m_installer; QTreeView* const m_treeView; QLabel *m_descriptionLabel; QLabel *m_sizeLabel; }; -void ComponentSelectionPage::entering() -{ - wizard()->button( QWizard::CancelButton )->setEnabled( true ); - if( !d->connected ) - { - Gui* par = dynamic_cast< Gui* > ( wizard() ); - if ( par ) - { - verbose() << "connect Models" << std::endl; - connect( d->m_model, SIGNAL( workRequested( bool ) ), par, SLOT( setModified( bool ) ), Qt::QueuedConnection ); - connect( d->m_model, SIGNAL( workRequested( bool ) ), this, SLOT( setModified( bool ) ), Qt::QueuedConnection ); - connect( d.get(), SIGNAL( workRequested( bool) ), par, SLOT( setModified( bool ) ), Qt::QueuedConnection ); - connect( d->m_model, SIGNAL( modelReset() ), this, SLOT( modelWasReseted() ), Qt::QueuedConnection ); - d->connected = true; - } - if ( !d->m_installer->isInstaller() ) - setButtonText( QWizard::CancelButton, tr( "Close" ) ); - } -} + +// -- ComponentSelectionPage /*! - \class QInstaller::ComponentSelectionPage - On this page the user can select and deselect what he wants to be installed. - */ -ComponentSelectionPage::ComponentSelectionPage( Installer* installer ) - : Page( installer ), - d( new Private( this, installer ) ) -{ - setObjectName( QLatin1String( "ComponentSelectionPage" ) ); - if( !installer->isUninstaller() ) - { - setTitle( tr( "Select Components" ) ); - setSubTitle( tr( "Please select the components you want to install." ) ); - } - else - { - setTitle( tr( "Select Components" ) ); - setSubTitle( tr( "Please select the components you want to uninstall." ) ); - } - setPixmap( QWizard::LogoPixmap, logoPixmap() ); - setPixmap( QWizard::WatermarkPixmap, QPixmap() ); + \class QInstaller::ComponentSelectionPage + On this page the user can select and deselect what he wants to be installed. +*/ +ComponentSelectionPage::ComponentSelectionPage(Installer* installer) + : Page(installer), + d(new Private(this, installer)) +{ + setTitle(tr("Select Components")); + setPixmap(QWizard::LogoPixmap, logoPixmap()); + setPixmap(QWizard::WatermarkPixmap, QPixmap()); + setObjectName(QLatin1String("ComponentSelectionPage")); + + if (installer->isInstaller()) + setSubTitle(tr("Please select the components you want to install.")); + if (installer->isUninstaller()) + setSubTitle(tr("Please select the components you want to uninstall.")); + + if (installer->isUpdater()) + setSubTitle(tr("Please select the components you want to update.")); + if (installer->isPackageManager()) + setSubTitle(tr("Please (de)select the components you want to (un)install.")); } ComponentSelectionPage::~ComponentSelectionPage() { + delete d; } -void ComponentSelectionPage::modelWasReseted() +void ComponentSelectionPage::entering() { - if( d->m_treeView->model()->rowCount() == 1 ) - { - d->m_treeView->setExpanded( d->m_treeView->model()->index( 0, 0 ), true ); - d->wasshown = true; + if (!d->connected) { + if (Gui* par = dynamic_cast<Gui*> (wizard())) { + d->connected = true; + connect(d->m_model, SIGNAL(workRequested(bool)), par, SLOT(setModified(bool)), + Qt::QueuedConnection); + connect(d->m_model, SIGNAL(workRequested(bool)), this, SLOT(setModified(bool)), + Qt::QueuedConnection); + } } + d->componentsChanged(); + setModified(d->modified); + wizard()->button(QWizard::CancelButton)->setEnabled(true); } -void ComponentSelectionPage::showEvent( QShowEvent* event ) +void ComponentSelectionPage::selectAll() { - if( !d->wasshown && d->m_treeView->model()->rowCount() == 1 ) - { - d->m_treeView->setExpanded( d->m_treeView->model()->index( 0, 0 ), true ); - d->wasshown = true; - } - Page::showEvent( event ); + d->selectAll(); +} + +void ComponentSelectionPage::deselectAll() +{ + d->deselectAll(); } +void ComponentSelectionPage::selectDefault() +{ + if (installer()->isInstaller()) + d->selectDefault(); +} /*! - Selects the component with /a id in the component tree. - */ -void ComponentSelectionPage::selectComponent( const QString& id ) { - const QModelIndex idx = d->m_model->findComponent( id ); - if ( !idx.isValid() ) + Selects the component with /a id in the component tree. +*/ +void ComponentSelectionPage::selectComponent(const QString& id) +{ + const QModelIndex idx = d->m_model->findComponent(id); + if (!idx.isValid()) return; - d->m_model->setData( idx, Qt::Checked ); + d->m_model->setData(idx, Qt::Checked); } /*! - Deselects the component with /a id in the component tree. - */ -void ComponentSelectionPage::deselectComponent( const QString& id ) { - const QModelIndex idx = d->m_model->findComponent( id ); - if ( !idx.isValid() ) + Deselects the component with /a id in the component tree. +*/ +void ComponentSelectionPage::deselectComponent(const QString& id) +{ + const QModelIndex idx = d->m_model->findComponent(id); + if (!idx.isValid()) return; - d->m_model->setData( idx, Qt::Unchecked ); + d->m_model->setData(idx, Qt::Unchecked); } -void ComponentSelectionPage::setModified( bool value ) +void ComponentSelectionPage::setModified(bool value) { d->modified = value; - if (d->m_installer->isInstaller() || value) - setButtonText( QWizard::CancelButton, tr( "Cancel" ) ); - else - setButtonText( QWizard::CancelButton, tr( "Close" ) ); + setButtonText(QWizard::CancelButton, isComplete() ? tr("Cancel") : tr("Close")); } bool ComponentSelectionPage::isComplete() const { - // uninstall all - if( !d->m_treeView->isEnabled() ) - return true; - - if( d->m_installer->isPackageManager() ) - { + if (installer()->isPackageManager()) { // at least component should be different from its previous state - if ( d->modified ) + if (d->modified) return true; - else - return false; + return false; } + + const QList<Component*> components = installer()->components(true, installer()->runMode()); + if (installer()->isUpdater()) { + foreach (Component *component, components) { + if (component->isSelected(UpdaterMode)) + return true; + } + return false; + } + // at least one component needs to be selected for (un)installation - const QList< Component* > components = d->m_installer->components( true ); - for( QList< Component* >::const_iterator it = components.begin(); it != components.end(); ++it ) - { - if( (*it)->isSelected() == d->m_installer->isInstaller() ) + foreach (Component *component, components) { + if (component->isSelected() == installer()->isInstaller()) return true; } return false; } -//////////////////////////////////////////////////////////////////// -// -// TargetDirectoryPage -// -//////////////////////////////////////////////////////////////////// + +// -- TargetDirectoryPage TargetDirectoryPage::TargetDirectoryPage(Installer *installer) : Page(installer) { - setObjectName( QLatin1String( "TargetDirectoryPage" ) ); + setObjectName(QLatin1String("TargetDirectoryPage")); setTitle(tr("Installation Folder")); setPixmap(QWizard::LogoPixmap, logoPixmap()); setPixmap(QWizard::WatermarkPixmap, QPixmap()); @@ -1109,14 +1154,14 @@ TargetDirectoryPage::TargetDirectoryPage(Installer *installer) msgLabel->setText(tr("Please specify the folder where %1 " "will be installed.").arg(productName())); msgLabel->setWordWrap(true); - msgLabel->setObjectName( QLatin1String( "MessageLabel" ) ); + msgLabel->setObjectName(QLatin1String("MessageLabel")); m_lineEdit = new QLineEdit(this); - m_lineEdit->setObjectName( QLatin1String("targetDirectoryLE") ); + m_lineEdit->setObjectName(QLatin1String("targetDirectoryLE")); QPushButton *browseButton = new QPushButton(this); - browseButton->setObjectName( QLatin1String( "BrowseButton" ) ); - browseButton->setText( tr( "Browse..." ) ); + browseButton->setObjectName(QLatin1String("BrowseButton")); + browseButton->setText(tr("Browse...")); QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(msgLabel); @@ -1127,8 +1172,7 @@ TargetDirectoryPage::TargetDirectoryPage(Installer *installer) setLayout(layout); connect(browseButton, SIGNAL(clicked()), this, SLOT(dirRequested())); - connect(m_lineEdit, SIGNAL(textChanged(QString)), this, - SIGNAL(completeChanged())); + connect(m_lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(completeChanged())); } QString TargetDirectoryPage::targetDir() const @@ -1143,15 +1187,15 @@ void TargetDirectoryPage::setTargetDir(const QString &dirName) void TargetDirectoryPage::initializePage() { - QString targetDir = installer()->value( QLatin1String( "TargetDir" ) ); - if( targetDir.isEmpty() ) - { + QString targetDir = installer()->value(QLatin1String("TargetDir")); + if (targetDir.isEmpty()) { targetDir = QDir::homePath() + QDir::separator(); - if( targetDir.contains( QLatin1Char( ' ' ) ) ) // prevent spaces in the default target directory + // prevent spaces in the default target directory + if (targetDir.contains(QLatin1Char(' '))) targetDir = QDir::rootPath(); - targetDir += productName().remove( QLatin1Char( ' ' ) ); + targetDir += productName().remove(QLatin1Char(' ')); } - m_lineEdit->setText( QDir::toNativeSeparators( QDir( targetDir ).absolutePath() ) ); + m_lineEdit->setText(QDir::toNativeSeparators(QDir(targetDir).absolutePath())); Page::initializePage(); } @@ -1165,20 +1209,17 @@ bool TargetDirectoryPage::validatePage() QMessageBox::Ok); return false; } - const QDir dir( targetDir() ); - - if( dir.exists() && dir.entryList( QDir::NoDotAndDotDot ).isEmpty() ) // it exists, but is empty (might be created by the Browse button (getExistingDirectory) - { + const QDir dir(targetDir()); + // it exists, but is empty (might be created by the Browse button (getExistingDirectory) + if (dir.exists() && dir.entryList(QDir::NoDotAndDotDot).isEmpty()) { return true; - } - else if( dir.exists() && dir.isReadable() ) // it exists, but is not empty - { - if ( dir == QDir::root() ) - { + } else if (dir.exists() && dir.isReadable()) { + // it exists, but is not empty + if (dir == QDir::root()) { MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), - QLatin1String("forbiddenTargetDirectory"), tr( "Error" ), - tr( "As the install directory is completely deleted installing in %1 is forbidden" ).arg( QDir::rootPath() ), - QMessageBox::Ok); + QLatin1String("forbiddenTargetDirectory"), tr("Error"), + tr("As the install directory is completely deleted installing in %1 is forbidden") + .arg(QDir::rootPath()), QMessageBox::Ok); return false; } @@ -1187,17 +1228,13 @@ bool TargetDirectoryPage::validatePage() return true; return MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), - QLatin1String("overwriteTargetDirectory"), tr( "Warning" ), - tr( "You have selected an existing, non-empty folder for installation.\n" - "Note that it will be completely wiped on uninstallation of this application.\n" - "It is not advisable to install into this folder as installation might fail.\n" - "Do you want to continue?" ), - QMessageBox::Yes | QMessageBox::No ) == QMessageBox::Yes; - } - else - { - return true; + QLatin1String("overwriteTargetDirectory"), tr("Warning"), + tr("You have selected an existing, non-empty folder for installation.\n" + "Note that it will be completely wiped on uninstallation of this application.\n" + "It is not advisable to install into this folder as installation might fail.\n" + "Do you want to continue?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes; } + return true; } void TargetDirectoryPage::entering() @@ -1206,7 +1243,7 @@ void TargetDirectoryPage::entering() void TargetDirectoryPage::leaving() { - installer()->setValue( QLatin1String( "TargetDir" ), targetDir()); + installer()->setValue(QLatin1String("TargetDir"), targetDir()); } void TargetDirectoryPage::targetDirSelected() @@ -1215,70 +1252,67 @@ void TargetDirectoryPage::targetDirSelected() void TargetDirectoryPage::dirRequested() { - //qDebug() << "DIR REQUESTED"; - QString newDirName = QFileDialog::getExistingDirectory(this, - tr("Select Installation Folder"), targetDir() - /*, Options options = ShowDirsOnly*/); + QString newDirName = QFileDialog::getExistingDirectory(this, tr("Select Installation Folder"), + targetDir()); if (newDirName.isEmpty() || newDirName == targetDir()) return; - m_lineEdit->setText( QDir::toNativeSeparators( newDirName ) ); + m_lineEdit->setText(QDir::toNativeSeparators(newDirName)); } -// #pragma mark -- StartMenuDirectoryPage - +// -- StartMenuDirectoryPage StartMenuDirectoryPage::StartMenuDirectoryPage(Installer *installer) : Page(installer) { - setObjectName( QLatin1String( "StartMenuDirectoryPage" ) ); + setObjectName(QLatin1String("StartMenuDirectoryPage")); setTitle(tr("Start Menu shortcuts")); setPixmap(QWizard::LogoPixmap, logoPixmap()); setPixmap(QWizard::WatermarkPixmap, QPixmap()); - QString msg = tr("Select the Start Menu in which you would like to " - "create the program's shortcuts. You can also enter a name to " - "create a new folder."); + QString msg = tr("Select the Start Menu in which you would like to create the program's " + "shortcuts. You can also enter a name to create a new folder."); QLabel *msgLabel = new QLabel(this); msgLabel->setText(msg); msgLabel->setWordWrap(true); - msgLabel->setObjectName( QLatin1String( "MessageLabel" ) ); + msgLabel->setObjectName(QLatin1String("MessageLabel")); m_lineEdit = new QLineEdit(this); - m_lineEdit->setObjectName( QLatin1String( "LineEdit" ) ); + m_lineEdit->setObjectName(QLatin1String("LineEdit")); - QString startMenuDir = installer->value( QLatin1String( "StartMenuDir" ) ); + QString startMenuDir = installer->value(QLatin1String("StartMenuDir")); if (startMenuDir.isEmpty()) startMenuDir = productName(); m_lineEdit->setText(startMenuDir); // grab existing start menu folders - QSettings user(QLatin1String("HKEY_CURRENT_USER\\Software\\Microsoft\\" - "Windows\\CurrentVersion\\Explorer\\User Shell Folders"), - QSettings::NativeFormat); + QSettings user(QLatin1String("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\" + "Explorer\\User Shell Folders"), QSettings::NativeFormat); //User Shell Folders uses %USERPROFILE% - startMenuPath = replaceWindowsEnvironmentVariables( user.value(QLatin1String("Programs"), QString()).toString() ); - installer->setValue( QLatin1String( "DesktopDir" ), replaceWindowsEnvironmentVariables( user.value( QLatin1String( "Desktop" ) ).toString() ) ); + startMenuPath = replaceWindowsEnvironmentVariables(user.value(QLatin1String("Programs"), + QString()).toString()); + installer->setValue(QLatin1String("DesktopDir"), + replaceWindowsEnvironmentVariables(user.value(QLatin1String("Desktop")).toString())); QDir dir(startMenuPath); // user only dirs QStringList dirs = dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); - if (installer->value(QLatin1String("AllUsers")) == QLatin1String( "true" ) ) { + if (installer->value(QLatin1String("AllUsers")) == QLatin1String("true")) { verbose() << "AllUsers set. Using HKEY_LOCAL_MACHINE" << std::endl; - QSettings system(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\" - "Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"), - QSettings::NativeFormat); - startMenuPath = system.value(QLatin1String("Common Programs"), - QString()).toString(); - installer->setValue( QLatin1String( "DesktopDir" ), system.value( QLatin1String( "Desktop" ) ).toString() ); + QSettings system(QLatin1String("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\" + "CurrentVersion\\Explorer\\Shell Folders"), QSettings::NativeFormat); + startMenuPath = system.value(QLatin1String("Common Programs"), QString()).toString(); + installer->setValue(QLatin1String("DesktopDir"), + system.value(QLatin1String("Desktop")).toString()); dir.setPath(startMenuPath); // system only dirs dirs += dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot); } + verbose() << "StartMenuPath: " << startMenuPath; - verbose() << "DesktopDir:" << installer->value( QLatin1String("DesktopDir") ) << std::endl; + verbose() << "DesktopDir:" << installer->value(QLatin1String("DesktopDir")) << std::endl; m_listWidget = new QListWidget(this); if (!dirs.isEmpty()) { @@ -1294,57 +1328,50 @@ StartMenuDirectoryPage::StartMenuDirectoryPage(Installer *installer) setLayout(layout); - connect(m_listWidget, SIGNAL(currentItemChanged(QListWidgetItem*, - QListWidgetItem*)), this, SLOT(currentItemChanged(QListWidgetItem*))); + connect(m_listWidget, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, + SLOT(currentItemChanged(QListWidgetItem*))); } -QString -StartMenuDirectoryPage::startMenuDir() const +QString StartMenuDirectoryPage::startMenuDir() const { return m_lineEdit->text(); } -void -StartMenuDirectoryPage::setStartMenuDir(const QString &startMenuDir) +void StartMenuDirectoryPage::setStartMenuDir(const QString &startMenuDir) { m_lineEdit->setText(startMenuDir); } -void -StartMenuDirectoryPage::leaving() +void StartMenuDirectoryPage::leaving() { - installer()->setValue( QLatin1String( "StartMenuDir" ), startMenuPath + QDir::separator() + startMenuDir()); + installer()->setValue(QLatin1String("StartMenuDir"), startMenuPath + QDir::separator() + + startMenuDir()); } -void -StartMenuDirectoryPage::currentItemChanged(QListWidgetItem* current) +void StartMenuDirectoryPage::currentItemChanged(QListWidgetItem* current) { if (current) { QString dir = current->data(Qt::DisplayRole).toString(); if (!dir.isEmpty()) dir += QDir::separator(); - setStartMenuDir(dir + installer()->value( QLatin1String( "StartMenuDir" ) ) ); + setStartMenuDir(dir + installer()->value(QLatin1String("StartMenuDir"))); } } -//////////////////////////////////////////////////////////////////// -// -// ReadyForInstallationPage -// -//////////////////////////////////////////////////////////////////// +// -- ReadyForInstallationPage -ReadyForInstallationPage::ReadyForInstallationPage( Installer* installer ) - : Page(installer), - msgLabel( new QLabel ) +ReadyForInstallationPage::ReadyForInstallationPage(Installer* installer) + : Page(installer) + , msgLabel(new QLabel) { setPixmap(QWizard::LogoPixmap, logoPixmap()); setPixmap(QWizard::WatermarkPixmap, QPixmap()); - setObjectName( QLatin1String( "ReadyForInstallationPage" ) ); + setObjectName(QLatin1String("ReadyForInstallationPage")); - msgLabel->setWordWrap( true ); - msgLabel->setObjectName( QLatin1String( "MessageLabel" ) ); + msgLabel->setWordWrap(true); + msgLabel->setObjectName(QLatin1String("MessageLabel")); QLayout *layout = new QVBoxLayout(this); layout->addWidget(msgLabel); @@ -1352,154 +1379,149 @@ ReadyForInstallationPage::ReadyForInstallationPage( Installer* installer ) } /*! - \reimp - */ + \reimp +*/ void ReadyForInstallationPage::initializePage() { - setCommitPage( true ); - - if( installer()->isUninstaller() ) - { + setCommitPage(true); + + if (installer()->isUninstaller()) { setTitle(tr("Ready to Uninstall")); setButtonText(QWizard::CommitButton, tr("Uninstall")); - msgLabel->setText( tr( "Setup is now ready to begin removing %1 " - "from your computer.\n" - "The program dir %2 will be deleted completely, including " - "all content in that directory!").arg( productName(), - QDir::toNativeSeparators( QDir( installer()->value( QLatin1String( "TargetDir" ) ) ).absolutePath() ) ) ); - } - else if( installer()->isPackageManager() ) - { - setTitle( tr( "Ready to Update Packages" ) ); - setButtonText( QWizard::CommitButton, tr( "Update" ) ); - msgLabel->setText( tr( "Setup is now ready to begin installing the additional components you selected." ) ); - } - else - { + msgLabel->setText(tr("Setup is now ready to begin removing %1 from your computer.\nThe " + "program dir %2 will be deleted completely, including all content in that directory!") + .arg(productName(), + QDir::toNativeSeparators(QDir(installer()->value(QLatin1String("TargetDir"))) + .absolutePath()))); + } else if (installer()->isPackageManager() || installer()->isUpdater()) { + setTitle(tr("Ready to Update Packages")); + setButtonText(QWizard::CommitButton, tr("Update")); + msgLabel->setText(tr("Setup is now ready to begin updating your installation.")); + } else { Q_ASSERT(installer()->isInstaller()); setTitle(tr("Ready to Install")); setButtonText(QWizard::CommitButton, tr("Install")); - msgLabel->setText(tr("Setup is now ready to begin installing %1 " - "on your computer.").arg(productName())); - } + msgLabel->setText(tr("Setup is now ready to begin installing %1 on your computer.") + .arg(productName())); } - +} /*! - \reimp - */ + \reimp +*/ void ReadyForInstallationPage::entering() { initializePage(); - if( installer()->isUninstaller() ) + if (installer()->isUninstaller()) return; - const QString target = installer()->value( QLatin1String( "TargetDir" ) ); + const QString target = installer()->value(QLatin1String("TargetDir")); - const KDSysInfo::Volume vol = KDSysInfo::Volume::fromPath( target ); - const KDSysInfo::Volume tempVolume = KDSysInfo::Volume::fromPath( QInstaller::generateTemporaryFileName() ); + const KDSysInfo::Volume vol = KDSysInfo::Volume::fromPath(target); + const KDSysInfo::Volume tempVolume = + KDSysInfo::Volume::fromPath(QInstaller::generateTemporaryFileName()); const bool tempOnSameVolume = vol == tempVolume; - if ( vol.size().size() == 0 && vol.availableSpace().size() == 0 ) { //there is no better way atm to check this - verbose() << "Could not determine available space on device " << target << ". Continue silently." << std::endl; + //there is no better way atm to check this + if (vol.size().size() == 0 && vol.availableSpace().size() == 0) { + verbose() << "Could not determine available space on device " << target + << ". Continue silently." << std::endl; return; } - const KDByteSize required( installer()->requiredDiskSpace() ); - const KDByteSize tempRequired( installer()->requiredTemporaryDiskSpace() ); + const KDByteSize required(installer()->requiredDiskSpace()); + const KDByteSize tempRequired(installer()->requiredTemporaryDiskSpace()); const KDByteSize available = vol.availableSpace(); const KDByteSize tempAvailable = tempVolume.availableSpace(); - const KDByteSize realRequiredTempSpace = KDByteSize( 0.1 * tempRequired + tempRequired ); - const KDByteSize realRequiredSpace = KDByteSize( 0.5 * required + required ); + const KDByteSize realRequiredTempSpace = KDByteSize(0.1 * tempRequired + tempRequired); + const KDByteSize realRequiredSpace = KDByteSize(0.5 * required + required); - const bool tempInstFailure = tempOnSameVolume && available < realRequiredSpace + realRequiredTempSpace; + const bool tempInstFailure = tempOnSameVolume && available < realRequiredSpace + + realRequiredTempSpace; - verbose() << "Disk space check on " << target << ": required=" << required.size() << " available=" << available.size() << " size=" << vol.size().size() << std::endl; + verbose() << "Disk space check on " << target << ": required=" << required.size() + << " available=" << available.size() << " size=" << vol.size().size() << std::endl; QString tempString; - if ( tempAvailable < realRequiredTempSpace || tempInstFailure ) - { - if ( tempOnSameVolume ) - { - tempString = tr( "Not enough diskspace to store temporary files and the installation, at least %1 are required" ).arg( unitSizeText(realRequiredTempSpace + realRequiredSpace) ); - } - else - { - tempString = tr( "Not enough diskspace to store temporary files, at least %1 are required" ).arg( unitSizeText(realRequiredTempSpace.size()) ); + if (tempAvailable < realRequiredTempSpace || tempInstFailure) { + if (tempOnSameVolume) { + tempString = tr("Not enough diskspace to store temporary files and the installation, " + "at least %1 are required").arg(unitSizeText(realRequiredTempSpace + realRequiredSpace)); + } else { + tempString = tr("Not enough diskspace to store temporary files, at least %1 are required") + .arg(unitSizeText(realRequiredTempSpace.size())); } } // error on not enough space - if( available < required || tempInstFailure ) - { - if ( tempOnSameVolume ) - msgLabel->setText( tempString ); - else - msgLabel->setText( tr( "The volume you selected for installation has insufficient space for the selected components.\n\n" - "The installation requires approximately %1." ).arg( required.toString() ) + tempString ); - setCommitPage( false ); - } - // warn for less than 1% of the volume's space being free - else if( available - required < 0.01 * vol.size() ) - { - msgLabel->setText( tr( "The volume you selected for installation seems to have sufficient space for installation,\n" - "but there will not more than 1% of the volume's space available afterwards.\n\n%1" ).arg( msgLabel->text() ) ); - } - // warn for less than 100MB being free - else if( available - required < 100*1024*1024LL ) - { - msgLabel->setText( tr( "The volume you selected for installation seems to have sufficient space for installation,\n" - "but there will not more than 100 MB available afterwards.\n\n%1" ).arg( msgLabel->text() ) ); + if (available < required || tempInstFailure) { + if (tempOnSameVolume) { + msgLabel->setText(tempString); + } else { + msgLabel->setText(tr("The volume you selected for installation has insufficient space " + "for the selected components.\n\nThe installation requires approximately %1.") + .arg(required.toString()) + tempString); + } + setCommitPage(false); + } else if (available - required < 0.01 * vol.size()) { + // warn for less than 1% of the volume's space being free + msgLabel->setText(tr("The volume you selected for installation seems to have sufficient " + "space for installation,\nbut there will not more than 1% of the volume's space " + "available afterwards.\n\n%1").arg(msgLabel->text())); + } else if (available - required < 100*1024*1024LL) { + // warn for less than 100MB being free + msgLabel->setText(tr("The volume you selected for installation seems to have sufficient " + "space for installation,\nbut there will not more than 100 MB available afterwards.\n\n%1") + .arg(msgLabel->text())); } } /*! - \reimp - */ + \reimp +*/ bool ReadyForInstallationPage::isComplete() const { return isCommitPage(); } + +// -- PerformInstallationPage + /*! - \class QInstaller::PerformInstallationPage - On this page the user can see on a progressbar how far the current installation is. - */ + \class QInstaller::PerformInstallationPage + On this page the user can see on a progressbar how far the current installation is. +*/ PerformInstallationPage::PerformInstallationPage(Installer *gui) - : Page(gui), - m_performInstallationForm(new PerformInstallationForm(this)) + : Page(gui) + , m_performInstallationForm(new PerformInstallationForm(this)) { setPixmap(QWizard::LogoPixmap, logoPixmap()); setPixmap(QWizard::WatermarkPixmap, QPixmap()); - setObjectName( QLatin1String( "PerformInstallationPage" ) ); + setObjectName(QLatin1String("PerformInstallationPage")); setCommitPage(true); m_performInstallationForm->setupUi(this); - m_performInstallationForm->setDetailsWidgetVisible( installer()->isInstaller() || installer()->isPackageManager() ); - connect(ProgressCoordninator::instance(), SIGNAL( detailTextChanged( QString ) ), - m_performInstallationForm, SLOT( appendProgressDetails( QString ) ) ); + m_performInstallationForm->setDetailsWidgetVisible(installer()->isInstaller() + || installer()->isPackageManager() || installer()->isUpdater()); + connect(ProgressCoordninator::instance(), SIGNAL(detailTextChanged(QString)), + m_performInstallationForm, SLOT(appendProgressDetails(QString))); connect(ProgressCoordninator::instance(), SIGNAL(detailTextResetNeeded()), - m_performInstallationForm, SLOT(clearDetailsBrowser())); + m_performInstallationForm, SLOT(clearDetailsBrowser())); - connect(m_performInstallationForm, SIGNAL(showDetailsChanged()), - this, SLOT(toggleDetailsWereChanged())); + connect(m_performInstallationForm, SIGNAL(showDetailsChanged()), this, + SLOT(toggleDetailsWereChanged())); - connect(installer(), SIGNAL(installationStarted()), - this, SLOT(installationStarted())); - connect(installer(), SIGNAL(uninstallationStarted()), - this, SLOT(installationStarted())); - connect(installer(), SIGNAL(installationFinished()), - this, SLOT(installationFinished())); - connect(installer(), SIGNAL(uninstallationFinished()), - this, SLOT(installationFinished())); - connect( installer(), SIGNAL( titleMessageChanged( QString ) ), - this, SLOT( setTitleMessage( QString ) ) ); - connect( this, SIGNAL( setAutomatedPageSwitchEnabled( bool ) ), - installer(), SIGNAL( setAutomatedPageSwitchEnabled( bool ) ) ); + connect(installer(), SIGNAL(installationStarted()), this, SLOT(installationStarted())); + connect(installer(), SIGNAL(uninstallationStarted()), this, SLOT(installationStarted())); + connect(installer(), SIGNAL(installationFinished()), this, SLOT(installationFinished())); + connect(installer(), SIGNAL(uninstallationFinished()), this, SLOT(installationFinished())); + connect(installer(), SIGNAL(titleMessageChanged(QString)), this, SLOT(setTitleMessage(QString))); + connect(this, SIGNAL(setAutomatedPageSwitchEnabled(bool)), installer(), + SIGNAL(setAutomatedPageSwitchEnabled(bool))); } PerformInstallationPage::~PerformInstallationPage() @@ -1511,52 +1533,43 @@ void PerformInstallationPage::entering() { setComplete(false); - if( installer()->isUninstaller() ) - { - setTitle(tr("Uninstalling %1").arg(installer()->value( QLatin1String( "ProductName" ) ))); + if (installer()->isUninstaller()) { + setTitle(tr("Uninstalling %1").arg(installer()->value(QLatin1String("ProductName")))); setButtonText(QWizard::CommitButton, tr("Uninstall")); - } - else if( installer()->isPackageManager() ) - { - setTitle( tr( "Updating component configuration of %1" ).arg( installer()->value( QLatin1String( "ProductName" ) ) ) ); - setButtonText( QWizard::CommitButton, tr( "Update" ) ); - } - else - { + } else if (installer()->isPackageManager() || installer()->isUpdater()) { + setTitle(tr("Updating component configuration of %1") + .arg(installer()->value(QLatin1String("ProductName")))); + setButtonText(QWizard::CommitButton, tr("Update")); + } else { Q_ASSERT(installer()->isInstaller()); - setTitle(tr("Installing %1").arg(installer()->value( QLatin1String( "ProductName" ) ))); + setTitle(tr("Installing %1").arg(installer()->value(QLatin1String("ProductName")))); setButtonText(QWizard::CommitButton, tr("Install")); } m_performInstallationForm->enableDetails(); - emit setAutomatedPageSwitchEnabled( true ); + emit setAutomatedPageSwitchEnabled(true); } void PerformInstallationPage::initializePage() { QWizardPage::initializePage(); - if( installer()->isUninstaller() ) - { - wizard()->removePage( QInstaller::Installer::InstallationFinished + 1 ); - wizard()->removePage( QInstaller::Installer::InstallationFinished + 2 ); - setTitle( tr( "Uninstalling %1" ).arg( installer()->value( QLatin1String( "ProductName" ) ) ) ); - m_commitBtnText = tr( "Uninstall" ); - setButtonText( QWizard::CommitButton, m_commitBtnText ); - QTimer::singleShot( 30, installer(), SLOT( runUninstaller() ) ); - } - else if( installer()->isPackageManager() ) - { - setTitle(tr("Updating components of %1").arg( installer()->value( QLatin1String( "ProductName" ) ))); - m_commitBtnText = tr ( "Update" ); - setButtonText( QWizard::CommitButton, m_commitBtnText ); - QTimer::singleShot( 30, installer(), SLOT( runPackageUpdater() ) ); - } - else - { - Q_ASSERT( installer()->isInstaller() ); - setTitle( tr( "Installing %1" ).arg( installer()->value( QLatin1String( "ProductName" ) ) ) ); - m_commitBtnText = tr( "Install" ); - setButtonText( QWizard::CommitButton, m_commitBtnText ); - QTimer::singleShot( 30, installer(), SLOT( runInstaller() ) ); + if (installer()->isUninstaller()) { + wizard()->removePage(QInstaller::Installer::InstallationFinished + 1); + wizard()->removePage(QInstaller::Installer::InstallationFinished + 2); + setTitle(tr("Uninstalling %1").arg(installer()->value(QLatin1String("ProductName")))); + m_commitBtnText = tr("Uninstall"); + setButtonText(QWizard::CommitButton, m_commitBtnText); + QTimer::singleShot(30, installer(), SLOT(runUninstaller())); + } else if (installer()->isPackageManager() || installer()->isUpdater()) { + setTitle(tr("Updating components of %1").arg(installer()->value(QLatin1String("ProductName")))); + m_commitBtnText = tr ("Update"); + setButtonText(QWizard::CommitButton, m_commitBtnText); + QTimer::singleShot(30, installer(), SLOT(runPackageUpdater())); + } else { + Q_ASSERT(installer()->isInstaller()); + setTitle(tr("Installing %1").arg(installer()->value(QLatin1String("ProductName")))); + m_commitBtnText = tr("Install"); + setButtonText(QWizard::CommitButton, m_commitBtnText); + QTimer::singleShot(30, installer(), SLOT(runInstaller())); } } @@ -1568,12 +1581,12 @@ void PerformInstallationPage::installationStarted() void PerformInstallationPage::installationFinished() { m_performInstallationForm->stopUpdateProgress(); - if (!isAutoSwitching()){ + if (!isAutoSwitching()) { m_performInstallationForm->scrollDetailsToTheEnd(); - m_performInstallationForm->setDetailsButtonEnabled( false ); - setButtonText( QWizard::NextButton, tr( "Next" ) ); - setButtonText( QWizard::CommitButton, tr( "Next" ) ); - setComplete( true ); + m_performInstallationForm->setDetailsButtonEnabled(false); + setButtonText(QWizard::NextButton, tr("Next")); + setButtonText(QWizard::CommitButton, tr("Next")); + setComplete(true); } } @@ -1585,32 +1598,28 @@ bool PerformInstallationPage::isAutoSwitching() const void PerformInstallationPage::toggleDetailsWereChanged() { const bool needAutoSwitching = isAutoSwitching(); - setButtonText( QWizard::CommitButton, needAutoSwitching ? m_commitBtnText : tr( "Next" ) ); - emit setAutomatedPageSwitchEnabled( needAutoSwitching ); + setButtonText(QWizard::CommitButton, needAutoSwitching ? m_commitBtnText : tr("Next")); + emit setAutomatedPageSwitchEnabled(needAutoSwitching); } -void PerformInstallationPage::setTitleMessage( const QString& title ) +void PerformInstallationPage::setTitleMessage(const QString& title) { - setTitle( title ); + setTitle(title); } -//////////////////////////////////////////////////////////////////// -// -// FinishedPage -// -//////////////////////////////////////////////////////////////////// + +// -- FinishedPage FinishedPage::FinishedPage(Installer *installer) : Page(installer) { - //setCommitPage( true ); - setObjectName( QLatin1String( "FinishedPage" ) ); + setObjectName(QLatin1String("FinishedPage")); setTitle(tr("Completing the %1 Setup Wizard").arg(productName())); setPixmap(QWizard::WatermarkPixmap, watermarkPixmap()); setSubTitle(QString()); m_msgLabel = new QLabel(this); - m_msgLabel->setObjectName( QLatin1String( "MessageLabel" ) ); + m_msgLabel->setObjectName(QLatin1String("MessageLabel")); m_msgLabel->setWordWrap(true); #ifdef Q_WS_MAC m_msgLabel->setText(tr("Click Done to exit the Setup Wizard")); @@ -1619,7 +1628,7 @@ FinishedPage::FinishedPage(Installer *installer) #endif m_runItCheckBox = new QCheckBox(this); - m_runItCheckBox->setObjectName( QLatin1String( "RunItCheckBox" ) ); + m_runItCheckBox->setObjectName(QLatin1String("RunItCheckBox")); m_runItCheckBox->setChecked(true); QVBoxLayout *layout = new QVBoxLayout(this); @@ -1630,104 +1639,94 @@ FinishedPage::FinishedPage(Installer *installer) void FinishedPage::entering() { - if ( wizard()->button( QWizard::BackButton ) ) - wizard()->button( QWizard::BackButton )->setVisible( false ); - if ( installer()->isPackageManager() ) - { - setButtonText( QWizard::CommitButton, QLatin1String( "Finish" ) ); - wizard()->button( QWizard::CommitButton )->disconnect( this ); - connect( wizard()->button( QWizard::CommitButton ), SIGNAL( clicked() ), - this, SLOT( handleFinishClicked() ) ); - Gui* par = dynamic_cast< Gui* > ( wizard() ); - if ( par ) - { - connect( this, SIGNAL( finishClicked() ), par, SIGNAL( finishButtonClicked() ) ); - } + if (wizard()->button(QWizard::BackButton)) + wizard()->button(QWizard::BackButton)->setVisible(false); + + if (installer()->isPackageManager() || installer()->isUpdater()) { + setButtonText(QWizard::CommitButton, QLatin1String("Finish")); + wizard()->button(QWizard::CommitButton)->disconnect(this); + connect(wizard()->button(QWizard::CommitButton), SIGNAL(clicked()), this, + SLOT(handleFinishClicked())); + if (Gui* par = dynamic_cast<Gui*> (wizard())) + connect(this, SIGNAL(finishClicked()), par, SIGNAL(finishButtonClicked())); } + verbose() << "FINISHED ENTERING: " << std::endl; - connect( wizard()->button( QWizard::FinishButton ), SIGNAL( clicked() ), - this, SLOT( handleFinishClicked() ) ); - wizard()->setOption(QWizard::NoCancelButton, true); - if (installer()->status() == Installer::InstallerSucceeded) { + connect(wizard()->button(QWizard::FinishButton), SIGNAL(clicked()), this, + SLOT(handleFinishClicked())); + wizard()->setOption(QWizard::NoCancelButton, true); - const QString finishedtext = installer()->value( QLatin1String( "FinishedText" ) ); - if( ! finishedtext.isEmpty() ) - m_msgLabel->setText( finishedtext ); + if (installer()->status() == Installer::Success) { + const QString finishedtext = installer()->value(QLatin1String("FinishedText")); + if (!finishedtext.isEmpty()) + m_msgLabel->setText(finishedtext); - if ( ! installer()->value( QLatin1String( "RunProgram" ) ).isEmpty() ) { + if (!installer()->value(QLatin1String("RunProgram")).isEmpty()) { m_runItCheckBox->show(); - m_runItCheckBox->setText( installer()->value( QLatin1String( "RunProgramDescription" ), tr( "Run %1 now." ).arg( productName() ) ) ); + m_runItCheckBox->setText(installer()->value(QLatin1String("RunProgramDescription"), + tr("Run %1 now.").arg(productName()))); return; // job done } - } else { setTitle(tr("The %1 Setup Wizard failed").arg(productName())); } m_runItCheckBox->hide(); - m_runItCheckBox->setChecked( false ); + m_runItCheckBox->setChecked(false); } void FinishedPage::initializePage() { - setCommitPage( true ); - if ( wizard()->button( QWizard::BackButton ) ) - wizard()->button( QWizard::BackButton )->setVisible( false ); - if ( installer()->isPackageManager() ) - { - setButtonText( QWizard::CommitButton, QLatin1String( "Finish" ) ); - setButtonText( QWizard::NextButton, QLatin1String( "Finish" ) ); + setCommitPage(true); + if (wizard()->button(QWizard::BackButton)) + wizard()->button(QWizard::BackButton)->setVisible(false); + + if (installer()->isPackageManager() || installer()->isUpdater()) { + setButtonText(QWizard::CommitButton, QLatin1String("Finish")); + setButtonText(QWizard::NextButton, QLatin1String("Finish")); } } void FinishedPage::leaving() { - disconnect( wizard(), SIGNAL( customButtonClicked( int ) ), - this, SLOT( handleFinishClicked() ) ); - if ( installer()->isPackageManager() ) - { - disconnect( wizard()->button( QWizard::CommitButton ), SIGNAL( clicked() ), - this, SLOT( handleFinishClicked() ) ); - Gui* par = dynamic_cast< Gui* > ( wizard() ); - if ( par ) - { - disconnect( this, SIGNAL( finishClicked() ), par, SIGNAL( finishButtonClicked() ) ); - } + disconnect(wizard(), SIGNAL(customButtonClicked(int)), this, SLOT(handleFinishClicked())); + if (installer()->isPackageManager() || installer()->isUpdater()) { + disconnect(wizard()->button(QWizard::CommitButton), SIGNAL(clicked()), this, + SLOT(handleFinishClicked())); + if (Gui* par = dynamic_cast<Gui*> (wizard())) + disconnect(this, SIGNAL(finishClicked()), par, SIGNAL(finishButtonClicked())); } } void FinishedPage::handleFinishClicked() { - QString program = installer()->value( QLatin1String( "RunProgram" ) ); - if ( !m_runItCheckBox->isChecked() || program.isEmpty() ) + QString program = installer()->value(QLatin1String("RunProgram")); + if (!m_runItCheckBox->isChecked() || program.isEmpty()) return; - program = installer()->replaceVariables( program ); + program = installer()->replaceVariables(program); verbose() << "STARTING " << program << std::endl; - QProcess::startDetached( program ); + QProcess::startDetached(program); } -//////////////////////////////////////////////////////////////////// -// -// RestartPage -// -//////////////////////////////////////////////////////////////////// + +// -- RestartPage RestartPage::RestartPage(Installer *installer) : Page(installer) { - setObjectName( QLatin1String( "RestartPage" ) ); - setTitle(tr("Completing the %1 Setup Wizard").arg( productName() ) ); + setObjectName(QLatin1String("RestartPage")); + setTitle(tr("Completing the %1 Setup Wizard").arg(productName())); setPixmap(QWizard::WatermarkPixmap, watermarkPixmap()); - setSubTitle( QString() ); - setFinalPage( false ); + setSubTitle(QString()); + setFinalPage(false); } void RestartPage::entering() { emit restart(); wizard()->restart(); - if ( wizard()->button( QWizard::FinishButton ) ) - wizard()->button( QWizard::FinishButton )->setVisible( false ); + if (wizard()->button(QWizard::FinishButton)) + wizard()->button(QWizard::FinishButton)->setVisible(false); wizard()->setOption(QWizard::NoCancelButton, false); } diff --git a/installerbuilder/libinstaller/qinstallergui.h b/installerbuilder/libinstaller/qinstallergui.h index 4e602ebcc..ea5a35ce5 100644 --- a/installerbuilder/libinstaller/qinstallergui.h +++ b/installerbuilder/libinstaller/qinstallergui.h @@ -26,18 +26,17 @@ #ifndef QINSTALLER_GUI_H #define QINSTALLER_GUI_H -#include <QtGui/QWizard> -#include <QtCore/QMetaType> +#include "qinstaller.h" +#include "messageboxhandler.h" #include <QtCore/QEvent> -#include <QtGui/QAbstractButton> - -#include <KDToolsCore/pimpl_ptr> +#include <QtCore/QMetaType> -#include "qinstaller.h" -#include "messageboxhandler.h" +#include <QtGui/QAbstractButton> +#include <QtGui/QWizard> // FIXME: move to private classes +QT_BEGIN_NAMESPACE class QCheckBox; class QLabel; class QLineEdit; @@ -48,31 +47,56 @@ class QRadioButton; class QTextBrowser; class QTreeView; class QScriptEngine; +QT_END_NAMESPACE namespace QInstaller { class Installer; -class Page; class IntroductionPage; +class Page; class PerformInstallationForm; -class INSTALLER_EXPORT MessageBoxHandlerImpl : public MessageBoxHandler { + +// -- MessageBoxHandlerImpl + +class INSTALLER_EXPORT MessageBoxHandlerImpl : public MessageBoxHandler +{ public: - explicit MessageBoxHandlerImpl( QWidget* parentWidget ); - void setAutomaticAnswer( const QString& identifier, QMessageBox::StandardButton answer ); - void setDefaultAction( DefaultAction da ); - - QMessageBox::StandardButton critical( const QString& identifier, const QString& title, const QString& text, QMessageBox::StandardButtons buttons=QMessageBox::Ok, QMessageBox::StandardButton button=QMessageBox::NoButton ) const; - QMessageBox::StandardButton information( const QString& identifier, const QString& title, const QString& text, QMessageBox::StandardButtons buttons=QMessageBox::Ok, QMessageBox::StandardButton button=QMessageBox::NoButton ) const; - QMessageBox::StandardButton question( const QString& identifier, const QString& title, const QString& text, QMessageBox::StandardButtons buttons=QMessageBox::Yes|QMessageBox::No, QMessageBox::StandardButton button=QMessageBox::NoButton ) const; - QMessageBox::StandardButton warning( const QString& identifier, const QString& title, const QString& text, QMessageBox::StandardButtons buttons=QMessageBox::Ok, QMessageBox::StandardButton button=QMessageBox::NoButton ) const; - QMessageBox::StandardButton critical( QWidget* parent, const QString& identifier, const QString& title, const QString& text, QMessageBox::StandardButtons buttons=QMessageBox::Ok, QMessageBox::StandardButton button=QMessageBox::NoButton ) const; - QMessageBox::StandardButton information( QWidget* parent, const QString& identifier, const QString& title, const QString& text, QMessageBox::StandardButtons buttons=QMessageBox::Ok, QMessageBox::StandardButton button=QMessageBox::NoButton ) const; - QMessageBox::StandardButton question( QWidget* parent, const QString& identifier, const QString& title, const QString& text, QMessageBox::StandardButtons buttons=QMessageBox::Yes|QMessageBox::No, QMessageBox::StandardButton button=QMessageBox::NoButton ) const; - QMessageBox::StandardButton warning( QWidget* parent, const QString& identifier, const QString& title, const QString& text, QMessageBox::StandardButtons buttons=QMessageBox::Ok, QMessageBox::StandardButton button=QMessageBox::NoButton ) const; + explicit MessageBoxHandlerImpl(QWidget* parentWidget); + void setAutomaticAnswer(const QString& identifier, QMessageBox::StandardButton answer); + void setDefaultAction(DefaultAction da); + + QMessageBox::StandardButton critical(const QString& identifier, const QString& title, + const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton button = QMessageBox::NoButton) const; + QMessageBox::StandardButton information(const QString& identifier, const QString& title, + const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton button = QMessageBox::NoButton) const; + QMessageBox::StandardButton question(const QString& identifier, const QString& title, + const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Yes|QMessageBox::No, + QMessageBox::StandardButton button = QMessageBox::NoButton) const; + QMessageBox::StandardButton warning(const QString& identifier, const QString& title, + const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton button = QMessageBox::NoButton) const; + QMessageBox::StandardButton critical(QWidget* parent, const QString& identifier, + const QString& title, const QString& text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton button = QMessageBox::NoButton) const; + QMessageBox::StandardButton information(QWidget* parent, const QString& identifier, + const QString& title, const QString& text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton button = QMessageBox::NoButton) const; + QMessageBox::StandardButton question(QWidget* parent, const QString& identifier, + const QString& title, const QString& text, + QMessageBox::StandardButtons buttons = QMessageBox::Yes|QMessageBox::No, + QMessageBox::StandardButton button = QMessageBox::NoButton) const; + QMessageBox::StandardButton warning(QWidget* parent, const QString& identifier, + const QString& title, const QString& text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton button = QMessageBox::NoButton) const; private: - QMessageBox::StandardButton autoReply( QMessageBox::StandardButtons buttons ) const; + QMessageBox::StandardButton autoReply(QMessageBox::StandardButtons buttons) const; private: QList<QMessageBox::Button> m_buttonOrder; @@ -81,6 +105,9 @@ private: QHash<QString,QMessageBox::StandardButton> m_automaticAnswers; }; + +// -- Gui + class INSTALLER_EXPORT Gui : public QWizard { Q_OBJECT @@ -89,17 +116,17 @@ public: explicit Gui(Installer *installer, QWidget *parent = 0); ~Gui(); virtual void init() = 0; - IntroductionPage* introductionPage() const; - void loadControlScript( const QString& scriptPath ); - void callControlScriptMethod( const QString& methodName ); + void loadControlScript(const QString& scriptPath); + void callControlScriptMethod(const QString& methodName); void triggerControlScriptForCurrentPage(); QScriptEngine* controlScriptEngine() const; - Q_INVOKABLE QWidget* pageWidgetByObjectName( const QString& name ) const; + Q_INVOKABLE Page* page(int pageId) const; + Q_INVOKABLE QWidget* pageWidgetByObjectName(const QString& name) const; Q_INVOKABLE QWidget* currentPageWidget() const; - Q_INVOKABLE void clickButton( int wizardButton, int delayInMs=0 ); + Q_INVOKABLE void clickButton(int wizardButton, int delayInMs=0); Q_SIGNALS: void interrupted(); @@ -112,32 +139,33 @@ public slots: void reject(); void rejectWithoutPrompt(); void showFinishedPage(); - void setModified( bool value ); + void setModified(bool value); protected Q_SLOTS: - void wizardPageInsertionRequested( QWidget* widget, Installer::WizardPage page ); - void wizardPageRemovalRequested( QWidget* widget ); - void wizardWidgetInsertionRequested( QWidget* widget, Installer::WizardPage page ); - void wizardWidgetRemovalRequested( QWidget* widget ); - void wizardPageVisibilityChangeRequested( bool visible, int page ); - void slotCurrentPageChanged( int id ); - void delayedControlScriptExecution( int id ); + void wizardPageInsertionRequested(QWidget* widget, Installer::WizardPage page); + void wizardPageRemovalRequested(QWidget* widget); + void wizardWidgetInsertionRequested(QWidget* widget, Installer::WizardPage page); + void wizardWidgetRemovalRequested(QWidget* widget); + void wizardPageVisibilityChangeRequested(bool visible, int page); + void slotCurrentPageChanged(int id); + void delayedControlScriptExecution(int id); - void setAutomatedPageSwitchEnabled( bool request ); + void setAutomatedPageSwitchEnabled(bool request); protected: - bool event( QEvent* event ); + bool event(QEvent* event); Installer *m_installer; private: class Private; Private* const d; - QInstaller::IntroductionPage *m_introPage; QMap< int, QWizardPage* > defaultPages; }; +// -- Page + class INSTALLER_EXPORT Page : public QWizardPage { Q_OBJECT @@ -158,8 +186,7 @@ protected: // Inserts widget into the same layout like a sibling identified // by its name. Default position is just behind the sibling. - virtual void insertWidget(QWidget *widget, const QString &siblingName, - int offset = 1); + virtual void insertWidget(QWidget *widget, const QString &siblingName, int offset = 1); virtual QWidget *findWidget(const QString &objectName) const; virtual void setVisible(bool visible); // reimp @@ -179,26 +206,33 @@ private: }; +// -- IntroductionPage + class INSTALLER_EXPORT IntroductionPage : public Page { Q_OBJECT + public: explicit IntroductionPage(Installer *installer); void setText(const QString &text); void setWidget(QWidget *w); + private: QLabel *m_msgLabel; QWidget *m_widget; }; +// -- LicenseAgreementPage + class INSTALLER_EXPORT LicenseAgreementPage : public Page { Q_OBJECT public: explicit LicenseAgreementPage(Installer *installer); - void initializePage(); + + void entering(); bool isComplete() const; private Q_SLOTS: @@ -217,6 +251,8 @@ private: }; +// -- ComponentSelectionPage + class INSTALLER_EXPORT ComponentSelectionPage : public Page { Q_OBJECT @@ -224,23 +260,29 @@ class INSTALLER_EXPORT ComponentSelectionPage : public Page public: explicit ComponentSelectionPage(Installer *installer); ~ComponentSelectionPage(); + bool isComplete() const; - Q_INVOKABLE void selectComponent( const QString& id ); - Q_INVOKABLE void deselectComponent( const QString& id ); + Q_INVOKABLE void selectAll(); + Q_INVOKABLE void deselectAll(); + Q_INVOKABLE void selectDefault(); + Q_INVOKABLE void selectComponent(const QString& id); + Q_INVOKABLE void deselectComponent(const QString& id); protected: - void showEvent( QShowEvent* event ); void entering(); + private Q_SLOTS: - void setModified( bool value ); - void modelWasReseted(); + void setModified(bool value); private: class Private; - kdtools::pimpl_ptr< Private > d; + Private *d; }; + +// -- TargetDirectoryPage + class INSTALLER_EXPORT TargetDirectoryPage : public Page { Q_OBJECT @@ -266,6 +308,8 @@ private: }; +// -- StartMenuDirectoryPage + class INSTALLER_EXPORT StartMenuDirectoryPage : public Page { Q_OBJECT @@ -289,6 +333,8 @@ private: }; +// -- ReadyForInstallationPage + class INSTALLER_EXPORT ReadyForInstallationPage : public Page { Q_OBJECT @@ -304,6 +350,8 @@ private: }; +// -- PerformInstallationPage + class INSTALLER_EXPORT PerformInstallationPage : public Page { Q_OBJECT @@ -319,11 +367,11 @@ protected: bool isInterruptible() const { return true; } public Q_SLOTS: - void setTitleMessage( const QString& title ); + void setTitleMessage(const QString& title); Q_SIGNALS: void installationRequested(); - void setAutomatedPageSwitchEnabled( bool request ); + void setAutomatedPageSwitchEnabled(bool request); private Q_SLOTS: void installationStarted(); @@ -335,6 +383,9 @@ private: PerformInstallationForm *m_performInstallationForm; }; + +// -- FinishedPage + class INSTALLER_EXPORT FinishedPage : public Page { Q_OBJECT @@ -358,6 +409,9 @@ private: QCheckBox *m_runItCheckBox; }; + +// -- RestartPage + class INSTALLER_EXPORT RestartPage : public Page { Q_OBJECT @@ -368,6 +422,7 @@ public: protected: void entering(); void leaving(); + Q_SIGNALS: void restart(); }; diff --git a/installerbuilder/libinstaller/selfrestartoperation.cpp b/installerbuilder/libinstaller/selfrestartoperation.cpp index caf51c3f0..f7330bbd1 100644 --- a/installerbuilder/libinstaller/selfrestartoperation.cpp +++ b/installerbuilder/libinstaller/selfrestartoperation.cpp @@ -54,10 +54,9 @@ void SelfRestartOperation::backup() bool SelfRestartOperation::performOperation() { const Installer* const installer = qVariantValue< Installer* >( value( QLatin1String( "installer" ) ) ); - if( !installer->isUpdater() ) - { - setError( UserDefinedError ); - setErrorString ( tr("Self Restart: Only valid within Updater.") ); + if(!installer->isUpdater() && !installer->isPackageManager()) { + setError(UserDefinedError); + setErrorString (tr("Self Restart: Only valid within updater or packagemanager mode.")); return false; } diff --git a/installerbuilder/libinstaller/updateagent.cpp b/installerbuilder/libinstaller/updateagent.cpp index dad07373b..60d0c43b2 100644 --- a/installerbuilder/libinstaller/updateagent.cpp +++ b/installerbuilder/libinstaller/updateagent.cpp @@ -80,7 +80,7 @@ public: Installer installer; installer.setRemoteRepositories( settings.repositories() ); - QList< Component* > components = installer.components(); + QList< Component* > components = installer.components(false, UpdaterMode); // remove all unimportant updates if( settings.checkOnlyImportantUpdates() ) diff --git a/installerbuilder/libinstaller/updater.cpp b/installerbuilder/libinstaller/updater.cpp index b4e301391..f1250029c 100644 --- a/installerbuilder/libinstaller/updater.cpp +++ b/installerbuilder/libinstaller/updater.cpp @@ -31,294 +31,288 @@ ** **************************************************************************/ #include "updater.h" -#include "messageboxhandler.h" - -#include <QDateTime> -#include <QDomDocument> -#include <QProgressDialog> -#include <QSharedPointer> #include "common/binaryformat.h" -#include "common/binaryformatenginehandler.h" #include "common/errors.h" #include "common/utils.h" - +#include "componentselectiondialog.h" +#include "init.h" +#include "installationprogressdialog.h" +#include "messageboxhandler.h" #include "qinstaller.h" #include "qinstallercomponent.h" #include "qinstallercomponentmodel.h" #include "updatesettings.h" -#include "init.h" - -#include "installationprogressdialog.h" -#include "componentselectiondialog.h" #include <KDUpdater/Application> #include <KDUpdater/PackagesInfo> -#include <KDToolsCore/KDAutoPointer> +#include <QtCore/QDateTime> + +#include <QtGui/QProgressDialog> -#include <memory> -#include <iostream> +#include <QtXml/QDomDocument> using namespace QInstaller; +using namespace QInstallerCreator; + + +// -- Updater::Private class Updater::Private { public: - Private() : dialog( 0 ) { - } - - Installer* installer_shared; - ComponentSelectionDialog * dialog; - QSharedPointer< QInstallerCreator::BinaryFormatEngineHandler > handler; - QSharedPointer< UpdateSettings > settings; - QList< Component* > components; + Private() + : dialog(0) {} + + Installer *installer_shared; + ComponentSelectionDialog *dialog; + QSharedPointer<QInstallerCreator::BinaryFormatEngineHandler> handler; + QSharedPointer<UpdateSettings> settings; + QList<QInstaller::Component*> components; }; -void Updater::init() -{ - //d->installer.setLinearComponentList( true ); - d->handler = QSharedPointer< QInstallerCreator::BinaryFormatEngineHandler > ( new QInstallerCreator::BinaryFormatEngineHandler( QInstallerCreator::ComponentIndex() ) ); - d->settings = QSharedPointer< UpdateSettings > ( new UpdateSettings() ); - //d->dialog = QSharedPointer< ComponentSelectionDialog >( new ComponentSelectionDialog( &d->installer ) ); - //ComponentModel::setVirtualComponentsVisible( true ); -} -Updater::Updater( QObject* parent ) - : QObject( parent ) -{ -} +// -- Updater -void Updater::setInstaller( QInstaller::Installer * installer ) +Updater::Updater(QObject* parent) + : QObject(parent) + , d(new Private) { - d->installer_shared = installer; } -//QInstaller::Installer * Updater::getInstaller() -//{ -// return &d->installer; -//} - Updater::~Updater() { + delete d; } -ComponentSelectionDialog* Updater::updaterGui() const { - return d->dialog; +void Updater::init() +{ + d->settings = QSharedPointer<UpdateSettings> (new UpdateSettings()); + d->handler = + QSharedPointer<BinaryFormatEngineHandler> (new BinaryFormatEngineHandler(ComponentIndex())); } -void Updater::setUpdaterGui( QInstaller::ComponentSelectionDialog * gui ) +void Updater::setVerbose(bool verbose) { - if ( d->dialog ) - disconnect( d->dialog, SIGNAL( requestUpdate() ), this, SLOT( update() ) ); - //disconnect( d->dialog, SIGNAL( accepted() ), this, SLOT( update() ) ); - d->dialog = gui; - //connect( gui, SIGNAL( accepted() ), this, SLOT( update() ) ); - connect( gui, SIGNAL( requestUpdate() ), this, SLOT( update() ) ); + QInstaller::setVerbose(verbose); } -bool Updater::searchForUpdates() +void Updater::setInstaller(QInstaller::Installer *installer) { - try - { - KDAutoPointer< QProgressDialog > progress( new QProgressDialog( d->dialog ) ); - progress->setLabelText( tr( "Checking for updates..." ) ); - progress->setRange( 0, 0 ); - connect (progress.get(), SIGNAL( canceled() ), d->dialog, SLOT( reject() ) ); - progress->show(); + d->installer_shared = installer; +} - d->settings->setLastCheck( QDateTime::currentDateTime() ); - d->installer_shared->setRemoteRepositories( d->settings->repositories() ); - d->installer_shared->setValue(QLatin1String("TargetDir"), - QFileInfo(d->installer_shared->updaterApplication().packagesInfo()->fileName()) - .absolutePath()); - } - catch( const Error& error ) - { - QMessageBox::critical( d->dialog, tr( "Check for Updates" ), tr( "Error while checking for updates:\n%1" ).arg( QString::fromStdString( error.what() ) ) ); - d->settings->setLastResult( tr( "Software Update failed." ) ); - return false; - } - catch( ... ) - { - QMessageBox::critical( d->dialog, tr( "Check for Updates" ), tr( "Unknown error while checking for updates." ) ); - d->settings->setLastResult( tr( "Software Update failed." ) ); - return false; - } +bool Updater::checkForUpdates(bool checkonly) +{ + QInstaller::init(); - d->components = d->installer_shared->components( true ); + BinaryContent content = BinaryContent::readFromApplicationFile(); + content.registerEmbeddedQResources(); - // no updates for us - if( d->components.isEmpty() ) - { - QMessageBox::information( d->dialog, tr( "Check for Updates" ), tr( "There are currently no updates available." ) ); + if (content.magicmaker == MagicInstallerMarker) { + QMessageBox::information(0, tr("Check for Updates"), + tr("Impossible to use an installer to check for updates!")); return false; } - return true; -} -bool Updater::update() -{ -// if( d->dialog->exec() == QDialog::Rejected ) -// return false; - - try - { - InstallationProgressDialog* dialog = new InstallationProgressDialog( d->dialog ); - dialog->setAttribute( Qt::WA_DeleteOnClose, true ); - dialog->setModal( true ); - dialog->setFixedSize( 480, 360 ); - dialog->show(); - connect( dialog, SIGNAL( canceled() ), d->installer_shared, SLOT( interrupt() ) ); - connect( d->installer_shared, SIGNAL( updateFinished() ), dialog, SLOT( finished() ) ); - d->installer_shared->installSelectedComponents(); - QEventLoop loop; - connect( dialog, SIGNAL( destroyed() ), &loop, SLOT( quit() ) ); - loop.exec(); - } - catch( const Error& error ) - { - //if the user clicked the confirm cancel dialog he don't want to see another messagebox - if ( d->installer_shared->status() != Installer::InstallerCanceledByUser ) - { - MessageBoxHandler::critical(d->dialog, - QLatin1String("updaterCriticalInstallError"), tr( "Check for Updates" ), - tr( "Error while installing updates:\n%1" ).arg( error.message() ) ); - } - d->installer_shared->rollBackInstallation(); - d->settings->setLastResult( tr( "Software Update failed." ) ); - emit updateFinished( true ); - return false; - } - catch( ... ) - { - MessageBoxHandler::critical(d->dialog, - QLatin1String("updaterCriticalUnknownError"), - tr( "Check for Updates" ), - tr( "Unknown error while installing updates." ) ); - d->installer_shared->rollBackInstallation(); - d->settings->setLastResult( tr( "Software Update failed." ) ); - emit updateFinished( true ); - return false; - } - emit updateFinished( false ); - return true; -} + Installer installer(content.magicmaker, content.performedOperations); + installer.setUpdater(); + installer.setLinearComponentList(true); -bool Updater::checkForUpdates( bool checkonly ) -{ KDUpdater::Application updaterapp; - BinaryContent content = BinaryContent::readFromApplicationFile(); - Installer installer( content.magicmaker, content.performedOperations ); - QInstaller::init(); - installer.setUpdaterApplication( &updaterapp ); - installer.setPackageManager(); - installer.setLinearComponentList( true ); - - std::auto_ptr< QInstallerCreator::BinaryFormatEngineHandler > handler( new QInstallerCreator::BinaryFormatEngineHandler( QInstallerCreator::ComponentIndex() ) ); - handler->setComponentIndex( QInstallerCreator::ComponentIndex() ); - - UpdateSettings settings; - KDAutoPointer< ComponentSelectionDialog > dialog( checkonly ? 0 : new ComponentSelectionDialog( &installer ) ); - if( !checkonly ) + installer.setUpdaterApplication(&updaterapp); + + QSharedPointer<UpdateSettings> settings = QSharedPointer<UpdateSettings> (new UpdateSettings());; + QScopedPointer<ComponentSelectionDialog> dialog(checkonly + ? 0 : new ComponentSelectionDialog(&installer)); + if (!checkonly) { + d->settings = settings; + setInstaller(&installer); + setUpdaterGui(dialog.data()); dialog->show(); + } - ComponentModel::setVirtualComponentsVisible( true ); + ComponentModel::setVirtualComponentsVisible(true); - try - { - KDAutoPointer< QProgressDialog > progress( checkonly ? 0 : new QProgressDialog( dialog.get() ) ); - if( !checkonly ) - { - progress->setLabelText( tr( "Checking for updates..." ) ); - progress->setRange( 0, 0 ); + try { + QScopedPointer<QProgressDialog> progress(checkonly ? 0 : new QProgressDialog(dialog.data())); + if (!checkonly) { + progress->setLabelText(tr("Checking for updates...")); + progress->setRange(0, 0); progress->show(); } - - settings.setLastCheck( QDateTime::currentDateTime() ); - installer.setRemoteRepositories( settings.repositories() ); - if ( installer.status() == QInstaller::Installer::InstallerFailed ) + + settings->setLastCheck(QDateTime::currentDateTime()); + installer.setRemoteRepositories(settings->repositories()); + if (installer.status() == QInstaller::Installer::Failure) return false; - installer.setValue( QLatin1String( "TargetDir" ), QFileInfo( updaterapp.packagesInfo()->fileName() ).absolutePath() ); - } - catch( const Error& error ) - { - if( !checkonly ) - QMessageBox::critical( dialog.get(), tr( "Check for Updates" ), tr( "Error while checking for updates:\n%1" ).arg( QString::fromStdString( error.what() ) ) ); - settings.setLastResult( tr( "Software Update failed." ) ); + installer.setValue(QLatin1String("TargetDir"), + QFileInfo(updaterapp.packagesInfo()->fileName()).absolutePath()); + } catch (const Error& error) { + QMessageBox::critical(dialog.data(), tr("Check for Updates"), + tr("Error while checking for updates:\n%1").arg(QString::fromStdString(error.what()))); + settings->setLastResult(tr("Software Update failed.")); return false; - } - catch( ... ) - { - if( !checkonly ) - QMessageBox::critical( dialog.get(), tr( "Check for Updates" ), tr( "Unknown error while checking for updates." ) ); - settings.setLastResult( tr( "Software Update failed." ) ); + } catch (...) { + QMessageBox::critical(dialog.data(), tr("Check for Updates"), + tr("Unknown error while checking for updates.")); + settings->setLastResult(tr("Software Update failed.")); return false; } - const QList< Component* > components = installer.components( true, UpdaterMode ); + const QList<QInstaller::Component*> components = installer.components(true, UpdaterMode); // no updates for us - if( components.isEmpty() && !checkonly ) - { - QMessageBox::information( dialog.get(), tr( "Check for Updates" ), tr( "There are currently no updates available." ) ); + if (components.isEmpty()) { + QMessageBox::information(dialog.data(), tr("Check for Updates"), + tr("There are currently no updates available.")); return false; } - if( checkonly ) - { + if (checkonly) { QDomDocument doc; - QDomElement root = doc.createElement( QLatin1String( "updates" ) ); - doc.appendChild( root ); - for( QList< Component* >::const_iterator it = components.begin(); it != components.end(); ++it ) - { - QDomElement update = doc.createElement( QLatin1String( "update" ) ); - update.setAttribute( QLatin1String( "name" ), (*it)->value( QLatin1String( "DisplayName" ) ) ); - update.setAttribute( QLatin1String( "version" ), (*it)->value( QLatin1String( "Version" ) ) ); - update.setAttribute( QLatin1String( "size" ), (*it)->value( QLatin1String( "UncompressedSize" ) ) ); - root.appendChild( update ); + QDomElement root = doc.createElement(QLatin1String("updates")); + doc.appendChild(root); + + QList< QInstaller::Component* >::const_iterator it; + for (it = components.begin(); it != components.end(); ++it) { + QDomElement update = doc.createElement(QLatin1String("update")); + update.setAttribute(QLatin1String("name"), (*it)->value(QLatin1String("DisplayName"))); + update.setAttribute(QLatin1String("version"), (*it)->value(QLatin1String("Version"))); + update.setAttribute(QLatin1String("size"), (*it)->value(QLatin1String("UncompressedSize"))); + root.appendChild(update); } - std::cout << doc.toString( 4 ).toStdString() << std::endl; + QMessageBox::information(dialog.data(), tr("Check for Updates"), doc.toString(4)); return true; } - if( dialog->exec() == QDialog::Rejected ) + if (dialog->exec() == QDialog::Rejected) return false; - try - { + try { InstallationProgressDialog* dialog = new InstallationProgressDialog(); - dialog->setModal( true ); - dialog->setAttribute( Qt::WA_DeleteOnClose, true ); - dialog->setFixedSize( 480, 360 ); + dialog->setModal(true); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + dialog->setFixedSize(480, 360); dialog->show(); - connect( dialog, SIGNAL( canceled() ), &installer, SLOT( interrupt() ) ); - connect( &installer, SIGNAL( installationProgressTextChanged( QString ) ), dialog, SLOT( changeInstallationProgressText( QString ) ) ); - connect( &installer, SIGNAL( installationProgressChanged( int ) ), dialog, SLOT( changeInstallationProgress( int ) ) ); - connect( &installer, SIGNAL( updateFinished() ), dialog, SLOT( finished() ) ); + + connect(dialog, SIGNAL(canceled()), &installer, SLOT(interrupt())); + connect(&installer, SIGNAL(installationProgressTextChanged(QString)), dialog, + SLOT(changeInstallationProgressText(QString))); + connect(&installer, SIGNAL(installationProgressChanged(int)), dialog, + SLOT(changeInstallationProgress(int))); + connect(&installer, SIGNAL(updateFinished()), dialog, SLOT(finished())); installer.installSelectedComponents(); + QEventLoop loop; - connect( dialog, SIGNAL( destroyed() ), &loop, SLOT( quit() ) ); + connect(dialog, SIGNAL(destroyed()), &loop, SLOT(quit())); loop.exec(); - } - catch( const Error& error ) - { + } catch (const Error& error) { //if the user clicked the confirm cancel dialog he don't want to see another messagebox - if ( installer.status() != Installer::InstallerCanceledByUser ) - { - QMessageBox::critical( dialog.get(), tr( "Check for Updates" ), tr( "Error while installing updates:\n%1" ).arg( QString::fromStdString( error.what() ) ) ); + if (installer.status() != Installer::Canceled) { + QMessageBox::critical(dialog.data(), tr("Check for Updates"), + tr("Error while installing updates:\n%1").arg(QString::fromStdString(error.what()))); } installer.rollBackInstallation(); - settings.setLastResult( tr( "Software Update failed." ) ); + settings->setLastResult(tr("Software Update failed.")); return false; - } - catch( ... ) - { - QMessageBox::critical( dialog.get(), tr( "Check for Updates" ), tr( "Unknown error while installing updates." ) ); + } catch (...) { + QMessageBox::critical(dialog.data(), tr("Check for Updates"), + tr("Unknown error while installing updates.")); installer.rollBackInstallation(); - settings.setLastResult( tr( "Software Update failed." ) ); + settings->setLastResult(tr("Software Update failed.")); return false; } return true; } + +ComponentSelectionDialog* Updater::updaterGui() const +{ + return d->dialog; +} + +void Updater::setUpdaterGui(QInstaller::ComponentSelectionDialog *gui) +{ + if (d->dialog) + disconnect(d->dialog, SIGNAL(requestUpdate()), this, SLOT(update())); + + d->dialog = gui; + connect(gui, SIGNAL(requestUpdate()), this, SLOT(update())); +} + +bool Updater::update() +{ + try { + InstallationProgressDialog* dialog = new InstallationProgressDialog(d->dialog); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + dialog->setModal(true); + dialog->setFixedSize(480, 360); + dialog->show(); + + connect(dialog, SIGNAL(canceled()), d->installer_shared, SLOT(interrupt())); + connect(d->installer_shared, SIGNAL(updateFinished()), dialog, SLOT(finished())); + d->installer_shared->installSelectedComponents(); + + QEventLoop loop; + connect(dialog, SIGNAL(destroyed()), &loop, SLOT(quit())); + loop.exec(); + } catch (const Error& error) { + //if the user clicked the confirm cancel dialog he don't want to see another messagebox + if (d->installer_shared->status() != Installer::Canceled) { + MessageBoxHandler::critical(d->dialog, QLatin1String("updaterCriticalInstallError"), + tr("Check for Updates"), tr("Error while installing updates:\n%1").arg(error.message())); + } + d->installer_shared->rollBackInstallation(); + d->settings->setLastResult(tr("Software Update failed.")); + emit updateFinished(true); + return false; + } catch (...) { + MessageBoxHandler::critical(d->dialog, QLatin1String("updaterCriticalUnknownError"), + tr("Check for Updates"), tr("Unknown error while installing updates.")); + d->installer_shared->rollBackInstallation(); + d->settings->setLastResult(tr("Software Update failed.")); + emit updateFinished(true); + return false; + } + emit updateFinished(false); + return true; +} + +bool Updater::searchForUpdates() +{ + try { + QSharedPointer<QProgressDialog> progress(new QProgressDialog(d->dialog)); + progress->setLabelText(tr("Checking for updates...")); + progress->setRange(0, 0); + connect(progress.data(), SIGNAL(canceled()), d->dialog, SLOT(reject())); + progress->show(); + + d->settings->setLastCheck(QDateTime::currentDateTime()); + d->installer_shared->setRemoteRepositories(d->settings->repositories()); + d->installer_shared->setValue(QLatin1String("TargetDir"), + QFileInfo(d->installer_shared->updaterApplication().packagesInfo()->fileName()) + .absolutePath()); + } catch (const Error& error) { + QMessageBox::critical(d->dialog, tr("Check for Updates"), + tr("Error while checking for updates:\n%1").arg(QString::fromStdString(error.what()))); + d->settings->setLastResult(tr("Software Update failed.")); + return false; + } catch(...) { + QMessageBox::critical(d->dialog, tr("Check for Updates"), + tr("Unknown error while checking for updates.")); + d->settings->setLastResult(tr("Software Update failed.")); + return false; + } + + d->components = d->installer_shared->components(true, UpdaterMode); + + // no updates for us + if (d->components.isEmpty()) { + QMessageBox::information(d->dialog, tr("Check for Updates"), + tr("There are currently no updates available.")); + return false; + } + return true; +} diff --git a/installerbuilder/libinstaller/updater.h b/installerbuilder/libinstaller/updater.h index 94076e6a0..d5c8daacc 100644 --- a/installerbuilder/libinstaller/updater.h +++ b/installerbuilder/libinstaller/updater.h @@ -29,36 +29,40 @@ #include "installer_global.h" #include <QtCore/QObject> -#include <KDToolsCore/pimpl_ptr.h> -#include <QSharedPointer> -namespace QInstaller -{ - class ComponentSelectionDialog; - class Installer; -} +namespace QInstaller { + +class ComponentSelectionDialog; +class Installer; class INSTALLER_EXPORT Updater : public QObject { -Q_OBJECT + Q_OBJECT + public: - explicit Updater( QObject* parent = 0 ); + explicit Updater(QObject* parent = 0); ~Updater(); + void init(); - QInstaller::ComponentSelectionDialog* updaterGui() const; - void setUpdaterGui( QInstaller::ComponentSelectionDialog * gui ); -// QInstaller::Installer* getInstaller(); - void setInstaller( QInstaller::Installer * installer ); - bool checkForUpdates( bool checkonly = false ); + void setVerbose(bool verbose); + void setInstaller(Installer *installer); + bool checkForUpdates(bool checkonly = false); + + ComponentSelectionDialog* updaterGui() const; + void setUpdaterGui(ComponentSelectionDialog *gui); + public Q_SLOTS: bool searchForUpdates(); bool update(); + Q_SIGNALS: - void updateFinished( bool error ); + void updateFinished(bool error); private: class Private; - kdtools::pimpl_ptr< Private > d; + Private *d; }; +} // namespace QInstaller + #endif diff --git a/installerbuilder/libinstaller/updatesettings.h b/installerbuilder/libinstaller/updatesettings.h index 4ba31be7f..9031c63bb 100644 --- a/installerbuilder/libinstaller/updatesettings.h +++ b/installerbuilder/libinstaller/updatesettings.h @@ -30,10 +30,12 @@ #include "installer_global.h" +QT_BEGIN_NAMESPACE class QDateTime; template< typename T > class QList; class QSettings; +QT_END_NAMESPACE namespace QInstaller { |