summaryrefslogtreecommitdiffstats
path: root/desktop/source/lib/lokclipboard.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--desktop/source/lib/lokclipboard.cxx230
1 files changed, 230 insertions, 0 deletions
diff --git a/desktop/source/lib/lokclipboard.cxx b/desktop/source/lib/lokclipboard.cxx
new file mode 100644
index 000000000..b4de36c56
--- /dev/null
+++ b/desktop/source/lib/lokclipboard.cxx
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "lokclipboard.hxx"
+#include <unordered_map>
+#include <vcl/lazydelete.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <sal/log.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace css;
+using namespace css::uno;
+
+/* static */ osl::Mutex LOKClipboardFactory::gMutex;
+static vcl::DeleteOnDeinit<std::unordered_map<int, rtl::Reference<LOKClipboard>>> gClipboards{};
+
+rtl::Reference<LOKClipboard> LOKClipboardFactory::getClipboardForCurView()
+{
+ int nViewId = SfxLokHelper::getView(); // currently active.
+
+ osl::MutexGuard aGuard(gMutex);
+
+ auto it = gClipboards.get()->find(nViewId);
+ if (it != gClipboards.get()->end())
+ {
+ SAL_INFO("lok", "Got clip: " << it->second.get() << " from " << nViewId);
+ return it->second;
+ }
+ rtl::Reference<LOKClipboard> xClip(new LOKClipboard());
+ (*gClipboards.get())[nViewId] = xClip;
+ SAL_INFO("lok", "Created clip: " << xClip.get() << " for viewId " << nViewId);
+ return xClip;
+}
+
+void LOKClipboardFactory::releaseClipboardForView(int nViewId)
+{
+ osl::MutexGuard aGuard(gMutex);
+
+ if (nViewId < 0) // clear all
+ {
+ gClipboards.get()->clear();
+ SAL_INFO("lok", "Released all clipboards on doc destroy\n");
+ }
+ else if (gClipboards.get())
+ {
+ auto it = gClipboards.get()->find(nViewId);
+ if (it != gClipboards.get()->end())
+ {
+ SAL_INFO("lok", "Releasing clip: " << it->second.get() << " for destroyed " << nViewId);
+ gClipboards.get()->erase(it);
+ }
+ }
+}
+
+uno::Reference<uno::XInterface>
+ SAL_CALL LOKClipboardFactory::createInstanceWithArguments(const Sequence<Any>& /* rArgs */)
+{
+ return { static_cast<cppu::OWeakObject*>(getClipboardForCurView().get()) };
+}
+
+LOKClipboard::LOKClipboard()
+ : cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard,
+ css::lang::XServiceInfo>(m_aMutex)
+{
+ // Encourage 'paste' menu items to always show up.
+ uno::Reference<datatransfer::XTransferable> xTransferable(new LOKTransferable());
+ setContents(xTransferable, uno::Reference<datatransfer::clipboard::XClipboardOwner>());
+}
+
+Sequence<OUString> LOKClipboard::getSupportedServiceNames_static()
+{
+ Sequence<OUString> aRet{ "com.sun.star.datatransfer.clipboard.SystemClipboard" };
+ return aRet;
+}
+
+OUString LOKClipboard::getImplementationName() { return "com.sun.star.datatransfer.LOKClipboard"; }
+
+Sequence<OUString> LOKClipboard::getSupportedServiceNames()
+{
+ return getSupportedServiceNames_static();
+}
+
+sal_Bool LOKClipboard::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Reference<css::datatransfer::XTransferable> LOKClipboard::getContents() { return m_xTransferable; }
+
+void LOKClipboard::setContents(
+ const Reference<css::datatransfer::XTransferable>& xTrans,
+ const Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner)
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+ Reference<datatransfer::clipboard::XClipboardOwner> xOldOwner(m_aOwner);
+ Reference<datatransfer::XTransferable> xOldContents(m_xTransferable);
+ m_xTransferable = xTrans;
+ m_aOwner = xClipboardOwner;
+
+ std::vector<Reference<datatransfer::clipboard::XClipboardListener>> aListeners(m_aListeners);
+ datatransfer::clipboard::ClipboardEvent aEv;
+ aEv.Contents = m_xTransferable;
+ SAL_INFO("lok", "Clip: " << this << " set contents to " << m_xTransferable);
+
+ aGuard.clear();
+
+ if (xOldOwner.is() && xOldOwner != xClipboardOwner)
+ xOldOwner->lostOwnership(this, xOldContents);
+ for (auto const& listener : aListeners)
+ {
+ listener->changedContents(aEv);
+ }
+}
+
+void LOKClipboard::addClipboardListener(
+ const Reference<datatransfer::clipboard::XClipboardListener>& listener)
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+ m_aListeners.push_back(listener);
+}
+
+void LOKClipboard::removeClipboardListener(
+ const Reference<datatransfer::clipboard::XClipboardListener>& listener)
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+ m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), listener),
+ m_aListeners.end());
+}
+LOKTransferable::LOKTransferable(const OUString& sMimeType,
+ const css::uno::Sequence<sal_Int8>& aSequence)
+{
+ m_aContent.reserve(1);
+ m_aFlavors = css::uno::Sequence<css::datatransfer::DataFlavor>(1);
+ initFlavourFromMime(m_aFlavors.getArray()[0], sMimeType);
+
+ uno::Any aContent;
+ if (m_aFlavors[0].DataType == cppu::UnoType<OUString>::get())
+ {
+ auto pText = reinterpret_cast<const char*>(aSequence.getConstArray());
+ aContent <<= OUString(pText, aSequence.getLength(), RTL_TEXTENCODING_UTF8);
+ }
+ else
+ aContent <<= aSequence;
+ m_aContent.push_back(aContent);
+}
+
+/// Use to ensure we have some dummy content on the clipboard to allow a 1st 'paste'
+LOKTransferable::LOKTransferable()
+{
+ m_aContent.reserve(1);
+ m_aFlavors = css::uno::Sequence<css::datatransfer::DataFlavor>(1);
+ initFlavourFromMime(m_aFlavors.getArray()[0], "text/plain");
+ uno::Any aContent;
+ aContent <<= OUString();
+ m_aContent.push_back(aContent);
+}
+
+// cf. sot/source/base/exchange.cxx for these two exceptional types.
+void LOKTransferable::initFlavourFromMime(css::datatransfer::DataFlavor& rFlavor,
+ OUString aMimeType)
+{
+ if (aMimeType.startsWith("text/plain"))
+ {
+ aMimeType = "text/plain;charset=utf-16";
+ rFlavor.DataType = cppu::UnoType<OUString>::get();
+ }
+ else if (aMimeType == "application/x-libreoffice-tsvc")
+ rFlavor.DataType = cppu::UnoType<OUString>::get();
+ else
+ rFlavor.DataType = cppu::UnoType<uno::Sequence<sal_Int8>>::get();
+ rFlavor.MimeType = aMimeType;
+ rFlavor.HumanPresentableName = aMimeType;
+}
+
+LOKTransferable::LOKTransferable(const size_t nInCount, const char** pInMimeTypes,
+ const size_t* pInSizes, const char** pInStreams)
+{
+ m_aContent.reserve(nInCount);
+ m_aFlavors = css::uno::Sequence<css::datatransfer::DataFlavor>(nInCount);
+ auto p_aFlavors = m_aFlavors.getArray();
+ for (size_t i = 0; i < nInCount; ++i)
+ {
+ initFlavourFromMime(p_aFlavors[i], OUString::fromUtf8(pInMimeTypes[i]));
+
+ uno::Any aContent;
+ if (m_aFlavors[i].DataType == cppu::UnoType<OUString>::get())
+ aContent <<= OUString(pInStreams[i], pInSizes[i], RTL_TEXTENCODING_UTF8);
+ else
+ aContent <<= css::uno::Sequence<sal_Int8>(
+ reinterpret_cast<const sal_Int8*>(pInStreams[i]), pInSizes[i]);
+ m_aContent.push_back(aContent);
+ }
+}
+
+uno::Any SAL_CALL LOKTransferable::getTransferData(const datatransfer::DataFlavor& rFlavor)
+{
+ assert(m_aContent.size() == static_cast<size_t>(m_aFlavors.getLength()));
+ for (size_t i = 0; i < m_aContent.size(); ++i)
+ {
+ if (m_aFlavors[i].MimeType == rFlavor.MimeType)
+ {
+ if (m_aFlavors[i].DataType != rFlavor.DataType)
+ SAL_WARN("lok", "Horror type mismatch!");
+ return m_aContent[i];
+ }
+ }
+ return {};
+}
+
+uno::Sequence<datatransfer::DataFlavor> SAL_CALL LOKTransferable::getTransferDataFlavors()
+{
+ return m_aFlavors;
+}
+
+sal_Bool SAL_CALL LOKTransferable::isDataFlavorSupported(const datatransfer::DataFlavor& rFlavor)
+{
+ return std::find_if(std::cbegin(m_aFlavors), std::cend(m_aFlavors),
+ [&rFlavor](const datatransfer::DataFlavor& i) {
+ return i.MimeType == rFlavor.MimeType && i.DataType == rFlavor.DataType;
+ })
+ != std::cend(m_aFlavors);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */