From b1bdeba086327e165ac990b9a28aaa65a9d67134 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 12 Feb 2014 13:37:37 +0100 Subject: iOS: implement clipboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will implement support for copy/paste operations inside, and between, applications. Change-Id: I50031b89bdb07f106950dc90fb8b1accbd1191bb Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/ios.pro | 6 +- src/plugins/platforms/ios/qiosclipboard.h | 68 ++++++++ src/plugins/platforms/ios/qiosclipboard.mm | 238 +++++++++++++++++++++++++++ src/plugins/platforms/ios/qiosintegration.h | 2 + src/plugins/platforms/ios/qiosintegration.mm | 13 ++ 5 files changed, 325 insertions(+), 2 deletions(-) create mode 100644 src/plugins/platforms/ios/qiosclipboard.h create mode 100644 src/plugins/platforms/ios/qiosclipboard.mm diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro index 175cc3f8bd..b7e074b95a 100644 --- a/src/plugins/platforms/ios/ios.pro +++ b/src/plugins/platforms/ios/ios.pro @@ -21,7 +21,8 @@ OBJECTIVE_SOURCES = \ qiosinputcontext.mm \ qiostheme.mm \ qiosglobal.mm \ - qiosservices.mm + qiosservices.mm \ + qiosclipboard.mm HEADERS = \ qiosintegration.h \ @@ -37,7 +38,8 @@ HEADERS = \ qiostheme.h \ qiosglobal.h \ qiosservices.h \ - quiview.h + quiview.h \ + qiosclipboard.h OTHER_FILES = \ quiview_textinput.mm diff --git a/src/plugins/platforms/ios/qiosclipboard.h b/src/plugins/platforms/ios/qiosclipboard.h new file mode 100644 index 0000000000..da4226a40d --- /dev/null +++ b/src/plugins/platforms/ios/qiosclipboard.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QIOSCLIPBOARD_H +#define QIOSCLIPBOARD_H + +#import + +#include + +@class QUIClipboard; + +QT_BEGIN_NAMESPACE + +class QIOSClipboard : public QPlatformClipboard +{ +public: + QIOSClipboard(); + QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE; + void setMimeData(QMimeData *mimeData, QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE; + bool supportsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE; + bool ownsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE; + +private: + QUIClipboard *m_clipboard; +}; + +QT_END_NAMESPACE + +#endif // QIOSCLIPBOARD_H diff --git a/src/plugins/platforms/ios/qiosclipboard.mm b/src/plugins/platforms/ios/qiosclipboard.mm new file mode 100644 index 0000000000..0a7b34a216 --- /dev/null +++ b/src/plugins/platforms/ios/qiosclipboard.mm @@ -0,0 +1,238 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qiosclipboard.h" + +#include +#include +#include + +@interface UIPasteboard (QUIPasteboard) + + (UIPasteboard *)pasteboardWithQClipboardMode:(QClipboard::Mode)mode; +@end + +@implementation UIPasteboard (QUIPasteboard) ++ (UIPasteboard *)pasteboardWithQClipboardMode:(QClipboard::Mode)mode +{ + NSString *name = (mode == QClipboard::Clipboard) ? UIPasteboardNameGeneral : UIPasteboardNameFind; + return [UIPasteboard pasteboardWithName:name create:NO]; +} +@end + +// -------------------------------------------------------------------- + +@interface QUIClipboard : NSObject +{ +@public + QIOSClipboard *m_qiosClipboard; + NSInteger m_changeCountClipboard; + NSInteger m_changeCountFindBuffer; +} +@end + +@implementation QUIClipboard + +-(id)initWithQIOSClipboard:(QIOSClipboard *)qiosClipboard +{ + self = [super init]; + if (self) { + m_qiosClipboard = qiosClipboard; + m_changeCountClipboard = [UIPasteboard pasteboardWithQClipboardMode:QClipboard::Clipboard].changeCount; + m_changeCountFindBuffer = [UIPasteboard pasteboardWithQClipboardMode:QClipboard::FindBuffer].changeCount; + + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(updatePasteboardChanged:) + name:UIPasteboardChangedNotification object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(updatePasteboardChanged:) + name:UIPasteboardRemovedNotification object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(updatePasteboardChanged:) + name:UIApplicationDidBecomeActiveNotification + object:nil]; + } + return self; +} + +-(void)dealloc +{ + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:UIPasteboardChangedNotification object:nil]; + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:UIPasteboardRemovedNotification object:nil]; + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:UIApplicationDidBecomeActiveNotification + object:nil]; + [super dealloc]; +} + +- (void)updatePasteboardChanged:(NSNotification *)notification +{ + Q_UNUSED(notification); + NSInteger changeCountClipboard = [UIPasteboard pasteboardWithQClipboardMode:QClipboard::Clipboard].changeCount; + NSInteger changeCountFindBuffer = [UIPasteboard pasteboardWithQClipboardMode:QClipboard::FindBuffer].changeCount; + + if (m_changeCountClipboard != changeCountClipboard) { + m_changeCountClipboard = changeCountClipboard; + m_qiosClipboard->emitChanged(QClipboard::Clipboard); + } + + if (m_changeCountFindBuffer != changeCountFindBuffer) { + m_changeCountFindBuffer = changeCountFindBuffer; + m_qiosClipboard->emitChanged(QClipboard::FindBuffer); + } +} + +@end + +// -------------------------------------------------------------------- + +QT_BEGIN_NAMESPACE + +class QIOSMimeData : public QMimeData { +public: + QIOSMimeData(QClipboard::Mode mode) : QMimeData(), m_mode(mode) { } + ~QIOSMimeData() { } + + QStringList formats() const Q_DECL_OVERRIDE; + QVariant retrieveData(const QString &mimeType, QVariant::Type type) const Q_DECL_OVERRIDE; + +private: + const QClipboard::Mode m_mode; +}; + +QStringList QIOSMimeData::formats() const +{ + QStringList foundMimeTypes; + UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:m_mode]; + NSArray *pasteboardTypes = [pb pasteboardTypes]; + + for (NSUInteger i = 0; i < [pasteboardTypes count]; ++i) { + QString uti = QString::fromNSString([pasteboardTypes objectAtIndex:i]); + QString mimeType = QMacInternalPasteboardMime::flavorToMime(QMacInternalPasteboardMime::MIME_ALL, uti); + if (!mimeType.isEmpty() && !foundMimeTypes.contains(mimeType)) + foundMimeTypes << mimeType; + } + + return foundMimeTypes; +} + +QVariant QIOSMimeData::retrieveData(const QString &mimeType, QVariant::Type) const +{ + UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:m_mode]; + NSArray *pasteboardTypes = [pb pasteboardTypes]; + + foreach (QMacInternalPasteboardMime *converter, + QMacInternalPasteboardMime::all(QMacInternalPasteboardMime::MIME_ALL)) { + if (!converter->canConvert(mimeType, converter->flavorFor(mimeType))) + continue; + + for (NSUInteger i = 0; i < [pasteboardTypes count]; ++i) { + NSString *availableUtiNSString = [pasteboardTypes objectAtIndex:i]; + QString availableUti = QString::fromNSString(availableUtiNSString); + if (!converter->canConvert(mimeType, availableUti)) + continue; + + NSData *nsData = [pb dataForPasteboardType:availableUtiNSString]; + QList dataList; + dataList << QByteArray(reinterpret_cast([nsData bytes]), [nsData length]); + return converter->convertToMime(mimeType, dataList, availableUti); + } + } + + return QVariant(); +} + +// -------------------------------------------------------------------- + +QIOSClipboard::QIOSClipboard() + : m_clipboard([[QUIClipboard alloc] initWithQIOSClipboard:this]) +{ +} + +QMimeData *QIOSClipboard::mimeData(QClipboard::Mode mode) +{ + Q_ASSERT(supportsMode(mode)); + return new QIOSMimeData(mode); +} + +void QIOSClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode) +{ + Q_ASSERT(supportsMode(mode)); + + UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:mode]; + NSMutableDictionary *pbItem = [NSMutableDictionary dictionaryWithCapacity:mimeData->formats().size()]; + + foreach (const QString &mimeType, mimeData->formats()) { + foreach (QMacInternalPasteboardMime *converter, + QMacInternalPasteboardMime::all(QMacInternalPasteboardMime::MIME_ALL)) { + QString uti = converter->flavorFor(mimeType); + if (uti.isEmpty() || !converter->canConvert(mimeType, uti)) + continue; + + QByteArray byteArray = converter->convertFromMime(mimeType, mimeData->data(mimeType), uti).first(); + NSData *nsData = [NSData dataWithBytes:byteArray.constData() length:byteArray.size()]; + [pbItem setValue:nsData forKey:uti.toNSString()]; + break; + } + } + + pb.items = [NSArray arrayWithObject:pbItem]; +} + +bool QIOSClipboard::supportsMode(QClipboard::Mode mode) const +{ + return (mode == QClipboard::Clipboard || mode == QClipboard::FindBuffer); +} + +bool QIOSClipboard::ownsMode(QClipboard::Mode mode) const +{ + Q_UNUSED(mode); + return false; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h index c655d8d3bf..a28926ff99 100644 --- a/src/plugins/platforms/ios/qiosintegration.h +++ b/src/plugins/platforms/ios/qiosintegration.h @@ -66,6 +66,7 @@ public: QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; QPlatformFontDatabase *fontDatabase() const; + QPlatformClipboard *clipboard() const; QPlatformInputContext *inputContext() const; QPlatformServices *services() const Q_DECL_OVERRIDE; @@ -82,6 +83,7 @@ public: QTouchDevice *touchDevice(); private: QPlatformFontDatabase *m_fontDatabase; + QPlatformClipboard *m_clipboard; QPlatformInputContext *m_inputContext; QPlatformScreen *m_screen; QTouchDevice *m_touchDevice; diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index 660da6397f..7a40e349c9 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -46,11 +46,13 @@ #include "qiosbackingstore.h" #include "qiosscreen.h" #include "qioscontext.h" +#include "qiosclipboard.h" #include "qiosinputcontext.h" #include "qiostheme.h" #include "qiosservices.h" #include +#include #include #include @@ -59,6 +61,7 @@ QT_BEGIN_NAMESPACE QIOSIntegration::QIOSIntegration() : m_fontDatabase(new QCoreTextFontDatabase) + , m_clipboard(new QIOSClipboard) , m_inputContext(new QIOSInputContext) , m_screen(new QIOSScreen(QIOSScreen::MainScreen)) , m_platformServices(new QIOSServices) @@ -81,6 +84,7 @@ QIOSIntegration::QIOSIntegration() m_touchDevice->setType(QTouchDevice::TouchScreen); m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::NormalizedPosition); QWindowSystemInterface::registerTouchDevice(m_touchDevice); + QMacInternalPasteboardMime::initializeMimeTypes(); } QIOSIntegration::~QIOSIntegration() @@ -88,6 +92,10 @@ QIOSIntegration::~QIOSIntegration() delete m_fontDatabase; m_fontDatabase = 0; + delete m_clipboard; + m_clipboard = 0; + QMacInternalPasteboardMime::destroyMimeTypes(); + delete m_inputContext; m_inputContext = 0; @@ -149,6 +157,11 @@ QPlatformFontDatabase * QIOSIntegration::fontDatabase() const return m_fontDatabase; } +QPlatformClipboard *QIOSIntegration::clipboard() const +{ + return m_clipboard; +} + QPlatformInputContext *QIOSIntegration::inputContext() const { return m_inputContext; -- cgit v1.2.3