Add QUrl based static methods to QFileDialog

With QUrl variants of the static methods, it is possible to get to use
VFS facilities of the platform if available.

Since we can't predict if the application will use the VFS available in
the platform or its own mechanisms, an extra parameter is provided to
restrict the protocols allowed to the user. This extra parameter
defaults to no restriction, which is the most convenient if the platform
file dialog and the application use a matching VFS. It's likely to be
the most common use.

Change-Id: I4c9effde9d194d226cd8b7a140eb9036187ba87b
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
Kevin Ottens 2013-03-14 14:41:47 +01:00 committed by The Qt Project
parent 2e749c089f
commit ac06bfdc76
5 changed files with 338 additions and 1 deletions

View File

@ -86,15 +86,27 @@ Q_GLOBAL_STATIC(QString, lastVisitedDir)
typedef QString (*_qt_filedialog_existing_directory_hook)(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options);
Q_WIDGETS_EXPORT _qt_filedialog_existing_directory_hook qt_filedialog_existing_directory_hook = 0;
typedef QUrl (*_qt_filedialog_existing_directory_url_hook)(QWidget *parent, const QString &caption, const QUrl &dir, QFileDialog::Options options, const QStringList &supportedSchemes);
Q_WIDGETS_EXPORT _qt_filedialog_existing_directory_url_hook qt_filedialog_existing_directory_url_hook = 0;
typedef QString (*_qt_filedialog_open_filename_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options);
Q_WIDGETS_EXPORT _qt_filedialog_open_filename_hook qt_filedialog_open_filename_hook = 0;
typedef QUrl (*_qt_filedialog_open_file_url_hook)(QWidget * parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options, const QStringList &supportedSchemes);
Q_WIDGETS_EXPORT _qt_filedialog_open_file_url_hook qt_filedialog_open_file_url_hook = 0;
typedef QStringList (*_qt_filedialog_open_filenames_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options);
Q_WIDGETS_EXPORT _qt_filedialog_open_filenames_hook qt_filedialog_open_filenames_hook = 0;
typedef QList<QUrl> (*_qt_filedialog_open_file_urls_hook)(QWidget * parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options, const QStringList &supportedSchemes);
Q_WIDGETS_EXPORT _qt_filedialog_open_file_urls_hook qt_filedialog_open_file_urls_hook = 0;
typedef QString (*_qt_filedialog_save_filename_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options);
Q_WIDGETS_EXPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook = 0;
typedef QUrl (*_qt_filedialog_save_file_url_hook)(QWidget * parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options, const QStringList &supportedSchemes);
Q_WIDGETS_EXPORT _qt_filedialog_save_file_url_hook qt_filedialog_save_file_url_hook = 0;
/*!
\class QFileDialog
\brief The QFileDialog class provides a dialog that allow users to select files or directories.
@ -1797,6 +1809,48 @@ QString QFileDialog::getOpenFileName(QWidget *parent,
return QString();
}
/*!
This is a convenience static function that returns an existing file
selected by the user. If the user presses Cancel, it returns an
empty url.
The function is used similarly to QFileDialog::getOpenFileName(). In
particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter
and \a options are used in the exact same way.
The main difference with QFileDialog::getOpenFileName() comes from
the ability offered to the user to select a remote file. That's why
the return type and the type of \a dir is QUrl.
The \a supportedSchemes argument allows to restrict the type of URLs the
user will be able to select. It is a way for the application to declare
the protocols it will support to fetch the file content. An empty list
means that no restriction is applied (the default).
Supported for local files ("file" scheme) is implicit and always enabled.
it is not necessary to include in the restriction.
When possible, this static function will use the native file dialog and
not a QFileDialog. On platforms which don't support selecting remote
files, Qt will allow to select only local files.
\sa getOpenFileName(), getOpenFileUrls(), getSaveFileUrl(), getExistingDirectoryUrl()
\since 5.2
*/
QUrl QFileDialog::getOpenFileUrl(QWidget *parent,
const QString &caption,
const QUrl &dir,
const QString &filter,
QString *selectedFilter,
Options options,
const QStringList &supportedSchemes)
{
if (qt_filedialog_open_file_url_hook && !(options & DontUseNativeDialog))
return qt_filedialog_open_file_url_hook(parent, caption, dir, filter, selectedFilter, options, supportedSchemes);
// Falls back to local file
return QUrl::fromLocalFile(getOpenFileName(parent, caption, dir.toLocalFile(), filter, selectedFilter, options));
}
/*!
This is a convenience static function that will return one or more existing
files selected by the user.
@ -1882,6 +1936,55 @@ QStringList QFileDialog::getOpenFileNames(QWidget *parent,
return QStringList();
}
/*!
This is a convenience static function that will return or or more existing
files selected by the user. If the user presses Cancel, it returns an
empty list.
The function is used similarly to QFileDialog::getOpenFileNames(). In
particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter
and \a options are used in the exact same way.
The main difference with QFileDialog::getOpenFileNames() comes from
the ability offered to the user to select remote files. That's why
the return type and the type of \a dir are respectively QList<QUrl>
and QUrl.
The \a supportedSchemes argument allows to restrict the type of URLs the
user will be able to select. It is a way for the application to declare
the protocols it will support to fetch the file content. An empty list
means that no restriction is applied (the default).
Supported for local files ("file" scheme) is implicit and always enabled.
it is not necessary to include in the restriction.
When possible, this static function will use the native file dialog and
not a QFileDialog. On platforms which don't support selecting remote
files, Qt will allow to select only local files.
\sa getOpenFileNames(), getOpenFileUrl(), getSaveFileUrl(), getExistingDirectoryUrl()
\since 5.2
*/
QList<QUrl> QFileDialog::getOpenFileUrls(QWidget *parent,
const QString &caption,
const QUrl &dir,
const QString &filter,
QString *selectedFilter,
Options options,
const QStringList &supportedSchemes)
{
if (qt_filedialog_open_file_urls_hook && !(options & DontUseNativeDialog))
return qt_filedialog_open_file_urls_hook(parent, caption, dir, filter, selectedFilter, options, supportedSchemes);
// Falls back to local files
QList<QUrl> urls;
const QStringList fileNames = getOpenFileNames(parent, caption, dir.toLocalFile(), filter, selectedFilter, options);
foreach (const QString &fileName, fileNames)
urls << QUrl::fromLocalFile(fileName);
return urls;
}
/*!
This is a convenience static function that will return a file name selected
by the user. The file does not have to exist.
@ -1970,6 +2073,48 @@ QString QFileDialog::getSaveFileName(QWidget *parent,
return QString();
}
/*!
This is a convenience static function that returns a file selected by
the user. The file does not have to exist. If the user presses Cancel,
it returns an empty url.
The function is used similarly to QFileDialog::getSaveFileName(). In
particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter
and \a options are used in the exact same way.
The main difference with QFileDialog::getSaveFileName() comes from
the ability offered to the user to select a remote file. That's why
the return type and the type of \a dir is QUrl.
The \a supportedSchemes argument allows to restrict the type of URLs the
user will be able to select. It is a way for the application to declare
the protocols it will support to save the file content. An empty list
means that no restriction is applied (the default).
Supported for local files ("file" scheme) is implicit and always enabled.
it is not necessary to include in the restriction.
When possible, this static function will use the native file dialog and
not a QFileDialog. On platforms which don't support selecting remote
files, Qt will allow to select only local files.
\sa getSaveFileName(), getOpenFileUrl(), getOpenFileUrls(), getExistingDirectoryUrl()
\since 5.2
*/
QUrl QFileDialog::getSaveFileUrl(QWidget *parent,
const QString &caption,
const QUrl &dir,
const QString &filter,
QString *selectedFilter,
Options options,
const QStringList &supportedSchemes)
{
if (qt_filedialog_save_file_url_hook && !(options & DontUseNativeDialog))
return qt_filedialog_save_file_url_hook(parent, caption, dir, filter, selectedFilter, options, supportedSchemes);
// Falls back to local file
return QUrl::fromLocalFile(getSaveFileName(parent, caption, dir.toLocalFile(), filter, selectedFilter, options));
}
/*!
This is a convenience static function that will return an existing
directory selected by the user.
@ -2041,6 +2186,46 @@ QString QFileDialog::getExistingDirectory(QWidget *parent,
return QString();
}
/*!
This is a convenience static function that will return an existing
directory selected by the user. If the user presses Cancel, it
returns an empty url.
The function is used similarly to QFileDialog::getExistingDirectory().
In particular \a parent, \a caption, \a dir and \a options are used
in the exact same way.
The main difference with QFileDialog::getExistingDirectory() comes from
the ability offered to the user to select a remote directory. That's why
the return type and the type of \a dir is QUrl.
The \a supportedSchemes argument allows to restrict the type of URLs the
user will be able to select. It is a way for the application to declare
the protocols it will support to fetch the file content. An empty list
means that no restriction is applied (the default).
Supported for local files ("file" scheme) is implicit and always enabled.
it is not necessary to include in the restriction.
When possible, this static function will use the native file dialog and
not a QFileDialog. On platforms which don't support selecting remote
files, Qt will allow to select only local files.
\sa getExistingDirectory(), getOpenFileUrl(), getOpenFileUrls(), getSaveFileUrl()
\since 5.2
*/
QUrl QFileDialog::getExistingDirectoryUrl(QWidget *parent,
const QString &caption,
const QUrl &dir,
Options options,
const QStringList &supportedSchemes)
{
if (qt_filedialog_existing_directory_url_hook && !(options & DontUseNativeDialog))
return qt_filedialog_existing_directory_url_hook(parent, caption, dir, options, supportedSchemes);
// Falls back to local file
return QUrl::fromLocalFile(getExistingDirectory(parent, caption, dir.toLocalFile(), options));
}
inline static QString _qt_get_directory(const QString &path)
{
QFileInfo info = QFileInfo(QDir::current(), path);

View File

@ -44,6 +44,7 @@
#include <QtCore/qdir.h>
#include <QtCore/qstring.h>
#include <QtCore/qurl.h>
#include <QtWidgets/qdialog.h>
QT_BEGIN_NAMESPACE
@ -58,7 +59,6 @@ class QFileIconProvider;
class QFileDialogPrivate;
class QAbstractItemDelegate;
class QAbstractProxyModel;
class QUrl;
class Q_WIDGETS_EXPORT QFileDialog : public QDialog
{
@ -195,6 +195,14 @@ public:
QString *selectedFilter = 0,
Options options = 0);
static QUrl getOpenFileUrl(QWidget *parent = 0,
const QString &caption = QString(),
const QUrl &dir = QUrl(),
const QString &filter = QString(),
QString *selectedFilter = 0,
Options options = 0,
const QStringList &supportedSchemes = QStringList());
static QString getSaveFileName(QWidget *parent = 0,
const QString &caption = QString(),
const QString &dir = QString(),
@ -202,11 +210,25 @@ public:
QString *selectedFilter = 0,
Options options = 0);
static QUrl getSaveFileUrl(QWidget *parent = 0,
const QString &caption = QString(),
const QUrl &dir = QUrl(),
const QString &filter = QString(),
QString *selectedFilter = 0,
Options options = 0,
const QStringList &supportedSchemes = QStringList());
static QString getExistingDirectory(QWidget *parent = 0,
const QString &caption = QString(),
const QString &dir = QString(),
Options options = ShowDirsOnly);
static QUrl getExistingDirectoryUrl(QWidget *parent = 0,
const QString &caption = QString(),
const QUrl &dir = QUrl(),
Options options = ShowDirsOnly,
const QStringList &supportedSchemes = QStringList());
static QStringList getOpenFileNames(QWidget *parent = 0,
const QString &caption = QString(),
const QString &dir = QString(),
@ -214,6 +236,14 @@ public:
QString *selectedFilter = 0,
Options options = 0);
static QList<QUrl> getOpenFileUrls(QWidget *parent = 0,
const QString &caption = QString(),
const QUrl &dir = QUrl(),
const QString &filter = QString(),
QString *selectedFilter = 0,
Options options = 0,
const QStringList &supportedSchemes = QStringList());
protected:
QFileDialog(const QFileDialogArgs &args);

View File

@ -1346,6 +1346,38 @@ QString saveName(QWidget *, const QString &, const QString &, const QString &, Q
return "saveName";
}
QT_BEGIN_NAMESPACE
typedef QUrl (*_qt_filedialog_existing_directory_url_hook)(QWidget *parent, const QString &caption, const QUrl &dir, QFileDialog::Options options, const QStringList &supportedSchemes);
extern Q_WIDGETS_EXPORT _qt_filedialog_existing_directory_url_hook qt_filedialog_existing_directory_url_hook;
QT_END_NAMESPACE
QUrl existingUrl(QWidget *, const QString &, const QUrl &, QFileDialog::Options, const QStringList &) {
return QUrl("http://dirUrl");
}
QT_BEGIN_NAMESPACE
typedef QUrl (*_qt_filedialog_open_file_url_hook)(QWidget * parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options, const QStringList &supportedSchemes);
extern Q_WIDGETS_EXPORT _qt_filedialog_open_file_url_hook qt_filedialog_open_file_url_hook;
QT_END_NAMESPACE
QUrl openUrl(QWidget *, const QString &, const QUrl &, const QString &, QString *, QFileDialog::Options, const QStringList &) {
return QUrl("http://openUrl");
}
QT_BEGIN_NAMESPACE
typedef QList<QUrl> (*_qt_filedialog_open_file_urls_hook)(QWidget * parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options, const QStringList &supportedSchemes);
extern Q_WIDGETS_EXPORT _qt_filedialog_open_file_urls_hook qt_filedialog_open_file_urls_hook;
QT_END_NAMESPACE
QList<QUrl> openUrls(QWidget *, const QString &, const QUrl &, const QString &, QString *, QFileDialog::Options, const QStringList &) {
return QList<QUrl>() << QUrl("http://openUrls");
}
QT_BEGIN_NAMESPACE
typedef QUrl (*_qt_filedialog_save_file_url_hook)(QWidget * parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options, const QStringList &supportedSchemes);
extern Q_WIDGETS_EXPORT _qt_filedialog_save_file_url_hook qt_filedialog_save_file_url_hook;
QT_END_NAMESPACE
QUrl saveUrl(QWidget *, const QString &, const QUrl &, const QString &, QString *, QFileDialog::Options, const QStringList &) {
return QUrl("http://saveUrl");
}
void tst_QFiledialog::hooks()
{
@ -1358,6 +1390,20 @@ void tst_QFiledialog::hooks()
QCOMPARE(QFileDialog::getOpenFileName(), QString("openName"));
QCOMPARE(QFileDialog::getOpenFileNames(), QStringList("openNames"));
QCOMPARE(QFileDialog::getSaveFileName(), QString("saveName"));
QCOMPARE(QFileDialog::getExistingDirectoryUrl(), QUrl::fromLocalFile("dir"));
QCOMPARE(QFileDialog::getOpenFileUrl(), QUrl::fromLocalFile("openName"));
QCOMPARE(QFileDialog::getOpenFileUrls(), QList<QUrl>() << QUrl::fromLocalFile("openNames"));
QCOMPARE(QFileDialog::getSaveFileUrl(), QUrl::fromLocalFile("saveName"));
qt_filedialog_existing_directory_url_hook = &existingUrl;
qt_filedialog_save_file_url_hook = &saveUrl;
qt_filedialog_open_file_url_hook = &openUrl;
qt_filedialog_open_file_urls_hook = &openUrls;
QCOMPARE(QFileDialog::getExistingDirectoryUrl(), QUrl("http://dirUrl"));
QCOMPARE(QFileDialog::getOpenFileUrl(), QUrl("http://openUrl"));
QCOMPARE(QFileDialog::getOpenFileUrls(), QList<QUrl>() << QUrl("http://openUrls"));
QCOMPARE(QFileDialog::getSaveFileUrl(), QUrl("http://saveUrl"));
}
#ifdef Q_OS_UNIX

View File

@ -157,6 +157,7 @@ FileDialogPanel::FileDialogPanel(QWidget *parent)
, m_acceptMode(createCombo(this, acceptModeComboData, sizeof(acceptModeComboData)/sizeof(ComboData)))
, m_fileMode(createCombo(this, fileModeComboData, sizeof(fileModeComboData)/sizeof(ComboData)))
, m_viewMode(createCombo(this, viewModeComboData, sizeof(viewModeComboData)/sizeof(ComboData)))
, m_allowedSchemes(new QLineEdit(this))
, m_defaultSuffix(new QLineEdit(this))
, m_directory(new QLineEdit(this))
, m_selectedFileName(new QLineEdit(this))
@ -171,6 +172,7 @@ FileDialogPanel::FileDialogPanel(QWidget *parent)
optionsLayout->addRow(tr("AcceptMode:"), m_acceptMode);
optionsLayout->addRow(tr("FileMode:"), m_fileMode);
optionsLayout->addRow(tr("ViewMode:"), m_viewMode);
optionsLayout->addRow(tr("Allowed Schemes:"), m_allowedSchemes);
optionsLayout->addRow(m_native);
optionsLayout->addRow(m_confirmOverWrite);
optionsLayout->addRow(m_nameFilterDetailsVisible);
@ -216,9 +218,13 @@ FileDialogPanel::FileDialogPanel(QWidget *parent)
row = 0;
column++;
addButton(tr("getOpenFileName"), buttonLayout, row, column, this, SLOT(getOpenFileName()));
addButton(tr("getOpenFileUrl"), buttonLayout, row, column, this, SLOT(getOpenFileUrl()));
addButton(tr("getOpenFileNames"), buttonLayout, row, column, this, SLOT(getOpenFileNames()));
addButton(tr("getOpenFileUrls"), buttonLayout, row, column, this, SLOT(getOpenFileUrls()));
addButton(tr("getSaveFileName"), buttonLayout, row, column, this, SLOT(getSaveFileName()));
addButton(tr("getSaveFileUrl"), buttonLayout, row, column, this, SLOT(getSaveFileUrl()));
addButton(tr("getExistingDirectory"), buttonLayout, row, column, this, SLOT(getExistingDirectory()));
addButton(tr("getExistingDirectoryUrl"), buttonLayout, row, column, this, SLOT(getExistingDirectoryUrl()));
addButton(tr("Restore defaults"), buttonLayout, row, column, this, SLOT(restoreDefaults()));
// Main layout
@ -319,6 +325,11 @@ QFileDialog::Options FileDialogPanel::options() const
return result;
}
QStringList FileDialogPanel::allowedSchemes() const
{
return m_allowedSchemes->text().simplified().split(' ', QString::SkipEmptyParts);
}
void FileDialogPanel::getOpenFileNames()
{
QString selectedFilter = m_selectedNameFilter->text().trimmed();
@ -334,6 +345,22 @@ void FileDialogPanel::getOpenFileNames()
}
}
void FileDialogPanel::getOpenFileUrls()
{
QString selectedFilter = m_selectedNameFilter->text().trimmed();
const QList<QUrl> files =
QFileDialog::getOpenFileUrls(this, tr("getOpenFileNames Qt %1").arg(QLatin1String(QT_VERSION_STR)),
QUrl(m_directory->text()), filterString(), &selectedFilter, options(),
allowedSchemes());
if (!files.isEmpty()) {
QString result;
QDebug(&result).nospace()
<< "Files: " << QUrl::toStringList(files)
<< "\nName filter: " << selectedFilter;
QMessageBox::information(this, tr("getOpenFileNames"), result, QMessageBox::Ok);
}
}
void FileDialogPanel::getOpenFileName()
{
QString selectedFilter = m_selectedNameFilter->text().trimmed();
@ -349,6 +376,22 @@ void FileDialogPanel::getOpenFileName()
}
}
void FileDialogPanel::getOpenFileUrl()
{
QString selectedFilter = m_selectedNameFilter->text().trimmed();
const QUrl file =
QFileDialog::getOpenFileUrl(this, tr("getOpenFileUrl Qt %1").arg(QLatin1String(QT_VERSION_STR)),
QUrl(m_directory->text()), filterString(), &selectedFilter, options(),
allowedSchemes());
if (file.isValid()) {
QString result;
QDebug(&result).nospace()
<< "File: " << file.toString()
<< "\nName filter: " << selectedFilter;
QMessageBox::information(this, tr("getOpenFileName"), result, QMessageBox::Ok);
}
}
void FileDialogPanel::getSaveFileName()
{
QString selectedFilter = m_selectedNameFilter->text().trimmed();
@ -364,6 +407,22 @@ void FileDialogPanel::getSaveFileName()
}
}
void FileDialogPanel::getSaveFileUrl()
{
QString selectedFilter = m_selectedNameFilter->text().trimmed();
const QUrl file =
QFileDialog::getSaveFileUrl(this, tr("getSaveFileName Qt %1").arg(QLatin1String(QT_VERSION_STR)),
QUrl(m_directory->text()), filterString(), &selectedFilter, options(),
allowedSchemes());
if (file.isValid()) {
QString result;
QDebug(&result).nospace()
<< "File: " << file.toString()
<< "\nName filter: " << selectedFilter;
QMessageBox::information(this, tr("getSaveFileNames"), result, QMessageBox::Ok);
}
}
void FileDialogPanel::getExistingDirectory()
{
const QString dir =
@ -373,12 +432,23 @@ void FileDialogPanel::getExistingDirectory()
QMessageBox::information(this, tr("getExistingDirectory"), QLatin1String("Directory: ") + dir, QMessageBox::Ok);
}
void FileDialogPanel::getExistingDirectoryUrl()
{
const QUrl dir =
QFileDialog::getExistingDirectoryUrl(this, tr("getExistingDirectory Qt %1").arg(QLatin1String(QT_VERSION_STR)),
QUrl(m_directory->text()), options() | QFileDialog::ShowDirsOnly,
allowedSchemes());
if (!dir.isEmpty())
QMessageBox::information(this, tr("getExistingDirectory"), QLatin1String("Directory: ") + dir.toString(), QMessageBox::Ok);
}
void FileDialogPanel::restoreDefaults()
{
QFileDialog d;
setComboBoxValue(m_acceptMode, d.acceptMode());
setComboBoxValue(m_fileMode, d.fileMode());
setComboBoxValue(m_viewMode, d.viewMode());
m_allowedSchemes->setText(QString());
m_confirmOverWrite->setChecked(d.confirmOverwrite());
m_nameFilterDetailsVisible->setChecked(d.isNameFilterDetailsVisible());
m_resolveSymLinks->setChecked(d.resolveSymlinks());

View File

@ -66,9 +66,13 @@ public slots:
void deleteNonModalDialog();
void deleteModalDialog();
void getOpenFileNames();
void getOpenFileUrls();
void getOpenFileName();
void getOpenFileUrl();
void getSaveFileName();
void getSaveFileUrl();
void getExistingDirectory();
void getExistingDirectoryUrl();
void accepted();
void showAcceptedResult();
void restoreDefaults();
@ -80,6 +84,7 @@ private slots:
private:
QString filterString() const;
QFileDialog::Options options() const;
QStringList allowedSchemes() const;
void applySettings(QFileDialog *d) const;
QCheckBox *m_readOnly;
@ -90,6 +95,7 @@ private:
QComboBox *m_acceptMode;
QComboBox *m_fileMode;
QComboBox *m_viewMode;
QLineEdit *m_allowedSchemes;
QLineEdit *m_defaultSuffix;
QLineEdit *m_directory;
QLineEdit *m_selectedFileName;