Skip to content

Commit

Permalink
Replace currentFile(s) with selectedFile(s)
Browse files Browse the repository at this point in the history
selectedFile can represent the currently-selected file (if the platform
supports it), and so we can free up "currentFolder" for FolderDialog
now that it means the folder that is being displayed, rather than the
folder that is currently selected.

[ChangeLog][QtQuickDialogs] FileDialog's currentFile and currentFiles
properties have been deprecated. The selectedFile and selectedFiles
properties now refer to the currently selected file(s), as well
as the final selection.

Fixes: QTBUG-98562
Task-number: QTBUG-87798
Pick-to: 6.3
Change-Id: Ic66481332338f21169a9f63617cf4db4be83265d
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
  • Loading branch information
mitchcurtis committed Jan 5, 2022
1 parent c1938dd commit 13399bd
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 135 deletions.
9 changes: 7 additions & 2 deletions src/quickcontrols2impl/qquickplatformtheme.cpp
Expand Up @@ -56,11 +56,16 @@ QQuickPlatformTheme::QQuickPlatformTheme(QObject *parent) :

QVariant QQuickPlatformTheme::themeHint(QPlatformTheme::ThemeHint themeHint) const
{
if (themeHint == QPlatformTheme::ShowDirectoriesFirst) {
// Allow tests to force this value, otherwise they get very messy and difficult to understand.
// Allow tests to force some theme hint values, otherwise they get very messy and difficult to understand.
switch (themeHint) {
case QPlatformTheme::ShowDirectoriesFirst: {
const QVariant showDirsFirst = qEnvironmentVariable("QT_QUICK_DIALOGS_SHOW_DIRS_FIRST");
if (showDirsFirst.isValid() && showDirsFirst.canConvert<bool>())
return showDirsFirst;
break;
}
default:
break;
}
return QGuiApplicationPrivate::platformTheme()->themeHint(themeHint);
}
Expand Down
69 changes: 25 additions & 44 deletions src/quickdialogs2/quickdialogs2/qquickfiledialog.cpp
Expand Up @@ -159,18 +159,16 @@ void QQuickFileDialog::setFileMode(FileMode mode)
\qmlproperty url QtQuick.Dialogs::FileDialog::selectedFile
\readonly
This property holds the final accepted file.
This property holds the last file that was selected in the dialog.
If there are multiple selected files, this property refers to the first
file.
Unlike the \l currentFile property, the \c selectedFile property is not
updated while the user is selecting files in the dialog, but only after the
final selection has been made. That is, when the user has clicked
\uicontrol OK to accept a file. Alternatively, the
\l {Dialog::}{accepted()} signal can be handled to get the final selection.
The value of this property is updated each time the user selects a file in
the dialog, and when the dialog is accepted. Handle the
\l {Dialog::}{accepted()} signal to get the final selection.
\sa selectedFiles, currentFile, {Dialog::}{accepted()}, currentFolder
\sa selectedFiles, {Dialog::}{accepted()}, currentFolder
*/
QUrl QQuickFileDialog::selectedFile() const
{
Expand All @@ -180,15 +178,13 @@ QUrl QQuickFileDialog::selectedFile() const
/*!
\qmlproperty list<url> QtQuick.Dialogs::FileDialog::selectedFiles
This property holds the final accepted files.
This property holds the last files that were selected in the dialog.
Unlike the \l currentFiles property, the \c selectedFiles property is not
updated while the user is selecting files in the dialog, but only after the
final selection has been made. That is, when the user has clicked
\uicontrol OK to accept files. Alternatively, the \l {Dialog::}{accepted()}
signal can be handled to get the final selection.
The value of this property is updated each time the user selects files in
the dialog, and when the dialog is accepted. Handle the
\l {Dialog::}{accepted()} signal to get the final selection.
\sa currentFiles, {Dialog::}{accepted()}, currentFolder
\sa {Dialog::}{accepted()}, currentFolder
*/
QList<QUrl> QQuickFileDialog::selectedFiles() const
{
Expand All @@ -202,57 +198,48 @@ void QQuickFileDialog::setSelectedFiles(const QList<QUrl> &selectedFiles)

bool firstChanged = m_selectedFiles.value(0) != selectedFiles.value(0);
m_selectedFiles = selectedFiles;
if (firstChanged)
if (firstChanged) {
emit selectedFileChanged();
emit currentFileChanged();
}
emit selectedFilesChanged();
emit currentFilesChanged();
}

/*!
\qmlproperty url QtQuick.Dialogs::FileDialog::currentFile
\deprecated [6.3] Use \l selectedFile instead.
This property holds the currently selected file in the dialog.
Unlike the \l selectedFile property, the \c currentFile property is updated
while the user is selecting files in the dialog, even before the final
selection has been made.
\sa selectedFile, currentFiles, currentFolder
*/
QUrl QQuickFileDialog::currentFile() const
{
return currentFiles().value(0);
return selectedFile();
}

void QQuickFileDialog::setCurrentFile(const QUrl &file)
{
setCurrentFiles(QList<QUrl>() << file);
setSelectedFiles(QList<QUrl>() << file);
}

/*!
\qmlproperty list<url> QtQuick.Dialogs::FileDialog::currentFiles
\deprecated [6.3] Use \l selectedFiles instead.
This property holds the currently selected files in the dialog.
Unlike the \l selectedFiles property, the \c currentFiles property is
updated while the user is selecting files in the dialog, even before the
final selection has been made.
\sa selectedFiles, currentFile, currentFolder
*/
QList<QUrl> QQuickFileDialog::currentFiles() const
{
if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle()))
return fileDialog->selectedFiles();
return m_options->initiallySelectedFiles();
return selectedFiles();
}

