summaryrefslogtreecommitdiff
path: root/vcl/inc/qt5
diff options
context:
space:
mode:
authorJan-Marek Glogowski <glogow@fbihome.de>2019-05-31 16:40:34 +0000
committerThorsten Behrens <Thorsten.Behrens@CIB.de>2019-06-13 23:18:58 +0200
commitbcca1cf28cbd6c961d59bd8b8a8e58184dfc3823 (patch)
treea0ea40c0ab19a32f4da2a7247631454006378692 /vcl/inc/qt5
parent1b39bae5debe3bf952449bd7d2910defcea92b9e (diff)
tdf#122239 Qt5 implement lazy clipboard handling
This changes the Qt5Clipboard to a lazy loading one, which will just deliver data on read requests. This fixes not only the PRIMARY selection problems with Writer, but will generally speed up C'n'P, inside LO, because the data has not to be copied or transferred via QMimeData. This is mainly done by implementing the "mirror" interface of the Qt5Transferable, the Qt5MimeData using the retrieveData override. To prevent clipboard loss on shutdown, this sets a deep copied QMimeData of the current XTransferable, to make it persistent. This code explicitly doesn't use any of the QMimeData convenience functions and relies completely on LO's string handling, so we won't mix in eventual Qt bugs; all bugs are ours... Change-Id: I43d92a95df8fcac88dc41b00021cea0b5f040413 Reviewed-on: https://gerrit.libreoffice.org/73288 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
Diffstat (limited to 'vcl/inc/qt5')
-rw-r--r--vcl/inc/qt5/Qt5Clipboard.hxx56
-rw-r--r--vcl/inc/qt5/Qt5Transferable.hxx90
2 files changed, 104 insertions, 42 deletions
diff --git a/vcl/inc/qt5/Qt5Clipboard.hxx b/vcl/inc/qt5/Qt5Clipboard.hxx
index 2c2bb93f5016..93ad36a0e672 100644
--- a/vcl/inc/qt5/Qt5Clipboard.hxx
+++ b/vcl/inc/qt5/Qt5Clipboard.hxx
@@ -20,7 +20,14 @@
#include <QtGui/QClipboard>
-class Qt5Clipboard
+/**
+ * This implementation has two main functions, which handle the clipboard content:
+ * the XClipboard::setContent function and the QClipboard::change signal handler.
+ *
+ * The first just sets the respective clipboard to the expected content from LO,
+ * the latter will handle any reported changes.
+ **/
+class Qt5Clipboard final
: public QObject,
public cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard,
css::datatransfer::clipboard::XFlushableClipboard,
@@ -29,61 +36,50 @@ class Qt5Clipboard
Q_OBJECT
osl::Mutex m_aMutex;
+ const OUString m_aClipboardName;
+ const QClipboard::Mode m_aClipboardMode;
+
+ // if not empty, this holds the setContents provided XTransferable or a Qt5ClipboardTransferable
css::uno::Reference<css::datatransfer::XTransferable> m_aContents;
+ // the owner of the current contents, which must be informed on content change
css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> m_aOwner;
std::vector<css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>> m_aListeners;
- OUString m_aClipboardName;
- QClipboard::Mode m_aClipboardMode;
- // custom MIME type to detect whether clipboard content was added by self or externally
- const QString m_sMimeTypeUuid = "application/x-libreoffice-clipboard-uuid";
- const QByteArray m_aUuid;
+
+ static bool isOwner(const QClipboard::Mode aMode);
+ static bool isSupported(const QClipboard::Mode aMode);
+
+ explicit Qt5Clipboard(const OUString& aModeString, const QClipboard::Mode aMode);
private Q_SLOTS:
- void handleClipboardChange(QClipboard::Mode mode);
+ void handleChanged(QClipboard::Mode mode);
public:
- explicit Qt5Clipboard(const OUString& aModeString);
- virtual ~Qt5Clipboard() override;
-
- /*
- * XServiceInfo
- */
+ // factory function to construct only valid Qt5Clipboard objects by name
+ static css::uno::Reference<css::uno::XInterface> create(const OUString& aModeString);
+ // XServiceInfo
virtual OUString SAL_CALL getImplementationName() override;
virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
- /*
- * XClipboard
- */
-
+ // XClipboard
virtual css::uno::Reference<css::datatransfer::XTransferable> SAL_CALL getContents() override;
-
virtual void SAL_CALL setContents(
const css::uno::Reference<css::datatransfer::XTransferable>& xTrans,
const css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner)
override;
-
virtual OUString SAL_CALL getName() override;
- /*
- * XClipboardEx
- */
-
+ // XClipboardEx
virtual sal_Int8 SAL_CALL getRenderingCapabilities() override;
- /*
- * XFlushableClipboard
- */
+ // XFlushableClipboard
virtual void SAL_CALL flushClipboard() override;
- /*
- * XClipboardNotifier
- */
+ // XClipboardNotifier
virtual void SAL_CALL addClipboardListener(
const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener)
override;
-
virtual void SAL_CALL removeClipboardListener(
const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener)
override;
diff --git a/vcl/inc/qt5/Qt5Transferable.hxx b/vcl/inc/qt5/Qt5Transferable.hxx
index edc14904f769..f36216eed121 100644
--- a/vcl/inc/qt5/Qt5Transferable.hxx
+++ b/vcl/inc/qt5/Qt5Transferable.hxx
@@ -13,44 +13,110 @@
#include <cppuhelper/compbase.hxx>
#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <QtCore/QMimeData>
+#include <QtCore/QStringList>
#include <QtGui/QClipboard>
/**
- * Abstract XTransferable used for clipboard and D'n'D transfers
+ * Qt5Transferable classes are used to read QMimeData via the XTransferable
+ * interface. All the functionality is already implemented in the Qt5Transferable.
+ *
+ * The specialisations map to the two users, which provide QMimeData: the Clipboard
+ * and the Drag'n'Drop functionality.
+ *
+ * LO itself seem to just accept "text/plain;charset=utf-16", so it relies on the
+ * backend to convert to this charset, but still offers "text/plain" itself.
+ *
+ * It's the "mirror" interface of the Qt5MimeData, which is defined below.
**/
class Qt5Transferable : public cppu::WeakImplHelper<css::datatransfer::XTransferable>
{
- Qt5Transferable() = delete;
Qt5Transferable(const Qt5Transferable&) = delete;
-protected:
const QMimeData* m_pMimeData;
-
- Qt5Transferable(const QMimeData* pMimeData);
- std::vector<css::datatransfer::DataFlavor> getTransferDataFlavorsAsVector();
+ osl::Mutex m_aMutex;
+ bool m_bConvertFromLocale;
+ css::uno::Sequence<css::datatransfer::DataFlavor> m_aMimeTypeSeq;
public:
- ~Qt5Transferable() override;
+ Qt5Transferable(const QMimeData* pMimeData);
+ const QMimeData* mimeData() const { return m_pMimeData; }
css::uno::Sequence<css::datatransfer::DataFlavor> SAL_CALL getTransferDataFlavors() override;
sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) override;
+ css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override;
};
+/**
+ * The QClipboard's QMimeData is volatile. As written in the QClipboard::mimeData
+ * documentation, "the pointer returned might become invalidated when the contents
+ * of the clipboard changes". Therefore it can just be accessed reliably inside
+ * the QClipboard's object thread, which is the QApplication's thread, so all of
+ * the access has to go through RunInMainThread().
+ *
+ * If we detect a QMimeData change, we simply drop reporting any content. In theory
+ * we can recover in the case where there hadn't been any calls of the XTransferable
+ * interface, but currently we don't. But we ensure to never report mixed content,
+ * so we'll just cease operation on QMimeData change.
+ **/
class Qt5ClipboardTransferable final : public Qt5Transferable
{
+ // to detect in-flight QMimeData changes
+ const QClipboard::Mode m_aMode;
+
+ bool hasInFlightChanged() const;
+
public:
- explicit Qt5ClipboardTransferable(QClipboard::Mode aMode);
- ~Qt5ClipboardTransferable() override;
+ explicit Qt5ClipboardTransferable(const QClipboard::Mode aMode, const QMimeData* pMimeData);
+ // these are the same then Qt5Transferable, except they go through RunInMainThread
+ css::uno::Sequence<css::datatransfer::DataFlavor> SAL_CALL getTransferDataFlavors() override;
+ sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) override;
css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override;
};
-class Qt5DnDTransferable final : public Qt5Transferable
+/**
+ * Convenience typedef for better code readability
+ *
+ * This just uses the QMimeData provided by the QWidgets D'n'D events.
+ **/
+typedef Qt5Transferable Qt5DnDTransferable;
+
+/**
+ * A lazy loading QMimeData for XTransferable reads
+ *
+ * This is an interface class to make a XTransferable read accessible as a
+ * QMimeData. The mime data is just stored inside the XTransferable, never
+ * in the QMimeData itself! It's objects are just used for QClipboard to read
+ * the XTransferable data.
+ *
+ * Like XTransferable itself, this class should be considered an immutable
+ * container for mime data. There is no need to ever set any of its data.
+ *
+ * LO will offer at least UTF-16, if there is a viable text representation.
+ * If LO misses to offer an UTF-8 or a locale encoded string, these objects
+ * will offer them themselves and convert from UTF-16 on demand.
+ *
+ * It's the "mirror" interface of the Qt5Transferable.
+ **/
+class Qt5MimeData final : public QMimeData
{
+ friend class Qt5ClipboardTransferable;
+
+ const css::uno::Reference<css::datatransfer::XTransferable> m_aContents;
+ mutable bool m_bHaveNoCharset; // = uses the locale charset
+ mutable bool m_bHaveUTF8;
+ mutable QStringList m_aMimeTypeList;
+
+ QVariant retrieveData(const QString& mimeType, QVariant::Type type) const override;
+
public:
- Qt5DnDTransferable(const QMimeData* pMimeData);
+ explicit Qt5MimeData(const css::uno::Reference<css::datatransfer::XTransferable>& aContents);
- css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override;
+ bool hasFormat(const QString& mimeType) const override;
+ QStringList formats() const override;
+
+ bool deepCopy(QMimeData** const) const;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */