LibreOffice Module sd (master) 1
Annotation.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 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
22#include <Annotation.hxx>
23#include <drawdoc.hxx>
24
25#include <com/sun/star/drawing/XDrawPage.hpp>
26
28#include <comphelper/lok.hxx>
29
30#include <unotools/datetime.hxx>
31
32#include <sfx2/viewsh.hxx>
33#include <svx/svdundo.hxx>
34
35#include <LibreOfficeKit/LibreOfficeKitEnums.h>
36
38
39#include <tools/json_writer.hxx>
40
41using namespace css;
42
43namespace com::sun::star::uno { class XComponentContext; }
44
45namespace sd {
46
47namespace {
48
49class UndoInsertOrRemoveAnnotation : public SdrUndoAction
50{
51public:
52 UndoInsertOrRemoveAnnotation( Annotation& rAnnotation, bool bInsert );
53
54 virtual void Undo() override;
55 virtual void Redo() override;
56
57protected:
59 bool mbInsert;
60 int mnIndex;
61};
62
63struct AnnotationData
64{
65 geometry::RealPoint2D m_Position;
66 geometry::RealSize2D m_Size;
67 OUString m_Author;
68 OUString m_Initials;
69 util::DateTime m_DateTime;
70 OUString m_Text;
71
72 void get( const rtl::Reference< Annotation >& xAnnotation )
73 {
74 m_Position = xAnnotation->getPosition();
75 m_Size = xAnnotation->getSize();
76 m_Author = xAnnotation->getAuthor();
77 m_Initials = xAnnotation->getInitials();
78 m_DateTime = xAnnotation->getDateTime();
79 uno::Reference<text::XText> xText(xAnnotation->getTextRange());
80 m_Text = xText->getString();
81 }
82
83 void set( const rtl::Reference< Annotation >& xAnnotation )
84 {
85 xAnnotation->setPosition(m_Position);
86 xAnnotation->setSize(m_Size);
87 xAnnotation->setAuthor(m_Author);
88 xAnnotation->setInitials(m_Initials);
89 xAnnotation->setDateTime(m_DateTime);
90 uno::Reference<text::XText> xText(xAnnotation->getTextRange());
91 xText->setString(m_Text);
92 }
93};
94
95class UndoAnnotation : public SdrUndoAction
96{
97public:
98 explicit UndoAnnotation( Annotation& rAnnotation );
99
100 virtual void Undo() override;
101 virtual void Redo() override;
102
103protected:
104 rtl::Reference< Annotation > mxAnnotation;
105 AnnotationData maUndoData;
106 AnnotationData maRedoData;
107};
108
109}
110
111void createAnnotation(uno::Reference<office::XAnnotation>& xAnnotation, SdPage* pPage )
112{
113 xAnnotation.set(
115 pPage->addAnnotation(xAnnotation, -1);
116}
117
118sal_uInt32 Annotation::m_nLastId = 1;
119
120Annotation::Annotation(const uno::Reference<uno::XComponentContext>& context, SdPage* pPage)
121 : ::cppu::WeakComponentImplHelper<office::XAnnotation>(m_aMutex)
122 , ::cppu::PropertySetMixin<office::XAnnotation>(context, IMPLEMENTS_PROPERTY_SET,
123 uno::Sequence<OUString>())
124 , m_nId(m_nLastId++)
125 , mpPage(pPage)
126 , m_bIsFreeText(false)
127{
128}
129
130// override WeakComponentImplHelperBase::disposing()
131// This function is called upon disposing the component,
132// if your component needs special work when it becomes
133// disposed, do it here.
134void SAL_CALL Annotation::disposing()
135{
136 mpPage = nullptr;
137 if( m_TextRange.is() )
138 {
139 m_TextRange->dispose();
140 m_TextRange.clear();
141 }
142}
143
144uno::Any Annotation::queryInterface(css::uno::Type const & type)
145{
146 return ::cppu::WeakComponentImplHelper<office::XAnnotation>::queryInterface(type);
147}
148
149// com.sun.star.beans.XPropertySet:
150uno::Reference<beans::XPropertySetInfo> SAL_CALL Annotation::getPropertySetInfo()
151{
152 return ::cppu::PropertySetMixin<office::XAnnotation>::getPropertySetInfo();
153}
154
155void SAL_CALL Annotation::setPropertyValue(const OUString & aPropertyName, const uno::Any & aValue)
156{
158}
159
160uno::Any SAL_CALL Annotation::getPropertyValue(const OUString & aPropertyName)
161{
162 return ::cppu::PropertySetMixin<office::XAnnotation>::getPropertyValue(aPropertyName);
163}
164
165void SAL_CALL Annotation::addPropertyChangeListener(const OUString & aPropertyName, const uno::Reference<beans::XPropertyChangeListener> & xListener)
166{
168}
169
170void SAL_CALL Annotation::removePropertyChangeListener(const OUString & aPropertyName, const uno::Reference<beans::XPropertyChangeListener> & xListener)
171{
173}
174
175void SAL_CALL Annotation::addVetoableChangeListener(const OUString & aPropertyName, const uno::Reference<beans::XVetoableChangeListener> & xListener)
176{
178}
179
180void SAL_CALL Annotation::removeVetoableChangeListener(const OUString & aPropertyName, const uno::Reference<beans::XVetoableChangeListener> & xListener)
181{
183}
184
185uno::Any SAL_CALL Annotation::getAnchor()
186{
187 osl::MutexGuard g(m_aMutex);
188 uno::Any aRet;
189 if( mpPage )
190 {
191 uno::Reference<drawing::XDrawPage> xPage( mpPage->getUnoPage(), uno::UNO_QUERY );
192 aRet <<= xPage;
193 }
194 return aRet;
195}
196
197// css::office::XAnnotation:
198geometry::RealPoint2D SAL_CALL Annotation::getPosition()
199{
200 osl::MutexGuard g(m_aMutex);
201 return m_Position;
202}
203
204void SAL_CALL Annotation::setPosition(const geometry::RealPoint2D & the_value)
205{
206 prepareSet("Position", uno::Any(), uno::Any(), nullptr);
207 {
208 osl::MutexGuard g(m_aMutex);
209 createChangeUndo();
210 m_Position = the_value;
211 }
212}
213
214// css::office::XAnnotation:
215geometry::RealSize2D SAL_CALL Annotation::getSize()
216{
217 osl::MutexGuard g(m_aMutex);
218 return m_Size;
219}
220
221void SAL_CALL Annotation::setSize(const geometry::RealSize2D & the_value)
222{
223 prepareSet("Size", uno::Any(), uno::Any(), nullptr);
224 {
225 osl::MutexGuard g(m_aMutex);
226 createChangeUndo();
227 m_Size = the_value;
228 }
229}
230
231OUString SAL_CALL Annotation::getAuthor()
232{
233 osl::MutexGuard g(m_aMutex);
234 return m_Author;
235}
236
237void SAL_CALL Annotation::setAuthor(const OUString & the_value)
238{
239 prepareSet("Author", uno::Any(), uno::Any(), nullptr);
240 {
241 osl::MutexGuard g(m_aMutex);
242 createChangeUndo();
243 m_Author = the_value;
244 }
245}
246
247OUString SAL_CALL Annotation::getInitials()
248{
249 osl::MutexGuard g(m_aMutex);
250 return m_Initials;
251}
252
253void SAL_CALL Annotation::setInitials(const OUString & the_value)
254{
255 prepareSet("Initials", uno::Any(), uno::Any(), nullptr);
256 {
257 osl::MutexGuard g(m_aMutex);
258 createChangeUndo();
259 m_Initials = the_value;
260 }
261}
262
263util::DateTime SAL_CALL Annotation::getDateTime()
264{
265 osl::MutexGuard g(m_aMutex);
266 return m_DateTime;
267}
268
269void SAL_CALL Annotation::setDateTime(const util::DateTime & the_value)
270{
271 prepareSet("DateTime", uno::Any(), uno::Any(), nullptr);
272 {
273 osl::MutexGuard g(m_aMutex);
274 createChangeUndo();
275 m_DateTime = the_value;
276 }
277}
278
279void Annotation::createChangeUndo()
280{
281 SdrModel* pModel = GetModel(); // TTTT should use reference
282 if( pModel && pModel->IsUndoEnabled() )
283 pModel->AddUndo( std::make_unique<UndoAnnotation>( *this ) );
284
285 if( pModel )
286 {
287 pModel->SetChanged();
288 uno::Reference< XInterface > xSource( static_cast<uno::XWeak*>( this ) );
290 static_cast< SdDrawDocument& >( *pModel ),
291 "OnAnnotationChanged" ,
292 xSource );
293 }
294}
295
296uno::Reference<text::XText> SAL_CALL Annotation::getTextRange()
297{
298 osl::MutexGuard g(m_aMutex);
299 if( !m_TextRange.is() && (mpPage != nullptr) )
300 {
301 m_TextRange = TextApiObject::create( static_cast< SdDrawDocument* >( &mpPage->getSdrModelFromSdrPage() ) );
302 }
303 return m_TextRange;
304}
305
306std::unique_ptr<SdrUndoAction> CreateUndoInsertOrRemoveAnnotation( const uno::Reference<office::XAnnotation>& xAnnotation, bool bInsert )
307{
308 Annotation* pAnnotation = dynamic_cast< Annotation* >( xAnnotation.get() );
309 if( pAnnotation )
310 {
311 return std::make_unique< UndoInsertOrRemoveAnnotation >( *pAnnotation, bInsert );
312 }
313 else
314 {
315 return nullptr;
316 }
317}
318
319void CreateChangeUndo(const uno::Reference<office::XAnnotation>& xAnnotation)
320{
321 Annotation* pAnnotation = dynamic_cast<Annotation*>(xAnnotation.get());
322 if (pAnnotation)
323 pAnnotation->createChangeUndo();
324}
325
326sal_uInt32 getAnnotationId(const uno::Reference<office::XAnnotation>& xAnnotation)
327{
328 Annotation* pAnnotation = dynamic_cast<Annotation*>(xAnnotation.get());
329 sal_uInt32 nId = 0;
330 if (pAnnotation)
331 nId = pAnnotation->GetId();
332 return nId;
333}
334
335const SdPage* getAnnotationPage(const uno::Reference<office::XAnnotation>& xAnnotation)
336{
337 Annotation* pAnnotation = dynamic_cast<Annotation*>(xAnnotation.get());
338 if (pAnnotation)
339 return pAnnotation->GetPage();
340 return nullptr;
341}
342
343namespace
344{
345OString lcl_LOKGetCommentPayload(CommentNotificationType nType, uno::Reference<office::XAnnotation> const & rxAnnotation)
346{
347 ::tools::JsonWriter aJsonWriter;
348 {
349 auto aCommentNode = aJsonWriter.startNode("comment");
350
351 aJsonWriter.put("action", (nType == CommentNotificationType::Add ? "Add" :
352 (nType == CommentNotificationType::Remove ? "Remove" :
353 (nType == CommentNotificationType::Modify ? "Modify" : "???"))));
354 aJsonWriter.put("id", sd::getAnnotationId(rxAnnotation));
355
356 if (nType != CommentNotificationType::Remove && rxAnnotation.is())
357 {
358 aJsonWriter.put("id", sd::getAnnotationId(rxAnnotation));
359 aJsonWriter.put("author", rxAnnotation->getAuthor());
360 aJsonWriter.put("dateTime", utl::toISO8601(rxAnnotation->getDateTime()));
361 uno::Reference<text::XText> xText(rxAnnotation->getTextRange());
362 aJsonWriter.put("text", xText->getString());
363 const SdPage* pPage = sd::getAnnotationPage(rxAnnotation);
364 aJsonWriter.put("parthash", pPage ? OString::number(pPage->GetHashCode()) : OString());
365 geometry::RealPoint2D const & rPoint = rxAnnotation->getPosition();
366 geometry::RealSize2D const & rSize = rxAnnotation->getSize();
367 ::tools::Rectangle aRectangle(Point(rPoint.X * 100.0, rPoint.Y * 100.0), Size(rSize.Width * 100.0, rSize.Height * 100.0));
368 aRectangle = OutputDevice::LogicToLogic(aRectangle, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip));
369 OString sRectangle = aRectangle.toString();
370 aJsonWriter.put("rectangle", sRectangle.getStr());
371 }
372 }
373 return aJsonWriter.finishAndGetAsOString();
374}
375} // anonymous ns
376
377void LOKCommentNotify(CommentNotificationType nType, const SfxViewShell* pViewShell, uno::Reference<office::XAnnotation> const & rxAnnotation)
378{
379 // callbacks only if tiled annotations are explicitly turned off by LOK client
381 return ;
382
383 OString aPayload = lcl_LOKGetCommentPayload(nType, rxAnnotation);
384 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_COMMENT, aPayload);
385}
386
387void LOKCommentNotifyAll(CommentNotificationType nType, uno::Reference<office::XAnnotation> const & rxAnnotation)
388{
389 // callbacks only if tiled annotations are explicitly turned off by LOK client
391 return ;
392
393 OString aPayload = lcl_LOKGetCommentPayload(nType, rxAnnotation);
394
395 const SfxViewShell* pViewShell = SfxViewShell::GetFirst();
396 while (pViewShell)
397 {
398 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_COMMENT, aPayload);
399 pViewShell = SfxViewShell::GetNext(*pViewShell);
400 }
401}
402
403UndoInsertOrRemoveAnnotation::UndoInsertOrRemoveAnnotation( Annotation& rAnnotation, bool bInsert )
404: SdrUndoAction( *rAnnotation.GetModel() )
405, mxAnnotation( &rAnnotation )
406, mbInsert( bInsert )
407, mnIndex( 0 )
408{
409 SdPage* pPage = rAnnotation.GetPage();
410 if( pPage )
411 {
412 uno::Reference<office::XAnnotation> xAnnotation( &rAnnotation );
413
414 const AnnotationVector& rVec = pPage->getAnnotations();
415 auto iter = std::find(rVec.begin(), rVec.end(), xAnnotation);
416 mnIndex += std::distance(rVec.begin(), iter);
417 }
418}
419
420void UndoInsertOrRemoveAnnotation::Undo()
421{
422 SdPage* pPage = mxAnnotation->GetPage();
423 SdrModel* pModel = mxAnnotation->GetModel();
424 if( !(pPage && pModel) )
425 return;
426
427 uno::Reference<office::XAnnotation> xAnnotation( mxAnnotation );
428 if( mbInsert )
429 {
430 pPage->removeAnnotation( xAnnotation );
431 }
432 else
433 {
434 pPage->addAnnotation( xAnnotation, mnIndex );
435 LOKCommentNotifyAll( CommentNotificationType::Add, xAnnotation );
436 }
437}
438
439void UndoInsertOrRemoveAnnotation::Redo()
440{
441 SdPage* pPage = mxAnnotation->GetPage();
442 SdrModel* pModel = mxAnnotation->GetModel();
443 if( !(pPage && pModel) )
444 return;
445
446 uno::Reference<office::XAnnotation> xAnnotation( mxAnnotation );
447
448 if( mbInsert )
449 {
450 pPage->addAnnotation( xAnnotation, mnIndex );
451 LOKCommentNotifyAll( CommentNotificationType::Add, xAnnotation );
452 }
453 else
454 {
455 pPage->removeAnnotation( xAnnotation );
456 }
457}
458
459UndoAnnotation::UndoAnnotation( Annotation& rAnnotation )
460: SdrUndoAction( *rAnnotation.GetModel() )
461, mxAnnotation( &rAnnotation )
462{
463 maUndoData.get( mxAnnotation );
464}
465
466void UndoAnnotation::Undo()
467{
468 maRedoData.get( mxAnnotation );
469 maUndoData.set( mxAnnotation );
470 LOKCommentNotifyAll( CommentNotificationType::Modify, mxAnnotation );
471}
472
473void UndoAnnotation::Redo()
474{
475 maUndoData.get( mxAnnotation );
476 maRedoData.set( mxAnnotation );
477 LOKCommentNotifyAll( CommentNotificationType::Modify, mxAnnotation );
478}
479
480} // namespace sd
481
482/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
FPDF_PAGE mpPage
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
const sd::AnnotationVector & getAnnotations() const
Definition: sdpage.hxx:373
void removeAnnotation(const css::uno::Reference< css::office::XAnnotation > &xAnnotation)
Definition: sdpage2.cxx:591
void addAnnotation(const css::uno::Reference< css::office::XAnnotation > &xAnnotation, int nIndex)
Definition: sdpage2.cxx:565
sal_Int64 GetHashCode() const
Definition: sdpage.cxx:2698
virtual void SetChanged(bool bFlg=true)
void AddUndo(std::unique_ptr< SdrUndoAction > pUndo)
bool IsUndoEnabled() const
virtual void libreOfficeKitViewCallback(int nType, const OString &pPayload) const override
static SAL_WARN_UNUSED_RESULT SfxViewShell * GetNext(const SfxViewShell &rPrev, bool bOnlyVisible=true, const std::function< bool(const SfxViewShell *)> &isViewShell=nullptr)
static SAL_WARN_UNUSED_RESULT SfxViewShell * GetFirst(bool bOnlyVisible=true, const std::function< bool(const SfxViewShell *)> &isViewShell=nullptr)
virtual void SAL_CALL removeVetoableChangeListener(rtl::OUString const &propertyName, css::uno::Reference< css::beans::XVetoableChangeListener > const &listener) SAL_OVERRIDE
virtual void SAL_CALL addPropertyChangeListener(rtl::OUString const &propertyName, css::uno::Reference< css::beans::XPropertyChangeListener > const &listener) SAL_OVERRIDE
virtual void SAL_CALL addVetoableChangeListener(rtl::OUString const &propertyName, css::uno::Reference< css::beans::XVetoableChangeListener > const &listener) SAL_OVERRIDE
virtual void SAL_CALL setPropertyValue(rtl::OUString const &propertyName, css::uno::Any const &value) SAL_OVERRIDE
virtual void SAL_CALL removePropertyChangeListener(rtl::OUString const &propertyName, css::uno::Reference< css::beans::XPropertyChangeListener > const &listener) SAL_OVERRIDE
Annotation(const css::uno::Reference< css::uno::XComponentContext > &context, SdPage *pPage)
sal_uInt32 GetId() const
Definition: Annotation.hxx:89
SdPage * GetPage() const
Definition: Annotation.hxx:87
void createChangeUndo()
Definition: Annotation.cxx:279
static sal_uInt32 m_nLastId
Definition: Annotation.hxx:85
void put(std::u16string_view pPropName, const OUString &rPropValue)
OString finishAndGetAsOString()
ScopedJsonWriterNode startNode(std::string_view)
static OUString getInitials(const OUString &rName)
Definition: eppt.cxx:1027
std::mutex m_aMutex
void set(css::uno::UnoInterfaceReference const &value)
Reference< XComponentContext > getProcessComponentContext()
std::vector< css::uno::Reference< css::office::XAnnotation > > AnnotationVector
Definition: sdpage.hxx:82
sal_uInt32 getAnnotationId(const uno::Reference< office::XAnnotation > &xAnnotation)
Definition: Annotation.cxx:326
void createAnnotation(uno::Reference< office::XAnnotation > &xAnnotation, SdPage *pPage)
Definition: Annotation.cxx:111
void LOKCommentNotifyAll(CommentNotificationType nType, uno::Reference< office::XAnnotation > const &rxAnnotation)
Definition: Annotation.cxx:387
const SdPage * getAnnotationPage(const uno::Reference< office::XAnnotation > &xAnnotation)
Definition: Annotation.cxx:335
void CreateChangeUndo(const uno::Reference< office::XAnnotation > &xAnnotation)
Definition: Annotation.cxx:319
std::unique_ptr< SdrUndoAction > CreateUndoInsertOrRemoveAnnotation(const uno::Reference< office::XAnnotation > &xAnnotation, bool bInsert)
Definition: Annotation.cxx:306
void LOKCommentNotify(CommentNotificationType nType, const SfxViewShell *pViewShell, uno::Reference< office::XAnnotation > const &rxAnnotation)
Definition: Annotation.cxx:377
CommentNotificationType
Definition: Annotation.hxx:50
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
OUString toISO8601(const css::util::DateTime &rDateTime)
sal_Int16 nId
QPRO_FUNC_TYPE nType
sal_uInt32 mnIndex
ResultType type
void NotifyDocumentEvent(SdDrawDocument const &rDocument, const OUString &rEventName)
Definition: unomodel.cxx:3754