/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sd.hxx" #include "OutlinerIterator.hxx" #include "OutlinerIteratorImpl.hxx" #include #include #include #include "Outliner.hxx" #include "drawdoc.hxx" #include "DrawViewShell.hxx" #include "drawview.hxx" #include "sdpage.hxx" #ifndef SD_FRAME_VIEW #include "FrameView.hxx" #endif #include "DrawDocShell.hxx" #include "Window.hxx" namespace sd { namespace outliner { //===== IteratorPosition ====================================================== IteratorPosition::IteratorPosition (void) : mnText(0) , mnPageIndex(-1) , mePageKind(PK_STANDARD) , meEditMode(EM_PAGE) { } IteratorPosition::IteratorPosition (const IteratorPosition& aPosition) : mxObject(aPosition.mxObject) , mnText(aPosition.mnText) , mnPageIndex(aPosition.mnPageIndex) , mePageKind(aPosition.mePageKind) , meEditMode(aPosition.meEditMode) { } IteratorPosition::~IteratorPosition (void) { } IteratorPosition& IteratorPosition::operator= (const IteratorPosition& aPosition) { mxObject = aPosition.mxObject; mnText = aPosition.mnText; mnPageIndex = aPosition.mnPageIndex; mePageKind = aPosition.mePageKind; meEditMode = aPosition.meEditMode; return *this; } bool IteratorPosition::operator== (const IteratorPosition& aPosition) const { return mxObject.get() == aPosition.mxObject.get() && mnText == aPosition.mnText && mnPageIndex == aPosition.mnPageIndex && mePageKind == aPosition.mePageKind && meEditMode == aPosition.meEditMode; } //===== Iterator ============================================================== Iterator::Iterator (void) { mpIterator = NULL; } Iterator::Iterator (const Iterator& rIterator) { mpIterator = rIterator.mpIterator->Clone(); } Iterator::Iterator (IteratorImplBase* pObject) { mpIterator = pObject; } Iterator::~Iterator (void) { delete mpIterator; } Iterator& Iterator::operator= (const Iterator& rIterator) { if (this != &rIterator) { delete mpIterator; if (rIterator.mpIterator != NULL) mpIterator = rIterator.mpIterator->Clone(); else mpIterator = NULL; } return *this; } const IteratorPosition& Iterator::operator* () const { DBG_ASSERT (mpIterator!=NULL, "::sd::outliner::Iterator::operator* : missing implementation object"); return mpIterator->GetPosition(); } Iterator& Iterator::operator++ () { if (mpIterator!=NULL) mpIterator->GotoNextText(); return *this; } Iterator Iterator::operator++ (int) { Iterator aTmp (*this); if (mpIterator!=NULL) mpIterator->GotoNextText(); return aTmp; } bool Iterator::operator== (const Iterator& rIterator) { if (mpIterator == NULL || rIterator.mpIterator==NULL) return mpIterator == rIterator.mpIterator; else return *mpIterator == *rIterator.mpIterator; } bool Iterator::operator!= (const Iterator& rIterator) { return ! operator==(rIterator); } void Iterator::Reverse (void) { if (mpIterator != NULL) mpIterator->Reverse(); } //===== IteratorFactory ======================================================= OutlinerContainer::OutlinerContainer (Outliner* pOutliner) : mpOutliner(pOutliner) { } Iterator OutlinerContainer::begin (void) { return CreateIterator (BEGIN); } Iterator OutlinerContainer::end (void) { return CreateIterator (END); } Iterator OutlinerContainer::current (void) { return CreateIterator (CURRENT); } Iterator OutlinerContainer::CreateIterator (IteratorLocation aLocation) { // Decide on certain features of the outliner which kind of iterator to // use. if (mpOutliner->mbRestrictSearchToSelection) // There is a selection. Search only in this. return CreateSelectionIterator ( mpOutliner->maMarkListCopy, mpOutliner->mpDrawDocument, mpOutliner->mpViewShell, mpOutliner->mbDirectionIsForward, aLocation); else // Search in the whole document. return CreateDocumentIterator ( mpOutliner->mpDrawDocument, mpOutliner->mpViewShell, mpOutliner->mbDirectionIsForward, aLocation); } Iterator OutlinerContainer::CreateSelectionIterator ( const ::std::vector& rObjectList, SdDrawDocument* pDocument, const ::boost::shared_ptr& rpViewShell, bool bDirectionIsForward, IteratorLocation aLocation) { OSL_ASSERT(rpViewShell.get()); sal_Int32 nObjectIndex; if (bDirectionIsForward) switch (aLocation) { case CURRENT: case BEGIN: default: nObjectIndex = 0; break; case END: nObjectIndex = rObjectList.size(); break; } else switch (aLocation) { case CURRENT: case BEGIN: default: nObjectIndex = rObjectList.size()-1; break; case END: nObjectIndex = -1; break; } return Iterator (new SelectionIteratorImpl ( rObjectList, nObjectIndex, pDocument, rpViewShell, bDirectionIsForward)); } Iterator OutlinerContainer::CreateDocumentIterator ( SdDrawDocument* pDocument, const ::boost::shared_ptr& rpViewShell, bool bDirectionIsForward, IteratorLocation aLocation) { OSL_ASSERT(rpViewShell.get()); PageKind ePageKind; EditMode eEditMode; switch (aLocation) { case BEGIN: default: if (bDirectionIsForward) { ePageKind = PK_STANDARD; eEditMode = EM_PAGE; } else { ePageKind = PK_HANDOUT; eEditMode = EM_MASTERPAGE; } break; case END: if (bDirectionIsForward) { ePageKind = PK_HANDOUT; eEditMode = EM_MASTERPAGE; } else { ePageKind = PK_STANDARD; eEditMode = EM_PAGE; } break; case CURRENT: const ::boost::shared_ptr pDrawViewShell( ::boost::dynamic_pointer_cast(rpViewShell)); if (pDrawViewShell.get()) { ePageKind = pDrawViewShell->GetPageKind(); eEditMode = pDrawViewShell->GetEditMode(); } else { ePageKind = PK_STANDARD; eEditMode = EM_PAGE; } break; } sal_Int32 nPageIndex = GetPageIndex (pDocument, rpViewShell, ePageKind, eEditMode, bDirectionIsForward, aLocation); return Iterator ( new DocumentIteratorImpl (nPageIndex, ePageKind, eEditMode, pDocument, rpViewShell, bDirectionIsForward)); } sal_Int32 OutlinerContainer::GetPageIndex ( SdDrawDocument* pDocument, const ::boost::shared_ptr& rpViewShell, PageKind ePageKind, EditMode eEditMode, bool bDirectionIsForward, IteratorLocation aLocation) { OSL_ASSERT(rpViewShell); sal_Int32 nPageIndex; sal_Int32 nPageCount; const ::boost::shared_ptr pDrawViewShell( ::boost::dynamic_pointer_cast(rpViewShell)); switch (eEditMode) { case EM_PAGE: nPageCount = pDocument->GetSdPageCount (ePageKind); break; case EM_MASTERPAGE: nPageCount = pDocument->GetMasterSdPageCount(ePageKind); break; default: nPageCount = 0; } switch (aLocation) { case CURRENT: if (pDrawViewShell.get()) nPageIndex = pDrawViewShell->GetCurPageId() - 1; else { const SdPage* pPage = rpViewShell->GetActualPage(); if (pPage != NULL) nPageIndex = (pPage->GetPageNum()-1)/2; else nPageIndex = 0; } break; case BEGIN: default: if (bDirectionIsForward) nPageIndex = 0; else nPageIndex = nPageCount-1; break; case END: if (bDirectionIsForward) nPageIndex = nPageCount; else nPageIndex = -1; break; } return nPageIndex; } //===== IteratorImplBase ==================================================== IteratorImplBase::IteratorImplBase(SdDrawDocument* pDocument, const ::boost::weak_ptr& rpViewShellWeak, bool bDirectionIsForward) : maPosition() , mpDocument (pDocument) , mpViewShellWeak (rpViewShellWeak) , mbDirectionIsForward (bDirectionIsForward) { ::boost::shared_ptr pDrawViewShell; if ( ! mpViewShellWeak.expired()) pDrawViewShell = ::boost::dynamic_pointer_cast(rpViewShellWeak.lock()); if (pDrawViewShell.get()) { maPosition.mePageKind = pDrawViewShell->GetPageKind(); maPosition.meEditMode = pDrawViewShell->GetEditMode(); } else { maPosition.mePageKind = PK_STANDARD; maPosition.meEditMode = EM_PAGE; } } IteratorImplBase::IteratorImplBase( SdDrawDocument* pDocument, const ::boost::weak_ptr& rpViewShellWeak, bool bDirectionIsForward, PageKind ePageKind, EditMode eEditMode) : maPosition() , mpDocument (pDocument) , mpViewShellWeak (rpViewShellWeak) , mbDirectionIsForward (bDirectionIsForward) { maPosition.mePageKind = ePageKind; maPosition.meEditMode = eEditMode; } IteratorImplBase::~IteratorImplBase (void) {} bool IteratorImplBase::operator== (const IteratorImplBase& rIterator) const { return maPosition == rIterator.maPosition; } bool IteratorImplBase::IsEqual (const IteratorImplBase& rIterator, IteratorType ) const { // When this method is executed instead of the ones from derived classes // then the argument is of another type then the object itself. In this // just compare the position objects. return maPosition == rIterator.maPosition; } const IteratorPosition& IteratorImplBase::GetPosition (void) { return maPosition; } IteratorImplBase* IteratorImplBase::Clone (IteratorImplBase* pObject) const { if (pObject != NULL) { pObject->maPosition = maPosition; pObject->mpDocument = mpDocument; pObject->mpViewShellWeak = mpViewShellWeak; pObject->mbDirectionIsForward = mbDirectionIsForward; } return pObject; } void IteratorImplBase::Reverse (void) { mbDirectionIsForward = ! mbDirectionIsForward; } //===== SelectionIteratorImpl =========================================== SelectionIteratorImpl::SelectionIteratorImpl ( const ::std::vector& rObjectList, sal_Int32 nObjectIndex, SdDrawDocument* pDocument, const ::boost::weak_ptr& rpViewShellWeak, bool bDirectionIsForward) : IteratorImplBase (pDocument, rpViewShellWeak, bDirectionIsForward), mrObjectList(rObjectList), mnObjectIndex(nObjectIndex) { } SelectionIteratorImpl::~SelectionIteratorImpl (void) {} IteratorImplBase* SelectionIteratorImpl::Clone (IteratorImplBase* pObject) const { SelectionIteratorImpl* pIterator = static_cast(pObject); if (pIterator == NULL) pIterator = new SelectionIteratorImpl ( mrObjectList, mnObjectIndex, mpDocument, mpViewShellWeak, mbDirectionIsForward); return pIterator; } void SelectionIteratorImpl::GotoNextText (void) { SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( mrObjectList.at(mnObjectIndex).get() ); if (mbDirectionIsForward) { if( pTextObj ) { ++maPosition.mnText; if( maPosition.mnText >= pTextObj->getTextCount() ) { maPosition.mnText = 0; ++mnObjectIndex; } } else { ++mnObjectIndex; } } else { if( pTextObj ) { --maPosition.mnText; if( maPosition.mnText < 0 ) { maPosition.mnText = -1; --mnObjectIndex; } } else { --mnObjectIndex; maPosition.mnText = -1; } if( (maPosition.mnText == -1) && (mnObjectIndex >= 0) ) { pTextObj = dynamic_cast< SdrTextObj* >( mrObjectList.at(mnObjectIndex).get() ); if( pTextObj ) maPosition.mnText = pTextObj->getTextCount() - 1; } if( maPosition.mnText == -1 ) maPosition.mnText = 0; } } const IteratorPosition& SelectionIteratorImpl::GetPosition (void) { maPosition.mxObject = mrObjectList.at(mnObjectIndex); return maPosition; } bool SelectionIteratorImpl::operator== (const IteratorImplBase& rIterator) const { return rIterator.IsEqual (*this, SELECTION); } bool SelectionIteratorImpl::IsEqual ( const IteratorImplBase& rIterator, IteratorType aType) const { if (aType == SELECTION) { const SelectionIteratorImpl* pSelectionIterator = static_cast(&rIterator); return mpDocument == pSelectionIterator->mpDocument && mnObjectIndex == pSelectionIterator->mnObjectIndex; } else return false; } //===== ViewIteratorImpl ================================================ ViewIteratorImpl::ViewIteratorImpl ( sal_Int32 nPageIndex, SdDrawDocument* pDocument, const ::boost::weak_ptr& rpViewShellWeak, bool bDirectionIsForward) : IteratorImplBase (pDocument, rpViewShellWeak, bDirectionIsForward), mbPageChangeOccured(false), mpPage(NULL), mpObjectIterator(NULL) { SetPage (nPageIndex); } ViewIteratorImpl::ViewIteratorImpl ( sal_Int32 nPageIndex, SdDrawDocument* pDocument, const ::boost::weak_ptr& rpViewShellWeak, bool bDirectionIsForward, PageKind ePageKind, EditMode eEditMode) : IteratorImplBase (pDocument, rpViewShellWeak, bDirectionIsForward, ePageKind, eEditMode), mbPageChangeOccured(false), mpPage(NULL), mpObjectIterator(NULL) { SetPage (nPageIndex); } ViewIteratorImpl::~ViewIteratorImpl (void) { } IteratorImplBase* ViewIteratorImpl::Clone (IteratorImplBase* pObject) const { ViewIteratorImpl* pIterator = static_cast(pObject); if (pIterator == NULL) pIterator = new ViewIteratorImpl ( maPosition.mnPageIndex, mpDocument, mpViewShellWeak, mbDirectionIsForward); IteratorImplBase::Clone (pObject); if (mpObjectIterator != NULL) { pIterator->mpObjectIterator = new SdrObjListIter(*mpPage, IM_DEEPNOGROUPS, !mbDirectionIsForward); // No direct way to set the object iterator to the current object. pIterator->maPosition.mxObject.reset(NULL); while (pIterator->mpObjectIterator->IsMore() && pIterator->maPosition.mxObject!=maPosition.mxObject) pIterator->maPosition.mxObject.reset(pIterator->mpObjectIterator->Next()); } else pIterator->mpObjectIterator = NULL; return pIterator; } void ViewIteratorImpl::GotoNextText(void) { SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( maPosition.mxObject.get() ); if( pTextObj ) { if (mbDirectionIsForward) { ++maPosition.mnText; if( maPosition.mnText < pTextObj->getTextCount() ) return; } else { --maPosition.mnText; if( maPosition.mnText >= 0 ) return; } } if (mpObjectIterator != NULL && mpObjectIterator->IsMore()) maPosition.mxObject.reset(mpObjectIterator->Next()); else maPosition.mxObject.reset(NULL); if (!maPosition.mxObject.is() ) { if (mbDirectionIsForward) SetPage (maPosition.mnPageIndex+1); else SetPage (maPosition.mnPageIndex-1); if (mpPage != NULL) mpObjectIterator = new SdrObjListIter(*mpPage, IM_DEEPNOGROUPS, !mbDirectionIsForward); if (mpObjectIterator!=NULL && mpObjectIterator->IsMore()) maPosition.mxObject.reset(mpObjectIterator->Next()); else maPosition.mxObject.reset(NULL); } maPosition.mnText = 0; if( !mbDirectionIsForward && maPosition.mxObject.is() ) { pTextObj = dynamic_cast< SdrTextObj* >( maPosition.mxObject.get() ); if( pTextObj ) maPosition.mnText = pTextObj->getTextCount() - 1; } } void ViewIteratorImpl::SetPage (sal_Int32 nPageIndex) { mbPageChangeOccured = (maPosition.mnPageIndex!=nPageIndex); if (mbPageChangeOccured) { maPosition.mnPageIndex = nPageIndex; sal_Int32 nPageCount; if (maPosition.meEditMode == EM_PAGE) nPageCount = mpDocument->GetSdPageCount(maPosition.mePageKind); else nPageCount = mpDocument->GetMasterSdPageCount( maPosition.mePageKind); // Get page pointer. Here we have three cases: regular pages, // master pages and invalid page indices. The later ones are not // errors but the effect of the iterator advancing to the next page // and going past the last one. This dropping of the rim at the far // side is detected here and has to be reacted to by the caller. if (nPageIndex>=0 && nPageIndex < nPageCount) { if (maPosition.meEditMode == EM_PAGE) mpPage = mpDocument->GetSdPage ( (sal_uInt16)nPageIndex, maPosition.mePageKind); else mpPage = mpDocument->GetMasterSdPage ( (sal_uInt16)nPageIndex, maPosition.mePageKind); } else mpPage = NULL; } // Set up object list iterator. if (mpPage != NULL) mpObjectIterator = new SdrObjListIter(*mpPage, IM_DEEPNOGROUPS, ! mbDirectionIsForward); else mpObjectIterator = NULL; // Get object pointer. if (mpObjectIterator!=NULL && mpObjectIterator->IsMore()) maPosition.mxObject.reset( mpObjectIterator->Next() ); else maPosition.mxObject.reset( NULL ); maPosition.mnText = 0; if( !mbDirectionIsForward && maPosition.mxObject.is() ) { SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( maPosition.mxObject.get() ); if( pTextObj ) maPosition.mnText = pTextObj->getTextCount() - 1; } } void ViewIteratorImpl::Reverse (void) { IteratorImplBase::Reverse (); // Create reversed object list iterator. if (mpObjectIterator != NULL) delete mpObjectIterator; if (mpPage != NULL) mpObjectIterator = new SdrObjListIter(*mpPage, IM_DEEPNOGROUPS, ! mbDirectionIsForward); else mpObjectIterator = NULL; // Move iterator to the current object. SdrObjectWeakRef xObject = maPosition.mxObject; maPosition.mxObject.reset(NULL); while (mpObjectIterator->IsMore() && maPosition.mxObject != xObject) maPosition.mxObject.reset(mpObjectIterator->Next()); } //===== DocumentIteratorImpl ============================================ DocumentIteratorImpl::DocumentIteratorImpl ( sal_Int32 nPageIndex, PageKind ePageKind, EditMode eEditMode, SdDrawDocument* pDocument, const ::boost::weak_ptr& rpViewShellWeak, bool bDirectionIsForward) : ViewIteratorImpl (nPageIndex, pDocument, rpViewShellWeak, bDirectionIsForward, ePageKind, eEditMode) { if (eEditMode == EM_PAGE) mnPageCount = pDocument->GetSdPageCount (ePageKind); else mnPageCount = pDocument->GetMasterSdPageCount(ePageKind); } DocumentIteratorImpl::~DocumentIteratorImpl (void) {} IteratorImplBase* DocumentIteratorImpl::Clone (IteratorImplBase* pObject) const { DocumentIteratorImpl* pIterator = static_cast(pObject); if (pIterator == NULL) pIterator = new DocumentIteratorImpl ( maPosition.mnPageIndex, maPosition.mePageKind, maPosition.meEditMode, mpDocument, mpViewShellWeak, mbDirectionIsForward); // Finish the cloning. return ViewIteratorImpl::Clone (pIterator); } void DocumentIteratorImpl::GotoNextText (void) { bool bSetToOnePastLastPage = false; bool bViewChanged = false; ViewIteratorImpl::GotoNextText(); if (mbDirectionIsForward) { if (maPosition.mnPageIndex >= mnPageCount) { // Switch to master page. if (maPosition.meEditMode == EM_PAGE) { maPosition.meEditMode = EM_MASTERPAGE; SetPage (0); } // Switch to next view mode. else { if (maPosition.mePageKind == PK_HANDOUT) // Not really necessary but makes things more clear. bSetToOnePastLastPage = true; else { maPosition.meEditMode = EM_PAGE; if (maPosition.mePageKind == PK_STANDARD) maPosition.mePageKind = PK_NOTES; else if (maPosition.mePageKind == PK_NOTES) maPosition.mePageKind = PK_HANDOUT; SetPage (0); } } bViewChanged = true; } } else if (maPosition.mnPageIndex < 0) { // Switch from master pages to draw pages. if (maPosition.meEditMode == EM_MASTERPAGE) { maPosition.meEditMode = EM_PAGE; bSetToOnePastLastPage = true; } // Switch to previous view mode. else { if (maPosition.mePageKind == PK_STANDARD) SetPage (-1); else { maPosition.meEditMode = EM_MASTERPAGE; if (maPosition.mePageKind == PK_HANDOUT) maPosition.mePageKind = PK_NOTES; else if (maPosition.mePageKind == PK_NOTES) maPosition.mePageKind = PK_STANDARD; bSetToOnePastLastPage = true; } } bViewChanged = true; } if (bViewChanged) { // Get new page count; sal_Int32 nPageCount; if (maPosition.meEditMode == EM_PAGE) nPageCount = mpDocument->GetSdPageCount (maPosition.mePageKind); else nPageCount = mpDocument->GetMasterSdPageCount(maPosition.mePageKind); // Now that we know the number of pages we can set the current page index. if (bSetToOnePastLastPage) SetPage (nPageCount); } } } } // end of namespace ::sd::outliner