Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickplatformfiledialog.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
6
7#include <QtCore/qloggingcategory.h>
8#include <QtGui/qwindow.h>
9#include <QtQml/qqmlcontext.h>
10#include <QtQml/qqmlinfo.h>
11#include <QtQml/qqmlcomponent.h>
12#include <QtQuick/qquickwindow.h>
13#include <QtQuickDialogs2Utils/private/qquickfilenamefilter_p.h>
14#include <QtQuickTemplates2/private/qquickdialog_p.h>
15#include <QtQuickTemplates2/private/qquickdialog_p_p.h>
16#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
17#include <QtQuickTemplates2/private/qquickpopupanchors_p.h>
18
20
22
23Q_STATIC_LOGGING_CATEGORY(lcQuickPlatformFileDialog, "qt.quick.dialogs.quickplatformfiledialog")
24
25/*!
26 \class QQuickPlatformFileDialog
27 \internal
28
29 An interface that QQuickFileDialog can use to access the non-native Qt Quick FileDialog.
30
31 Both this and the native implementations are created in QQuickAbstractDialog::create().
32*/
33QQuickPlatformFileDialog::QQuickPlatformFileDialog(QObject *parent)
34{
35 qCDebug(lcQuickPlatformFileDialog) << "creating non-native Qt Quick FileDialog with parent" << parent;
36
37 // Set a parent so that we get deleted if we can't be shown for whatever reason.
38 // Our eventual parent should be the window, though.
39 setParent(parent);
40
41 auto qmlContext = ::qmlContext(parent);
42 if (!qmlContext) {
43 qmlWarning(parent) << "No QQmlContext for QQuickPlatformFileDialog; can't create non-native FileDialog implementation";
44 return;
45 }
46
47 const auto dialogQmlUrl = QUrl(QStringLiteral("qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/qml/FileDialog.qml"));
48 QQmlComponent fileDialogComponent(qmlContext->engine(), dialogQmlUrl, parent);
49 if (!fileDialogComponent.isReady()) {
50 qmlWarning(parent) << "Failed to load non-native FileDialog implementation:\n" << fileDialogComponent.errorString();
51 return;
52 }
53 m_dialog = qobject_cast<QQuickFileDialogImpl*>(fileDialogComponent.create());
54 if (!m_dialog) {
55 qmlWarning(parent) << "Failed to create an instance of the non-native FileDialog:\n" << fileDialogComponent.errorString();
56 return;
57 }
58 // Give it a parent until it's parented to the window in show().
59 m_dialog->setParent(this);
60
61 connect(m_dialog, &QQuickDialog::accepted, this, &QPlatformDialogHelper::accept);
62 connect(m_dialog, &QQuickDialog::rejected, this, &QPlatformDialogHelper::reject);
63
64 connect(m_dialog, &QQuickFileDialogImpl::fileSelected, this, &QQuickPlatformFileDialog::fileSelected);
65 // TODO: add support for multiple file selection (QTBUG-92585)
66// connect(m_dialog, &QQuickFileDialogImpl::filesSelected, [this](const QList<QString> &files) {
67// QList<QUrl> urls;
68// urls.reserve(files.count());
69// for (const QString &file : files)
70// urls += QUrl::fromLocalFile(file);
71// emit filesSelected(urls);
72// });
73 connect(m_dialog, &QQuickFileDialogImpl::selectedFileChanged, this, &QQuickPlatformFileDialog::currentChanged);
74 connect(m_dialog, &QQuickFileDialogImpl::currentFolderChanged, this, &QQuickPlatformFileDialog::directoryEntered);
75 connect(m_dialog, &QQuickFileDialogImpl::filterSelected, this, &QQuickPlatformFileDialog::filterSelected);
76}
77
78bool QQuickPlatformFileDialog::isValid() const
79{
80 return m_dialog;
81}
82
83bool QQuickPlatformFileDialog::defaultNameFilterDisables() const
84{
85 return false;
86}
87
88void QQuickPlatformFileDialog::setDirectory(const QUrl &directory)
89{
90 if (!m_dialog)
91 return;
92
93 m_dialog->setCurrentFolder(directory);
94}
95
96QUrl QQuickPlatformFileDialog::directory() const
97{
98 if (!m_dialog)
99 return {};
100
101 return m_dialog->currentFolder();
102}
103
104void QQuickPlatformFileDialog::selectFile(const QUrl &file)
105{
106 if (!m_dialog)
107 return;
108
109 if (m_dialog->isVisible()) {
110 qWarning() << "Cannot set an initial selectedFile while FileDialog is open";
111 return;
112 }
113
114 // Since we're only called once each time the FileDialog is shown,
115 // we call setInitialCurrentFolderAndSelectedFile here, which will ensure that
116 // the first currentIndex change (to 0, as a result of the ListView's model changing
117 // as a result of the FolderListModel directory change) is effectively
118 // ignored and the correct index for the initial selectedFile is maintained.
119 m_dialog->setInitialCurrentFolderAndSelectedFile(file);
120}
121
122// TODO: support for multiple selected files
123QList<QUrl> QQuickPlatformFileDialog::selectedFiles() const
124{
125 if (!m_dialog || m_dialog->selectedFile().isEmpty())
126 return {};
127
128 return { m_dialog->selectedFile() };
129}
130
131void QQuickPlatformFileDialog::setFilter()
132{
133}
134
135void QQuickPlatformFileDialog::selectNameFilter(const QString &filter)
136{
137 // There is a bit of a problem with order here - QQuickFileDialog::onShow()
138 // is called before our show(), but it needs to set the selected filter
139 // (which we can't do in our show() because we don't know about QQuickFileDialog).
140 // So, delay setting the filter until we're shown. This shouldn't be an issue
141 // in practice, since it doesn't make sense for the filter to programmatically
142 // change while the dialog is visible.
143 m_pendingNameFilter = filter;
144}
145
146QString QQuickPlatformFileDialog::selectedNameFilter() const
147{
148 return m_dialog->selectedNameFilter()->name();
149}
150
151void QQuickPlatformFileDialog::exec()
152{
153 qCWarning(lcQuickPlatformFileDialog) << "exec() is not supported for the Qt Quick FileDialog fallback";
154}
155
156/*!
157 \internal
158
159 This is called after QQuickFileDialog::onShow().
160 Both are called in QQuickAbstractDialog::open().
161*/
162bool QQuickPlatformFileDialog::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
163{
164 qCDebug(lcQuickPlatformFileDialog) << "show called with flags" << flags <<
165 "modality" << modality << "parent" << parent;
166 if (!m_dialog)
167 return false;
168
169 if (!parent)
170 return false;
171
172 auto quickWindow = qobject_cast<QQuickWindow*>(parent);
173 if (!quickWindow) {
174 qmlInfo(this->parent()) << "Parent window (" << parent << ") of non-native dialog is not a QQuickWindow";
175 return false;
176 }
177 m_dialog->setParent(parent);
178 m_dialog->resetParentItem();
179
180 auto popupPrivate = QQuickPopupPrivate::get(m_dialog);
181 popupPrivate->getAnchors()->setCenterIn(m_dialog->parentItem());
182
183 QSharedPointer<QFileDialogOptions> options = QPlatformFileDialogHelper::options();
184 m_dialog->setTitle(options->windowTitle());
185 m_dialog->setOptions(options);
186 m_dialog->selectNameFilter(m_pendingNameFilter);
187 m_pendingNameFilter.clear();
188 m_dialog->setAcceptLabel(options->isLabelExplicitlySet(QFileDialogOptions::Accept)
189 ? options->labelText(QFileDialogOptions::Accept) : QString());
190 m_dialog->setRejectLabel(options->isLabelExplicitlySet(QFileDialogOptions::Reject)
191 ? options->labelText(QFileDialogOptions::Reject) : QString());
192
193 if (options->initiallySelectedFiles().isEmpty()) {
194 if (m_dialog->currentFolder().isEmpty()) {
195 // The user didn't set an initial selectedFile nor currentFolder, so we'll set it to the working directory.
196 qCDebug(lcQuickPlatformFileDialog) << "- calling setCurrentFolder(QDir()) on quick dialog" << parent;
197 m_dialog->setCurrentFolder(QUrl::fromLocalFile(QDir().absolutePath()));
198 }
199 }
200 m_dialog->setWindowModality(modality);
201 m_dialog->open();
202 return true;
203}
204
205void QQuickPlatformFileDialog::hide()
206{
207 if (!m_dialog)
208 return;
209
210 m_dialog->close();
211}
212
213QQuickFileDialogImpl *QQuickPlatformFileDialog::dialog() const
214{
215 return m_dialog;
216}
217
218QT_END_NAMESPACE
219
220#include "moc_qquickplatformfiledialog_p.cpp"