diff options
-rw-r--r-- | doc/scripting-api/packagemanagercore.qdoc | 19 | ||||
-rw-r--r-- | doc/scripting-api/qfiledialog.qdoc | 7 | ||||
-rw-r--r-- | src/libs/installer/commandlineparser.cpp | 6 | ||||
-rw-r--r-- | src/libs/installer/constants.h | 1 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore.cpp | 49 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore.h | 5 | ||||
-rw-r--r-- | src/libs/installer/scriptengine.cpp | 69 | ||||
-rw-r--r-- | src/libs/installer/scriptengine_p.h | 22 | ||||
-rw-r--r-- | src/sdk/sdkapp.h | 12 | ||||
-rw-r--r-- | tests/auto/installer/cliinterface/data/filequeryrepository/A/1.0.2-1meta.7z | bin | 0 -> 907 bytes | |||
-rw-r--r-- | tests/auto/installer/cliinterface/data/filequeryrepository/Updates.xml | 13 | ||||
-rw-r--r-- | tests/auto/installer/cliinterface/settings.qrc | 2 | ||||
-rw-r--r-- | tests/auto/installer/cliinterface/tst_cliinterface.cpp | 25 |
13 files changed, 218 insertions, 12 deletions
diff --git a/doc/scripting-api/packagemanagercore.qdoc b/doc/scripting-api/packagemanagercore.qdoc index 1cff11c84..cb11cef0d 100644 --- a/doc/scripting-api/packagemanagercore.qdoc +++ b/doc/scripting-api/packagemanagercore.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -332,6 +332,23 @@ */ /*! + \qmlmethod void installer::setFileDialogAutomaticAnswer(string identifier, string &value) + + Automatically sets the existing directory or filename \a value to QFileDialog with the ID + \a identifier. + + \sa removeFileDialogAutomaticAnswer +*/ + +/*! + \qmlmethod void installer::removeFileDialogAutomaticAnswer(string identifier) + + Removes the automatic answer from QFileDialog with the ID \a identifier. + + \sa setFileDialogAutomaticAnswer +*/ + +/*! \qmlmethod float installer::requiredDiskSpace() Returns the additional estimated amount of disk space in bytes required after installation. diff --git a/doc/scripting-api/qfiledialog.qdoc b/doc/scripting-api/qfiledialog.qdoc index 661a702f7..e6cdfdb24 100644 --- a/doc/scripting-api/qfiledialog.qdoc +++ b/doc/scripting-api/qfiledialog.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -34,6 +34,11 @@ that displays an existing directory selected by the user. Use the QFileDialog::getOpenFileName() method to create a dialog that displays matching files in the directory selected by the user. + When a command line interface is used, a dialog is not displayed. Instead, + the user can type the directory or the file name in the console. For + automatic installations, \c{--file-query} with \c{identifier=value} pairs + can be given separated with a comma. For example, + \c{--file-query filedialog.id=C:/Temp,filedialog.id2=C:/Temp2}. */ /*! diff --git a/src/libs/installer/commandlineparser.cpp b/src/libs/installer/commandlineparser.cpp index 60b02c3ae..f3939dc36 100644 --- a/src/libs/installer/commandlineparser.cpp +++ b/src/libs/installer/commandlineparser.cpp @@ -163,6 +163,12 @@ CommandLineParser::CommandLineParser() QLatin1String("Automatically answers to message queries with their default values."))); m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scAcceptLicenses, QLatin1String("Accepts all licenses without user input."))); + m_parser.addOption(QCommandLineOption(QStringList() << CommandLineOptions::scFileDialogAutomaticAnswer, + QLatin1String("Automatically sets the QFileDialog values getExistingDirectory() or getOpenFileName() " + "requested by install script. " + "Several identifier=value pairs can be given separated with comma, " + "for example --file-query filedialog.id=C:\Temp,filedialog.id2=C:\Temp2"), + QLatin1String("identifier=value"))); // Developer options m_parser.addOption(QCommandLineOption(QStringList() diff --git a/src/libs/installer/constants.h b/src/libs/installer/constants.h index fecba0e6c..9e90d9383 100644 --- a/src/libs/installer/constants.h +++ b/src/libs/installer/constants.h @@ -158,6 +158,7 @@ static const QLatin1String scRejectMessageQuery("reject-messages"); static const QLatin1String scMessageAutomaticAnswer("auto-answer"); static const QLatin1String scMessageDefaultAnswer("default-answer"); static const QLatin1String scAcceptLicenses("accept-licenses"); +static const QLatin1String scFileDialogAutomaticAnswer("file-query"); // Misc installation options static const QLatin1String scRootShort("t"); diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index 2287e5a73..0bfde19c3 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -625,6 +625,55 @@ void PackageManagerCore::setAutoAcceptLicenses() } /*! + Automatically sets the existing directory or filename \a value to QFileDialog with the ID + \a identifier. QFileDialog can be called from script. + + This can be used for unattended (automatic) installations. + + \sa {installer::setFileDialogAutomaticAnswer){installer.setFileDialogAutomaticAnswer} + \sa {QFileDialog::getExistingDirectory}{QFileDialog.getExistingDirectory} + \sa {QFileDialog::getOpenFileName}{QFileDialog.getOpenFileName} + */ +void PackageManagerCore::setFileDialogAutomaticAnswer(const QString &identifier, const QString &value) +{ + m_fileDialogAutomaticAnswers.insert(identifier, value); +} + +/*! + Removes the automatic answer from QFileDialog with the ID \a identifier. + QFileDialog can be called from script. + + \sa {installer::removeFileDialogAutomaticAnswer){installer.removeFileDialogAutomaticAnswer} + \sa {QFileDialog::getExistingDirectory}{QFileDialog.getExistingDirectory} + \sa {QFileDialog::getOpenFileName}{QFileDialog.getOpenFileName} + */ +void PackageManagerCore::removeFileDialogAutomaticAnswer(const QString &identifier) +{ + m_fileDialogAutomaticAnswers.remove(identifier); +} + +/*! + Returns \c true if QFileDialog with the ID \a identifier has an automatic answer set. + + \sa {installer.containsFileDialogAutomaticAnswer}{installer::containsFileDialogAutomaticAnswer} + \sa {installer::removeFileDialogAutomaticAnswer){installer.removeFileDialogAutomaticAnswer} + \sa {QFileDialog::getExistingDirectory}{QFileDialog.getExistingDirectory} + \sa {QFileDialog::getOpenFileName}{QFileDialog.getOpenFileName} + */ +bool PackageManagerCore::containsFileDialogAutomaticAnswer(const QString &identifier) const +{ + return m_fileDialogAutomaticAnswers.contains(identifier); +} +/*! + * Returns the hash of file dialog automatic answers + * \sa setFileDialogAutomaticAnswer() + */ +QHash<QString, QString> PackageManagerCore::fileDialogAutomaticAnswers() const +{ + return m_fileDialogAutomaticAnswers; +} + +/*! Returns the size of the component \a component as \a value. */ quint64 PackageManagerCore::size(QInstaller::Component *component, const QString &value) const diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h index 67e7d6365..e188ed34d 100644 --- a/src/libs/installer/packagemanagercore.h +++ b/src/libs/installer/packagemanagercore.h @@ -187,6 +187,10 @@ public: Q_INVOKABLE void acceptMessageBoxDefaultButton(); Q_INVOKABLE void setAutoAcceptLicenses(); + Q_INVOKABLE void setFileDialogAutomaticAnswer(const QString &identifier, const QString &value); + Q_INVOKABLE void removeFileDialogAutomaticAnswer(const QString &identifier); + Q_INVOKABLE bool containsFileDialogAutomaticAnswer(const QString &identifier) const; + QHash<QString, QString> fileDialogAutomaticAnswers() const; quint64 size(QInstaller::Component *component, const QString &value) const; @@ -385,6 +389,7 @@ private: private: PackageManagerCorePrivate *const d; friend class PackageManagerCorePrivate; + QHash<QString, QString> m_fileDialogAutomaticAnswers; private: // remove once we deprecate isSelected, setSelected etc... diff --git a/src/libs/installer/scriptengine.cpp b/src/libs/installer/scriptengine.cpp index 994fa1406..accd54957 100644 --- a/src/libs/installer/scriptengine.cpp +++ b/src/libs/installer/scriptengine.cpp @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -265,6 +265,71 @@ void GuiProxy::setModified(bool value) m_gui->setModified(value); } +QFileDialogProxy::QFileDialogProxy(PackageManagerCore *core): m_core(core) +{ +} + +QString QFileDialogProxy::getExistingDirectory(const QString &caption, + const QString &dir, const QString &identifier) +{ + if (m_core->isCommandLineInstance()) { + return getExistingFileOrDirectory(caption, identifier, true); + } else { + return QFileDialog::getExistingDirectory(0, caption, dir); + } +} + +QString QFileDialogProxy::getOpenFileName(const QString &caption, const QString &dir, + const QString &filter, const QString &identifier) +{ + if (m_core->isCommandLineInstance()) { + return getExistingFileOrDirectory(caption, identifier, false); + } else { + return QFileDialog::getOpenFileName(0, caption, dir, filter); + } +} + +QString QFileDialogProxy::getExistingFileOrDirectory(const QString &caption, + const QString &identifier, bool isDirectory) +{ + QHash<QString, QString> autoAnswers = m_core->fileDialogAutomaticAnswers(); + QString selectedDirectoryOrFile; + QString errorString; + if (autoAnswers.contains(identifier)) { + selectedDirectoryOrFile = autoAnswers.value(identifier); + QFileInfo fileInfo(selectedDirectoryOrFile); + if (isDirectory ? fileInfo.isDir() : fileInfo.isFile()) { + qCDebug(QInstaller::lcInstallerInstallLog).nospace() << "Automatic answer for "<< identifier + << ": " << selectedDirectoryOrFile; + } else { + if (isDirectory) + errorString = QString::fromLatin1("Automatic answer for %1: Directory '%2' not found.") + .arg(identifier, selectedDirectoryOrFile); + else + errorString = QString::fromLatin1("Automatic answer for %1: File '%2' not found.") + .arg(identifier, selectedDirectoryOrFile); + selectedDirectoryOrFile = QString(); + } + } else { + qDebug().nospace().noquote() << identifier << ": " << caption << ": "; + QTextStream stream(stdin); + stream.readLineInto(&selectedDirectoryOrFile); + QFileInfo fileInfo(selectedDirectoryOrFile); + if (isDirectory ? !fileInfo.isDir() : !fileInfo.isFile()) { + if (isDirectory) + errorString = QString::fromLatin1("Directory '%1' not found.") + .arg(selectedDirectoryOrFile); + else + errorString = QString::fromLatin1("File '%1' not found.") + .arg(selectedDirectoryOrFile); + selectedDirectoryOrFile = QString(); + } + } + if (!errorString.isEmpty()) + qCWarning(QInstaller::lcInstallerInstallLog).nospace() << errorString; + return selectedDirectoryOrFile; +} + /*! Constructs a script engine with \a core as parent. @@ -275,7 +340,7 @@ ScriptEngine::ScriptEngine(PackageManagerCore *core) : { QJSValue global = m_engine.globalObject(); global.setProperty(QLatin1String("console"), m_engine.newQObject(new ConsoleProxy)); - global.setProperty(QLatin1String("QFileDialog"), m_engine.newQObject(new QFileDialogProxy)); + global.setProperty(QLatin1String("QFileDialog"), m_engine.newQObject(new QFileDialogProxy(core))); const QJSValue proxy = m_engine.newQObject(new InstallerProxy(this, core)); global.setProperty(QLatin1String("InstallerProxy"), proxy); global.setProperty(QLatin1String("print"), m_engine.newQObject(new ConsoleProxy) diff --git a/src/libs/installer/scriptengine_p.h b/src/libs/installer/scriptengine_p.h index 928f903cb..0fc963bf9 100644 --- a/src/libs/installer/scriptengine_p.h +++ b/src/libs/installer/scriptengine_p.h @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -77,15 +77,21 @@ class QFileDialogProxy : public QObject Q_DISABLE_COPY(QFileDialogProxy) public: - QFileDialogProxy() {} + QFileDialogProxy(PackageManagerCore *core); public slots : - QString getExistingDirectory(const QString &caption, const QString &dir) const { - return QFileDialog::getExistingDirectory(0, caption, dir); - } - QString getOpenFileName(const QString &caption, const QString &dir, const QString &filter) const { - return QFileDialog::getOpenFileName(0, caption, dir, filter); - } + QString getExistingDirectory(const QString &caption, const QString &dir, + const QString &identifier = QLatin1String("GetExistingDirectory")); + + QString getOpenFileName(const QString &caption, const QString &dir, const QString &filter, + const QString &identifier = QLatin1String("GetExistingFile")); + +private: + QString getExistingFileOrDirectory(const QString &caption, const QString &identifier, + bool isDirectory); + +private: + PackageManagerCore *m_core; }; class QDesktopServicesProxy : public QObject diff --git a/src/sdk/sdkapp.h b/src/sdk/sdkapp.h index ecaee3758..378555633 100644 --- a/src/sdk/sdkapp.h +++ b/src/sdk/sdkapp.h @@ -292,6 +292,18 @@ public: } } + if (m_parser.isSet(CommandLineOptions::scFileDialogAutomaticAnswer)) { + const QString positionalArguments = m_parser.value(CommandLineOptions::scFileDialogAutomaticAnswer); + const QStringList items = positionalArguments.split(QLatin1Char(','), QString::SkipEmptyParts); + + foreach (const QString &item, items) { + if (item.contains(QLatin1Char('='))) { + const QString name = item.section(QLatin1Char('='), 0, 0); + QString value = item.section(QLatin1Char('='), 1, 1); + m_core->setFileDialogAutomaticAnswer(name, value); + } + } + } if (m_parser.isSet(CommandLineOptions::scMessageDefaultAnswer)) { m_core->acceptMessageBoxDefaultButton(); } diff --git a/tests/auto/installer/cliinterface/data/filequeryrepository/A/1.0.2-1meta.7z b/tests/auto/installer/cliinterface/data/filequeryrepository/A/1.0.2-1meta.7z Binary files differnew file mode 100644 index 000000000..a006c5c96 --- /dev/null +++ b/tests/auto/installer/cliinterface/data/filequeryrepository/A/1.0.2-1meta.7z diff --git a/tests/auto/installer/cliinterface/data/filequeryrepository/Updates.xml b/tests/auto/installer/cliinterface/data/filequeryrepository/Updates.xml new file mode 100644 index 000000000..72b7938d9 --- /dev/null +++ b/tests/auto/installer/cliinterface/data/filequeryrepository/Updates.xml @@ -0,0 +1,13 @@ +<Updates> + <ApplicationName>{AnyApplication}</ApplicationName> + <ApplicationVersion>1.0.0</ApplicationVersion> + <PackageUpdate> + <Name>A</Name> + <DisplayName>A</DisplayName> + <Description>A component</Description> + <Version>1.0.2-1</Version> + <ReleaseDate>2015-01-01</ReleaseDate> + <Default>true</Default> + <Script>script.qs</Script> + </PackageUpdate> +</Updates> diff --git a/tests/auto/installer/cliinterface/settings.qrc b/tests/auto/installer/cliinterface/settings.qrc index 85e344d1b..be97adfbe 100644 --- a/tests/auto/installer/cliinterface/settings.qrc +++ b/tests/auto/installer/cliinterface/settings.qrc @@ -19,6 +19,8 @@ <file>data/installPackagesRepository/componentF.subcomponent1.subsubcomponent2/1.0.0content.7z</file> <file>data/installPackagesRepository/componentF.subcomponent2.subsubcomponent1/1.0.0content.7z</file> <file>data/installPackagesRepository/componentF.subcomponent2.subsubcomponent2/1.0.0content.7z</file> + <file>data/filequeryrepository/Updates.xml</file> + <file>data/filequeryrepository/A/1.0.2-1meta.7z</file> <file>data/componentsFromInstallPackagesRepository.xml</file> </qresource> </RCC> diff --git a/tests/auto/installer/cliinterface/tst_cliinterface.cpp b/tests/auto/installer/cliinterface/tst_cliinterface.cpp index 6040927ea..ebf63ff9d 100644 --- a/tests/auto/installer/cliinterface/tst_cliinterface.cpp +++ b/tests/auto/installer/cliinterface/tst_cliinterface.cpp @@ -351,6 +351,31 @@ private slots: << "installcontentA.txt" << "installcontentE.txt" << "installcontentG.txt" << "installcontentB.txt" << "installcontentD.txt"); } + void testFileQuery() + { + PackageManagerCore *core = PackageManager::getPackageManagerWithInit(m_installDir, + ":///data/filequeryrepository"); + core->setCommandLineInstance(true); + core->setFileDialogAutomaticAnswer("ValidDirectory", m_installDir); + + QString testFile = qApp->applicationDirPath() + QDir::toNativeSeparators("/test"); + QFile file(testFile); + QVERIFY(file.open(QIODevice::WriteOnly)); + core->setFileDialogAutomaticAnswer("ValidFile", testFile); + + //File dialog launched without ID + core->setFileDialogAutomaticAnswer("GetExistingDirectory", m_installDir); + core->setFileDialogAutomaticAnswer("GetExistingFile", testFile); + + core->installDefaultComponentsSilently(); + + QVERIFY(core->containsFileDialogAutomaticAnswer("ValidFile")); + core->removeFileDialogAutomaticAnswer("ValidFile"); + QVERIFY(!core->containsFileDialogAutomaticAnswer("ValidFile")); + + QVERIFY(file.remove()); + core->deleteLater(); + } void init() { |