void QQuickFileDialog::setCurrentFiles(const QList<QUrl> &currentFiles)
{
if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle())) {
for (const QUrl &file : currentFiles)
fileDialog->selectFile(file);
}
m_options->setInitiallySelectedFiles(currentFiles);
setSelectedFiles(currentFiles);
}

/*!
Expand Down Expand Up @@ -541,10 +528,13 @@ bool QQuickFileDialog::useNativeDialog() const
void QQuickFileDialog::onCreate(QPlatformDialogHelper *dialog)
{
if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(dialog)) {
connect(fileDialog, &QPlatformFileDialogHelper::currentChanged, this, &QQuickFileDialog::currentFileChanged);
connect(fileDialog, &QPlatformFileDialogHelper::currentChanged, this, &QQuickFileDialog::currentFilesChanged);
connect(fileDialog, &QPlatformFileDialogHelper::currentChanged, this, [=](){ setSelectedFiles(fileDialog->selectedFiles()); });
connect(fileDialog, &QPlatformFileDialogHelper::directoryEntered, this, &QQuickFileDialog::currentFolderChanged);
fileDialog->setOptions(m_options);

// Need to call this manually once on creation because QPlatformFileDialogHelper::currentChanged
// has already been emitted by this point (because of QQuickFileDialogImplPrivate::updateSelectedFile).
setSelectedFiles(fileDialog->selectedFiles());
}
}

Expand Down Expand Up @@ -580,15 +570,6 @@ void QQuickFileDialog::onHide(QPlatformDialogHelper *dialog)
}
}

void QQuickFileDialog::accept()
{
if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle())) {
// Take the currently selected files and make them the final set of files.
setSelectedFiles(fileDialog->selectedFiles());
}
QQuickAbstractDialog::accept();
}

QUrl QQuickFileDialog::addDefaultSuffix(const QUrl &file) const
{
QUrl url = file;
Expand Down
1 change: 0 additions & 1 deletion src/quickdialogs2/quickdialogs2/qquickfiledialog_p.h
Expand Up @@ -146,7 +146,6 @@ class Q_QUICKDIALOGS2_PRIVATE_EXPORT QQuickFileDialog : public QQuickAbstractDia
void onCreate(QPlatformDialogHelper *dialog) override;
void onShow(QPlatformDialogHelper *dialog) override;
void onHide(QPlatformDialogHelper *dialog) override;
void accept() override;

private:
QUrl addDefaultSuffix(const QUrl &file) const;
Expand Down
Expand Up @@ -84,7 +84,7 @@ void QQuickFileDialogDelegatePrivate::highlightFile()
if (converted) {
attached->view()->setCurrentIndex(index);
if (fileDialog)
fileDialog->setCurrentFile(file);
fileDialog->setSelectedFile(file);
else if (folderDialog)
folderDialog->setSelectedFolder(file);
}
Expand Down
66 changes: 26 additions & 40 deletions src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogimpl.cpp
Expand Up @@ -52,6 +52,7 @@
QT_BEGIN_NAMESPACE

Q_LOGGING_CATEGORY(lcCurrentFolder, "qt.quick.dialogs.quickfiledialogimpl.currentFolder")
Q_LOGGING_CATEGORY(lcUpdateSelectedFile, "qt.quick.dialogs.quickfiledialogimpl.updateSelectedFile")
Q_LOGGING_CATEGORY(lcOptions, "qt.quick.dialogs.quickfiledialogimpl.options")
Q_LOGGING_CATEGORY(lcNameFilters, "qt.quick.dialogs.quickfiledialogimpl.namefilters")
Q_LOGGING_CATEGORY(lcAttachedNameFilters, "qt.quick.dialogs.quickfiledialogimplattached.namefilters")
Expand Down Expand Up @@ -83,7 +84,7 @@ void QQuickFileDialogImplPrivate::updateEnabled()
return;
}

openButton->setEnabled(!currentFile.isEmpty() && attached->breadcrumbBar()
openButton->setEnabled(!selectedFile.isEmpty() && attached->breadcrumbBar()
&& !attached->breadcrumbBar()->textField()->isVisible());
}

Expand All @@ -94,47 +95,47 @@ void QQuickFileDialogImplPrivate::updateEnabled()
\a oldFolderPath is the previous value of \c folder.
*/
void QQuickFileDialogImplPrivate::updateCurrentFile(const QString &oldFolderPath)
void QQuickFileDialogImplPrivate::updateSelectedFile(const QString &oldFolderPath)
{
Q_Q(QQuickFileDialogImpl);
QQuickFileDialogImplAttached *attached = attachedOrWarn();
if (!attached || !attached->fileDialogListView())
return;

QString newCurrentFilePath;
int newCurrentFileIndex = 0;
QString newSelectedFilePath;
int newSelectedFileIndex = 0;
const QString newFolderPath = QQmlFile::urlToLocalFileOrQrc(currentFolder);
if (!oldFolderPath.isEmpty() && !newFolderPath.isEmpty()) {
// If the user went up a directory (or several), we should set
// currentFile to be the directory that we were in (or
// selectedFile to be the directory that we were in (or
// its closest ancestor that is a child of the new directory).
// E.g. if oldFolderPath is /foo/bar/baz/abc/xyz, and newFolderPath is /foo/bar,
// then we want to set currentFile to be /foo/bar/baz.
// then we want to set selectedFile to be /foo/bar/baz.
const int indexOfFolder = oldFolderPath.indexOf(newFolderPath);
if (indexOfFolder != -1) {
// [folder]
// [ oldFolderPath ]
// /foo/bar/baz/abc/xyz
// [rel...Paths]
QStringList relativePaths = oldFolderPath.mid(indexOfFolder + newFolderPath.size()).split(QLatin1Char('/'), Qt::SkipEmptyParts);
newCurrentFilePath = newFolderPath + QLatin1Char('/') + relativePaths.first();
newSelectedFilePath = newFolderPath + QLatin1Char('/') + relativePaths.first();

// Now find the index of that directory so that we can set the ListView's currentIndex to it.
const QDir newFolderDir(newFolderPath);
// Just to be safe...
if (!newFolderDir.exists()) {
qmlWarning(q) << "Directory" << newCurrentFilePath << "doesn't exist; can't get a file entry list for it";
qmlWarning(q) << "Directory" << newSelectedFilePath << "doesn't exist; can't get a file entry list for it";
return;
}

const QFileInfoList dirs = newFolderDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::DirsFirst);
const QFileInfo newCurrentFileInfo(newCurrentFilePath);
const QFileInfo newSelectedFileInfo(newSelectedFilePath);
// The directory can contain files, but since we put dirs first, that should never affect the indices.
newCurrentFileIndex = dirs.indexOf(newCurrentFileInfo);
newSelectedFileIndex = dirs.indexOf(newSelectedFileInfo);
}
}

