| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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(); |
| 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( !bool(pDescriptor) && 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; |
| } |
| |
| |
| |
| |
| sal_uInt16 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()); |
| const bool bIsSelected (pDescriptor->HasState(PageDescriptor::ST_Selected)); |
| pDescriptor->GetPage()->SetSelected(bIsSelected); |
| } |
| } |
| |
| |
| |
| |
| void SlideSorterModel::SynchronizeModelSelection (void) |
| { |
| ::osl::MutexGuard aGuard (maMutex); |
| |
| PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); |
| while (aAllPages.HasMoreElements()) |
| { |
| SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); |
| const bool bIsSelected (pDescriptor->GetPage()->IsSelected()); |
| pDescriptor->SetState(PageDescriptor::ST_Selected, bIsSelected); |
| } |
| } |
| |
| |
| |
| |
| ::osl::Mutex& SlideSorterModel::GetMutex (void) |
| { |
| return maMutex; |
| } |
| |
| |
| |
| |
| void SlideSorterModel::SetDocumentSlides ( |
| const Reference<container::XIndexAccess>& rxSlides) |
| { |
| ::osl::MutexGuard aGuard (maMutex); |
| |
| // Make the current selection persistent and then release the |
| // current set of pages. |
| SynchronizeDocumentSelection(); |
| mxSlides = NULL; |
| ClearDescriptorList (); |
| |
| // Reset the current page to cause everbody to release references to it. |
| mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(-1); |
| |
| // Set the new set of pages. |
| mxSlides = rxSlides; |
| AdaptSize(); |
| SynchronizeModelSelection(); |
| mrSlideSorter.GetController().GetPageSelector().CountSelectedPages(); |
| |
| model::PageEnumeration aSelectedPages ( |
| model::PageEnumerationProvider::CreateSelectedPagesEnumeration(*this)); |
| if (aSelectedPages.HasMoreElements()) |
| { |
| SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); |
| mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange( |
| pDescriptor->GetPage()); |
| } |
| |
| 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. |
| sal_uInt16 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); |
| } |
| |
| |
| |
| |
| void SlideSorterModel::DeleteSlide (const SdPage* pPage) |
| { |
| sal_Int32 nIndex(0); |
| |
| // Caution, GetIndex() may be negative since it uses GetPageNumber()-1 |
| // for calculation, so do this only when page is inserted, else the |
| // GetPageNumber() will be zero and thus GetIndex() == -1 |
| if(pPage->IsInserted()) |
| { |
| nIndex = GetIndex(pPage); |
| } |
| else |
| { |
| // if not inserted, search for page |
| for(; nIndex < static_cast<sal_Int32>(maPageDescriptors.size()); nIndex++) |
| { |
| if(maPageDescriptors[nIndex]->GetPage() == pPage) |
| { |
| break; |
| } |
| } |
| } |
| |
| if(nIndex >= 0 && nIndex < static_cast<sal_Int32>(maPageDescriptors.size())) |
| { |
| if (maPageDescriptors[nIndex]) |
| if (maPageDescriptors[nIndex]->GetPage() != pPage) |
| return; |
| |
| maPageDescriptors.erase(maPageDescriptors.begin()+nIndex); |
| UpdateIndices(nIndex); |
| } |
| } |
| |
| |
| |
| |
| 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 ((sal_uInt16)nSdIndex, mePageKind); |
| else |
| return pModel->GetMasterSdPage ((sal_uInt16)nSdIndex, mePageKind); |
| } |
| else |
| return NULL; |
| } |
| |
| |
| } } } // end of namespace ::sd::slidesorter::model |