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 <config_wasm_strip.h>
22 #include <boost/property_tree/json_parser.hpp>
24 #include <PostItMgr.hxx>
25 #include <postithelper.hxx>
27 #include <AnnotationWin.hxx>
28 #include "frmsidebarwincontainer.hxx"
31 #include <SidebarWindowsConsts.hxx>
32 #include "AnchorOverlayObject.hxx"
33 #include "ShadowOverlayObject.hxx"
36 #include <vcl/svapp.hxx>
37 #include <vcl/outdev.hxx>
38 #include <vcl/settings.hxx>
40 #include <chrdlgmodes.hxx>
41 #include <viewopt.hxx>
46 #include <IDocumentSettingAccess.hxx>
47 #include <IDocumentFieldsAccess.hxx>
48 #include <docstyle.hxx>
51 #include <docufld.hxx>
54 #include <txtannotationfld.hxx>
55 #include <rootfrm.hxx>
56 #include <SwRewriter.hxx>
57 #include <tools/color.hxx>
58 #include <unotools/datetime.hxx>
60 #include <swmodule.hxx>
61 #include <strings.hrc>
64 #include <sfx2/request.hxx>
65 #include <sfx2/event.hxx>
66 #include <svl/srchitem.hxx>
68 #include <svl/languageoptions.hxx>
69 #include <svl/hint.hxx>
71 #include <svx/svdview.hxx>
72 #include <editeng/eeitem.hxx>
73 #include <editeng/langitem.hxx>
74 #include <editeng/outliner.hxx>
75 #include <editeng/outlobj.hxx>
77 #include <comphelper/lok.hxx>
78 #include <comphelper/string.hxx>
79 #include <officecfg/Office/Writer.hxx>
80 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
82 #include <annotsh.hxx>
83 #include <swabstdlg.hxx>
84 #include <pagefrm.hxx>
85 #include <officecfg/Office/Common.hxx>
89 // distance between Anchor Y and initial note position
90 #define POSTIT_INITIAL_ANCHOR_DISTANCE 20
91 //distance between two postits
92 #define POSTIT_SPACE_BETWEEN 8
93 #define POSTIT_MINIMUMSIZE_WITH_META 60
94 #define POSTIT_SCROLL_SIDEBAR_HEIGHT 20
96 // if we layout more often we stop, this should never happen
97 #define MAX_LOOP_COUNT 50
99 using namespace sw::sidebarwindows
;
100 using namespace sw::annotation
;
104 enum class CommentNotificationType
{ Add
, Remove
, Modify
, Resolve
, RedlinedDeletion
};
106 bool comp_pos(const std::unique_ptr
<SwAnnotationItem
>& a
, const std::unique_ptr
<SwAnnotationItem
>& b
)
108 // sort by anchor position
109 SwPosition aPosAnchorA
= a
->GetAnchorPosition();
110 SwPosition aPosAnchorB
= b
->GetAnchorPosition();
112 bool aAnchorAInFooter
= false;
113 bool aAnchorBInFooter
= false;
115 // is the anchor placed in Footnote or the Footer?
116 if( aPosAnchorA
.GetNode().FindFootnoteStartNode() || aPosAnchorA
.GetNode().FindFooterStartNode() )
117 aAnchorAInFooter
= true;
118 if( aPosAnchorB
.GetNode().FindFootnoteStartNode() || aPosAnchorB
.GetNode().FindFooterStartNode() )
119 aAnchorBInFooter
= true;
122 // if AnchorA is in footnote, and AnchorB isn't
123 // we do not want to change over the position
124 if( aAnchorAInFooter
&& !aAnchorBInFooter
)
126 // if aAnchorA is not placed in a footnote, and aAnchorB is
127 // force a change over
128 else if( !aAnchorAInFooter
&& aAnchorBInFooter
)
130 // If neither or both are in the footer, compare the positions.
131 // Since footnotes are in Inserts section of nodes array and footers
132 // in Autotext section, all footnotes precede any footers so no need
135 return aPosAnchorA
< aPosAnchorB
;
138 /// Emits LOK notification about one addition/removal/change of a comment
139 void lcl_CommentNotification(const SwView
* pView
, const CommentNotificationType nType
, const SwAnnotationItem
* pItem
, const sal_uInt32 nPostItId
)
141 if (!comphelper::LibreOfficeKit::isActive())
144 boost::property_tree::ptree aAnnotation
;
145 aAnnotation
.put("action", (nType
== CommentNotificationType::Add
? "Add" :
146 (nType
== CommentNotificationType::Remove
? "Remove" :
147 (nType
== CommentNotificationType::Modify
? "Modify" :
148 (nType
== CommentNotificationType::RedlinedDeletion
? "RedlinedDeletion" :
149 (nType
== CommentNotificationType::Resolve
? "Resolve" : "???"))))));
151 aAnnotation
.put("id", nPostItId
);
152 if (nType
!= CommentNotificationType::Remove
&& pItem
!= nullptr)
154 sw::annotation::SwAnnotationWin
* pWin
= pItem
->mpPostIt
.get();
156 const SwPostItField
* pField
= pWin
->GetPostItField();
157 const SwRect
& aRect
= pWin
->GetAnchorRect();
158 tools::Rectangle
aSVRect(aRect
.Pos().getX(),
160 aRect
.Pos().getX() + aRect
.SSize().Width(),
161 aRect
.Pos().getY() + aRect
.SSize().Height());
163 if (!pItem
->maLayoutInfo
.mPositionFromCommentAnchor
)
165 // Comments on frames: anchor position is the corner position, not the whole frame.
166 aSVRect
.SetSize(Size(0, 0));
169 std::vector
<OString
> aRects
;
170 for (const basegfx::B2DRange
& aRange
: pWin
->GetAnnotationTextRanges())
172 const SwRect
rect(aRange
.getMinX(), aRange
.getMinY(), aRange
.getWidth(), aRange
.getHeight());
173 aRects
.push_back(rect
.SVRect().toString());
175 const OString sRects
= comphelper::string::join("; ", aRects
);
177 aAnnotation
.put("id", pField
->GetPostItId());
178 aAnnotation
.put("parentId", pField
->GetParentPostItId());
179 aAnnotation
.put("author", pField
->GetPar1().toUtf8().getStr());
180 // Note, for just plain text we could use "text" populated by pField->GetPar2()
181 aAnnotation
.put("html", pWin
->GetSimpleHtml());
182 aAnnotation
.put("resolved", pField
->GetResolved() ? "true" : "false");
183 aAnnotation
.put("dateTime", utl::toISO8601(pField
->GetDateTime().GetUNODateTime()));
184 aAnnotation
.put("anchorPos", aSVRect
.toString());
185 aAnnotation
.put("textRange", sRects
.getStr());
186 aAnnotation
.put("layoutStatus", pItem
->mLayoutStatus
);
188 if (nType
== CommentNotificationType::Remove
&& comphelper::LibreOfficeKit::isActive())
190 // Redline author is basically the author which has made the modification rather than author of the comments
191 // This is important to know who removed the comment
192 aAnnotation
.put("author", SwModule::get()->GetRedlineAuthor(SwModule::get()->GetRedlineAuthor()));
195 boost::property_tree::ptree aTree
;
196 aTree
.add_child("comment", aAnnotation
);
197 std::stringstream aStream
;
198 boost::property_tree::write_json(aStream
, aTree
);
199 std::string aPayload
= aStream
.str();
203 pView
->libreOfficeKitViewCallback(LOK_CALLBACK_COMMENT
, OString(aPayload
));
210 virtual bool operator()(const SwFormatField
* pField
) const = 0;
211 virtual ~FilterFunctor() {}
214 class IsPostitField
: public FilterFunctor
217 bool operator()(const SwFormatField
* pField
) const override
219 return pField
->GetField()->GetTyp()->Which() == SwFieldIds::Postit
;
223 class IsPostitFieldWithAuthorOf
: public FilterFunctor
227 explicit IsPostitFieldWithAuthorOf(OUString aAuthor
)
228 : m_sAuthor(std::move(aAuthor
))
231 bool operator()(const SwFormatField
* pField
) const override
233 if (pField
->GetField()->GetTyp()->Which() != SwFieldIds::Postit
)
235 return static_cast<const SwPostItField
*>(pField
->GetField())->GetPar1() == m_sAuthor
;
239 class IsPostitFieldWithPostitId
: public FilterFunctor
241 sal_uInt32 m_nPostItId
;
243 explicit IsPostitFieldWithPostitId(sal_uInt32 nPostItId
)
244 : m_nPostItId(nPostItId
)
247 bool operator()(const SwFormatField
* pField
) const override
249 if (pField
->GetField()->GetTyp()->Which() != SwFieldIds::Postit
)
251 return static_cast<const SwPostItField
*>(pField
->GetField())->GetPostItId() == m_nPostItId
;
255 class IsFieldNotDeleted
: public FilterFunctor
258 IDocumentRedlineAccess
const& m_rIDRA
;
259 FilterFunctor
const& m_rNext
;
262 IsFieldNotDeleted(IDocumentRedlineAccess
const& rIDRA
,
263 const FilterFunctor
& rNext
)
268 bool operator()(const SwFormatField
* pField
) const override
270 if (!m_rNext(pField
))
272 if (!pField
->GetTextField())
274 return !sw::IsFieldDeletedInModel(m_rIDRA
, *pField
->GetTextField());
278 //Manages the passed in vector by automatically removing entries if they are deleted
279 //and automatically adding entries if they appear in the document and match the
282 //This will completely refill in the case of a "anonymous" NULL pField stating
283 //rather unhelpfully that "something changed" so you may process the same
284 //Fields more than once.
285 class FieldDocWatchingStack
: public SfxListener
287 std::vector
<std::unique_ptr
<SwAnnotationItem
>>& m_aSidebarItems
;
288 std::vector
<const SwFormatField
*> m_aFormatFields
;
289 SwDocShell
& m_rDocShell
;
290 FilterFunctor
& m_rFilter
;
292 virtual void Notify(SfxBroadcaster
&, const SfxHint
& rHint
) override
294 if ( rHint
.GetId() != SfxHintId::SwFormatField
)
296 const SwFormatFieldHint
* pHint
= static_cast<const SwFormatFieldHint
*>(&rHint
);
298 bool bAllInvalidated
= false;
299 if (pHint
->Which() == SwFormatFieldHintWhich::REMOVED
)
301 const SwFormatField
* pField
= pHint
->GetField();
302 bAllInvalidated
= pField
== nullptr;
303 if (!bAllInvalidated
&& m_rFilter(pField
))
305 EndListening(const_cast<SwFormatField
&>(*pField
));
306 std::erase(m_aFormatFields
, pField
);
309 else if (pHint
->Which() == SwFormatFieldHintWhich::INSERTED
)
311 const SwFormatField
* pField
= pHint
->GetField();
312 bAllInvalidated
= pField
== nullptr;
313 if (!bAllInvalidated
&& m_rFilter(pField
))
315 StartListening(const_cast<SwFormatField
&>(*pField
));
316 m_aFormatFields
.push_back(pField
);
327 FieldDocWatchingStack(std::vector
<std::unique_ptr
<SwAnnotationItem
>>& in
, SwDocShell
&rDocShell
, FilterFunctor
& rFilter
)
328 : m_aSidebarItems(in
)
329 , m_rDocShell(rDocShell
)
333 StartListening(m_rDocShell
);
337 EndListeningToAllFields();
338 m_aFormatFields
.clear();
339 m_aFormatFields
.reserve(m_aSidebarItems
.size());
340 for (auto const& p
: m_aSidebarItems
)
342 const SwFormatField
& rField
= p
->GetFormatField();
343 if (!m_rFilter(&rField
))
345 StartListening(const_cast<SwFormatField
&>(rField
));
346 m_aFormatFields
.push_back(&rField
);
349 void EndListeningToAllFields()
351 for (auto const& pField
: m_aFormatFields
)
353 EndListening(const_cast<SwFormatField
&>(*pField
));
356 virtual ~FieldDocWatchingStack() override
358 EndListeningToAllFields();
359 EndListening(m_rDocShell
);
361 const SwFormatField
* pop()
363 if (m_aFormatFields
.empty())
365 const SwFormatField
* p
= m_aFormatFields
.back();
366 EndListening(const_cast<SwFormatField
&>(*p
));
367 m_aFormatFields
.pop_back();
372 } // anonymous namespace
374 SwPostItMgr::SwPostItMgr(SwView
* pView
)
376 , mpWrtShell(mpView
->GetDocShell()->GetWrtShell())
377 , mpEditWin(&mpView
->GetEditWin())
379 , mbWaitingForCalcRects(false)
380 , mpActivePostIt(nullptr)
384 , mbReadOnly(mpView
->GetDocShell()->IsReadOnly())
387 if(!mpView
->GetDrawView() )
388 mpView
->GetWrtShell().MakeDrawView();
390 //make sure we get the colour yellow always, even if not the first one of comments or redlining
391 SwModule::get()->GetRedlineAuthor();
393 // collect all PostIts and redline comments that exist after loading the document
394 // don't check for existence for any of them, don't focus them
395 AddPostIts(false,false);
396 /* this code can be used once we want redline comments in the Sidebar
397 AddRedlineComments(false,false);
399 // we want to receive stuff like SfxHintId::DocChanged
400 StartListening(*mpView
->GetDocShell());
401 // listen to stylesheet pool to update on stylesheet rename,
402 // as EditTextObject references styles by name.
403 SfxStyleSheetBasePool
* pStyleSheetPool
= mpView
->GetDocShell()->GetStyleSheetPool();
405 StartListening(*static_cast<SwDocStyleSheetPool
*>(pStyleSheetPool
)->GetEEStyleSheetPool());
406 if (!mvPostItFields
.empty())
408 mbWaitingForCalcRects
= true;
409 mnEventId
= Application::PostUserEvent( LINK( this, SwPostItMgr
, CalcHdl
) );
413 SwPostItMgr::~SwPostItMgr()
416 Application::RemoveUserEvent( mnEventId
);
417 // forget about all our Sidebar windows
424 bool SwPostItMgr::CheckForRemovedPostIts()
426 IDocumentRedlineAccess
const& rIDRA(mpWrtShell
->getIDocumentRedlineAccess());
427 bool bRemoved
= false;
428 auto it
= mvPostItFields
.begin();
429 while(it
!= mvPostItFields
.end())
431 if (!(*it
)->UseElement(*mpWrtShell
->GetLayout(), rIDRA
))
433 EndListening(const_cast<SfxBroadcaster
&>(*(*it
)->GetBroadcaster()));
435 if((*it
)->mpPostIt
&& (*it
)->mpPostIt
->GetPostItField())
436 lcl_CommentNotification(mpView
, CommentNotificationType::Remove
, nullptr, (*it
)->mpPostIt
->GetPostItField()->GetPostItId());
438 std::unique_ptr
<SwAnnotationItem
> p
= std::move(*it
);
439 it
= mvPostItFields
.erase(it
);
440 if (GetActiveSidebarWin() == p
->mpPostIt
)
441 SetActiveSidebarWin(nullptr);
442 p
->mpPostIt
.disposeAndClear();
444 if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
446 const SwPostItField
* pPostItField
= static_cast<const SwPostItField
*>(p
->GetFormatField().GetField());
447 lcl_CommentNotification(mpView
, CommentNotificationType::Remove
, nullptr, pPostItField
->GetPostItId());
459 // make sure that no deleted items remain in page lists
460 // todo: only remove deleted ones?!
461 if ( mvPostItFields
.empty() )
463 PreparePageContainer();
468 // if postits are there make sure that page lists are not empty
469 // otherwise sudden paints can cause pain (in BorderOverPageBorder)
476 SwAnnotationItem
* SwPostItMgr::InsertItem(SfxBroadcaster
* pItem
, bool bCheckExistence
, bool bFocus
)
480 for (auto const& postItField
: mvPostItFields
)
482 if ( postItField
->GetBroadcaster() == pItem
)
488 SwAnnotationItem
* pAnnotationItem
= nullptr;
489 if (auto pSwFormatField
= dynamic_cast< SwFormatField
*>( pItem
))
491 IsPostitField isPostitField
;
492 if (!isPostitField(pSwFormatField
))
494 mvPostItFields
.push_back(std::make_unique
<SwAnnotationItem
>(*pSwFormatField
, bFocus
));
495 pAnnotationItem
= mvPostItFields
.back().get();
497 assert(dynamic_cast< const SwFormatField
*>( pItem
) && "Mgr::InsertItem: seems like new stuff was added");
498 StartListening(*pItem
);
499 return pAnnotationItem
;
502 sw::annotation::SwAnnotationWin
* SwPostItMgr::GetRemovedAnnotationWin( const SfxBroadcaster
* pBroadcast
)
504 auto i
= std::find_if(mvPostItFields
.begin(), mvPostItFields
.end(),
505 [&pBroadcast
](const std::unique_ptr
<SwAnnotationItem
>& pField
) { return pField
->GetBroadcaster() == pBroadcast
; });
506 if (i
!= mvPostItFields
.end())
508 return (*i
)->mpPostIt
;
513 void SwPostItMgr::RemoveItem( SfxBroadcaster
* pBroadcast
)
515 EndListening(*pBroadcast
);
516 auto i
= std::find_if(mvPostItFields
.begin(), mvPostItFields
.end(),
517 [&pBroadcast
](const std::unique_ptr
<SwAnnotationItem
>& pField
) { return pField
->GetBroadcaster() == pBroadcast
; });
518 if (i
!= mvPostItFields
.end())
520 std::unique_ptr
<SwAnnotationItem
> p
= std::move(*i
);
521 // tdf#120487 remove from list before dispose, so comment window
522 // won't be recreated due to the entry still in the list if focus
523 // transferring from the pPostIt triggers relayout of postits
524 // tdf#133348 remove from list before calling SetActiveSidebarWin
525 // so GetNextPostIt won't deal with mvPostItFields containing empty unique_ptr
526 mvPostItFields
.erase(i
);
527 if (GetActiveSidebarWin() == p
->mpPostIt
)
528 SetActiveSidebarWin(nullptr);
529 p
->mpPostIt
.disposeAndClear();
535 void SwPostItMgr::Notify( SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
537 if (rHint
.GetId() == SfxHintId::ThisIsAnSfxEventHint
)
539 const SfxEventHint
& rSfxEventHint
= static_cast<const SfxEventHint
&>(rHint
);
540 if (rSfxEventHint
.GetEventId() == SfxEventHintId::SwEventLayoutFinished
)
542 if ( !mbWaitingForCalcRects
&& !mvPostItFields
.empty())
544 mbWaitingForCalcRects
= true;
545 mnEventId
= Application::PostUserEvent( LINK( this, SwPostItMgr
, CalcHdl
) );
549 else if ( rHint
.GetId() == SfxHintId::SwFormatField
)
551 const SwFormatFieldHint
* pFormatHint
= static_cast<const SwFormatFieldHint
*>(&rHint
);
552 SwFormatField
* pField
= const_cast <SwFormatField
*>( pFormatHint
->GetField() );
553 switch ( pFormatHint
->Which() )
555 case SwFormatFieldHintWhich::INSERTED
:
562 // get field to be inserted from hint
563 if ( pField
->IsFieldInDoc() )
565 bool bEmpty
= !HasNotes();
566 SwAnnotationItem
* pItem
= InsertItem( pField
, true, false );
568 if (bEmpty
&& !mvPostItFields
.empty())
571 // True until the layout of this post it finishes
573 pItem
->mbPendingLayout
= true;
577 OSL_FAIL("Inserted field not in document!" );
581 case SwFormatFieldHintWhich::REMOVED
:
582 case SwFormatFieldHintWhich::REDLINED_DELETION
:
588 const bool bWasRemoved
= CheckForRemovedPostIts();
589 // tdf#143643 ensure relayout on undo of insert comment
594 this->Broadcast(rHint
);
597 // If LOK has disabled tiled annotations, emit annotation callbacks
598 if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
600 SwPostItField
* pPostItField
= static_cast<SwPostItField
*>(pField
->GetField());
601 auto type
= pFormatHint
->Which() == SwFormatFieldHintWhich::REMOVED
? CommentNotificationType::Remove
: CommentNotificationType::RedlinedDeletion
;
602 lcl_CommentNotification(mpView
, type
, nullptr, pPostItField
->GetPostItId());
607 case SwFormatFieldHintWhich::FOCUS
:
609 if (pFormatHint
->GetView()== mpView
)
613 case SwFormatFieldHintWhich::CHANGED
:
614 case SwFormatFieldHintWhich::RESOLVED
:
616 SwFormatField
* pFormatField
= dynamic_cast<SwFormatField
*>(&rBC
);
617 for (auto const& postItField
: mvPostItFields
)
619 if ( pFormatField
== postItField
->GetBroadcaster() )
621 if (postItField
->mpPostIt
)
623 postItField
->mpPostIt
->SetPostItText();
625 this->Forward(rBC
, rHint
);
628 // If LOK has disabled tiled annotations, emit annotation callbacks
629 if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
631 if(SwFormatFieldHintWhich::CHANGED
== pFormatHint
->Which())
632 lcl_CommentNotification(mpView
, CommentNotificationType::Modify
, postItField
.get(), 0);
634 lcl_CommentNotification(mpView
, CommentNotificationType::Resolve
, postItField
.get(), 0);
643 else if ( rHint
.GetId() == SfxHintId::StyleSheetModifiedExtended
)
645 const SfxStyleSheetModifiedHint
* pStyleHint
= static_cast<const SfxStyleSheetModifiedHint
*>(&rHint
);
646 for (const auto& postItField
: mvPostItFields
)
648 auto pField
= static_cast<SwPostItField
*>(postItField
->GetFormatField().GetField());
649 pField
->ChangeStyleSheetName(pStyleHint
->GetOldName(), pStyleHint
->GetStyleSheet());
654 SfxHintId nId
= rHint
.GetId();
657 case SfxHintId::ModeChanged
:
659 if ( mbReadOnly
!= mpView
->GetDocShell()->IsReadOnly() )
661 mbReadOnly
= !mbReadOnly
;
667 case SfxHintId::DocChanged
:
669 if ( mpView
->GetDocShell() == &rBC
)
671 if ( !mbWaitingForCalcRects
&& !mvPostItFields
.empty())
673 mbWaitingForCalcRects
= true;
674 mnEventId
= Application::PostUserEvent( LINK( this, SwPostItMgr
, CalcHdl
) );
679 case SfxHintId::LanguageChanged
:
684 case SfxHintId::SwSplitNodeOperation
:
686 // if we are in a SplitNode/Cut operation, do not delete note and then add again, as this will flicker
687 mbDeleteNote
= !mbDeleteNote
;
690 case SfxHintId::Dying
:
692 if ( mpView
->GetDocShell() != &rBC
)
694 // field to be removed is the broadcaster
695 OSL_FAIL("Notification for removed SwFormatField was not sent!");
705 void SwPostItMgr::Focus(const SfxBroadcaster
& rBC
)
707 if (!mpWrtShell
->GetViewOptions()->IsPostIts())
709 SfxRequest
aRequest(mpView
->GetViewFrame(), SID_TOGGLE_NOTES
);
710 mpView
->ExecViewOptions(aRequest
);
713 for (auto const& postItField
: mvPostItFields
)
715 // field to get the focus is the broadcaster
716 if ( &rBC
== postItField
->GetBroadcaster() )
718 if (postItField
->mpPostIt
)
720 if (postItField
->mpPostIt
->IsResolved() &&
721 !mpWrtShell
->GetViewOptions()->IsResolvedPostIts())
723 SfxRequest
aRequest(mpView
->GetViewFrame(), SID_TOGGLE_RESOLVED_NOTES
);
724 mpView
->ExecViewOptions(aRequest
);
726 postItField
->mpPostIt
->GrabFocus();
727 MakeVisible(postItField
->mpPostIt
);
731 // when the layout algorithm starts, this postit is created and receives focus
732 postItField
->mbFocus
= true;
738 bool SwPostItMgr::CalcRects()
742 // if CalcRects() was forced and an event is still pending: remove it
743 // it is superfluous and also may cause reentrance problems if triggered while layouting
744 Application::RemoveUserEvent( mnEventId
);
748 bool bChange
= false;
749 bool bRepair
= false;
750 PreparePageContainer();
751 if ( !mvPostItFields
.empty() )
753 IDocumentRedlineAccess
const& rIDRA(mpWrtShell
->getIDocumentRedlineAccess());
754 for (auto const& pItem
: mvPostItFields
)
756 if (!pItem
->UseElement(*mpWrtShell
->GetLayout(), rIDRA
))
758 OSL_FAIL("PostIt is not in doc or other wrong use");
762 const SwRect
aOldAnchorRect( pItem
->maLayoutInfo
.mPosition
);
763 const SwPostItHelper::SwLayoutStatus eOldLayoutStatus
= pItem
->mLayoutStatus
;
764 const SwNodeOffset
nOldStartNodeIdx( pItem
->maLayoutInfo
.mnStartNodeIdx
);
765 const sal_Int32
nOldStartContent( pItem
->maLayoutInfo
.mnStartContent
);
767 // update layout information
768 const SwTextAnnotationField
* pTextAnnotationField
=
769 dynamic_cast< const SwTextAnnotationField
* >( pItem
->GetFormatField().GetTextField() );
770 const ::sw::mark::MarkBase
* pAnnotationMark
=
771 pTextAnnotationField
!= nullptr ? pTextAnnotationField
->GetAnnotationMark() : nullptr;
772 if ( pAnnotationMark
!= nullptr )
774 pItem
->mLayoutStatus
=
775 SwPostItHelper::getLayoutInfos(
777 pItem
->GetAnchorPosition(),
782 pItem
->mLayoutStatus
=
783 SwPostItHelper::getLayoutInfos( pItem
->maLayoutInfo
, pItem
->GetAnchorPosition() );
787 || pItem
->maLayoutInfo
.mPosition
!= aOldAnchorRect
788 || pItem
->mLayoutStatus
!= eOldLayoutStatus
789 || pItem
->maLayoutInfo
.mnStartNodeIdx
!= nOldStartNodeIdx
790 || pItem
->maLayoutInfo
.mnStartContent
!= nOldStartContent
;
793 // show notes in right order in navigator
794 //prevent Anchors during layout to overlap, e.g. when moving a frame
795 if (mvPostItFields
.size()>1 )
796 std::stable_sort(mvPostItFields
.begin(), mvPostItFields
.end(), comp_pos
);
798 // sort the items into the right page vector, so layout can be done by page
799 for (auto const& pItem
: mvPostItFields
)
801 if( SwPostItHelper::INVISIBLE
== pItem
->mLayoutStatus
)
804 pItem
->mpPostIt
->HideNote();
808 if( SwPostItHelper::HIDDEN
== pItem
->mLayoutStatus
)
810 if (!mpWrtShell
->GetViewOptions()->IsShowHiddenChar())
813 pItem
->mpPostIt
->HideNote();
818 const tools::ULong aPageNum
= pItem
->maLayoutInfo
.mnPageNumber
;
819 if (aPageNum
> mPages
.size())
821 const tools::ULong nNumberOfPages
= mPages
.size();
822 mPages
.reserve(aPageNum
);
823 for (tools::ULong j
=0; j
<aPageNum
- nNumberOfPages
; ++j
)
824 mPages
.emplace_back( new SwPostItPageItem());
826 mPages
[aPageNum
-1]->mvSidebarItems
.push_back(pItem
.get());
827 mPages
[aPageNum
-1]->mPageRect
= pItem
->maLayoutInfo
.mPageFrame
;
828 mPages
[aPageNum
-1]->eSidebarPosition
= pItem
->maLayoutInfo
.meSidebarPosition
;
831 if (!bChange
&& mpWrtShell
->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE
))
833 tools::Long nLayoutHeight
= SwPostItHelper::getLayoutHeight( mpWrtShell
->GetLayout() );
834 if( nLayoutHeight
> mbLayoutHeight
)
836 if (mPages
[0]->bScrollbar
|| HasScrollbars())
839 else if( nLayoutHeight
< mbLayoutHeight
)
841 if (mPages
[0]->bScrollbar
|| !BorderOverPageBorder(1))
848 CheckForRemovedPostIts();
850 mbLayoutHeight
= SwPostItHelper::getLayoutHeight( mpWrtShell
->GetLayout() );
851 mbWaitingForCalcRects
= false;
855 bool SwPostItMgr::HasScrollbars() const
857 for (auto const& postItField
: mvPostItFields
)
859 if (postItField
->mbShow
&& postItField
->mpPostIt
&& postItField
->mpPostIt
->HasScrollbar())
865 void SwPostItMgr::PreparePageContainer()
867 // we do not just delete the SwPostItPageItem, so offset/scrollbar is not lost
868 tools::Long lPageSize
= mpWrtShell
->GetNumPages();
869 tools::Long lContainerSize
= mPages
.size();
871 if (lContainerSize
< lPageSize
)
873 mPages
.reserve(lPageSize
);
874 for (tools::Long i
=0; i
<lPageSize
- lContainerSize
;i
++)
875 mPages
.emplace_back( new SwPostItPageItem());
877 else if (lContainerSize
> lPageSize
)
879 for (int i
=mPages
.size()-1; i
>= lPageSize
;--i
)
884 // only clear the list, DO NOT delete the objects itself
885 for (auto const& page
: mPages
)
887 page
->mvSidebarItems
.clear();
888 if (mvPostItFields
.empty())
889 page
->bScrollbar
= false;
893 VclPtr
<SwAnnotationWin
> SwPostItMgr::GetOrCreateAnnotationWindow(SwAnnotationItem
& rItem
)
895 VclPtr
<SwAnnotationWin
> pPostIt
= rItem
.mpPostIt
;
898 pPostIt
= rItem
.GetSidebarWindow( mpView
->GetEditWin(),
900 pPostIt
->InitControls();
901 pPostIt
->SetReadonly(mbReadOnly
);
902 rItem
.mpPostIt
= pPostIt
;
905 if (pPostIt
->GetPostItField()->GetParentPostItId() != 0) //do we really have another note in front of this one
907 pPostIt
->InitAnswer(*mpAnswer
);
912 return rItem
.mpPostIt
;
915 void SwPostItMgr::LayoutPostIts()
917 const bool bLoKitActive
= comphelper::LibreOfficeKit::isActive();
918 const bool bTiledAnnotations
= comphelper::LibreOfficeKit::isTiledAnnotations();
919 const bool bShowNotes
= ShowNotes();
921 const bool bEnableMapMode
= bLoKitActive
&& !mpEditWin
->IsMapModeEnabled();
923 mpEditWin
->EnableMapMode();
925 if ( !mvPostItFields
.empty() && !mbWaitingForCalcRects
)
929 //loop over all pages and do the layout
930 // - create SwPostIt if necessary
931 // - place SwPostIts on their initial position
932 // - calculate necessary height for all PostIts together
933 bool bUpdate
= false;
934 for (std::unique_ptr
<SwPostItPageItem
>& pPage
: mPages
)
936 // only layout if there are notes on this page
937 if (!pPage
->mvSidebarItems
.empty())
939 std::vector
<SwAnnotationWin
*> aVisiblePostItList
;
940 tools::ULong lNeededHeight
= 0;
942 for (auto const& pItem
: pPage
->mvSidebarItems
)
946 VclPtr
<SwAnnotationWin
> pPostIt
= GetOrCreateAnnotationWindow(*pItem
);
948 pPostIt
->SetChangeTracking(
949 pItem
->mLayoutStatus
,
950 GetColorAnchor(pItem
->maLayoutInfo
.mRedlineAuthor
));
951 pPostIt
->SetSidebarPosition(pPage
->eSidebarPosition
);
953 if (pPostIt
->GetPostItField()->GetParentPostItId() != 0)
954 pPostIt
->SetFollow(true);
956 tools::Long aPostItHeight
= 0;
959 tools::Long mlPageBorder
= 0;
960 tools::Long mlPageEnd
= 0;
962 if (pPage
->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::LEFT
)
964 // x value for notes positioning
965 mlPageBorder
= mpEditWin
->LogicToPixel( Point( pPage
->mPageRect
.Left(), 0)).X() - GetSidebarWidth(true);// - GetSidebarBorderWidth(true);
968 mpWrtShell
->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE
)
969 ? pItem
->maLayoutInfo
.mPagePrtArea
.Left()
970 : pPage
->mPageRect
.Left() + 350;
972 else if (pPage
->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::RIGHT
)
974 // x value for notes positioning
975 mlPageBorder
= mpEditWin
->LogicToPixel( Point(pPage
->mPageRect
.Right(), 0)).X() + GetSidebarBorderWidth(true);
978 mpWrtShell
->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE
)
979 ? pItem
->maLayoutInfo
.mPagePrtArea
.Right() :
980 pPage
->mPageRect
.Right() - 350;
983 tools::Long Y
= mpEditWin
->LogicToPixel( Point(0,pItem
->maLayoutInfo
.mPosition
.Bottom())).Y();
985 aPostItHeight
= ( pPostIt
->GetPostItTextHeight() < pPostIt
->GetMinimumSizeWithoutMeta()
986 ? pPostIt
->GetMinimumSizeWithoutMeta()
987 : pPostIt
->GetPostItTextHeight() )
988 + pPostIt
->GetMetaHeight();
989 pPostIt
->SetPosSizePixelRect( mlPageBorder
,
990 Y
- GetInitialAnchorDistance(),
991 GetSidebarWidth(true),
996 pPostIt
->SetAnchorRect(pItem
->maLayoutInfo
.mPosition
);
998 pPostIt
->ChangeSidebarItem( *pItem
);
1003 pPostIt
->GrabFocus();
1004 pItem
->mbFocus
= false;
1006 // only the visible postits are used for the final layout
1007 aVisiblePostItList
.push_back(pPostIt
);
1009 lNeededHeight
+= pPostIt
->IsFollow() ? aPostItHeight
: aPostItHeight
+GetSpaceBetween();
1011 else // we don't want to see it
1013 VclPtr
<SwAnnotationWin
> pPostIt
= pItem
->mpPostIt
;
1015 pPostIt
->HideNote();
1017 SwFormatField
* pFormatField
= &(pItem
->GetFormatField());
1018 SwFormatFieldHintWhich nWhich
= SwFormatFieldHintWhich::INSERTED
;
1019 this->Broadcast(SwFormatFieldHint(pFormatField
, nWhich
, mpView
));
1022 if (!aVisiblePostItList
.empty() && ShowNotes())
1024 bool bOldScrollbar
= pPage
->bScrollbar
;
1025 pPage
->bScrollbar
= LayoutByPage(aVisiblePostItList
, pPage
->mPageRect
.SVRect(), lNeededHeight
);
1026 if (!pPage
->bScrollbar
)
1030 else if (sal_Int32 nScrollSize
= GetScrollSize())
1032 //when we changed our zoom level, the offset value can be too big, so let's check for the largest possible zoom value
1033 tools::Long aAvailableHeight
= mpEditWin
->LogicToPixel(Size(0,pPage
->mPageRect
.Height())).Height() - 2 * GetSidebarScrollerHeight();
1034 tools::Long lOffset
= -1 * nScrollSize
* (aVisiblePostItList
.size() - aAvailableHeight
/ nScrollSize
);
1035 if (pPage
->lOffset
< lOffset
)
1036 pPage
->lOffset
= lOffset
;
1038 bUpdate
= (bOldScrollbar
!= pPage
->bScrollbar
) || bUpdate
;
1039 const tools::Long aSidebarheight
= pPage
->bScrollbar
? mpEditWin
->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height() : 0;
1042 - enlarge all notes till GetNextBorder(), as we resized to average value before
1044 //let's hide the ones which overlap the page
1045 for (auto const& visiblePostIt
: aVisiblePostItList
)
1047 if (pPage
->lOffset
!= 0)
1048 visiblePostIt
->TranslateTopPosition(pPage
->lOffset
);
1050 bool bBottom
= mpEditWin
->PixelToLogic(Point(0,visiblePostIt
->VirtualPos().Y()+visiblePostIt
->VirtualSize().Height())).Y() <= (pPage
->mPageRect
.Bottom()-aSidebarheight
);
1051 bool bTop
= mpEditWin
->PixelToLogic(Point(0,visiblePostIt
->VirtualPos().Y())).Y() >= (pPage
->mPageRect
.Top()+aSidebarheight
);
1052 if ( bBottom
&& bTop
)
1054 // When tiled rendering, make sure that only the
1055 // view that has the comment focus emits callbacks,
1056 // so the editing view jumps to the comment, but
1058 bool bTiledPainting
= comphelper::LibreOfficeKit::isTiledPainting();
1059 if (!bTiledPainting
)
1060 // No focus -> disable callbacks.
1061 comphelper::LibreOfficeKit::setTiledPainting(!visiblePostIt
->HasChildPathFocus());
1062 visiblePostIt
->ShowNote();
1063 if (!bTiledPainting
)
1064 comphelper::LibreOfficeKit::setTiledPainting(bTiledPainting
);
1068 if (mpEditWin
->PixelToLogic(Point(0,visiblePostIt
->VirtualPos().Y())).Y() < (pPage
->mPageRect
.Top()+aSidebarheight
))
1070 if ( pPage
->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::LEFT
)
1071 visiblePostIt
->ShowAnchorOnly(Point( pPage
->mPageRect
.Left(),
1072 pPage
->mPageRect
.Top()));
1073 else if ( pPage
->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::RIGHT
)
1074 visiblePostIt
->ShowAnchorOnly(Point( pPage
->mPageRect
.Right(),
1075 pPage
->mPageRect
.Top()));
1079 if ( pPage
->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::LEFT
)
1080 visiblePostIt
->ShowAnchorOnly(Point(pPage
->mPageRect
.Left(),
1081 pPage
->mPageRect
.Bottom()));
1082 else if ( pPage
->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::RIGHT
)
1083 visiblePostIt
->ShowAnchorOnly(Point(pPage
->mPageRect
.Right(),
1084 pPage
->mPageRect
.Bottom()));
1086 OSL_ENSURE(pPage
->bScrollbar
,"SwPostItMgr::LayoutByPage(): note overlaps, but bScrollbar is not true");
1092 for (auto const& visiblePostIt
: aVisiblePostItList
)
1094 visiblePostIt
->SetPosAndSize();
1097 bool bOldScrollbar
= pPage
->bScrollbar
;
1098 pPage
->bScrollbar
= false;
1099 bUpdate
= (bOldScrollbar
!= pPage
->bScrollbar
) || bUpdate
;
1102 for (auto const& visiblePostIt
: aVisiblePostItList
)
1104 if (bLoKitActive
&& !bTiledAnnotations
)
1106 if (visiblePostIt
->GetSidebarItem().mbPendingLayout
&& visiblePostIt
->GetSidebarItem().mLayoutStatus
!= SwPostItHelper::DELETED
)
1107 lcl_CommentNotification(mpView
, CommentNotificationType::Add
, &visiblePostIt
->GetSidebarItem(), 0);
1108 else if (visiblePostIt
->IsAnchorRectChanged())
1110 lcl_CommentNotification(mpView
, CommentNotificationType::Modify
, &visiblePostIt
->GetSidebarItem(), 0);
1111 visiblePostIt
->ResetAnchorRectChanged();
1115 // Layout for this post it finished now
1116 visiblePostIt
->GetSidebarItem().mbPendingLayout
= false;
1121 if (pPage
->bScrollbar
)
1123 pPage
->bScrollbar
= false;
1128 { // we do not want to see the notes anymore -> Options-Writer-View-Notes
1129 IDocumentRedlineAccess
const& rIDRA(mpWrtShell
->getIDocumentRedlineAccess());
1130 bool bRepair
= false;
1131 for (auto const& postItField
: mvPostItFields
)
1133 if (!postItField
->UseElement(*mpWrtShell
->GetLayout(), rIDRA
))
1135 OSL_FAIL("PostIt is not in doc!");
1140 if (postItField
->mpPostIt
)
1142 postItField
->mpPostIt
->HideNote();
1143 if (postItField
->mpPostIt
->HasChildPathFocus())
1145 SetActiveSidebarWin(nullptr);
1146 postItField
->mpPostIt
->GrabFocusToDocument();
1152 CheckForRemovedPostIts();
1155 // notes scrollbar is otherwise not drawn correctly for some cases
1156 // scrollbar area is enough
1158 mpEditWin
->Invalidate(); /*This is a super expensive relayout and render of the entire page*/
1160 mbLayouting
= false;
1164 mpEditWin
->EnableMapMode(false);
1167 bool SwPostItMgr::BorderOverPageBorder(tools::ULong aPage
) const
1169 if ( mPages
[aPage
-1]->mvSidebarItems
.empty() )
1171 OSL_FAIL("Notes SidePane painted but no rects and page lists calculated!");
1175 auto aItem
= mPages
[aPage
-1]->mvSidebarItems
.end();
1177 OSL_ENSURE ((*aItem
)->mpPostIt
,"BorderOverPageBorder: NULL postIt, should never happen");
1178 if ((*aItem
)->mpPostIt
)
1180 const tools::Long aSidebarheight
= mPages
[aPage
-1]->bScrollbar
? mpEditWin
->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height() : 0;
1181 const tools::Long aEndValue
= mpEditWin
->PixelToLogic(Point(0,(*aItem
)->mpPostIt
->GetPosPixel().Y()+(*aItem
)->mpPostIt
->GetSizePixel().Height())).Y();
1182 return aEndValue
<= mPages
[aPage
-1]->mPageRect
.Bottom()-aSidebarheight
;
1188 void SwPostItMgr::DrawNotesForPage(OutputDevice
*pOutDev
, sal_uInt32 nPage
)
1190 assert(nPage
< mPages
.size());
1191 if (nPage
>= mPages
.size())
1193 for (auto const& pItem
: mPages
[nPage
]->mvSidebarItems
)
1195 SwAnnotationWin
* pPostIt
= pItem
->mpPostIt
;
1198 Point
aPoint(mpEditWin
->PixelToLogic(pPostIt
->GetPosPixel()));
1199 pPostIt
->DrawForPage(pOutDev
, aPoint
);
1203 void SwPostItMgr::PaintTile(OutputDevice
& rRenderContext
)
1205 for (const std::unique_ptr
<SwAnnotationItem
>& pItem
: mvPostItFields
)
1207 SwAnnotationWin
* pPostIt
= pItem
->mpPostIt
;
1211 bool bEnableMapMode
= !mpEditWin
->IsMapModeEnabled();
1212 mpEditWin
->EnableMapMode();
1213 rRenderContext
.Push(vcl::PushFlags::MAPMODE
);
1214 Point
aOffset(mpEditWin
->PixelToLogic(pPostIt
->GetPosPixel()));
1215 MapMode
aMapMode(rRenderContext
.GetMapMode());
1216 aMapMode
.SetOrigin(aMapMode
.GetOrigin() + aOffset
);
1217 rRenderContext
.SetMapMode(aMapMode
);
1218 Size
aSize(rRenderContext
.PixelToLogic(pPostIt
->GetSizePixel()));
1219 tools::Rectangle
aRectangle(Point(0, 0), aSize
);
1221 pPostIt
->PaintTile(rRenderContext
, aRectangle
);
1223 rRenderContext
.Pop();
1225 mpEditWin
->EnableMapMode(false);
1229 void SwPostItMgr::Scroll(const tools::Long lScroll
,const tools::ULong aPage
)
1231 OSL_ENSURE((lScroll
% GetScrollSize() )==0,"SwPostItMgr::Scroll: scrolling by wrong value");
1232 // do not scroll more than necessary up or down
1233 if ( ((mPages
[aPage
-1]->lOffset
== 0) && (lScroll
>0)) || ( BorderOverPageBorder(aPage
) && (lScroll
<0)) )
1236 const bool bOldUp
= ArrowEnabled(KEY_PAGEUP
,aPage
);
1237 const bool bOldDown
= ArrowEnabled(KEY_PAGEDOWN
,aPage
);
1238 const tools::Long aSidebarheight
= mpEditWin
->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height();
1239 for (auto const& item
: mPages
[aPage
-1]->mvSidebarItems
)
1241 SwAnnotationWin
* pPostIt
= item
->mpPostIt
;
1242 // if this is an answer, we should take the normal position and not the real, slightly moved position
1243 pPostIt
->SetVirtualPosSize(pPostIt
->GetPosPixel(),pPostIt
->GetSizePixel());
1244 pPostIt
->TranslateTopPosition(lScroll
);
1248 bool bBottom
= mpEditWin
->PixelToLogic(Point(0,pPostIt
->VirtualPos().Y()+pPostIt
->VirtualSize().Height())).Y() <= (mPages
[aPage
-1]->mPageRect
.Bottom()-aSidebarheight
);
1249 bool bTop
= mpEditWin
->PixelToLogic(Point(0,pPostIt
->VirtualPos().Y())).Y() >= (mPages
[aPage
-1]->mPageRect
.Top()+aSidebarheight
);
1250 if ( bBottom
&& bTop
)
1252 pPostIt
->ShowNote();
1256 if ( mpEditWin
->PixelToLogic(Point(0,pPostIt
->VirtualPos().Y())).Y() < (mPages
[aPage
-1]->mPageRect
.Top()+aSidebarheight
))
1258 if (mPages
[aPage
-1]->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::LEFT
)
1259 pPostIt
->ShowAnchorOnly(Point(mPages
[aPage
-1]->mPageRect
.Left(),mPages
[aPage
-1]->mPageRect
.Top()));
1260 else if (mPages
[aPage
-1]->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::RIGHT
)
1261 pPostIt
->ShowAnchorOnly(Point(mPages
[aPage
-1]->mPageRect
.Right(),mPages
[aPage
-1]->mPageRect
.Top()));
1265 if (mPages
[aPage
-1]->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::LEFT
)
1266 pPostIt
->ShowAnchorOnly(Point(mPages
[aPage
-1]->mPageRect
.Left(),mPages
[aPage
-1]->mPageRect
.Bottom()));
1267 else if (mPages
[aPage
-1]->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::RIGHT
)
1268 pPostIt
->ShowAnchorOnly(Point(mPages
[aPage
-1]->mPageRect
.Right(),mPages
[aPage
-1]->mPageRect
.Bottom()));
1273 mPages
[aPage
-1]->lOffset
+= lScroll
;
1274 if ( (bOldUp
!= ArrowEnabled(KEY_PAGEUP
,aPage
)) ||(bOldDown
!= ArrowEnabled(KEY_PAGEDOWN
,aPage
)) )
1276 mpEditWin
->Invalidate(GetBottomScrollRect(aPage
));
1277 mpEditWin
->Invalidate(GetTopScrollRect(aPage
));
1281 void SwPostItMgr::AutoScroll(const SwAnnotationWin
* pPostIt
,const tools::ULong aPage
)
1283 // otherwise all notes are visible
1284 if (!mPages
[aPage
-1]->bScrollbar
)
1287 const tools::Long aSidebarheight
= mpEditWin
->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height();
1288 const bool bBottom
= mpEditWin
->PixelToLogic(Point(0,pPostIt
->GetPosPixel().Y()+pPostIt
->GetSizePixel().Height())).Y() <= (mPages
[aPage
-1]->mPageRect
.Bottom()-aSidebarheight
);
1289 const bool bTop
= mpEditWin
->PixelToLogic(Point(0,pPostIt
->GetPosPixel().Y())).Y() >= (mPages
[aPage
-1]->mPageRect
.Top()+aSidebarheight
);
1290 if ( !(bBottom
&& bTop
))
1292 const tools::Long aDiff
= bBottom
? mpEditWin
->LogicToPixel(Point(0,mPages
[aPage
-1]->mPageRect
.Top() + aSidebarheight
)).Y() - pPostIt
->GetPosPixel().Y() :
1293 mpEditWin
->LogicToPixel(Point(0,mPages
[aPage
-1]->mPageRect
.Bottom() - aSidebarheight
)).Y() - (pPostIt
->GetPosPixel().Y()+pPostIt
->GetSizePixel().Height());
1294 // this just adds the missing value to get the next a* GetScrollSize() after aDiff
1295 // e.g aDiff= 61 POSTIT_SCROLL=50 --> lScroll = 100
1296 const auto nScrollSize
= GetScrollSize();
1297 assert(nScrollSize
);
1298 const tools::Long lScroll
= bBottom
? (aDiff
+ ( nScrollSize
- (aDiff
% nScrollSize
))) : (aDiff
- (nScrollSize
+ (aDiff
% nScrollSize
)));
1299 Scroll(lScroll
, aPage
);
1303 void SwPostItMgr::MakeVisible(const SwAnnotationWin
* pPostIt
)
1305 tools::Long aPage
= -1;
1306 // we don't know the page yet, let's find it ourselves
1307 std::vector
<SwPostItPageItem
*>::size_type n
=0;
1308 for (auto const& page
: mPages
)
1310 for (auto const& item
: page
->mvSidebarItems
)
1312 if (item
->mpPostIt
==pPostIt
)
1321 AutoScroll(pPostIt
,aPage
);
1322 tools::Rectangle
aNoteRect (Point(pPostIt
->GetPosPixel().X(),pPostIt
->GetPosPixel().Y()-5),pPostIt
->GetSizePixel());
1323 if (!aNoteRect
.IsEmpty())
1324 mpWrtShell
->MakeVisible(SwRect(mpEditWin
->PixelToLogic(aNoteRect
)));
1327 bool SwPostItMgr::ArrowEnabled(sal_uInt16 aDirection
,tools::ULong aPage
) const
1333 return (mPages
[aPage
-1]->lOffset
!= 0);
1337 return (!BorderOverPageBorder(aPage
));
1339 default: return false;
1343 Color
SwPostItMgr::GetArrowColor(sal_uInt16 aDirection
,tools::ULong aPage
) const
1345 if (ArrowEnabled(aDirection
,aPage
))
1347 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode())
1350 return COL_NOTES_SIDEPANE_ARROW_ENABLED
;
1354 return COL_NOTES_SIDEPANE_ARROW_DISABLED
;
1358 bool SwPostItMgr::LayoutByPage(std::vector
<SwAnnotationWin
*> &aVisiblePostItList
, const tools::Rectangle
& rBorder
, tools::Long lNeededHeight
)
1360 /*** General layout idea:***/
1361 // - if we have space left, we always move the current one up,
1362 // otherwise the next one down
1363 // - first all notes are resized
1364 // - then the real layout starts
1366 //rBorder is the page rect
1367 const tools::Rectangle aBorder
= mpEditWin
->LogicToPixel(rBorder
);
1368 tools::Long lTopBorder
= aBorder
.Top() + 5;
1369 tools::Long lBottomBorder
= aBorder
.Bottom() - 5;
1370 const tools::Long lVisibleHeight
= lBottomBorder
- lTopBorder
; //aBorder.GetHeight() ;
1371 const size_t nPostItListSize
= aVisiblePostItList
.size();
1372 tools::Long lTranslatePos
= 0;
1373 bool bScrollbars
= false;
1375 // do all necessary resizings
1376 if (nPostItListSize
> 0 && lVisibleHeight
< lNeededHeight
)
1378 // ok, now we have to really resize and adding scrollbars
1379 const tools::Long lAverageHeight
= (lVisibleHeight
- nPostItListSize
*GetSpaceBetween()) / nPostItListSize
;
1380 if (lAverageHeight
<GetMinimumSizeWithMeta())
1383 lTopBorder
+= GetSidebarScrollerHeight() + 10;
1384 lBottomBorder
-= (GetSidebarScrollerHeight() + 10);
1385 for (auto const& visiblePostIt
: aVisiblePostItList
)
1386 visiblePostIt
->SetSize(Size(visiblePostIt
->VirtualSize().getWidth(),visiblePostIt
->GetMinimumSizeWithMeta()));
1390 for (auto const& visiblePostIt
: aVisiblePostItList
)
1392 if ( visiblePostIt
->VirtualSize().getHeight() > lAverageHeight
)
1393 visiblePostIt
->SetSize(Size(visiblePostIt
->VirtualSize().getWidth(),lAverageHeight
));
1398 //start the real layout so nothing overlaps anymore
1399 if (aVisiblePostItList
.size()>1)
1403 // if no window is moved anymore we are finished
1408 tools::Long lSpaceUsed
= lTopBorder
+ GetSpaceBetween();
1409 for(auto i
= aVisiblePostItList
.begin(); i
!= aVisiblePostItList
.end() ; ++i
)
1411 auto aNextPostIt
= i
;
1414 if (aNextPostIt
!= aVisiblePostItList
.end())
1416 lTranslatePos
= ( (*i
)->VirtualPos().Y() + (*i
)->VirtualSize().Height()) - (*aNextPostIt
)->VirtualPos().Y();
1417 if (lTranslatePos
> 0) // note windows overlaps the next one
1419 // we are not done yet, loop at least once more
1421 // if there is space left, move the current note up
1422 // it could also happen that there is no space left for the first note due to a scrollbar
1423 // then we also jump into, so we move the current one up and the next one down
1424 if ( (lSpaceUsed
<= (*i
)->VirtualPos().Y()) || (i
==aVisiblePostItList
.begin()))
1426 // we have space left, so let's move the current one up
1427 if ( ((*i
)->VirtualPos().Y()- lTranslatePos
- GetSpaceBetween()) > lTopBorder
)
1429 if ((*aNextPostIt
)->IsFollow())
1430 (*i
)->TranslateTopPosition(-1*(lTranslatePos
+ANCHORLINE_WIDTH
));
1432 (*i
)->TranslateTopPosition(-1*(lTranslatePos
+GetSpaceBetween()));
1436 tools::Long lMoveUp
= (*i
)->VirtualPos().Y() - lTopBorder
;
1437 (*i
)->TranslateTopPosition(-1* lMoveUp
);
1438 if ((*aNextPostIt
)->IsFollow())
1439 (*aNextPostIt
)->TranslateTopPosition( (lTranslatePos
+ANCHORLINE_WIDTH
) - lMoveUp
);
1441 (*aNextPostIt
)->TranslateTopPosition( (lTranslatePos
+GetSpaceBetween()) - lMoveUp
);
1446 // no space left, left move the next one down
1447 if ((*aNextPostIt
)->IsFollow())
1448 (*aNextPostIt
)->TranslateTopPosition(lTranslatePos
+ANCHORLINE_WIDTH
);
1450 (*aNextPostIt
)->TranslateTopPosition(lTranslatePos
+GetSpaceBetween());
1455 // the first one could overlap the topborder instead of a second note
1456 if (i
==aVisiblePostItList
.begin())
1458 tools::Long lMoveDown
= lTopBorder
- (*i
)->VirtualPos().Y();
1462 (*i
)->TranslateTopPosition( lMoveDown
);
1466 if ( (*aNextPostIt
)->IsFollow() )
1467 lSpaceUsed
+= (*i
)->VirtualSize().Height() + ANCHORLINE_WIDTH
;
1469 lSpaceUsed
+= (*i
)->VirtualSize().Height() + GetSpaceBetween();
1473 //(*i) is the last visible item
1474 auto aPrevPostIt
= i
;
1476 lTranslatePos
= ( (*aPrevPostIt
)->VirtualPos().Y() + (*aPrevPostIt
)->VirtualSize().Height() ) - (*i
)->VirtualPos().Y();
1477 if (lTranslatePos
> 0)
1480 if ( ((*i
)->VirtualPos().Y()+ (*i
)->VirtualSize().Height()+lTranslatePos
) < lBottomBorder
)
1482 if ( (*i
)->IsFollow() )
1483 (*i
)->TranslateTopPosition(lTranslatePos
+ANCHORLINE_WIDTH
);
1485 (*i
)->TranslateTopPosition(lTranslatePos
+GetSpaceBetween());
1489 (*i
)->TranslateTopPosition(lBottomBorder
- ((*i
)->VirtualPos().Y()+ (*i
)->VirtualSize().Height()) );
1494 // note does not overlap, but we might be over the lower border
1495 // only do this if there are no scrollbars, otherwise notes are supposed to overlap the border
1496 if (!bScrollbars
&& ((*i
)->VirtualPos().Y()+ (*i
)->VirtualSize().Height() > lBottomBorder
) )
1499 (*i
)->TranslateTopPosition(lBottomBorder
- ((*i
)->VirtualPos().Y()+ (*i
)->VirtualSize().Height()));
1504 // security check so we don't loop forever
1505 if (loop
>MAX_LOOP_COUNT
)
1507 OSL_FAIL("PostItMgr::Layout(): We are looping forever");
1514 // only one left, make sure it is not hidden at the top or bottom
1515 auto i
= aVisiblePostItList
.begin();
1516 lTranslatePos
= lTopBorder
- (*i
)->VirtualPos().Y();
1517 if (lTranslatePos
>0)
1519 (*i
)->TranslateTopPosition(lTranslatePos
+GetSpaceBetween());
1521 lTranslatePos
= lBottomBorder
- ((*i
)->VirtualPos().Y()+ (*i
)->VirtualSize().Height());
1522 if (lTranslatePos
<0)
1524 (*i
)->TranslateTopPosition(lTranslatePos
);
1530 std::vector
<SwFormatField
*> SwPostItMgr::UpdatePostItsParentInfo()
1532 IDocumentRedlineAccess
const& rIDRA(mpWrtShell
->getIDocumentRedlineAccess());
1533 SwFieldType
* pType
= mpView
->GetDocShell()->GetDoc()->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Postit
, OUString(),false);
1534 std::vector
<SwFormatField
*> vFormatFields
;
1535 pType
->CollectPostIts(vFormatFields
, rIDRA
, mpWrtShell
->GetLayout()->IsHideRedlines());
1537 for (std::vector
<SwFormatField
*>::iterator i
= vFormatFields
.begin(); i
!= vFormatFields
.end(); i
++)
1539 SwPostItField
*pChildPostIt
= static_cast<SwPostItField
*>((*i
)->GetField());
1541 if (pChildPostIt
->GetParentId() != 0 || !pChildPostIt
->GetParentName().isEmpty())
1543 for (std::vector
<SwFormatField
*>::iterator j
= vFormatFields
.begin(); j
!= vFormatFields
.end(); j
++)
1545 SwPostItField
*pParentPostIt
= static_cast<SwPostItField
*>((*j
)->GetField());
1546 if (pChildPostIt
->GetParentId() != 0 && pParentPostIt
->GetParaId() == pChildPostIt
->GetParentId())
1548 pChildPostIt
->SetParentPostItId(pParentPostIt
->GetPostItId());
1549 pChildPostIt
->SetParentName(pParentPostIt
->GetName());
1551 else if (!pParentPostIt
->GetName().isEmpty() && pParentPostIt
->GetName() == pChildPostIt
->GetParentName())
1553 pChildPostIt
->SetParentPostItId(pParentPostIt
->GetPostItId());
1554 pChildPostIt
->SetParentName(pParentPostIt
->GetName());
1559 return vFormatFields
;
1563 void SwPostItMgr::AddPostIts(const bool bCheckExistence
, const bool bFocus
)
1565 const bool bEmpty
= mvPostItFields
.empty();
1566 std::vector
<SwFormatField
*> vFormatFields
= UpdatePostItsParentInfo();
1568 for(auto pFormatField
: vFormatFields
)
1569 InsertItem(pFormatField
, bCheckExistence
, bFocus
);
1570 // if we just added the first one we have to update the view for centering
1571 if (bEmpty
&& !mvPostItFields
.empty())
1575 void SwPostItMgr::RemoveSidebarWin()
1577 for (auto& postItField
: mvPostItFields
)
1579 EndListening( *const_cast<SfxBroadcaster
*>(postItField
->GetBroadcaster()) );
1580 postItField
->mpPostIt
.disposeAndClear();
1581 postItField
.reset();
1583 mvPostItFields
.clear();
1585 // all postits removed, no items should be left in pages
1586 PreparePageContainer();
1589 static bool ConfirmDeleteAll(SwView
& pView
, const OUString
& sText
)
1591 const bool bAsk
= officecfg::Office::Common::Misc::QueryDeleteAllComments::get();
1592 bool bConfirm
= true;
1595 VclAbstractDialogFactory
* pFact
= VclAbstractDialogFactory::Create();
1597 = pFact
->CreateQueryDialog(pView
.GetFrameWeld(),
1598 SwResId(STR_QUERY_DELALLCOMMENTS_TITLE
), sText
, "", true);
1599 sal_Int32 nResult
= pDlg
->Execute();
1600 if (pDlg
->ShowAgain() == false)
1602 std::shared_ptr
<comphelper::ConfigurationChanges
> xChanges(
1603 comphelper::ConfigurationChanges::create());
1604 officecfg::Office::Common::Misc::QueryDeleteAllComments::set(false, xChanges
);
1607 bConfirm
= (nResult
== RET_YES
);
1608 pDlg
->disposeOnce();
1613 // copy to new vector, otherwise RemoveItem would operate and delete stuff on mvPostItFields as well
1614 // RemoveItem will clean up the core field and visible postit if necessary
1615 // we cannot just delete everything as before, as postits could move into change tracking
1616 void SwPostItMgr::Delete(const OUString
& rAuthor
)
1618 OUString sQuestion
= SwResId(STR_QUERY_DELALLCOMMENTSAUTHOR_QUESTION
);
1619 sQuestion
= sQuestion
.replaceAll("%AUTHOR", rAuthor
);
1620 if (!ConfirmDeleteAll(mpWrtShell
->GetView(), sQuestion
))
1623 mpWrtShell
->StartAllAction();
1624 if (HasActiveSidebarWin() && (GetActiveSidebarWin()->GetAuthor() == rAuthor
))
1626 SetActiveSidebarWin(nullptr);
1628 SwRewriter aRewriter
;
1629 aRewriter
.AddRule(UndoArg1
, SwResId(STR_DELETE_AUTHOR_NOTES
) + rAuthor
);
1630 mpWrtShell
->StartUndo( SwUndoId::DELETE
, &aRewriter
);
1632 IsPostitFieldWithAuthorOf
aFilter(rAuthor
);
1633 IDocumentRedlineAccess
const& rIDRA(mpWrtShell
->getIDocumentRedlineAccess());
1634 IsFieldNotDeleted
aFilter2(rIDRA
, aFilter
);
1635 FieldDocWatchingStack
aStack(mvPostItFields
, *mpView
->GetDocShell(), aFilter2
);
1636 while (const SwFormatField
* pField
= aStack
.pop())
1638 if (mpWrtShell
->GotoField(*pField
))
1639 mpWrtShell
->DelRight();
1641 mpWrtShell
->EndUndo();
1643 mpWrtShell
->EndAllAction();
1649 void SwPostItMgr::Delete(sal_uInt32 nPostItId
)
1651 mpWrtShell
->StartAllAction();
1652 if (HasActiveSidebarWin() &&
1653 mpActivePostIt
->GetPostItField()->GetPostItId() == nPostItId
)
1655 SetActiveSidebarWin(nullptr);
1657 SwRewriter aRewriter
;
1658 aRewriter
.AddRule(UndoArg1
, SwResId(STR_CONTENT_TYPE_SINGLE_POSTIT
));
1659 mpWrtShell
->StartUndo( SwUndoId::DELETE
, &aRewriter
);
1661 IsPostitFieldWithPostitId
aFilter(nPostItId
);
1662 IDocumentRedlineAccess
const& rIDRA(mpWrtShell
->getIDocumentRedlineAccess());
1663 IsFieldNotDeleted
aFilter2(rIDRA
, aFilter
);
1664 FieldDocWatchingStack
aStack(mvPostItFields
, *mpView
->GetDocShell(), aFilter2
);
1665 const SwFormatField
* pField
= aStack
.pop();
1666 if (pField
&& mpWrtShell
->GotoField(*pField
))
1667 mpWrtShell
->DelRight();
1668 mpWrtShell
->EndUndo();
1670 mpWrtShell
->EndAllAction();
1676 void SwPostItMgr::DeleteCommentThread(sal_uInt32 nPostItId
)
1678 mpWrtShell
->StartAllAction();
1680 SwRewriter aRewriter
;
1681 aRewriter
.AddRule(UndoArg1
, SwResId(STR_CONTENT_TYPE_SINGLE_POSTIT
));
1683 // We have no undo ID at the moment.
1685 IsPostitFieldWithPostitId
aFilter(nPostItId
);
1686 FieldDocWatchingStack
aStack(mvPostItFields
, *mpView
->GetDocShell(), aFilter
);
1687 const SwFormatField
* pField
= aStack
.pop();
1688 // pField now contains our AnnotationWin object
1690 SwAnnotationWin
* pWin
= GetSidebarWin(pField
);
1691 pWin
->DeleteThread();
1694 mpWrtShell
->EndAllAction();
1700 void SwPostItMgr::ToggleResolved(sal_uInt32 nPostItId
)
1702 mpWrtShell
->StartAllAction();
1704 SwRewriter aRewriter
;
1705 aRewriter
.AddRule(UndoArg1
, SwResId(STR_CONTENT_TYPE_SINGLE_POSTIT
));
1707 // We have no undo ID at the moment.
1709 IsPostitFieldWithPostitId
aFilter(nPostItId
);
1710 FieldDocWatchingStack
aStack(mvPostItFields
, *mpView
->GetDocShell(), aFilter
);
1711 const SwFormatField
* pField
= aStack
.pop();
1712 // pField now contains our AnnotationWin object
1714 SwAnnotationWin
* pWin
= GetSidebarWin(pField
);
1715 pWin
->ToggleResolved();
1719 mpWrtShell
->EndAllAction();
1725 void SwPostItMgr::ToggleResolvedForThread(sal_uInt32 nPostItId
)
1727 mpWrtShell
->StartAllAction();
1729 SwRewriter aRewriter
;
1730 aRewriter
.AddRule(UndoArg1
, SwResId(STR_CONTENT_TYPE_SINGLE_POSTIT
));
1732 // We have no undo ID at the moment.
1734 IsPostitFieldWithPostitId
aFilter(nPostItId
);
1735 FieldDocWatchingStack
aStack(mvPostItFields
, *mpView
->GetDocShell(), aFilter
);
1736 const SwFormatField
* pField
= aStack
.pop();
1737 // pField now contains our AnnotationWin object
1739 SwAnnotationWin
* pWin
= GetSidebarWin(pField
);
1740 pWin
->ToggleResolvedForThread();
1744 mpWrtShell
->EndAllAction();
1751 void SwPostItMgr::Delete()
1753 if (!ConfirmDeleteAll(mpWrtShell
->GetView(), SwResId(STR_QUERY_DELALLCOMMENTS_QUESTION
)))
1756 mpWrtShell
->StartAllAction();
1757 SetActiveSidebarWin(nullptr);
1758 SwRewriter aRewriter
;
1759 aRewriter
.AddRule(UndoArg1
, SwResId(STR_DELETE_ALL_NOTES
) );
1760 mpWrtShell
->StartUndo( SwUndoId::DELETE
, &aRewriter
);
1762 IsPostitField aFilter
;
1763 IDocumentRedlineAccess
const& rIDRA(mpWrtShell
->getIDocumentRedlineAccess());
1764 IsFieldNotDeleted
aFilter2(rIDRA
, aFilter
);
1765 FieldDocWatchingStack
aStack(mvPostItFields
, *mpView
->GetDocShell(),
1767 while (const SwFormatField
* pField
= aStack
.pop())
1769 if (mpWrtShell
->GotoField(*pField
))
1770 mpWrtShell
->DelRight();
1773 mpWrtShell
->EndUndo();
1775 mpWrtShell
->EndAllAction();
1781 void SwPostItMgr::PromoteToRoot(sal_uInt32 nPostItId
)
1783 mpWrtShell
->StartAllAction();
1785 SwRewriter aRewriter
;
1786 aRewriter
.AddRule(UndoArg1
, SwResId(STR_CONTENT_TYPE_SINGLE_POSTIT
));
1788 // We have no undo ID at the moment.
1790 IsPostitFieldWithPostitId
aFilter(nPostItId
);
1791 FieldDocWatchingStack
aStack(mvPostItFields
, *mpView
->GetDocShell(), aFilter
);
1792 const SwFormatField
* pField
= aStack
.pop();
1793 // pField now contains our AnnotationWin object
1796 SwAnnotationWin
* pWin
= GetSidebarWin(pField
);
1800 mpWrtShell
->EndAllAction();
1806 void SwPostItMgr::MoveSubthreadToRoot(const sw::annotation::SwAnnotationWin
* pNewRoot
)
1808 std::vector
<std::unique_ptr
<SwAnnotationItem
>>::iterator first
, middle
, last
;
1809 first
= std::find_if(mvPostItFields
.begin(), mvPostItFields
.end(),
1810 [&pNewRoot
](const std::unique_ptr
<SwAnnotationItem
>& pField
) {
1811 return pField
->mpPostIt
== pNewRoot
;
1813 if (first
== mvPostItFields
.end())
1815 std::set
<int> aPostItIds
;
1816 aPostItIds
.insert(pNewRoot
->GetPostItField()->GetPostItId());
1818 while (middle
!= mvPostItFields
.end()
1819 && aPostItIds
.contains((*middle
)->mpPostIt
->GetPostItField()->GetParentPostItId()))
1821 aPostItIds
.insert((*middle
)->mpPostIt
->GetPostItField()->GetPostItId());
1824 if (middle
== mvPostItFields
.end())
1827 while (last
!= mvPostItFields
.end()
1828 && (*last
)->mpPostIt
->GetPostItField()->GetParentPostItId() != 0)
1832 std::rotate(first
, middle
, last
);
1837 void SwPostItMgr::ExecuteFormatAllDialog(SwView
& rView
)
1839 if (mvPostItFields
.empty())
1841 sw::annotation::SwAnnotationWin
*pOrigActiveWin
= GetActiveSidebarWin();
1842 sw::annotation::SwAnnotationWin
*pWin
= pOrigActiveWin
;
1845 for (auto const& postItField
: mvPostItFields
)
1847 pWin
= postItField
->mpPostIt
;
1854 SetActiveSidebarWin(pWin
);
1855 OutlinerView
* pOLV
= pWin
->GetOutlinerView();
1856 SfxItemSet
aEditAttr(pOLV
->GetAttribs());
1857 SfxItemPool
* pPool(SwAnnotationShell::GetAnnotationPool(rView
));
1858 auto xDlgAttr
= std::make_shared
<SfxItemSetFixed
<XATTR_FILLSTYLE
, XATTR_FILLCOLOR
, EE_ITEMS_START
, EE_ITEMS_END
>>(*pPool
);
1859 xDlgAttr
->Put(aEditAttr
);
1860 SwAbstractDialogFactory
* pFact
= SwAbstractDialogFactory::Create();
1861 VclPtr
<SfxAbstractTabDialog
> pDlg(pFact
->CreateSwCharDlg(rView
.GetFrameWeld(), rView
, *xDlgAttr
, SwCharDlgMode::Ann
));
1862 pDlg
->StartExecuteAsync(
1863 [this, pDlg
, xDlgAttr
=std::move(xDlgAttr
), pOrigActiveWin
] (sal_Int32 nResult
)->void
1865 if (nResult
== RET_OK
)
1867 auto aNewAttr
= *xDlgAttr
;
1868 aNewAttr
.Put(*pDlg
->GetOutputItemSet());
1869 FormatAll(aNewAttr
);
1871 pDlg
->disposeOnce();
1872 SetActiveSidebarWin(pOrigActiveWin
);
1877 void SwPostItMgr::FormatAll(const SfxItemSet
&rNewAttr
)
1879 mpWrtShell
->StartAllAction();
1880 SwRewriter aRewriter
;
1881 aRewriter
.AddRule(UndoArg1
, SwResId(STR_FORMAT_ALL_NOTES
) );
1882 mpWrtShell
->StartUndo( SwUndoId::INSATTR
, &aRewriter
);
1884 for (auto const& postItField
: mvPostItFields
)
1886 if (!postItField
->mpPostIt
)
1888 OutlinerView
* pOLV
= postItField
->mpPostIt
->GetOutlinerView();
1889 //save old selection
1890 ESelection
aOrigSel(pOLV
->GetSelection());
1892 Outliner
*pOutliner
= pOLV
->GetOutliner();
1895 sal_Int32 nParaCount
= pOutliner
->GetParagraphCount();
1897 pOLV
->SelectRange(0, nParaCount
);
1899 //set new char properties
1900 pOLV
->SetAttribs(rNewAttr
);
1901 //restore old selection
1902 pOLV
->SetSelection(aOrigSel
);
1903 // tdf#91596 store updated formatting in SwField
1904 postItField
->mpPostIt
->UpdateData();
1907 mpWrtShell
->EndUndo();
1909 mpWrtShell
->EndAllAction();
1915 void SwPostItMgr::Hide( std::u16string_view rAuthor
)
1917 for (auto const& postItField
: mvPostItFields
)
1919 if ( postItField
->mpPostIt
&& (postItField
->mpPostIt
->GetAuthor() == rAuthor
) )
1921 postItField
->mbShow
= false;
1922 postItField
->mpPostIt
->HideNote();
1929 void SwPostItMgr::Hide()
1931 for (auto const& postItField
: mvPostItFields
)
1933 postItField
->mbShow
= false;
1934 if (postItField
->mpPostIt
)
1935 postItField
->mpPostIt
->HideNote();
1939 SwAnnotationWin
* SwPostItMgr::GetSidebarWin( const SfxBroadcaster
* pBroadcaster
) const
1941 for (auto const& postItField
: mvPostItFields
)
1943 if ( postItField
->GetBroadcaster() == pBroadcaster
)
1944 return postItField
->mpPostIt
;
1949 sw::annotation::SwAnnotationWin
* SwPostItMgr::GetAnnotationWin(const SwPostItField
* pField
) const
1951 for (auto const& postItField
: mvPostItFields
)
1953 if ( postItField
->GetFormatField().GetField() == pField
)
1954 return postItField
->mpPostIt
.get();
1959 sw::annotation::SwAnnotationWin
* SwPostItMgr::GetAnnotationWin(const sal_uInt32 nPostItId
) const
1961 for (auto const& postItField
: mvPostItFields
)
1963 if ( static_cast<const SwPostItField
*>(postItField
->GetFormatField().GetField())->GetPostItId() == nPostItId
)
1964 return postItField
->mpPostIt
.get();
1969 SwPostItField
* SwPostItMgr::GetLatestPostItField()
1971 return static_cast<SwPostItField
*>(mvPostItFields
.back()->GetFormatField().GetField());
1974 sw::annotation::SwAnnotationWin
* SwPostItMgr::GetOrCreateAnnotationWindowForLatestPostItField()
1976 return GetOrCreateAnnotationWindow(*mvPostItFields
.back());
1979 SwAnnotationWin
* SwPostItMgr::GetNextPostIt( sal_uInt16 aDirection
,
1980 SwAnnotationWin
* aPostIt
)
1982 if (mvPostItFields
.size()>1)
1984 auto i
= std::find_if(mvPostItFields
.begin(), mvPostItFields
.end(),
1985 [&aPostIt
](const std::unique_ptr
<SwAnnotationItem
>& pField
) { return pField
->mpPostIt
== aPostIt
; });
1986 if (i
== mvPostItFields
.end())
1989 auto iNextPostIt
= i
;
1990 if (aDirection
== KEY_PAGEUP
)
1992 if ( iNextPostIt
== mvPostItFields
.begin() )
2001 if ( iNextPostIt
== mvPostItFields
.end() )
2006 // let's quit, we are back at the beginning
2007 if ( (*iNextPostIt
)->mpPostIt
== aPostIt
)
2009 return (*iNextPostIt
)->mpPostIt
;
2015 tools::Long
SwPostItMgr::GetNextBorder()
2017 for (auto const& pPage
: mPages
)
2019 for(auto b
= pPage
->mvSidebarItems
.begin(); b
!= pPage
->mvSidebarItems
.end(); ++b
)
2021 if ((*b
)->mpPostIt
== mpActivePostIt
)
2025 bool bFollow
= (aNext
!= pPage
->mvSidebarItems
.end()) && (*aNext
)->mpPostIt
->IsFollow();
2026 if ( pPage
->bScrollbar
|| bFollow
)
2032 //if this is the last item, return the bottom border otherwise the next item
2033 if (aNext
== pPage
->mvSidebarItems
.end())
2034 return mpEditWin
->LogicToPixel(Point(0,pPage
->mPageRect
.Bottom())).Y() - GetSpaceBetween();
2036 return (*aNext
)->mpPostIt
->GetPosPixel().Y() - GetSpaceBetween();
2042 OSL_FAIL("SwPostItMgr::GetNextBorder(): We have to find a next border here");
2046 void SwPostItMgr::SetShadowState(const SwPostItField
* pField
,bool bCursor
)
2050 if (pField
!=mShadowState
.mpShadowField
)
2052 if (mShadowState
.mpShadowField
)
2054 // reset old one if still alive
2055 // TODO: does not work properly if mouse and cursor was set
2056 sw::annotation::SwAnnotationWin
* pOldPostIt
=
2057 GetAnnotationWin(mShadowState
.mpShadowField
);
2058 if (pOldPostIt
&& pOldPostIt
->Shadow() && (pOldPostIt
->Shadow()->GetShadowState() != SS_EDIT
))
2059 pOldPostIt
->SetViewState(ViewState::NORMAL
);
2061 //set new one, if it is not currently edited
2062 sw::annotation::SwAnnotationWin
* pNewPostIt
= GetAnnotationWin(pField
);
2063 if (pNewPostIt
&& pNewPostIt
->Shadow() && (pNewPostIt
->Shadow()->GetShadowState() != SS_EDIT
))
2065 pNewPostIt
->SetViewState(ViewState::VIEW
);
2066 //remember our new field
2067 mShadowState
.mpShadowField
= pField
;
2068 mShadowState
.bCursor
= false;
2069 mShadowState
.bMouse
= false;
2073 mShadowState
.bCursor
= true;
2075 mShadowState
.bMouse
= true;
2079 if (mShadowState
.mpShadowField
)
2082 mShadowState
.bCursor
= false;
2084 mShadowState
.bMouse
= false;
2085 if (!mShadowState
.bCursor
&& !mShadowState
.bMouse
)
2087 // reset old one if still alive
2088 sw::annotation::SwAnnotationWin
* pOldPostIt
= GetAnnotationWin(mShadowState
.mpShadowField
);
2089 if (pOldPostIt
&& pOldPostIt
->Shadow() && (pOldPostIt
->Shadow()->GetShadowState() != SS_EDIT
))
2091 pOldPostIt
->SetViewState(ViewState::NORMAL
);
2092 mShadowState
.mpShadowField
= nullptr;
2099 void SwPostItMgr::PrepareView(bool bIgnoreCount
)
2101 if (!HasNotes() || bIgnoreCount
)
2103 mpWrtShell
->StartAllAction();
2104 SwRootFrame
* pLayout
= mpWrtShell
->GetLayout();
2106 SwPostItHelper::setSidebarChanged( pLayout
,
2107 mpWrtShell
->getIDocumentSettingAccess().get( DocumentSettingId::BROWSE_MODE
) );
2108 mpWrtShell
->EndAllAction();
2112 bool SwPostItMgr::ShowScrollbar(const tools::ULong aPage
) const
2114 if (mPages
.size() > aPage
-1)
2115 return (mPages
[aPage
-1]->bScrollbar
&& !mbWaitingForCalcRects
);
2120 bool SwPostItMgr::IsHit(const Point
& aPointPixel
)
2122 if (!HasNotes() || !ShowNotes())
2125 const Point aPoint
= mpEditWin
->PixelToLogic(aPointPixel
);
2126 tools::Rectangle
aRect(GetSidebarRect(aPoint
));
2127 if (!aRect
.Contains(aPoint
))
2130 // we hit the note's sidebar
2131 // let's now test for the arrow area
2133 const tools::ULong nPageNum
2134 = SwPostItHelper::getPageInfo(aPageFrame
, mpWrtShell
->GetLayout(), aPoint
);
2137 if (mPages
[nPageNum
- 1]->bScrollbar
)
2138 return ScrollbarHit(nPageNum
, aPoint
);
2142 vcl::Window
* SwPostItMgr::IsHitSidebarWindow(const Point
& rPointLogic
)
2144 vcl::Window
* pRet
= nullptr;
2146 if (HasNotes() && ShowNotes())
2148 bool bEnableMapMode
= !mpEditWin
->IsMapModeEnabled();
2150 mpEditWin
->EnableMapMode();
2152 for (const std::unique_ptr
<SwAnnotationItem
>& pItem
: mvPostItFields
)
2154 SwAnnotationWin
* pPostIt
= pItem
->mpPostIt
;
2158 if (pPostIt
->IsHitWindow(rPointLogic
))
2166 mpEditWin
->EnableMapMode(false);
2172 tools::Rectangle
SwPostItMgr::GetSidebarRect(const Point
& rPointLogic
)
2174 const SwRootFrame
* pLayout
= mpWrtShell
->GetLayout();
2176 const tools::ULong nPageNum
= SwPostItHelper::getPageInfo(aPageFrame
, pLayout
, rPointLogic
);
2178 return tools::Rectangle();
2180 return GetSidebarPos(rPointLogic
) == sw::sidebarwindows::SidebarPosition::LEFT
2182 Point(aPageFrame
.Left() - GetSidebarWidth() - GetSidebarBorderWidth(),
2184 Size(GetSidebarWidth(), aPageFrame
.Height()))
2186 Point(aPageFrame
.Right() + GetSidebarBorderWidth(), aPageFrame
.Top()),
2187 Size(GetSidebarWidth(), aPageFrame
.Height()));
2190 bool SwPostItMgr::IsHitSidebarDragArea(const Point
& rPointPx
)
2192 if (!HasNotes() || !ShowNotes())
2195 const Point aPointLogic
= mpEditWin
->PixelToLogic(rPointPx
);
2196 sw::sidebarwindows::SidebarPosition eSidebarPosition
= GetSidebarPos(aPointLogic
);
2197 if (eSidebarPosition
== sw::sidebarwindows::SidebarPosition::NONE
)
2200 tools::Rectangle
aDragArea(GetSidebarRect(aPointLogic
));
2201 aDragArea
.SetTop(aPointLogic
.Y());
2202 if (eSidebarPosition
== sw::sidebarwindows::SidebarPosition::RIGHT
)
2203 aDragArea
.SetPos(Point(aDragArea
.Right() - 50, aDragArea
.Top()));
2205 aDragArea
.SetPos(Point(aDragArea
.Left() - 50, aDragArea
.Top()));
2207 Size
aS(aDragArea
.GetSize());
2209 aDragArea
.SetSize(aS
);
2210 return aDragArea
.Contains(aPointLogic
);
2213 tools::Rectangle
SwPostItMgr::GetBottomScrollRect(const tools::ULong aPage
) const
2215 SwRect aPageRect
= mPages
[aPage
-1]->mPageRect
;
2216 Point aPointBottom
= mPages
[aPage
-1]->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::LEFT
2217 ? Point(aPageRect
.Left() - GetSidebarWidth() - GetSidebarBorderWidth() + mpEditWin
->PixelToLogic(Size(2,0)).Width(),aPageRect
.Bottom()- mpEditWin
->PixelToLogic(Size(0,2+GetSidebarScrollerHeight())).Height())
2218 : Point(aPageRect
.Right() + GetSidebarBorderWidth() + mpEditWin
->PixelToLogic(Size(2,0)).Width(),aPageRect
.Bottom()- mpEditWin
->PixelToLogic(Size(0,2+GetSidebarScrollerHeight())).Height());
2219 Size
aSize(GetSidebarWidth() - mpEditWin
->PixelToLogic(Size(4,0)).Width(), mpEditWin
->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height()) ;
2220 return tools::Rectangle(aPointBottom
,aSize
);
2223 tools::Rectangle
SwPostItMgr::GetTopScrollRect(const tools::ULong aPage
) const
2225 SwRect aPageRect
= mPages
[aPage
-1]->mPageRect
;
2226 Point aPointTop
= mPages
[aPage
-1]->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::LEFT
2227 ? Point(aPageRect
.Left() - GetSidebarWidth() -GetSidebarBorderWidth()+ mpEditWin
->PixelToLogic(Size(2,0)).Width(),aPageRect
.Top() + mpEditWin
->PixelToLogic(Size(0,2)).Height())
2228 : Point(aPageRect
.Right() + GetSidebarBorderWidth() + mpEditWin
->PixelToLogic(Size(2,0)).Width(),aPageRect
.Top() + mpEditWin
->PixelToLogic(Size(0,2)).Height());
2229 Size
aSize(GetSidebarWidth() - mpEditWin
->PixelToLogic(Size(4,0)).Width(), mpEditWin
->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height()) ;
2230 return tools::Rectangle(aPointTop
,aSize
);
2233 //IMPORTANT: if you change the rects here, also change SwPageFrame::PaintNotesSidebar()
2234 bool SwPostItMgr::ScrollbarHit(const tools::ULong aPage
,const Point
&aPoint
)
2236 SwRect aPageRect
= mPages
[aPage
-1]->mPageRect
;
2237 Point aPointBottom
= mPages
[aPage
-1]->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::LEFT
2238 ? Point(aPageRect
.Left() - GetSidebarWidth()-GetSidebarBorderWidth() + mpEditWin
->PixelToLogic(Size(2,0)).Width(),aPageRect
.Bottom()- mpEditWin
->PixelToLogic(Size(0,2+GetSidebarScrollerHeight())).Height())
2239 : Point(aPageRect
.Right() + GetSidebarBorderWidth()+ mpEditWin
->PixelToLogic(Size(2,0)).Width(),aPageRect
.Bottom()- mpEditWin
->PixelToLogic(Size(0,2+GetSidebarScrollerHeight())).Height());
2241 Point aPointTop
= mPages
[aPage
-1]->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::LEFT
2242 ? Point(aPageRect
.Left() - GetSidebarWidth()-GetSidebarBorderWidth()+ mpEditWin
->PixelToLogic(Size(2,0)).Width(),aPageRect
.Top() + mpEditWin
->PixelToLogic(Size(0,2)).Height())
2243 : Point(aPageRect
.Right()+GetSidebarBorderWidth()+ mpEditWin
->PixelToLogic(Size(2,0)).Width(),aPageRect
.Top() + mpEditWin
->PixelToLogic(Size(0,2)).Height());
2245 tools::Rectangle
aRectBottom(GetBottomScrollRect(aPage
));
2246 tools::Rectangle
aRectTop(GetTopScrollRect(aPage
));
2248 if (aRectBottom
.Contains(aPoint
))
2250 if (aPoint
.X() < tools::Long((aPointBottom
.X() + GetSidebarWidth()/3)))
2251 Scroll( GetScrollSize(),aPage
);
2253 Scroll( -1*GetScrollSize(), aPage
);
2256 else if (aRectTop
.Contains(aPoint
))
2258 if (aPoint
.X() < tools::Long((aPointTop
.X() + GetSidebarWidth()/3*2)))
2259 Scroll(GetScrollSize(), aPage
);
2261 Scroll(-1*GetScrollSize(), aPage
);
2267 void SwPostItMgr::CorrectPositions()
2269 if ( mbWaitingForCalcRects
|| mbLayouting
|| mvPostItFields
.empty() )
2272 // find first valid note
2273 SwAnnotationWin
*pFirstPostIt
= nullptr;
2274 for (auto const& postItField
: mvPostItFields
)
2276 pFirstPostIt
= postItField
->mpPostIt
;
2281 //if we have not found a valid note, forget about it and leave
2285 // yeah, I know, if this is a left page it could be wrong, but finding the page and the note is probably not even faster than just doing it
2286 // check, if anchor overlay object exists.
2287 const tools::Long aAnchorX
= pFirstPostIt
->Anchor()
2288 ? mpEditWin
->LogicToPixel( Point(static_cast<tools::Long
>(pFirstPostIt
->Anchor()->GetSixthPosition().getX()),0)).X()
2290 const tools::Long aAnchorY
= pFirstPostIt
->Anchor()
2291 ? mpEditWin
->LogicToPixel( Point(0,static_cast<tools::Long
>(pFirstPostIt
->Anchor()->GetSixthPosition().getY()))).Y() + 1
2293 if (Point(aAnchorX
,aAnchorY
) == pFirstPostIt
->GetPosPixel())
2296 tools::Long aAnchorPosX
= 0;
2297 tools::Long aAnchorPosY
= 0;
2298 for (const std::unique_ptr
<SwPostItPageItem
>& pPage
: mPages
)
2300 for (auto const& item
: pPage
->mvSidebarItems
)
2302 // check, if anchor overlay object exists.
2303 if ( item
->mbShow
&& item
->mpPostIt
&& item
->mpPostIt
->Anchor() )
2305 aAnchorPosX
= pPage
->eSidebarPosition
== sw::sidebarwindows::SidebarPosition::LEFT
2306 ? mpEditWin
->LogicToPixel( Point(static_cast<tools::Long
>(item
->mpPostIt
->Anchor()->GetSeventhPosition().getX()),0)).X()
2307 : mpEditWin
->LogicToPixel( Point(static_cast<tools::Long
>(item
->mpPostIt
->Anchor()->GetSixthPosition().getX()),0)).X();
2308 aAnchorPosY
= mpEditWin
->LogicToPixel( Point(0,static_cast<tools::Long
>(item
->mpPostIt
->Anchor()->GetSixthPosition().getY()))).Y() + 1;
2309 item
->mpPostIt
->SetPosPixel(Point(aAnchorPosX
,aAnchorPosY
));
2315 bool SwPostItMgr::ShowNotes() const
2317 // we only want to see notes if Options - Writer - View - Notes is ticked
2318 return mpWrtShell
->GetViewOptions()->IsPostIts();
2321 bool SwPostItMgr::HasNotes() const
2323 return !mvPostItFields
.empty();
2326 void SwPostItMgr::SetSidebarWidth(const Point
& rPointLogic
)
2328 tools::Rectangle nSidebarRect
= GetSidebarRect(rPointLogic
);
2329 if (nSidebarRect
.IsEmpty())
2332 sw::sidebarwindows::SidebarPosition eSidebarPosition
= GetSidebarPos(rPointLogic
);
2333 if (eSidebarPosition
== sw::sidebarwindows::SidebarPosition::NONE
)
2336 // Calculate the width to be applied in logic units
2337 tools::Long nLogicWidth
;
2338 if (eSidebarPosition
== sw::sidebarwindows::SidebarPosition::RIGHT
)
2339 nLogicWidth
= rPointLogic
.X() - nSidebarRect
.Left();
2341 nLogicWidth
= nSidebarRect
.Right() - rPointLogic
.X();
2343 // The zoom level is conveniently used as reference to define the minimum width
2344 const sal_uInt16 nZoom
= mpWrtShell
->GetViewOptions()->GetZoom();
2345 double nFactor
= static_cast<double>(mpEditWin
->LogicToPixel(Point(nLogicWidth
, 0)).X())
2346 / static_cast<double>(nZoom
);
2347 // The width may vary from 1x to 8x the zoom factor
2348 nFactor
= std::clamp(nFactor
, 1.0, 8.0);
2349 std::shared_ptr
<comphelper::ConfigurationChanges
> xChanges(
2350 comphelper::ConfigurationChanges::create());
2351 officecfg::Office::Writer::Notes::DisplayWidthFactor::set(nFactor
, xChanges
);
2354 // tdf#159146 After resizing the sidebar the layout and the ruler needs to be updated
2355 mpWrtShell
->InvalidateLayout(true);
2356 mpView
->GetHRuler().Invalidate();
2357 mpView
->InvalidateRulerPos();
2362 tools::ULong
SwPostItMgr::GetSidebarWidth(bool bPx
) const
2364 bool bEnableMapMode
= !mpWrtShell
->GetOut()->IsMapModeEnabled();
2365 sal_uInt16 nZoom
= mpWrtShell
->GetViewOptions()->GetZoom();
2366 if (comphelper::LibreOfficeKit::isActive() && !bEnableMapMode
)
2368 // The output device is the tile and contains the real wanted scale factor.
2369 double fScaleX
= double(mpWrtShell
->GetOut()->GetMapMode().GetScaleX());
2370 nZoom
= fScaleX
* 100;
2372 tools::ULong aWidth
= static_cast<tools::ULong
>(
2373 nZoom
* officecfg::Office::Writer::Notes::DisplayWidthFactor::get());
2380 // The output device is the window.
2381 mpWrtShell
->GetOut()->EnableMapMode();
2382 tools::Long nRet
= mpWrtShell
->GetOut()->PixelToLogic(Size(aWidth
, 0)).Width();
2384 mpWrtShell
->GetOut()->EnableMapMode(false);
2389 tools::ULong
SwPostItMgr::GetSidebarBorderWidth(bool bPx
) const
2394 return mpWrtShell
->GetOut()->PixelToLogic(Size(2,0)).Width();
2397 Color
SwPostItMgr::GetColorDark(std::size_t aAuthorIndex
)
2399 Color aColor
= GetColorAnchor(aAuthorIndex
);
2400 svtools::ColorConfig aColorConfig
;
2401 const Color
aBgColor(aColorConfig
.GetColorValue(svtools::DOCCOLOR
).nColor
);
2402 if (aBgColor
.IsDark())
2403 aColor
.DecreaseLuminance(80);
2405 aColor
.IncreaseLuminance(150);
2409 Color
SwPostItMgr::GetColorLight(std::size_t aAuthorIndex
)
2411 Color aColor
= GetColorAnchor(aAuthorIndex
);
2412 svtools::ColorConfig aColorConfig
;
2413 const Color
aBgColor(aColorConfig
.GetColorValue(svtools::DOCCOLOR
).nColor
);
2414 if (aBgColor
.IsDark())
2415 aColor
.DecreaseLuminance(130);
2417 aColor
.IncreaseLuminance(200);
2421 Color
SwPostItMgr::GetColorAnchor(std::size_t aAuthorIndex
)
2423 if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
2425 svtools::ColorConfig aColorConfig
;
2426 switch (aAuthorIndex
% 9)
2428 case 0: return aColorConfig
.GetColorValue(svtools::AUTHOR1
).nColor
;
2429 case 1: return aColorConfig
.GetColorValue(svtools::AUTHOR2
).nColor
;
2430 case 2: return aColorConfig
.GetColorValue(svtools::AUTHOR3
).nColor
;
2431 case 3: return aColorConfig
.GetColorValue(svtools::AUTHOR4
).nColor
;
2432 case 4: return aColorConfig
.GetColorValue(svtools::AUTHOR5
).nColor
;
2433 case 5: return aColorConfig
.GetColorValue(svtools::AUTHOR6
).nColor
;
2434 case 6: return aColorConfig
.GetColorValue(svtools::AUTHOR7
).nColor
;
2435 case 7: return aColorConfig
.GetColorValue(svtools::AUTHOR8
).nColor
;
2436 case 8: return aColorConfig
.GetColorValue(svtools::AUTHOR9
).nColor
;
2443 void SwPostItMgr::SetActiveSidebarWin( SwAnnotationWin
* p
)
2445 if ( p
== mpActivePostIt
)
2448 // we need the temp variable so we can set mpActivePostIt before we call DeactivatePostIt
2449 // therefore we get a new layout in DOCCHANGED when switching from postit to document,
2450 // otherwise, GetActivePostIt() would still hold our old postit
2451 SwAnnotationWin
* pActive
= mpActivePostIt
;
2455 pActive
->DeactivatePostIt();
2456 mShadowState
.mpShadowField
= nullptr;
2460 mpActivePostIt
->GotoPos();
2461 mpView
->AttrChangedNotify(nullptr);
2462 mpActivePostIt
->ActivatePostIt();
2466 IMPL_LINK_NOARG( SwPostItMgr
, CalcHdl
, void*, void )
2468 mnEventId
= nullptr;
2471 OSL_FAIL("Reentrance problem in Layout Manager!");
2472 mbWaitingForCalcRects
= false;
2476 // do not change order, even if it would seem so in the first place, we need the calcrects always
2477 if (CalcRects() || mbLayout
)
2484 void SwPostItMgr::Rescale()
2486 for (auto const& postItField
: mvPostItFields
)
2487 if ( postItField
->mpPostIt
)
2488 postItField
->mpPostIt
->Rescale();
2491 sal_Int32
SwPostItMgr::GetInitialAnchorDistance() const
2493 const Fraction
& f( mpEditWin
->GetMapMode().GetScaleY() );
2494 return sal_Int32(POSTIT_INITIAL_ANCHOR_DISTANCE
* f
);
2497 sal_Int32
SwPostItMgr::GetSpaceBetween() const
2499 const Fraction
& f( mpEditWin
->GetMapMode().GetScaleY() );
2500 return sal_Int32(POSTIT_SPACE_BETWEEN
* f
);
2503 sal_Int32
SwPostItMgr::GetScrollSize() const
2505 const Fraction
& f( mpEditWin
->GetMapMode().GetScaleY() );
2506 return sal_Int32((POSTIT_SPACE_BETWEEN
+ POSTIT_MINIMUMSIZE_WITH_META
) * f
);
2509 sal_Int32
SwPostItMgr::GetMinimumSizeWithMeta() const
2511 const Fraction
& f( mpEditWin
->GetMapMode().GetScaleY() );
2512 return sal_Int32(POSTIT_MINIMUMSIZE_WITH_META
* f
);
2515 sal_Int32
SwPostItMgr::GetSidebarScrollerHeight() const
2517 const Fraction
& f( mpEditWin
->GetMapMode().GetScaleY() );
2518 return sal_Int32(POSTIT_SCROLL_SIDEBAR_HEIGHT
* f
);
2521 void SwPostItMgr::SetSpellChecking()
2523 for (auto const& postItField
: mvPostItFields
)
2524 if ( postItField
->mpPostIt
)
2525 postItField
->mpPostIt
->SetSpellChecking();
2528 void SwPostItMgr::SetReadOnlyState()
2530 for (auto const& postItField
: mvPostItFields
)
2531 if ( postItField
->mpPostIt
)
2532 postItField
->mpPostIt
->SetReadonly( mbReadOnly
);
2535 void SwPostItMgr::CheckMetaText()
2537 for (auto const& postItField
: mvPostItFields
)
2538 if ( postItField
->mpPostIt
)
2539 postItField
->mpPostIt
->CheckMetaText();
2542 void SwPostItMgr::UpdateColors()
2544 for (auto const& postItField
: mvPostItFields
)
2545 if ( postItField
->mpPostIt
)
2547 postItField
->mpPostIt
->UpdateColors();
2548 postItField
->mpPostIt
->Invalidate();
2552 sal_uInt16
SwPostItMgr::Replace(SvxSearchItem
const * pItem
)
2554 SwAnnotationWin
* pWin
= GetActiveSidebarWin();
2555 sal_uInt16 aResult
= pWin
->GetOutlinerView()->StartSearchAndReplace( *pItem
);
2557 SetActiveSidebarWin(nullptr);
2561 sal_uInt16
SwPostItMgr::FinishSearchReplace(const i18nutil::SearchOptions2
& rSearchOptions
, bool bSrchForward
)
2563 SwAnnotationWin
* pWin
= GetActiveSidebarWin();
2564 SvxSearchItem
aItem(SID_SEARCH_ITEM
);
2565 aItem
.SetSearchOptions(rSearchOptions
);
2566 aItem
.SetBackward(!bSrchForward
);
2567 sal_uInt16 aResult
= pWin
->GetOutlinerView()->StartSearchAndReplace( aItem
);
2569 SetActiveSidebarWin(nullptr);
2573 sal_uInt16
SwPostItMgr::SearchReplace(const SwFormatField
&pField
, const i18nutil::SearchOptions2
& rSearchOptions
, bool bSrchForward
)
2575 sal_uInt16 aResult
= 0;
2576 SwAnnotationWin
* pWin
= GetSidebarWin(&pField
);
2579 ESelection aOldSelection
= pWin
->GetOutlinerView()->GetSelection();
2581 pWin
->GetOutlinerView()->SetSelection(ESelection(0, 0));
2583 pWin
->GetOutlinerView()->SetSelection(ESelection::AtEnd());
2584 SvxSearchItem
aItem(SID_SEARCH_ITEM
);
2585 aItem
.SetSearchOptions(rSearchOptions
);
2586 aItem
.SetBackward(!bSrchForward
);
2587 aResult
= pWin
->GetOutlinerView()->StartSearchAndReplace( aItem
);
2589 pWin
->GetOutlinerView()->SetSelection(aOldSelection
);
2592 SetActiveSidebarWin(pWin
);
2599 void SwPostItMgr::AssureStdModeAtShell()
2601 mpWrtShell
->AssureStdMode();
2604 bool SwPostItMgr::HasActiveSidebarWin() const
2606 return mpActivePostIt
!= nullptr;
2609 bool SwPostItMgr::HasActiveAnnotationWin() const
2611 return HasActiveSidebarWin() &&
2612 mpActivePostIt
!= nullptr;
2615 void SwPostItMgr::GrabFocusOnActiveSidebarWin()
2617 if ( HasActiveSidebarWin() )
2619 mpActivePostIt
->GrabFocus();
2623 void SwPostItMgr::UpdateDataOnActiveSidebarWin()
2625 if ( HasActiveSidebarWin() )
2627 mpActivePostIt
->UpdateData();
2631 void SwPostItMgr::DeleteActiveSidebarWin()
2633 if ( HasActiveSidebarWin() )
2635 mpActivePostIt
->Delete();
2639 void SwPostItMgr::HideActiveSidebarWin()
2641 if ( HasActiveSidebarWin() )
2643 mpActivePostIt
->Hide();
2647 void SwPostItMgr::ToggleInsModeOnActiveSidebarWin()
2649 if ( HasActiveSidebarWin() )
2651 mpActivePostIt
->ToggleInsMode();
2655 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
2656 void SwPostItMgr::ConnectSidebarWinToFrame( const SwFrame
& rFrame
,
2657 const SwFormatField
& rFormatField
,
2658 SwAnnotationWin
& rSidebarWin
)
2660 if ( mpFrameSidebarWinContainer
== nullptr )
2662 mpFrameSidebarWinContainer
.reset(new SwFrameSidebarWinContainer());
2665 const bool bInserted
= mpFrameSidebarWinContainer
->insert( rFrame
, rFormatField
, rSidebarWin
);
2667 mpWrtShell
->GetAccessibleMap() )
2669 mpWrtShell
->GetAccessibleMap()->InvalidatePosOrSize( nullptr, nullptr, &rSidebarWin
, SwRect() );
2673 void SwPostItMgr::DisconnectSidebarWinFromFrame( const SwFrame
& rFrame
,
2674 SwAnnotationWin
& rSidebarWin
)
2676 if ( mpFrameSidebarWinContainer
!= nullptr )
2678 const bool bRemoved
= mpFrameSidebarWinContainer
->remove( rFrame
, rSidebarWin
);
2680 mpWrtShell
->GetAccessibleMap() )
2682 mpWrtShell
->GetAccessibleMap()->A11yDispose( nullptr, nullptr, &rSidebarWin
);
2686 #endif // ENABLE_WASM_STRIP_ACCESSIBILITY
2688 bool SwPostItMgr::HasFrameConnectedSidebarWins( const SwFrame
& rFrame
)
2692 if ( mpFrameSidebarWinContainer
!= nullptr )
2694 bRet
= !mpFrameSidebarWinContainer
->empty( rFrame
);
2700 vcl::Window
* SwPostItMgr::GetSidebarWinForFrameByIndex( const SwFrame
& rFrame
,
2701 const sal_Int32 nIndex
)
2703 vcl::Window
* pSidebarWin( nullptr );
2705 if ( mpFrameSidebarWinContainer
!= nullptr )
2707 pSidebarWin
= mpFrameSidebarWinContainer
->get( rFrame
, nIndex
);
2713 void SwPostItMgr::GetAllSidebarWinForFrame( const SwFrame
& rFrame
,
2714 std::vector
< vcl::Window
* >* pChildren
)
2716 if ( mpFrameSidebarWinContainer
!= nullptr )
2718 mpFrameSidebarWinContainer
->getAll( rFrame
, pChildren
);
2722 void SwPostItMgr::ShowHideResolvedNotes(bool visible
) {
2723 for (auto const& pPage
: mPages
)
2725 for(auto b
= pPage
->mvSidebarItems
.begin(); b
!= pPage
->mvSidebarItems
.end(); ++b
)
2727 if ((*b
)->mpPostIt
->IsResolved())
2729 (*b
)->mpPostIt
->SetResolved(true);
2730 (*b
)->mpPostIt
->GetSidebarItem().mbShow
= visible
;
2737 void SwPostItMgr::UpdateResolvedStatus(const sw::annotation::SwAnnotationWin
* topNote
) {
2738 // Given the topmost note as an argument, scans over all notes and sets the
2739 // 'resolved' state of each descendant of the top notes to the resolved state
2741 bool resolved
= topNote
->IsResolved();
2742 for (auto const& pPage
: mPages
)
2744 for(auto b
= pPage
->mvSidebarItems
.begin(); b
!= pPage
->mvSidebarItems
.end(); ++b
)
2746 if((*b
)->mpPostIt
->GetTopReplyNote() == topNote
) {
2747 (*b
)->mpPostIt
->SetResolved(resolved
);
2753 sw::sidebarwindows::SidebarPosition
SwPostItMgr::GetSidebarPos(const Point
& rPointLogic
)
2755 if (const SwRootFrame
* pLayout
= mpWrtShell
->GetLayout())
2757 const SwPageFrame
* pPageFrame
= pLayout
->GetPageAtPos(rPointLogic
, nullptr, true);
2759 return pPageFrame
->SidebarPosition();
2761 return sw::sidebarwindows::SidebarPosition::NONE
;
2764 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */