/* -*- 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 #include #include #include #include using namespace css; using namespace css::uno; /* static */ osl::Mutex LOKClipboardFactory::gMutex; static vcl::DeleteOnDeinit>> gClipboards{}; rtl::Reference 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 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 SAL_CALL LOKClipboardFactory::createInstanceWithArguments(const Sequence& /* rArgs */) { return { static_cast(getClipboardForCurView().get()) }; } LOKClipboard::LOKClipboard() : cppu::WeakComponentImplHelper(m_aMutex) { // Encourage 'paste' menu items to always show up. uno::Reference xTransferable(new LOKTransferable()); setContents(xTransferable, uno::Reference()); } Sequence LOKClipboard::getSupportedServiceNames_static() { Sequence aRet{ "com.sun.star.datatransfer.clipboard.SystemClipboard" }; return aRet; } OUString LOKClipboard::getImplementationName() { return "com.sun.star.datatransfer.LOKClipboard"; } Sequence LOKClipboard::getSupportedServiceNames() { return getSupportedServiceNames_static(); } sal_Bool LOKClipboard::supportsService(const OUString& ServiceName) { return cppu::supportsService(this, ServiceName); } Reference LOKClipboard::getContents() { return m_xTransferable; } void LOKClipboard::setContents( const Reference& xTrans, const Reference& xClipboardOwner) { osl::ClearableMutexGuard aGuard(m_aMutex); Reference xOldOwner(m_aOwner); Reference xOldContents(m_xTransferable); m_xTransferable = xTrans; m_aOwner = xClipboardOwner; std::vector> 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& listener) { osl::ClearableMutexGuard aGuard(m_aMutex); m_aListeners.push_back(listener); } void LOKClipboard::removeClipboardListener( const Reference& 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& aSequence) { m_aContent.reserve(1); m_aFlavors = css::uno::Sequence(1); initFlavourFromMime(m_aFlavors.getArray()[0], sMimeType); uno::Any aContent; if (m_aFlavors[0].DataType == cppu::UnoType::get()) { auto pText = reinterpret_cast(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(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::get(); } else if (aMimeType == "application/x-libreoffice-tsvc") rFlavor.DataType = cppu::UnoType::get(); else rFlavor.DataType = cppu::UnoType>::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(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::get()) aContent <<= OUString(pInStreams[i], pInSizes[i], RTL_TEXTENCODING_UTF8); else aContent <<= css::uno::Sequence( reinterpret_cast(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(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 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: */