diff options
Diffstat (limited to 'src/quickdialogs/quickdialogsquickimpl/qquickfiledialogdelegate.cpp')
-rw-r--r-- | src/quickdialogs/quickdialogsquickimpl/qquickfiledialogdelegate.cpp | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogdelegate.cpp b/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogdelegate.cpp new file mode 100644 index 0000000000..369176f844 --- /dev/null +++ b/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogdelegate.cpp @@ -0,0 +1,163 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qquickfiledialogdelegate_p.h" + +#include <QtCore/qfileinfo.h> +#include <QtGui/qpa/qplatformtheme.h> +#include <QtQml/QQmlFile> +#include <QtQml/qqmlexpression.h> +#include <QtQuick/private/qquicklistview_p.h> +#include <QtQuickTemplates2/private/qquickitemdelegate_p_p.h> + +#include "qquickfiledialogimpl_p.h" +#include "qquickfiledialogimpl_p_p.h" +#include "qquickfolderdialogimpl_p.h" + +QT_BEGIN_NAMESPACE + +class QQuickFileDialogDelegatePrivate : public QQuickItemDelegatePrivate +{ +public: + Q_DECLARE_PUBLIC(QQuickFileDialogDelegate) + + void highlightFile(); + void chooseFile(); + + bool acceptKeyClick(Qt::Key key) const override; + + QQuickDialog *dialog = nullptr; + QQuickFileDialogImpl *fileDialog = nullptr; + QQuickFolderDialogImpl *folderDialog = nullptr; + QUrl file; +}; + +void QQuickFileDialogDelegatePrivate::highlightFile() +{ + Q_Q(QQuickFileDialogDelegate); + QQuickListViewAttached *attached = static_cast<QQuickListViewAttached*>( + qmlAttachedPropertiesObject<QQuickListView>(q)); + if (!attached) + return; + + QQmlContext *delegateContext = qmlContext(q); + if (!delegateContext) + return; + + bool converted = false; + const int index = q->property("index").toInt(&converted); + if (converted) { + attached->view()->setCurrentIndex(index); + if (fileDialog) + fileDialog->setSelectedFile(file); + else if (folderDialog) + folderDialog->setSelectedFolder(file); + } +} + +void QQuickFileDialogDelegatePrivate::chooseFile() +{ + const QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(file)); + if (fileInfo.isDir()) { + // If it's a directory, navigate to it. + if (fileDialog) + fileDialog->setCurrentFolder(file); + else + folderDialog->setCurrentFolder(file); + } else { + Q_ASSERT(fileDialog); + // Otherwise it's a file, so select it and close the dialog. + fileDialog->setSelectedFile(file); + + // Prioritize closing the dialog with QQuickDialogPrivate::handleClick() over QQuickDialog::accept() + const QQuickFileDialogImplAttached *attached = QQuickFileDialogImplPrivate::get(fileDialog)->attachedOrWarn(); + if (Q_LIKELY(attached)) { + auto *openButton = attached->buttonBox()->standardButton(QPlatformDialogHelper::Open); + if (Q_LIKELY(openButton)) { + emit openButton->clicked(); + return; + } + } + fileDialog->accept(); + } +} + +bool QQuickFileDialogDelegatePrivate::acceptKeyClick(Qt::Key key) const +{ + return key == Qt::Key_Return || key == Qt::Key_Enter; +} + +QQuickFileDialogDelegate::QQuickFileDialogDelegate(QQuickItem *parent) + : QQuickItemDelegate(*(new QQuickFileDialogDelegatePrivate), parent) +{ + Q_D(QQuickFileDialogDelegate); + // Clicking and tabbing should result in it getting focus, + // as e.g. Ubuntu and Windows both allow tabbing through file dialogs. + setFocusPolicy(Qt::StrongFocus); + setCheckable(true); + QObjectPrivate::connect(this, &QQuickFileDialogDelegate::clicked, + d, &QQuickFileDialogDelegatePrivate::highlightFile); + QObjectPrivate::connect(this, &QQuickFileDialogDelegate::doubleClicked, + d, &QQuickFileDialogDelegatePrivate::chooseFile); +} + +QQuickDialog *QQuickFileDialogDelegate::dialog() const +{ + Q_D(const QQuickFileDialogDelegate); + return d->dialog; +} + +void QQuickFileDialogDelegate::setDialog(QQuickDialog *dialog) +{ + Q_D(QQuickFileDialogDelegate); + if (dialog == d->dialog) + return; + + d->dialog = dialog; + d->fileDialog = qobject_cast<QQuickFileDialogImpl*>(dialog); + d->folderDialog = qobject_cast<QQuickFolderDialogImpl*>(dialog); + emit dialogChanged(); +} + +QUrl QQuickFileDialogDelegate::file() const +{ + Q_D(const QQuickFileDialogDelegate); + return d->file; +} + +void QQuickFileDialogDelegate::setFile(const QUrl &file) +{ + Q_D(QQuickFileDialogDelegate); + QUrl adjustedFile = file; +#ifdef Q_OS_WIN32 + // Work around QTBUG-99105 (FolderListModel uses lowercase drive letter). + QString path = adjustedFile.path(); + const int driveColonIndex = path.indexOf(QLatin1Char(':')); + if (driveColonIndex == 2) { + path.replace(1, 1, path.at(1).toUpper()); + adjustedFile.setPath(path); + } +#endif + if (adjustedFile == d->file) + return; + + d->file = adjustedFile; + emit fileChanged(); +} + +void QQuickFileDialogDelegate::keyReleaseEvent(QKeyEvent *event) +{ + Q_D(QQuickFileDialogDelegate); + // We need to respond to being triggered by enter being pressed, + // but we can't use event->isAccepted() to check, because events are pre-accepted. + auto connection = QObjectPrivate::connect(this, &QQuickFileDialogDelegate::clicked, + d, &QQuickFileDialogDelegatePrivate::chooseFile); + + QQuickItemDelegate::keyReleaseEvent(event); + + disconnect(connection); +} + +QT_END_NAMESPACE + +#include "moc_qquickfiledialogdelegate_p.cpp" |