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>
31 #include <ViewShellBase.hxx>
32 #include <ViewShellManager.hxx>
34 namespace sd::outliner
{
36 //===== IteratorPosition ======================================================
38 IteratorPosition::IteratorPosition()
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 ==============================================================
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
))
80 Iterator
& Iterator::operator= (const Iterator
& rIterator
)
82 if (this != &rIterator
)
84 if (rIterator
.mxIterator
)
85 mxIterator
.reset(rIterator
.mxIterator
->Clone());
92 Iterator
& Iterator::operator=(Iterator
&& rIterator
) noexcept
94 mxIterator
= std::move(rIterator
.mxIterator
);
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++ ()
107 mxIterator
->GotoNextText();
111 bool Iterator::operator== (const Iterator
& rIterator
) const
113 if (!mxIterator
|| !rIterator
.mxIterator
)
114 return mxIterator
.get() == rIterator
.mxIterator
.get();
116 return *mxIterator
== *rIterator
.mxIterator
;
119 bool Iterator::operator!= (const Iterator
& rIterator
) const
121 return ! operator==(rIterator
);
124 void Iterator::Reverse()
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
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
,
171 // Search in the whole document.
172 return CreateDocumentIterator (
173 mpOutliner
->mpDrawDocument
,
174 pOverridingShell
? std::move(pOverridingShell
) :
175 mpOutliner
->mpWeakViewShell
.lock(),
176 mpOutliner
->mbDirectionIsForward
,
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
)
200 nObjectIndex
= rObjectList
.size();
209 nObjectIndex
= rObjectList
.size()-1;
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
);
235 if (bDirectionIsForward
)
237 ePageKind
= PageKind::Standard
;
238 eEditMode
= EditMode::Page
;
242 ePageKind
= PageKind::Handout
;
243 eEditMode
= EditMode::MasterPage
;
248 if (bDirectionIsForward
)
250 ePageKind
= PageKind::Handout
;
251 eEditMode
= EditMode::MasterPage
;
255 ePageKind
= PageKind::Standard
;
256 eEditMode
= EditMode::Page
;
261 const std::shared_ptr
<DrawViewShell
> pDrawViewShell(
262 std::dynamic_pointer_cast
<DrawViewShell
>(rpViewShell
));
265 ePageKind
= pDrawViewShell
->GetPageKind();
266 eEditMode
= pDrawViewShell
->GetEditMode();
270 auto pPage
= rpViewShell
->getCurrentPage();
271 ePageKind
= pPage
? pPage
->GetPageKind() : PageKind::Standard
;
272 eEditMode
= EditMode::Page
;
277 sal_Int32 nPageIndex
= GetPageIndex (pDocument
, rpViewShell
,
278 ePageKind
, eEditMode
, bDirectionIsForward
, aLocation
);
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
,
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
));
304 nPageCount
= pDocument
->GetSdPageCount (ePageKind
);
306 case EditMode::MasterPage
:
307 nPageCount
= pDocument
->GetMasterSdPageCount(ePageKind
);
317 nPageIndex
= pDrawViewShell
->GetCurPagePos();
320 const SdPage
* pPage
= rpViewShell
->GetActualPage();
321 if (pPage
!= nullptr)
322 nPageIndex
= (pPage
->GetPageNum()-1)/2;
330 if (bDirectionIsForward
)
333 nPageIndex
= nPageCount
-1;
337 if (bDirectionIsForward
)
338 nPageIndex
= nPageCount
;
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());
362 maPosition
.mePageKind
= pDrawViewShell
->GetPageKind();
363 maPosition
.meEditMode
= pDrawViewShell
->GetEditMode();
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()
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
;
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
);
447 void SelectionIteratorImpl::GotoNextText()
449 SdrTextObj
* pTextObj
= DynCastSdrTextObj( mrObjectList
.at(mnObjectIndex
).get().get() );
450 if (mbDirectionIsForward
)
455 if( maPosition
.mnText
>= pTextObj
->getTextCount() )
457 maPosition
.mnText
= 0;
471 if( maPosition
.mnText
< 0 )
473 maPosition
.mnText
= -1;
480 maPosition
.mnText
= -1;
483 if( (maPosition
.mnText
== -1) && (mnObjectIndex
>= 0) )
485 pTextObj
= DynCastSdrTextObj( mrObjectList
.at(mnObjectIndex
).get().get() );
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
);
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
);
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
);
538 mpPage
= mpDocument
->GetMasterSdPage (
539 static_cast<sal_uInt16
>(nPageIndex
),
540 maPosition
.mePageKind
);
545 // Set up object list iterator.
546 if (mpPage
!= nullptr)
547 moObjectIterator
.emplace(mpPage
, SdrIterMode::DeepNoGroups
, ! mbDirectionIsForward
);
549 moObjectIterator
.reset();
551 // Get object pointer.
552 if (moObjectIterator
&& moObjectIterator
->IsMore())
553 maPosition
.mxObject
= moObjectIterator
->Next();
555 maPosition
.mxObject
= nullptr;
557 maPosition
.mnText
= 0;
558 if( !mbDirectionIsForward
&& maPosition
.mxObject
.get().is() )
560 SdrTextObj
* pTextObj
= DynCastSdrTextObj( maPosition
.mxObject
.get().get() );
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
);
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
)
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
)
599 if (eEditMode
== EditMode::Page
)
600 mnPageCount
= pDocument
->GetSdPageCount (ePageKind
);
602 mnPageCount
= pDocument
->GetMasterSdPageCount(ePageKind
);
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();
629 pIterator
->moObjectIterator
.reset();
634 void DocumentIteratorImpl::GotoNextText()
636 bool bSetToOnePastLastPage
= false;
637 bool bViewChanged
= false;
639 SdrTextObj
* pTextObj
= DynCastSdrTextObj( maPosition
.mxObject
.get().get() );
642 if (mbDirectionIsForward
)
645 if( maPosition
.mnText
< pTextObj
->getTextCount() )
651 if( maPosition
.mnText
>= 0 )
656 if (moObjectIterator
&& moObjectIterator
->IsMore())
657 maPosition
.mxObject
= moObjectIterator
->Next();
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
);
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);
679 SetPage(maPosition
.mnPageIndex
);
683 if (mbDirectionIsForward
)
684 SetPage(maPosition
.mnPageIndex
+ 1);
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();
694 maPosition
.mxObject
= nullptr;
697 maPosition
.mnText
= 0;
698 if( !mbDirectionIsForward
&& maPosition
.mxObject
.get().is() )
700 pTextObj
= DynCastSdrTextObj( maPosition
.mxObject
.get().get() );
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
;
716 // Switch to next view mode.
719 if (maPosition
.mePageKind
== PageKind::Handout
)
722 bSetToOnePastLastPage
= true;
724 else if (maPosition
.mePageKind
== PageKind::Standard
)
726 // switch to master notes
727 maPosition
.mePageKind
= PageKind::Notes
;
730 else if (maPosition
.mePageKind
== PageKind::Notes
)
732 // switch to master handout
733 maPosition
.mePageKind
= PageKind::Handout
;
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;
775 // Get new page count;
776 if (maPosition
.meEditMode
== EditMode::Page
)
777 mnPageCount
= mpDocument
->GetSdPageCount (maPosition
.mePageKind
);
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: */