Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / uibase / docvw / PostItMgr.cxx
blob68c1a00221f70a9432c3f03ca56fca4eb8918371
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
29 #include <accmap.hxx>
31 #include <SidebarWindowsConsts.hxx>
32 #include "AnchorOverlayObject.hxx"
33 #include "ShadowOverlayObject.hxx"
35 #include <utility>
36 #include <vcl/svapp.hxx>
37 #include <vcl/outdev.hxx>
38 #include <vcl/settings.hxx>
40 #include <chrdlgmodes.hxx>
41 #include <viewopt.hxx>
42 #include <view.hxx>
43 #include <docsh.hxx>
44 #include <wrtsh.hxx>
45 #include <doc.hxx>
46 #include <IDocumentSettingAccess.hxx>
47 #include <IDocumentFieldsAccess.hxx>
48 #include <fldbas.hxx>
49 #include <fmtfld.hxx>
50 #include <docufld.hxx>
51 #include <edtwin.hxx>
52 #include <txtfld.hxx>
53 #include <txtannotationfld.hxx>
54 #include <rootfrm.hxx>
55 #include <SwRewriter.hxx>
56 #include <tools/color.hxx>
57 #include <unotools/datetime.hxx>
59 #include <swmodule.hxx>
60 #include <strings.hrc>
61 #include <cmdid.h>
63 #include <sfx2/request.hxx>
64 #include <sfx2/event.hxx>
65 #include <svl/srchitem.hxx>
67 #include <svl/languageoptions.hxx>
68 #include <svl/hint.hxx>
70 #include <svx/svdview.hxx>
71 #include <editeng/eeitem.hxx>
72 #include <editeng/langitem.hxx>
73 #include <editeng/outliner.hxx>
74 #include <editeng/outlobj.hxx>
76 #include <comphelper/lok.hxx>
77 #include <comphelper/string.hxx>
78 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
80 #include <annotsh.hxx>
81 #include <swabstdlg.hxx>
82 #include <memory>
84 // distance between Anchor Y and initial note position
85 #define POSTIT_INITIAL_ANCHOR_DISTANCE 20
86 //distance between two postits
87 #define POSTIT_SPACE_BETWEEN 8
88 #define POSTIT_MINIMUMSIZE_WITH_META 60
89 #define POSTIT_SCROLL_SIDEBAR_HEIGHT 20
91 // if we layout more often we stop, this should never happen
92 #define MAX_LOOP_COUNT 50
94 using namespace sw::sidebarwindows;
95 using namespace sw::annotation;
97 namespace {
99 enum class CommentNotificationType { Add, Remove, Modify, Resolve };
101 bool comp_pos(const std::unique_ptr<SwSidebarItem>& a, const std::unique_ptr<SwSidebarItem>& b)
103 // sort by anchor position
104 SwPosition aPosAnchorA = a->GetAnchorPosition();
105 SwPosition aPosAnchorB = b->GetAnchorPosition();
107 bool aAnchorAInFooter = false;
108 bool aAnchorBInFooter = false;
110 // is the anchor placed in Footnote or the Footer?
111 if( aPosAnchorA.GetNode().FindFootnoteStartNode() || aPosAnchorA.GetNode().FindFooterStartNode() )
112 aAnchorAInFooter = true;
113 if( aPosAnchorB.GetNode().FindFootnoteStartNode() || aPosAnchorB.GetNode().FindFooterStartNode() )
114 aAnchorBInFooter = true;
116 // fdo#34800
117 // if AnchorA is in footnote, and AnchorB isn't
118 // we do not want to change over the position
119 if( aAnchorAInFooter && !aAnchorBInFooter )
120 return false;
121 // if aAnchorA is not placed in a footnote, and aAnchorB is
122 // force a change over
123 else if( !aAnchorAInFooter && aAnchorBInFooter )
124 return true;
125 // If neither or both are in the footer, compare the positions.
126 // Since footnotes are in Inserts section of nodes array and footers
127 // in Autotext section, all footnotes precede any footers so no need
128 // to check that.
129 else
130 return aPosAnchorA < aPosAnchorB;
133 /// Emits LOK notification about one addition/removal/change of a comment
134 void lcl_CommentNotification(const SwView* pView, const CommentNotificationType nType, const SwSidebarItem* pItem, const sal_uInt32 nPostItId)
136 if (!comphelper::LibreOfficeKit::isActive())
137 return;
139 boost::property_tree::ptree aAnnotation;
140 aAnnotation.put("action", (nType == CommentNotificationType::Add ? "Add" :
141 (nType == CommentNotificationType::Remove ? "Remove" :
142 (nType == CommentNotificationType::Modify ? "Modify" :
143 (nType == CommentNotificationType::Resolve ? "Resolve" : "???")))));
144 aAnnotation.put("id", nPostItId);
145 if (nType != CommentNotificationType::Remove && pItem != nullptr)
147 sw::annotation::SwAnnotationWin* pWin = pItem->mpPostIt.get();
149 const SwPostItField* pField = pWin->GetPostItField();
150 const SwRect& aRect = pWin->GetAnchorRect();
151 tools::Rectangle aSVRect(aRect.Pos().getX(),
152 aRect.Pos().getY(),
153 aRect.Pos().getX() + aRect.SSize().Width(),
154 aRect.Pos().getY() + aRect.SSize().Height());
156 if (!pItem->maLayoutInfo.mPositionFromCommentAnchor)
158 // Comments on frames: anchor position is the corner position, not the whole frame.
159 aSVRect.SetSize(Size(0, 0));
162 std::vector<OString> aRects;
163 for (const basegfx::B2DRange& aRange : pWin->GetAnnotationTextRanges())
165 const SwRect rect(aRange.getMinX(), aRange.getMinY(), aRange.getWidth(), aRange.getHeight());
166 aRects.push_back(rect.SVRect().toString());
168 const OString sRects = comphelper::string::join("; ", aRects);
170 aAnnotation.put("id", pField->GetPostItId());
171 aAnnotation.put("parent", pWin->CalcParent());
172 aAnnotation.put("paraIdParent", pField->GetParentId());
173 aAnnotation.put("author", pField->GetPar1().toUtf8().getStr());
174 aAnnotation.put("text", pField->GetPar2().toUtf8().getStr());
175 aAnnotation.put("resolved", pField->GetResolved() ? "true" : "false");
176 aAnnotation.put("dateTime", utl::toISO8601(pField->GetDateTime().GetUNODateTime()));
177 aAnnotation.put("anchorPos", aSVRect.toString());
178 aAnnotation.put("textRange", sRects.getStr());
181 boost::property_tree::ptree aTree;
182 aTree.add_child("comment", aAnnotation);
183 std::stringstream aStream;
184 boost::property_tree::write_json(aStream, aTree);
185 std::string aPayload = aStream.str();
187 if (pView)
189 pView->libreOfficeKitViewCallback(LOK_CALLBACK_COMMENT, OString(aPayload));
193 } // anonymous namespace
195 SwPostItMgr::SwPostItMgr(SwView* pView)
196 : mpView(pView)
197 , mpWrtShell(mpView->GetDocShell()->GetWrtShell())
198 , mpEditWin(&mpView->GetEditWin())
199 , mnEventId(nullptr)
200 , mbWaitingForCalcRects(false)
201 , mpActivePostIt(nullptr)
202 , mbLayout(false)
203 , mbLayoutHeight(0)
204 , mbLayouting(false)
205 , mbReadOnly(mpView->GetDocShell()->IsReadOnly())
206 , mbDeleteNote(true)
207 , mbIsShowAnchor( false )
209 if(!mpView->GetDrawView() )
210 mpView->GetWrtShell().MakeDrawView();
212 SwNoteProps aProps;
213 mbIsShowAnchor = aProps.IsShowAnchor();
215 //make sure we get the colour yellow always, even if not the first one of comments or redlining
216 SW_MOD()->GetRedlineAuthor();
218 // collect all PostIts and redline comments that exist after loading the document
219 // don't check for existence for any of them, don't focus them
220 AddPostIts(false,false);
221 /* this code can be used once we want redline comments in the Sidebar
222 AddRedlineComments(false,false);
224 // we want to receive stuff like SfxHintId::DocChanged
225 StartListening(*mpView->GetDocShell());
226 if (!mvPostItFields.empty())
228 mbWaitingForCalcRects = true;
229 mnEventId = Application::PostUserEvent( LINK( this, SwPostItMgr, CalcHdl) );
233 SwPostItMgr::~SwPostItMgr()
235 if ( mnEventId )
236 Application::RemoveUserEvent( mnEventId );
237 // forget about all our Sidebar windows
238 RemoveSidebarWin();
239 EndListening( *mpView->GetDocShell() );
241 mPages.clear();
244 bool SwPostItMgr::CheckForRemovedPostIts()
246 IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
247 bool bRemoved = false;
248 auto it = mvPostItFields.begin();
249 while(it != mvPostItFields.end())
251 if (!(*it)->UseElement(*mpWrtShell->GetLayout(), rIDRA))
253 EndListening(const_cast<SfxBroadcaster&>(*(*it)->GetBroadcaster()));
255 if((*it)->mpPostIt && (*it)->mpPostIt->GetPostItField())
256 lcl_CommentNotification(mpView, CommentNotificationType::Remove, nullptr, (*it)->mpPostIt->GetPostItField()->GetPostItId());
258 std::unique_ptr<SwSidebarItem> p = std::move(*it);
259 it = mvPostItFields.erase(it);
260 if (GetActiveSidebarWin() == p->mpPostIt)
261 SetActiveSidebarWin(nullptr);
262 p->mpPostIt.disposeAndClear();
264 if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
266 const SwPostItField* pPostItField = static_cast<const SwPostItField*>(p->GetFormatField().GetField());
267 lcl_CommentNotification(mpView, CommentNotificationType::Remove, nullptr, pPostItField->GetPostItId());
270 bRemoved = true;
272 else
273 ++it;
276 if ( !bRemoved )
277 return false;
279 // make sure that no deleted items remain in page lists
280 // todo: only remove deleted ones?!
281 if ( mvPostItFields.empty() )
283 PreparePageContainer();
284 PrepareView();
286 else
288 // if postits are there make sure that page lists are not empty
289 // otherwise sudden paints can cause pain (in BorderOverPageBorder)
290 CalcRects();
293 return true;
296 SwSidebarItem* SwPostItMgr::InsertItem(SfxBroadcaster* pItem, bool bCheckExistence, bool bFocus)
298 if (bCheckExistence)
300 for (auto const& postItField : mvPostItFields)
302 if ( postItField->GetBroadcaster() == pItem )
303 return nullptr;
306 mbLayout = bFocus;
308 SwSidebarItem* pAnnotationItem = nullptr;
309 if (auto pSwFormatField = dynamic_cast< SwFormatField *>( pItem ))
311 mvPostItFields.push_back(std::make_unique<SwAnnotationItem>(*pSwFormatField, bFocus));
312 pAnnotationItem = mvPostItFields.back().get();
314 assert(dynamic_cast< const SwFormatField *>( pItem ) && "Mgr::InsertItem: seems like new stuff was added");
315 StartListening(*pItem);
316 return pAnnotationItem;
319 void SwPostItMgr::RemoveItem( SfxBroadcaster* pBroadcast )
321 EndListening(*pBroadcast);
322 auto i = std::find_if(mvPostItFields.begin(), mvPostItFields.end(),
323 [&pBroadcast](const std::unique_ptr<SwSidebarItem>& pField) { return pField->GetBroadcaster() == pBroadcast; });
324 if (i != mvPostItFields.end())
326 std::unique_ptr<SwSidebarItem> p = std::move(*i);
327 // tdf#120487 remove from list before dispose, so comment window
328 // won't be recreated due to the entry still in the list if focus
329 // transferring from the pPostIt triggers relayout of postits
330 // tdf#133348 remove from list before calling SetActiveSidebarWin
331 // so GetNextPostIt won't deal with mvPostItFields containing empty unique_ptr
332 mvPostItFields.erase(i);
333 if (GetActiveSidebarWin() == p->mpPostIt)
334 SetActiveSidebarWin(nullptr);
335 p->mpPostIt.disposeAndClear();
337 mbLayout = true;
338 PrepareView();
341 void SwPostItMgr::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
343 if ( const SfxEventHint* pSfxEventHint = dynamic_cast<const SfxEventHint*>(&rHint) )
345 if ( pSfxEventHint->GetEventId() == SfxEventHintId::SwEventLayoutFinished )
347 if ( !mbWaitingForCalcRects && !mvPostItFields.empty())
349 mbWaitingForCalcRects = true;
350 mnEventId = Application::PostUserEvent( LINK( this, SwPostItMgr, CalcHdl) );
354 else if ( const SwFormatFieldHint * pFormatHint = dynamic_cast<const SwFormatFieldHint*>(&rHint) )
356 SwFormatField* pField = const_cast <SwFormatField*>( pFormatHint->GetField() );
357 switch ( pFormatHint->Which() )
359 case SwFormatFieldHintWhich::INSERTED :
361 if (!pField)
363 AddPostIts();
364 break;
366 // get field to be inserted from hint
367 if ( pField->IsFieldInDoc() )
369 bool bEmpty = !HasNotes();
370 SwSidebarItem* pItem = InsertItem( pField, true, false );
372 if (bEmpty && !mvPostItFields.empty())
373 PrepareView(true);
375 // True until the layout of this post it finishes
376 if (pItem)
377 pItem->mbPendingLayout = true;
379 else
381 OSL_FAIL("Inserted field not in document!" );
383 break;
385 case SwFormatFieldHintWhich::REMOVED:
387 if (mbDeleteNote)
389 if (!pField)
391 const bool bWasRemoved = CheckForRemovedPostIts();
392 // tdf#143643 ensure relayout on undo of insert comment
393 if (bWasRemoved)
394 mbLayout = true;
395 break;
397 RemoveItem(pField);
399 // If LOK has disabled tiled annotations, emit annotation callbacks
400 if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
402 SwPostItField* pPostItField = static_cast<SwPostItField*>(pField->GetField());
403 lcl_CommentNotification(mpView, CommentNotificationType::Remove, nullptr, pPostItField->GetPostItId());
406 break;
408 case SwFormatFieldHintWhich::FOCUS:
410 if (pFormatHint->GetView()== mpView)
411 Focus(rBC);
412 break;
414 case SwFormatFieldHintWhich::CHANGED:
415 case SwFormatFieldHintWhich::RESOLVED:
417 SwFormatField* pFormatField = dynamic_cast<SwFormatField*>(&rBC);
418 for (auto const& postItField : mvPostItFields)
420 if ( pFormatField == postItField->GetBroadcaster() )
422 if (postItField->mpPostIt)
424 postItField->mpPostIt->SetPostItText();
425 mbLayout = true;
428 // If LOK has disabled tiled annotations, emit annotation callbacks
429 if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
431 if(SwFormatFieldHintWhich::CHANGED == pFormatHint->Which())
432 lcl_CommentNotification(mpView, CommentNotificationType::Modify, postItField.get(), 0);
433 else
434 lcl_CommentNotification(mpView, CommentNotificationType::Resolve, postItField.get(), 0);
436 break;
439 break;
442 case SwFormatFieldHintWhich::LANGUAGE:
444 SwFormatField* pFormatField = dynamic_cast<SwFormatField*>(&rBC);
445 for (auto const& postItField : mvPostItFields)
447 if ( pFormatField == postItField->GetBroadcaster() )
449 if (postItField->mpPostIt)
451 const SvtScriptType nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( postItField->GetFormatField().GetField()->GetLanguage() );
452 sal_uInt16 nLangWhichId = 0;
453 switch (nScriptType)
455 case SvtScriptType::LATIN : nLangWhichId = EE_CHAR_LANGUAGE ; break;
456 case SvtScriptType::ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break;
457 case SvtScriptType::COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break;
458 default: break;
460 postItField->mpPostIt->SetLanguage(
461 SvxLanguageItem(
462 postItField->GetFormatField().GetField()->GetLanguage(),
463 nLangWhichId) );
465 break;
468 break;
472 else
474 SfxHintId nId = rHint.GetId();
475 switch ( nId )
477 case SfxHintId::ModeChanged:
479 if ( mbReadOnly != mpView->GetDocShell()->IsReadOnly() )
481 mbReadOnly = !mbReadOnly;
482 SetReadOnlyState();
483 mbLayout = true;
485 break;
487 case SfxHintId::DocChanged:
489 if ( mpView->GetDocShell() == &rBC )
491 if ( !mbWaitingForCalcRects && !mvPostItFields.empty())
493 mbWaitingForCalcRects = true;
494 mnEventId = Application::PostUserEvent( LINK( this, SwPostItMgr, CalcHdl) );
497 break;
499 case SfxHintId::SwSplitNodeOperation:
501 // if we are in a SplitNode/Cut operation, do not delete note and then add again, as this will flicker
502 mbDeleteNote = !mbDeleteNote;
503 break;
505 case SfxHintId::Dying:
507 if ( mpView->GetDocShell() != &rBC )
509 // field to be removed is the broadcaster
510 OSL_FAIL("Notification for removed SwFormatField was not sent!");
511 RemoveItem(&rBC);
513 break;
515 default: break;
520 void SwPostItMgr::Focus(const SfxBroadcaster& rBC)
522 if (!mpWrtShell->GetViewOptions()->IsPostIts())
524 SfxRequest aRequest(mpView->GetViewFrame(), SID_TOGGLE_NOTES);
525 mpView->ExecViewOptions(aRequest);
528 for (auto const& postItField : mvPostItFields)
530 // field to get the focus is the broadcaster
531 if ( &rBC == postItField->GetBroadcaster() )
533 if (postItField->mpPostIt)
535 if (postItField->mpPostIt->IsResolved() &&
536 !mpWrtShell->GetViewOptions()->IsResolvedPostIts())
538 SfxRequest aRequest(mpView->GetViewFrame(), SID_TOGGLE_RESOLVED_NOTES);
539 mpView->ExecViewOptions(aRequest);
541 postItField->mpPostIt->GrabFocus();
542 MakeVisible(postItField->mpPostIt);
544 else
546 // when the layout algorithm starts, this postit is created and receives focus
547 postItField->mbFocus = true;
553 bool SwPostItMgr::CalcRects()
555 if ( mnEventId )
557 // if CalcRects() was forced and an event is still pending: remove it
558 // it is superfluous and also may cause reentrance problems if triggered while layouting
559 Application::RemoveUserEvent( mnEventId );
560 mnEventId = nullptr;
563 bool bChange = false;
564 bool bRepair = false;
565 PreparePageContainer();
566 if ( !mvPostItFields.empty() )
568 IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
569 for (auto const& pItem : mvPostItFields)
571 if (!pItem->UseElement(*mpWrtShell->GetLayout(), rIDRA))
573 OSL_FAIL("PostIt is not in doc or other wrong use");
574 bRepair = true;
575 continue;
577 const SwRect aOldAnchorRect( pItem->maLayoutInfo.mPosition );
578 const SwPostItHelper::SwLayoutStatus eOldLayoutStatus = pItem->mLayoutStatus;
579 const SwNodeOffset nOldStartNodeIdx( pItem->maLayoutInfo.mnStartNodeIdx );
580 const sal_Int32 nOldStartContent( pItem->maLayoutInfo.mnStartContent );
582 // update layout information
583 const SwTextAnnotationField* pTextAnnotationField =
584 dynamic_cast< const SwTextAnnotationField* >( pItem->GetFormatField().GetTextField() );
585 const ::sw::mark::IMark* pAnnotationMark =
586 pTextAnnotationField != nullptr ? pTextAnnotationField->GetAnnotationMark() : nullptr;
587 if ( pAnnotationMark != nullptr )
589 pItem->mLayoutStatus =
590 SwPostItHelper::getLayoutInfos(
591 pItem->maLayoutInfo,
592 pItem->GetAnchorPosition(),
593 pAnnotationMark );
595 else
597 pItem->mLayoutStatus =
598 SwPostItHelper::getLayoutInfos( pItem->maLayoutInfo, pItem->GetAnchorPosition() );
601 bChange = bChange
602 || pItem->maLayoutInfo.mPosition != aOldAnchorRect
603 || pItem->mLayoutStatus != eOldLayoutStatus
604 || pItem->maLayoutInfo.mnStartNodeIdx != nOldStartNodeIdx
605 || pItem->maLayoutInfo.mnStartContent != nOldStartContent;
608 // show notes in right order in navigator
609 //prevent Anchors during layout to overlap, e.g. when moving a frame
610 if (mvPostItFields.size()>1 )
611 std::stable_sort(mvPostItFields.begin(), mvPostItFields.end(), comp_pos);
613 // sort the items into the right page vector, so layout can be done by page
614 for (auto const& pItem : mvPostItFields)
616 if( SwPostItHelper::INVISIBLE == pItem->mLayoutStatus )
618 if (pItem->mpPostIt)
619 pItem->mpPostIt->HideNote();
620 continue;
623 if( SwPostItHelper::HIDDEN == pItem->mLayoutStatus )
625 if (!mpWrtShell->GetViewOptions()->IsShowHiddenChar())
627 if (pItem->mpPostIt)
628 pItem->mpPostIt->HideNote();
629 continue;
633 const tools::ULong aPageNum = pItem->maLayoutInfo.mnPageNumber;
634 if (aPageNum > mPages.size())
636 const tools::ULong nNumberOfPages = mPages.size();
637 mPages.reserve(aPageNum);
638 for (tools::ULong j=0; j<aPageNum - nNumberOfPages; ++j)
639 mPages.emplace_back( new SwPostItPageItem());
641 mPages[aPageNum-1]->mvSidebarItems.push_back(pItem.get());
642 mPages[aPageNum-1]->mPageRect = pItem->maLayoutInfo.mPageFrame;
643 mPages[aPageNum-1]->eSidebarPosition = pItem->maLayoutInfo.meSidebarPosition;
646 if (!bChange && mpWrtShell->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE))
648 tools::Long nLayoutHeight = SwPostItHelper::getLayoutHeight( mpWrtShell->GetLayout() );
649 if( nLayoutHeight > mbLayoutHeight )
651 if (mPages[0]->bScrollbar || HasScrollbars())
652 bChange = true;
654 else if( nLayoutHeight < mbLayoutHeight )
656 if (mPages[0]->bScrollbar || !BorderOverPageBorder(1))
657 bChange = true;
662 if ( bRepair )
663 CheckForRemovedPostIts();
665 mbLayoutHeight = SwPostItHelper::getLayoutHeight( mpWrtShell->GetLayout() );
666 mbWaitingForCalcRects = false;
667 return bChange;
670 bool SwPostItMgr::HasScrollbars() const
672 for (auto const& postItField : mvPostItFields)
674 if (postItField->mbShow && postItField->mpPostIt && postItField->mpPostIt->HasScrollbar())
675 return true;
677 return false;
680 void SwPostItMgr::PreparePageContainer()
682 // we do not just delete the SwPostItPageItem, so offset/scrollbar is not lost
683 tools::Long lPageSize = mpWrtShell->GetNumPages();
684 tools::Long lContainerSize = mPages.size();
686 if (lContainerSize < lPageSize)
688 mPages.reserve(lPageSize);
689 for (tools::Long i=0; i<lPageSize - lContainerSize;i++)
690 mPages.emplace_back( new SwPostItPageItem());
692 else if (lContainerSize > lPageSize)
694 for (int i=mPages.size()-1; i >= lPageSize;--i)
696 mPages.pop_back();
699 // only clear the list, DO NOT delete the objects itself
700 for (auto const& page : mPages)
702 page->mvSidebarItems.clear();
703 if (mvPostItFields.empty())
704 page->bScrollbar = false;
708 void SwPostItMgr::LayoutPostIts()
710 bool bEnableMapMode = comphelper::LibreOfficeKit::isActive() && !mpEditWin->IsMapModeEnabled();
711 if (bEnableMapMode)
712 mpEditWin->EnableMapMode();
714 if ( !mvPostItFields.empty() && !mbWaitingForCalcRects )
716 mbLayouting = true;
718 //loop over all pages and do the layout
719 // - create SwPostIt if necessary
720 // - place SwPostIts on their initial position
721 // - calculate necessary height for all PostIts together
722 bool bUpdate = false;
723 for (std::unique_ptr<SwPostItPageItem>& pPage : mPages)
725 // only layout if there are notes on this page
726 if (!pPage->mvSidebarItems.empty())
728 std::vector<SwAnnotationWin*> aVisiblePostItList;
729 tools::ULong lNeededHeight = 0;
730 tools::Long mlPageBorder = 0;
731 tools::Long mlPageEnd = 0;
733 for (auto const& pItem : pPage->mvSidebarItems)
735 VclPtr<SwAnnotationWin> pPostIt = pItem->mpPostIt;
737 if (pPage->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT )
739 // x value for notes positioning
740 mlPageBorder = mpEditWin->LogicToPixel( Point( pPage->mPageRect.Left(), 0)).X() - GetSidebarWidth(true);// - GetSidebarBorderWidth(true);
741 //bending point
742 mlPageEnd =
743 mpWrtShell->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE)
744 ? pItem->maLayoutInfo.mPagePrtArea.Left()
745 : pPage->mPageRect.Left() + 350;
747 else if (pPage->eSidebarPosition == sw::sidebarwindows::SidebarPosition::RIGHT )
749 // x value for notes positioning
750 mlPageBorder = mpEditWin->LogicToPixel( Point(pPage->mPageRect.Right(), 0)).X() + GetSidebarBorderWidth(true);
751 //bending point
752 mlPageEnd =
753 mpWrtShell->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE)
754 ? pItem->maLayoutInfo.mPagePrtArea.Right() :
755 pPage->mPageRect.Right() - 350;
758 if (pItem->mbShow)
760 tools::Long Y = mpEditWin->LogicToPixel( Point(0,pItem->maLayoutInfo.mPosition.Bottom())).Y();
761 tools::Long aPostItHeight = 0;
762 if (!pPostIt)
764 pPostIt = pItem->GetSidebarWindow( mpView->GetEditWin(),
765 *this );
766 pPostIt->InitControls();
767 pPostIt->SetReadonly(mbReadOnly);
768 pItem->mpPostIt = pPostIt;
769 if (mpAnswer)
771 if (static_cast<bool>(pPostIt->CalcParent())) //do we really have another note in front of this one
772 pPostIt->InitAnswer(*mpAnswer);
773 mpAnswer.reset();
777 pPostIt->SetChangeTracking(
778 pItem->mLayoutStatus,
779 GetColorAnchor(pItem->maLayoutInfo.mRedlineAuthor));
780 pPostIt->SetSidebarPosition(pPage->eSidebarPosition);
781 pPostIt->SetFollow(static_cast<bool>(pPostIt->CalcParent()));
782 aPostItHeight = ( pPostIt->GetPostItTextHeight() < pPostIt->GetMinimumSizeWithoutMeta()
783 ? pPostIt->GetMinimumSizeWithoutMeta()
784 : pPostIt->GetPostItTextHeight() )
785 + pPostIt->GetMetaHeight();
786 pPostIt->SetPosSizePixelRect( mlPageBorder ,
787 Y - GetInitialAnchorDistance(),
788 GetSidebarWidth(true),
789 aPostItHeight,
790 pItem->maLayoutInfo.mPosition,
791 mlPageEnd );
792 pPostIt->ChangeSidebarItem( *pItem );
794 if (pItem->mbFocus)
796 mbLayout = true;
797 pPostIt->GrabFocus();
798 pItem->mbFocus = false;
800 // only the visible postits are used for the final layout
801 aVisiblePostItList.push_back(pPostIt);
802 lNeededHeight += pPostIt->IsFollow() ? aPostItHeight : aPostItHeight+GetSpaceBetween();
804 else // we don't want to see it
806 if (pPostIt)
807 pPostIt->HideNote();
811 if ((!aVisiblePostItList.empty()) && ShowNotes())
813 bool bOldScrollbar = pPage->bScrollbar;
814 if (ShowNotes())
815 pPage->bScrollbar = LayoutByPage(aVisiblePostItList, pPage->mPageRect.SVRect(), lNeededHeight);
816 else
817 pPage->bScrollbar = false;
818 if (!pPage->bScrollbar)
820 pPage->lOffset = 0;
822 else if (sal_Int32 nScrollSize = GetScrollSize())
824 //when we changed our zoom level, the offset value can be too big, so lets check for the largest possible zoom value
825 tools::Long aAvailableHeight = mpEditWin->LogicToPixel(Size(0,pPage->mPageRect.Height())).Height() - 2 * GetSidebarScrollerHeight();
826 tools::Long lOffset = -1 * nScrollSize * (aVisiblePostItList.size() - aAvailableHeight / nScrollSize);
827 if (pPage->lOffset < lOffset)
828 pPage->lOffset = lOffset;
830 bUpdate = (bOldScrollbar != pPage->bScrollbar) || bUpdate;
831 const tools::Long aSidebarheight = pPage->bScrollbar ? mpEditWin->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height() : 0;
833 TODO
834 - enlarge all notes till GetNextBorder(), as we resized to average value before
836 //lets hide the ones which overlap the page
837 for (auto const& visiblePostIt : aVisiblePostItList)
839 if (pPage->lOffset != 0)
840 visiblePostIt->TranslateTopPosition(pPage->lOffset);
842 bool bBottom = mpEditWin->PixelToLogic(Point(0,visiblePostIt->VirtualPos().Y()+visiblePostIt->VirtualSize().Height())).Y() <= (pPage->mPageRect.Bottom()-aSidebarheight);
843 bool bTop = mpEditWin->PixelToLogic(Point(0,visiblePostIt->VirtualPos().Y())).Y() >= (pPage->mPageRect.Top()+aSidebarheight);
844 if ( bBottom && bTop )
846 // When tiled rendering, make sure that only the
847 // view that has the comment focus emits callbacks,
848 // so the editing view jumps to the comment, but
849 // not the others.
850 bool bTiledPainting = comphelper::LibreOfficeKit::isTiledPainting();
851 if (!bTiledPainting)
852 // No focus -> disable callbacks.
853 comphelper::LibreOfficeKit::setTiledPainting(!visiblePostIt->HasChildPathFocus());
854 visiblePostIt->ShowNote();
855 if (!bTiledPainting)
856 comphelper::LibreOfficeKit::setTiledPainting(bTiledPainting);
858 else
860 if (mpEditWin->PixelToLogic(Point(0,visiblePostIt->VirtualPos().Y())).Y() < (pPage->mPageRect.Top()+aSidebarheight))
862 if ( pPage->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT )
863 visiblePostIt->ShowAnchorOnly(Point( pPage->mPageRect.Left(),
864 pPage->mPageRect.Top()));
865 else if ( pPage->eSidebarPosition == sw::sidebarwindows::SidebarPosition::RIGHT )
866 visiblePostIt->ShowAnchorOnly(Point( pPage->mPageRect.Right(),
867 pPage->mPageRect.Top()));
869 else
871 if ( pPage->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT )
872 visiblePostIt->ShowAnchorOnly(Point(pPage->mPageRect.Left(),
873 pPage->mPageRect.Bottom()));
874 else if ( pPage->eSidebarPosition == sw::sidebarwindows::SidebarPosition::RIGHT )
875 visiblePostIt->ShowAnchorOnly(Point(pPage->mPageRect.Right(),
876 pPage->mPageRect.Bottom()));
878 OSL_ENSURE(pPage->bScrollbar,"SwPostItMgr::LayoutByPage(): note overlaps, but bScrollbar is not true");
882 else
884 for (auto const& visiblePostIt : aVisiblePostItList)
886 visiblePostIt->SetPosAndSize();
889 bool bOldScrollbar = pPage->bScrollbar;
890 pPage->bScrollbar = false;
891 bUpdate = (bOldScrollbar != pPage->bScrollbar) || bUpdate;
894 for (auto const& visiblePostIt : aVisiblePostItList)
896 if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
898 if (visiblePostIt->GetSidebarItem().mbPendingLayout)
899 lcl_CommentNotification(mpView, CommentNotificationType::Add, &visiblePostIt->GetSidebarItem(), 0);
900 else if (visiblePostIt->IsAnchorRectChanged())
902 lcl_CommentNotification(mpView, CommentNotificationType::Modify, &visiblePostIt->GetSidebarItem(), 0);
903 visiblePostIt->ResetAnchorRectChanged();
907 // Layout for this post it finished now
908 visiblePostIt->GetSidebarItem().mbPendingLayout = false;
911 else
913 if (pPage->bScrollbar)
914 bUpdate = true;
915 pPage->bScrollbar = false;
919 if (!ShowNotes())
920 { // we do not want to see the notes anymore -> Options-Writer-View-Notes
921 IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
922 bool bRepair = false;
923 for (auto const& postItField : mvPostItFields)
925 if (!postItField->UseElement(*mpWrtShell->GetLayout(), rIDRA))
927 OSL_FAIL("PostIt is not in doc!");
928 bRepair = true;
929 continue;
932 if (postItField->mpPostIt)
934 postItField->mpPostIt->HideNote();
935 if (postItField->mpPostIt->HasChildPathFocus())
937 SetActiveSidebarWin(nullptr);
938 postItField->mpPostIt->GrabFocusToDocument();
943 if ( bRepair )
944 CheckForRemovedPostIts();
947 // notes scrollbar is otherwise not drawn correctly for some cases
948 // scrollbar area is enough
949 if (bUpdate)
950 mpEditWin->Invalidate(); /*This is a super expensive relayout and render of the entire page*/
952 mbLayouting = false;
955 if (bEnableMapMode)
956 mpEditWin->EnableMapMode(false);
959 bool SwPostItMgr::BorderOverPageBorder(tools::ULong aPage) const
961 if ( mPages[aPage-1]->mvSidebarItems.empty() )
963 OSL_FAIL("Notes SidePane painted but no rects and page lists calculated!");
964 return false;
967 auto aItem = mPages[aPage-1]->mvSidebarItems.end();
968 --aItem;
969 OSL_ENSURE ((*aItem)->mpPostIt,"BorderOverPageBorder: NULL postIt, should never happen");
970 if ((*aItem)->mpPostIt)
972 const tools::Long aSidebarheight = mPages[aPage-1]->bScrollbar ? mpEditWin->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height() : 0;
973 const tools::Long aEndValue = mpEditWin->PixelToLogic(Point(0,(*aItem)->mpPostIt->GetPosPixel().Y()+(*aItem)->mpPostIt->GetSizePixel().Height())).Y();
974 return aEndValue <= mPages[aPage-1]->mPageRect.Bottom()-aSidebarheight;
976 else
977 return false;
980 void SwPostItMgr::DrawNotesForPage(OutputDevice *pOutDev, sal_uInt32 nPage)
982 assert(nPage < mPages.size());
983 if (nPage >= mPages.size())
984 return;
985 for (auto const& pItem : mPages[nPage]->mvSidebarItems)
987 SwAnnotationWin* pPostIt = pItem->mpPostIt;
988 if (!pPostIt)
989 continue;
990 Point aPoint(mpEditWin->PixelToLogic(pPostIt->GetPosPixel()));
991 pPostIt->DrawForPage(pOutDev, aPoint);
995 void SwPostItMgr::PaintTile(OutputDevice& rRenderContext)
997 for (const std::unique_ptr<SwSidebarItem>& pItem : mvPostItFields)
999 SwAnnotationWin* pPostIt = pItem->mpPostIt;
1000 if (!pPostIt)
1001 continue;
1003 bool bEnableMapMode = !mpEditWin->IsMapModeEnabled();
1004 mpEditWin->EnableMapMode();
1005 rRenderContext.Push(vcl::PushFlags::MAPMODE);
1006 Point aOffset(mpEditWin->PixelToLogic(pPostIt->GetPosPixel()));
1007 MapMode aMapMode(rRenderContext.GetMapMode());
1008 aMapMode.SetOrigin(aMapMode.GetOrigin() + aOffset);
1009 rRenderContext.SetMapMode(aMapMode);
1010 Size aSize(rRenderContext.PixelToLogic(pPostIt->GetSizePixel()));
1011 tools::Rectangle aRectangle(Point(0, 0), aSize);
1013 pPostIt->PaintTile(rRenderContext, aRectangle);
1015 rRenderContext.Pop();
1016 if (bEnableMapMode)
1017 mpEditWin->EnableMapMode(false);
1021 void SwPostItMgr::Scroll(const tools::Long lScroll,const tools::ULong aPage)
1023 OSL_ENSURE((lScroll % GetScrollSize() )==0,"SwPostItMgr::Scroll: scrolling by wrong value");
1024 // do not scroll more than necessary up or down
1025 if ( ((mPages[aPage-1]->lOffset == 0) && (lScroll>0)) || ( BorderOverPageBorder(aPage) && (lScroll<0)) )
1026 return;
1028 const bool bOldUp = ArrowEnabled(KEY_PAGEUP,aPage);
1029 const bool bOldDown = ArrowEnabled(KEY_PAGEDOWN,aPage);
1030 const tools::Long aSidebarheight = mpEditWin->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height();
1031 for (auto const& item : mPages[aPage-1]->mvSidebarItems)
1033 SwAnnotationWin* pPostIt = item->mpPostIt;
1034 // if this is an answer, we should take the normal position and not the real, slightly moved position
1035 pPostIt->SetVirtualPosSize(pPostIt->GetPosPixel(),pPostIt->GetSizePixel());
1036 pPostIt->TranslateTopPosition(lScroll);
1038 if (item->mbShow)
1040 bool bBottom = mpEditWin->PixelToLogic(Point(0,pPostIt->VirtualPos().Y()+pPostIt->VirtualSize().Height())).Y() <= (mPages[aPage-1]->mPageRect.Bottom()-aSidebarheight);
1041 bool bTop = mpEditWin->PixelToLogic(Point(0,pPostIt->VirtualPos().Y())).Y() >= (mPages[aPage-1]->mPageRect.Top()+aSidebarheight);
1042 if ( bBottom && bTop)
1044 pPostIt->ShowNote();
1046 else
1048 if ( mpEditWin->PixelToLogic(Point(0,pPostIt->VirtualPos().Y())).Y() < (mPages[aPage-1]->mPageRect.Top()+aSidebarheight))
1050 if (mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT)
1051 pPostIt->ShowAnchorOnly(Point(mPages[aPage-1]->mPageRect.Left(),mPages[aPage-1]->mPageRect.Top()));
1052 else if (mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::RIGHT)
1053 pPostIt->ShowAnchorOnly(Point(mPages[aPage-1]->mPageRect.Right(),mPages[aPage-1]->mPageRect.Top()));
1055 else
1057 if (mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT)
1058 pPostIt->ShowAnchorOnly(Point(mPages[aPage-1]->mPageRect.Left(),mPages[aPage-1]->mPageRect.Bottom()));
1059 else if (mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::RIGHT)
1060 pPostIt->ShowAnchorOnly(Point(mPages[aPage-1]->mPageRect.Right(),mPages[aPage-1]->mPageRect.Bottom()));
1065 mPages[aPage-1]->lOffset += lScroll;
1066 if ( (bOldUp != ArrowEnabled(KEY_PAGEUP,aPage)) ||(bOldDown != ArrowEnabled(KEY_PAGEDOWN,aPage)) )
1068 mpEditWin->Invalidate(GetBottomScrollRect(aPage));
1069 mpEditWin->Invalidate(GetTopScrollRect(aPage));
1073 void SwPostItMgr::AutoScroll(const SwAnnotationWin* pPostIt,const tools::ULong aPage )
1075 // otherwise all notes are visible
1076 if (!mPages[aPage-1]->bScrollbar)
1077 return;
1079 const tools::Long aSidebarheight = mpEditWin->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height();
1080 const bool bBottom = mpEditWin->PixelToLogic(Point(0,pPostIt->GetPosPixel().Y()+pPostIt->GetSizePixel().Height())).Y() <= (mPages[aPage-1]->mPageRect.Bottom()-aSidebarheight);
1081 const bool bTop = mpEditWin->PixelToLogic(Point(0,pPostIt->GetPosPixel().Y())).Y() >= (mPages[aPage-1]->mPageRect.Top()+aSidebarheight);
1082 if ( !(bBottom && bTop))
1084 const tools::Long aDiff = bBottom ? mpEditWin->LogicToPixel(Point(0,mPages[aPage-1]->mPageRect.Top() + aSidebarheight)).Y() - pPostIt->GetPosPixel().Y() :
1085 mpEditWin->LogicToPixel(Point(0,mPages[aPage-1]->mPageRect.Bottom() - aSidebarheight)).Y() - (pPostIt->GetPosPixel().Y()+pPostIt->GetSizePixel().Height());
1086 // this just adds the missing value to get the next a* GetScrollSize() after aDiff
1087 // e.g aDiff= 61 POSTIT_SCROLL=50 --> lScroll = 100
1088 const auto nScrollSize = GetScrollSize();
1089 assert(nScrollSize);
1090 const tools::Long lScroll = bBottom ? (aDiff + ( nScrollSize - (aDiff % nScrollSize))) : (aDiff - (nScrollSize + (aDiff % nScrollSize)));
1091 Scroll(lScroll, aPage);
1095 void SwPostItMgr::MakeVisible(const SwAnnotationWin* pPostIt )
1097 tools::Long aPage = -1;
1098 // we don't know the page yet, lets find it ourselves
1099 std::vector<SwPostItPageItem*>::size_type n=0;
1100 for (auto const& page : mPages)
1102 for (auto const& item : page->mvSidebarItems)
1104 if (item->mpPostIt==pPostIt)
1106 aPage = n+1;
1107 break;
1110 ++n;
1112 if (aPage!=-1)
1113 AutoScroll(pPostIt,aPage);
1114 tools::Rectangle aNoteRect (Point(pPostIt->GetPosPixel().X(),pPostIt->GetPosPixel().Y()-5),pPostIt->GetSizePixel());
1115 if (!aNoteRect.IsEmpty())
1116 mpWrtShell->MakeVisible(SwRect(mpEditWin->PixelToLogic(aNoteRect)));
1119 bool SwPostItMgr::ArrowEnabled(sal_uInt16 aDirection,tools::ULong aPage) const
1121 switch (aDirection)
1123 case KEY_PAGEUP:
1125 return (mPages[aPage-1]->lOffset != 0);
1127 case KEY_PAGEDOWN:
1129 return (!BorderOverPageBorder(aPage));
1131 default: return false;
1135 Color SwPostItMgr::GetArrowColor(sal_uInt16 aDirection,tools::ULong aPage) const
1137 if (ArrowEnabled(aDirection,aPage))
1139 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode())
1140 return COL_WHITE;
1141 else
1142 return COL_NOTES_SIDEPANE_ARROW_ENABLED;
1144 else
1146 return COL_NOTES_SIDEPANE_ARROW_DISABLED;
1150 bool SwPostItMgr::LayoutByPage(std::vector<SwAnnotationWin*> &aVisiblePostItList, const tools::Rectangle& rBorder, tools::Long lNeededHeight)
1152 /*** General layout idea:***/
1153 // - if we have space left, we always move the current one up,
1154 // otherwise the next one down
1155 // - first all notes are resized
1156 // - then the real layout starts
1158 //rBorder is the page rect
1159 const tools::Rectangle aBorder = mpEditWin->LogicToPixel(rBorder);
1160 tools::Long lTopBorder = aBorder.Top() + 5;
1161 tools::Long lBottomBorder = aBorder.Bottom() - 5;
1162 const tools::Long lVisibleHeight = lBottomBorder - lTopBorder; //aBorder.GetHeight() ;
1163 const size_t nPostItListSize = aVisiblePostItList.size();
1164 tools::Long lTranslatePos = 0;
1165 bool bScrollbars = false;
1167 // do all necessary resizings
1168 if (nPostItListSize > 0 && lVisibleHeight < lNeededHeight)
1170 // ok, now we have to really resize and adding scrollbars
1171 const tools::Long lAverageHeight = (lVisibleHeight - nPostItListSize*GetSpaceBetween()) / nPostItListSize;
1172 if (lAverageHeight<GetMinimumSizeWithMeta())
1174 bScrollbars = true;
1175 lTopBorder += GetSidebarScrollerHeight() + 10;
1176 lBottomBorder -= (GetSidebarScrollerHeight() + 10);
1177 for (auto const& visiblePostIt : aVisiblePostItList)
1178 visiblePostIt->SetSize(Size(visiblePostIt->VirtualSize().getWidth(),visiblePostIt->GetMinimumSizeWithMeta()));
1180 else
1182 for (auto const& visiblePostIt : aVisiblePostItList)
1184 if ( visiblePostIt->VirtualSize().getHeight() > lAverageHeight)
1185 visiblePostIt->SetSize(Size(visiblePostIt->VirtualSize().getWidth(),lAverageHeight));
1190 //start the real layout so nothing overlaps anymore
1191 if (aVisiblePostItList.size()>1)
1193 int loop = 0;
1194 bool bDone = false;
1195 // if no window is moved anymore we are finished
1196 while (!bDone)
1198 loop++;
1199 bDone = true;
1200 tools::Long lSpaceUsed = lTopBorder + GetSpaceBetween();
1201 for(auto i = aVisiblePostItList.begin(); i != aVisiblePostItList.end() ; ++i)
1203 auto aNextPostIt = i;
1204 ++aNextPostIt;
1206 if (aNextPostIt != aVisiblePostItList.end())
1208 lTranslatePos = ( (*i)->VirtualPos().Y() + (*i)->VirtualSize().Height()) - (*aNextPostIt)->VirtualPos().Y();
1209 if (lTranslatePos > 0) // note windows overlaps the next one
1211 // we are not done yet, loop at least once more
1212 bDone = false;
1213 // if there is space left, move the current note up
1214 // it could also happen that there is no space left for the first note due to a scrollbar
1215 // then we also jump into, so we move the current one up and the next one down
1216 if ( (lSpaceUsed <= (*i)->VirtualPos().Y()) || (i==aVisiblePostItList.begin()))
1218 // we have space left, so let's move the current one up
1219 if ( ((*i)->VirtualPos().Y()- lTranslatePos - GetSpaceBetween()) > lTopBorder)
1221 if ((*aNextPostIt)->IsFollow())
1222 (*i)->TranslateTopPosition(-1*(lTranslatePos+ANCHORLINE_WIDTH));
1223 else
1224 (*i)->TranslateTopPosition(-1*(lTranslatePos+GetSpaceBetween()));
1226 else
1228 tools::Long lMoveUp = (*i)->VirtualPos().Y() - lTopBorder;
1229 (*i)->TranslateTopPosition(-1* lMoveUp);
1230 if ((*aNextPostIt)->IsFollow())
1231 (*aNextPostIt)->TranslateTopPosition( (lTranslatePos+ANCHORLINE_WIDTH) - lMoveUp);
1232 else
1233 (*aNextPostIt)->TranslateTopPosition( (lTranslatePos+GetSpaceBetween()) - lMoveUp);
1236 else
1238 // no space left, left move the next one down
1239 if ((*aNextPostIt)->IsFollow())
1240 (*aNextPostIt)->TranslateTopPosition(lTranslatePos+ANCHORLINE_WIDTH);
1241 else
1242 (*aNextPostIt)->TranslateTopPosition(lTranslatePos+GetSpaceBetween());
1245 else
1247 // the first one could overlap the topborder instead of a second note
1248 if (i==aVisiblePostItList.begin())
1250 tools::Long lMoveDown = lTopBorder - (*i)->VirtualPos().Y();
1251 if (lMoveDown>0)
1253 bDone = false;
1254 (*i)->TranslateTopPosition( lMoveDown);
1258 if ( (*aNextPostIt)->IsFollow() )
1259 lSpaceUsed += (*i)->VirtualSize().Height() + ANCHORLINE_WIDTH;
1260 else
1261 lSpaceUsed += (*i)->VirtualSize().Height() + GetSpaceBetween();
1263 else
1265 //(*i) is the last visible item
1266 auto aPrevPostIt = i;
1267 --aPrevPostIt;
1268 lTranslatePos = ( (*aPrevPostIt)->VirtualPos().Y() + (*aPrevPostIt)->VirtualSize().Height() ) - (*i)->VirtualPos().Y();
1269 if (lTranslatePos > 0)
1271 bDone = false;
1272 if ( ((*i)->VirtualPos().Y()+ (*i)->VirtualSize().Height()+lTranslatePos) < lBottomBorder)
1274 if ( (*i)->IsFollow() )
1275 (*i)->TranslateTopPosition(lTranslatePos+ANCHORLINE_WIDTH);
1276 else
1277 (*i)->TranslateTopPosition(lTranslatePos+GetSpaceBetween());
1279 else
1281 (*i)->TranslateTopPosition(lBottomBorder - ((*i)->VirtualPos().Y()+ (*i)->VirtualSize().Height()) );
1284 else
1286 // note does not overlap, but we might be over the lower border
1287 // only do this if there are no scrollbars, otherwise notes are supposed to overlap the border
1288 if (!bScrollbars && ((*i)->VirtualPos().Y()+ (*i)->VirtualSize().Height() > lBottomBorder) )
1290 bDone = false;
1291 (*i)->TranslateTopPosition(lBottomBorder - ((*i)->VirtualPos().Y()+ (*i)->VirtualSize().Height()));
1296 // security check so we don't loop forever
1297 if (loop>MAX_LOOP_COUNT)
1299 OSL_FAIL("PostItMgr::Layout(): We are looping forever");
1300 break;
1304 else
1306 // only one left, make sure it is not hidden at the top or bottom
1307 auto i = aVisiblePostItList.begin();
1308 lTranslatePos = lTopBorder - (*i)->VirtualPos().Y();
1309 if (lTranslatePos>0)
1311 (*i)->TranslateTopPosition(lTranslatePos+GetSpaceBetween());
1313 lTranslatePos = lBottomBorder - ((*i)->VirtualPos().Y()+ (*i)->VirtualSize().Height());
1314 if (lTranslatePos<0)
1316 (*i)->TranslateTopPosition(lTranslatePos);
1319 return bScrollbars;
1322 void SwPostItMgr::AddPostIts(const bool bCheckExistence, const bool bFocus)
1324 const bool bEmpty = mvPostItFields.empty();
1325 IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
1326 SwFieldType* pType = mpView->GetDocShell()->GetDoc()->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Postit, OUString(),false);
1327 std::vector<SwFormatField*> vFormatFields;
1328 pType->CollectPostIts(vFormatFields, rIDRA, mpWrtShell->GetLayout()->IsHideRedlines());
1329 for(auto pFormatField : vFormatFields)
1330 InsertItem(pFormatField, bCheckExistence, bFocus);
1331 // if we just added the first one we have to update the view for centering
1332 if (bEmpty && !mvPostItFields.empty())
1333 PrepareView(true);
1336 void SwPostItMgr::RemoveSidebarWin()
1338 for (auto& postItField : mvPostItFields)
1340 EndListening( *const_cast<SfxBroadcaster*>(postItField->GetBroadcaster()) );
1341 postItField->mpPostIt.disposeAndClear();
1342 postItField.reset();
1344 mvPostItFields.clear();
1346 // all postits removed, no items should be left in pages
1347 PreparePageContainer();
1350 namespace {
1352 class FilterFunctor
1354 public:
1355 virtual bool operator()(const SwFormatField* pField) const = 0;
1356 virtual ~FilterFunctor() {}
1359 class IsPostitField : public FilterFunctor
1361 public:
1362 bool operator()(const SwFormatField* pField) const override
1364 return pField->GetField()->GetTyp()->Which() == SwFieldIds::Postit;
1368 class IsPostitFieldWithAuthorOf : public FilterFunctor
1370 OUString m_sAuthor;
1371 public:
1372 explicit IsPostitFieldWithAuthorOf(OUString aAuthor)
1373 : m_sAuthor(std::move(aAuthor))
1376 bool operator()(const SwFormatField* pField) const override
1378 if (pField->GetField()->GetTyp()->Which() != SwFieldIds::Postit)
1379 return false;
1380 return static_cast<const SwPostItField*>(pField->GetField())->GetPar1() == m_sAuthor;
1384 class IsPostitFieldWithPostitId : public FilterFunctor
1386 sal_uInt32 m_nPostItId;
1387 public:
1388 explicit IsPostitFieldWithPostitId(sal_uInt32 nPostItId)
1389 : m_nPostItId(nPostItId)
1392 bool operator()(const SwFormatField* pField) const override
1394 if (pField->GetField()->GetTyp()->Which() != SwFieldIds::Postit)
1395 return false;
1396 return static_cast<const SwPostItField*>(pField->GetField())->GetPostItId() == m_nPostItId;
1400 class IsFieldNotDeleted : public FilterFunctor
1402 private:
1403 IDocumentRedlineAccess const& m_rIDRA;
1404 FilterFunctor const& m_rNext;
1406 public:
1407 IsFieldNotDeleted(IDocumentRedlineAccess const& rIDRA,
1408 const FilterFunctor & rNext)
1409 : m_rIDRA(rIDRA)
1410 , m_rNext(rNext)
1413 bool operator()(const SwFormatField* pField) const override
1415 if (!m_rNext(pField))
1416 return false;
1417 if (!pField->GetTextField())
1418 return false;
1419 return !sw::IsFieldDeletedInModel(m_rIDRA, *pField->GetTextField());
1423 //Manages the passed in vector by automatically removing entries if they are deleted
1424 //and automatically adding entries if they appear in the document and match the
1425 //functor.
1427 //This will completely refill in the case of a "anonymous" NULL pField stating
1428 //rather unhelpfully that "something changed" so you may process the same
1429 //Fields more than once.
1430 class FieldDocWatchingStack : public SfxListener
1432 std::vector<std::unique_ptr<SwSidebarItem>>& m_aSidebarItems;
1433 std::vector<const SwFormatField*> m_aFormatFields;
1434 SwDocShell& m_rDocShell;
1435 FilterFunctor& m_rFilter;
1437 virtual void Notify(SfxBroadcaster&, const SfxHint& rHint) override
1439 const SwFormatFieldHint* pHint = dynamic_cast<const SwFormatFieldHint*>(&rHint);
1440 if (!pHint)
1441 return;
1443 bool bAllInvalidated = false;
1444 if (pHint->Which() == SwFormatFieldHintWhich::REMOVED)
1446 const SwFormatField* pField = pHint->GetField();
1447 bAllInvalidated = pField == nullptr;
1448 if (!bAllInvalidated && m_rFilter(pField))
1450 EndListening(const_cast<SwFormatField&>(*pField));
1451 m_aFormatFields.erase(std::remove(m_aFormatFields.begin(), m_aFormatFields.end(), pField), m_aFormatFields.end());
1454 else if (pHint->Which() == SwFormatFieldHintWhich::INSERTED)
1456 const SwFormatField* pField = pHint->GetField();
1457 bAllInvalidated = pField == nullptr;
1458 if (!bAllInvalidated && m_rFilter(pField))
1460 StartListening(const_cast<SwFormatField&>(*pField));
1461 m_aFormatFields.push_back(pField);
1465 if (bAllInvalidated)
1466 FillVector();
1468 return;
1471 public:
1472 FieldDocWatchingStack(std::vector<std::unique_ptr<SwSidebarItem>>& in, SwDocShell &rDocShell, FilterFunctor& rFilter)
1473 : m_aSidebarItems(in)
1474 , m_rDocShell(rDocShell)
1475 , m_rFilter(rFilter)
1477 FillVector();
1478 StartListening(m_rDocShell);
1480 void FillVector()
1482 EndListeningToAllFields();
1483 m_aFormatFields.clear();
1484 m_aFormatFields.reserve(m_aSidebarItems.size());
1485 for (auto const& p : m_aSidebarItems)
1487 const SwFormatField& rField = p->GetFormatField();
1488 if (!m_rFilter(&rField))
1489 continue;
1490 StartListening(const_cast<SwFormatField&>(rField));
1491 m_aFormatFields.push_back(&rField);
1494 void EndListeningToAllFields()
1496 for (auto const& pField : m_aFormatFields)
1498 EndListening(const_cast<SwFormatField&>(*pField));
1501 virtual ~FieldDocWatchingStack() override
1503 EndListeningToAllFields();
1504 EndListening(m_rDocShell);
1506 const SwFormatField* pop()
1508 if (m_aFormatFields.empty())
1509 return nullptr;
1510 const SwFormatField* p = m_aFormatFields.back();
1511 EndListening(const_cast<SwFormatField&>(*p));
1512 m_aFormatFields.pop_back();
1513 return p;
1519 // copy to new vector, otherwise RemoveItem would operate and delete stuff on mvPostItFields as well
1520 // RemoveItem will clean up the core field and visible postit if necessary
1521 // we cannot just delete everything as before, as postits could move into change tracking
1522 void SwPostItMgr::Delete(const OUString& rAuthor)
1524 mpWrtShell->StartAllAction();
1525 if (HasActiveSidebarWin() && (GetActiveSidebarWin()->GetAuthor() == rAuthor))
1527 SetActiveSidebarWin(nullptr);
1529 SwRewriter aRewriter;
1530 aRewriter.AddRule(UndoArg1, SwResId(STR_DELETE_AUTHOR_NOTES) + rAuthor);
1531 mpWrtShell->StartUndo( SwUndoId::DELETE, &aRewriter );
1533 IsPostitFieldWithAuthorOf aFilter(rAuthor);
1534 IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
1535 IsFieldNotDeleted aFilter2(rIDRA, aFilter);
1536 FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(), aFilter2);
1537 while (const SwFormatField* pField = aStack.pop())
1539 if (mpWrtShell->GotoField(*pField))
1540 mpWrtShell->DelRight();
1542 mpWrtShell->EndUndo();
1543 PrepareView();
1544 mpWrtShell->EndAllAction();
1545 mbLayout = true;
1546 CalcRects();
1547 LayoutPostIts();
1550 void SwPostItMgr::Delete(sal_uInt32 nPostItId)
1552 mpWrtShell->StartAllAction();
1553 if (HasActiveSidebarWin() &&
1554 mpActivePostIt->GetPostItField()->GetPostItId() == nPostItId)
1556 SetActiveSidebarWin(nullptr);
1558 SwRewriter aRewriter;
1559 aRewriter.AddRule(UndoArg1, SwResId(STR_CONTENT_TYPE_SINGLE_POSTIT));
1560 mpWrtShell->StartUndo( SwUndoId::DELETE, &aRewriter );
1562 IsPostitFieldWithPostitId aFilter(nPostItId);
1563 IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
1564 IsFieldNotDeleted aFilter2(rIDRA, aFilter);
1565 FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(), aFilter2);
1566 const SwFormatField* pField = aStack.pop();
1567 if (pField && mpWrtShell->GotoField(*pField))
1568 mpWrtShell->DelRight();
1569 mpWrtShell->EndUndo();
1570 PrepareView();
1571 mpWrtShell->EndAllAction();
1572 mbLayout = true;
1573 CalcRects();
1574 LayoutPostIts();
1577 void SwPostItMgr::DeleteCommentThread(sal_uInt32 nPostItId)
1579 mpWrtShell->StartAllAction();
1581 SwRewriter aRewriter;
1582 aRewriter.AddRule(UndoArg1, SwResId(STR_CONTENT_TYPE_SINGLE_POSTIT));
1584 // We have no undo ID at the moment.
1586 IsPostitFieldWithPostitId aFilter(nPostItId);
1587 FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(), aFilter);
1588 const SwFormatField* pField = aStack.pop();
1589 // pField now contains our AnnotationWin object
1590 if (pField) {
1591 SwAnnotationWin* pWin = GetSidebarWin(pField);
1592 pWin->DeleteThread();
1594 PrepareView();
1595 mpWrtShell->EndAllAction();
1596 mbLayout = true;
1597 CalcRects();
1598 LayoutPostIts();
1601 void SwPostItMgr::ToggleResolved(sal_uInt32 nPostItId)
1603 mpWrtShell->StartAllAction();
1605 SwRewriter aRewriter;
1606 aRewriter.AddRule(UndoArg1, SwResId(STR_CONTENT_TYPE_SINGLE_POSTIT));
1608 // We have no undo ID at the moment.
1610 IsPostitFieldWithPostitId aFilter(nPostItId);
1611 FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(), aFilter);
1612 const SwFormatField* pField = aStack.pop();
1613 // pField now contains our AnnotationWin object
1614 if (pField) {
1615 SwAnnotationWin* pWin = GetSidebarWin(pField);
1616 pWin->ToggleResolved();
1619 PrepareView();
1620 mpWrtShell->EndAllAction();
1621 mbLayout = true;
1622 CalcRects();
1623 LayoutPostIts();
1626 void SwPostItMgr::ToggleResolvedForThread(sal_uInt32 nPostItId)
1628 mpWrtShell->StartAllAction();
1630 SwRewriter aRewriter;
1631 aRewriter.AddRule(UndoArg1, SwResId(STR_CONTENT_TYPE_SINGLE_POSTIT));
1633 // We have no undo ID at the moment.
1635 IsPostitFieldWithPostitId aFilter(nPostItId);
1636 FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(), aFilter);
1637 const SwFormatField* pField = aStack.pop();
1638 // pField now contains our AnnotationWin object
1639 if (pField) {
1640 SwAnnotationWin* pWin = GetSidebarWin(pField);
1641 pWin->ToggleResolvedForThread();
1644 PrepareView();
1645 mpWrtShell->EndAllAction();
1646 mbLayout = true;
1647 CalcRects();
1648 LayoutPostIts();
1652 void SwPostItMgr::Delete()
1654 mpWrtShell->StartAllAction();
1655 SetActiveSidebarWin(nullptr);
1656 SwRewriter aRewriter;
1657 aRewriter.AddRule(UndoArg1, SwResId(STR_DELETE_ALL_NOTES) );
1658 mpWrtShell->StartUndo( SwUndoId::DELETE, &aRewriter );
1660 IsPostitField aFilter;
1661 IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
1662 IsFieldNotDeleted aFilter2(rIDRA, aFilter);
1663 FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(),
1664 aFilter2);
1665 while (const SwFormatField* pField = aStack.pop())
1667 if (mpWrtShell->GotoField(*pField))
1668 mpWrtShell->DelRight();
1671 mpWrtShell->EndUndo();
1672 PrepareView();
1673 mpWrtShell->EndAllAction();
1674 mbLayout = true;
1675 CalcRects();
1676 LayoutPostIts();
1679 void SwPostItMgr::ExecuteFormatAllDialog(SwView& rView)
1681 if (mvPostItFields.empty())
1682 return;
1683 sw::annotation::SwAnnotationWin *pOrigActiveWin = GetActiveSidebarWin();
1684 sw::annotation::SwAnnotationWin *pWin = pOrigActiveWin;
1685 if (!pWin)
1687 for (auto const& postItField : mvPostItFields)
1689 pWin = postItField->mpPostIt;
1690 if (pWin)
1691 break;
1694 if (!pWin)
1695 return;
1696 SetActiveSidebarWin(pWin);
1697 OutlinerView* pOLV = pWin->GetOutlinerView();
1698 SfxItemSet aEditAttr(pOLV->GetAttribs());
1699 SfxItemPool* pPool(SwAnnotationShell::GetAnnotationPool(rView));
1700 SfxItemSetFixed<XATTR_FILLSTYLE, XATTR_FILLCOLOR, EE_ITEMS_START, EE_ITEMS_END> aDlgAttr(*pPool);
1701 aDlgAttr.Put(aEditAttr);
1702 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
1703 ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateSwCharDlg(rView.GetFrameWeld(), rView, aDlgAttr, SwCharDlgMode::Ann));
1704 sal_uInt16 nRet = pDlg->Execute();
1705 if (RET_OK == nRet)
1707 aDlgAttr.Put(*pDlg->GetOutputItemSet());
1708 FormatAll(aDlgAttr);
1710 pDlg.disposeAndClear();
1711 SetActiveSidebarWin(pOrigActiveWin);
1714 void SwPostItMgr::FormatAll(const SfxItemSet &rNewAttr)
1716 mpWrtShell->StartAllAction();
1717 SwRewriter aRewriter;
1718 aRewriter.AddRule(UndoArg1, SwResId(STR_FORMAT_ALL_NOTES) );
1719 mpWrtShell->StartUndo( SwUndoId::INSATTR, &aRewriter );
1721 for (auto const& postItField : mvPostItFields)
1723 if (!postItField->mpPostIt)
1724 continue;
1725 OutlinerView* pOLV = postItField->mpPostIt->GetOutlinerView();
1726 //save old selection
1727 ESelection aOrigSel(pOLV->GetSelection());
1728 //select all
1729 Outliner *pOutliner = pOLV->GetOutliner();
1730 if (pOutliner)
1732 sal_Int32 nParaCount = pOutliner->GetParagraphCount();
1733 if (nParaCount > 0)
1734 pOLV->SelectRange(0, nParaCount);
1736 //set new char properties
1737 pOLV->SetAttribs(rNewAttr);
1738 //restore old selection
1739 pOLV->SetSelection(aOrigSel);
1740 // tdf#91596 store updated formatting in SwField
1741 postItField->mpPostIt->UpdateData();
1744 mpWrtShell->EndUndo();
1745 PrepareView();
1746 mpWrtShell->EndAllAction();
1747 mbLayout = true;
1748 CalcRects();
1749 LayoutPostIts();
1752 void SwPostItMgr::Hide( std::u16string_view rAuthor )
1754 for (auto const& postItField : mvPostItFields)
1756 if ( postItField->mpPostIt && (postItField->mpPostIt->GetAuthor() == rAuthor) )
1758 postItField->mbShow = false;
1759 postItField->mpPostIt->HideNote();
1763 LayoutPostIts();
1766 void SwPostItMgr::Hide()
1768 for (auto const& postItField : mvPostItFields)
1770 postItField->mbShow = false;
1771 if (postItField->mpPostIt)
1772 postItField->mpPostIt->HideNote();
1776 void SwPostItMgr::Show()
1778 for (auto const& postItField : mvPostItFields)
1780 postItField->mbShow = true;
1782 LayoutPostIts();
1785 SwAnnotationWin* SwPostItMgr::GetSidebarWin( const SfxBroadcaster* pBroadcaster) const
1787 for (auto const& postItField : mvPostItFields)
1789 if ( postItField->GetBroadcaster() == pBroadcaster)
1790 return postItField->mpPostIt;
1792 return nullptr;
1795 sw::annotation::SwAnnotationWin* SwPostItMgr::GetAnnotationWin(const SwPostItField* pField) const
1797 for (auto const& postItField : mvPostItFields)
1799 if ( postItField->GetFormatField().GetField() == pField )
1800 return postItField->mpPostIt.get();
1802 return nullptr;
1805 sw::annotation::SwAnnotationWin* SwPostItMgr::GetAnnotationWin(const sal_uInt32 nPostItId) const
1807 for (auto const& postItField : mvPostItFields)
1809 if ( static_cast<const SwPostItField*>(postItField->GetFormatField().GetField())->GetPostItId() == nPostItId )
1810 return postItField->mpPostIt.get();
1812 return nullptr;
1815 SwPostItField* SwPostItMgr::GetLatestPostItField()
1817 return static_cast<SwPostItField*>(mvPostItFields.back()->GetFormatField().GetField());
1820 SwAnnotationWin* SwPostItMgr::GetNextPostIt( sal_uInt16 aDirection,
1821 SwAnnotationWin* aPostIt )
1823 if (mvPostItFields.size()>1)
1825 auto i = std::find_if(mvPostItFields.begin(), mvPostItFields.end(),
1826 [&aPostIt](const std::unique_ptr<SwSidebarItem>& pField) { return pField->mpPostIt == aPostIt; });
1827 if (i == mvPostItFields.end())
1828 return nullptr;
1830 auto iNextPostIt = i;
1831 if (aDirection == KEY_PAGEUP)
1833 if ( iNextPostIt == mvPostItFields.begin() )
1835 return nullptr;
1837 --iNextPostIt;
1839 else
1841 ++iNextPostIt;
1842 if ( iNextPostIt == mvPostItFields.end() )
1844 return nullptr;
1847 // lets quit, we are back at the beginning
1848 if ( (*iNextPostIt)->mpPostIt == aPostIt)
1849 return nullptr;
1850 return (*iNextPostIt)->mpPostIt;
1852 else
1853 return nullptr;
1856 tools::Long SwPostItMgr::GetNextBorder()
1858 for (auto const& pPage : mPages)
1860 for(auto b = pPage->mvSidebarItems.begin(); b!= pPage->mvSidebarItems.end(); ++b)
1862 if ((*b)->mpPostIt == mpActivePostIt)
1864 auto aNext = b;
1865 ++aNext;
1866 bool bFollow = (aNext != pPage->mvSidebarItems.end()) && (*aNext)->mpPostIt->IsFollow();
1867 if ( pPage->bScrollbar || bFollow )
1869 return -1;
1871 else
1873 //if this is the last item, return the bottom border otherwise the next item
1874 if (aNext == pPage->mvSidebarItems.end())
1875 return mpEditWin->LogicToPixel(Point(0,pPage->mPageRect.Bottom())).Y() - GetSpaceBetween();
1876 else
1877 return (*aNext)->mpPostIt->GetPosPixel().Y() - GetSpaceBetween();
1883 OSL_FAIL("SwPostItMgr::GetNextBorder(): We have to find a next border here");
1884 return -1;
1887 void SwPostItMgr::SetShadowState(const SwPostItField* pField,bool bCursor)
1889 if (pField)
1891 if (pField !=mShadowState.mpShadowField)
1893 if (mShadowState.mpShadowField)
1895 // reset old one if still alive
1896 // TODO: does not work properly if mouse and cursor was set
1897 sw::annotation::SwAnnotationWin* pOldPostIt =
1898 GetAnnotationWin(mShadowState.mpShadowField);
1899 if (pOldPostIt && pOldPostIt->Shadow() && (pOldPostIt->Shadow()->GetShadowState() != SS_EDIT))
1900 pOldPostIt->SetViewState(ViewState::NORMAL);
1902 //set new one, if it is not currently edited
1903 sw::annotation::SwAnnotationWin* pNewPostIt = GetAnnotationWin(pField);
1904 if (pNewPostIt && pNewPostIt->Shadow() && (pNewPostIt->Shadow()->GetShadowState() != SS_EDIT))
1906 pNewPostIt->SetViewState(ViewState::VIEW);
1907 //remember our new field
1908 mShadowState.mpShadowField = pField;
1909 mShadowState.bCursor = false;
1910 mShadowState.bMouse = false;
1913 if (bCursor)
1914 mShadowState.bCursor = true;
1915 else
1916 mShadowState.bMouse = true;
1918 else
1920 if (mShadowState.mpShadowField)
1922 if (bCursor)
1923 mShadowState.bCursor = false;
1924 else
1925 mShadowState.bMouse = false;
1926 if (!mShadowState.bCursor && !mShadowState.bMouse)
1928 // reset old one if still alive
1929 sw::annotation::SwAnnotationWin* pOldPostIt = GetAnnotationWin(mShadowState.mpShadowField);
1930 if (pOldPostIt && pOldPostIt->Shadow() && (pOldPostIt->Shadow()->GetShadowState() != SS_EDIT))
1932 pOldPostIt->SetViewState(ViewState::NORMAL);
1933 mShadowState.mpShadowField = nullptr;
1940 void SwPostItMgr::PrepareView(bool bIgnoreCount)
1942 if (!HasNotes() || bIgnoreCount)
1944 mpWrtShell->StartAllAction();
1945 SwRootFrame* pLayout = mpWrtShell->GetLayout();
1946 if ( pLayout )
1947 SwPostItHelper::setSidebarChanged( pLayout,
1948 mpWrtShell->getIDocumentSettingAccess().get( DocumentSettingId::BROWSE_MODE ) );
1949 mpWrtShell->EndAllAction();
1953 bool SwPostItMgr::ShowScrollbar(const tools::ULong aPage) const
1955 if (mPages.size() > aPage-1)
1956 return (mPages[aPage-1]->bScrollbar && !mbWaitingForCalcRects);
1957 else
1958 return false;
1961 bool SwPostItMgr::IsHit(const Point &aPointPixel)
1963 if (HasNotes() && ShowNotes())
1965 const Point aPoint = mpEditWin->PixelToLogic(aPointPixel);
1966 const SwRootFrame* pLayout = mpWrtShell->GetLayout();
1967 SwRect aPageFrame;
1968 const tools::ULong nPageNum = SwPostItHelper::getPageInfo( aPageFrame, pLayout, aPoint );
1969 if( nPageNum )
1971 tools::Rectangle aRect;
1972 OSL_ENSURE(mPages.size()>nPageNum-1,"SwPostitMgr:: page container size wrong");
1973 aRect = mPages[nPageNum-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT
1974 ? tools::Rectangle(Point(aPageFrame.Left()-GetSidebarWidth()-GetSidebarBorderWidth(),aPageFrame.Top()),Size(GetSidebarWidth(),aPageFrame.Height()))
1975 : tools::Rectangle( Point(aPageFrame.Right()+GetSidebarBorderWidth(),aPageFrame.Top()) , Size(GetSidebarWidth(),aPageFrame.Height()));
1976 if (aRect.Contains(aPoint))
1978 // we hit the note's sidebar
1979 // lets now test for the arrow area
1980 if (mPages[nPageNum-1]->bScrollbar)
1981 return ScrollbarHit(nPageNum,aPoint);
1982 else
1983 return false;
1987 return false;
1990 vcl::Window* SwPostItMgr::IsHitSidebarWindow(const Point& rPointLogic)
1992 vcl::Window* pRet = nullptr;
1994 if (HasNotes() && ShowNotes())
1996 bool bEnableMapMode = !mpEditWin->IsMapModeEnabled();
1997 if (bEnableMapMode)
1998 mpEditWin->EnableMapMode();
2000 for (const std::unique_ptr<SwSidebarItem>& pItem : mvPostItFields)
2002 SwAnnotationWin* pPostIt = pItem->mpPostIt;
2003 if (!pPostIt)
2004 continue;
2006 if (pPostIt->IsHitWindow(rPointLogic))
2008 pRet = pPostIt;
2009 break;
2013 if (bEnableMapMode)
2014 mpEditWin->EnableMapMode(false);
2017 return pRet;
2020 tools::Rectangle SwPostItMgr::GetBottomScrollRect(const tools::ULong aPage) const
2022 SwRect aPageRect = mPages[aPage-1]->mPageRect;
2023 Point aPointBottom = mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT
2024 ? Point(aPageRect.Left() - GetSidebarWidth() - GetSidebarBorderWidth() + mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Bottom()- mpEditWin->PixelToLogic(Size(0,2+GetSidebarScrollerHeight())).Height())
2025 : Point(aPageRect.Right() + GetSidebarBorderWidth() + mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Bottom()- mpEditWin->PixelToLogic(Size(0,2+GetSidebarScrollerHeight())).Height());
2026 Size aSize(GetSidebarWidth() - mpEditWin->PixelToLogic(Size(4,0)).Width(), mpEditWin->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height()) ;
2027 return tools::Rectangle(aPointBottom,aSize);
2030 tools::Rectangle SwPostItMgr::GetTopScrollRect(const tools::ULong aPage) const
2032 SwRect aPageRect = mPages[aPage-1]->mPageRect;
2033 Point aPointTop = mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT
2034 ? Point(aPageRect.Left() - GetSidebarWidth() -GetSidebarBorderWidth()+ mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Top() + mpEditWin->PixelToLogic(Size(0,2)).Height())
2035 : Point(aPageRect.Right() + GetSidebarBorderWidth() + mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Top() + mpEditWin->PixelToLogic(Size(0,2)).Height());
2036 Size aSize(GetSidebarWidth() - mpEditWin->PixelToLogic(Size(4,0)).Width(), mpEditWin->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height()) ;
2037 return tools::Rectangle(aPointTop,aSize);
2040 //IMPORTANT: if you change the rects here, also change SwPageFrame::PaintNotesSidebar()
2041 bool SwPostItMgr::ScrollbarHit(const tools::ULong aPage,const Point &aPoint)
2043 SwRect aPageRect = mPages[aPage-1]->mPageRect;
2044 Point aPointBottom = mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT
2045 ? Point(aPageRect.Left() - GetSidebarWidth()-GetSidebarBorderWidth() + mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Bottom()- mpEditWin->PixelToLogic(Size(0,2+GetSidebarScrollerHeight())).Height())
2046 : Point(aPageRect.Right() + GetSidebarBorderWidth()+ mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Bottom()- mpEditWin->PixelToLogic(Size(0,2+GetSidebarScrollerHeight())).Height());
2048 Point aPointTop = mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT
2049 ? Point(aPageRect.Left() - GetSidebarWidth()-GetSidebarBorderWidth()+ mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Top() + mpEditWin->PixelToLogic(Size(0,2)).Height())
2050 : Point(aPageRect.Right()+GetSidebarBorderWidth()+ mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Top() + mpEditWin->PixelToLogic(Size(0,2)).Height());
2052 tools::Rectangle aRectBottom(GetBottomScrollRect(aPage));
2053 tools::Rectangle aRectTop(GetTopScrollRect(aPage));
2055 if (aRectBottom.Contains(aPoint))
2057 if (aPoint.X() < tools::Long((aPointBottom.X() + GetSidebarWidth()/3)))
2058 Scroll( GetScrollSize(),aPage);
2059 else
2060 Scroll( -1*GetScrollSize(), aPage);
2061 return true;
2063 else if (aRectTop.Contains(aPoint))
2065 if (aPoint.X() < tools::Long((aPointTop.X() + GetSidebarWidth()/3*2)))
2066 Scroll(GetScrollSize(), aPage);
2067 else
2068 Scroll(-1*GetScrollSize(), aPage);
2069 return true;
2071 return false;
2074 void SwPostItMgr::CorrectPositions()
2076 if ( mbWaitingForCalcRects || mbLayouting || mvPostItFields.empty() )
2077 return;
2079 // find first valid note
2080 SwAnnotationWin *pFirstPostIt = nullptr;
2081 for (auto const& postItField : mvPostItFields)
2083 pFirstPostIt = postItField->mpPostIt;
2084 if (pFirstPostIt)
2085 break;
2088 //if we have not found a valid note, forget about it and leave
2089 if (!pFirstPostIt)
2090 return;
2092 // 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
2093 // check, if anchor overlay object exists.
2094 const tools::Long aAnchorX = pFirstPostIt->Anchor()
2095 ? mpEditWin->LogicToPixel( Point(static_cast<tools::Long>(pFirstPostIt->Anchor()->GetSixthPosition().getX()),0)).X()
2096 : 0;
2097 const tools::Long aAnchorY = pFirstPostIt->Anchor()
2098 ? mpEditWin->LogicToPixel( Point(0,static_cast<tools::Long>(pFirstPostIt->Anchor()->GetSixthPosition().getY()))).Y() + 1
2099 : 0;
2100 if (Point(aAnchorX,aAnchorY) == pFirstPostIt->GetPosPixel())
2101 return;
2103 tools::Long aAnchorPosX = 0;
2104 tools::Long aAnchorPosY = 0;
2105 for (const std::unique_ptr<SwPostItPageItem>& pPage : mPages)
2107 for (auto const& item : pPage->mvSidebarItems)
2109 // check, if anchor overlay object exists.
2110 if ( item->mbShow && item->mpPostIt && item->mpPostIt->Anchor() )
2112 aAnchorPosX = pPage->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT
2113 ? mpEditWin->LogicToPixel( Point(static_cast<tools::Long>(item->mpPostIt->Anchor()->GetSeventhPosition().getX()),0)).X()
2114 : mpEditWin->LogicToPixel( Point(static_cast<tools::Long>(item->mpPostIt->Anchor()->GetSixthPosition().getX()),0)).X();
2115 aAnchorPosY = mpEditWin->LogicToPixel( Point(0,static_cast<tools::Long>(item->mpPostIt->Anchor()->GetSixthPosition().getY()))).Y() + 1;
2116 item->mpPostIt->SetPosPixel(Point(aAnchorPosX,aAnchorPosY));
2122 bool SwPostItMgr::ShowNotes() const
2124 // we only want to see notes if Options - Writer - View - Notes is ticked
2125 return mpWrtShell->GetViewOptions()->IsPostIts();
2128 bool SwPostItMgr::HasNotes() const
2130 return !mvPostItFields.empty();
2133 tools::ULong SwPostItMgr::GetSidebarWidth(bool bPx) const
2135 bool bEnableMapMode = !mpWrtShell->GetOut()->IsMapModeEnabled();
2136 sal_uInt16 nZoom = mpWrtShell->GetViewOptions()->GetZoom();
2137 if (comphelper::LibreOfficeKit::isActive() && !bEnableMapMode)
2139 // The output device is the tile and contains the real wanted scale factor.
2140 double fScaleX = double(mpWrtShell->GetOut()->GetMapMode().GetScaleX());
2141 nZoom = fScaleX * 100;
2143 tools::ULong aWidth = static_cast<tools::ULong>(nZoom * 1.8);
2145 if (bPx)
2146 return aWidth;
2147 else
2149 if (bEnableMapMode)
2150 // The output device is the window.
2151 mpWrtShell->GetOut()->EnableMapMode();
2152 tools::Long nRet = mpWrtShell->GetOut()->PixelToLogic(Size(aWidth, 0)).Width();
2153 if (bEnableMapMode)
2154 mpWrtShell->GetOut()->EnableMapMode(false);
2155 return nRet;
2159 tools::ULong SwPostItMgr::GetSidebarBorderWidth(bool bPx) const
2161 if (bPx)
2162 return 2;
2163 else
2164 return mpWrtShell->GetOut()->PixelToLogic(Size(2,0)).Width();
2167 Color SwPostItMgr::GetColorDark(std::size_t aAuthorIndex)
2169 if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
2171 static const Color aArrayNormal[] = {
2172 COL_AUTHOR1_NORMAL, COL_AUTHOR2_NORMAL, COL_AUTHOR3_NORMAL,
2173 COL_AUTHOR4_NORMAL, COL_AUTHOR5_NORMAL, COL_AUTHOR6_NORMAL,
2174 COL_AUTHOR7_NORMAL, COL_AUTHOR8_NORMAL, COL_AUTHOR9_NORMAL };
2176 return aArrayNormal[ aAuthorIndex % SAL_N_ELEMENTS( aArrayNormal )];
2178 else
2179 return COL_WHITE;
2182 Color SwPostItMgr::GetColorLight(std::size_t aAuthorIndex)
2184 if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
2186 static const Color aArrayLight[] = {
2187 COL_AUTHOR1_LIGHT, COL_AUTHOR2_LIGHT, COL_AUTHOR3_LIGHT,
2188 COL_AUTHOR4_LIGHT, COL_AUTHOR5_LIGHT, COL_AUTHOR6_LIGHT,
2189 COL_AUTHOR7_LIGHT, COL_AUTHOR8_LIGHT, COL_AUTHOR9_LIGHT };
2191 return aArrayLight[ aAuthorIndex % SAL_N_ELEMENTS( aArrayLight )];
2193 else
2194 return COL_WHITE;
2197 Color SwPostItMgr::GetColorAnchor(std::size_t aAuthorIndex)
2199 if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
2201 static const Color aArrayAnchor[] = {
2202 COL_AUTHOR1_DARK, COL_AUTHOR2_DARK, COL_AUTHOR3_DARK,
2203 COL_AUTHOR4_DARK, COL_AUTHOR5_DARK, COL_AUTHOR6_DARK,
2204 COL_AUTHOR7_DARK, COL_AUTHOR8_DARK, COL_AUTHOR9_DARK };
2206 return aArrayAnchor[ aAuthorIndex % SAL_N_ELEMENTS( aArrayAnchor )];
2208 else
2209 return COL_WHITE;
2212 void SwPostItMgr::SetActiveSidebarWin( SwAnnotationWin* p)
2214 if ( p == mpActivePostIt )
2215 return;
2217 // we need the temp variable so we can set mpActivePostIt before we call DeactivatePostIt
2218 // therefore we get a new layout in DOCCHANGED when switching from postit to document,
2219 // otherwise, GetActivePostIt() would still hold our old postit
2220 SwAnnotationWin* pActive = mpActivePostIt;
2221 mpActivePostIt = p;
2222 if (pActive)
2224 pActive->DeactivatePostIt();
2225 mShadowState.mpShadowField = nullptr;
2227 if (mpActivePostIt)
2229 mpActivePostIt->GotoPos();
2230 mpView->AttrChangedNotify(nullptr);
2231 mpActivePostIt->ActivatePostIt();
2235 IMPL_LINK_NOARG( SwPostItMgr, CalcHdl, void*, void )
2237 mnEventId = nullptr;
2238 if ( mbLayouting )
2240 OSL_FAIL("Reentrance problem in Layout Manager!");
2241 mbWaitingForCalcRects = false;
2242 return;
2245 // do not change order, even if it would seem so in the first place, we need the calcrects always
2246 if (CalcRects() || mbLayout)
2248 mbLayout = false;
2249 LayoutPostIts();
2253 void SwPostItMgr::Rescale()
2255 for (auto const& postItField : mvPostItFields)
2256 if ( postItField->mpPostIt )
2257 postItField->mpPostIt->Rescale();
2260 sal_Int32 SwPostItMgr::GetInitialAnchorDistance() const
2262 const Fraction& f( mpEditWin->GetMapMode().GetScaleY() );
2263 return sal_Int32(POSTIT_INITIAL_ANCHOR_DISTANCE * f);
2266 sal_Int32 SwPostItMgr::GetSpaceBetween() const
2268 const Fraction& f( mpEditWin->GetMapMode().GetScaleY() );
2269 return sal_Int32(POSTIT_SPACE_BETWEEN * f);
2272 sal_Int32 SwPostItMgr::GetScrollSize() const
2274 const Fraction& f( mpEditWin->GetMapMode().GetScaleY() );
2275 return sal_Int32((POSTIT_SPACE_BETWEEN + POSTIT_MINIMUMSIZE_WITH_META) * f);
2278 sal_Int32 SwPostItMgr::GetMinimumSizeWithMeta() const
2280 const Fraction& f( mpEditWin->GetMapMode().GetScaleY() );
2281 return sal_Int32(POSTIT_MINIMUMSIZE_WITH_META * f);
2284 sal_Int32 SwPostItMgr::GetSidebarScrollerHeight() const
2286 const Fraction& f( mpEditWin->GetMapMode().GetScaleY() );
2287 return sal_Int32(POSTIT_SCROLL_SIDEBAR_HEIGHT * f);
2290 void SwPostItMgr::SetSpellChecking()
2292 for (auto const& postItField : mvPostItFields)
2293 if ( postItField->mpPostIt )
2294 postItField->mpPostIt->SetSpellChecking();
2297 void SwPostItMgr::SetReadOnlyState()
2299 for (auto const& postItField : mvPostItFields)
2300 if ( postItField->mpPostIt )
2301 postItField->mpPostIt->SetReadonly( mbReadOnly );
2304 void SwPostItMgr::CheckMetaText()
2306 for (auto const& postItField : mvPostItFields)
2307 if ( postItField->mpPostIt )
2308 postItField->mpPostIt->CheckMetaText();
2312 sal_uInt16 SwPostItMgr::Replace(SvxSearchItem const * pItem)
2314 SwAnnotationWin* pWin = GetActiveSidebarWin();
2315 sal_uInt16 aResult = pWin->GetOutlinerView()->StartSearchAndReplace( *pItem );
2316 if (!aResult)
2317 SetActiveSidebarWin(nullptr);
2318 return aResult;
2321 sal_uInt16 SwPostItMgr::FinishSearchReplace(const i18nutil::SearchOptions2& rSearchOptions, bool bSrchForward)
2323 SwAnnotationWin* pWin = GetActiveSidebarWin();
2324 SvxSearchItem aItem(SID_SEARCH_ITEM );
2325 aItem.SetSearchOptions(rSearchOptions);
2326 aItem.SetBackward(!bSrchForward);
2327 sal_uInt16 aResult = pWin->GetOutlinerView()->StartSearchAndReplace( aItem );
2328 if (!aResult)
2329 SetActiveSidebarWin(nullptr);
2330 return aResult;
2333 sal_uInt16 SwPostItMgr::SearchReplace(const SwFormatField &pField, const i18nutil::SearchOptions2& rSearchOptions, bool bSrchForward)
2335 sal_uInt16 aResult = 0;
2336 SwAnnotationWin* pWin = GetSidebarWin(&pField);
2337 if (pWin)
2339 ESelection aOldSelection = pWin->GetOutlinerView()->GetSelection();
2340 if (bSrchForward)
2341 pWin->GetOutlinerView()->SetSelection(ESelection(0,0,0,0));
2342 else
2343 pWin->GetOutlinerView()->SetSelection(
2344 ESelection(EE_PARA_MAX_COUNT,EE_TEXTPOS_MAX_COUNT,EE_PARA_MAX_COUNT,EE_TEXTPOS_MAX_COUNT));
2345 SvxSearchItem aItem(SID_SEARCH_ITEM );
2346 aItem.SetSearchOptions(rSearchOptions);
2347 aItem.SetBackward(!bSrchForward);
2348 aResult = pWin->GetOutlinerView()->StartSearchAndReplace( aItem );
2349 if (!aResult)
2350 pWin->GetOutlinerView()->SetSelection(aOldSelection);
2351 else
2353 SetActiveSidebarWin(pWin);
2354 MakeVisible(pWin);
2357 return aResult;
2360 void SwPostItMgr::AssureStdModeAtShell()
2362 // deselect any drawing or frame and leave editing mode
2363 SdrView* pSdrView = mpWrtShell->GetDrawView();
2364 if ( pSdrView && pSdrView->IsTextEdit() )
2366 bool bLockView = mpWrtShell->IsViewLocked();
2367 mpWrtShell->LockView( true );
2368 mpWrtShell->EndTextEdit();
2369 mpWrtShell->LockView( bLockView );
2372 if( mpWrtShell->IsSelFrameMode() || mpWrtShell->IsObjSelected())
2374 mpWrtShell->UnSelectFrame();
2375 mpWrtShell->LeaveSelFrameMode();
2376 mpWrtShell->GetView().LeaveDrawCreate();
2377 mpWrtShell->EnterStdMode();
2379 mpWrtShell->DrawSelChanged();
2380 mpView->StopShellTimer();
2384 bool SwPostItMgr::HasActiveSidebarWin() const
2386 return mpActivePostIt != nullptr;
2389 bool SwPostItMgr::HasActiveAnnotationWin() const
2391 return HasActiveSidebarWin() &&
2392 mpActivePostIt != nullptr;
2395 void SwPostItMgr::GrabFocusOnActiveSidebarWin()
2397 if ( HasActiveSidebarWin() )
2399 mpActivePostIt->GrabFocus();
2403 void SwPostItMgr::UpdateDataOnActiveSidebarWin()
2405 if ( HasActiveSidebarWin() )
2407 mpActivePostIt->UpdateData();
2411 void SwPostItMgr::DeleteActiveSidebarWin()
2413 if ( HasActiveSidebarWin() )
2415 mpActivePostIt->Delete();
2419 void SwPostItMgr::HideActiveSidebarWin()
2421 if ( HasActiveSidebarWin() )
2423 mpActivePostIt->Hide();
2427 void SwPostItMgr::ToggleInsModeOnActiveSidebarWin()
2429 if ( HasActiveSidebarWin() )
2431 mpActivePostIt->ToggleInsMode();
2435 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
2436 void SwPostItMgr::ConnectSidebarWinToFrame( const SwFrame& rFrame,
2437 const SwFormatField& rFormatField,
2438 SwAnnotationWin& rSidebarWin )
2440 if ( mpFrameSidebarWinContainer == nullptr )
2442 mpFrameSidebarWinContainer.reset(new SwFrameSidebarWinContainer());
2445 const bool bInserted = mpFrameSidebarWinContainer->insert( rFrame, rFormatField, rSidebarWin );
2446 if ( bInserted &&
2447 mpWrtShell->GetAccessibleMap() )
2449 mpWrtShell->GetAccessibleMap()->InvalidatePosOrSize( nullptr, nullptr, &rSidebarWin, SwRect() );
2453 void SwPostItMgr::DisconnectSidebarWinFromFrame( const SwFrame& rFrame,
2454 SwAnnotationWin& rSidebarWin )
2456 if ( mpFrameSidebarWinContainer != nullptr )
2458 const bool bRemoved = mpFrameSidebarWinContainer->remove( rFrame, rSidebarWin );
2459 if ( bRemoved &&
2460 mpWrtShell->GetAccessibleMap() )
2462 mpWrtShell->GetAccessibleMap()->A11yDispose( nullptr, nullptr, &rSidebarWin );
2466 #endif // ENABLE_WASM_STRIP_ACCESSIBILITY
2468 bool SwPostItMgr::HasFrameConnectedSidebarWins( const SwFrame& rFrame )
2470 bool bRet( false );
2472 if ( mpFrameSidebarWinContainer != nullptr )
2474 bRet = !mpFrameSidebarWinContainer->empty( rFrame );
2477 return bRet;
2480 vcl::Window* SwPostItMgr::GetSidebarWinForFrameByIndex( const SwFrame& rFrame,
2481 const sal_Int32 nIndex )
2483 vcl::Window* pSidebarWin( nullptr );
2485 if ( mpFrameSidebarWinContainer != nullptr )
2487 pSidebarWin = mpFrameSidebarWinContainer->get( rFrame, nIndex );
2490 return pSidebarWin;
2493 void SwPostItMgr::GetAllSidebarWinForFrame( const SwFrame& rFrame,
2494 std::vector< vcl::Window* >* pChildren )
2496 if ( mpFrameSidebarWinContainer != nullptr )
2498 mpFrameSidebarWinContainer->getAll( rFrame, pChildren );
2502 void SwPostItMgr::ShowHideResolvedNotes(bool visible) {
2503 for (auto const& pPage : mPages)
2505 for(auto b = pPage->mvSidebarItems.begin(); b!= pPage->mvSidebarItems.end(); ++b)
2507 if ((*b)->mpPostIt->IsResolved())
2509 (*b)->mpPostIt->SetResolved(true);
2510 (*b)->mpPostIt->GetSidebarItem().mbShow = visible;
2514 LayoutPostIts();
2517 void SwPostItMgr::UpdateResolvedStatus(const sw::annotation::SwAnnotationWin* topNote) {
2518 // Given the topmost note as an argument, scans over all notes and sets the
2519 // 'resolved' state of each descendant of the top notes to the resolved state
2520 // of the top note.
2521 bool resolved = topNote->IsResolved();
2522 for (auto const& pPage : mPages)
2524 for(auto b = pPage->mvSidebarItems.begin(); b!= pPage->mvSidebarItems.end(); ++b)
2526 if((*b)->mpPostIt->GetTopReplyNote() == topNote) {
2527 (*b)->mpPostIt->SetResolved(resolved);
2533 void SwNoteProps::ImplCommit() {}
2534 void SwNoteProps::Notify( const css::uno::Sequence< OUString >& ) {}
2536 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */