cid#1607171 Data race condition
[LibreOffice.git] / sd / source / ui / view / OutlinerIterator.cxx
blobeb35b42cbaa60f514100417e9f0703e700716714
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <OutlinerIterator.hxx>
21 #include <OutlinerIteratorImpl.hxx>
22 #include <svx/svditer.hxx>
23 #include <tools/debug.hxx>
24 #include <osl/diagnose.h>
25 #include <Outliner.hxx>
27 #include <drawdoc.hxx>
28 #include <DrawViewShell.hxx>
29 #include <sdpage.hxx>
30 #include <utility>
31 #include <ViewShellBase.hxx>
32 #include <ViewShellManager.hxx>
34 namespace sd::outliner {
36 //===== IteratorPosition ======================================================
38 IteratorPosition::IteratorPosition()
39 : mnText(0)
40 , mnPageIndex(-1)
41 , mePageKind(PageKind::Standard)
42 , meEditMode(EditMode::Page)
46 bool IteratorPosition::operator== (const IteratorPosition& aPosition) const
48 return mxObject.get() == aPosition.mxObject.get()
49 && mnText == aPosition.mnText
50 && mnPageIndex == aPosition.mnPageIndex
51 && mePageKind == aPosition.mePageKind
52 && meEditMode == aPosition.meEditMode;
55 //===== Iterator ==============================================================
57 Iterator::Iterator()
61 Iterator::Iterator (const Iterator& rIterator)
62 : mxIterator(rIterator.mxIterator ? rIterator.mxIterator->Clone() : nullptr)
66 Iterator::Iterator(Iterator&& rIterator) noexcept
67 : mxIterator(std::move(rIterator.mxIterator))
71 Iterator::Iterator (std::unique_ptr<IteratorImplBase> pObject)
72 : mxIterator(std::move(pObject))
76 Iterator::~Iterator()
80 Iterator& Iterator::operator= (const Iterator& rIterator)
82 if (this != &rIterator)
84 if (rIterator.mxIterator)
85 mxIterator.reset(rIterator.mxIterator->Clone());
86 else
87 mxIterator.reset();
89 return *this;
92 Iterator& Iterator::operator=(Iterator&& rIterator) noexcept
94 mxIterator = std::move(rIterator.mxIterator);
95 return *this;
98 const IteratorPosition& Iterator::operator* () const
100 DBG_ASSERT (mxIterator, "::sd::outliner::Iterator::operator* : missing implementation object");
101 return mxIterator->GetPosition();
104 Iterator& Iterator::operator++ ()
106 if (mxIterator)
107 mxIterator->GotoNextText();
108 return *this;
111 bool Iterator::operator== (const Iterator& rIterator) const
113 if (!mxIterator || !rIterator.mxIterator)
114 return mxIterator.get() == rIterator.mxIterator.get();
115 else
116 return *mxIterator == *rIterator.mxIterator;
119 bool Iterator::operator!= (const Iterator& rIterator) const
121 return ! operator==(rIterator);
124 void Iterator::Reverse()
126 if (mxIterator)
127 mxIterator->Reverse();
130 //===== IteratorFactory =======================================================
132 OutlinerContainer::OutlinerContainer (SdOutliner* pOutliner)
133 : mpOutliner(pOutliner)
137 Iterator OutlinerContainer::begin()
139 return CreateIterator (BEGIN);
142 Iterator OutlinerContainer::end()
144 return CreateIterator (END);
147 Iterator OutlinerContainer::current()
149 return CreateIterator (CURRENT);
152 Iterator OutlinerContainer::CreateIterator (IteratorLocation aLocation)
154 std::shared_ptr<sd::ViewShell> pOverridingShell{};
155 if (auto pBase = dynamic_cast<sd::ViewShellBase*>(SfxViewShell::Current()))
156 if (auto pViewShellManager = pBase->GetViewShellManager())
157 pOverridingShell = pViewShellManager->GetOverridingMainShell();
159 // Decide on certain features of the outliner which kind of iterator to
160 // use.
161 if (mpOutliner->mbRestrictSearchToSelection)
162 // There is a selection. Search only in this.
163 return CreateSelectionIterator (
164 mpOutliner->maMarkListCopy,
165 mpOutliner->mpDrawDocument,
166 pOverridingShell ? std::move(pOverridingShell) :
167 mpOutliner->mpWeakViewShell.lock(),
168 mpOutliner->mbDirectionIsForward,
169 aLocation);
170 else
171 // Search in the whole document.
172 return CreateDocumentIterator (
173 mpOutliner->mpDrawDocument,
174 pOverridingShell ? std::move(pOverridingShell) :
175 mpOutliner->mpWeakViewShell.lock(),
176 mpOutliner->mbDirectionIsForward,
177 aLocation);
180 Iterator OutlinerContainer::CreateSelectionIterator (
181 const ::std::vector<::unotools::WeakReference<SdrObject>>& rObjectList,
182 SdDrawDocument* pDocument,
183 const std::shared_ptr<ViewShell>& rpViewShell,
184 bool bDirectionIsForward,
185 IteratorLocation aLocation)
187 OSL_ASSERT(rpViewShell);
189 sal_Int32 nObjectIndex;
191 if (bDirectionIsForward)
192 switch (aLocation)
194 case CURRENT:
195 case BEGIN:
196 default:
197 nObjectIndex = 0;
198 break;
199 case END:
200 nObjectIndex = rObjectList.size();
201 break;
203 else
204 switch (aLocation)
206 case CURRENT:
207 case BEGIN:
208 default:
209 nObjectIndex = rObjectList.size()-1;
210 break;
211 case END:
212 nObjectIndex = -1;
213 break;
216 return Iterator (std::make_unique<SelectionIteratorImpl> (
217 rObjectList, nObjectIndex, pDocument, rpViewShell, bDirectionIsForward));
220 Iterator OutlinerContainer::CreateDocumentIterator (
221 SdDrawDocument* pDocument,
222 const std::shared_ptr<ViewShell>& rpViewShell,
223 bool bDirectionIsForward,
224 IteratorLocation aLocation)
226 OSL_ASSERT(rpViewShell);
228 PageKind ePageKind;
229 EditMode eEditMode;
231 switch (aLocation)
233 case BEGIN:
234 default:
235 if (bDirectionIsForward)
237 ePageKind = PageKind::Standard;
238 eEditMode = EditMode::Page;
240 else
242 ePageKind = PageKind::Handout;
243 eEditMode = EditMode::MasterPage;
245 break;
247 case END:
248 if (bDirectionIsForward)
250 ePageKind = PageKind::Handout;
251 eEditMode = EditMode::MasterPage;
253 else
255 ePageKind = PageKind::Standard;
256 eEditMode = EditMode::Page;
258 break;
260 case CURRENT:
261 const std::shared_ptr<DrawViewShell> pDrawViewShell(
262 std::dynamic_pointer_cast<DrawViewShell>(rpViewShell));
263 if (pDrawViewShell)
265 ePageKind = pDrawViewShell->GetPageKind();
266 eEditMode = pDrawViewShell->GetEditMode();
268 else
270 auto pPage = rpViewShell->getCurrentPage();
271 ePageKind = pPage ? pPage->GetPageKind() : PageKind::Standard;
272 eEditMode = EditMode::Page;
274 break;
277 sal_Int32 nPageIndex = GetPageIndex (pDocument, rpViewShell,
278 ePageKind, eEditMode, bDirectionIsForward, aLocation);
280 return Iterator (
281 std::make_unique<DocumentIteratorImpl> (nPageIndex, ePageKind, eEditMode,
282 pDocument, rpViewShell, bDirectionIsForward));
285 sal_Int32 OutlinerContainer::GetPageIndex (
286 SdDrawDocument const * pDocument,
287 const std::shared_ptr<ViewShell>& rpViewShell,
288 PageKind ePageKind,
289 EditMode eEditMode,
290 bool bDirectionIsForward,
291 IteratorLocation aLocation)
293 OSL_ASSERT(rpViewShell);
295 sal_Int32 nPageIndex;
296 sal_Int32 nPageCount;
298 const std::shared_ptr<DrawViewShell> pDrawViewShell(
299 std::dynamic_pointer_cast<DrawViewShell>(rpViewShell));
301 switch (eEditMode)
303 case EditMode::Page:
304 nPageCount = pDocument->GetSdPageCount (ePageKind);
305 break;
306 case EditMode::MasterPage:
307 nPageCount = pDocument->GetMasterSdPageCount(ePageKind);
308 break;
309 default:
310 nPageCount = 0;
313 switch (aLocation)
315 case CURRENT:
316 if (pDrawViewShell)
317 nPageIndex = pDrawViewShell->GetCurPagePos();
318 else
320 const SdPage* pPage = rpViewShell->GetActualPage();
321 if (pPage != nullptr)
322 nPageIndex = (pPage->GetPageNum()-1)/2;
323 else
324 nPageIndex = 0;
326 break;
328 case BEGIN:
329 default:
330 if (bDirectionIsForward)
331 nPageIndex = 0;
332 else
333 nPageIndex = nPageCount-1;
334 break;
336 case END:
337 if (bDirectionIsForward)
338 nPageIndex = nPageCount;
339 else
340 nPageIndex = -1;
341 break;
344 return nPageIndex;
347 //===== IteratorImplBase ====================================================
349 IteratorImplBase::IteratorImplBase(SdDrawDocument* pDocument,
350 const std::weak_ptr<ViewShell>& rpViewShellWeak,
351 bool bDirectionIsForward)
352 : mpDocument (pDocument)
353 , mpViewShellWeak (rpViewShellWeak)
354 , mbDirectionIsForward (bDirectionIsForward)
356 std::shared_ptr<DrawViewShell> pDrawViewShell;
357 if ( ! mpViewShellWeak.expired())
358 pDrawViewShell = std::dynamic_pointer_cast<DrawViewShell>(rpViewShellWeak.lock());
360 if (pDrawViewShell)
362 maPosition.mePageKind = pDrawViewShell->GetPageKind();
363 maPosition.meEditMode = pDrawViewShell->GetEditMode();
365 else
367 maPosition.mePageKind = PageKind::Standard;
368 maPosition.meEditMode = EditMode::Page;
372 IteratorImplBase::IteratorImplBase( SdDrawDocument* pDocument,
373 std::weak_ptr<ViewShell> pViewShellWeak,
374 bool bDirectionIsForward, PageKind ePageKind, EditMode eEditMode)
375 : mpDocument (pDocument)
376 , mpViewShellWeak (std::move(pViewShellWeak))
377 , mbDirectionIsForward (bDirectionIsForward)
379 maPosition.mePageKind = ePageKind;
380 maPosition.meEditMode = eEditMode;
383 IteratorImplBase::~IteratorImplBase()
386 bool IteratorImplBase::operator== (const IteratorImplBase& rIterator) const
388 return maPosition == rIterator.maPosition;
391 bool IteratorImplBase::IsEqualSelection(const IteratorImplBase& rIterator) const
393 // When this method is executed instead of the ones from derived classes
394 // then the argument is of another type then the object itself. In this
395 // just compare the position objects.
396 return maPosition == rIterator.maPosition;
399 const IteratorPosition& IteratorImplBase::GetPosition()
401 return maPosition;
404 IteratorImplBase* IteratorImplBase::Clone (IteratorImplBase* pObject) const
406 if (pObject != nullptr)
408 pObject->maPosition = maPosition;
409 pObject->mpDocument = mpDocument;
410 pObject->mpViewShellWeak = mpViewShellWeak;
411 pObject->mbDirectionIsForward = mbDirectionIsForward;
413 return pObject;
416 void IteratorImplBase::Reverse()
418 mbDirectionIsForward = ! mbDirectionIsForward;
421 //===== SelectionIteratorImpl ===========================================
423 SelectionIteratorImpl::SelectionIteratorImpl (
424 const ::std::vector<::unotools::WeakReference<SdrObject>>& rObjectList,
425 sal_Int32 nObjectIndex,
426 SdDrawDocument* pDocument,
427 const std::weak_ptr<ViewShell>& rpViewShellWeak,
428 bool bDirectionIsForward)
429 : IteratorImplBase (pDocument, rpViewShellWeak, bDirectionIsForward),
430 mrObjectList(rObjectList),
431 mnObjectIndex(nObjectIndex)
435 SelectionIteratorImpl::~SelectionIteratorImpl()
438 IteratorImplBase* SelectionIteratorImpl::Clone (IteratorImplBase* pObject) const
440 SelectionIteratorImpl* pIterator = static_cast<SelectionIteratorImpl*>(pObject);
441 if (pIterator == nullptr)
442 pIterator = new SelectionIteratorImpl (
443 mrObjectList, mnObjectIndex, mpDocument, mpViewShellWeak, mbDirectionIsForward);
444 return pIterator;
447 void SelectionIteratorImpl::GotoNextText()
449 SdrTextObj* pTextObj = DynCastSdrTextObj( mrObjectList.at(mnObjectIndex).get().get() );
450 if (mbDirectionIsForward)
452 if( pTextObj )
454 ++maPosition.mnText;
455 if( maPosition.mnText >= pTextObj->getTextCount() )
457 maPosition.mnText = 0;
458 ++mnObjectIndex;
461 else
463 ++mnObjectIndex;
466 else
468 if( pTextObj )
470 --maPosition.mnText;
471 if( maPosition.mnText < 0 )
473 maPosition.mnText = -1;
474 --mnObjectIndex;
477 else
479 --mnObjectIndex;
480 maPosition.mnText = -1;
483 if( (maPosition.mnText == -1) && (mnObjectIndex >= 0) )
485 pTextObj = DynCastSdrTextObj( mrObjectList.at(mnObjectIndex).get().get() );
486 if( pTextObj )
487 maPosition.mnText = pTextObj->getTextCount() - 1;
490 if( maPosition.mnText == -1 )
491 maPosition.mnText = 0;
495 const IteratorPosition& SelectionIteratorImpl::GetPosition()
497 maPosition.mxObject = mrObjectList.at(mnObjectIndex);
499 return maPosition;
502 bool SelectionIteratorImpl::operator== (const IteratorImplBase& rIterator) const
504 return rIterator.IsEqualSelection(*this);
507 bool SelectionIteratorImpl::IsEqualSelection(const IteratorImplBase& rIterator) const
509 const SelectionIteratorImpl* pSelectionIterator =
510 static_cast<const SelectionIteratorImpl*>(&rIterator);
511 return mpDocument == pSelectionIterator->mpDocument
512 && mnObjectIndex == pSelectionIterator->mnObjectIndex;
515 void DocumentIteratorImpl::SetPage(sal_Int32 nPageIndex)
517 maPosition.mnPageIndex = nPageIndex;
519 sal_Int32 nPageCount;
520 if (maPosition.meEditMode == EditMode::Page)
521 nPageCount = mpDocument->GetSdPageCount(maPosition.mePageKind);
522 else
523 nPageCount = mpDocument->GetMasterSdPageCount(
524 maPosition.mePageKind);
526 // Get page pointer. Here we have three cases: regular pages,
527 // master pages and invalid page indices. The later ones are not
528 // errors but the effect of the iterator advancing to the next page
529 // and going past the last one. This dropping of the rim at the far
530 // side is detected here and has to be reacted to by the caller.
531 if (nPageIndex>=0 && nPageIndex < nPageCount)
533 if (maPosition.meEditMode == EditMode::Page)
534 mpPage = mpDocument->GetSdPage (
535 static_cast<sal_uInt16>(nPageIndex),
536 maPosition.mePageKind);
537 else
538 mpPage = mpDocument->GetMasterSdPage (
539 static_cast<sal_uInt16>(nPageIndex),
540 maPosition.mePageKind);
542 else
543 mpPage = nullptr;
545 // Set up object list iterator.
546 if (mpPage != nullptr)
547 moObjectIterator.emplace(mpPage, SdrIterMode::DeepNoGroups, ! mbDirectionIsForward);
548 else
549 moObjectIterator.reset();
551 // Get object pointer.
552 if (moObjectIterator && moObjectIterator->IsMore())
553 maPosition.mxObject = moObjectIterator->Next();
554 else
555 maPosition.mxObject = nullptr;
557 maPosition.mnText = 0;
558 if( !mbDirectionIsForward && maPosition.mxObject.get().is() )
560 SdrTextObj* pTextObj = DynCastSdrTextObj( maPosition.mxObject.get().get() );
561 if( pTextObj )
562 maPosition.mnText = pTextObj->getTextCount() - 1;
567 void DocumentIteratorImpl::Reverse()
569 IteratorImplBase::Reverse ();
571 // Create reversed object list iterator.
572 if (mpPage != nullptr)
573 moObjectIterator.emplace(mpPage, SdrIterMode::DeepNoGroups, ! mbDirectionIsForward);
574 else
575 moObjectIterator.reset();
577 // Move iterator to the current object.
578 ::unotools::WeakReference<SdrObject> xObject = std::move(maPosition.mxObject);
579 maPosition.mxObject = nullptr;
581 if (!moObjectIterator)
582 return;
584 while (moObjectIterator->IsMore() && maPosition.mxObject.get() != xObject.get())
585 maPosition.mxObject = moObjectIterator->Next();
588 //===== DocumentIteratorImpl ============================================
590 DocumentIteratorImpl::DocumentIteratorImpl (
591 sal_Int32 nPageIndex,
592 PageKind ePageKind, EditMode eEditMode,
593 SdDrawDocument* pDocument,
594 const std::weak_ptr<ViewShell>& rpViewShellWeak,
595 bool bDirectionIsForward)
596 : IteratorImplBase (pDocument, rpViewShellWeak, bDirectionIsForward, ePageKind, eEditMode)
597 , mpPage(nullptr)
599 if (eEditMode == EditMode::Page)
600 mnPageCount = pDocument->GetSdPageCount (ePageKind);
601 else
602 mnPageCount = pDocument->GetMasterSdPageCount(ePageKind);
603 SetPage(nPageIndex);
606 DocumentIteratorImpl::~DocumentIteratorImpl()
609 IteratorImplBase* DocumentIteratorImpl::Clone (IteratorImplBase* pObject) const
611 DocumentIteratorImpl* pIterator = static_cast<DocumentIteratorImpl*>(pObject);
612 if (pIterator == nullptr)
613 pIterator = new DocumentIteratorImpl (
614 maPosition.mnPageIndex, maPosition.mePageKind, maPosition.meEditMode,
615 mpDocument, mpViewShellWeak, mbDirectionIsForward);
616 // Finish the cloning.
617 IteratorImplBase::Clone (pObject);
619 if (moObjectIterator)
621 pIterator->moObjectIterator.emplace(mpPage, SdrIterMode::DeepNoGroups, !mbDirectionIsForward);
623 // No direct way to set the object iterator to the current object.
624 pIterator->maPosition.mxObject = nullptr;
625 while (pIterator->moObjectIterator->IsMore() && pIterator->maPosition.mxObject.get()!=maPosition.mxObject.get())
626 pIterator->maPosition.mxObject = pIterator->moObjectIterator->Next();
628 else
629 pIterator->moObjectIterator.reset();
631 return pIterator;
634 void DocumentIteratorImpl::GotoNextText()
636 bool bSetToOnePastLastPage = false;
637 bool bViewChanged = false;
639 SdrTextObj* pTextObj = DynCastSdrTextObj( maPosition.mxObject.get().get() );
640 if( pTextObj )
642 if (mbDirectionIsForward)
644 ++maPosition.mnText;
645 if( maPosition.mnText < pTextObj->getTextCount() )
646 return;
648 else
650 --maPosition.mnText;
651 if( maPosition.mnText >= 0 )
652 return;
656 if (moObjectIterator && moObjectIterator->IsMore())
657 maPosition.mxObject = moObjectIterator->Next();
658 else
659 maPosition.mxObject = nullptr;
661 if (!maPosition.mxObject.get().is() )
663 if (maPosition.meEditMode == EditMode::Page
664 && maPosition.mePageKind == PageKind::Standard)
666 maPosition.mePageKind = PageKind::Notes;
667 if (mbDirectionIsForward)
668 SetPage(maPosition.mnPageIndex);
669 else
670 SetPage(maPosition.mnPageIndex - 1);
672 else if (maPosition.meEditMode == EditMode::Page
673 && maPosition.mePageKind == PageKind::Notes)
675 maPosition.mePageKind = PageKind::Standard;
676 if (mbDirectionIsForward)
677 SetPage(maPosition.mnPageIndex + 1);
678 else
679 SetPage(maPosition.mnPageIndex);
681 else
683 if (mbDirectionIsForward)
684 SetPage(maPosition.mnPageIndex + 1);
685 else
686 SetPage(maPosition.mnPageIndex - 1);
689 if (mpPage != nullptr)
690 moObjectIterator.emplace( mpPage, SdrIterMode::DeepNoGroups, !mbDirectionIsForward );
691 if (moObjectIterator && moObjectIterator->IsMore())
692 maPosition.mxObject = moObjectIterator->Next();
693 else
694 maPosition.mxObject = nullptr;
697 maPosition.mnText = 0;
698 if( !mbDirectionIsForward && maPosition.mxObject.get().is() )
700 pTextObj = DynCastSdrTextObj( maPosition.mxObject.get().get() );
701 if( pTextObj )
702 maPosition.mnText = pTextObj->getTextCount() - 1;
706 if (mbDirectionIsForward)
708 if (maPosition.mnPageIndex >= mnPageCount)
710 // Switch to master page.
711 if (maPosition.meEditMode == EditMode::Page)
713 maPosition.meEditMode = EditMode::MasterPage;
714 SetPage (0);
716 // Switch to next view mode.
717 else
719 if (maPosition.mePageKind == PageKind::Handout)
721 // search wrapped
722 bSetToOnePastLastPage = true;
724 else if (maPosition.mePageKind == PageKind::Standard)
726 // switch to master notes
727 maPosition.mePageKind = PageKind::Notes;
728 SetPage(0);
730 else if (maPosition.mePageKind == PageKind::Notes)
732 // switch to master handout
733 maPosition.mePageKind = PageKind::Handout;
734 SetPage(0);
737 bViewChanged = true;
740 else
742 if (maPosition.mnPageIndex < 0)
744 if (maPosition.meEditMode == EditMode::MasterPage)
746 if (maPosition.mePageKind == PageKind::Standard)
748 maPosition.meEditMode = EditMode::Page;
749 maPosition.mePageKind = PageKind::Notes;
750 bSetToOnePastLastPage = true;
752 else if (maPosition.mePageKind == PageKind::Handout)
754 maPosition.mePageKind = PageKind::Notes;
755 bSetToOnePastLastPage = true;
757 else if (maPosition.mePageKind == PageKind::Notes)
759 maPosition.mePageKind = PageKind::Standard;
760 bSetToOnePastLastPage = true;
763 else
765 // search wrapped
766 SetPage(-1);
769 bViewChanged = true;
772 if (!bViewChanged)
773 return;
775 // Get new page count;
776 if (maPosition.meEditMode == EditMode::Page)
777 mnPageCount = mpDocument->GetSdPageCount (maPosition.mePageKind);
778 else
779 mnPageCount = mpDocument->GetMasterSdPageCount(maPosition.mePageKind);
781 // Now that we know the number of pages we can set the current page index.
782 if (bSetToOnePastLastPage)
783 SetPage (mnPageCount);
786 } // end of namespace ::sd::outliner
788 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */