bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / slidesorter / model / SlideSorterModel.cxx
blob9a02c88701961fbe67b007731ed98dcf1321c951
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 "model/SlideSorterModel.hxx"
22 #include "SlideSorter.hxx"
23 #include "model/SlsPageDescriptor.hxx"
24 #include "model/SlsPageEnumerationProvider.hxx"
25 #include "controller/SlideSorterController.hxx"
26 #include "controller/SlsProperties.hxx"
27 #include "controller/SlsPageSelector.hxx"
28 #include "controller/SlsCurrentSlideManager.hxx"
29 #include "controller/SlsSlotManager.hxx"
30 #include "view/SlideSorterView.hxx"
31 #include "taskpane/SlideSorterCacheDisplay.hxx"
32 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
33 #include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/beans/UnknownPropertyException.hpp>
37 #include "ViewShellBase.hxx"
38 #include "DrawViewShell.hxx"
39 #include "DrawDocShell.hxx"
40 #include "drawdoc.hxx"
41 #include "sdpage.hxx"
42 #include "FrameView.hxx"
44 #include <tools/diagnose_ex.h>
46 using namespace ::com::sun::star;
47 using namespace ::com::sun::star::uno;
49 namespace sd { namespace slidesorter { namespace model {
51 namespace {
52 bool PrintModel (const SlideSorterModel& rModel)
54 for (sal_Int32 nIndex=0,nCount=rModel.GetPageCount(); nIndex<nCount; ++nIndex)
56 SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
57 if (pDescriptor)
59 SAL_INFO(
60 "sd.sls",
61 nIndex << " " << pDescriptor->GetPageIndex() << " "
62 << pDescriptor->GetVisualState().mnPageId << " "
63 << FromCoreIndex(pDescriptor->GetPage()->GetPageNum())
64 << " " << pDescriptor->GetPage());
66 else
68 SAL_INFO("sd.sls", nIndex);
72 return true;
74 bool CheckModel (const SlideSorterModel& rModel)
76 for (sal_Int32 nIndex=0,nCount=rModel.GetPageCount(); nIndex<nCount; ++nIndex)
78 SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
79 if ( ! pDescriptor)
81 PrintModel(rModel);
82 OSL_ASSERT(pDescriptor);
83 return false;
85 if (nIndex != pDescriptor->GetPageIndex())
87 PrintModel(rModel);
88 OSL_ASSERT(nIndex == pDescriptor->GetPageIndex());
89 return false;
91 if (nIndex != pDescriptor->GetVisualState().mnPageId)
93 PrintModel(rModel);
94 OSL_ASSERT(nIndex == pDescriptor->GetVisualState().mnPageId);
95 return false;
99 return true;
103 SlideSorterModel::SlideSorterModel (SlideSorter& rSlideSorter)
104 : maMutex(),
105 mrSlideSorter(rSlideSorter),
106 mxSlides(),
107 mePageKind(PK_STANDARD),
108 meEditMode(EM_PAGE),
109 maPageDescriptors(0)
113 SlideSorterModel::~SlideSorterModel()
115 ClearDescriptorList ();
118 void SlideSorterModel::Dispose()
120 ClearDescriptorList ();
123 SdDrawDocument* SlideSorterModel::GetDocument()
125 if (mrSlideSorter.GetViewShellBase() != NULL)
126 return mrSlideSorter.GetViewShellBase()->GetDocument();
127 else
128 return NULL;
131 bool SlideSorterModel::SetEditMode (EditMode eEditMode)
133 bool bEditModeChanged = false;
134 if (meEditMode != eEditMode)
136 meEditMode = eEditMode;
137 UpdatePageList();
138 bEditModeChanged = true;
140 return bEditModeChanged;
143 sal_Int32 SlideSorterModel::GetPageCount() const
145 return maPageDescriptors.size();
148 SharedPageDescriptor SlideSorterModel::GetPageDescriptor (
149 const sal_Int32 nPageIndex,
150 const bool bCreate) const
152 ::osl::MutexGuard aGuard (maMutex);
154 SharedPageDescriptor pDescriptor;
156 if (nPageIndex>=0 && nPageIndex<GetPageCount())
158 pDescriptor = maPageDescriptors[nPageIndex];
159 if (pDescriptor == 0 && bCreate && mxSlides.is())
161 SdPage* pPage = GetPage(nPageIndex);
162 pDescriptor.reset(new PageDescriptor (
163 Reference<drawing::XDrawPage>(mxSlides->getByIndex(nPageIndex),UNO_QUERY),
164 pPage,
165 nPageIndex));
166 maPageDescriptors[nPageIndex] = pDescriptor;
170 return pDescriptor;
173 sal_Int32 SlideSorterModel::GetIndex (const Reference<drawing::XDrawPage>& rxSlide) const
175 ::osl::MutexGuard aGuard (maMutex);
177 // First try to guess the right index.
178 Reference<beans::XPropertySet> xSet (rxSlide, UNO_QUERY);
179 if (xSet.is())
183 const Any aNumber (xSet->getPropertyValue("Number"));
184 sal_Int16 nNumber (-1);
185 aNumber >>= nNumber;
186 nNumber -= 1;
187 SharedPageDescriptor pDescriptor (GetPageDescriptor(nNumber, false));
188 if (pDescriptor.get() != NULL
189 && pDescriptor->GetXDrawPage() == rxSlide)
191 return nNumber;
194 catch (uno::Exception&)
196 DBG_UNHANDLED_EXCEPTION();
200 // Guess was wrong, iterate over all slides and search for the right
201 // one.
202 const sal_Int32 nCount (maPageDescriptors.size());
203 for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
205 SharedPageDescriptor pDescriptor (maPageDescriptors[nIndex]);
207 // Make sure that the descriptor exists. Without it the given slide
208 // can not be found.
209 if (pDescriptor.get() == NULL)
211 // Call GetPageDescriptor() to create the missing descriptor.
212 pDescriptor = GetPageDescriptor(nIndex,true);
215 if (pDescriptor->GetXDrawPage() == rxSlide)
216 return nIndex;
219 return -1;
222 sal_Int32 SlideSorterModel::GetIndex (const SdrPage* pPage) const
224 if (pPage == NULL)
225 return -1;
227 ::osl::MutexGuard aGuard (maMutex);
229 // First try to guess the right index.
230 sal_Int16 nNumber ((pPage->GetPageNum()-1)/2);
231 SharedPageDescriptor pDescriptor (GetPageDescriptor(nNumber, false));
232 if (pDescriptor.get() != NULL
233 && pDescriptor->GetPage() == pPage)
235 return nNumber;
238 // Guess was wrong, iterate over all slides and search for the right
239 // one.
240 const sal_Int32 nCount (maPageDescriptors.size());
241 for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
243 pDescriptor = maPageDescriptors[nIndex];
245 // Make sure that the descriptor exists. Without it the given slide
246 // can not be found.
247 if (pDescriptor.get() == NULL)
249 // Call GetPageDescriptor() to create the missing descriptor.
250 pDescriptor = GetPageDescriptor(nIndex, true);
253 if (pDescriptor->GetPage() == pPage)
254 return nIndex;
257 return -1;
260 sal_uInt16 SlideSorterModel::GetCoreIndex (const sal_Int32 nIndex) const
262 SharedPageDescriptor pDescriptor (GetPageDescriptor(nIndex));
263 if (pDescriptor)
264 return pDescriptor->GetPage()->GetPageNum();
265 else
266 return mxSlides->getCount()*2+1;
269 /** For now this method uses a trivial algorithm: throw away all descriptors
270 and create them anew (on demand). The main problem that we are facing
271 when designing a better algorithm is that we can not compare pointers to
272 pages stored in the PageDescriptor objects and those obtained from the
273 document: pages may have been deleted and others may have been created
274 at the exact same memory locations.
276 void SlideSorterModel::Resync()
278 ::osl::MutexGuard aGuard (maMutex);
280 // Check if document and this model really differ.
281 bool bIsUpToDate (true);
282 SdDrawDocument* pDocument = GetDocument();
283 if (pDocument!=NULL && maPageDescriptors.size()==pDocument->GetSdPageCount(mePageKind))
285 for (sal_Int32 nIndex=0,nCount=maPageDescriptors.size(); nIndex<nCount; ++nIndex)
287 if (maPageDescriptors[nIndex]
288 && maPageDescriptors[nIndex]->GetPage()
289 != GetPage(nIndex))
291 SAL_INFO("sd.sls", "page " << nIndex << " differs");
292 bIsUpToDate = false;
293 break;
297 else
299 bIsUpToDate = false;
300 OSL_TRACE("models differ");
303 if ( ! bIsUpToDate)
305 SynchronizeDocumentSelection(); // Try to make the current selection persistent.
306 ClearDescriptorList ();
307 AdaptSize();
308 SynchronizeModelSelection();
309 mrSlideSorter.GetController().GetPageSelector().CountSelectedPages();
311 CheckModel(*this);
314 void SlideSorterModel::ClearDescriptorList()
316 DescriptorContainer aDescriptors;
319 ::osl::MutexGuard aGuard (maMutex);
320 aDescriptors.swap(maPageDescriptors);
323 for (DescriptorContainer::iterator iDescriptor=aDescriptors.begin(), iEnd=aDescriptors.end();
324 iDescriptor!=iEnd;
325 ++iDescriptor)
327 if (iDescriptor->get() != NULL)
329 if ( ! iDescriptor->unique())
331 SAL_INFO(
332 "sd.sls",
333 "trying to delete page descriptor that is still used with"
334 " count " << iDescriptor->use_count());
335 // No assertion here because that can hang the office when
336 // opening a dialog from here.
338 iDescriptor->reset();
343 void SlideSorterModel::SynchronizeDocumentSelection()
345 ::osl::MutexGuard aGuard (maMutex);
347 PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
348 while (aAllPages.HasMoreElements())
350 SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
351 const bool bIsSelected (pDescriptor->HasState(PageDescriptor::ST_Selected));
352 pDescriptor->GetPage()->SetSelected(bIsSelected);
356 void SlideSorterModel::SynchronizeModelSelection()
358 ::osl::MutexGuard aGuard (maMutex);
360 PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
361 while (aAllPages.HasMoreElements())
363 SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
364 const bool bIsSelected (pDescriptor->GetPage()->IsSelected());
365 pDescriptor->SetState(PageDescriptor::ST_Selected, bIsSelected);
369 void SlideSorterModel::SetDocumentSlides (
370 const Reference<container::XIndexAccess>& rxSlides)
372 ::osl::MutexGuard aGuard (maMutex);
374 // Make the current selection persistent and then release the
375 // current set of pages.
376 SynchronizeDocumentSelection();
377 mxSlides = NULL;
378 ClearDescriptorList ();
380 // Reset the current page to cause everbody to release references to it.
381 mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(-1);
383 // Set the new set of pages.
384 mxSlides = rxSlides;
385 AdaptSize();
386 SynchronizeModelSelection();
387 mrSlideSorter.GetController().GetPageSelector().CountSelectedPages();
389 model::PageEnumeration aSelectedPages (
390 model::PageEnumerationProvider::CreateSelectedPagesEnumeration(*this));
391 if (aSelectedPages.HasMoreElements())
393 SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
394 mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
395 pDescriptor->GetPage());
398 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
399 if (pViewShell != NULL)
401 SdPage* pPage = pViewShell->getCurrentPage();
402 if (pPage != NULL)
403 mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
404 pPage);
405 else
407 // No current page. This can only be when the slide sorter is
408 // the main view shell. Get current slide form frame view.
409 const FrameView* pFrameView = pViewShell->GetFrameView();
410 if (pFrameView != NULL)
411 mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
412 pFrameView->GetSelectedPage());
413 else
415 // No frame view. As a last resort use the first slide as
416 // current slide.
417 mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
418 sal_Int32(0));
423 mrSlideSorter.GetController().GetSlotManager()->NotifyEditModeChange();
426 Reference<container::XIndexAccess> SlideSorterModel::GetDocumentSlides() const
428 ::osl::MutexGuard aGuard (maMutex);
429 return mxSlides;
432 void SlideSorterModel::UpdatePageList()
434 ::osl::MutexGuard aGuard (maMutex);
436 Reference<container::XIndexAccess> xPages;
438 // Get the list of pages according to the edit mode.
439 Reference<frame::XController> xController (mrSlideSorter.GetXController());
440 if (xController.is())
442 switch (meEditMode)
444 case EM_MASTERPAGE:
446 Reference<drawing::XMasterPagesSupplier> xSupplier (
447 xController->getModel(), UNO_QUERY);
448 if (xSupplier.is())
450 xPages = Reference<container::XIndexAccess>(
451 xSupplier->getMasterPages(), UNO_QUERY);
454 break;
456 case EM_PAGE:
458 Reference<drawing::XDrawPagesSupplier> xSupplier (
459 xController->getModel(), UNO_QUERY);
460 if (xSupplier.is())
462 xPages = Reference<container::XIndexAccess>(
463 xSupplier->getDrawPages(), UNO_QUERY);
466 break;
468 default:
469 // We should never get here.
470 OSL_ASSERT(false);
471 break;
475 mrSlideSorter.GetController().SetDocumentSlides(xPages);
478 void SlideSorterModel::AdaptSize()
480 if (mxSlides.is())
481 maPageDescriptors.resize(mxSlides->getCount());
482 else
483 maPageDescriptors.resize(0);
486 bool SlideSorterModel::IsReadOnly() const
488 if (mrSlideSorter.GetViewShellBase() != NULL
489 && mrSlideSorter.GetViewShellBase()->GetDocShell())
490 return mrSlideSorter.GetViewShellBase()->GetDocShell()->IsReadOnly();
491 else
492 return true;
495 void SlideSorterModel::SaveCurrentSelection()
497 PageEnumeration aPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
498 while (aPages.HasMoreElements())
500 SharedPageDescriptor pDescriptor (aPages.GetNextElement());
501 pDescriptor->SetState(
502 PageDescriptor::ST_WasSelected,
503 pDescriptor->HasState(PageDescriptor::ST_Selected));
507 vcl::Region SlideSorterModel::RestoreSelection()
509 vcl::Region aRepaintRegion;
510 PageEnumeration aPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
511 while (aPages.HasMoreElements())
513 SharedPageDescriptor pDescriptor (aPages.GetNextElement());
514 if (pDescriptor->SetState(
515 PageDescriptor::ST_Selected,
516 pDescriptor->HasState(PageDescriptor::ST_WasSelected)))
518 aRepaintRegion.Union(pDescriptor->GetBoundingBox());
521 return aRepaintRegion;
524 bool SlideSorterModel::NotifyPageEvent (const SdrPage* pSdrPage)
526 ::osl::MutexGuard aGuard (maMutex);
528 SdPage* pPage = const_cast<SdPage*>(dynamic_cast<const SdPage*>(pSdrPage));
529 if (pPage == NULL)
530 return false;
532 // We are only interested in pages that are currently served by this
533 // model.
534 if (pPage->GetPageKind() != mePageKind)
535 return false;
536 if (pPage->IsMasterPage() != (meEditMode==EM_MASTERPAGE))
537 return false;
539 if (pPage->IsInserted())
540 InsertSlide(pPage);
541 else
542 DeleteSlide(pPage);
543 CheckModel(*this);
545 return true;
548 void SlideSorterModel::InsertSlide (SdPage* pPage)
550 // Find the index at which to insert the given page.
551 sal_uInt16 nCoreIndex (pPage->GetPageNum());
552 sal_Int32 nIndex (FromCoreIndex(nCoreIndex));
553 if (pPage != GetPage(nIndex))
554 return;
556 // Check that the pages in the document before and after the given page
557 // are present in this model.
558 if (nIndex>0)
559 if (GetPage(nIndex-1) != GetPageDescriptor(nIndex-1)->GetPage())
560 return;
561 if (size_t(nIndex)<maPageDescriptors.size()-1)
562 if (GetPage(nIndex+1) != GetPageDescriptor(nIndex)->GetPage())
563 return;
565 // Insert the given page at index nIndex
566 maPageDescriptors.insert(
567 maPageDescriptors.begin()+nIndex,
568 SharedPageDescriptor(
569 new PageDescriptor (
570 Reference<drawing::XDrawPage>(mxSlides->getByIndex(nIndex),UNO_QUERY),
571 pPage,
572 nIndex)));
574 // Update page indices.
575 UpdateIndices(nIndex+1);
578 void SlideSorterModel::DeleteSlide (const SdPage* pPage)
580 sal_Int32 nIndex(0);
582 // Caution, GetIndex() may be negative since it uses GetPageNumber()-1
583 // for calculation, so do this only when page is inserted, else the
584 // GetPageNumber() will be zero and thus GetIndex() == -1
585 if(pPage->IsInserted())
587 nIndex = GetIndex(pPage);
589 else
591 // if not inserted, search for page
592 for(; nIndex < static_cast<sal_Int32>(maPageDescriptors.size()); nIndex++)
594 if(maPageDescriptors[nIndex]->GetPage() == pPage)
596 break;
601 if(nIndex >= 0 && nIndex < static_cast<sal_Int32>(maPageDescriptors.size()))
603 if (maPageDescriptors[nIndex])
604 if (maPageDescriptors[nIndex]->GetPage() != pPage)
605 return;
607 maPageDescriptors.erase(maPageDescriptors.begin()+nIndex);
608 UpdateIndices(nIndex);
612 void SlideSorterModel::UpdateIndices (const sal_Int32 nFirstIndex)
614 for (sal_Int32 nDescriptorIndex=0,nCount=maPageDescriptors.size();
615 nDescriptorIndex<nCount;
616 ++nDescriptorIndex)
618 SharedPageDescriptor& rpDescriptor (maPageDescriptors[nDescriptorIndex]);
619 if (rpDescriptor)
621 if (nDescriptorIndex < nFirstIndex)
623 if (rpDescriptor->GetPageIndex()!=nDescriptorIndex)
625 OSL_ASSERT(rpDescriptor->GetPageIndex()==nDescriptorIndex);
628 else
630 rpDescriptor->SetPageIndex(nDescriptorIndex);
636 SdPage* SlideSorterModel::GetPage (const sal_Int32 nSdIndex) const
638 SdDrawDocument* pModel = const_cast<SlideSorterModel*>(this)->GetDocument();
639 if (pModel != NULL)
641 if (meEditMode == EM_PAGE)
642 return pModel->GetSdPage ((sal_uInt16)nSdIndex, mePageKind);
643 else
644 return pModel->GetMasterSdPage ((sal_uInt16)nSdIndex, mePageKind);
646 else
647 return NULL;
650 } } } // end of namespace ::sd::slidesorter::model
652 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */