1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickfiledialogdelegate_p.h"
5
6#include <QtCore/qfileinfo.h>
7#include <QtGui/qpa/qplatformtheme.h>
8#include <QtQml/QQmlFile>
9#include <QtQml/qqmlexpression.h>
10#include <QtQuick/private/qquicklistview_p.h>
11#include <QtQuickTemplates2/private/qquickitemdelegate_p_p.h>
12
13#include "qquickfiledialogimpl_p.h"
14#include "qquickfiledialogimpl_p_p.h"
15#include "qquickfolderdialogimpl_p.h"
16
17QT_BEGIN_NAMESPACE
18
19class QQuickFileDialogDelegatePrivate : public QQuickItemDelegatePrivate
20{
21public:
22 Q_DECLARE_PUBLIC(QQuickFileDialogDelegate)
23
24 void highlightFile();
25 void chooseFile();
26
27 bool acceptKeyClick(Qt::Key key) const override;
28
29 QQuickDialog *dialog = nullptr;
30 QQuickFileDialogImpl *fileDialog = nullptr;
31 QQuickFolderDialogImpl *folderDialog = nullptr;
32 QUrl file;
33};
34
35void QQuickFileDialogDelegatePrivate::highlightFile()
36{
37 Q_Q(QQuickFileDialogDelegate);
38 QQuickListViewAttached *attached = static_cast<QQuickListViewAttached*>(
39 qmlAttachedPropertiesObject<QQuickListView>(obj: q));
40 if (!attached)
41 return;
42
43 QQmlContext *delegateContext = qmlContext(q);
44 if (!delegateContext)
45 return;
46
47 bool converted = false;
48 const int index = q->property(name: "index").toInt(ok: &converted);
49 if (converted) {
50 attached->view()->setCurrentIndex(index);
51 if (fileDialog)
52 fileDialog->setSelectedFile(file);
53 else if (folderDialog)
54 folderDialog->setSelectedFolder(file);
55 }
56}
57
58void QQuickFileDialogDelegatePrivate::chooseFile()
59{
60 const QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(file));
61 if (fileInfo.isDir()) {
62 // If it's a directory, navigate to it.
63 if (fileDialog)
64 fileDialog->setCurrentFolder(currentFolder: file);
65 else
66 folderDialog->setCurrentFolder(file);
67 } else {
68 Q_ASSERT(fileDialog);
69 // Otherwise it's a file, so select it and close the dialog.
70 fileDialog->setSelectedFile(file);
71
72 // Prioritize closing the dialog with QQuickDialogPrivate::handleClick() over QQuickDialog::accept()
73 const QQuickFileDialogImplAttached *attached = QQuickFileDialogImplPrivate::get(dialog: fileDialog)->attachedOrWarn();
74 if (Q_LIKELY(attached)) {
75 auto *openButton = attached->buttonBox()->standardButton(button: QPlatformDialogHelper::Open);
76 if (Q_LIKELY(openButton)) {
77 emit openButton->clicked();
78 return;
79 }
80 }
81 fileDialog->accept();
82 }
83}
84
85bool QQuickFileDialogDelegatePrivate::acceptKeyClick(Qt::Key key) const
86{
87 return key == Qt::Key_Return || key == Qt::Key_Enter;
88}
89
90QQuickFileDialogDelegate::QQuickFileDialogDelegate(QQuickItem *parent)
91 : QQuickItemDelegate(*(new QQuickFileDialogDelegatePrivate), parent)
92{
93 Q_D(QQuickFileDialogDelegate);
94 // Clicking and tabbing should result in it getting focus,
95 // as e.g. Ubuntu and Windows both allow tabbing through file dialogs.
96 setFocusPolicy(Qt::StrongFocus);
97 setCheckable(true);
98 QObjectPrivate::connect(sender: this, signal: &QQuickFileDialogDelegate::clicked,
99 receiverPrivate: d, slot: &QQuickFileDialogDelegatePrivate::highlightFile);
100 QObjectPrivate::connect(sender: this, signal: &QQuickFileDialogDelegate::doubleClicked,
101 receiverPrivate: d, slot: &QQuickFileDialogDelegatePrivate::chooseFile);
102}
103
104QQuickDialog *QQuickFileDialogDelegate::dialog() const
105{
106 Q_D(const QQuickFileDialogDelegate);
107 return d->dialog;
108}
109
110void QQuickFileDialogDelegate::setDialog(QQuickDialog *dialog)
111{
112 Q_D(QQuickFileDialogDelegate);
113 if (dialog == d->dialog)
114 return;
115
116 d->dialog = dialog;
117 d->fileDialog = qobject_cast<QQuickFileDialogImpl*>(object: dialog);
118 d->folderDialog = qobject_cast<QQuickFolderDialogImpl*>(object: dialog);
119 emit dialogChanged();
120}
121
122QUrl QQuickFileDialogDelegate::file() const
123{
124 Q_D(const QQuickFileDialogDelegate);
125 return d->file;
126}
127
128void QQuickFileDialogDelegate::setFile(const QUrl &file)
129{
130 Q_D(QQuickFileDialogDelegate);
131 QUrl adjustedFile = file;
132#ifdef Q_OS_WIN32
133 // Work around QTBUG-99105 (FolderListModel uses lowercase drive letter).
134 QString path = adjustedFile.path();
135 const int driveColonIndex = path.indexOf(QLatin1Char(':'));
136 if (driveColonIndex == 2) {
137 path.replace(1, 1, path.at(1).toUpper());
138 adjustedFile.setPath(path);
139 }
140#endif
141 if (adjustedFile == d->file)
142 return;
143
144 d->file = adjustedFile;
145 emit fileChanged();
146}
147
148void QQuickFileDialogDelegate::keyReleaseEvent(QKeyEvent *event)
149{
150 Q_D(QQuickFileDialogDelegate);
151 // We need to respond to being triggered by enter being pressed,
152 // but we can't use event->isAccepted() to check, because events are pre-accepted.
153 auto connection = QObjectPrivate::connect(sender: this, signal: &QQuickFileDialogDelegate::clicked,
154 receiverPrivate: d, slot: &QQuickFileDialogDelegatePrivate::chooseFile);
155
156 QQuickItemDelegate::keyReleaseEvent(event);
157
158 disconnect(connection);
159}
160
161QT_END_NAMESPACE
162
163#include "moc_qquickfiledialogdelegate_p.cpp"
164

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtdeclarative/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogdelegate.cpp