diff options
Diffstat (limited to 'sd/source/ui/slidesorter/model/SlideSorterModel.cxx')
-rw-r--r-- | sd/source/ui/slidesorter/model/SlideSorterModel.cxx | 735 |
1 files changed, 735 insertions, 0 deletions
diff --git a/sd/source/ui/slidesorter/model/SlideSorterModel.cxx b/sd/source/ui/slidesorter/model/SlideSorterModel.cxx new file mode 100644 index 000000000000..5eaf64db7bf8 --- /dev/null +++ b/sd/source/ui/slidesorter/model/SlideSorterModel.cxx @@ -0,0 +1,735 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "model/SlideSorterModel.hxx" + +#include "SlideSorter.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsSlotManager.hxx" +#include "view/SlideSorterView.hxx" +#include "taskpane/SlideSorterCacheDisplay.hxx" +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/drawing/XMasterPagesSupplier.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> + +#include "ViewShellBase.hxx" +#include "DrawViewShell.hxx" +#include "DrawDocShell.hxx" +#include "drawdoc.hxx" +#include "sdpage.hxx" +#include "FrameView.hxx" + +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace sd { namespace slidesorter { namespace model { + +namespace { + class CompareToXDrawPage + { + public: + CompareToXDrawPage (const Reference<drawing::XDrawPage>& rxSlide) : mxSlide(rxSlide) {} + bool operator() (const SharedPageDescriptor& rpDescriptor) + { return rpDescriptor.get()!=NULL && rpDescriptor->GetXDrawPage()==mxSlide; } + private: + Reference<drawing::XDrawPage> mxSlide; + }; + + bool PrintModel (const SlideSorterModel& rModel) + { + for (sal_Int32 nIndex=0,nCount=rModel.GetPageCount(); nIndex<nCount; ++nIndex) + { + SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex)); + if (pDescriptor) + { + OSL_TRACE("%d %d %d %d %x", + nIndex, + pDescriptor->GetPageIndex(), + pDescriptor->GetVisualState().mnPageId, + FromCoreIndex(pDescriptor->GetPage()->GetPageNum()), + pDescriptor->GetPage()); + } + else + { + OSL_TRACE("%d", nIndex); + } + } + + return true; + } + bool CheckModel (const SlideSorterModel& rModel) + { + for (sal_Int32 nIndex=0,nCount=rModel.GetPageCount(); nIndex<nCount; ++nIndex) + { + SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex)); + if ( ! pDescriptor) + { + PrintModel(rModel); + OSL_ASSERT(pDescriptor); + return false; + } + if (nIndex != pDescriptor->GetPageIndex()) + { + PrintModel(rModel); + OSL_ASSERT(nIndex == pDescriptor->GetPageIndex()); + return false; + } + if (nIndex != pDescriptor->GetVisualState().mnPageId) + { + PrintModel(rModel); + OSL_ASSERT(nIndex == pDescriptor->GetVisualState().mnPageId); + return false; + } + } + + return true; + } +} + + + + +SlideSorterModel::SlideSorterModel (SlideSorter& rSlideSorter) + : maMutex(), + mrSlideSorter(rSlideSorter), + mxSlides(), + mePageKind(PK_STANDARD), + meEditMode(EM_PAGE), + maPageDescriptors(0) +{ +} + + + + +SlideSorterModel::~SlideSorterModel (void) +{ + ClearDescriptorList (); +} + + + + +void SlideSorterModel::Init (void) +{ +} + + + + +void SlideSorterModel::Dispose (void) +{ + ClearDescriptorList (); +} + + + + +SdDrawDocument* SlideSorterModel::GetDocument (void) +{ + if (mrSlideSorter.GetViewShellBase() != NULL) + return mrSlideSorter.GetViewShellBase()->GetDocument(); + else + return NULL; +} + + + + +bool SlideSorterModel::SetEditMode (EditMode eEditMode) +{ + bool bEditModeChanged = false; + if (meEditMode != eEditMode) + { + meEditMode = eEditMode; + UpdatePageList(); + ClearDescriptorList(); + bEditModeChanged = true; + } + return bEditModeChanged; +} + + + + +EditMode SlideSorterModel::GetEditMode (void) const +{ + return meEditMode; +} + + + + +PageKind SlideSorterModel::GetPageType (void) const +{ + return mePageKind; +} + + + + +sal_Int32 SlideSorterModel::GetPageCount (void) const +{ + return maPageDescriptors.size(); +} + + + + +SharedPageDescriptor SlideSorterModel::GetPageDescriptor ( + const sal_Int32 nPageIndex, + const bool bCreate) const +{ + ::osl::MutexGuard aGuard (maMutex); + + SharedPageDescriptor pDescriptor; + + if (nPageIndex>=0 && nPageIndex<GetPageCount()) + { + pDescriptor = maPageDescriptors[nPageIndex]; + if (pDescriptor == NULL && bCreate && mxSlides.is()) + { + SdPage* pPage = GetPage(nPageIndex); + pDescriptor.reset(new PageDescriptor ( + Reference<drawing::XDrawPage>(mxSlides->getByIndex(nPageIndex),UNO_QUERY), + pPage, + nPageIndex)); + maPageDescriptors[nPageIndex] = pDescriptor; + } + } + + return pDescriptor; +} + + + + +sal_Int32 SlideSorterModel::GetIndex (const Reference<drawing::XDrawPage>& rxSlide) const +{ + ::osl::MutexGuard aGuard (maMutex); + + // First try to guess the right index. + Reference<beans::XPropertySet> xSet (rxSlide, UNO_QUERY); + if (xSet.is()) + { + try + { + const Any aNumber (xSet->getPropertyValue(::rtl::OUString::createFromAscii("Number"))); + sal_Int16 nNumber (-1); + aNumber >>= nNumber; + nNumber -= 1; + SharedPageDescriptor pDescriptor (GetPageDescriptor(nNumber, false)); + if (pDescriptor.get() != NULL + && pDescriptor->GetXDrawPage() == rxSlide) + { + return nNumber; + } + } + catch (uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + // Guess was wrong, iterate over all slides and search for the right + // one. + const sal_Int32 nCount (maPageDescriptors.size()); + for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex) + { + SharedPageDescriptor pDescriptor (maPageDescriptors[nIndex]); + + // Make sure that the descriptor exists. Without it the given slide + // can not be found. + if (pDescriptor.get() == NULL) + { + // Call GetPageDescriptor() to create the missing descriptor. + pDescriptor = GetPageDescriptor(nIndex,true); + } + + if (pDescriptor->GetXDrawPage() == rxSlide) + return nIndex; + } + + return -1; +} + + + + +sal_Int32 SlideSorterModel::GetIndex (const SdrPage* pPage) const +{ + if (pPage == NULL) + return -1; + + ::osl::MutexGuard aGuard (maMutex); + + // First try to guess the right index. + sal_Int16 nNumber ((pPage->GetPageNum()-1)/2); + SharedPageDescriptor pDescriptor (GetPageDescriptor(nNumber, false)); + if (pDescriptor.get() != NULL + && pDescriptor->GetPage() == pPage) + { + return nNumber; + } + + // Guess was wrong, iterate over all slides and search for the right + // one. + const sal_Int32 nCount (maPageDescriptors.size()); + for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex) + { + pDescriptor = maPageDescriptors[nIndex]; + + // Make sure that the descriptor exists. Without it the given slide + // can not be found. + if (pDescriptor.get() == NULL) + { + // Call GetPageDescriptor() to create the missing descriptor. + pDescriptor = GetPageDescriptor(nIndex, true); + } + + if (pDescriptor->GetPage() == pPage) + return nIndex; + } + + return -1; +} + + + + +USHORT SlideSorterModel::GetCoreIndex (const sal_Int32 nIndex) const +{ + SharedPageDescriptor pDescriptor (GetPageDescriptor(nIndex)); + if (pDescriptor) + return pDescriptor->GetPage()->GetPageNum(); + else + return mxSlides->getCount()*2+1; +} + + + + +/** For now this method uses a trivial algorithm: throw away all descriptors + and create them anew (on demand). The main problem that we are facing + when designing a better algorithm is that we can not compare pointers to + pages stored in the PageDescriptor objects and those obtained from the + document: pages may have been deleted and others may have been created + at the exact same memory locations. +*/ +void SlideSorterModel::Resync (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + // Check if document and this model really differ. + bool bIsUpToDate (true); + SdDrawDocument* pDocument = GetDocument(); + if (pDocument!=NULL && maPageDescriptors.size()==pDocument->GetSdPageCount(mePageKind)) + { + for (sal_Int32 nIndex=0,nCount=maPageDescriptors.size(); nIndex<nCount; ++nIndex) + { + if (maPageDescriptors[nIndex] + && maPageDescriptors[nIndex]->GetPage() + != GetPage(nIndex)) + { + OSL_TRACE("page %d differs\n", nIndex); + bIsUpToDate = false; + break; + } + } + } + else + { + bIsUpToDate = false; + OSL_TRACE("models differ"); + } + + if ( ! bIsUpToDate) + { + SynchronizeDocumentSelection(); // Try to make the current selection persistent. + ClearDescriptorList (); + AdaptSize(); + SynchronizeModelSelection(); + mrSlideSorter.GetController().GetPageSelector().CountSelectedPages(); + } + CheckModel(*this); +} + + + + +void SlideSorterModel::ClearDescriptorList (void) +{ + DescriptorContainer aDescriptors; + + { + ::osl::MutexGuard aGuard (maMutex); + aDescriptors.swap(maPageDescriptors); + } + + for (DescriptorContainer::iterator iDescriptor=aDescriptors.begin(), iEnd=aDescriptors.end(); + iDescriptor!=iEnd; + ++iDescriptor) + { + if (iDescriptor->get() != NULL) + { + if ( ! iDescriptor->unique()) + { + OSL_TRACE("SlideSorterModel::ClearDescriptorList: trying to delete page descriptor that is still used with count %d", iDescriptor->use_count()); + // No assertion here because that can hang the office when + // opening a dialog from here. + } + iDescriptor->reset(); + } + } +} + + + + +void SlideSorterModel::SynchronizeDocumentSelection (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); + while (aAllPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + pDescriptor->GetPage()->SetSelected(pDescriptor->HasState(PageDescriptor::ST_Selected)); + } +} + + + + +void SlideSorterModel::SynchronizeModelSelection (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); + while (aAllPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + pDescriptor->SetState(PageDescriptor::ST_Selected, pDescriptor->GetPage()->IsSelected()); + } +} + + + + +::osl::Mutex& SlideSorterModel::GetMutex (void) +{ + return maMutex; +} + + + + +void SlideSorterModel::SetDocumentSlides ( + const Reference<container::XIndexAccess>& rxSlides) +{ + ::osl::MutexGuard aGuard (maMutex); + + // Reset the current page so to cause everbody to release references to it. + mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(-1); + + mxSlides = rxSlides; + Resync(); + + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell != NULL) + { + SdPage* pPage = pViewShell->getCurrentPage(); + if (pPage != NULL) + mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange( + pPage); + else + { + // No current page. This can only be when the slide sorter is + // the main view shell. Get current slide form frame view. + const FrameView* pFrameView = pViewShell->GetFrameView(); + if (pFrameView != NULL) + mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange( + pFrameView->GetSelectedPage()); + else + { + // No frame view. As a last resort use the first slide as + // current slide. + mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange( + sal_Int32(0)); + } + } + } + + mrSlideSorter.GetController().GetSlotManager()->NotifyEditModeChange(); +} + + + + +Reference<container::XIndexAccess> SlideSorterModel::GetDocumentSlides (void) const +{ + ::osl::MutexGuard aGuard (maMutex); + return mxSlides; +} + + + + +void SlideSorterModel::UpdatePageList (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + Reference<container::XIndexAccess> xPages; + + // Get the list of pages according to the edit mode. + Reference<frame::XController> xController (mrSlideSorter.GetXController()); + if (xController.is()) + { + switch (meEditMode) + { + case EM_MASTERPAGE: + { + Reference<drawing::XMasterPagesSupplier> xSupplier ( + xController->getModel(), UNO_QUERY); + if (xSupplier.is()) + { + xPages = Reference<container::XIndexAccess>( + xSupplier->getMasterPages(), UNO_QUERY); + } + } + break; + + case EM_PAGE: + { + Reference<drawing::XDrawPagesSupplier> xSupplier ( + xController->getModel(), UNO_QUERY); + if (xSupplier.is()) + { + xPages = Reference<container::XIndexAccess>( + xSupplier->getDrawPages(), UNO_QUERY); + } + } + break; + + default: + // We should never get here. + OSL_ASSERT(false); + break; + } + } + + mrSlideSorter.GetController().SetDocumentSlides(xPages); +} + + + + +void SlideSorterModel::AdaptSize (void) +{ + if (mxSlides.is()) + maPageDescriptors.resize(mxSlides->getCount()); + else + maPageDescriptors.resize(0); +} + + + + +bool SlideSorterModel::IsReadOnly (void) const +{ + if (mrSlideSorter.GetViewShellBase() != NULL + && mrSlideSorter.GetViewShellBase()->GetDocShell()) + return mrSlideSorter.GetViewShellBase()->GetDocShell()->IsReadOnly(); + else + return true; +} + + + + +void SlideSorterModel::SaveCurrentSelection (void) +{ + PageEnumeration aPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); + while (aPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aPages.GetNextElement()); + pDescriptor->SetState( + PageDescriptor::ST_WasSelected, + pDescriptor->HasState(PageDescriptor::ST_Selected)); + } +} + + + + +Region SlideSorterModel::RestoreSelection (void) +{ + Region aRepaintRegion; + PageEnumeration aPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); + while (aPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aPages.GetNextElement()); + if (pDescriptor->SetState( + PageDescriptor::ST_Selected, + pDescriptor->HasState(PageDescriptor::ST_WasSelected))) + { + aRepaintRegion.Union(pDescriptor->GetBoundingBox()); + } + } + return aRepaintRegion; +} + + + + +bool SlideSorterModel::NotifyPageEvent (const SdrPage* pSdrPage) +{ + ::osl::MutexGuard aGuard (maMutex); + + SdPage* pPage = const_cast<SdPage*>(dynamic_cast<const SdPage*>(pSdrPage)); + if (pPage == NULL) + return false; + + // We are only interested in pages that are currently served by this + // model. + if (pPage->GetPageKind() != mePageKind) + return false; + if (pPage->IsMasterPage() != (meEditMode==EM_MASTERPAGE)) + return false; + + if (pPage->IsInserted()) + InsertSlide(pPage); + else + DeleteSlide(pPage); + CheckModel(*this); + + return true; +} + + + + +void SlideSorterModel::InsertSlide (SdPage* pPage) +{ + // Find the index at which to insert the given page. + USHORT nCoreIndex (pPage->GetPageNum()); + sal_Int32 nIndex (FromCoreIndex(nCoreIndex)); + if (pPage != GetPage(nIndex)) + return; + + // Check that the pages in the document before and after the given page + // are present in this model. + if (nIndex>0) + if (GetPage(nIndex-1) != GetPageDescriptor(nIndex-1)->GetPage()) + return; + if (size_t(nIndex)<maPageDescriptors.size()-1) + if (GetPage(nIndex+1) != GetPageDescriptor(nIndex)->GetPage()) + return; + + // Insert the given page at index nIndex + maPageDescriptors.insert( + maPageDescriptors.begin()+nIndex, + SharedPageDescriptor( + new PageDescriptor ( + Reference<drawing::XDrawPage>(mxSlides->getByIndex(nIndex),UNO_QUERY), + pPage, + nIndex))); + + // Update page indices. + UpdateIndices(nIndex+1); + OSL_TRACE("page inserted"); +} + + + + +void SlideSorterModel::DeleteSlide (const SdPage* pPage) +{ + const sal_Int32 nIndex (GetIndex(pPage)); + if (maPageDescriptors[nIndex]) + if (maPageDescriptors[nIndex]->GetPage() != pPage) + return; + + maPageDescriptors.erase(maPageDescriptors.begin()+nIndex); + UpdateIndices(nIndex); + OSL_TRACE("page removed"); +} + + + + +void SlideSorterModel::UpdateIndices (const sal_Int32 nFirstIndex) +{ + for (sal_Int32 nDescriptorIndex=0,nCount=maPageDescriptors.size(); + nDescriptorIndex<nCount; + ++nDescriptorIndex) + { + SharedPageDescriptor& rpDescriptor (maPageDescriptors[nDescriptorIndex]); + if (rpDescriptor) + if (nDescriptorIndex < nFirstIndex) + { + if (rpDescriptor->GetPageIndex()!=nDescriptorIndex) + { + OSL_ASSERT(rpDescriptor->GetPageIndex()==nDescriptorIndex); + } + } + else + { + rpDescriptor->SetPageIndex(nDescriptorIndex); + } + } +} + + + + +SdPage* SlideSorterModel::GetPage (const sal_Int32 nSdIndex) const +{ + SdDrawDocument* pModel = const_cast<SlideSorterModel*>(this)->GetDocument(); + if (pModel != NULL) + { + if (meEditMode == EM_PAGE) + return pModel->GetSdPage ((USHORT)nSdIndex, mePageKind); + else + return pModel->GetMasterSdPage ((USHORT)nSdIndex, mePageKind); + } + else + return NULL; +} + + +} } } // end of namespace ::sd::slidesorter::model |