Add native iOS file dialog

This patch adds native iOS file open and directory picking support for
the QFileDialog using the iOS UIDocumentPickerViewController class.

Change-Id: Ia724a59742650a01c62067aed3477f82ab1fd546
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Harald Meyer 2020-03-10 19:16:20 +01:00
parent 395e2d9bc4
commit 91436e2409
5 changed files with 182 additions and 6 deletions

View File

@ -57,13 +57,15 @@ HEADERS = \
qiosmenu.mm \ qiosmenu.mm \
qiosfiledialog.mm \ qiosfiledialog.mm \
qiosmessagedialog.mm \ qiosmessagedialog.mm \
qiostextinputoverlay.mm qiostextinputoverlay.mm \
qiosdocumentpickercontroller.mm
HEADERS += \ HEADERS += \
qiosclipboard.h \ qiosclipboard.h \
qiosmenu.h \ qiosmenu.h \
qiosfiledialog.h \ qiosfiledialog.h \
qiosmessagedialog.h \ qiosmessagedialog.h \
qiostextinputoverlay.h qiostextinputoverlay.h \
qiosdocumentpickercontroller.h
} }
OTHER_FILES = \ OTHER_FILES = \

View File

@ -0,0 +1,46 @@
/****************************************************************************
**
** Copyright (C) 2020 Harald Meyer.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#import <UIKit/UIKit.h>
#include "qiosfiledialog.h"
@interface QIOSDocumentPickerController : UIDocumentPickerViewController <UIDocumentPickerDelegate, UINavigationControllerDelegate>
- (instancetype)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog;
@end

View File

@ -0,0 +1,103 @@
/****************************************************************************
**
** Copyright (C) 2020 Harald Meyer.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#import <UIKit/UIKit.h>
#import <MobileCoreServices/MobileCoreServices.h>
#include "qiosdocumentpickercontroller.h"
@implementation QIOSDocumentPickerController {
QIOSFileDialog *m_fileDialog;
}
- (instancetype)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog
{
NSMutableArray <NSString *> *docTypes = [[[NSMutableArray alloc] init] autorelease];
UIDocumentPickerMode importMode;
switch (fileDialog->options()->fileMode()) {
case QFileDialogOptions::AnyFile:
case QFileDialogOptions::ExistingFile:
case QFileDialogOptions::ExistingFiles:
[docTypes addObject:(__bridge NSString *)kUTTypeContent];
[docTypes addObject:(__bridge NSString *)kUTTypeItem];
[docTypes addObject:(__bridge NSString *)kUTTypeData];
importMode = UIDocumentPickerModeImport;
break;
case QFileDialogOptions::Directory:
case QFileDialogOptions::DirectoryOnly:
// Directory picking is not supported because it requires
// special handling not possible with the current QFilePicker
// implementation.
Q_UNREACHABLE();
}
if (self = [super initWithDocumentTypes:docTypes inMode:importMode]) {
m_fileDialog = fileDialog;
self.modalPresentationStyle = UIModalPresentationFormSheet;
self.delegate = self;
if (m_fileDialog->options()->fileMode() == QFileDialogOptions::ExistingFiles)
self.allowsMultipleSelection = YES;
if (@available(ios 13.0, *))
self.directoryURL = m_fileDialog->options()->initialDirectory().toNSURL();
}
return self;
}
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray <NSURL *>*)urls
{
Q_UNUSED(controller);
QList<QUrl> files;
for (NSURL* url in urls)
files.append(QUrl::fromNSURL(url));
m_fileDialog->selectedFilesChanged(files);
emit m_fileDialog->accept();
}
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller
{
Q_UNUSED(controller)
emit m_fileDialog->reject();
}
@end

View File

@ -65,7 +65,7 @@ public:
void selectNameFilter(const QString &) override {} void selectNameFilter(const QString &) override {}
QString selectedNameFilter() const override { return QString(); } QString selectedNameFilter() const override { return QString(); }
void selectedFilesChanged(QList<QUrl> selection); void selectedFilesChanged(const QList<QUrl> &selection);
private: private:
QUrl m_directory; QUrl m_directory;
@ -74,6 +74,7 @@ private:
UIViewController *m_viewController; UIViewController *m_viewController;
bool showImagePickerDialog(QWindow *parent); bool showImagePickerDialog(QWindow *parent);
bool showNativeDocumentPickerDialog(QWindow *parent);
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -48,6 +48,7 @@
#include "qiosfiledialog.h" #include "qiosfiledialog.h"
#include "qiosintegration.h" #include "qiosintegration.h"
#include "qiosoptionalplugininterface.h" #include "qiosoptionalplugininterface.h"
#include "qiosdocumentpickercontroller.h"
QIOSFileDialog::QIOSFileDialog() QIOSFileDialog::QIOSFileDialog()
: m_viewController(nullptr) : m_viewController(nullptr)
@ -72,8 +73,12 @@ bool QIOSFileDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality window
bool acceptOpen = options()->acceptMode() == QFileDialogOptions::AcceptOpen; bool acceptOpen = options()->acceptMode() == QFileDialogOptions::AcceptOpen;
QString directory = options()->initialDirectory().toLocalFile(); QString directory = options()->initialDirectory().toLocalFile();
if (acceptOpen && directory.startsWith(QLatin1String("assets-library:"))) if (acceptOpen) {
return showImagePickerDialog(parent); if (directory.startsWith(QLatin1String("assets-library:")))
return showImagePickerDialog(parent);
else
return showNativeDocumentPickerDialog(parent);
}
return false; return false;
} }
@ -102,6 +107,25 @@ bool QIOSFileDialog::showImagePickerDialog(QWindow *parent)
return true; return true;
} }
bool QIOSFileDialog::showNativeDocumentPickerDialog(QWindow *parent)
{
#ifndef Q_OS_TVOS
if (options()->fileMode() == QFileDialogOptions::Directory ||
options()->fileMode() == QFileDialogOptions::DirectoryOnly)
return false;
m_viewController = [[QIOSDocumentPickerController alloc] initWithQIOSFileDialog:this];
UIWindow *window = parent ? reinterpret_cast<UIView *>(parent->winId()).window
: qt_apple_sharedApplication().keyWindow;
[window.rootViewController presentViewController:m_viewController animated:YES completion:nil];
return true;
#else
return false;
#endif
}
void QIOSFileDialog::hide() void QIOSFileDialog::hide()
{ {
// QFileDialog will remember the last directory set, and open subsequent dialogs in the same // QFileDialog will remember the last directory set, and open subsequent dialogs in the same
@ -123,7 +147,7 @@ QList<QUrl> QIOSFileDialog::selectedFiles() const
return m_selection; return m_selection;
} }
void QIOSFileDialog::selectedFilesChanged(QList<QUrl> selection) void QIOSFileDialog::selectedFilesChanged(const QList<QUrl> &selection)
{ {
m_selection = selection; m_selection = selection;
emit filesSelected(m_selection); emit filesSelected(m_selection);