1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <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>
32 namespace sd::outliner
{
34 //===== IteratorPosition ======================================================
36 IteratorPosition::IteratorPosition()
39 , mePageKind(PageKind::Standard
)
40 , meEditMode(EditMode::Page
)
44 bool IteratorPosition::operator== (const IteratorPosition
& aPosition
) const
46 return mxObject
.get() == aPosition
.mxObject
.get()
47 && mnText
== aPosition
.mnText
48 && mnPageIndex
== aPosition
.mnPageIndex
49 && mePageKind
== aPosition
.mePageKind
50 && meEditMode
== aPosition
.meEditMode
;
53 //===== Iterator ==============================================================
59 Iterator::Iterator (const Iterator
& rIterator
)
60 : mxIterator(rIterator
.mxIterator
? rIterator
.mxIterator
->Clone() : nullptr)
64 Iterator::Iterator(Iterator
&& rIterator
) noexcept
65 : mxIterator(std::move(rIterator
.mxIterator
))
69 Iterator::Iterator (std::unique_ptr
<IteratorImplBase
> pObject
)
70 : mxIterator(std::move(pObject
))
78 Iterator
& Iterator::operator= (const Iterator
& rIterator
)
80 if (this != &rIterator
)
82 if (rIterator
.mxIterator
)
83 mxIterator
.reset(rIterator
.mxIterator
->Clone());
90 Iterator
& Iterator::operator=(Iterator
&& rIterator
) noexcept
92 mxIterator
= std::move(rIterator
.mxIterator
);
96 const IteratorPosition
& Iterator::operator* () const
98 DBG_ASSERT (mxIterator
, "::sd::outliner::Iterator::operator* : missing implementation object");
99 return mxIterator
->GetPosition();
102 Iterator
& Iterator::operator++ ()
105 mxIterator
->GotoNextText();
109 bool Iterator::operator== (const Iterator
& rIterator
) const
111 if (!mxIterator
|| !rIterator
.mxIterator
)
112 return mxIterator
.get() == rIterator
.mxIterator
.get();
114 return *mxIterator
== *rIterator
.mxIterator
;
117 bool Iterator::operator!= (const Iterator
& rIterator
) const
119 return ! operator==(rIterator
);
122 void Iterator::Reverse()
125 mxIterator
->Reverse();
128 //===== IteratorFactory =======================================================
130 OutlinerContainer::OutlinerContainer (SdOutliner
* pOutliner
)
131 : mpOutliner(pOutliner
)
135 Iterator
OutlinerContainer::begin()
137 return CreateIterator (BEGIN
);
140 Iterator
OutlinerContainer::end()
142 return CreateIterator (END
);
145 Iterator
OutlinerContainer::current()
147 return CreateIterator (CURRENT
);
150 Iterator
OutlinerContainer::CreateIterator (IteratorLocation aLocation
)
152 // Decide on certain features of the outliner which kind of iterator to
154 if (mpOutliner
->mbRestrictSearchToSelection
)
155 // There is a selection. Search only in this.
156 return CreateSelectionIterator (
157 mpOutliner
->maMarkListCopy
,
158 mpOutliner
->mpDrawDocument
,
159 mpOutliner
->mpWeakViewShell
.lock(),
160 mpOutliner
->mbDirectionIsForward
,
163 // Search in the whole document.
164 return CreateDocumentIterator (
165 mpOutliner
->mpDrawDocument
,
166 mpOutliner
->mpWeakViewShell
.lock(),
167 mpOutliner
->mbDirectionIsForward
,
171 Iterator
OutlinerContainer::CreateSelectionIterator (
172 const ::std::vector
<::unotools::WeakReference
<SdrObject
>>& rObjectList
,
173 SdDrawDocument
* pDocument
,
174 const std::shared_ptr
<ViewShell
>& rpViewShell
,
175 bool bDirectionIsForward
,
176 IteratorLocation aLocation
)
178 OSL_ASSERT(rpViewShell
);
180 sal_Int32 nObjectIndex
;
182 if (bDirectionIsForward
)
191 nObjectIndex
= rObjectList
.size();
200 nObjectIndex
= rObjectList
.size()-1;
207 return Iterator (std::make_unique
<SelectionIteratorImpl
> (
208 rObjectList
, nObjectIndex
, pDocument
, rpViewShell
, bDirectionIsForward
));
211 Iterator
OutlinerContainer::CreateDocumentIterator (
212 SdDrawDocument
* pDocument
,
213 const std::shared_ptr
<ViewShell
>& rpViewShell
,
214 bool bDirectionIsForward
,
215 IteratorLocation aLocation
)
217 OSL_ASSERT(rpViewShell
);
226 if (bDirectionIsForward
)
228 ePageKind
= PageKind::Standard
;
229 eEditMode
= EditMode::Page
;
233 ePageKind
= PageKind::Handout
;
234 eEditMode
= EditMode::MasterPage
;
239 if (bDirectionIsForward
)
241 ePageKind
= PageKind::Handout
;
242 eEditMode
= EditMode::MasterPage
;
246 ePageKind
= PageKind::Standard
;
247 eEditMode
= EditMode::Page
;
252 const std::shared_ptr
<DrawViewShell
> pDrawViewShell(
253 std::dynamic_pointer_cast
<DrawViewShell
>(rpViewShell
));
256 ePageKind
= pDrawViewShell
->GetPageKind();
257 eEditMode
= pDrawViewShell
->GetEditMode();
261 ePageKind
= PageKind::Standard
;
262 eEditMode
= EditMode::Page
;
267 sal_Int32 nPageIndex
= GetPageIndex (pDocument
, rpViewShell
,
268 ePageKind
, eEditMode
, bDirectionIsForward
, aLocation
);
271 std::make_unique
<DocumentIteratorImpl
> (nPageIndex
, ePageKind
, eEditMode
,
272 pDocument
, rpViewShell
, bDirectionIsForward
));
275 sal_Int32
OutlinerContainer::GetPageIndex (
276 SdDrawDocument
const * pDocument
,
277 const std::shared_ptr
<ViewShell
>& rpViewShell
,
280 bool bDirectionIsForward
,
281 IteratorLocation aLocation
)
283 OSL_ASSERT(rpViewShell
);
285 sal_Int32 nPageIndex
;
286 sal_Int32 nPageCount
;
288 const std::shared_ptr
<DrawViewShell
> pDrawViewShell(
289 std::dynamic_pointer_cast
<DrawViewShell
>(rpViewShell
));
294 nPageCount
= pDocument
->GetSdPageCount (ePageKind
);
296 case EditMode::MasterPage
:
297 nPageCount
= pDocument
->GetMasterSdPageCount(ePageKind
);
307 nPageIndex
= pDrawViewShell
->GetCurPagePos();
310 const SdPage
* pPage
= rpViewShell
->GetActualPage();
311 if (pPage
!= nullptr)
312 nPageIndex
= (pPage
->GetPageNum()-1)/2;
320 if (bDirectionIsForward
)
323 nPageIndex
= nPageCount
-1;
327 if (bDirectionIsForward
)
328 nPageIndex
= nPageCount
;
337 //===== IteratorImplBase ====================================================
339 IteratorImplBase::IteratorImplBase(SdDrawDocument
* pDocument
,
340 const std::weak_ptr
<ViewShell
>& rpViewShellWeak
,
341 bool bDirectionIsForward
)
342 : mpDocument (pDocument
)
343 , mpViewShellWeak (rpViewShellWeak
)
344 , mbDirectionIsForward (bDirectionIsForward
)
346 std::shared_ptr
<DrawViewShell
> pDrawViewShell
;
347 if ( ! mpViewShellWeak
.expired())
348 pDrawViewShell
= std::dynamic_pointer_cast
<DrawViewShell
>(rpViewShellWeak
.lock());
352 maPosition
.mePageKind
= pDrawViewShell
->GetPageKind();
353 maPosition
.meEditMode
= pDrawViewShell
->GetEditMode();
357 maPosition
.mePageKind
= PageKind::Standard
;
358 maPosition
.meEditMode
= EditMode::Page
;
362 IteratorImplBase::IteratorImplBase( SdDrawDocument
* pDocument
,
363 std::weak_ptr
<ViewShell
> pViewShellWeak
,
364 bool bDirectionIsForward
, PageKind ePageKind
, EditMode eEditMode
)
365 : mpDocument (pDocument
)
366 , mpViewShellWeak (std::move(pViewShellWeak
))
367 , mbDirectionIsForward (bDirectionIsForward
)
369 maPosition
.mePageKind
= ePageKind
;
370 maPosition
.meEditMode
= eEditMode
;
373 IteratorImplBase::~IteratorImplBase()
376 bool IteratorImplBase::operator== (const IteratorImplBase
& rIterator
) const
378 return maPosition
== rIterator
.maPosition
;
381 bool IteratorImplBase::IsEqualSelection(const IteratorImplBase
& rIterator
) const
383 // When this method is executed instead of the ones from derived classes
384 // then the argument is of another type then the object itself. In this
385 // just compare the position objects.
386 return maPosition
== rIterator
.maPosition
;
389 const IteratorPosition
& IteratorImplBase::GetPosition()
394 IteratorImplBase
* IteratorImplBase::Clone (IteratorImplBase
* pObject
) const
396 if (pObject
!= nullptr)
398 pObject
->maPosition
= maPosition
;
399 pObject
->mpDocument
= mpDocument
;
400 pObject
->mpViewShellWeak
= mpViewShellWeak
;
401 pObject
->mbDirectionIsForward
= mbDirectionIsForward
;
406 void IteratorImplBase::Reverse()
408 mbDirectionIsForward
= ! mbDirectionIsForward
;
411 //===== SelectionIteratorImpl ===========================================
413 SelectionIteratorImpl::SelectionIteratorImpl (
414 const ::std::vector
<::unotools::WeakReference
<SdrObject
>>& rObjectList
,
415 sal_Int32 nObjectIndex
,
416 SdDrawDocument
* pDocument
,
417 const std::weak_ptr
<ViewShell
>& rpViewShellWeak
,
418 bool bDirectionIsForward
)
419 : IteratorImplBase (pDocument
, rpViewShellWeak
, bDirectionIsForward
),
420 mrObjectList(rObjectList
),
421 mnObjectIndex(nObjectIndex
)
425 SelectionIteratorImpl::~SelectionIteratorImpl()
428 IteratorImplBase
* SelectionIteratorImpl::Clone (IteratorImplBase
* pObject
) const
430 SelectionIteratorImpl
* pIterator
= static_cast<SelectionIteratorImpl
*>(pObject
);
431 if (pIterator
== nullptr)
432 pIterator
= new SelectionIteratorImpl (
433 mrObjectList
, mnObjectIndex
, mpDocument
, mpViewShellWeak
, mbDirectionIsForward
);
437 void SelectionIteratorImpl::GotoNextText()
439 SdrTextObj
* pTextObj
= DynCastSdrTextObj( mrObjectList
.at(mnObjectIndex
).get().get() );
440 if (mbDirectionIsForward
)
445 if( maPosition
.mnText
>= pTextObj
->getTextCount() )
447 maPosition
.mnText
= 0;
461 if( maPosition
.mnText
< 0 )
463 maPosition
.mnText
= -1;
470 maPosition
.mnText
= -1;
473 if( (maPosition
.mnText
== -1) && (mnObjectIndex
>= 0) )
475 pTextObj
= DynCastSdrTextObj( mrObjectList
.at(mnObjectIndex
).get().get() );
477 maPosition
.mnText
= pTextObj
->getTextCount() - 1;
480 if( maPosition
.mnText
== -1 )
481 maPosition
.mnText
= 0;
485 const IteratorPosition
& SelectionIteratorImpl::GetPosition()
487 maPosition
.mxObject
= mrObjectList
.at(mnObjectIndex
);
492 bool SelectionIteratorImpl::operator== (const IteratorImplBase
& rIterator
) const
494 return rIterator
.IsEqualSelection(*this);
497 bool SelectionIteratorImpl::IsEqualSelection(const IteratorImplBase
& rIterator
) const
499 const SelectionIteratorImpl
* pSelectionIterator
=
500 static_cast<const SelectionIteratorImpl
*>(&rIterator
);
501 return mpDocument
== pSelectionIterator
->mpDocument
502 && mnObjectIndex
== pSelectionIterator
->mnObjectIndex
;
505 //===== ViewIteratorImpl ================================================
507 ViewIteratorImpl::ViewIteratorImpl (
508 sal_Int32 nPageIndex
,
509 SdDrawDocument
* pDocument
,
510 const std::weak_ptr
<ViewShell
>& rpViewShellWeak
,
511 bool bDirectionIsForward
)
512 : IteratorImplBase (pDocument
, rpViewShellWeak
, bDirectionIsForward
),
513 mbPageChangeOccurred(false),
516 SetPage (nPageIndex
);
519 ViewIteratorImpl::ViewIteratorImpl (
520 sal_Int32 nPageIndex
,
521 SdDrawDocument
* pDocument
,
522 const std::weak_ptr
<ViewShell
>& rpViewShellWeak
,
523 bool bDirectionIsForward
,
526 : IteratorImplBase (pDocument
, rpViewShellWeak
, bDirectionIsForward
, ePageKind
, eEditMode
),
527 mbPageChangeOccurred(false),
530 SetPage (nPageIndex
);
533 ViewIteratorImpl::~ViewIteratorImpl()
537 IteratorImplBase
* ViewIteratorImpl::Clone (IteratorImplBase
* pObject
) const
540 ViewIteratorImpl
* pIterator
= static_cast<ViewIteratorImpl
*>(pObject
);
541 if (pIterator
== nullptr)
542 pIterator
= new ViewIteratorImpl (
543 maPosition
.mnPageIndex
, mpDocument
, mpViewShellWeak
, mbDirectionIsForward
);
545 IteratorImplBase::Clone (pObject
);
547 if (moObjectIterator
)
549 pIterator
->moObjectIterator
.emplace(mpPage
, SdrIterMode::DeepNoGroups
, !mbDirectionIsForward
);
551 // No direct way to set the object iterator to the current object.
552 pIterator
->maPosition
.mxObject
= nullptr;
553 while (pIterator
->moObjectIterator
->IsMore() && pIterator
->maPosition
.mxObject
.get()!=maPosition
.mxObject
.get())
554 pIterator
->maPosition
.mxObject
= pIterator
->moObjectIterator
->Next();
557 pIterator
->moObjectIterator
.reset();
562 void ViewIteratorImpl::GotoNextText()
564 SdrTextObj
* pTextObj
= DynCastSdrTextObj( maPosition
.mxObject
.get().get() );
567 if (mbDirectionIsForward
)
570 if( maPosition
.mnText
< pTextObj
->getTextCount() )
576 if( maPosition
.mnText
>= 0 )
581 if (moObjectIterator
&& moObjectIterator
->IsMore())
582 maPosition
.mxObject
= moObjectIterator
->Next();
584 maPosition
.mxObject
= nullptr;
586 if (!maPosition
.mxObject
.get().is() )
588 if (mbDirectionIsForward
)
589 SetPage (maPosition
.mnPageIndex
+1);
591 SetPage (maPosition
.mnPageIndex
-1);
593 if (mpPage
!= nullptr)
594 moObjectIterator
.emplace( mpPage
, SdrIterMode::DeepNoGroups
, !mbDirectionIsForward
);
595 if (moObjectIterator
&& moObjectIterator
->IsMore())
596 maPosition
.mxObject
= moObjectIterator
->Next();
598 maPosition
.mxObject
= nullptr;
601 maPosition
.mnText
= 0;
602 if( !mbDirectionIsForward
&& maPosition
.mxObject
.get().is() )
604 pTextObj
= DynCastSdrTextObj( maPosition
.mxObject
.get().get() );
606 maPosition
.mnText
= pTextObj
->getTextCount() - 1;
610 void ViewIteratorImpl::SetPage (sal_Int32 nPageIndex
)
612 mbPageChangeOccurred
= (maPosition
.mnPageIndex
!=nPageIndex
);
613 if (mbPageChangeOccurred
)
615 maPosition
.mnPageIndex
= nPageIndex
;
617 sal_Int32 nPageCount
;
618 if (maPosition
.meEditMode
== EditMode::Page
)
619 nPageCount
= mpDocument
->GetSdPageCount(maPosition
.mePageKind
);
621 nPageCount
= mpDocument
->GetMasterSdPageCount(
622 maPosition
.mePageKind
);
624 // Get page pointer. Here we have three cases: regular pages,
625 // master pages and invalid page indices. The later ones are not
626 // errors but the effect of the iterator advancing to the next page
627 // and going past the last one. This dropping of the rim at the far
628 // side is detected here and has to be reacted to by the caller.
629 if (nPageIndex
>=0 && nPageIndex
< nPageCount
)
631 if (maPosition
.meEditMode
== EditMode::Page
)
632 mpPage
= mpDocument
->GetSdPage (
633 static_cast<sal_uInt16
>(nPageIndex
),
634 maPosition
.mePageKind
);
636 mpPage
= mpDocument
->GetMasterSdPage (
637 static_cast<sal_uInt16
>(nPageIndex
),
638 maPosition
.mePageKind
);
644 // Set up object list iterator.
645 if (mpPage
!= nullptr)
646 moObjectIterator
.emplace(mpPage
, SdrIterMode::DeepNoGroups
, ! mbDirectionIsForward
);
648 moObjectIterator
.reset();
650 // Get object pointer.
651 if (moObjectIterator
&& moObjectIterator
->IsMore())
652 maPosition
.mxObject
= moObjectIterator
->Next();
654 maPosition
.mxObject
= nullptr;
656 maPosition
.mnText
= 0;
657 if( !mbDirectionIsForward
&& maPosition
.mxObject
.get().is() )
659 SdrTextObj
* pTextObj
= DynCastSdrTextObj( maPosition
.mxObject
.get().get() );
661 maPosition
.mnText
= pTextObj
->getTextCount() - 1;
666 void ViewIteratorImpl::Reverse()
668 IteratorImplBase::Reverse ();
670 // Create reversed object list iterator.
671 if (mpPage
!= nullptr)
672 moObjectIterator
.emplace(mpPage
, SdrIterMode::DeepNoGroups
, ! mbDirectionIsForward
);
674 moObjectIterator
.reset();
676 // Move iterator to the current object.
677 ::unotools::WeakReference
<SdrObject
> xObject
= std::move(maPosition
.mxObject
);
678 maPosition
.mxObject
= nullptr;
680 if (!moObjectIterator
)
683 while (moObjectIterator
->IsMore() && maPosition
.mxObject
.get() != xObject
.get())
684 maPosition
.mxObject
= moObjectIterator
->Next();
687 //===== DocumentIteratorImpl ============================================
689 DocumentIteratorImpl::DocumentIteratorImpl (
690 sal_Int32 nPageIndex
,
691 PageKind ePageKind
, EditMode eEditMode
,
692 SdDrawDocument
* pDocument
,
693 const std::weak_ptr
<ViewShell
>& rpViewShellWeak
,
694 bool bDirectionIsForward
)
695 : ViewIteratorImpl (nPageIndex
, pDocument
, rpViewShellWeak
, bDirectionIsForward
,
696 ePageKind
, eEditMode
)
698 if (eEditMode
== EditMode::Page
)
699 mnPageCount
= pDocument
->GetSdPageCount (ePageKind
);
701 mnPageCount
= pDocument
->GetMasterSdPageCount(ePageKind
);
704 DocumentIteratorImpl::~DocumentIteratorImpl()
707 IteratorImplBase
* DocumentIteratorImpl::Clone (IteratorImplBase
* pObject
) const
709 DocumentIteratorImpl
* pIterator
= static_cast<DocumentIteratorImpl
*>(pObject
);
710 if (pIterator
== nullptr)
711 pIterator
= new DocumentIteratorImpl (
712 maPosition
.mnPageIndex
, maPosition
.mePageKind
, maPosition
.meEditMode
,
713 mpDocument
, mpViewShellWeak
, mbDirectionIsForward
);
714 // Finish the cloning.
715 return ViewIteratorImpl::Clone (pIterator
);
718 void DocumentIteratorImpl::GotoNextText()
720 bool bSetToOnePastLastPage
= false;
721 bool bViewChanged
= false;
723 ViewIteratorImpl::GotoNextText();
725 if (mbDirectionIsForward
)
727 if (maPosition
.mnPageIndex
>= mnPageCount
)
729 // Switch to master page.
730 if (maPosition
.meEditMode
== EditMode::Page
)
732 maPosition
.meEditMode
= EditMode::MasterPage
;
736 // Switch to next view mode.
739 if (maPosition
.mePageKind
== PageKind::Handout
)
740 // Not really necessary but makes things more clear.
741 bSetToOnePastLastPage
= true;
744 maPosition
.meEditMode
= EditMode::Page
;
745 if (maPosition
.mePageKind
== PageKind::Standard
)
746 maPosition
.mePageKind
= PageKind::Notes
;
747 else if (maPosition
.mePageKind
== PageKind::Notes
)
748 maPosition
.mePageKind
= PageKind::Handout
;
756 if (maPosition
.mnPageIndex
< 0)
758 // Switch from master pages to draw pages.
759 if (maPosition
.meEditMode
== EditMode::MasterPage
)
761 maPosition
.meEditMode
= EditMode::Page
;
762 bSetToOnePastLastPage
= true;
765 // Switch to previous view mode.
768 if (maPosition
.mePageKind
== PageKind::Standard
)
772 maPosition
.meEditMode
= EditMode::MasterPage
;
773 if (maPosition
.mePageKind
== PageKind::Handout
)
774 maPosition
.mePageKind
= PageKind::Notes
;
775 else if (maPosition
.mePageKind
== PageKind::Notes
)
776 maPosition
.mePageKind
= PageKind::Standard
;
777 bSetToOnePastLastPage
= true;
786 // Get new page count;
787 sal_Int32 nPageCount
;
788 if (maPosition
.meEditMode
== EditMode::Page
)
789 nPageCount
= mpDocument
->GetSdPageCount (maPosition
.mePageKind
);
791 nPageCount
= mpDocument
->GetMasterSdPageCount(maPosition
.mePageKind
);
793 // Now that we know the number of pages we can set the current page index.
794 if (bSetToOnePastLastPage
)
795 SetPage (nPageCount
);
798 } // end of namespace ::sd::outliner
800 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */