Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qiosfiledialog.mm
Go to the documentation of this file.
1// Copyright (C) 2016 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#import <UIKit/UIKit.h>
5
6#import <Photos/Photos.h>
7
8#include <QtCore/qstandardpaths.h>
9#include <QtGui/qwindow.h>
10#include <QDebug>
11
12#include <QtCore/private/qcore_mac_p.h>
13
14#include "qiosglobal.h"
15#include "qiosfiledialog.h"
16#include "qiosintegration.h"
19
20#include <QtCore/qpointer.h>
21
22using namespace Qt::StringLiterals;
23
25 : m_viewController(nullptr)
26{
27}
28
30{
31 [m_viewController release];
32}
33
35{
36 m_eventLoop.exec(QEventLoop::DialogExec);
37}
38
39bool QIOSFileDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent)
40{
41 Q_UNUSED(windowFlags);
42 Q_UNUSED(windowModality);
43
44 const bool acceptOpen = options()->acceptMode() == QFileDialogOptions::AcceptOpen;
45 const auto initialDir = options()->initialDirectory();
46 const QString directory = initialDir.toLocalFile();
47 // We manually add assets-library:// to the list of paths,
48 // when converted to QUrl, it becames a scheme.
49 const QString scheme = initialDir.scheme();
50
51 if (acceptOpen) {
52 if (directory.startsWith("assets-library:"_L1) || scheme == "assets-library"_L1)
53 return showImagePickerDialog(parent);
54 else
55 return showNativeDocumentPickerDialog(parent);
56 }
57
58 return false;
59}
60
61void QIOSFileDialog::showImagePickerDialog_helper(QWindow *parent)
62{
63 UIWindow *window = presentationWindow(parent);
64 [window.rootViewController presentViewController:m_viewController animated:YES completion:nil];
65}
66
67bool QIOSFileDialog::showImagePickerDialog(QWindow *parent)
68{
69 if (!m_viewController) {
70 QFactoryLoader *plugins = QIOSIntegration::instance()->optionalPlugins();
71 qsizetype size = QList<QPluginParsedMetaData>(plugins->metaData()).size();
72 for (qsizetype i = 0; i < size; ++i) {
73 QIosOptionalPluginInterface *plugin = qobject_cast<QIosOptionalPluginInterface *>(plugins->instance(i));
74 m_viewController = [plugin->createImagePickerController(this) retain];
75 if (m_viewController)
76 break;
77 }
78 }
79
80 if (!m_viewController) {
81 qWarning() << "QIOSFileDialog: Could not resolve Qt plugin that gives access to photos on iOS";
82 return false;
83 }
84
85 // "Old style" authorization (deprecated, but we have to work with AssetsLibrary anyway).
86 //
87 // From the documentation:
88 // "The authorizationStatus and requestAuthorization: methods aren’t compatible with the
89 // limited library and return PHAuthorizationStatusAuthorized when the user authorizes your
90 // app for limited access only."
91 //
92 // This is good enough for us.
93
94 const auto authStatus = [PHPhotoLibrary authorizationStatus];
95 if (authStatus == PHAuthorizationStatusAuthorized) {
96 showImagePickerDialog_helper(parent);
97 } else if (authStatus == PHAuthorizationStatusNotDetermined) {
98 QPointer<QWindow> winGuard(parent);
99 QPointer<QIOSFileDialog> thisGuard(this);
100 [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
101 dispatch_async(dispatch_get_main_queue(), ^{
102 if (status == PHAuthorizationStatusAuthorized) {
103 if (thisGuard && winGuard)
104 thisGuard->showImagePickerDialog_helper(winGuard);
105
106 } else if (thisGuard) {
107 emit thisGuard->reject();
108 }
109 });
110 }];
111 } else {
112 // Treat 'Limited' (we don't know how to deal with anyway) and 'Denied' as errors.
113 // FIXME: logging category?
114 qWarning() << "QIOSFileDialog: insufficient permission, cannot pick images";
115 return false;
116 }
117
118 return true;
119}
120
121bool QIOSFileDialog::showNativeDocumentPickerDialog(QWindow *parent)
122{
123#ifndef Q_OS_TVOS
124 m_viewController = [[QIOSDocumentPickerController alloc] initWithQIOSFileDialog:this];
125
126 UIWindow *window = presentationWindow(parent);
127 [window.rootViewController presentViewController:m_viewController animated:YES completion:nil];
128
129 return true;
130#else
131 return false;
132#endif
133}
134
136{
137 // QFileDialog will remember the last directory set, and open subsequent dialogs in the same
138 // directory for convenience. This works for normal file dialogs, but not when using native
139 // pickers. Those can only be used for picking specific types, without support for normal file
140 // system navigation. To avoid showing a native picker by accident, we change directory back
141 // before we return. More could have been done to preserve the "last directory" logic here, but
142 // navigating the file system on iOS is not recommended in the first place, so we keep it simple.
144
145 [m_viewController dismissViewControllerAnimated:YES completion:nil];
146 [m_viewController release];
147 m_viewController = nullptr;
148 m_eventLoop.exit();
149}
150
152{
153 return m_selection;
154}
155
157{
158 m_selection = selection;
159 emit filesSelected(m_selection);
160 if (m_selection.count() == 1)
161 emit fileSelected(m_selection[0]);
162}
static QString currentPath()
Returns the absolute path of the application's current directory.
Definition qdir.cpp:2054
int exec(ProcessEventsFlags flags=AllEvents)
Enters the main event loop and waits until exit() is called.
void exit(int returnCode=0)
Tells the event loop to exit with a return code.
MetaDataList metaData() const
QObject * instance(int index) const
AcceptMode acceptMode() const
void hide() override
QUrl directory() const override
QList< QUrl > selectedFiles() const override
bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override
void selectedFilesChanged(const QList< QUrl > &selection)
void exec() override
static QIOSIntegration * instance()
qsizetype count() const noexcept
Definition qlist.h:398
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
void fileSelected(const QUrl &file)
void directoryEntered(const QUrl &directory)
const QSharedPointer< QFileDialogOptions > & options() const
void filesSelected(const QList< QUrl > &files)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
Definition qurl.cpp:3368
QString toLocalFile() const
Returns the path of this URL formatted as a local file path.
Definition qurl.cpp:3425
\inmodule QtGui
Definition qwindow.h:63
WindowModality
UIWindow * presentationWindow(QWindow *)
Definition qiosglobal.mm:96
#define qWarning
Definition qlogging.h:166
GLenum GLuint GLintptr GLsizeiptr size
[1]
#define emit
#define Q_UNUSED(x)
ptrdiff_t qsizetype
Definition qtypes.h:165
QObject::connect nullptr
sem release()
QItemSelection * selection
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]