summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2020-08-10 16:03:17 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2020-08-12 23:06:36 +0200
commit5382bf4220bb76055943678196a84387510ee059 (patch)
treec1f065c290a64be8573cca3bb18fa228104574d1
parent53da069b3294b45db05feca751a6d4569eb8c7ab (diff)
QFileDialog: reduce number of times a file is stat'ed
When opening a QFileDialog with an initial directory that lives on a disconnected network drive, repeatedly testing that directory consumes a significant amount of time during which the UI is blocked. To reduce the amount of file accesses, refactor the initialization code to allow sharing of a QFileInfo for the default case of operating on a local and absolute file system. This reduces the amount of stat calls significantly during startup time, and in case of a disconnected network shaves of 10-15 seconds of blocked UI, if Windows has already noticed that the file system is disconnected. Pick-to: 5.15 Fixes: QTBUG-6039 Change-Id: Ie082e447db214033291455bef2087cd05f366806 Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
-rw-r--r--src/widgets/dialogs/qfiledialog.cpp128
-rw-r--r--src/widgets/dialogs/qfiledialog_p.h13
2 files changed, 65 insertions, 76 deletions
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
index 587db6343f..e81fc66a03 100644
--- a/src/widgets/dialogs/qfiledialog.cpp
+++ b/src/widgets/dialogs/qfiledialog.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWidgets module of the Qt Toolkit.
@@ -360,7 +360,8 @@ QFileDialog::QFileDialog(QWidget *parent, Qt::WindowFlags f)
: QDialog(*new QFileDialogPrivate, parent, f)
{
Q_D(QFileDialog);
- d->init();
+ QFileDialogArgs args;
+ d->init(args);
}
/*!
@@ -377,7 +378,10 @@ QFileDialog::QFileDialog(QWidget *parent,
: QDialog(*new QFileDialogPrivate, parent, { })
{
Q_D(QFileDialog);
- d->init(QUrl::fromLocalFile(directory), filter, caption);
+ QFileDialogArgs args(QUrl::fromLocalFile(directory));
+ args.filter = filter;
+ args.caption = caption;
+ d->init(args);
}
/*!
@@ -387,7 +391,7 @@ QFileDialog::QFileDialog(const QFileDialogArgs &args)
: QDialog(*new QFileDialogPrivate, args.parent, { })
{
Q_D(QFileDialog);
- d->init(args.directory, args.filter, args.caption);
+ d->init(args);
setFileMode(args.mode);
setOptions(args.options);
selectFile(args.selection);
@@ -2143,11 +2147,9 @@ QUrl QFileDialog::getOpenFileUrl(QWidget *parent,
Options options,
const QStringList &supportedSchemes)
{
- QFileDialogArgs args;
+ QFileDialogArgs args(dir);
args.parent = parent;
args.caption = caption;
- args.directory = QFileDialogPrivate::workingDirectory(dir);
- args.selection = QFileDialogPrivate::initialSelection(dir);
args.filter = filter;
args.mode = ExistingFile;
args.options = options;
@@ -2263,11 +2265,9 @@ QList<QUrl> QFileDialog::getOpenFileUrls(QWidget *parent,
Options options,
const QStringList &supportedSchemes)
{
- QFileDialogArgs args;
+ QFileDialogArgs args(dir);
args.parent = parent;
args.caption = caption;
- args.directory = QFileDialogPrivate::workingDirectory(dir);
- args.selection = QFileDialogPrivate::initialSelection(dir);
args.filter = filter;
args.mode = ExistingFiles;
args.options = options;
@@ -2509,11 +2509,9 @@ QUrl QFileDialog::getSaveFileUrl(QWidget *parent,
Options options,
const QStringList &supportedSchemes)
{
- QFileDialogArgs args;
+ QFileDialogArgs args(dir);
args.parent = parent;
args.caption = caption;
- args.directory = QFileDialogPrivate::workingDirectory(dir);
- args.selection = QFileDialogPrivate::initialSelection(dir);
args.filter = filter;
args.mode = AnyFile;
args.options = options;
@@ -2619,10 +2617,9 @@ QUrl QFileDialog::getExistingDirectoryUrl(QWidget *parent,
Options options,
const QStringList &supportedSchemes)
{
- QFileDialogArgs args;
+ QFileDialogArgs args(dir);
args.parent = parent;
args.caption = caption;
- args.directory = QFileDialogPrivate::workingDirectory(dir);
args.mode = Directory;
args.options = options;
@@ -2633,58 +2630,54 @@ QUrl QFileDialog::getExistingDirectoryUrl(QWidget *parent,
return QUrl();
}
-inline static QUrl _qt_get_directory(const QUrl &url)
+inline static QUrl _qt_get_directory(const QUrl &url, const QFileInfo &local)
{
if (url.isLocalFile()) {
- QFileInfo info = QFileInfo(QDir::current(), url.toLocalFile());
+ QFileInfo info = local;
+ if (!local.isAbsolute())
+ info = QFileInfo(QDir::current(), url.toLocalFile());
+ const QFileInfo pathInfo(info.absolutePath());
+ if (!pathInfo.exists() || !pathInfo.isDir())
+ return QUrl();
if (info.exists() && info.isDir())
return QUrl::fromLocalFile(QDir::cleanPath(info.absoluteFilePath()));
- info.setFile(info.absolutePath());
- if (info.exists() && info.isDir())
- return QUrl::fromLocalFile(info.absoluteFilePath());
- return QUrl();
+ return QUrl::fromLocalFile(pathInfo.absoluteFilePath());
} else {
return url;
}
}
-/*
- Get the initial directory URL
-
- \sa initialSelection()
- */
-QUrl QFileDialogPrivate::workingDirectory(const QUrl &url)
-{
- if (!url.isEmpty()) {
- QUrl directory = _qt_get_directory(url);
- if (!directory.isEmpty())
- return directory;
- }
- QUrl directory = _qt_get_directory(*lastVisitedDir());
- if (!directory.isEmpty())
- return directory;
- return QUrl::fromLocalFile(QDir::currentPath());
-}
/*
- Get the initial selection given a path. The initial directory
- can contain both the initial directory and initial selection
- /home/user/foo.txt
-
- \sa workingDirectory()
- */
-QString QFileDialogPrivate::initialSelection(const QUrl &url)
-{
- if (url.isEmpty())
- return QString();
- if (url.isLocalFile()) {
- QFileInfo info(url.toLocalFile());
- if (!info.isDir())
- return info.fileName();
- else
- return QString();
+ Initialize working directory and selection from \a url.
+*/
+QFileDialogArgs::QFileDialogArgs(const QUrl &url)
+{
+ // default case, re-use QFileInfo to avoid stat'ing
+ const QFileInfo local(url.toLocalFile());
+ // Get the initial directory URL
+ if (!url.isEmpty())
+ directory = _qt_get_directory(url, local);
+ if (directory.isEmpty()) {
+ const QUrl lastVisited = *lastVisitedDir();
+ if (lastVisited != url)
+ directory = _qt_get_directory(lastVisited, QFileInfo());
+ }
+ if (directory.isEmpty())
+ directory = QUrl::fromLocalFile(QDir::currentPath());
+
+ /*
+ The initial directory can contain both the initial directory
+ and initial selection, e.g. /home/user/foo.txt
+ */
+ if (selection.isEmpty() && !url.isEmpty()) {
+ if (url.isLocalFile()) {
+ if (!local.isDir())
+ selection = local.fileName();
+ } else {
+ // With remote URLs we can only assume.
+ selection = url.fileName();
+ }
}
- // With remote URLs we can only assume.
- return url.fileName();
}
/*!
@@ -2923,14 +2916,13 @@ bool QFileDialogPrivate::restoreWidgetState(QStringList &history, int splitterPo
Create widgets, layout and set default values
*/
-void QFileDialogPrivate::init(const QUrl &directory, const QString &nameFilter,
- const QString &caption)
+void QFileDialogPrivate::init(const QFileDialogArgs &args)
{
Q_Q(QFileDialog);
- if (!caption.isEmpty()) {
+ if (!args.caption.isEmpty()) {
useDefaultCaption = false;
- setWindowTitle = caption;
- q->setWindowTitle(caption);
+ setWindowTitle = args.caption;
+ q->setWindowTitle(args.caption);
}
q->setAcceptMode(QFileDialog::AcceptOpen);
@@ -2938,17 +2930,17 @@ void QFileDialogPrivate::init(const QUrl &directory, const QString &nameFilter,
if (!nativeDialogInUse)
createWidgets();
q->setFileMode(QFileDialog::AnyFile);
- if (!nameFilter.isEmpty())
- q->setNameFilter(nameFilter);
+ if (!args.filter.isEmpty())
+ q->setNameFilter(args.filter);
// QTBUG-70798, prevent the default blocking the restore logic.
- const bool dontStoreDir = !directory.isValid() && !lastVisitedDir()->isValid();
- q->setDirectoryUrl(workingDirectory(directory));
+ const bool dontStoreDir = !args.directory.isValid() && !lastVisitedDir()->isValid();
+ q->setDirectoryUrl(args.directory);
if (dontStoreDir)
lastVisitedDir()->clear();
- if (directory.isLocalFile())
- q->selectFile(initialSelection(directory));
+ if (args.directory.isLocalFile())
+ q->selectFile(args.selection);
else
- q->selectUrl(directory);
+ q->selectUrl(args.directory);
#if QT_CONFIG(settings)
// Try to restore from the FileDialog settings group; if it fails, fall back
diff --git a/src/widgets/dialogs/qfiledialog_p.h b/src/widgets/dialogs/qfiledialog_p.h
index 42932bab5d..1d9929e36a 100644
--- a/src/widgets/dialogs/qfiledialog_p.h
+++ b/src/widgets/dialogs/qfiledialog_p.h
@@ -98,15 +98,15 @@ class QPlatformDialogHelper;
struct QFileDialogArgs
{
- QFileDialogArgs() : parent(nullptr), mode(QFileDialog::AnyFile) {}
+ QFileDialogArgs(const QUrl &url = {});
- QWidget *parent;
+ QWidget *parent = nullptr;
QString caption;
QUrl directory;
QString selection;
QString filter;
- QFileDialog::FileMode mode;
- QFileDialog::Options options;
+ QFileDialog::FileMode mode = QFileDialog::AnyFile;
+ QFileDialog::Options options = {};
};
#define UrlRole (Qt::UserRole + 1)
@@ -133,12 +133,9 @@ public:
void createMenuActions();
void createWidgets();
- void init(const QUrl &directory = QUrl(), const QString &nameFilter = QString(),
- const QString &caption = QString());
+ void init(const QFileDialogArgs &args);
bool itemViewKeyboardEvent(QKeyEvent *event);
QString getEnvironmentVariable(const QString &string);
- static QUrl workingDirectory(const QUrl &path);
- static QString initialSelection(const QUrl &path);
QStringList typedFiles() const;
QList<QUrl> userSelectedFiles() const;
QStringList addDefaultSuffixToFiles(const QStringList &filesToFix) const;