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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/drawing/XDrawView.hpp>
21 #include <com/sun/star/geometry/RealPoint2D.hpp>
22 #include <com/sun/star/text/XText.hpp>
23 #include <com/sun/star/document/XEventBroadcaster.hpp>
24 #include <com/sun/star/office/XAnnotationAccess.hpp>
25 #include <comphelper/lok.hxx>
26 #include <svx/svxids.hrc>
28 #include <vcl/commandinfoprovider.hxx>
29 #include <vcl/settings.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/menu.hxx>
32 #include <vcl/weld.hxx>
34 #include <sal/macros.h>
35 #include <svl/itempool.hxx>
36 #include <unotools/localedatawrapper.hxx>
37 #include <unotools/useroptions.hxx>
38 #include <unotools/syslocale.hxx>
39 #include <unotools/saveopt.hxx>
41 #include <tools/datetime.hxx>
43 #include <sfx2/viewfrm.hxx>
44 #include <sfx2/bindings.hxx>
45 #include <sfx2/request.hxx>
46 #include <sfx2/dispatch.hxx>
48 #include <editeng/editeng.hxx>
49 #include <editeng/eeitem.hxx>
50 #include <editeng/fontitem.hxx>
51 #include <editeng/fhgtitem.hxx>
52 #include <editeng/outlobj.hxx>
53 #include <editeng/postitem.hxx>
54 #include <editeng/wghtitem.hxx>
55 #include <editeng/udlnitem.hxx>
56 #include <editeng/crossedoutitem.hxx>
58 #include <svx/postattr.hxx>
60 #include <annotationmanager.hxx>
61 #include "annotationmanagerimpl.hxx"
62 #include "annotationwindow.hxx"
63 #include <strings.hrc>
65 #include <Annotation.hxx>
66 #include <DrawDocShell.hxx>
67 #include <DrawViewShell.hxx>
68 #include <sdresid.hxx>
69 #include <EventMultiplexer.hxx>
70 #include <ViewShellBase.hxx>
72 #include <drawdoc.hxx>
73 #include <textapi.hxx>
74 #include <optsitem.hxx>
79 using namespace ::com::sun::star
;
80 using namespace ::com::sun::star::uno
;
81 using namespace ::com::sun::star::drawing
;
82 using namespace ::com::sun::star::document
;
83 using namespace ::com::sun::star::geometry
;
84 using namespace ::com::sun::star::container
;
85 using namespace ::com::sun::star::beans
;
86 using namespace ::com::sun::star::text
;
87 using namespace ::com::sun::star::view
;
88 using namespace ::com::sun::star::style
;
89 using namespace ::com::sun::star::frame
;
90 using namespace ::com::sun::star::lang
;
91 using namespace ::com::sun::star::ui
;
92 using namespace ::com::sun::star::task
;
93 using namespace ::com::sun::star::office
;
97 SfxItemPool
* GetAnnotationPool()
99 static SfxItemPool
* s_pAnnotationPool
= nullptr;
100 if( s_pAnnotationPool
== nullptr )
102 s_pAnnotationPool
= EditEngine::CreatePool();
103 s_pAnnotationPool
->SetPoolDefaultItem(SvxFontHeightItem(423,100,EE_CHAR_FONTHEIGHT
));
105 vcl::Font
aAppFont( Application::GetSettings().GetStyleSettings().GetAppFont() );
106 s_pAnnotationPool
->SetPoolDefaultItem(SvxFontItem(aAppFont
.GetFamilyType(),aAppFont
.GetFamilyName(),"",PITCH_DONTKNOW
,RTL_TEXTENCODING_DONTKNOW
,EE_CHAR_FONTINFO
));
109 return s_pAnnotationPool
;
112 static SfxBindings
* getBindings( ViewShellBase
const & rBase
)
114 if( rBase
.GetMainViewShell().get() && rBase
.GetMainViewShell()->GetViewFrame() )
115 return &rBase
.GetMainViewShell()->GetViewFrame()->GetBindings();
120 static SfxDispatcher
* getDispatcher( ViewShellBase
const & rBase
)
122 if( rBase
.GetMainViewShell().get() && rBase
.GetMainViewShell()->GetViewFrame() )
123 return rBase
.GetMainViewShell()->GetViewFrame()->GetDispatcher();
128 css::util::DateTime
getCurrentDateTime()
130 DateTime
aCurrentDate( DateTime::SYSTEM
);
131 return css::util::DateTime( 0, aCurrentDate
.GetSec(),
132 aCurrentDate
.GetMin(), aCurrentDate
.GetHour(),
133 aCurrentDate
.GetDay(), aCurrentDate
.GetMonth(),
134 aCurrentDate
.GetYear(), false );
137 OUString
getAnnotationDateTimeString( const Reference
< XAnnotation
>& xAnnotation
)
140 if( xAnnotation
.is() )
142 const SvtSysLocale aSysLocale
;
143 const LocaleDataWrapper
& rLocalData
= aSysLocale
.GetLocaleData();
145 css::util::DateTime
aDateTime( xAnnotation
->getDateTime() );
147 Date
aSysDate( Date::SYSTEM
);
148 Date
aDate( aDateTime
.Day
, aDateTime
.Month
, aDateTime
.Year
);
150 sRet
= SdResId(STR_ANNOTATION_TODAY
);
151 else if (aDate
== (aSysDate
-1))
152 sRet
= SdResId(STR_ANNOTATION_YESTERDAY
);
153 else if (aDate
.IsValidAndGregorian() )
154 sRet
= rLocalData
.getDate(aDate
);
156 ::tools::Time
aTime( aDateTime
);
157 if(aTime
.GetTime() != 0)
158 sRet
+= " " + rLocalData
.getTime( aTime
,false );
163 AnnotationManagerImpl::AnnotationManagerImpl( ViewShellBase
& rViewShellBase
)
164 : AnnotationManagerImplBase( m_aMutex
)
165 , mrBase( rViewShellBase
)
166 , mpDoc( rViewShellBase
.GetDocument() )
167 , mbShowAnnotations( true )
168 , mbPopupMenuActive( false )
169 , mnUpdateTagsEvent( nullptr )
171 SdOptions
* pOptions
= SD_MOD()->GetSdOptions(mpDoc
->GetDocumentType());
173 mbShowAnnotations
= pOptions
->IsShowComments();
176 void AnnotationManagerImpl::init()
178 // get current controller and initialize listeners
182 mxView
.set(mrBase
.GetController(), UNO_QUERY
);
186 OSL_FAIL( "sd::AnnotationManagerImpl::AnnotationManagerImpl(), Exception caught!" );
191 Reference
<XEventBroadcaster
> xModel (mrBase
.GetDocShell()->GetModel(), UNO_QUERY_THROW
);
192 Reference
<XEventListener
> xListener( this );
193 xModel
->addEventListener( xListener
);
200 // WeakComponentImplHelper
201 void SAL_CALL
AnnotationManagerImpl::disposing ()
205 Reference
<XEventBroadcaster
> xModel (mrBase
.GetDocShell()->GetModel(), UNO_QUERY_THROW
);
206 Reference
<XEventListener
> xListener( this );
207 xModel
->removeEventListener( xListener
);
216 if( mnUpdateTagsEvent
)
218 Application::RemoveUserEvent( mnUpdateTagsEvent
);
219 mnUpdateTagsEvent
= nullptr;
223 mxCurrentPage
.clear();
227 void SAL_CALL
AnnotationManagerImpl::notifyEvent( const css::document::EventObject
& aEvent
)
229 if( !(aEvent
.EventName
== "OnAnnotationInserted" || aEvent
.EventName
== "OnAnnotationRemoved" || aEvent
.EventName
== "OnAnnotationChanged") )
232 // AnnotationInsertion and modification is not handled here because when
233 // a new annotation is inserted, it consists of OnAnnotationInserted
234 // followed by a chain of OnAnnotationChanged (called for setting each
235 // of the annotation attributes - author, text etc.). This is not what a
236 // LOK client wants. So only handle removal here as annotation removal
237 // consists of only one event - 'OnAnnotationRemoved'
238 if ( aEvent
.EventName
== "OnAnnotationRemoved" )
240 Reference
< XAnnotation
> xAnnotation( aEvent
.Source
, uno::UNO_QUERY
);
241 if ( xAnnotation
.is() )
243 LOKCommentNotify(CommentNotificationType::Remove
, &mrBase
, xAnnotation
);
250 void SAL_CALL
AnnotationManagerImpl::disposing( const css::lang::EventObject
& /*Source*/ )
254 Reference
<XAnnotation
> AnnotationManagerImpl::GetAnnotationById(sal_uInt32 nAnnotationId
)
256 SdPage
* pPage
= nullptr;
259 pPage
= GetNextPage(pPage
, true);
260 if( pPage
&& !pPage
->getAnnotations().empty() )
262 AnnotationVector
aAnnotations(pPage
->getAnnotations());
263 auto iter
= std::find_if(aAnnotations
.begin(), aAnnotations
.end(),
264 [nAnnotationId
](const Reference
<XAnnotation
>& xAnnotation
) {
265 return sd::getAnnotationId(xAnnotation
) == nAnnotationId
;
267 if (iter
!= aAnnotations
.end())
272 Reference
<XAnnotation
> xAnnotationEmpty
;
273 return xAnnotationEmpty
;
276 void AnnotationManagerImpl::ShowAnnotations( bool bShow
)
278 // enforce show annotations if a new annotation is inserted
279 if( mbShowAnnotations
!= bShow
)
281 mbShowAnnotations
= bShow
;
283 SdOptions
* pOptions
= SD_MOD()->GetSdOptions(mpDoc
->GetDocumentType());
285 pOptions
->SetShowComments( mbShowAnnotations
);
291 void AnnotationManagerImpl::ExecuteAnnotation(SfxRequest
const & rReq
)
293 switch( rReq
.GetSlot() )
295 case SID_INSERT_POSTIT
:
296 ExecuteInsertAnnotation( rReq
);
298 case SID_DELETE_POSTIT
:
299 case SID_DELETEALL_POSTIT
:
300 case SID_DELETEALLBYAUTHOR_POSTIT
:
301 ExecuteDeleteAnnotation( rReq
);
303 case SID_EDIT_POSTIT
:
304 ExecuteEditAnnotation( rReq
);
306 case SID_PREVIOUS_POSTIT
:
307 case SID_NEXT_POSTIT
:
308 SelectNextAnnotation( rReq
.GetSlot() == SID_NEXT_POSTIT
);
310 case SID_REPLYTO_POSTIT
:
311 ExecuteReplyToAnnotation( rReq
);
313 case SID_TOGGLE_NOTES
:
314 ShowAnnotations( !mbShowAnnotations
);
319 void AnnotationManagerImpl::ExecuteInsertAnnotation(SfxRequest
const & rReq
)
321 if (!comphelper::LibreOfficeKit::isActive() || comphelper::LibreOfficeKit::isTiledAnnotations())
322 ShowAnnotations(true);
324 const SfxItemSet
* pArgs
= rReq
.GetArgs();
328 const SfxPoolItem
* pPoolItem
= nullptr;
329 if (SfxItemState::SET
== pArgs
->GetItemState(SID_ATTR_POSTIT_TEXT
, true, &pPoolItem
))
331 sText
= static_cast<const SfxStringItem
*>(pPoolItem
)->GetValue();
335 InsertAnnotation(sText
);
338 void AnnotationManagerImpl::ExecuteDeleteAnnotation(SfxRequest
const & rReq
)
340 ShowAnnotations( true );
342 const SfxItemSet
* pArgs
= rReq
.GetArgs();
344 switch( rReq
.GetSlot() )
346 case SID_DELETEALL_POSTIT
:
347 DeleteAllAnnotations();
349 case SID_DELETEALLBYAUTHOR_POSTIT
:
352 const SfxPoolItem
* pPoolItem
= nullptr;
353 if( SfxItemState::SET
== pArgs
->GetItemState( SID_DELETEALLBYAUTHOR_POSTIT
, true, &pPoolItem
) )
355 OUString
sAuthor( static_cast<const SfxStringItem
*>( pPoolItem
)->GetValue() );
356 DeleteAnnotationsByAuthor( sAuthor
);
360 case SID_DELETE_POSTIT
:
362 Reference
< XAnnotation
> xAnnotation
;
366 const SfxPoolItem
* pPoolItem
= nullptr;
367 if( SfxItemState::SET
== pArgs
->GetItemState( SID_DELETE_POSTIT
, true, &pPoolItem
) )
368 static_cast<const SfxUnoAnyItem
*>(pPoolItem
)->GetValue() >>= xAnnotation
;
369 if( SfxItemState::SET
== pArgs
->GetItemState( SID_ATTR_POSTIT_ID
, true, &pPoolItem
) )
370 nId
= static_cast<const SvxPostItIdItem
*>(pPoolItem
)->GetValue().toUInt32();
374 xAnnotation
= GetAnnotationById(nId
);
375 else if( !xAnnotation
.is() )
376 GetSelectedAnnotation( xAnnotation
);
378 DeleteAnnotation( xAnnotation
);
386 void AnnotationManagerImpl::ExecuteEditAnnotation(SfxRequest
const & rReq
)
388 const SfxItemSet
* pArgs
= rReq
.GetArgs();
389 Reference
< XAnnotation
> xAnnotation
;
395 if (mpDoc
->IsUndoEnabled())
396 mpDoc
->BegUndo(SdResId(STR_ANNOTATION_UNDO_EDIT
));
398 const SfxPoolItem
* pPoolItem
= nullptr;
399 if (SfxItemState::SET
== pArgs
->GetItemState(SID_ATTR_POSTIT_ID
, true, &pPoolItem
))
401 nId
= static_cast<const SvxPostItIdItem
*>(pPoolItem
)->GetValue().toUInt32();
402 xAnnotation
= GetAnnotationById(nId
);
404 if (SfxItemState::SET
== pArgs
->GetItemState(SID_ATTR_POSTIT_TEXT
, true, &pPoolItem
))
405 sText
= static_cast<const SfxStringItem
*>(pPoolItem
)->GetValue();
407 if (xAnnotation
.is() && !sText
.isEmpty())
409 CreateChangeUndo(xAnnotation
);
411 // TODO: Not allow other authors to change others' comments ?
412 Reference
<XText
> xText(xAnnotation
->getTextRange());
413 xText
->setString(sText
);
415 LOKCommentNotifyAll(CommentNotificationType::Modify
, xAnnotation
);
418 if (mpDoc
->IsUndoEnabled())
424 void AnnotationManagerImpl::InsertAnnotation(const OUString
& rText
)
426 SdPage
* pPage
= GetCurrentPage();
430 if( mpDoc
->IsUndoEnabled() )
431 mpDoc
->BegUndo( SdResId( STR_ANNOTATION_UNDO_INSERT
) );
433 // find free space for new annotation
436 AnnotationVector
aAnnotations( pPage
->getAnnotations() );
437 if( !aAnnotations
.empty() )
439 const int page_width
= pPage
->GetSize().Width();
440 const int width
= 1000;
441 const int height
= 800;
442 ::tools::Rectangle aTagRect
;
446 ::tools::Rectangle
aNewRect( x
, y
, x
+ width
- 1, y
+ height
- 1 );
449 for( const auto& rxAnnotation
: aAnnotations
)
451 RealPoint2D
aPoint( rxAnnotation
->getPosition() );
452 aTagRect
.SetLeft( sal::static_int_cast
< long >( aPoint
.X
* 100.0 ) );
453 aTagRect
.SetTop( sal::static_int_cast
< long >( aPoint
.Y
* 100.0 ) );
454 aTagRect
.SetRight( aTagRect
.Left() + width
- 1 );
455 aTagRect
.SetBottom( aTagRect
.Top() + height
- 1 );
457 if( aNewRect
.IsOver( aTagRect
) )
480 Reference
< XAnnotation
> xAnnotation
;
481 pPage
->createAnnotation( xAnnotation
);
484 if (comphelper::LibreOfficeKit::isActive())
485 sAuthor
= mrBase
.GetMainViewShell()->GetView()->GetAuthor();
488 SvtUserOptions aUserOptions
;
489 sAuthor
= aUserOptions
.GetFullName();
490 xAnnotation
->setInitials( aUserOptions
.GetID() );
493 if (!rText
.isEmpty())
495 Reference
<XText
> xText(xAnnotation
->getTextRange());
496 xText
->setString(rText
);
499 // set current author to new annotation
500 xAnnotation
->setAuthor( sAuthor
);
501 // set current time to new annotation
502 xAnnotation
->setDateTime( getCurrentDateTime() );
505 RealPoint2D
aPos( static_cast<double>(x
) / 100.0, static_cast<double>(y
) / 100.0 );
506 xAnnotation
->setPosition( aPos
);
508 if( mpDoc
->IsUndoEnabled() )
511 // Tell our LOK clients about new comment added
512 LOKCommentNotifyAll(CommentNotificationType::Add
, xAnnotation
);
515 SelectAnnotation( xAnnotation
, true );
518 void AnnotationManagerImpl::ExecuteReplyToAnnotation( SfxRequest
const & rReq
)
520 Reference
< XAnnotation
> xAnnotation
;
521 const SfxItemSet
* pArgs
= rReq
.GetArgs();
522 sal_uInt32 nReplyId
= 0; // Id of the comment to reply to
526 const SfxPoolItem
* pPoolItem
= nullptr;
527 if( SfxItemState::SET
== pArgs
->GetItemState( SID_ATTR_POSTIT_ID
, true, &pPoolItem
) )
529 nReplyId
= static_cast<const SvxPostItIdItem
*>(pPoolItem
)->GetValue().toUInt32();
530 xAnnotation
= GetAnnotationById(nReplyId
);
532 else if( SfxItemState::SET
== pArgs
->GetItemState( rReq
.GetSlot(), true, &pPoolItem
) )
533 static_cast<const SfxUnoAnyItem
*>( pPoolItem
)->GetValue() >>= xAnnotation
;
535 if( SfxItemState::SET
== pArgs
->GetItemState( SID_ATTR_POSTIT_TEXT
, true, &pPoolItem
) )
536 sReplyText
= static_cast<const SvxPostItTextItem
*>( pPoolItem
)->GetValue();
539 TextApiObject
* pTextApi
= getTextApiObject( xAnnotation
);
543 std::unique_ptr
< ::Outliner
> pOutliner( new ::Outliner(GetAnnotationPool(),OutlinerMode::TextObject
) );
545 SdDrawDocument::SetCalcFieldValueHdl( pOutliner
.get() );
546 pOutliner
->SetUpdateMode( true );
548 OUString
aStr(SdResId(STR_ANNOTATION_REPLY
));
549 OUString
sAuthor( xAnnotation
->getAuthor() );
550 if( sAuthor
.isEmpty() )
551 sAuthor
= SdResId( STR_ANNOTATION_NOAUTHOR
);
553 aStr
= aStr
.replaceFirst("%1", sAuthor
) +
554 " (" + getAnnotationDateTimeString( xAnnotation
) + "): \"";
556 OUString
sQuote( pTextApi
->GetText() );
558 if( sQuote
.isEmpty() )
560 aStr
+= sQuote
+ "\"\n";
562 for( sal_Int32 nIdx
= 0; nIdx
>= 0; )
563 pOutliner
->Insert( aStr
.getToken( 0, '\n', nIdx
), EE_PARA_APPEND
, -1 );
565 if( pOutliner
->GetParagraphCount() > 1 )
567 SfxItemSet
aAnswerSet( pOutliner
->GetEmptyItemSet() );
568 aAnswerSet
.Put(SvxPostureItem(ITALIC_NORMAL
,EE_CHAR_ITALIC
));
571 aSel
.nEndPara
= pOutliner
->GetParagraphCount()-2;
572 aSel
.nEndPos
= pOutliner
->GetText( pOutliner
->GetParagraph( aSel
.nEndPara
) ).getLength();
574 pOutliner
->QuickSetAttribs( aAnswerSet
, aSel
);
577 if (!sReplyText
.isEmpty())
578 pOutliner
->Insert(sReplyText
);
580 std::unique_ptr
< OutlinerParaObject
> pOPO( pOutliner
->CreateParaObject() );
581 pTextApi
->SetText(*pOPO
);
583 OUString sReplyAuthor
;
584 if (comphelper::LibreOfficeKit::isActive())
585 sReplyAuthor
= mrBase
.GetMainViewShell()->GetView()->GetAuthor();
588 SvtUserOptions aUserOptions
;
589 sReplyAuthor
= aUserOptions
.GetFullName();
590 xAnnotation
->setInitials( aUserOptions
.GetID() );
593 xAnnotation
->setAuthor( sReplyAuthor
);
594 // set current time to reply
595 xAnnotation
->setDateTime( getCurrentDateTime() );
597 // Tell our LOK clients about this (comment modification)
598 LOKCommentNotifyAll(CommentNotificationType::Modify
, xAnnotation
);
601 SelectAnnotation( xAnnotation
, true );
604 void AnnotationManagerImpl::DeleteAnnotation( const Reference
< XAnnotation
>& xAnnotation
)
606 SdPage
* pPage
= GetCurrentPage();
608 if( xAnnotation
.is() && pPage
)
610 if( mpDoc
->IsUndoEnabled() )
611 mpDoc
->BegUndo( SdResId( STR_ANNOTATION_UNDO_DELETE
) );
613 pPage
->removeAnnotation( xAnnotation
);
615 if( mpDoc
->IsUndoEnabled() )
622 void AnnotationManagerImpl::DeleteAnnotationsByAuthor( const OUString
& sAuthor
)
624 if( mpDoc
->IsUndoEnabled() )
625 mpDoc
->BegUndo( SdResId( STR_ANNOTATION_UNDO_DELETE
) );
627 SdPage
* pPage
= nullptr;
630 pPage
= GetNextPage( pPage
, true );
632 if( pPage
&& !pPage
->getAnnotations().empty() )
634 AnnotationVector
aAnnotations( pPage
->getAnnotations() );
635 for( Reference
< XAnnotation
>& xAnnotation
: aAnnotations
)
637 if( xAnnotation
->getAuthor() == sAuthor
)
639 if( mxSelectedAnnotation
== xAnnotation
)
640 mxSelectedAnnotation
.clear();
641 pPage
->removeAnnotation( xAnnotation
);
647 if( mpDoc
->IsUndoEnabled() )
651 void AnnotationManagerImpl::DeleteAllAnnotations()
653 if( mpDoc
->IsUndoEnabled() )
654 mpDoc
->BegUndo( SdResId( STR_ANNOTATION_UNDO_DELETE
) );
656 SdPage
* pPage
= nullptr;
659 pPage
= GetNextPage( pPage
, true );
661 if( pPage
&& !pPage
->getAnnotations().empty() )
664 AnnotationVector
aAnnotations( pPage
->getAnnotations() );
665 for( const auto& rxAnnotation
: aAnnotations
)
667 pPage
->removeAnnotation( rxAnnotation
);
673 mxSelectedAnnotation
.clear();
675 if( mpDoc
->IsUndoEnabled() )
679 void AnnotationManagerImpl::GetAnnotationState(SfxItemSet
& rSet
)
681 SdPage
* pCurrentPage
= GetCurrentPage();
683 const bool bReadOnly
= mrBase
.GetDocShell()->IsReadOnly();
684 const bool bWrongPageKind
= (pCurrentPage
== nullptr) || (pCurrentPage
->GetPageKind() != PageKind::Standard
);
686 const SvtSaveOptions::ODFDefaultVersion
nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
688 if( bReadOnly
|| bWrongPageKind
|| (nCurrentODFVersion
<= SvtSaveOptions::ODFVER_012
) )
689 rSet
.DisableItem( SID_INSERT_POSTIT
);
691 rSet
.Put(SfxBoolItem(SID_TOGGLE_NOTES
, mbShowAnnotations
));
693 Reference
< XAnnotation
> xAnnotation
;
694 GetSelectedAnnotation( xAnnotation
);
696 // Don't disable these slot in case of LOK, as postit doesn't need to
697 // selected before doing an operation on it in LOK
698 if( (!xAnnotation
.is() && !comphelper::LibreOfficeKit::isActive()) || bReadOnly
)
700 rSet
.DisableItem( SID_DELETE_POSTIT
);
701 rSet
.DisableItem( SID_EDIT_POSTIT
);
704 SdPage
* pPage
= nullptr;
706 bool bHasAnnotations
= false;
709 pPage
= GetNextPage( pPage
, true );
711 if( pPage
&& !pPage
->getAnnotations().empty() )
712 bHasAnnotations
= true;
714 while( pPage
&& !bHasAnnotations
);
716 if( !bHasAnnotations
|| bReadOnly
)
718 rSet
.DisableItem( SID_DELETEALL_POSTIT
);
721 if( bWrongPageKind
|| !bHasAnnotations
)
723 rSet
.DisableItem( SID_PREVIOUS_POSTIT
);
724 rSet
.DisableItem( SID_NEXT_POSTIT
);
728 void AnnotationManagerImpl::SelectNextAnnotation(bool bForeward
)
730 ShowAnnotations( true );
732 Reference
< XAnnotation
> xCurrent
;
733 GetSelectedAnnotation( xCurrent
);
734 SdPage
* pPage
= GetCurrentPage();
738 AnnotationVector
aAnnotations( pPage
->getAnnotations() );
744 auto iter
= std::find(aAnnotations
.begin(), aAnnotations
.end(), xCurrent
);
745 if (iter
!= aAnnotations
.end())
748 if( iter
!= aAnnotations
.end() )
750 SelectAnnotation( (*iter
) );
755 else if( !aAnnotations
.empty() )
757 SelectAnnotation( *(aAnnotations
.begin()) );
765 auto iter
= std::find(aAnnotations
.begin(), aAnnotations
.end(), xCurrent
);
766 if (iter
!= aAnnotations
.end() && iter
!= aAnnotations
.begin())
769 SelectAnnotation( (*iter
) );
773 else if( !aAnnotations
.empty() )
775 AnnotationVector::iterator
iter( aAnnotations
.end() );
776 SelectAnnotation( *(--iter
) );
781 mxSelectedAnnotation
.clear();
786 pPage
= GetNextPage( pPage
, bForeward
);
788 if( pPage
&& !pPage
->getAnnotations().empty() )
790 // switch to next/previous slide with annotations
791 std::shared_ptr
<DrawViewShell
> pDrawViewShell(std::dynamic_pointer_cast
<DrawViewShell
>(mrBase
.GetMainViewShell()));
792 if (pDrawViewShell
!= nullptr)
794 pDrawViewShell
->ChangeEditMode(pPage
->IsMasterPage() ? EditMode::MasterPage
: EditMode::Page
, false);
795 pDrawViewShell
->SwitchPage((pPage
->GetPageNum() - 1) >> 1);
797 SfxDispatcher
* pDispatcher
= getDispatcher( mrBase
);
799 pDispatcher
->Execute( bForeward
? SID_NEXT_POSTIT
: SID_PREVIOUS_POSTIT
);
807 // The question text depends on the search direction.
808 bool bImpress
= mpDoc
->GetDocumentType() == DocumentType::Impress
;
809 const char* pStringId
;
811 pStringId
= bImpress
? STR_ANNOTATION_WRAP_FORWARD
: STR_ANNOTATION_WRAP_FORWARD_DRAW
;
813 pStringId
= bImpress
? STR_ANNOTATION_WRAP_BACKWARD
: STR_ANNOTATION_WRAP_BACKWARD_DRAW
;
815 // Pop up question box that asks the user whether to wrap around.
816 // The dialog is made modal with respect to the whole application.
817 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(nullptr,
818 VclMessageType::Question
, VclButtonsType::YesNo
,
819 SdResId(pStringId
)));
820 xQueryBox
->set_default_response(RET_YES
);
821 if (xQueryBox
->run() != RET_YES
)
827 void AnnotationManagerImpl::onTagSelected( AnnotationTag
const & rTag
)
829 mxSelectedAnnotation
= rTag
.GetAnnotation();
833 void AnnotationManagerImpl::onTagDeselected( AnnotationTag
const & rTag
)
835 if( rTag
.GetAnnotation() == mxSelectedAnnotation
)
837 mxSelectedAnnotation
.clear();
842 void AnnotationManagerImpl::SelectAnnotation( const css::uno::Reference
< css::office::XAnnotation
>& xAnnotation
, bool bEdit
/* = sal_False */ )
844 mxSelectedAnnotation
= xAnnotation
;
846 auto iter
= std::find_if(maTagVector
.begin(), maTagVector
.end(),
847 [&xAnnotation
](const rtl::Reference
<AnnotationTag
>& rxTag
) { return rxTag
->GetAnnotation() == xAnnotation
; });
848 if (iter
!= maTagVector
.end())
850 SmartTagReference
xTag( (*iter
).get() );
851 mrBase
.GetMainViewShell()->GetView()->getSmartTags().select( xTag
);
852 (*iter
)->OpenPopup( bEdit
);
856 void AnnotationManagerImpl::GetSelectedAnnotation( css::uno::Reference
< css::office::XAnnotation
>& xAnnotation
)
858 xAnnotation
= mxSelectedAnnotation
;
861 void AnnotationManagerImpl::invalidateSlots()
863 SfxBindings
* pBindings
= getBindings( mrBase
);
866 pBindings
->Invalidate( SID_INSERT_POSTIT
);
867 pBindings
->Invalidate( SID_DELETE_POSTIT
);
868 pBindings
->Invalidate( SID_DELETEALL_POSTIT
);
869 pBindings
->Invalidate( SID_PREVIOUS_POSTIT
);
870 pBindings
->Invalidate( SID_NEXT_POSTIT
);
871 pBindings
->Invalidate( SID_UNDO
);
872 pBindings
->Invalidate( SID_REDO
);
876 void AnnotationManagerImpl::onSelectionChanged()
878 if( !(mxView
.is() && mrBase
.GetDrawView()) )
883 Reference
< XAnnotationAccess
> xPage( mxView
->getCurrentPage(), UNO_QUERY
);
885 if( xPage
!= mxCurrentPage
)
887 mxCurrentPage
= xPage
;
894 OSL_FAIL( "sd::AnnotationManagerImpl::onSelectionChanged(), exception caught!" );
898 void AnnotationManagerImpl::UpdateTags( bool bSynchron
)
902 if( mnUpdateTagsEvent
)
903 Application::RemoveUserEvent( mnUpdateTagsEvent
);
905 UpdateTagsHdl(nullptr);
909 if( !mnUpdateTagsEvent
&& mxView
.is() )
910 mnUpdateTagsEvent
= Application::PostUserEvent( LINK( this, AnnotationManagerImpl
, UpdateTagsHdl
) );
914 IMPL_LINK_NOARG(AnnotationManagerImpl
, UpdateTagsHdl
, void*, void)
916 mnUpdateTagsEvent
= nullptr;
919 if( mbShowAnnotations
)
922 if( mrBase
.GetDrawView() )
923 static_cast< ::sd::View
* >( mrBase
.GetDrawView() )->updateHandles();
928 void AnnotationManagerImpl::CreateTags()
931 if( !(mxCurrentPage
.is() && mpDoc
) )
937 maFont
= Application::GetSettings().GetStyleSettings().GetAppFont();
939 rtl::Reference
< AnnotationTag
> xSelectedTag
;
941 Reference
< XAnnotationEnumeration
> xEnum( mxCurrentPage
->createAnnotationEnumeration() );
942 while( xEnum
->hasMoreElements() )
944 Reference
< XAnnotation
> xAnnotation( xEnum
->nextElement() );
945 Color
aColor( GetColorLight( mpDoc
->GetAnnotationAuthorIndex( xAnnotation
->getAuthor() ) ) );
946 rtl::Reference
< AnnotationTag
> xTag( new AnnotationTag( *this, *mrBase
.GetMainViewShell()->GetView(), xAnnotation
, aColor
, nIndex
++, maFont
) );
947 maTagVector
.push_back(xTag
);
949 if( xAnnotation
== mxSelectedAnnotation
)
955 if( xSelectedTag
.is() )
957 SmartTagReference
xTag( xSelectedTag
.get() );
958 mrBase
.GetMainViewShell()->GetView()->getSmartTags().select( xTag
);
962 // no tag, no selection!
963 mxSelectedAnnotation
.clear();
968 OSL_FAIL( "sd::AnnotationManagerImpl::onSelectionChanged(), exception caught!" );
972 void AnnotationManagerImpl::DisposeTags()
974 for (auto& rxTag
: maTagVector
)
982 void AnnotationManagerImpl::addListener()
984 Link
<tools::EventMultiplexerEvent
&,void> aLink( LINK(this,AnnotationManagerImpl
,EventMultiplexerListener
) );
985 mrBase
.GetEventMultiplexer()->AddEventListener(aLink
);
988 void AnnotationManagerImpl::removeListener()
990 Link
<tools::EventMultiplexerEvent
&,void> aLink( LINK(this,AnnotationManagerImpl
,EventMultiplexerListener
) );
991 mrBase
.GetEventMultiplexer()->RemoveEventListener( aLink
);
994 IMPL_LINK(AnnotationManagerImpl
,EventMultiplexerListener
,
995 tools::EventMultiplexerEvent
&, rEvent
, void)
997 switch (rEvent
.meEventId
)
999 case EventMultiplexerEventId::CurrentPageChanged
:
1000 case EventMultiplexerEventId::EditViewSelection
:
1001 onSelectionChanged();
1004 case EventMultiplexerEventId::MainViewRemoved
:
1006 onSelectionChanged();
1009 case EventMultiplexerEventId::MainViewAdded
:
1010 mxView
.set( mrBase
.GetController(), UNO_QUERY
);
1011 onSelectionChanged();
1020 sal_uInt16
IdentToSID(const OString
& rIdent
)
1022 if (rIdent
== "reply")
1023 return SID_REPLYTO_POSTIT
;
1024 else if (rIdent
== "delete")
1025 return SID_DELETE_POSTIT
;
1026 else if (rIdent
== "deleteby")
1027 return SID_DELETEALLBYAUTHOR_POSTIT
;
1028 else if (rIdent
== "deleteall")
1029 return SID_DELETEALL_POSTIT
;
1030 else if (rIdent
== "copy")
1032 else if (rIdent
== "paste")
1034 else if (rIdent
== "bold")
1035 return SID_ATTR_CHAR_WEIGHT
;
1036 else if (rIdent
== "italic")
1037 return SID_ATTR_CHAR_POSTURE
;
1038 else if (rIdent
== "underline")
1039 return SID_ATTR_CHAR_UNDERLINE
;
1040 else if (rIdent
== "strike")
1041 return SID_ATTR_CHAR_STRIKEOUT
;
1046 void AnnotationManagerImpl::ExecuteAnnotationContextMenu( const Reference
< XAnnotation
>& xAnnotation
, vcl::Window
* pParent
, const ::tools::Rectangle
& rContextRect
, bool bButtonMenu
/* = false */ )
1048 SfxDispatcher
* pDispatcher( getDispatcher( mrBase
) );
1052 const bool bReadOnly
= mrBase
.GetDocShell()->IsReadOnly();
1054 AnnotationWindow
* pAnnotationWindow
= bButtonMenu
? nullptr : dynamic_cast< AnnotationWindow
* >( pParent
);
1056 if( bReadOnly
&& !pAnnotationWindow
)
1060 if (pAnnotationWindow
)
1061 sUIFile
= "modules/simpress/ui/annotationmenu.ui";
1063 sUIFile
= "modules/simpress/ui/annotationtagmenu.ui";
1064 VclBuilder
aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), sUIFile
, "");
1065 VclPtr
<PopupMenu
> pMenu(aBuilder
.get_menu("menu"));
1067 SvtUserOptions aUserOptions
;
1068 OUString
sCurrentAuthor( aUserOptions
.GetFullName() );
1069 OUString
sAuthor( xAnnotation
->getAuthor() );
1071 OUString
aStr(pMenu
->GetItemText(pMenu
->GetItemId("deleteby")));
1072 OUString
aReplace( sAuthor
);
1073 if( aReplace
.isEmpty() )
1074 aReplace
= SdResId( STR_ANNOTATION_NOAUTHOR
);
1075 aStr
= aStr
.replaceFirst("%1", aReplace
);
1076 pMenu
->SetItemText(pMenu
->GetItemId("deleteby"), aStr
);
1077 pMenu
->EnableItem(pMenu
->GetItemId("reply"), (sAuthor
!= sCurrentAuthor
) && !bReadOnly
);
1078 pMenu
->EnableItem(pMenu
->GetItemId("delete"), xAnnotation
.is() && !bReadOnly
);
1079 pMenu
->EnableItem(pMenu
->GetItemId("deleteby"), !bReadOnly
);
1080 pMenu
->EnableItem(pMenu
->GetItemId("deleteall"), !bReadOnly
);
1082 if( pAnnotationWindow
)
1084 if( pAnnotationWindow
->IsProtected() || bReadOnly
)
1086 pMenu
->EnableItem(pMenu
->GetItemId("bold"), false);
1087 pMenu
->EnableItem(pMenu
->GetItemId("italic"), false);
1088 pMenu
->EnableItem(pMenu
->GetItemId("underline"), false);
1089 pMenu
->EnableItem(pMenu
->GetItemId("strike"), false);
1090 pMenu
->EnableItem(pMenu
->GetItemId("paste"), false);
1094 SfxItemSet
aSet(pAnnotationWindow
->getView()->GetAttribs());
1096 if ( aSet
.GetItemState( EE_CHAR_WEIGHT
) == SfxItemState::SET
)
1098 if( aSet
.Get( EE_CHAR_WEIGHT
).GetWeight() == WEIGHT_BOLD
)
1099 pMenu
->CheckItem("bold");
1102 if ( aSet
.GetItemState( EE_CHAR_ITALIC
) == SfxItemState::SET
)
1104 if( aSet
.Get( EE_CHAR_ITALIC
).GetPosture() != ITALIC_NONE
)
1105 pMenu
->CheckItem("italic");
1108 if ( aSet
.GetItemState( EE_CHAR_UNDERLINE
) == SfxItemState::SET
)
1110 if( aSet
.Get( EE_CHAR_UNDERLINE
).GetLineStyle() != LINESTYLE_NONE
)
1111 pMenu
->CheckItem("underline");
1114 if ( aSet
.GetItemState( EE_CHAR_STRIKEOUT
) == SfxItemState::SET
)
1116 if( aSet
.Get( EE_CHAR_STRIKEOUT
).GetStrikeout() != STRIKEOUT_NONE
)
1117 pMenu
->CheckItem("strike");
1119 TransferableDataHelper
aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pAnnotationWindow
) );
1120 pMenu
->EnableItem(pMenu
->GetItemId("paste"), aDataHelper
.GetFormatCount() != 0);
1123 pMenu
->EnableItem(pMenu
->GetItemId("copy"), pAnnotationWindow
->getView()->HasSelection());
1127 Reference
< css::frame::XFrame
> xFrame( mrBase
.GetMainViewShell()->GetViewFrame()->GetFrame().GetFrameInterface() );
1130 for( sal_uInt16 nPos
= 0; nPos
< pMenu
->GetItemCount(); nPos
++ )
1132 sal_uInt16 nId
= pMenu
->GetItemId( nPos
);
1133 if (!pMenu
->IsItemEnabled(nId
))
1136 Image
aImage( vcl::CommandInfoProvider::GetImageForCommand( pMenu
->GetItemCommand( nId
), xFrame
) );
1138 pMenu
->SetItemImage( nId
, aImage
);
1142 // tdf#99388 and tdf#99712 make known that PopupMenu is active at parent to
1143 // allow suppressing closing of that window if needed
1144 setPopupMenuActive(true);
1146 sal_uInt16 nId
= pMenu
->Execute( pParent
, rContextRect
, PopupMenuFlags::ExecuteDown
|PopupMenuFlags::NoMouseUpClose
);
1147 nId
= IdentToSID(pMenu
->GetItemIdent(nId
));
1149 // tdf#99388 and tdf#99712 reset flag, need to be done before reacting
1150 // since closing it is one possible reaction
1151 setPopupMenuActive(false);
1155 case SID_REPLYTO_POSTIT
:
1157 const SfxUnoAnyItem
aItem( SID_REPLYTO_POSTIT
, Any( xAnnotation
) );
1158 pDispatcher
->ExecuteList(SID_REPLYTO_POSTIT
,
1159 SfxCallMode::ASYNCHRON
, { &aItem
});
1162 case SID_DELETE_POSTIT
:
1164 const SfxUnoAnyItem
aItem( SID_DELETE_POSTIT
, Any( xAnnotation
) );
1165 pDispatcher
->ExecuteList(SID_DELETE_POSTIT
, SfxCallMode::ASYNCHRON
,
1169 case SID_DELETEALLBYAUTHOR_POSTIT
:
1171 const SfxStringItem
aItem( SID_DELETEALLBYAUTHOR_POSTIT
, sAuthor
);
1172 pDispatcher
->ExecuteList( SID_DELETEALLBYAUTHOR_POSTIT
,
1173 SfxCallMode::ASYNCHRON
, { &aItem
});
1176 case SID_DELETEALL_POSTIT
:
1177 pDispatcher
->Execute( SID_DELETEALL_POSTIT
);
1181 case SID_ATTR_CHAR_WEIGHT
:
1182 case SID_ATTR_CHAR_POSTURE
:
1183 case SID_ATTR_CHAR_UNDERLINE
:
1184 case SID_ATTR_CHAR_STRIKEOUT
:
1185 if( pAnnotationWindow
)
1186 pAnnotationWindow
->ExecuteSlot( nId
);
1191 Color
AnnotationManagerImpl::GetColor(sal_uInt16 aAuthorIndex
)
1193 if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
1195 static const Color aArrayNormal
[] = {
1196 COL_AUTHOR1_NORMAL
, COL_AUTHOR2_NORMAL
, COL_AUTHOR3_NORMAL
,
1197 COL_AUTHOR4_NORMAL
, COL_AUTHOR5_NORMAL
, COL_AUTHOR6_NORMAL
,
1198 COL_AUTHOR7_NORMAL
, COL_AUTHOR8_NORMAL
, COL_AUTHOR9_NORMAL
};
1200 return aArrayNormal
[ aAuthorIndex
% SAL_N_ELEMENTS( aArrayNormal
) ];
1206 Color
AnnotationManagerImpl::GetColorLight(sal_uInt16 aAuthorIndex
)
1208 if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
1210 static const Color aArrayLight
[] = {
1211 COL_AUTHOR1_LIGHT
, COL_AUTHOR2_LIGHT
, COL_AUTHOR3_LIGHT
,
1212 COL_AUTHOR4_LIGHT
, COL_AUTHOR5_LIGHT
, COL_AUTHOR6_LIGHT
,
1213 COL_AUTHOR7_LIGHT
, COL_AUTHOR8_LIGHT
, COL_AUTHOR9_LIGHT
};
1215 return aArrayLight
[ aAuthorIndex
% SAL_N_ELEMENTS( aArrayLight
) ];
1221 Color
AnnotationManagerImpl::GetColorDark(sal_uInt16 aAuthorIndex
)
1223 if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
1225 static const Color aArrayAnkor
[] = {
1226 COL_AUTHOR1_DARK
, COL_AUTHOR2_DARK
, COL_AUTHOR3_DARK
,
1227 COL_AUTHOR4_DARK
, COL_AUTHOR5_DARK
, COL_AUTHOR6_DARK
,
1228 COL_AUTHOR7_DARK
, COL_AUTHOR8_DARK
, COL_AUTHOR9_DARK
};
1230 return aArrayAnkor
[ aAuthorIndex
% SAL_N_ELEMENTS( aArrayAnkor
) ];
1236 SdPage
* AnnotationManagerImpl::GetNextPage( SdPage
const * pPage
, bool bForward
)
1238 if( pPage
== nullptr )
1241 return mpDoc
->GetSdPage(0, PageKind::Standard
); // first page
1243 return mpDoc
->GetMasterSdPage( mpDoc
->GetMasterSdPageCount(PageKind::Standard
) - 1, PageKind::Standard
); // last page
1246 sal_uInt16 nPageNum
= (pPage
->GetPageNum() - 1) >> 1;
1248 // first all non master pages
1249 if( !pPage
->IsMasterPage() )
1253 if( nPageNum
>= mpDoc
->GetSdPageCount(PageKind::Standard
)-1 )
1255 // we reached end of draw pages, start with master pages (skip handout master for draw)
1256 return mpDoc
->GetMasterSdPage( (mpDoc
->GetDocumentType() == DocumentType::Impress
) ? 0 : 1, PageKind::Standard
);
1263 return nullptr; // we are already on the first draw page, finished
1267 return mpDoc
->GetSdPage(nPageNum
, PageKind::Standard
);
1273 if( nPageNum
>= mpDoc
->GetMasterSdPageCount(PageKind::Standard
)-1 )
1275 return nullptr; // we reached the end, there is nothing more to see here
1281 if( nPageNum
== (mpDoc
->GetDocumentType() == DocumentType::Impress
? 0 : 1) )
1283 // we reached beginning of master pages, start with end if pages
1284 return mpDoc
->GetSdPage( mpDoc
->GetSdPageCount(PageKind::Standard
)-1, PageKind::Standard
);
1289 return mpDoc
->GetMasterSdPage(nPageNum
,PageKind::Standard
);
1293 SdPage
* AnnotationManagerImpl::GetCurrentPage()
1295 if (mrBase
.GetMainViewShell().get())
1296 return mrBase
.GetMainViewShell()->getCurrentPage();
1300 AnnotationManager::AnnotationManager( ViewShellBase
& rViewShellBase
)
1301 : mxImpl( new AnnotationManagerImpl( rViewShellBase
) )
1306 AnnotationManager::~AnnotationManager()
1311 void AnnotationManager::ExecuteAnnotation(SfxRequest
const & rRequest
)
1313 mxImpl
->ExecuteAnnotation( rRequest
);
1316 void AnnotationManager::GetAnnotationState(SfxItemSet
& rItemSet
)
1318 mxImpl
->GetAnnotationState(rItemSet
);
1323 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */