LibreOffice Module desktop (master)  1
lokclipboard.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  */
9 
10 #include "lokclipboard.hxx"
11 #include <unordered_map>
12 #include <vcl/lazydelete.hxx>
13 #include <sfx2/lokhelper.hxx>
14 #include <sal/log.hxx>
16 
17 using namespace css;
18 using namespace css::uno;
19 
20 /* static */ osl::Mutex LOKClipboardFactory::gMutex;
22 
24 {
25  int nViewId = SfxLokHelper::getView(); // currently active.
26 
27  osl::MutexGuard aGuard(gMutex);
28 
29  auto it = gClipboards.get()->find(nViewId);
30  if (it != gClipboards.get()->end())
31  {
32  SAL_INFO("lok", "Got clip: " << it->second.get() << " from " << nViewId);
33  return it->second;
34  }
36  (*gClipboards.get())[nViewId] = xClip;
37  SAL_INFO("lok", "Created clip: " << xClip.get() << " for viewId " << nViewId);
38  return xClip;
39 }
40 
42 {
43  osl::MutexGuard aGuard(gMutex);
44 
45  if (nViewId < 0) // clear all
46  {
47  gClipboards.get()->clear();
48  SAL_INFO("lok", "Released all clipboards on doc destroy\n");
49  }
50  else if (gClipboards.get())
51  {
52  auto it = gClipboards.get()->find(nViewId);
53  if (it != gClipboards.get()->end())
54  {
55  SAL_INFO("lok", "Releasing clip: " << it->second.get() << " for destroyed " << nViewId);
56  gClipboards.get()->erase(it);
57  }
58  }
59 }
60 
61 uno::Reference<uno::XInterface>
62  SAL_CALL LOKClipboardFactory::createInstanceWithArguments(const Sequence<Any>& /* rArgs */)
63 {
64  return { static_cast<cppu::OWeakObject*>(getClipboardForCurView().get()) };
65 }
66 
68  : cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard,
69  css::lang::XServiceInfo>(m_aMutex)
70 {
71  // Encourage 'paste' menu items to always show up.
72  uno::Reference<datatransfer::XTransferable> xTransferable(new LOKTransferable());
73  setContents(xTransferable, uno::Reference<datatransfer::clipboard::XClipboardOwner>());
74 }
75 
77 {
78  Sequence<OUString> aRet{ "com.sun.star.datatransfer.clipboard.SystemClipboard" };
79  return aRet;
80 }
81 
82 OUString LOKClipboard::getImplementationName() { return "com.sun.star.datatransfer.LOKClipboard"; }
83 
85 {
87 }
88 
89 sal_Bool LOKClipboard::supportsService(const OUString& ServiceName)
90 {
91  return cppu::supportsService(this, ServiceName);
92 }
93 
94 Reference<css::datatransfer::XTransferable> LOKClipboard::getContents() { return m_xTransferable; }
95 
97  const Reference<css::datatransfer::XTransferable>& xTrans,
98  const Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner)
99 {
100  osl::ClearableMutexGuard aGuard(m_aMutex);
101  Reference<datatransfer::clipboard::XClipboardOwner> xOldOwner(m_aOwner);
102  Reference<datatransfer::XTransferable> xOldContents(m_xTransferable);
103  m_xTransferable = xTrans;
104  m_aOwner = xClipboardOwner;
105 
106  std::vector<Reference<datatransfer::clipboard::XClipboardListener>> aListeners(m_aListeners);
107  datatransfer::clipboard::ClipboardEvent aEv;
108  aEv.Contents = m_xTransferable;
109  SAL_INFO("lok", "Clip: " << this << " set contents to " << m_xTransferable);
110 
111  aGuard.clear();
112 
113  if (xOldOwner.is() && xOldOwner != xClipboardOwner)
114  xOldOwner->lostOwnership(this, xOldContents);
115  for (auto const& listener : aListeners)
116  {
117  listener->changedContents(aEv);
118  }
119 }
120 
122  const Reference<datatransfer::clipboard::XClipboardListener>& listener)
123 {
124  osl::ClearableMutexGuard aGuard(m_aMutex);
125  m_aListeners.push_back(listener);
126 }
127 
129  const Reference<datatransfer::clipboard::XClipboardListener>& listener)
130 {
131  osl::ClearableMutexGuard aGuard(m_aMutex);
132  m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), listener),
133  m_aListeners.end());
134 }
135 LOKTransferable::LOKTransferable(const OUString& sMimeType,
136  const css::uno::Sequence<sal_Int8>& aSequence)
137 {
138  m_aContent.reserve(1);
139  m_aFlavors = css::uno::Sequence<css::datatransfer::DataFlavor>(1);
140  initFlavourFromMime(m_aFlavors[0], sMimeType);
141 
142  uno::Any aContent;
144  {
145  auto pText = reinterpret_cast<const char*>(aSequence.getConstArray());
146  aContent <<= OUString(pText, aSequence.getLength(), RTL_TEXTENCODING_UTF8);
147  }
148  else
149  aContent <<= aSequence;
150  m_aContent.push_back(aContent);
151 }
152 
155 {
156  m_aContent.reserve(1);
157  m_aFlavors = css::uno::Sequence<css::datatransfer::DataFlavor>(1);
158  initFlavourFromMime(m_aFlavors[0], "text/plain");
159  uno::Any aContent;
160  aContent <<= OUString();
161  m_aContent.push_back(aContent);
162 }
163 
164 // cf. sot/source/base/exchange.cxx for these two exceptional types.
165 void LOKTransferable::initFlavourFromMime(css::datatransfer::DataFlavor& rFlavor,
166  OUString aMimeType)
167 {
168  if (aMimeType.startsWith("text/plain"))
169  {
170  aMimeType = "text/plain;charset=utf-16";
171  rFlavor.DataType = cppu::UnoType<OUString>::get();
172  }
173  else if (aMimeType == "application/x-libreoffice-tsvc")
174  rFlavor.DataType = cppu::UnoType<OUString>::get();
175  else
176  rFlavor.DataType = cppu::UnoType<uno::Sequence<sal_Int8>>::get();
177  rFlavor.MimeType = aMimeType;
178  rFlavor.HumanPresentableName = aMimeType;
179 }
180 
181 LOKTransferable::LOKTransferable(const size_t nInCount, const char** pInMimeTypes,
182  const size_t* pInSizes, const char** pInStreams)
183 {
184  m_aContent.reserve(nInCount);
185  m_aFlavors = css::uno::Sequence<css::datatransfer::DataFlavor>(nInCount);
186  for (size_t i = 0; i < nInCount; ++i)
187  {
188  initFlavourFromMime(m_aFlavors[i], OUString::fromUtf8(pInMimeTypes[i]));
189 
190  uno::Any aContent;
192  aContent <<= OUString(pInStreams[i], pInSizes[i], RTL_TEXTENCODING_UTF8);
193  else
194  aContent <<= css::uno::Sequence<sal_Int8>(
195  reinterpret_cast<const sal_Int8*>(pInStreams[i]), pInSizes[i]);
196  m_aContent.push_back(aContent);
197  }
198 }
199 
200 uno::Any SAL_CALL LOKTransferable::getTransferData(const datatransfer::DataFlavor& rFlavor)
201 {
202  assert(m_aContent.size() == static_cast<size_t>(m_aFlavors.getLength()));
203  for (size_t i = 0; i < m_aContent.size(); ++i)
204  {
205  if (m_aFlavors[i].MimeType == rFlavor.MimeType)
206  {
207  if (m_aFlavors[i].DataType != rFlavor.DataType)
208  SAL_WARN("lok", "Horror type mismatch!");
209  return m_aContent[i];
210  }
211  }
212  return {};
213 }
214 
215 uno::Sequence<datatransfer::DataFlavor> SAL_CALL LOKTransferable::getTransferDataFlavors()
216 {
217  return m_aFlavors;
218 }
219 
220 sal_Bool SAL_CALL LOKTransferable::isDataFlavorSupported(const datatransfer::DataFlavor& rFlavor)
221 {
222  return std::find_if(m_aFlavors.begin(), m_aFlavors.end(),
223  [&rFlavor](const datatransfer::DataFlavor& i) {
224  return i.MimeType == rFlavor.MimeType && i.DataType == rFlavor.DataType;
225  })
226  != m_aFlavors.end();
227 }
228 
229 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::datatransfer::clipboard::XClipboardOwner > m_aOwner
static void initFlavourFromMime(css::datatransfer::DataFlavor &rFlavor, OUString aMimeType)
exports com.sun.star.datatransfer. clipboard
Sequence< OUString > SAL_CALL getSupportedServiceNames() override
signed char sal_Int8
void SAL_CALL setContents(const css::uno::Reference< css::datatransfer::XTransferable > &xTransferable, const css::uno::Reference< css::datatransfer::clipboard::XClipboardOwner > &xClipboardOwner) override
static rtl::Reference< LOKClipboard > getClipboardForCurView()
Fetch clipboard from the global pool.
void SAL_CALL removeClipboardListener(const css::uno::Reference< css::datatransfer::clipboard::XClipboardListener > &listener) override
LOKTransferable()
Use to ensure we have some dummy content on the clipboard to allow a 1st 'paste'. ...
css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor &rFlavor) override
DataType
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
std::mutex m_aMutex
sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor &rFlavor) override
css::uno::Sequence< css::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors() override
Listeners aListeners
static Sequence< OUString > getSupportedServiceNames_static()
exports com.sun.star. datatransfer
osl::Mutex m_aMutex
css::uno::Reference< css::datatransfer::XTransferable > SAL_CALL getContents() override
void SAL_CALL addClipboardListener(const css::uno::Reference< css::datatransfer::clipboard::XClipboardListener > &listener) override
int i
sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
static vcl::DeleteOnDeinit< std::unordered_map< int, rtl::Reference< LOKClipboard > > > gClipboards
unsigned char sal_Bool
css::uno::Type const & get()
css::uno::Sequence< css::datatransfer::DataFlavor > m_aFlavors
std::vector< css::uno::Reference< css::datatransfer::clipboard::XClipboardListener > > m_aListeners
A clipboard implementation for LibreOfficeKit.
#define SAL_INFO(area, stream)
static int getView(const SfxViewShell *pViewShell=nullptr)
css::uno::Reference< css::datatransfer::XTransferable > m_xTransferable
static void releaseClipboardForView(int nViewId)
Release a clipboard before its document dies, nViewId of -1 clears all.
#define SAL_WARN(area, stream)
std::vector< css::uno::Any > m_aContent
static osl::Mutex gMutex
OUString SAL_CALL getImplementationName() override
Represents the contents of LOKClipboard.
css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments(const css::uno::Sequence< css::uno::Any > &) override