summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKatja Marttila <katja.marttila@qt.io>2020-05-05 13:31:32 +0300
committerKatja Marttila <katja.marttila@qt.io>2020-05-26 15:08:51 +0300
commit17a4630886d4a91362f508f27022ae48e076d9c3 (patch)
tree6975e737ae17555de11605e515cfe79337aea760
parent0fcfdebf88372d527008ff0a080bf0f9eb493c9a (diff)
CLI: Add new option --file-query to auto answer QFileDialog
QFileDialog.getExistingDirectory and QFileDialog.getOpenFileName can be called from scipt. If command line interface is used, user must type the correct directory or file name from command line during install. With --file-query option user can give the values when running the installer or maintenancetool with syntax --file-query filedialogId=C:/temp,filedialogId2=C:/temp/file.txt. Task-number: QTIFW-1631 Change-Id: I5e58be6b509cf00de832646ef31ec4eda90773be Reviewed-by: Arttu Tarkiainen <arttu.tarkiainen@qt.io>
-rw-r--r--doc/scripting-api/packagemanagercore.qdoc19
-rw-r--r--doc/scripting-api/qfiledialog.qdoc7
-rw-r--r--src/libs/installer/commandlineparser.cpp6
-rw-r--r--src/libs/installer/constants.h1
-rw-r--r--src/libs/installer/packagemanagercore.cpp49
-rw-r--r--src/libs/installer/packagemanagercore.h5
-rw-r--r--src/libs/installer/scriptengine.cpp69
-rw-r--r--src/libs/installer/scriptengine_p.h22
-rw-r--r--src/sdk/sdkapp.h12
-rw-r--r--tests/auto/installer/cliinterface/data/filequeryrepository/A/1.0.2-1meta.7zbin0 -> 907 bytes
-rw-r--r--tests/auto/installer/cliinterface/data/filequeryrepository/Updates.xml13
-rw-r--r--tests/auto/installer/cliinterface/settings.qrc2
-rw-r--r--tests/auto/installer/cliinterface/tst_cliinterface.cpp25
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
new file mode 100644
index 000000000..a006c5c96
--- /dev/null
+++ b/tests/auto/installer/cliinterface/data/filequeryrepository/A/1.0.2-1meta.7z
Binary files differ
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()
{