if (newCurrentFilePath.isEmpty()) {
if (newSelectedFilePath.isEmpty()) {
// When entering into a directory that isn't a parent of the old one, the first
// file delegate should be selected.
// TODO: is there a cheaper way to do this? QDirIterator doesn't support sorting,
Expand All @@ -145,13 +146,15 @@ void QQuickFileDialogImplPrivate::updateCurrentFile(const QString &oldFolderPath
if (newFolderDir.exists()) {
const QFileInfoList files = newFolderDir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, QDir::DirsFirst);
if (!files.isEmpty())
newCurrentFilePath = files.first().absoluteFilePath();
newSelectedFilePath = files.first().absoluteFilePath();
}
}

if (!newCurrentFilePath.isEmpty()) {
q->setCurrentFile(QUrl::fromLocalFile(newCurrentFilePath));
attached->fileDialogListView()->setCurrentIndex(newCurrentFileIndex);
const QUrl newSelectedFileUrl = QUrl::fromLocalFile(newSelectedFilePath);
qCDebug(lcUpdateSelectedFile) << "updateSelectedFile is setting selectedFile to" << newSelectedFileUrl;
q->setSelectedFile(newSelectedFileUrl);
if (!newSelectedFilePath.isEmpty()) {
attached->fileDialogListView()->setCurrentIndex(newSelectedFileIndex);
if (QQuickItem *currentItem = attached->fileDialogListView()->currentItem())
currentItem->forceActiveFocus();
}
Expand All @@ -165,19 +168,19 @@ void QQuickFileDialogImplPrivate::handleAccept()
void QQuickFileDialogImplPrivate::handleClick(QQuickAbstractButton *button)
{
Q_Q(QQuickFileDialogImpl);
if (buttonRole(button) == QPlatformDialogHelper::AcceptRole && currentFile.isValid()) {
if (buttonRole(button) == QPlatformDialogHelper::AcceptRole && selectedFile.isValid()) {
// The "Open" button was clicked, so we need to set the file to the current file, if any.
const QFileInfo fileInfo(currentFile.toLocalFile());
const QFileInfo fileInfo(selectedFile.toLocalFile());
if (fileInfo.isDir()) {
// If it's a directory, navigate to it.
q->setCurrentFolder(currentFile);
q->setCurrentFolder(selectedFile);
// Don't call accept(), because selecting a folder != accepting the dialog.
} else {
// Otherwise it's a file, so select it and close the dialog.
q->setSelectedFile(currentFile);
q->setSelectedFile(selectedFile);
q->accept();
QQuickDialogPrivate::handleClick(button);
emit q->fileSelected(currentFile);
emit q->fileSelected(selectedFile);
}
}
}
Expand Down Expand Up @@ -209,8 +212,7 @@ void QQuickFileDialogImpl::setCurrentFolder(const QUrl &currentFolder)

d->currentFolder = currentFolder;
// Since the directory changed, the old file can no longer be selected.
setCurrentFile(QUrl());
d->updateCurrentFile(oldFolderPath);
d->updateSelectedFile(oldFolderPath);
emit currentFolderChanged(d->currentFolder);
}

Expand All @@ -227,24 +229,8 @@ void QQuickFileDialogImpl::setSelectedFile(const QUrl &selectedFile)
return;

d->selectedFile = selectedFile;
emit selectedFileChanged();
}

QUrl QQuickFileDialogImpl::currentFile() const
{
Q_D(const QQuickFileDialogImpl);
return d->currentFile;
}

void QQuickFileDialogImpl::setCurrentFile(const QUrl &currentFile)
{
Q_D(QQuickFileDialogImpl);
if (currentFile == d->currentFile)
return;

d->currentFile = currentFile;
d->updateEnabled();
emit currentFileChanged(d->currentFile);
emit selectedFileChanged(d->selectedFile);
}

QSharedPointer<QFileDialogOptions> QQuickFileDialogImpl::options() const
Expand Down Expand Up @@ -432,7 +418,7 @@ void QQuickFileDialogImplAttachedPrivate::fileDialogListViewCurrentIndexChanged(
if (!fileDialogDelegate)
return;

fileDialogImpl->setCurrentFile(fileDialogDelegate->file());
fileDialogImpl->setSelectedFile(fileDialogDelegate->file());
}

QQuickFileDialogImplAttached::QQuickFileDialogImplAttached(QObject *parent)
Expand Down
Expand Up @@ -72,7 +72,6 @@ class Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT QQuickFileDialogImpl : public QQui
Q_OBJECT
Q_PROPERTY(QUrl currentFolder READ currentFolder WRITE setCurrentFolder NOTIFY currentFolderChanged FINAL)
Q_PROPERTY(QUrl selectedFile READ selectedFile WRITE setSelectedFile NOTIFY selectedFileChanged FINAL)
Q_PROPERTY(QUrl currentFile READ currentFile WRITE setCurrentFile NOTIFY currentFileChanged FINAL)
Q_PROPERTY(QStringList nameFilters READ nameFilters NOTIFY nameFiltersChanged FINAL)
Q_PROPERTY(QQuickFileNameFilter *selectedNameFilter READ selectedNameFilter CONSTANT)
QML_NAMED_ELEMENT(FileDialogImpl)
Expand All @@ -92,9 +91,6 @@ class Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT QQuickFileDialogImpl : public QQui
QUrl selectedFile() const;
void setSelectedFile(const QUrl &file);

QUrl currentFile() const;
void setCurrentFile(const QUrl &currentFile);

QSharedPointer<QFileDialogOptions> options() const;
void setOptions(const QSharedPointer<QFileDialogOptions> &options);

Expand All @@ -111,8 +107,7 @@ public Q_SLOTS:

Q_SIGNALS:
void currentFolderChanged(const QUrl &folderUrl);
void selectedFileChanged();
void currentFileChanged(const QUrl &currentFileUrl);
void selectedFileChanged(const QUrl &selectedFileUrl);
void nameFiltersChanged();
void fileSelected(const QUrl &fileUrl);
void filterSelected(const QString &filter);
Expand Down
Expand Up @@ -78,15 +78,14 @@ class QQuickFileDialogImplPrivate : public QQuickDialogPrivate
void setNameFilters(const QStringList &filters);

void updateEnabled();
void updateCurrentFile(const QString &oldFolderPath);
void updateSelectedFile(const QString &oldFolderPath);

void handleAccept() override;
void handleClick(QQuickAbstractButton *button) override;

QSharedPointer<QFileDialogOptions> options;
QUrl currentFolder;
QUrl selectedFile;
QUrl currentFile;
QStringList nameFilters;
mutable QQuickFileNameFilter *selectedNameFilter = nullptr;
QString acceptLabel;
Expand Down

0 comments on commit 13399bd

Please sign in to comment.