Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 192, column 9
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name PostItMgr.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx

/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <boost/property_tree/json_parser.hpp>
21
22#include <PostItMgr.hxx>
23#include <postithelper.hxx>
24
25#include <AnnotationWin.hxx>
26#include "frmsidebarwincontainer.hxx"
27#include <accmap.hxx>
28
29#include <SidebarWindowsConsts.hxx>
30#include "AnchorOverlayObject.hxx"
31#include "ShadowOverlayObject.hxx"
32
33#include <vcl/svapp.hxx>
34#include <vcl/outdev.hxx>
35#include <vcl/settings.hxx>
36
37#include <chrdlgmodes.hxx>
38#include <viewopt.hxx>
39#include <view.hxx>
40#include <docsh.hxx>
41#include <wrtsh.hxx>
42#include <doc.hxx>
43#include <IDocumentSettingAccess.hxx>
44#include <IDocumentFieldsAccess.hxx>
45#include <fldbas.hxx>
46#include <fmtfld.hxx>
47#include <docufld.hxx>
48#include <edtwin.hxx>
49#include <txtfld.hxx>
50#include <txtannotationfld.hxx>
51#include <rootfrm.hxx>
52#include <SwRewriter.hxx>
53#include <tools/color.hxx>
54#include <unotools/datetime.hxx>
55
56#include <swmodule.hxx>
57#include <strings.hrc>
58#include <cmdid.h>
59
60#include <sfx2/request.hxx>
61#include <sfx2/event.hxx>
62#include <svl/srchitem.hxx>
63
64#include <svl/languageoptions.hxx>
65#include <svl/hint.hxx>
66
67#include <svx/svdview.hxx>
68#include <editeng/eeitem.hxx>
69#include <editeng/langitem.hxx>
70#include <editeng/outliner.hxx>
71#include <editeng/outlobj.hxx>
72
73#include <comphelper/lok.hxx>
74#include <comphelper/string.hxx>
75#include <LibreOfficeKit/LibreOfficeKitEnums.h>
76
77#include <annotsh.hxx>
78#include <swabstdlg.hxx>
79#include <memory>
80
81// distance between Anchor Y and initial note position
82#define POSTIT_INITIAL_ANCHOR_DISTANCE20 20
83//distance between two postits
84#define POSTIT_SPACE_BETWEEN8 8
85#define POSTIT_MINIMUMSIZE_WITH_META60 60
86#define POSTIT_SCROLL_SIDEBAR_HEIGHT20 20
87
88// if we layout more often we stop, this should never happen
89#define MAX_LOOP_COUNT50 50
90
91using namespace sw::sidebarwindows;
92using namespace sw::annotation;
93
94namespace {
95
96 enum class CommentNotificationType { Add, Remove, Modify, Resolve };
97
98 bool comp_pos(const std::unique_ptr<SwSidebarItem>& a, const std::unique_ptr<SwSidebarItem>& b)
99 {
100 // sort by anchor position
101 SwPosition aPosAnchorA = a->GetAnchorPosition();
102 SwPosition aPosAnchorB = b->GetAnchorPosition();
103
104 bool aAnchorAInFooter = false;
105 bool aAnchorBInFooter = false;
106
107 // is the anchor placed in Footnote or the Footer?
108 if( aPosAnchorA.nNode.GetNode().FindFootnoteStartNode() || aPosAnchorA.nNode.GetNode().FindFooterStartNode() )
109 aAnchorAInFooter = true;
110 if( aPosAnchorB.nNode.GetNode().FindFootnoteStartNode() || aPosAnchorB.nNode.GetNode().FindFooterStartNode() )
111 aAnchorBInFooter = true;
112
113 // fdo#34800
114 // if AnchorA is in footnote, and AnchorB isn't
115 // we do not want to change over the position
116 if( aAnchorAInFooter && !aAnchorBInFooter )
117 return false;
118 // if aAnchorA is not placed in a footnote, and aAnchorB is
119 // force a change over
120 else if( !aAnchorAInFooter && aAnchorBInFooter )
121 return true;
122 // If neither or both are in the footer, compare the positions.
123 // Since footnotes are in Inserts section of nodes array and footers
124 // in Autotext section, all footnotes precede any footers so no need
125 // to check that.
126 else
127 return aPosAnchorA < aPosAnchorB;
128 }
129
130 /// Emits LOK notification about one addition/removal/change of a comment
131 void lcl_CommentNotification(const SwView* pView, const CommentNotificationType nType, const SwSidebarItem* pItem, const sal_uInt32 nPostItId)
132 {
133 if (!comphelper::LibreOfficeKit::isActive())
134 return;
135
136 boost::property_tree::ptree aAnnotation;
137 aAnnotation.put("action", (nType == CommentNotificationType::Add ? "Add" :
138 (nType == CommentNotificationType::Remove ? "Remove" :
139 (nType == CommentNotificationType::Modify ? "Modify" :
140 (nType == CommentNotificationType::Resolve ? "Resolve" : "???")))));
141 aAnnotation.put("id", nPostItId);
142 if (nType != CommentNotificationType::Remove && pItem != nullptr)
143 {
144 sw::annotation::SwAnnotationWin* pWin = pItem->mpPostIt.get();
145
146 const SwPostItField* pField = pWin->GetPostItField();
147 const SwRect& aRect = pWin->GetAnchorRect();
148 tools::Rectangle aSVRect(aRect.Pos().getX(),
149 aRect.Pos().getY(),
150 aRect.Pos().getX() + aRect.SSize().Width(),
151 aRect.Pos().getY() + aRect.SSize().Height());
152
153 if (!pItem->maLayoutInfo.mPositionFromCommentAnchor)
154 {
155 // Comments on frames: anchor position is the corner position, not the whole frame.
156 aSVRect.SetSize(Size(0, 0));
157 }
158
159 std::vector<OString> aRects;
160 for (const basegfx::B2DRange& aRange : pWin->GetAnnotationTextRanges())
161 {
162 const SwRect rect(aRange.getMinX(), aRange.getMinY(), aRange.getWidth(), aRange.getHeight());
163 aRects.push_back(rect.SVRect().toString());
164 }
165 const OString sRects = comphelper::string::join("; ", aRects);
166
167 aAnnotation.put("id", pField->GetPostItId());
168 aAnnotation.put("parent", pWin->CalcParent());
169 aAnnotation.put("author", pField->GetPar1().toUtf8().getStr());
170 aAnnotation.put("text", pField->GetPar2().toUtf8().getStr());
171 aAnnotation.put("resolved", pField->GetResolved() ? "true" : "false");
172 aAnnotation.put("dateTime", utl::toISO8601(pField->GetDateTime().GetUNODateTime()));
173 aAnnotation.put("anchorPos", aSVRect.toString());
174 aAnnotation.put("textRange", sRects.getStr());
175 }
176
177 boost::property_tree::ptree aTree;
178 aTree.add_child("comment", aAnnotation);
179 std::stringstream aStream;
180 boost::property_tree::write_json(aStream, aTree);
181 std::string aPayload = aStream.str();
182
183 if (pView)
184 {
185 pView->libreOfficeKitViewCallback(LOK_CALLBACK_COMMENT, aPayload.c_str());
186 }
187 }
188
189} // anonymous namespace
190
191SwPostItMgr::SwPostItMgr(SwView* pView)
192 : mpView(pView)
193 , mpWrtShell(mpView->GetDocShell()->GetWrtShell())
194 , mpEditWin(&mpView->GetEditWin())
195 , mnEventId(nullptr)
196 , mbWaitingForCalcRects(false)
197 , mpActivePostIt(nullptr)
198 , mbLayout(false)
199 , mbLayoutHeight(0)
200 , mbLayouting(false)
201 , mbReadOnly(mpView->GetDocShell()->IsReadOnly())
202 , mbDeleteNote(true)
203 , mpAnswer(nullptr)
204 , mbIsShowAnchor( false )
205{
206 if(!mpView->GetDrawView() )
207 mpView->GetWrtShell().MakeDrawView();
208
209 SwNoteProps aProps;
210 mbIsShowAnchor = aProps.IsShowAnchor();
211
212 //make sure we get the colour yellow always, even if not the first one of comments or redlining
213 SW_MOD()( static_cast<SwModule*>(SfxApplication::GetModule(SfxToolsModule
::Writer)))
->GetRedlineAuthor();
214
215 // collect all PostIts and redline comments that exist after loading the document
216 // don't check for existence for any of them, don't focus them
217 AddPostIts(false,false);
218 /* this code can be used once we want redline comments in the Sidebar
219 AddRedlineComments(false,false);
220 */
221 // we want to receive stuff like SfxHintId::DocChanged
222 StartListening(*mpView->GetDocShell());
223 if (!mvPostItFields.empty())
224 {
225 mbWaitingForCalcRects = true;
226 mnEventId = Application::PostUserEvent( LINK( this, SwPostItMgr, CalcHdl)::tools::detail::makeLink( ::tools::detail::castTo<SwPostItMgr
*>(this), &SwPostItMgr::LinkStubCalcHdl)
);
227 }
228}
229
230SwPostItMgr::~SwPostItMgr()
231{
232 if ( mnEventId )
233 Application::RemoveUserEvent( mnEventId );
234 // forget about all our Sidebar windows
235 RemoveSidebarWin();
236 EndListening( *mpView->GetDocShell() );
237
238 mPages.clear();
239}
240
241void SwPostItMgr::CheckForRemovedPostIts()
242{
243 IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
244 bool bRemoved = false;
245 auto it = mvPostItFields.begin();
246 while(it != mvPostItFields.end())
247 {
248 if (!(*it)->UseElement(*mpWrtShell->GetLayout(), rIDRA))
249 {
250 EndListening(const_cast<SfxBroadcaster&>(*(*it)->GetBroadcaster()));
251 std::unique_ptr<SwSidebarItem> p = std::move(*it);
252 it = mvPostItFields.erase(it);
253 if (GetActiveSidebarWin() == p->mpPostIt)
254 SetActiveSidebarWin(nullptr);
255 p->mpPostIt.disposeAndClear();
256 bRemoved = true;
257 }
258 else
259 ++it;
260 }
261
262 if ( !bRemoved )
263 return;
264
265 // make sure that no deleted items remain in page lists
266 // todo: only remove deleted ones?!
267 if ( mvPostItFields.empty() )
268 {
269 PreparePageContainer();
270 PrepareView();
271 }
272 else
273 // if postits are their make sure that page lists are not empty
274 // otherwise sudden paints can cause pain (in BorderOverPageBorder)
275 CalcRects();
276}
277
278SwSidebarItem* SwPostItMgr::InsertItem(SfxBroadcaster* pItem, bool bCheckExistence, bool bFocus)
279{
280 if (bCheckExistence)
281 {
282 for (auto const& postItField : mvPostItFields)
283 {
284 if ( postItField->GetBroadcaster() == pItem )
285 return nullptr;
286 }
287 }
288 mbLayout = bFocus;
289
290 SwSidebarItem* pAnnotationItem = nullptr;
291 if (dynamic_cast< const SwFormatField *>( pItem ) != nullptr)
292 {
293 mvPostItFields.push_back(std::make_unique<SwAnnotationItem>(static_cast<SwFormatField&>(*pItem), bFocus));
294 pAnnotationItem = mvPostItFields.back().get();
295 }
296 OSL_ENSURE(dynamic_cast< const SwFormatField *>( pItem ) != nullptr,"Mgr::InsertItem: seems like new stuff was added")do { if (true && (!(dynamic_cast< const SwFormatField
*>( pItem ) != nullptr))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
":" "296" ": "), "%s", "Mgr::InsertItem: seems like new stuff was added"
); } } while (false)
;
297 StartListening(*pItem);
298 return pAnnotationItem;
299}
300
301void SwPostItMgr::RemoveItem( SfxBroadcaster* pBroadcast )
302{
303 EndListening(*pBroadcast);
304 auto i = std::find_if(mvPostItFields.begin(), mvPostItFields.end(),
305 [&pBroadcast](const std::unique_ptr<SwSidebarItem>& pField) { return pField->GetBroadcaster() == pBroadcast; });
306 if (i != mvPostItFields.end())
1
Taking true branch
307 {
308 std::unique_ptr<SwSidebarItem> p = std::move(*i);
309 // tdf#120487 remove from list before dispose, so comment window
310 // won't be recreated due to the entry still in the list if focus
311 // transferring from the pPostIt triggers relayout of postits
312 // tdf#133348 remove from list before calling SetActiveSidebarWin
313 // so GetNextPostIt won't deal with mvPostItFields containing empty unique_ptr
314 mvPostItFields.erase(i);
315 if (GetActiveSidebarWin() == p->mpPostIt)
2
Taking false branch
316 SetActiveSidebarWin(nullptr);
317 p->mpPostIt.disposeAndClear();
3
Calling 'VclPtr::disposeAndClear'
318 }
319 mbLayout = true;
320 PrepareView();
321}
322
323void SwPostItMgr::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
324{
325 if ( const SfxEventHint* pSfxEventHint = dynamic_cast<const SfxEventHint*>(&rHint) )
326 {
327 if ( pSfxEventHint->GetEventId() == SfxEventHintId::SwEventLayoutFinished )
328 {
329 if ( !mbWaitingForCalcRects && !mvPostItFields.empty())
330 {
331 mbWaitingForCalcRects = true;
332 mnEventId = Application::PostUserEvent( LINK( this, SwPostItMgr, CalcHdl)::tools::detail::makeLink( ::tools::detail::castTo<SwPostItMgr
*>(this), &SwPostItMgr::LinkStubCalcHdl)
);
333 }
334 }
335 }
336 else if ( const SwFormatFieldHint * pFormatHint = dynamic_cast<const SwFormatFieldHint*>(&rHint) )
337 {
338 SwFormatField* pField = const_cast <SwFormatField*>( pFormatHint->GetField() );
339 switch ( pFormatHint->Which() )
340 {
341 case SwFormatFieldHintWhich::INSERTED :
342 {
343 if (!pField)
344 {
345 AddPostIts();
346 break;
347 }
348 // get field to be inserted from hint
349 if ( pField->IsFieldInDoc() )
350 {
351 bool bEmpty = !HasNotes();
352 SwSidebarItem* pItem = InsertItem( pField, true, false );
353
354 if (bEmpty && !mvPostItFields.empty())
355 PrepareView(true);
356
357 // True until the layout of this post it finishes
358 if (pItem)
359 pItem->mbPendingLayout = true;
360 }
361 else
362 {
363 OSL_FAIL("Inserted field not in document!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
":" "363" ": "), "%s", "Inserted field not in document!"); }
} while (false)
;
364 }
365 break;
366 }
367 case SwFormatFieldHintWhich::REMOVED:
368 {
369 if (mbDeleteNote)
370 {
371 if (!pField)
372 {
373 CheckForRemovedPostIts();
374 break;
375 }
376 RemoveItem(pField);
377
378 // If LOK has disabled tiled annotations, emit annotation callbacks
379 if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
380 {
381 SwPostItField* pPostItField = static_cast<SwPostItField*>(pField->GetField());
382 lcl_CommentNotification(mpView, CommentNotificationType::Remove, nullptr, pPostItField->GetPostItId());
383 }
384 }
385 break;
386 }
387 case SwFormatFieldHintWhich::FOCUS:
388 {
389 if (pFormatHint->GetView()== mpView)
390 Focus(rBC);
391 break;
392 }
393 case SwFormatFieldHintWhich::CHANGED:
394 case SwFormatFieldHintWhich::RESOLVED:
395 {
396 SwFormatField* pFormatField = dynamic_cast<SwFormatField*>(&rBC);
397 for (auto const& postItField : mvPostItFields)
398 {
399 if ( pFormatField == postItField->GetBroadcaster() )
400 {
401 if (postItField->mpPostIt)
402 {
403 postItField->mpPostIt->SetPostItText();
404 mbLayout = true;
405 }
406
407 // If LOK has disabled tiled annotations, emit annotation callbacks
408 if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
409 {
410 if(SwFormatFieldHintWhich::CHANGED == pFormatHint->Which())
411 lcl_CommentNotification(mpView, CommentNotificationType::Modify, postItField.get(), 0);
412 else
413 lcl_CommentNotification(mpView, CommentNotificationType::Resolve, postItField.get(), 0);
414 }
415 break;
416 }
417 }
418 break;
419 }
420
421 case SwFormatFieldHintWhich::LANGUAGE:
422 {
423 SwFormatField* pFormatField = dynamic_cast<SwFormatField*>(&rBC);
424 for (auto const& postItField : mvPostItFields)
425 {
426 if ( pFormatField == postItField->GetBroadcaster() )
427 {
428 if (postItField->mpPostIt)
429 {
430 const SvtScriptType nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( postItField->GetFormatField().GetField()->GetLanguage() );
431 sal_uInt16 nLangWhichId = 0;
432 switch (nScriptType)
433 {
434 case SvtScriptType::LATIN : nLangWhichId = EE_CHAR_LANGUAGE ; break;
435 case SvtScriptType::ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break;
436 case SvtScriptType::COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break;
437 default: break;
438 }
439 postItField->mpPostIt->SetLanguage(
440 SvxLanguageItem(
441 postItField->GetFormatField().GetField()->GetLanguage(),
442 nLangWhichId) );
443 }
444 break;
445 }
446 }
447 break;
448 }
449 }
450 }
451 else
452 {
453 SfxHintId nId = rHint.GetId();
454 switch ( nId )
455 {
456 case SfxHintId::ModeChanged:
457 {
458 if ( mbReadOnly != mpView->GetDocShell()->IsReadOnly() )
459 {
460 mbReadOnly = !mbReadOnly;
461 SetReadOnlyState();
462 mbLayout = true;
463 }
464 break;
465 }
466 case SfxHintId::DocChanged:
467 {
468 if ( mpView->GetDocShell() == &rBC )
469 {
470 if ( !mbWaitingForCalcRects && !mvPostItFields.empty())
471 {
472 mbWaitingForCalcRects = true;
473 mnEventId = Application::PostUserEvent( LINK( this, SwPostItMgr, CalcHdl)::tools::detail::makeLink( ::tools::detail::castTo<SwPostItMgr
*>(this), &SwPostItMgr::LinkStubCalcHdl)
);
474 }
475 }
476 break;
477 }
478 case SfxHintId::SwSplitNodeOperation:
479 {
480 // if we are in a SplitNode/Cut operation, do not delete note and then add again, as this will flicker
481 mbDeleteNote = !mbDeleteNote;
482 break;
483 }
484 case SfxHintId::Dying:
485 {
486 if ( mpView->GetDocShell() != &rBC )
487 {
488 // field to be removed is the broadcaster
489 OSL_FAIL("Notification for removed SwFormatField was not sent!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
":" "489" ": "), "%s", "Notification for removed SwFormatField was not sent!"
); } } while (false)
;
490 RemoveItem(&rBC);
491 }
492 break;
493 }
494 default: break;
495 }
496 }
497}
498
499void SwPostItMgr::Focus(SfxBroadcaster& rBC)
500{
501 if (!mpWrtShell->GetViewOptions()->IsPostIts())
502 {
503 SfxRequest aRequest(mpView->GetViewFrame(), SID_TOGGLE_NOTES( 10000 + 1098 ));
504 mpView->ExecViewOptions(aRequest);
505 }
506
507 for (auto const& postItField : mvPostItFields)
508 {
509 // field to get the focus is the broadcaster
510 if ( &rBC == postItField->GetBroadcaster() )
511 {
512 if (postItField->mpPostIt)
513 {
514 postItField->mpPostIt->GrabFocus();
515 MakeVisible(postItField->mpPostIt);
516 }
517 else
518 {
519 // when the layout algorithm starts, this postit is created and receives focus
520 postItField->mbFocus = true;
521 }
522 }
523 }
524}
525
526bool SwPostItMgr::CalcRects()
527{
528 if ( mnEventId )
529 {
530 // if CalcRects() was forced and an event is still pending: remove it
531 // it is superfluous and also may cause reentrance problems if triggered while layouting
532 Application::RemoveUserEvent( mnEventId );
533 mnEventId = nullptr;
534 }
535
536 bool bChange = false;
537 bool bRepair = false;
538 PreparePageContainer();
539 if ( !mvPostItFields.empty() )
540 {
541 IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
542 for (auto const& pItem : mvPostItFields)
543 {
544 if (!pItem->UseElement(*mpWrtShell->GetLayout(), rIDRA))
545 {
546 OSL_FAIL("PostIt is not in doc or other wrong use")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
":" "546" ": "), "%s", "PostIt is not in doc or other wrong use"
); } } while (false)
;
547 bRepair = true;
548 continue;
549 }
550 const SwRect aOldAnchorRect( pItem->maLayoutInfo.mPosition );
551 const SwPostItHelper::SwLayoutStatus eOldLayoutStatus = pItem->mLayoutStatus;
552 const sal_uLong nOldStartNodeIdx( pItem->maLayoutInfo.mnStartNodeIdx );
553 const sal_Int32 nOldStartContent( pItem->maLayoutInfo.mnStartContent );
554 {
555 // update layout information
556 const SwTextAnnotationField* pTextAnnotationField =
557 dynamic_cast< const SwTextAnnotationField* >( pItem->GetFormatField().GetTextField() );
558 const ::sw::mark::IMark* pAnnotationMark =
559 pTextAnnotationField != nullptr ? pTextAnnotationField->GetAnnotationMark() : nullptr;
560 if ( pAnnotationMark != nullptr )
561 {
562 pItem->mLayoutStatus =
563 SwPostItHelper::getLayoutInfos(
564 pItem->maLayoutInfo,
565 pItem->GetAnchorPosition(),
566 pAnnotationMark );
567 }
568 else
569 {
570 pItem->mLayoutStatus =
571 SwPostItHelper::getLayoutInfos( pItem->maLayoutInfo, pItem->GetAnchorPosition() );
572 }
573 }
574 bChange = bChange
575 || pItem->maLayoutInfo.mPosition != aOldAnchorRect
576 || pItem->mLayoutStatus != eOldLayoutStatus
577 || pItem->maLayoutInfo.mnStartNodeIdx != nOldStartNodeIdx
578 || pItem->maLayoutInfo.mnStartContent != nOldStartContent;
579 }
580
581 // show notes in right order in navigator
582 //prevent Anchors during layout to overlap, e.g. when moving a frame
583 if (mvPostItFields.size()>1 )
584 std::stable_sort(mvPostItFields.begin(), mvPostItFields.end(), comp_pos);
585
586 // sort the items into the right page vector, so layout can be done by page
587 for (auto const& pItem : mvPostItFields)
588 {
589 if( SwPostItHelper::INVISIBLE == pItem->mLayoutStatus )
590 {
591 if (pItem->mpPostIt)
592 pItem->mpPostIt->HideNote();
593 continue;
594 }
595
596 if( SwPostItHelper::HIDDEN == pItem->mLayoutStatus )
597 {
598 if (!mpWrtShell->GetViewOptions()->IsShowHiddenChar())
599 {
600 if (pItem->mpPostIt)
601 pItem->mpPostIt->HideNote();
602 continue;
603 }
604 }
605
606 const unsigned long aPageNum = pItem->maLayoutInfo.mnPageNumber;
607 if (aPageNum > mPages.size())
608 {
609 const unsigned long nNumberOfPages = mPages.size();
610 mPages.reserve(aPageNum);
611 for (unsigned long j=0; j<aPageNum - nNumberOfPages; ++j)
612 mPages.emplace_back( new SwPostItPageItem());
613 }
614 mPages[aPageNum-1]->mvSidebarItems.push_back(pItem.get());
615 mPages[aPageNum-1]->mPageRect = pItem->maLayoutInfo.mPageFrame;
616 mPages[aPageNum-1]->eSidebarPosition = pItem->maLayoutInfo.meSidebarPosition;
617 }
618
619 if (!bChange && mpWrtShell->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE))
620 {
621 long nLayoutHeight = SwPostItHelper::getLayoutHeight( mpWrtShell->GetLayout() );
622 if( nLayoutHeight > mbLayoutHeight )
623 {
624 if (mPages[0]->bScrollbar || HasScrollbars())
625 bChange = true;
626 }
627 else if( nLayoutHeight < mbLayoutHeight )
628 {
629 if (mPages[0]->bScrollbar || !BorderOverPageBorder(1))
630 bChange = true;
631 }
632 }
633 }
634
635 if ( bRepair )
636 CheckForRemovedPostIts();
637
638 mbLayoutHeight = SwPostItHelper::getLayoutHeight( mpWrtShell->GetLayout() );
639 mbWaitingForCalcRects = false;
640 return bChange;
641}
642
643bool SwPostItMgr::HasScrollbars() const
644{
645 for (auto const& postItField : mvPostItFields)
646 {
647 if (postItField->mbShow && postItField->mpPostIt && postItField->mpPostIt->HasScrollbar())
648 return true;
649 }
650 return false;
651}
652
653void SwPostItMgr::PreparePageContainer()
654{
655 // we do not just delete the SwPostItPageItem, so offset/scrollbar is not lost
656 long lPageSize = mpWrtShell->GetNumPages();
657 long lContainerSize = mPages.size();
658
659 if (lContainerSize < lPageSize)
660 {
661 mPages.reserve(lPageSize);
662 for (long i=0; i<lPageSize - lContainerSize;i++)
663 mPages.emplace_back( new SwPostItPageItem());
664 }
665 else if (lContainerSize > lPageSize)
666 {
667 for (int i=mPages.size()-1; i >= lPageSize;--i)
668 {
669 mPages.pop_back();
670 }
671 }
672 // only clear the list, DO NOT delete the objects itself
673 for (auto const& page : mPages)
674 {
675 page->mvSidebarItems.clear();
676 if (mvPostItFields.empty())
677 page->bScrollbar = false;
678 }
679}
680
681void SwPostItMgr::LayoutPostIts()
682{
683 bool bEnableMapMode = comphelper::LibreOfficeKit::isActive() && !mpEditWin->IsMapModeEnabled();
684 if (bEnableMapMode)
685 mpEditWin->EnableMapMode();
686
687 if ( !mvPostItFields.empty() && !mbWaitingForCalcRects )
688 {
689 mbLayouting = true;
690
691 //loop over all pages and do the layout
692 // - create SwPostIt if necessary
693 // - place SwPostIts on their initial position
694 // - calculate necessary height for all PostIts together
695 bool bUpdate = false;
696 for (std::unique_ptr<SwPostItPageItem>& pPage : mPages)
697 {
698 // only layout if there are notes on this page
699 if (!pPage->mvSidebarItems.empty())
700 {
701 std::vector<SwAnnotationWin*> aVisiblePostItList;
702 unsigned long lNeededHeight = 0;
703 long mlPageBorder = 0;
704 long mlPageEnd = 0;
705
706 for (auto const& pItem : pPage->mvSidebarItems)
707 {
708 VclPtr<SwAnnotationWin> pPostIt = pItem->mpPostIt;
709
710 if (pPage->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT )
711 {
712 // x value for notes positioning
713 mlPageBorder = mpEditWin->LogicToPixel( Point( pPage->mPageRect.Left(), 0)).X() - GetSidebarWidth(true);// - GetSidebarBorderWidth(true);
714 //bending point
715 mlPageEnd =
716 mpWrtShell->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE)
717 ? pItem->maLayoutInfo.mPagePrtArea.Left()
718 : pPage->mPageRect.Left() + 350;
719 }
720 else if (pPage->eSidebarPosition == sw::sidebarwindows::SidebarPosition::RIGHT )
721 {
722 // x value for notes positioning
723 mlPageBorder = mpEditWin->LogicToPixel( Point(pPage->mPageRect.Right(), 0)).X() + GetSidebarBorderWidth(true);
724 //bending point
725 mlPageEnd =
726 mpWrtShell->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE)
727 ? pItem->maLayoutInfo.mPagePrtArea.Right() :
728 pPage->mPageRect.Right() - 350;
729 }
730
731 if (pItem->mbShow)
732 {
733 long Y = mpEditWin->LogicToPixel( Point(0,pItem->maLayoutInfo.mPosition.Bottom())).Y();
734 long aPostItHeight = 0;
735 if (!pPostIt)
736 {
737 pPostIt = pItem->GetSidebarWindow( mpView->GetEditWin(),
738 *this );
739 pPostIt->InitControls();
740 pPostIt->SetReadonly(mbReadOnly);
741 pItem->mpPostIt = pPostIt;
742 if (mpAnswer)
743 {
744 if (static_cast<bool>(pPostIt->CalcParent())) //do we really have another note in front of this one
745 pPostIt->InitAnswer(mpAnswer);
746 delete mpAnswer;
747 mpAnswer = nullptr;
748 }
749 }
750
751 pPostIt->SetChangeTracking(
752 pItem->mLayoutStatus,
753 GetColorAnchor(pItem->maLayoutInfo.mRedlineAuthor));
754 pPostIt->SetSidebarPosition(pPage->eSidebarPosition);
755 pPostIt->SetFollow(static_cast<bool>(pPostIt->CalcParent()));
756 aPostItHeight = ( pPostIt->GetPostItTextHeight() < pPostIt->GetMinimumSizeWithoutMeta()
757 ? pPostIt->GetMinimumSizeWithoutMeta()
758 : pPostIt->GetPostItTextHeight() )
759 + pPostIt->GetMetaHeight();
760 pPostIt->SetPosSizePixelRect( mlPageBorder ,
761 Y - GetInitialAnchorDistance(),
762 GetSidebarWidth(true),
763 aPostItHeight,
764 pItem->maLayoutInfo.mPosition,
765 mlPageEnd );
766 pPostIt->ChangeSidebarItem( *pItem );
767
768 if (pItem->mbFocus)
769 {
770 mbLayout = true;
771 pPostIt->GrabFocus();
772 pItem->mbFocus = false;
773 }
774 // only the visible postits are used for the final layout
775 aVisiblePostItList.push_back(pPostIt);
776 lNeededHeight += pPostIt->IsFollow() ? aPostItHeight : aPostItHeight+GetSpaceBetween();
777 }
778 else // we don't want to see it
779 {
780 if (pPostIt)
781 pPostIt->HideNote();
782 }
783 }
784
785 if ((!aVisiblePostItList.empty()) && ShowNotes())
786 {
787 bool bOldScrollbar = pPage->bScrollbar;
788 if (ShowNotes())
789 pPage->bScrollbar = LayoutByPage(aVisiblePostItList, pPage->mPageRect.SVRect(), lNeededHeight);
790 else
791 pPage->bScrollbar = false;
792 if (!pPage->bScrollbar)
793 {
794 pPage->lOffset = 0;
795 }
796 else if (sal_Int32 nScrollSize = GetScrollSize())
797 {
798 //when we changed our zoom level, the offset value can be too big, so lets check for the largest possible zoom value
799 long aAvailableHeight = mpEditWin->LogicToPixel(Size(0,pPage->mPageRect.Height())).Height() - 2 * GetSidebarScrollerHeight();
800 long lOffset = -1 * nScrollSize * (aVisiblePostItList.size() - aAvailableHeight / nScrollSize);
801 if (pPage->lOffset < lOffset)
802 pPage->lOffset = lOffset;
803 }
804 bUpdate = (bOldScrollbar != pPage->bScrollbar) || bUpdate;
805 const long aSidebarheight = pPage->bScrollbar ? mpEditWin->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height() : 0;
806 /*
807 TODO
808 - enlarge all notes till GetNextBorder(), as we resized to average value before
809 */
810 //lets hide the ones which overlap the page
811 for (auto const& visiblePostIt : aVisiblePostItList)
812 {
813 if (pPage->lOffset != 0)
814 visiblePostIt->TranslateTopPosition(pPage->lOffset);
815
816 bool bBottom = mpEditWin->PixelToLogic(Point(0,visiblePostIt->VirtualPos().Y()+visiblePostIt->VirtualSize().Height())).Y() <= (pPage->mPageRect.Bottom()-aSidebarheight);
817 bool bTop = mpEditWin->PixelToLogic(Point(0,visiblePostIt->VirtualPos().Y())).Y() >= (pPage->mPageRect.Top()+aSidebarheight);
818 if ( bBottom && bTop )
819 {
820 // When tiled rendering, make sure that only the
821 // view that has the comment focus emits callbacks,
822 // so the editing view jumps to the comment, but
823 // not the others.
824 bool bTiledPainting = comphelper::LibreOfficeKit::isTiledPainting();
825 if (!bTiledPainting)
826 // No focus -> disable callbacks.
827 comphelper::LibreOfficeKit::setTiledPainting(!visiblePostIt->HasChildPathFocus());
828 visiblePostIt->ShowNote();
829 if (!bTiledPainting)
830 {
831 comphelper::LibreOfficeKit::setTiledPainting(bTiledPainting);
832 visiblePostIt->InvalidateControl();
833 }
834 }
835 else
836 {
837 if (mpEditWin->PixelToLogic(Point(0,visiblePostIt->VirtualPos().Y())).Y() < (pPage->mPageRect.Top()+aSidebarheight))
838 {
839 if ( pPage->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT )
840 visiblePostIt->ShowAnchorOnly(Point( pPage->mPageRect.Left(),
841 pPage->mPageRect.Top()));
842 else if ( pPage->eSidebarPosition == sw::sidebarwindows::SidebarPosition::RIGHT )
843 visiblePostIt->ShowAnchorOnly(Point( pPage->mPageRect.Right(),
844 pPage->mPageRect.Top()));
845 }
846 else
847 {
848 if ( pPage->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT )
849 visiblePostIt->ShowAnchorOnly(Point(pPage->mPageRect.Left(),
850 pPage->mPageRect.Bottom()));
851 else if ( pPage->eSidebarPosition == sw::sidebarwindows::SidebarPosition::RIGHT )
852 visiblePostIt->ShowAnchorOnly(Point(pPage->mPageRect.Right(),
853 pPage->mPageRect.Bottom()));
854 }
855 OSL_ENSURE(pPage->bScrollbar,"SwPostItMgr::LayoutByPage(): note overlaps, but bScrollbar is not true")do { if (true && (!(pPage->bScrollbar))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
":" "855" ": "), "%s", "SwPostItMgr::LayoutByPage(): note overlaps, but bScrollbar is not true"
); } } while (false)
;
856 }
857 }
858 }
859 else
860 {
861 for (auto const& visiblePostIt : aVisiblePostItList)
862 {
863 visiblePostIt->SetPosAndSize();
864 }
865
866 bool bOldScrollbar = pPage->bScrollbar;
867 pPage->bScrollbar = false;
868 bUpdate = (bOldScrollbar != pPage->bScrollbar) || bUpdate;
869 }
870
871 for (auto const& visiblePostIt : aVisiblePostItList)
872 {
873 if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
874 {
875 if (visiblePostIt->GetSidebarItem().mbPendingLayout)
876 lcl_CommentNotification(mpView, CommentNotificationType::Add, &visiblePostIt->GetSidebarItem(), 0);
877 else if (visiblePostIt->IsAnchorRectChanged())
878 {
879 lcl_CommentNotification(mpView, CommentNotificationType::Modify, &visiblePostIt->GetSidebarItem(), 0);
880 visiblePostIt->ResetAnchorRectChanged();
881 }
882 }
883
884 // Layout for this post it finished now
885 visiblePostIt->GetSidebarItem().mbPendingLayout = false;
886 }
887 }
888 else
889 {
890 if (pPage->bScrollbar)
891 bUpdate = true;
892 pPage->bScrollbar = false;
893 }
894 }
895
896 if (!ShowNotes())
897 { // we do not want to see the notes anymore -> Options-Writer-View-Notes
898 IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
899 bool bRepair = false;
900 for (auto const& postItField : mvPostItFields)
901 {
902 if (!postItField->UseElement(*mpWrtShell->GetLayout(), rIDRA))
903 {
904 OSL_FAIL("PostIt is not in doc!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
":" "904" ": "), "%s", "PostIt is not in doc!"); } } while (
false)
;
905 bRepair = true;
906 continue;
907 }
908
909 if (postItField->mpPostIt)
910 {
911 postItField->mpPostIt->HideNote();
912 if (postItField->mpPostIt->HasChildPathFocus())
913 {
914 SetActiveSidebarWin(nullptr);
915 postItField->mpPostIt->GrabFocusToDocument();
916 }
917 }
918 }
919
920 if ( bRepair )
921 CheckForRemovedPostIts();
922 }
923
924 // notes scrollbar is otherwise not drawn correctly for some cases
925 // scrollbar area is enough
926 if (bUpdate)
927 mpEditWin->Invalidate(); /*This is a super expensive relayout and render of the entire page*/
928
929 mbLayouting = false;
930 }
931
932 if (bEnableMapMode)
933 mpEditWin->EnableMapMode(false);
934}
935
936bool SwPostItMgr::BorderOverPageBorder(unsigned long aPage) const
937{
938 if ( mPages[aPage-1]->mvSidebarItems.empty() )
939 {
940 OSL_FAIL("Notes SidePane painted but no rects and page lists calculated!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
":" "940" ": "), "%s", "Notes SidePane painted but no rects and page lists calculated!"
); } } while (false)
;
941 return false;
942 }
943
944 auto aItem = mPages[aPage-1]->mvSidebarItems.end();
945 --aItem;
946 OSL_ENSURE ((*aItem)->mpPostIt,"BorderOverPageBorder: NULL postIt, should never happen")do { if (true && (!((*aItem)->mpPostIt))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
":" "946" ": "), "%s", "BorderOverPageBorder: NULL postIt, should never happen"
); } } while (false)
;
947 if ((*aItem)->mpPostIt)
948 {
949 const long aSidebarheight = mPages[aPage-1]->bScrollbar ? mpEditWin->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height() : 0;
950 const long aEndValue = mpEditWin->PixelToLogic(Point(0,(*aItem)->mpPostIt->GetPosPixel().Y()+(*aItem)->mpPostIt->GetSizePixel().Height())).Y();
951 return aEndValue <= mPages[aPage-1]->mPageRect.Bottom()-aSidebarheight;
952 }
953 else
954 return false;
955}
956
957void SwPostItMgr::DrawNotesForPage(OutputDevice *pOutDev, sal_uInt32 nPage)
958{
959 assert(nPage < mPages.size())(static_cast <bool> (nPage < mPages.size()) ? void (
0) : __assert_fail ("nPage < mPages.size()", "/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
, 959, __extension__ __PRETTY_FUNCTION__))
;
960 if (nPage >= mPages.size())
961 return;
962 for (auto const& pItem : mPages[nPage]->mvSidebarItems)
963 {
964 SwAnnotationWin* pPostIt = pItem->mpPostIt;
965 if (!pPostIt)
966 continue;
967 Point aPoint(mpEditWin->PixelToLogic(pPostIt->GetPosPixel()));
968 pPostIt->Draw(pOutDev, aPoint, DrawFlags::NONE);
969 }
970}
971
972void SwPostItMgr::PaintTile(OutputDevice& rRenderContext)
973{
974 for (const std::unique_ptr<SwSidebarItem>& pItem : mvPostItFields)
975 {
976 SwAnnotationWin* pPostIt = pItem->mpPostIt;
977 if (!pPostIt)
978 continue;
979
980 bool bEnableMapMode = !mpEditWin->IsMapModeEnabled();
981 mpEditWin->EnableMapMode();
982 rRenderContext.Push(PushFlags::MAPMODE);
983 Point aOffset(mpEditWin->PixelToLogic(pPostIt->GetPosPixel()));
984 MapMode aMapMode(rRenderContext.GetMapMode());
985 aMapMode.SetOrigin(aMapMode.GetOrigin() + aOffset);
986 rRenderContext.SetMapMode(aMapMode);
987 Size aSize(rRenderContext.PixelToLogic(pPostIt->GetSizePixel()));
988 tools::Rectangle aRectangle(Point(0, 0), aSize);
989
990 pPostIt->PaintTile(rRenderContext, aRectangle);
991
992 rRenderContext.Pop();
993 if (bEnableMapMode)
994 mpEditWin->EnableMapMode(false);
995 }
996}
997
998void SwPostItMgr::Scroll(const long lScroll,const unsigned long aPage)
999{
1000 OSL_ENSURE((lScroll % GetScrollSize() )==0,"SwPostItMgr::Scroll: scrolling by wrong value")do { if (true && (!((lScroll % GetScrollSize() )==0))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
":" "1000" ": "), "%s", "SwPostItMgr::Scroll: scrolling by wrong value"
); } } while (false)
;
1001 // do not scroll more than necessary up or down
1002 if ( ((mPages[aPage-1]->lOffset == 0) && (lScroll>0)) || ( BorderOverPageBorder(aPage) && (lScroll<0)) )
1003 return;
1004
1005 const bool bOldUp = ArrowEnabled(KEY_PAGEUP,aPage);
1006 const bool bOldDown = ArrowEnabled(KEY_PAGEDOWN,aPage);
1007 const long aSidebarheight = mpEditWin->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height();
1008 for (auto const& item : mPages[aPage-1]->mvSidebarItems)
1009 {
1010 SwAnnotationWin* pPostIt = item->mpPostIt;
1011 // if this is an answer, we should take the normal position and not the real, slightly moved position
1012 pPostIt->SetVirtualPosSize(pPostIt->GetPosPixel(),pPostIt->GetSizePixel());
1013 pPostIt->TranslateTopPosition(lScroll);
1014
1015 if (item->mbShow)
1016 {
1017 bool bBottom = mpEditWin->PixelToLogic(Point(0,pPostIt->VirtualPos().Y()+pPostIt->VirtualSize().Height())).Y() <= (mPages[aPage-1]->mPageRect.Bottom()-aSidebarheight);
1018 bool bTop = mpEditWin->PixelToLogic(Point(0,pPostIt->VirtualPos().Y())).Y() >= (mPages[aPage-1]->mPageRect.Top()+aSidebarheight);
1019 if ( bBottom && bTop)
1020 {
1021 pPostIt->ShowNote();
1022 }
1023 else
1024 {
1025 if ( mpEditWin->PixelToLogic(Point(0,pPostIt->VirtualPos().Y())).Y() < (mPages[aPage-1]->mPageRect.Top()+aSidebarheight))
1026 {
1027 if (mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT)
1028 pPostIt->ShowAnchorOnly(Point(mPages[aPage-1]->mPageRect.Left(),mPages[aPage-1]->mPageRect.Top()));
1029 else if (mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::RIGHT)
1030 pPostIt->ShowAnchorOnly(Point(mPages[aPage-1]->mPageRect.Right(),mPages[aPage-1]->mPageRect.Top()));
1031 }
1032 else
1033 {
1034 if (mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT)
1035 pPostIt->ShowAnchorOnly(Point(mPages[aPage-1]->mPageRect.Left(),mPages[aPage-1]->mPageRect.Bottom()));
1036 else if (mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::RIGHT)
1037 pPostIt->ShowAnchorOnly(Point(mPages[aPage-1]->mPageRect.Right(),mPages[aPage-1]->mPageRect.Bottom()));
1038 }
1039 }
1040 }
1041 }
1042 mPages[aPage-1]->lOffset += lScroll;
1043 if ( (bOldUp != ArrowEnabled(KEY_PAGEUP,aPage)) ||(bOldDown != ArrowEnabled(KEY_PAGEDOWN,aPage)) )
1044 {
1045 mpEditWin->Invalidate(GetBottomScrollRect(aPage));
1046 mpEditWin->Invalidate(GetTopScrollRect(aPage));
1047 }
1048}
1049
1050void SwPostItMgr::AutoScroll(const SwAnnotationWin* pPostIt,const unsigned long aPage )
1051{
1052 // otherwise all notes are visible
1053 if (!mPages[aPage-1]->bScrollbar)
1054 return;
1055
1056 const long aSidebarheight = mpEditWin->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height();
1057 const bool bBottom = mpEditWin->PixelToLogic(Point(0,pPostIt->GetPosPixel().Y()+pPostIt->GetSizePixel().Height())).Y() <= (mPages[aPage-1]->mPageRect.Bottom()-aSidebarheight);
1058 const bool bTop = mpEditWin->PixelToLogic(Point(0,pPostIt->GetPosPixel().Y())).Y() >= (mPages[aPage-1]->mPageRect.Top()+aSidebarheight);
1059 if ( !(bBottom && bTop))
1060 {
1061 const long aDiff = bBottom ? mpEditWin->LogicToPixel(Point(0,mPages[aPage-1]->mPageRect.Top() + aSidebarheight)).Y() - pPostIt->GetPosPixel().Y() :
1062 mpEditWin->LogicToPixel(Point(0,mPages[aPage-1]->mPageRect.Bottom() - aSidebarheight)).Y() - (pPostIt->GetPosPixel().Y()+pPostIt->GetSizePixel().Height());
1063 // this just adds the missing value to get the next a* GetScrollSize() after aDiff
1064 // e.g aDiff= 61 POSTIT_SCROLL=50 --> lScroll = 100
1065 const auto nScrollSize = GetScrollSize();
1066 assert(nScrollSize)(static_cast <bool> (nScrollSize) ? void (0) : __assert_fail
("nScrollSize", "/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
, 1066, __extension__ __PRETTY_FUNCTION__))
;
1067 const long lScroll = bBottom ? (aDiff + ( nScrollSize - (aDiff % nScrollSize))) : (aDiff - (nScrollSize + (aDiff % nScrollSize)));
1068 Scroll(lScroll, aPage);
1069 }
1070}
1071
1072void SwPostItMgr::MakeVisible(const SwAnnotationWin* pPostIt )
1073{
1074 long aPage = -1;
1075 // we don't know the page yet, lets find it ourselves
1076 std::vector<SwPostItPageItem*>::size_type n=0;
1077 for (auto const& page : mPages)
1078 {
1079 for (auto const& item : page->mvSidebarItems)
1080 {
1081 if (item->mpPostIt==pPostIt)
1082 {
1083 aPage = n+1;
1084 break;
1085 }
1086 }
1087 ++n;
1088 }
1089 if (aPage!=-1)
1090 AutoScroll(pPostIt,aPage);
1091 tools::Rectangle aNoteRect (Point(pPostIt->GetPosPixel().X(),pPostIt->GetPosPixel().Y()-5),pPostIt->GetSizePixel());
1092 if (!aNoteRect.IsEmpty())
1093 mpWrtShell->MakeVisible(SwRect(mpEditWin->PixelToLogic(aNoteRect)));
1094}
1095
1096bool SwPostItMgr::ArrowEnabled(sal_uInt16 aDirection,unsigned long aPage) const
1097{
1098 switch (aDirection)
1099 {
1100 case KEY_PAGEUP:
1101 {
1102 return (mPages[aPage-1]->lOffset != 0);
1103 }
1104 case KEY_PAGEDOWN:
1105 {
1106 return (!BorderOverPageBorder(aPage));
1107 }
1108 default: return false;
1109 }
1110}
1111
1112Color SwPostItMgr::GetArrowColor(sal_uInt16 aDirection,unsigned long aPage) const
1113{
1114 if (ArrowEnabled(aDirection,aPage))
1115 {
1116 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode())
1117 return COL_WHITE;
1118 else
1119 return COL_NOTES_SIDEPANE_ARROW_ENABLEDColor(0,0,0);
1120 }
1121 else
1122 {
1123 return COL_NOTES_SIDEPANE_ARROW_DISABLEDColor(172,168,153);
1124 }
1125}
1126
1127bool SwPostItMgr::LayoutByPage(std::vector<SwAnnotationWin*> &aVisiblePostItList, const tools::Rectangle& rBorder, long lNeededHeight)
1128{
1129 /*** General layout idea:***/
1130 // - if we have space left, we always move the current one up,
1131 // otherwise the next one down
1132 // - first all notes are resized
1133 // - then the real layout starts
1134
1135 //rBorder is the page rect
1136 const tools::Rectangle aBorder = mpEditWin->LogicToPixel(rBorder);
1137 long lTopBorder = aBorder.Top() + 5;
1138 long lBottomBorder = aBorder.Bottom() - 5;
1139 const long lVisibleHeight = lBottomBorder - lTopBorder; //aBorder.GetHeight() ;
1140 const size_t nPostItListSize = aVisiblePostItList.size();
1141 long lTranslatePos = 0;
1142 bool bScrollbars = false;
1143
1144 // do all necessary resizings
1145 if (nPostItListSize > 0 && lVisibleHeight < lNeededHeight)
1146 {
1147 // ok, now we have to really resize and adding scrollbars
1148 const long lAverageHeight = (lVisibleHeight - nPostItListSize*GetSpaceBetween()) / nPostItListSize;
1149 if (lAverageHeight<GetMinimumSizeWithMeta())
1150 {
1151 bScrollbars = true;
1152 lTopBorder += GetSidebarScrollerHeight() + 10;
1153 lBottomBorder -= (GetSidebarScrollerHeight() + 10);
1154 for (auto const& visiblePostIt : aVisiblePostItList)
1155 visiblePostIt->SetSize(Size(visiblePostIt->VirtualSize().getWidth(),visiblePostIt->GetMinimumSizeWithMeta()));
1156 }
1157 else
1158 {
1159 for (auto const& visiblePostIt : aVisiblePostItList)
1160 {
1161 if ( visiblePostIt->VirtualSize().getHeight() > lAverageHeight)
1162 visiblePostIt->SetSize(Size(visiblePostIt->VirtualSize().getWidth(),lAverageHeight));
1163 }
1164 }
1165 }
1166
1167 //start the real layout so nothing overlaps anymore
1168 if (aVisiblePostItList.size()>1)
1169 {
1170 int loop = 0;
1171 bool bDone = false;
1172 // if no window is moved anymore we are finished
1173 while (!bDone)
1174 {
1175 loop++;
1176 bDone = true;
1177 long lSpaceUsed = lTopBorder + GetSpaceBetween();
1178 for(auto i = aVisiblePostItList.begin(); i != aVisiblePostItList.end() ; ++i)
1179 {
1180 auto aNextPostIt = i;
1181 ++aNextPostIt;
1182
1183 if (aNextPostIt != aVisiblePostItList.end())
1184 {
1185 lTranslatePos = ( (*i)->VirtualPos().Y() + (*i)->VirtualSize().Height()) - (*aNextPostIt)->VirtualPos().Y();
1186 if (lTranslatePos > 0) // note windows overlaps the next one
1187 {
1188 // we are not done yet, loop at least once more
1189 bDone = false;
1190 // if there is space left, move the current note up
1191 // it could also happen that there is no space left for the first note due to a scrollbar
1192 // then we also jump into, so we move the current one up and the next one down
1193 if ( (lSpaceUsed <= (*i)->VirtualPos().Y()) || (i==aVisiblePostItList.begin()))
1194 {
1195 // we have space left, so let's move the current one up
1196 if ( ((*i)->VirtualPos().Y()- lTranslatePos - GetSpaceBetween()) > lTopBorder)
1197 {
1198 if ((*aNextPostIt)->IsFollow())
1199 (*i)->TranslateTopPosition(-1*(lTranslatePos+ANCHORLINE_WIDTH));
1200 else
1201 (*i)->TranslateTopPosition(-1*(lTranslatePos+GetSpaceBetween()));
1202 }
1203 else
1204 {
1205 long lMoveUp = (*i)->VirtualPos().Y() - lTopBorder;
1206 (*i)->TranslateTopPosition(-1* lMoveUp);
1207 if ((*aNextPostIt)->IsFollow())
1208 (*aNextPostIt)->TranslateTopPosition( (lTranslatePos+ANCHORLINE_WIDTH) - lMoveUp);
1209 else
1210 (*aNextPostIt)->TranslateTopPosition( (lTranslatePos+GetSpaceBetween()) - lMoveUp);
1211 }
1212 }
1213 else
1214 {
1215 // no space left, left move the next one down
1216 if ((*aNextPostIt)->IsFollow())
1217 (*aNextPostIt)->TranslateTopPosition(lTranslatePos+ANCHORLINE_WIDTH);
1218 else
1219 (*aNextPostIt)->TranslateTopPosition(lTranslatePos+GetSpaceBetween());
1220 }
1221 }
1222 else
1223 {
1224 // the first one could overlap the topborder instead of a second note
1225 if (i==aVisiblePostItList.begin())
1226 {
1227 long lMoveDown = lTopBorder - (*i)->VirtualPos().Y();
1228 if (lMoveDown>0)
1229 {
1230 bDone = false;
1231 (*i)->TranslateTopPosition( lMoveDown);
1232 }
1233 }
1234 }
1235 if ( (*aNextPostIt)->IsFollow() )
1236 lSpaceUsed += (*i)->VirtualSize().Height() + ANCHORLINE_WIDTH;
1237 else
1238 lSpaceUsed += (*i)->VirtualSize().Height() + GetSpaceBetween();
1239 }
1240 else
1241 {
1242 //(*i) is the last visible item
1243 auto aPrevPostIt = i;
1244 --aPrevPostIt;
1245 lTranslatePos = ( (*aPrevPostIt)->VirtualPos().Y() + (*aPrevPostIt)->VirtualSize().Height() ) - (*i)->VirtualPos().Y();
1246 if (lTranslatePos > 0)
1247 {
1248 bDone = false;
1249 if ( ((*i)->VirtualPos().Y()+ (*i)->VirtualSize().Height()+lTranslatePos) < lBottomBorder)
1250 {
1251 if ( (*i)->IsFollow() )
1252 (*i)->TranslateTopPosition(lTranslatePos+ANCHORLINE_WIDTH);
1253 else
1254 (*i)->TranslateTopPosition(lTranslatePos+GetSpaceBetween());
1255 }
1256 else
1257 {
1258 (*i)->TranslateTopPosition(lBottomBorder - ((*i)->VirtualPos().Y()+ (*i)->VirtualSize().Height()) );
1259 }
1260 }
1261 else
1262 {
1263 // note does not overlap, but we might be over the lower border
1264 // only do this if there are no scrollbars, otherwise notes are supposed to overlap the border
1265 if (!bScrollbars && ((*i)->VirtualPos().Y()+ (*i)->VirtualSize().Height() > lBottomBorder) )
1266 {
1267 bDone = false;
1268 (*i)->TranslateTopPosition(lBottomBorder - ((*i)->VirtualPos().Y()+ (*i)->VirtualSize().Height()));
1269 }
1270 }
1271 }
1272 }
1273 // security check so we don't loop forever
1274 if (loop>MAX_LOOP_COUNT50)
1275 {
1276 OSL_FAIL("PostItMgr::Layout(): We are looping forever")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
":" "1276" ": "), "%s", "PostItMgr::Layout(): We are looping forever"
); } } while (false)
;
1277 break;
1278 }
1279 }
1280 }
1281 else
1282 {
1283 // only one left, make sure it is not hidden at the top or bottom
1284 auto i = aVisiblePostItList.begin();
1285 lTranslatePos = lTopBorder - (*i)->VirtualPos().Y();
1286 if (lTranslatePos>0)
1287 {
1288 (*i)->TranslateTopPosition(lTranslatePos+GetSpaceBetween());
1289 }
1290 lTranslatePos = lBottomBorder - ((*i)->VirtualPos().Y()+ (*i)->VirtualSize().Height());
1291 if (lTranslatePos<0)
1292 {
1293 (*i)->TranslateTopPosition(lTranslatePos);
1294 }
1295 }
1296 return bScrollbars;
1297 }
1298
1299void SwPostItMgr::AddPostIts(const bool bCheckExistence, const bool bFocus)
1300{
1301 const bool bEmpty = mvPostItFields.empty();
1302 IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
1303 SwFieldType* pType = mpView->GetDocShell()->GetDoc()->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Postit, OUString(),false);
1304 std::vector<SwFormatField*> vFormatFields;
1305 pType->CollectPostIts(vFormatFields, rIDRA, mpWrtShell->GetLayout()->IsHideRedlines());
1306 for(auto pFormatField : vFormatFields)
1307 InsertItem(pFormatField, bCheckExistence, bFocus);
1308 // if we just added the first one we have to update the view for centering
1309 if (bEmpty && !mvPostItFields.empty())
1310 PrepareView(true);
1311}
1312
1313void SwPostItMgr::RemoveSidebarWin()
1314{
1315 for (auto& postItField : mvPostItFields)
1316 {
1317 EndListening( *const_cast<SfxBroadcaster*>(postItField->GetBroadcaster()) );
1318 postItField->mpPostIt.disposeAndClear();
1319 postItField.reset();
1320 }
1321 mvPostItFields.clear();
1322
1323 // all postits removed, no items should be left in pages
1324 PreparePageContainer();
1325}
1326
1327namespace {
1328
1329class FilterFunctor
1330{
1331public:
1332 virtual bool operator()(const SwFormatField* pField) const = 0;
1333 virtual ~FilterFunctor() {}
1334};
1335
1336class IsPostitField : public FilterFunctor
1337{
1338public:
1339 bool operator()(const SwFormatField* pField) const override
1340 {
1341 return pField->GetField()->GetTyp()->Which() == SwFieldIds::Postit;
1342 }
1343};
1344
1345class IsPostitFieldWithAuthorOf : public FilterFunctor
1346{
1347 OUString m_sAuthor;
1348public:
1349 explicit IsPostitFieldWithAuthorOf(const OUString &rAuthor)
1350 : m_sAuthor(rAuthor)
1351 {
1352 }
1353 bool operator()(const SwFormatField* pField) const override
1354 {
1355 if (pField->GetField()->GetTyp()->Which() != SwFieldIds::Postit)
1356 return false;
1357 return static_cast<const SwPostItField*>(pField->GetField())->GetPar1() == m_sAuthor;
1358 }
1359};
1360
1361class IsPostitFieldWithPostitId : public FilterFunctor
1362{
1363 sal_uInt32 m_nPostItId;
1364public:
1365 explicit IsPostitFieldWithPostitId(sal_uInt32 nPostItId)
1366 : m_nPostItId(nPostItId)
1367 {}
1368
1369 bool operator()(const SwFormatField* pField) const override
1370 {
1371 if (pField->GetField()->GetTyp()->Which() != SwFieldIds::Postit)
1372 return false;
1373 return static_cast<const SwPostItField*>(pField->GetField())->GetPostItId() == m_nPostItId;
1374 }
1375};
1376
1377class IsFieldNotDeleted : public FilterFunctor
1378{
1379private:
1380 IDocumentRedlineAccess const& m_rIDRA;
1381 FilterFunctor const& m_rNext;
1382
1383public:
1384 IsFieldNotDeleted(IDocumentRedlineAccess const& rIDRA,
1385 const FilterFunctor & rNext)
1386 : m_rIDRA(rIDRA)
1387 , m_rNext(rNext)
1388 {
1389 }
1390 bool operator()(const SwFormatField* pField) const override
1391 {
1392 if (!m_rNext(pField))
1393 return false;
1394 if (!pField->GetTextField())
1395 return false;
1396 return !sw::IsFieldDeletedInModel(m_rIDRA, *pField->GetTextField());
1397 }
1398};
1399
1400//Manages the passed in vector by automatically removing entries if they are deleted
1401//and automatically adding entries if they appear in the document and match the
1402//functor.
1403//
1404//This will completely refill in the case of a "anonymous" NULL pField stating
1405//rather unhelpfully that "something changed" so you may process the same
1406//Fields more than once.
1407class FieldDocWatchingStack : public SfxListener
1408{
1409 std::vector<std::unique_ptr<SwSidebarItem>>& sidebarItemVector;
1410 std::vector<const SwFormatField*> v;
1411 SwDocShell& m_rDocShell;
1412 FilterFunctor& m_rFilter;
1413
1414 virtual void Notify(SfxBroadcaster&, const SfxHint& rHint) override
1415 {
1416 const SwFormatFieldHint* pHint = dynamic_cast<const SwFormatFieldHint*>(&rHint);
1417 if (!pHint)
1418 return;
1419
1420 bool bAllInvalidated = false;
1421 if (pHint->Which() == SwFormatFieldHintWhich::REMOVED)
1422 {
1423 const SwFormatField* pField = pHint->GetField();
1424 bAllInvalidated = pField == nullptr;
1425 if (!bAllInvalidated && m_rFilter(pField))
1426 {
1427 EndListening(const_cast<SwFormatField&>(*pField));
1428 v.erase(std::remove(v.begin(), v.end(), pField), v.end());
1429 }
1430 }
1431 else if (pHint->Which() == SwFormatFieldHintWhich::INSERTED)
1432 {
1433 const SwFormatField* pField = pHint->GetField();
1434 bAllInvalidated = pField == nullptr;
1435 if (!bAllInvalidated && m_rFilter(pField))
1436 {
1437 StartListening(const_cast<SwFormatField&>(*pField));
1438 v.push_back(pField);
1439 }
1440 }
1441
1442 if (bAllInvalidated)
1443 FillVector();
1444
1445 return;
1446 }
1447
1448public:
1449 FieldDocWatchingStack(std::vector<std::unique_ptr<SwSidebarItem>>& in, SwDocShell &rDocShell, FilterFunctor& rFilter)
1450 : sidebarItemVector(in)
1451 , m_rDocShell(rDocShell)
1452 , m_rFilter(rFilter)
1453 {
1454 FillVector();
1455 StartListening(m_rDocShell);
1456 }
1457 void FillVector()
1458 {
1459 EndListeningToAllFields();
1460 v.clear();
1461 v.reserve(sidebarItemVector.size());
1462 for (auto const& p : sidebarItemVector)
1463 {
1464 const SwFormatField& rField = p->GetFormatField();
1465 if (!m_rFilter(&rField))
1466 continue;
1467 StartListening(const_cast<SwFormatField&>(rField));
1468 v.push_back(&rField);
1469 }
1470 }
1471 void EndListeningToAllFields()
1472 {
1473 for (auto const& pField : v)
1474 {
1475 EndListening(const_cast<SwFormatField&>(*pField));
1476 }
1477 }
1478 virtual ~FieldDocWatchingStack() override
1479 {
1480 EndListeningToAllFields();
1481 EndListening(m_rDocShell);
1482 }
1483 const SwFormatField* pop()
1484 {
1485 if (v.empty())
1486 return nullptr;
1487 const SwFormatField* p = v.back();
1488 EndListening(const_cast<SwFormatField&>(*p));
1489 v.pop_back();
1490 return p;
1491 }
1492};
1493
1494}
1495
1496// copy to new vector, otherwise RemoveItem would operate and delete stuff on mvPostItFields as well
1497// RemoveItem will clean up the core field and visible postit if necessary
1498// we cannot just delete everything as before, as postits could move into change tracking
1499void SwPostItMgr::Delete(const OUString& rAuthor)
1500{
1501 mpWrtShell->StartAllAction();
1502 if (HasActiveSidebarWin() && (GetActiveSidebarWin()->GetAuthor() == rAuthor))
1503 {
1504 SetActiveSidebarWin(nullptr);
1505 }
1506 SwRewriter aRewriter;
1507 aRewriter.AddRule(UndoArg1, SwResId(STR_DELETE_AUTHOR_NOTESreinterpret_cast<char const *>("STR_DELETE_AUTHOR_NOTES"
"\004" u8"Comments by ")
) + rAuthor);
1508 mpWrtShell->StartUndo( SwUndoId::DELETE, &aRewriter );
1509
1510 IsPostitFieldWithAuthorOf aFilter(rAuthor);
1511 IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
1512 IsFieldNotDeleted aFilter2(rIDRA, aFilter);
1513 FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(), aFilter2);
1514 while (const SwFormatField* pField = aStack.pop())
1515 {
1516 if (mpWrtShell->GotoField(*pField))
1517 mpWrtShell->DelRight();
1518 }
1519 mpWrtShell->EndUndo();
1520 PrepareView();
1521 mpWrtShell->EndAllAction();
1522 mbLayout = true;
1523 CalcRects();
1524 LayoutPostIts();
1525}
1526
1527void SwPostItMgr::Delete(sal_uInt32 nPostItId)
1528{
1529 mpWrtShell->StartAllAction();
1530 if (HasActiveSidebarWin() &&
1531 mpActivePostIt->GetPostItField()->GetPostItId() == nPostItId)
1532 {
1533 SetActiveSidebarWin(nullptr);
1534 }
1535 SwRewriter aRewriter;
1536 aRewriter.AddRule(UndoArg1, SwResId(STR_CONTENT_TYPE_SINGLE_POSTITreinterpret_cast<char const *>("STR_CONTENT_TYPE_SINGLE_POSTIT"
"\004" u8"Comment")
));
1537 mpWrtShell->StartUndo( SwUndoId::DELETE, &aRewriter );
1538
1539 IsPostitFieldWithPostitId aFilter(nPostItId);
1540 IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
1541 IsFieldNotDeleted aFilter2(rIDRA, aFilter);
1542 FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(), aFilter2);
1543 const SwFormatField* pField = aStack.pop();
1544 if (pField && mpWrtShell->GotoField(*pField))
1545 mpWrtShell->DelRight();
1546 mpWrtShell->EndUndo();
1547 PrepareView();
1548 mpWrtShell->EndAllAction();
1549 mbLayout = true;
1550 CalcRects();
1551 LayoutPostIts();
1552}
1553
1554void SwPostItMgr::DeleteCommentThread(sal_uInt32 nPostItId)
1555{
1556 mpWrtShell->StartAllAction();
1557
1558 SwRewriter aRewriter;
1559 aRewriter.AddRule(UndoArg1, SwResId(STR_CONTENT_TYPE_SINGLE_POSTITreinterpret_cast<char const *>("STR_CONTENT_TYPE_SINGLE_POSTIT"
"\004" u8"Comment")
));
1560
1561 // We have no undo ID at the moment.
1562
1563 IsPostitFieldWithPostitId aFilter(nPostItId);
1564 FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(), aFilter);
1565 const SwFormatField* pField = aStack.pop();
1566 // pField now contains our AnnotationWin object
1567 if (pField) {
1568 SwAnnotationWin* pWin = GetSidebarWin(pField);
1569 pWin->DeleteThread();
1570 }
1571 PrepareView();
1572 mpWrtShell->EndAllAction();
1573 mbLayout = true;
1574 CalcRects();
1575 LayoutPostIts();
1576}
1577
1578void SwPostItMgr::ToggleResolved(sal_uInt32 nPostItId)
1579{
1580 mpWrtShell->StartAllAction();
1581
1582 SwRewriter aRewriter;
1583 aRewriter.AddRule(UndoArg1, SwResId(STR_CONTENT_TYPE_SINGLE_POSTITreinterpret_cast<char const *>("STR_CONTENT_TYPE_SINGLE_POSTIT"
"\004" u8"Comment")
));
1584
1585 // We have no undo ID at the moment.
1586
1587 IsPostitFieldWithPostitId aFilter(nPostItId);
1588 FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(), aFilter);
1589 const SwFormatField* pField = aStack.pop();
1590 // pField now contains our AnnotationWin object
1591 if (pField) {
1592 SwAnnotationWin* pWin = GetSidebarWin(pField);
1593 pWin->ToggleResolved();
1594 }
1595
1596 PrepareView();
1597 mpWrtShell->EndAllAction();
1598 mbLayout = true;
1599 CalcRects();
1600 LayoutPostIts();
1601}
1602
1603void SwPostItMgr::ToggleResolvedForThread(sal_uInt32 nPostItId)
1604{
1605 mpWrtShell->StartAllAction();
1606
1607 SwRewriter aRewriter;
1608 aRewriter.AddRule(UndoArg1, SwResId(STR_CONTENT_TYPE_SINGLE_POSTITreinterpret_cast<char const *>("STR_CONTENT_TYPE_SINGLE_POSTIT"
"\004" u8"Comment")
));
1609
1610 // We have no undo ID at the moment.
1611
1612 IsPostitFieldWithPostitId aFilter(nPostItId);
1613 FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(), aFilter);
1614 const SwFormatField* pField = aStack.pop();
1615 // pField now contains our AnnotationWin object
1616 if (pField) {
1617 SwAnnotationWin* pWin = GetSidebarWin(pField);
1618 pWin->ToggleResolvedForThread();
1619 }
1620
1621 PrepareView();
1622 mpWrtShell->EndAllAction();
1623 mbLayout = true;
1624 CalcRects();
1625 LayoutPostIts();
1626}
1627
1628
1629void SwPostItMgr::Delete()
1630{
1631 mpWrtShell->StartAllAction();
1632 SetActiveSidebarWin(nullptr);
1633 SwRewriter aRewriter;
1634 aRewriter.AddRule(UndoArg1, SwResId(STR_DELETE_ALL_NOTESreinterpret_cast<char const *>("STR_DELETE_ALL_NOTES" "\004"
u8"All Comments")
) );
1635 mpWrtShell->StartUndo( SwUndoId::DELETE, &aRewriter );
1636
1637 IsPostitField aFilter;
1638 IDocumentRedlineAccess const& rIDRA(mpWrtShell->getIDocumentRedlineAccess());
1639 IsFieldNotDeleted aFilter2(rIDRA, aFilter);
1640 FieldDocWatchingStack aStack(mvPostItFields, *mpView->GetDocShell(),
1641 aFilter2);
1642 while (const SwFormatField* pField = aStack.pop())
1643 {
1644 if (mpWrtShell->GotoField(*pField))
1645 mpWrtShell->DelRight();
1646 }
1647
1648 mpWrtShell->EndUndo();
1649 PrepareView();
1650 mpWrtShell->EndAllAction();
1651 mbLayout = true;
1652 CalcRects();
1653 LayoutPostIts();
1654}
1655
1656void SwPostItMgr::ExecuteFormatAllDialog(SwView& rView)
1657{
1658 if (mvPostItFields.empty())
1659 return;
1660 sw::annotation::SwAnnotationWin *pOrigActiveWin = GetActiveSidebarWin();
1661 sw::annotation::SwAnnotationWin *pWin = pOrigActiveWin;
1662 if (!pWin)
1663 {
1664 for (auto const& postItField : mvPostItFields)
1665 {
1666 pWin = postItField->mpPostIt;
1667 if (pWin)
1668 break;
1669 }
1670 }
1671 if (!pWin)
1672 return;
1673 SetActiveSidebarWin(pWin);
1674 OutlinerView* pOLV = pWin->GetOutlinerView();
1675 SfxItemSet aEditAttr(pOLV->GetAttribs());
1676 SfxItemPool* pPool(SwAnnotationShell::GetAnnotationPool(rView));
1677 SfxItemSet aDlgAttr(*pPool, svl::Items<XATTR_FILLSTYLE, XATTR_FILLCOLOR, EE_ITEMS_START, EE_ITEMS_END>{});
1678 aDlgAttr.Put(aEditAttr);
1679 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
1680 ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateSwCharDlg(rView.GetFrameWeld(), rView, aDlgAttr, SwCharDlgMode::Ann));
1681 sal_uInt16 nRet = pDlg->Execute();
1682 if (RET_OK == nRet)
1683 {
1684 aDlgAttr.Put(*pDlg->GetOutputItemSet());
1685 FormatAll(aDlgAttr);
1686 }
1687 pDlg.disposeAndClear();
1688 SetActiveSidebarWin(pOrigActiveWin);
1689}
1690
1691void SwPostItMgr::FormatAll(const SfxItemSet &rNewAttr)
1692{
1693 mpWrtShell->StartAllAction();
1694 SwRewriter aRewriter;
1695 aRewriter.AddRule(UndoArg1, SwResId(STR_FORMAT_ALL_NOTESreinterpret_cast<char const *>("STR_FORMAT_ALL_NOTES" "\004"
u8"All Comments")
) );
1696 mpWrtShell->StartUndo( SwUndoId::INSATTR, &aRewriter );
1697
1698 for (auto const& postItField : mvPostItFields)
1699 {
1700 if (!postItField->mpPostIt)
1701 continue;
1702 OutlinerView* pOLV = postItField->mpPostIt->GetOutlinerView();
1703 //save old selection
1704 ESelection aOrigSel(pOLV->GetSelection());
1705 //select all
1706 Outliner *pOutliner = pOLV->GetOutliner();
1707 if (pOutliner)
1708 {
1709 sal_Int32 nParaCount = pOutliner->GetParagraphCount();
1710 if (nParaCount > 0)
1711 pOLV->SelectRange(0, nParaCount);
1712 }
1713 //set new char properties
1714 pOLV->SetAttribs(rNewAttr);
1715 //restore old selection
1716 pOLV->SetSelection(aOrigSel);
1717 // tdf#91596 store updated formatting in SwField
1718 postItField->mpPostIt->UpdateData();
1719 }
1720
1721 mpWrtShell->EndUndo();
1722 PrepareView();
1723 mpWrtShell->EndAllAction();
1724 mbLayout = true;
1725 CalcRects();
1726 LayoutPostIts();
1727}
1728
1729void SwPostItMgr::Hide( const OUString& rAuthor )
1730{
1731 for (auto const& postItField : mvPostItFields)
1732 {
1733 if ( postItField->mpPostIt && (postItField->mpPostIt->GetAuthor() == rAuthor) )
1734 {
1735 postItField->mbShow = false;
1736 postItField->mpPostIt->HideNote();
1737 }
1738 }
1739
1740 LayoutPostIts();
1741}
1742
1743void SwPostItMgr::Hide()
1744{
1745 for (auto const& postItField : mvPostItFields)
1746 {
1747 postItField->mbShow = false;
1748 postItField->mpPostIt->HideNote();
1749 }
1750}
1751
1752void SwPostItMgr::Show()
1753{
1754 for (auto const& postItField : mvPostItFields)
1755 {
1756 postItField->mbShow = true;
1757 }
1758 LayoutPostIts();
1759}
1760
1761SwAnnotationWin* SwPostItMgr::GetSidebarWin( const SfxBroadcaster* pBroadcaster) const
1762{
1763 for (auto const& postItField : mvPostItFields)
1764 {
1765 if ( postItField->GetBroadcaster() == pBroadcaster)
1766 return postItField->mpPostIt;
1767 }
1768 return nullptr;
1769}
1770
1771sw::annotation::SwAnnotationWin* SwPostItMgr::GetAnnotationWin(const SwPostItField* pField) const
1772{
1773 for (auto const& postItField : mvPostItFields)
1774 {
1775 if ( postItField->GetFormatField().GetField() == pField )
1776 return postItField->mpPostIt.get();
1777 }
1778 return nullptr;
1779}
1780
1781sw::annotation::SwAnnotationWin* SwPostItMgr::GetAnnotationWin(const sal_uInt32 nPostItId) const
1782{
1783 for (auto const& postItField : mvPostItFields)
1784 {
1785 if ( static_cast<const SwPostItField*>(postItField->GetFormatField().GetField())->GetPostItId() == nPostItId )
1786 return postItField->mpPostIt.get();
1787 }
1788 return nullptr;
1789}
1790
1791SwAnnotationWin* SwPostItMgr::GetNextPostIt( sal_uInt16 aDirection,
1792 SwAnnotationWin* aPostIt )
1793{
1794 if (mvPostItFields.size()>1)
1795 {
1796 auto i = std::find_if(mvPostItFields.begin(), mvPostItFields.end(),
1797 [&aPostIt](const std::unique_ptr<SwSidebarItem>& pField) { return pField->mpPostIt == aPostIt; });
1798 if (i == mvPostItFields.end())
1799 return nullptr;
1800
1801 auto iNextPostIt = i;
1802 if (aDirection == KEY_PAGEUP)
1803 {
1804 if ( iNextPostIt == mvPostItFields.begin() )
1805 {
1806 return nullptr;
1807 }
1808 --iNextPostIt;
1809 }
1810 else
1811 {
1812 ++iNextPostIt;
1813 if ( iNextPostIt == mvPostItFields.end() )
1814 {
1815 return nullptr;
1816 }
1817 }
1818 // lets quit, we are back at the beginning
1819 if ( (*iNextPostIt)->mpPostIt == aPostIt)
1820 return nullptr;
1821 return (*iNextPostIt)->mpPostIt;
1822 }
1823 else
1824 return nullptr;
1825}
1826
1827long SwPostItMgr::GetNextBorder()
1828{
1829 for (auto const& pPage : mPages)
1830 {
1831 for(auto b = pPage->mvSidebarItems.begin(); b!= pPage->mvSidebarItems.end(); ++b)
1832 {
1833 if ((*b)->mpPostIt == mpActivePostIt)
1834 {
1835 auto aNext = b;
1836 ++aNext;
1837 bool bFollow = (aNext != pPage->mvSidebarItems.end()) && (*aNext)->mpPostIt->IsFollow();
1838 if ( pPage->bScrollbar || bFollow )
1839 {
1840 return -1;
1841 }
1842 else
1843 {
1844 //if this is the last item, return the bottom border otherwise the next item
1845 if (aNext == pPage->mvSidebarItems.end())
1846 return mpEditWin->LogicToPixel(Point(0,pPage->mPageRect.Bottom())).Y() - GetSpaceBetween();
1847 else
1848 return (*aNext)->mpPostIt->GetPosPixel().Y() - GetSpaceBetween();
1849 }
1850 }
1851 }
1852 }
1853
1854 OSL_FAIL("SwPostItMgr::GetNextBorder(): We have to find a next border here")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
":" "1854" ": "), "%s", "SwPostItMgr::GetNextBorder(): We have to find a next border here"
); } } while (false)
;
1855 return -1;
1856}
1857
1858void SwPostItMgr::SetShadowState(const SwPostItField* pField,bool bCursor)
1859{
1860 if (pField)
1861 {
1862 if (pField !=mShadowState.mpShadowField)
1863 {
1864 if (mShadowState.mpShadowField)
1865 {
1866 // reset old one if still alive
1867 // TODO: does not work properly if mouse and cursor was set
1868 sw::annotation::SwAnnotationWin* pOldPostIt =
1869 GetAnnotationWin(mShadowState.mpShadowField);
1870 if (pOldPostIt && pOldPostIt->Shadow() && (pOldPostIt->Shadow()->GetShadowState() != SS_EDIT))
1871 pOldPostIt->SetViewState(ViewState::NORMAL);
1872 }
1873 //set new one, if it is not currently edited
1874 sw::annotation::SwAnnotationWin* pNewPostIt = GetAnnotationWin(pField);
1875 if (pNewPostIt && pNewPostIt->Shadow() && (pNewPostIt->Shadow()->GetShadowState() != SS_EDIT))
1876 {
1877 pNewPostIt->SetViewState(ViewState::VIEW);
1878 //remember our new field
1879 mShadowState.mpShadowField = pField;
1880 mShadowState.bCursor = false;
1881 mShadowState.bMouse = false;
1882 }
1883 }
1884 if (bCursor)
1885 mShadowState.bCursor = true;
1886 else
1887 mShadowState.bMouse = true;
1888 }
1889 else
1890 {
1891 if (mShadowState.mpShadowField)
1892 {
1893 if (bCursor)
1894 mShadowState.bCursor = false;
1895 else
1896 mShadowState.bMouse = false;
1897 if (!mShadowState.bCursor && !mShadowState.bMouse)
1898 {
1899 // reset old one if still alive
1900 sw::annotation::SwAnnotationWin* pOldPostIt = GetAnnotationWin(mShadowState.mpShadowField);
1901 if (pOldPostIt && pOldPostIt->Shadow() && (pOldPostIt->Shadow()->GetShadowState() != SS_EDIT))
1902 {
1903 pOldPostIt->SetViewState(ViewState::NORMAL);
1904 mShadowState.mpShadowField = nullptr;
1905 }
1906 }
1907 }
1908 }
1909}
1910
1911void SwPostItMgr::PrepareView(bool bIgnoreCount)
1912{
1913 if (!HasNotes() || bIgnoreCount)
1914 {
1915 mpWrtShell->StartAllAction();
1916 SwRootFrame* pLayout = mpWrtShell->GetLayout();
1917 if ( pLayout )
1918 SwPostItHelper::setSidebarChanged( pLayout,
1919 mpWrtShell->getIDocumentSettingAccess().get( DocumentSettingId::BROWSE_MODE ) );
1920 mpWrtShell->EndAllAction();
1921 }
1922}
1923
1924bool SwPostItMgr::ShowScrollbar(const unsigned long aPage) const
1925{
1926 if (mPages.size() > aPage-1)
1927 return (mPages[aPage-1]->bScrollbar && !mbWaitingForCalcRects);
1928 else
1929 return false;
1930}
1931
1932bool SwPostItMgr::IsHit(const Point &aPointPixel)
1933{
1934 if (HasNotes() && ShowNotes())
1935 {
1936 const Point aPoint = mpEditWin->PixelToLogic(aPointPixel);
1937 const SwRootFrame* pLayout = mpWrtShell->GetLayout();
1938 SwRect aPageFrame;
1939 const unsigned long nPageNum = SwPostItHelper::getPageInfo( aPageFrame, pLayout, aPoint );
1940 if( nPageNum )
1941 {
1942 tools::Rectangle aRect;
1943 OSL_ENSURE(mPages.size()>nPageNum-1,"SwPostitMgr:: page container size wrong")do { if (true && (!(mPages.size()>nPageNum-1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
":" "1943" ": "), "%s", "SwPostitMgr:: page container size wrong"
); } } while (false)
;
1944 aRect = mPages[nPageNum-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT
1945 ? tools::Rectangle(Point(aPageFrame.Left()-GetSidebarWidth()-GetSidebarBorderWidth(),aPageFrame.Top()),Size(GetSidebarWidth(),aPageFrame.Height()))
1946 : tools::Rectangle( Point(aPageFrame.Right()+GetSidebarBorderWidth(),aPageFrame.Top()) , Size(GetSidebarWidth(),aPageFrame.Height()));
1947 if (aRect.IsInside(aPoint))
1948 {
1949 // we hit the note's sidebar
1950 // lets now test for the arrow area
1951 if (mPages[nPageNum-1]->bScrollbar)
1952 return ScrollbarHit(nPageNum,aPoint);
1953 else
1954 return false;
1955 }
1956 }
1957 }
1958 return false;
1959}
1960
1961vcl::Window* SwPostItMgr::IsHitSidebarWindow(const Point& rPointLogic)
1962{
1963 vcl::Window* pRet = nullptr;
1964
1965 if (HasNotes() && ShowNotes())
1966 {
1967 bool bEnableMapMode = !mpEditWin->IsMapModeEnabled();
1968 if (bEnableMapMode)
1969 mpEditWin->EnableMapMode();
1970
1971 for (const std::unique_ptr<SwSidebarItem>& pItem : mvPostItFields)
1972 {
1973 SwAnnotationWin* pPostIt = pItem->mpPostIt;
1974 if (!pPostIt)
1975 continue;
1976
1977 if (pPostIt->IsHitWindow(rPointLogic))
1978 {
1979 pRet = pPostIt;
1980 break;
1981 }
1982 }
1983
1984 if (bEnableMapMode)
1985 mpEditWin->EnableMapMode(false);
1986 }
1987
1988 return pRet;
1989}
1990
1991tools::Rectangle SwPostItMgr::GetBottomScrollRect(const unsigned long aPage) const
1992{
1993 SwRect aPageRect = mPages[aPage-1]->mPageRect;
1994 Point aPointBottom = mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT
1995 ? Point(aPageRect.Left() - GetSidebarWidth() - GetSidebarBorderWidth() + mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Bottom()- mpEditWin->PixelToLogic(Size(0,2+GetSidebarScrollerHeight())).Height())
1996 : Point(aPageRect.Right() + GetSidebarBorderWidth() + mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Bottom()- mpEditWin->PixelToLogic(Size(0,2+GetSidebarScrollerHeight())).Height());
1997 Size aSize(GetSidebarWidth() - mpEditWin->PixelToLogic(Size(4,0)).Width(), mpEditWin->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height()) ;
1998 return tools::Rectangle(aPointBottom,aSize);
1999}
2000
2001tools::Rectangle SwPostItMgr::GetTopScrollRect(const unsigned long aPage) const
2002{
2003 SwRect aPageRect = mPages[aPage-1]->mPageRect;
2004 Point aPointTop = mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT
2005 ? Point(aPageRect.Left() - GetSidebarWidth() -GetSidebarBorderWidth()+ mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Top() + mpEditWin->PixelToLogic(Size(0,2)).Height())
2006 : Point(aPageRect.Right() + GetSidebarBorderWidth() + mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Top() + mpEditWin->PixelToLogic(Size(0,2)).Height());
2007 Size aSize(GetSidebarWidth() - mpEditWin->PixelToLogic(Size(4,0)).Width(), mpEditWin->PixelToLogic(Size(0,GetSidebarScrollerHeight())).Height()) ;
2008 return tools::Rectangle(aPointTop,aSize);
2009}
2010
2011//IMPORTANT: if you change the rects here, also change SwPageFrame::PaintNotesSidebar()
2012bool SwPostItMgr::ScrollbarHit(const unsigned long aPage,const Point &aPoint)
2013{
2014 SwRect aPageRect = mPages[aPage-1]->mPageRect;
2015 Point aPointBottom = mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT
2016 ? Point(aPageRect.Left() - GetSidebarWidth()-GetSidebarBorderWidth() + mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Bottom()- mpEditWin->PixelToLogic(Size(0,2+GetSidebarScrollerHeight())).Height())
2017 : Point(aPageRect.Right() + GetSidebarBorderWidth()+ mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Bottom()- mpEditWin->PixelToLogic(Size(0,2+GetSidebarScrollerHeight())).Height());
2018
2019 Point aPointTop = mPages[aPage-1]->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT
2020 ? Point(aPageRect.Left() - GetSidebarWidth()-GetSidebarBorderWidth()+ mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Top() + mpEditWin->PixelToLogic(Size(0,2)).Height())
2021 : Point(aPageRect.Right()+GetSidebarBorderWidth()+ mpEditWin->PixelToLogic(Size(2,0)).Width(),aPageRect.Top() + mpEditWin->PixelToLogic(Size(0,2)).Height());
2022
2023 tools::Rectangle aRectBottom(GetBottomScrollRect(aPage));
2024 tools::Rectangle aRectTop(GetTopScrollRect(aPage));
2025
2026 if (aRectBottom.IsInside(aPoint))
2027 {
2028 if (aPoint.X() < long((aPointBottom.X() + GetSidebarWidth()/3)))
2029 Scroll( GetScrollSize(),aPage);
2030 else
2031 Scroll( -1*GetScrollSize(), aPage);
2032 return true;
2033 }
2034 else if (aRectTop.IsInside(aPoint))
2035 {
2036 if (aPoint.X() < long((aPointTop.X() + GetSidebarWidth()/3*2)))
2037 Scroll(GetScrollSize(), aPage);
2038 else
2039 Scroll(-1*GetScrollSize(), aPage);
2040 return true;
2041 }
2042 return false;
2043}
2044
2045void SwPostItMgr::CorrectPositions()
2046{
2047 if ( mbWaitingForCalcRects || mbLayouting || mvPostItFields.empty() )
2048 return;
2049
2050 // find first valid note
2051 SwAnnotationWin *pFirstPostIt = nullptr;
2052 for (auto const& postItField : mvPostItFields)
2053 {
2054 pFirstPostIt = postItField->mpPostIt;
2055 if (pFirstPostIt)
2056 break;
2057 }
2058
2059 //if we have not found a valid note, forget about it and leave
2060 if (!pFirstPostIt)
2061 return;
2062
2063 // 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
2064 // check, if anchor overlay object exists.
2065 const long aAnchorX = pFirstPostIt->Anchor()
2066 ? mpEditWin->LogicToPixel( Point(static_cast<long>(pFirstPostIt->Anchor()->GetSixthPosition().getX()),0)).X()
2067 : 0;
2068 const long aAnchorY = pFirstPostIt->Anchor()
2069 ? mpEditWin->LogicToPixel( Point(0,static_cast<long>(pFirstPostIt->Anchor()->GetSixthPosition().getY()))).Y() + 1
2070 : 0;
2071 if (Point(aAnchorX,aAnchorY) == pFirstPostIt->GetPosPixel())
2072 return;
2073
2074 long aAnchorPosX = 0;
2075 long aAnchorPosY = 0;
2076 for (const std::unique_ptr<SwPostItPageItem>& pPage : mPages)
2077 {
2078 for (auto const& item : pPage->mvSidebarItems)
2079 {
2080 // check, if anchor overlay object exists.
2081 if ( item->mbShow && item->mpPostIt && item->mpPostIt->Anchor() )
2082 {
2083 aAnchorPosX = pPage->eSidebarPosition == sw::sidebarwindows::SidebarPosition::LEFT
2084 ? mpEditWin->LogicToPixel( Point(static_cast<long>(item->mpPostIt->Anchor()->GetSeventhPosition().getX()),0)).X()
2085 : mpEditWin->LogicToPixel( Point(static_cast<long>(item->mpPostIt->Anchor()->GetSixthPosition().getX()),0)).X();
2086 aAnchorPosY = mpEditWin->LogicToPixel( Point(0,static_cast<long>(item->mpPostIt->Anchor()->GetSixthPosition().getY()))).Y() + 1;
2087 item->mpPostIt->SetPosPixel(Point(aAnchorPosX,aAnchorPosY));
2088 }
2089 }
2090 }
2091}
2092
2093bool SwPostItMgr::ShowNotes() const
2094{
2095 // we only want to see notes if Options - Writer - View - Notes is ticked
2096 return mpWrtShell->GetViewOptions()->IsPostIts();
2097}
2098
2099bool SwPostItMgr::HasNotes() const
2100{
2101 return !mvPostItFields.empty();
2102}
2103
2104unsigned long SwPostItMgr::GetSidebarWidth(bool bPx) const
2105{
2106 bool bEnableMapMode = !mpWrtShell->GetOut()->IsMapModeEnabled();
2107 sal_uInt16 nZoom = mpWrtShell->GetViewOptions()->GetZoom();
2108 if (comphelper::LibreOfficeKit::isActive() && !bEnableMapMode)
2109 {
2110 // The output device is the tile and contains the real wanted scale factor.
2111 double fScaleX = double(mpWrtShell->GetOut()->GetMapMode().GetScaleX());
2112 nZoom = fScaleX * 100;
2113 }
2114 unsigned long aWidth = static_cast<unsigned long>(nZoom * 1.8);
2115
2116 if (bPx)
2117 return aWidth;
2118 else
2119 {
2120 if (bEnableMapMode)
2121 // The output device is the window.
2122 mpWrtShell->GetOut()->EnableMapMode();
2123 long nRet = mpWrtShell->GetOut()->PixelToLogic(Size(aWidth, 0)).Width();
2124 if (bEnableMapMode)
2125 mpWrtShell->GetOut()->EnableMapMode(false);
2126 return nRet;
2127 }
2128}
2129
2130unsigned long SwPostItMgr::GetSidebarBorderWidth(bool bPx) const
2131{
2132 if (bPx)
2133 return 2;
2134 else
2135 return mpWrtShell->GetOut()->PixelToLogic(Size(2,0)).Width();
2136}
2137
2138Color SwPostItMgr::GetColorDark(std::size_t aAuthorIndex)
2139{
2140 if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
2141 {
2142 static const Color aArrayNormal[] = {
2143 COL_AUTHOR1_NORMAL, COL_AUTHOR2_NORMAL, COL_AUTHOR3_NORMAL,
2144 COL_AUTHOR4_NORMAL, COL_AUTHOR5_NORMAL, COL_AUTHOR6_NORMAL,
2145 COL_AUTHOR7_NORMAL, COL_AUTHOR8_NORMAL, COL_AUTHOR9_NORMAL };
2146
2147 return aArrayNormal[ aAuthorIndex % SAL_N_ELEMENTS( aArrayNormal )(sizeof(sal_n_array_size(aArrayNormal)))];
2148 }
2149 else
2150 return COL_WHITE;
2151}
2152
2153Color SwPostItMgr::GetColorLight(std::size_t aAuthorIndex)
2154{
2155 if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
2156 {
2157 static const Color aArrayLight[] = {
2158 COL_AUTHOR1_LIGHT, COL_AUTHOR2_LIGHT, COL_AUTHOR3_LIGHT,
2159 COL_AUTHOR4_LIGHT, COL_AUTHOR5_LIGHT, COL_AUTHOR6_LIGHT,
2160 COL_AUTHOR7_LIGHT, COL_AUTHOR8_LIGHT, COL_AUTHOR9_LIGHT };
2161
2162 return aArrayLight[ aAuthorIndex % SAL_N_ELEMENTS( aArrayLight )(sizeof(sal_n_array_size(aArrayLight)))];
2163 }
2164 else
2165 return COL_WHITE;
2166}
2167
2168Color SwPostItMgr::GetColorAnchor(std::size_t aAuthorIndex)
2169{
2170 if (!Application::GetSettings().GetStyleSettings().GetHighContrastMode())
2171 {
2172 static const Color aArrayAnchor[] = {
2173 COL_AUTHOR1_DARK, COL_AUTHOR2_DARK, COL_AUTHOR3_DARK,
2174 COL_AUTHOR4_DARK, COL_AUTHOR5_DARK, COL_AUTHOR6_DARK,
2175 COL_AUTHOR7_DARK, COL_AUTHOR8_DARK, COL_AUTHOR9_DARK };
2176
2177 return aArrayAnchor[ aAuthorIndex % SAL_N_ELEMENTS( aArrayAnchor )(sizeof(sal_n_array_size(aArrayAnchor)))];
2178 }
2179 else
2180 return COL_WHITE;
2181}
2182
2183void SwPostItMgr::SetActiveSidebarWin( SwAnnotationWin* p)
2184{
2185 if ( p == mpActivePostIt )
2186 return;
2187
2188 // we need the temp variable so we can set mpActivePostIt before we call DeactivatePostIt
2189 // therefore we get a new layout in DOCCHANGED when switching from postit to document,
2190 // otherwise, GetActivePostIt() would still hold our old postit
2191 SwAnnotationWin* pActive = mpActivePostIt;
2192 mpActivePostIt = p;
2193 if (pActive)
2194 {
2195 pActive->DeactivatePostIt();
2196 mShadowState.mpShadowField = nullptr;
2197 }
2198 if (mpActivePostIt)
2199 {
2200 mpActivePostIt->GotoPos();
2201 mpView->AttrChangedNotify(nullptr);
2202 mpActivePostIt->ActivatePostIt();
2203 }
2204}
2205
2206IMPL_LINK_NOARG( SwPostItMgr, CalcHdl, void*, void )void SwPostItMgr::LinkStubCalcHdl(void * instance, void* data
) { return static_cast<SwPostItMgr *>(instance)->CalcHdl
(data); } void SwPostItMgr::CalcHdl(__attribute__ ((unused)) void
*)
2207{
2208 mnEventId = nullptr;
2209 if ( mbLayouting )
2210 {
2211 OSL_FAIL("Reentrance problem in Layout Manager!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/uibase/docvw/PostItMgr.cxx"
":" "2211" ": "), "%s", "Reentrance problem in Layout Manager!"
); } } while (false)
;
2212 mbWaitingForCalcRects = false;
2213 return;
2214 }
2215
2216 // do not change order, even if it would seem so in the first place, we need the calcrects always
2217 if (CalcRects() || mbLayout)
2218 {
2219 mbLayout = false;
2220 LayoutPostIts();
2221 }
2222}
2223
2224void SwPostItMgr::Rescale()
2225{
2226 for (auto const& postItField : mvPostItFields)
2227 if ( postItField->mpPostIt )
2228 postItField->mpPostIt->Rescale();
2229}
2230
2231sal_Int32 SwPostItMgr::GetInitialAnchorDistance() const
2232{
2233 const Fraction& f( mpEditWin->GetMapMode().GetScaleY() );
2234 return sal_Int32(POSTIT_INITIAL_ANCHOR_DISTANCE20 * f);
2235}
2236
2237sal_Int32 SwPostItMgr::GetSpaceBetween() const
2238{
2239 const Fraction& f( mpEditWin->GetMapMode().GetScaleY() );
2240 return sal_Int32(POSTIT_SPACE_BETWEEN8 * f);
2241}
2242
2243sal_Int32 SwPostItMgr::GetScrollSize() const
2244{
2245 const Fraction& f( mpEditWin->GetMapMode().GetScaleY() );
2246 return sal_Int32((POSTIT_SPACE_BETWEEN8 + POSTIT_MINIMUMSIZE_WITH_META60) * f);
2247}
2248
2249sal_Int32 SwPostItMgr::GetMinimumSizeWithMeta() const
2250{
2251 const Fraction& f( mpEditWin->GetMapMode().GetScaleY() );
2252 return sal_Int32(POSTIT_MINIMUMSIZE_WITH_META60 * f);
2253}
2254
2255sal_Int32 SwPostItMgr::GetSidebarScrollerHeight() const
2256{
2257 const Fraction& f( mpEditWin->GetMapMode().GetScaleY() );
2258 return sal_Int32(POSTIT_SCROLL_SIDEBAR_HEIGHT20 * f);
2259}
2260
2261void SwPostItMgr::SetSpellChecking()
2262{
2263 for (auto const& postItField : mvPostItFields)
2264 if ( postItField->mpPostIt )
2265 postItField->mpPostIt->SetSpellChecking();
2266}
2267
2268void SwPostItMgr::SetReadOnlyState()
2269{
2270 for (auto const& postItField : mvPostItFields)
2271 if ( postItField->mpPostIt )
2272 postItField->mpPostIt->SetReadonly( mbReadOnly );
2273}
2274
2275void SwPostItMgr::CheckMetaText()
2276{
2277 for (auto const& postItField : mvPostItFields)
2278 if ( postItField->mpPostIt )
2279 postItField->mpPostIt->CheckMetaText();
2280
2281}
2282
2283sal_uInt16 SwPostItMgr::Replace(SvxSearchItem const * pItem)
2284{
2285 SwAnnotationWin* pWin = GetActiveSidebarWin();
2286 sal_uInt16 aResult = pWin->GetOutlinerView()->StartSearchAndReplace( *pItem );
2287 if (!aResult)
2288 SetActiveSidebarWin(nullptr);
2289 return aResult;
2290}
2291
2292sal_uInt16 SwPostItMgr::FinishSearchReplace(const i18nutil::SearchOptions2& rSearchOptions, bool bSrchForward)
2293{
2294 SwAnnotationWin* pWin = GetActiveSidebarWin();
2295 SvxSearchItem aItem(SID_SEARCH_ITEMTypedWhichId<SvxSearchItem>(10000 + 291) );
2296 aItem.SetSearchOptions(rSearchOptions);
2297 aItem.SetBackward(!bSrchForward);
2298 sal_uInt16 aResult = pWin->GetOutlinerView()->StartSearchAndReplace( aItem );
2299 if (!aResult)
2300 SetActiveSidebarWin(nullptr);
2301 return aResult;
2302}
2303
2304sal_uInt16 SwPostItMgr::SearchReplace(const SwFormatField &pField, const i18nutil::SearchOptions2& rSearchOptions, bool bSrchForward)
2305{
2306 sal_uInt16 aResult = 0;
2307 SwAnnotationWin* pWin = GetSidebarWin(&pField);
2308 if (pWin)
2309 {
2310 ESelection aOldSelection = pWin->GetOutlinerView()->GetSelection();
2311 if (bSrchForward)
2312 pWin->GetOutlinerView()->SetSelection(ESelection(0,0,0,0));
2313 else
2314 pWin->GetOutlinerView()->SetSelection(
2315 ESelection(EE_PARA_MAX_COUNT((sal_Int32) 0x7FFFFFFF),EE_TEXTPOS_MAX_COUNT((sal_Int32) 0x7FFFFFFF),EE_PARA_MAX_COUNT((sal_Int32) 0x7FFFFFFF),EE_TEXTPOS_MAX_COUNT((sal_Int32) 0x7FFFFFFF)));
2316 SvxSearchItem aItem(SID_SEARCH_ITEMTypedWhichId<SvxSearchItem>(10000 + 291) );
2317 aItem.SetSearchOptions(rSearchOptions);
2318 aItem.SetBackward(!bSrchForward);
2319 aResult = pWin->GetOutlinerView()->StartSearchAndReplace( aItem );
2320 if (!aResult)
2321 pWin->GetOutlinerView()->SetSelection(aOldSelection);
2322 else
2323 {
2324 SetActiveSidebarWin(pWin);
2325 MakeVisible(pWin);
2326 }
2327 }
2328 return aResult;
2329}
2330
2331void SwPostItMgr::AssureStdModeAtShell()
2332{
2333 // deselect any drawing or frame and leave editing mode
2334 SdrView* pSdrView = mpWrtShell->GetDrawView();
2335 if ( pSdrView && pSdrView->IsTextEdit() )
2336 {
2337 bool bLockView = mpWrtShell->IsViewLocked();
2338 mpWrtShell->LockView( true );
2339 mpWrtShell->EndTextEdit();
2340 mpWrtShell->LockView( bLockView );
2341 }
2342
2343 if( mpWrtShell->IsSelFrameMode() || mpWrtShell->IsObjSelected())
2344 {
2345 mpWrtShell->UnSelectFrame();
2346 mpWrtShell->LeaveSelFrameMode();
2347 mpWrtShell->GetView().LeaveDrawCreate();
2348 mpWrtShell->EnterStdMode();
2349
2350 mpWrtShell->DrawSelChanged();
2351 mpView->StopShellTimer();
2352 }
2353}
2354
2355bool SwPostItMgr::HasActiveSidebarWin() const
2356{
2357 return mpActivePostIt != nullptr;
2358}
2359
2360bool SwPostItMgr::HasActiveAnnotationWin() const
2361{
2362 return HasActiveSidebarWin() &&
2363 mpActivePostIt != nullptr;
2364}
2365
2366void SwPostItMgr::GrabFocusOnActiveSidebarWin()
2367{
2368 if ( HasActiveSidebarWin() )
2369 {
2370 mpActivePostIt->GrabFocus();
2371 }
2372}
2373
2374void SwPostItMgr::UpdateDataOnActiveSidebarWin()
2375{
2376 if ( HasActiveSidebarWin() )
2377 {
2378 mpActivePostIt->UpdateData();
2379 }
2380}
2381
2382void SwPostItMgr::DeleteActiveSidebarWin()
2383{
2384 if ( HasActiveSidebarWin() )
2385 {
2386 mpActivePostIt->Delete();
2387 }
2388}
2389
2390void SwPostItMgr::HideActiveSidebarWin()
2391{
2392 if ( HasActiveSidebarWin() )
2393 {
2394 mpActivePostIt->Hide();
2395 }
2396}
2397
2398void SwPostItMgr::ToggleInsModeOnActiveSidebarWin()
2399{
2400 if ( HasActiveSidebarWin() )
2401 {
2402 mpActivePostIt->ToggleInsMode();
2403 }
2404}
2405
2406void SwPostItMgr::ConnectSidebarWinToFrame( const SwFrame& rFrame,
2407 const SwFormatField& rFormatField,
2408 SwAnnotationWin& rSidebarWin )
2409{
2410 if ( mpFrameSidebarWinContainer == nullptr )
2411 {
2412 mpFrameSidebarWinContainer.reset(new SwFrameSidebarWinContainer());
2413 }
2414
2415 const bool bInserted = mpFrameSidebarWinContainer->insert( rFrame, rFormatField, rSidebarWin );
2416 if ( bInserted &&
2417 mpWrtShell->GetAccessibleMap() )
2418 {
2419 mpWrtShell->GetAccessibleMap()->InvalidatePosOrSize( nullptr, nullptr, &rSidebarWin, SwRect() );
2420 }
2421}
2422
2423void SwPostItMgr::DisconnectSidebarWinFromFrame( const SwFrame& rFrame,
2424 SwAnnotationWin& rSidebarWin )
2425{
2426 if ( mpFrameSidebarWinContainer != nullptr )
2427 {
2428 const bool bRemoved = mpFrameSidebarWinContainer->remove( rFrame, rSidebarWin );
2429 if ( bRemoved &&
2430 mpWrtShell->GetAccessibleMap() )
2431 {
2432 mpWrtShell->GetAccessibleMap()->A11yDispose( nullptr, nullptr, &rSidebarWin );
2433 }
2434 }
2435}
2436
2437bool SwPostItMgr::HasFrameConnectedSidebarWins( const SwFrame& rFrame )
2438{
2439 bool bRet( false );
2440
2441 if ( mpFrameSidebarWinContainer != nullptr )
2442 {
2443 bRet = !mpFrameSidebarWinContainer->empty( rFrame );
2444 }
2445
2446 return bRet;
2447}
2448
2449vcl::Window* SwPostItMgr::GetSidebarWinForFrameByIndex( const SwFrame& rFrame,
2450 const sal_Int32 nIndex )
2451{
2452 vcl::Window* pSidebarWin( nullptr );
2453
2454 if ( mpFrameSidebarWinContainer != nullptr )
2455 {
2456 pSidebarWin = mpFrameSidebarWinContainer->get( rFrame, nIndex );
2457 }
2458
2459 return pSidebarWin;
2460}
2461
2462void SwPostItMgr::GetAllSidebarWinForFrame( const SwFrame& rFrame,
2463 std::vector< vcl::Window* >* pChildren )
2464{
2465 if ( mpFrameSidebarWinContainer != nullptr )
2466 {
2467 mpFrameSidebarWinContainer->getAll( rFrame, pChildren );
2468 }
2469}
2470
2471void SwPostItMgr::ShowHideResolvedNotes(bool visible) {
2472 for (auto const& pPage : mPages)
2473 {
2474 for(auto b = pPage->mvSidebarItems.begin(); b!= pPage->mvSidebarItems.end(); ++b)
2475 {
2476 if ((*b)->mpPostIt->IsResolved())
2477 {
2478 (*b)->mpPostIt->SetResolved(true);
2479 (*b)->mpPostIt->GetSidebarItem().mbShow = visible;
2480 }
2481 }
2482 }
2483 LayoutPostIts();
2484}
2485
2486void SwPostItMgr::UpdateResolvedStatus(const sw::annotation::SwAnnotationWin* topNote) {
2487 // Given the topmost note as an argument, scans over all notes and sets the
2488 // 'resolved' state of each descendant of the top notes to the resolved state
2489 // of the top note.
2490 bool resolved = topNote->IsResolved();
2491 for (auto const& pPage : mPages)
2492 {
2493 for(auto b = pPage->mvSidebarItems.begin(); b!= pPage->mvSidebarItems.end(); ++b)
2494 {
2495 if((*b)->mpPostIt->GetTopReplyNote() == topNote) {
2496 (*b)->mpPostIt->SetResolved(resolved);
2497 }
2498 }
2499 }
2500}
2501
2502void SwNoteProps::ImplCommit() {}
2503void SwNoteProps::Notify( const css::uno::Sequence< OUString >& ) {}
2504
2505/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#ifndef INCLUDED_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
4
Calling copy constructor for 'Reference<sw::annotation::SwAnnotationWin>'
7
Returning from copy constructor for 'Reference<sw::annotation::SwAnnotationWin>'
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
8
Calling 'Reference::clear'
15
Returning; memory was released
205 if (aTmp.get()) {
16
Calling 'Reference::get'
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
5
Assuming field 'm_pBody' is non-null
6
Taking true branch
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody)
113 m_pBody->release();
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
127 pOld->release();
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody
8.1
Field 'm_pBody' is non-null
8.1
Field 'm_pBody' is non-null
8.1
Field 'm_pBody' is non-null
8.1
Field 'm_pBody' is non-null
)
9
Taking true branch
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
10
Calling 'VclReferenceBase::release'
14
Returning; memory was released
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
17
Use of memory after it is freed
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
11
Assuming the condition is true
12
Taking true branch
40 delete this;
13
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif