1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include "lokclipboard.hxx"
11 #include <unordered_map>
12 #include <tools/lazydelete.hxx>
13 #include <vcl/svapp.hxx>
14 #include <sfx2/lokhelper.hxx>
15 #include <sal/log.hxx>
16 #include <cppuhelper/supportsservice.hxx>
17 #include <com/sun/star/uno/XComponentContext.hpp>
20 using namespace css::uno
;
22 /* static */ osl::Mutex
LOKClipboardFactory::gMutex
;
23 static tools::DeleteOnDeinit
<std::unordered_map
<int, rtl::Reference
<LOKClipboard
>>>& getClipboards()
25 static tools::DeleteOnDeinit
<std::unordered_map
<int, rtl::Reference
<LOKClipboard
>>>
30 rtl::Reference
<LOKClipboard
> LOKClipboardFactory::getClipboardForCurView()
32 int nViewId
= SfxLokHelper::getView(); // currently active.
34 osl::MutexGuard
aGuard(gMutex
);
36 auto& gClipboards
= getClipboards();
37 auto it
= gClipboards
.get()->find(nViewId
);
38 if (it
!= gClipboards
.get()->end())
40 SAL_INFO("lok", "Got clip: " << it
->second
.get() << " from " << nViewId
);
43 rtl::Reference
<LOKClipboard
> xClip(new LOKClipboard());
44 (*gClipboards
.get())[nViewId
] = xClip
;
45 SAL_INFO("lok", "Created clip: " << xClip
.get() << " for viewId " << nViewId
);
49 void LOKClipboardFactory::releaseClipboardForView(int nViewId
)
51 osl::MutexGuard
aGuard(gMutex
);
53 auto& gClipboards
= getClipboards();
54 if (nViewId
< 0) // clear all
56 gClipboards
.get()->clear();
57 SAL_INFO("lok", "Released all clipboards on doc destroy\n");
59 else if (gClipboards
.get())
61 auto it
= gClipboards
.get()->find(nViewId
);
62 if (it
!= gClipboards
.get()->end())
64 SAL_INFO("lok", "Releasing clip: " << it
->second
.get() << " for destroyed " << nViewId
);
65 gClipboards
.get()->erase(it
);
70 uno::Reference
<uno::XInterface
>
71 SAL_CALL
LOKClipboardFactory::createInstanceWithArguments(const Sequence
<Any
>& /* rArgs */)
73 return { static_cast<cppu::OWeakObject
*>(getClipboardForCurView().get()) };
76 LOKClipboard::LOKClipboard()
77 : cppu::WeakComponentImplHelper
<css::datatransfer::clipboard::XSystemClipboard
,
78 css::lang::XServiceInfo
>(m_aMutex
)
80 // Encourage 'paste' menu items to always show up.
81 uno::Reference
<datatransfer::XTransferable
> xTransferable(new LOKTransferable());
82 setContents(xTransferable
, uno::Reference
<datatransfer::clipboard::XClipboardOwner
>());
85 Sequence
<OUString
> LOKClipboard::getSupportedServiceNames_static()
87 Sequence
<OUString
> aRet
{ u
"com.sun.star.datatransfer.clipboard.LokClipboard"_ustr
};
91 OUString
LOKClipboard::getImplementationName()
93 return u
"com.sun.star.datatransfer.LOKClipboard"_ustr
;
96 Sequence
<OUString
> LOKClipboard::getSupportedServiceNames()
98 return getSupportedServiceNames_static();
101 sal_Bool
LOKClipboard::supportsService(const OUString
& ServiceName
)
103 return cppu::supportsService(this, ServiceName
);
106 Reference
<css::datatransfer::XTransferable
> LOKClipboard::getContents() { return m_xTransferable
; }
108 void LOKClipboard::setContents(
109 const Reference
<css::datatransfer::XTransferable
>& xTrans
,
110 const Reference
<css::datatransfer::clipboard::XClipboardOwner
>& xClipboardOwner
)
112 osl::ClearableMutexGuard
aGuard(m_aMutex
);
113 Reference
<datatransfer::clipboard::XClipboardOwner
> xOldOwner(m_aOwner
);
114 Reference
<datatransfer::XTransferable
> xOldContents(m_xTransferable
);
115 m_xTransferable
= xTrans
;
116 m_aOwner
= xClipboardOwner
;
118 std::vector
<Reference
<datatransfer::clipboard::XClipboardListener
>> aListeners(m_aListeners
);
119 datatransfer::clipboard::ClipboardEvent aEv
;
120 aEv
.Contents
= m_xTransferable
;
121 SAL_INFO("lok", "Clip: " << this << " set contents to " << m_xTransferable
);
125 if (xOldOwner
.is() && xOldOwner
!= xClipboardOwner
)
126 xOldOwner
->lostOwnership(this, xOldContents
);
127 for (auto const& listener
: aListeners
)
129 listener
->changedContents(aEv
);
133 void LOKClipboard::addClipboardListener(
134 const Reference
<datatransfer::clipboard::XClipboardListener
>& listener
)
136 osl::ClearableMutexGuard
aGuard(m_aMutex
);
137 m_aListeners
.push_back(listener
);
140 void LOKClipboard::removeClipboardListener(
141 const Reference
<datatransfer::clipboard::XClipboardListener
>& listener
)
143 osl::ClearableMutexGuard
aGuard(m_aMutex
);
144 std::erase(m_aListeners
, listener
);
146 LOKTransferable::LOKTransferable(const OUString
& sMimeType
,
147 const css::uno::Sequence
<sal_Int8
>& aSequence
)
149 m_aContent
.reserve(1);
150 m_aFlavors
= css::uno::Sequence
<css::datatransfer::DataFlavor
>(1);
151 initFlavourFromMime(m_aFlavors
.getArray()[0], sMimeType
);
154 if (m_aFlavors
[0].DataType
== cppu::UnoType
<OUString
>::get())
156 auto pText
= reinterpret_cast<const char*>(aSequence
.getConstArray());
157 aContent
<<= OUString(pText
, aSequence
.getLength(), RTL_TEXTENCODING_UTF8
);
160 aContent
<<= aSequence
;
161 m_aContent
.push_back(aContent
);
164 /// Use to ensure we have some dummy content on the clipboard to allow a 1st 'paste'
165 LOKTransferable::LOKTransferable()
167 m_aContent
.reserve(1);
168 m_aFlavors
= css::uno::Sequence
<css::datatransfer::DataFlavor
>(1);
169 initFlavourFromMime(m_aFlavors
.getArray()[0], u
"text/plain"_ustr
);
171 aContent
<<= OUString();
172 m_aContent
.push_back(aContent
);
175 // cf. sot/source/base/exchange.cxx for these two exceptional types.
176 void LOKTransferable::initFlavourFromMime(css::datatransfer::DataFlavor
& rFlavor
,
179 if (aMimeType
.startsWith("text/plain"))
181 aMimeType
= "text/plain;charset=utf-16";
182 rFlavor
.DataType
= cppu::UnoType
<OUString
>::get();
184 else if (aMimeType
== "application/x-libreoffice-tsvc")
185 rFlavor
.DataType
= cppu::UnoType
<OUString
>::get();
187 rFlavor
.DataType
= cppu::UnoType
<uno::Sequence
<sal_Int8
>>::get();
188 rFlavor
.MimeType
= aMimeType
;
189 rFlavor
.HumanPresentableName
= aMimeType
;
192 LOKTransferable::LOKTransferable(const size_t nInCount
, const char** pInMimeTypes
,
193 const size_t* pInSizes
, const char** pInStreams
)
195 m_aContent
.reserve(nInCount
);
196 m_aFlavors
= css::uno::Sequence
<css::datatransfer::DataFlavor
>(nInCount
);
197 auto p_aFlavors
= m_aFlavors
.getArray();
198 for (size_t i
= 0; i
< nInCount
; ++i
)
200 initFlavourFromMime(p_aFlavors
[i
], OUString::fromUtf8(pInMimeTypes
[i
]));
203 if (m_aFlavors
[i
].DataType
== cppu::UnoType
<OUString
>::get())
204 aContent
<<= OUString(pInStreams
[i
], pInSizes
[i
], RTL_TEXTENCODING_UTF8
);
206 aContent
<<= css::uno::Sequence
<sal_Int8
>(
207 reinterpret_cast<const sal_Int8
*>(pInStreams
[i
]), pInSizes
[i
]);
208 m_aContent
.push_back(aContent
);
212 uno::Any SAL_CALL
LOKTransferable::getTransferData(const datatransfer::DataFlavor
& rFlavor
)
214 assert(m_aContent
.size() == static_cast<size_t>(m_aFlavors
.getLength()));
215 for (size_t i
= 0; i
< m_aContent
.size(); ++i
)
217 if (m_aFlavors
[i
].MimeType
== rFlavor
.MimeType
)
219 if (m_aFlavors
[i
].DataType
!= rFlavor
.DataType
)
220 SAL_WARN("lok", "Horror type mismatch!");
221 return m_aContent
[i
];
227 uno::Sequence
<datatransfer::DataFlavor
> SAL_CALL
LOKTransferable::getTransferDataFlavors()
232 sal_Bool SAL_CALL
LOKTransferable::isDataFlavorSupported(const datatransfer::DataFlavor
& rFlavor
)
234 return std::find_if(std::cbegin(m_aFlavors
), std::cend(m_aFlavors
),
235 [&rFlavor
](const datatransfer::DataFlavor
& i
) {
236 return i
.MimeType
== rFlavor
.MimeType
&& i
.DataType
== rFlavor
.DataType
;
238 != std::cend(m_aFlavors
);
241 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
242 desktop_LOKClipboard_get_implementation(css::uno::XComponentContext
*,
243 css::uno::Sequence
<css::uno::Any
> const& /*args*/)
245 SolarMutexGuard aGuard
;
247 cppu::OWeakObject
* pClipboard
= LOKClipboardFactory::getClipboardForCurView().get();
249 pClipboard
->acquire();
253 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */