bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / ui / slidesorter / model / SlideSorterModel.cxx
blobec35f545448b8888ec042f8510175d90985eb4a7
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 <sal/log.hxx>
24 #include <model/SlsPageDescriptor.hxx>
25 #include <model/SlsPageEnumerationProvider.hxx>
26 #include <controller/SlideSorterController.hxx>
27 #include <controller/SlsProperties.hxx>
28 #include <controller/SlsPageSelector.hxx>
29 #include <controller/SlsCurrentSlideManager.hxx>
30 #include <controller/SlsSlotManager.hxx>
31 #include <view/SlideSorterView.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>
36 #include <com/sun/star/frame/XController.hpp>
38 #include <ViewShellBase.hxx>
39 #include <DrawViewShell.hxx>
40 #include <DrawDocShell.hxx>
41 #include <drawdoc.hxx>
42 #include <sdpage.hxx>
43 #include <FrameView.hxx>
45 #include <tools/diagnose_ex.h>
47 using namespace ::com::sun::star;
48 using namespace ::com::sun::star::uno;
50 namespace sd { namespace slidesorter { namespace model {
52 namespace {
53 bool PrintModel (const SlideSorterModel& rModel)
55 for (sal_Int32 nIndex=0,nCount=rModel.GetPageCount(); nIndex<nCount; ++nIndex)
57 SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
58 if (pDescriptor)
60 SAL_INFO(
61 "sd.sls",
62 nIndex << " " << pDescriptor->GetPageIndex() << " "
63 << pDescriptor->GetVisualState().mnPageId << " "
64 << FromCoreIndex(pDescriptor->GetPage()->GetPageNum())
65 << " " << pDescriptor->GetPage());
67 else
69 SAL_INFO("sd.sls", nIndex);
73 return true;
75 bool CheckModel (const SlideSorterModel& rModel)
77 for (sal_Int32 nIndex=0,nCount=rModel.GetPageCount(); nIndex<nCount; ++nIndex)
79 SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
80 if ( ! pDescriptor)
82 PrintModel(rModel);
83 assert(pDescriptor);
84 return false;
86 if (nIndex != pDescriptor->GetPageIndex())
88 PrintModel(rModel);
89 assert(nIndex == pDescriptor->GetPageIndex());
90 return false;
92 if (nIndex != pDescriptor->GetVisualState().mnPageId)
94 PrintModel(rModel);
95 assert(nIndex == pDescriptor->GetVisualState().mnPageId);
96 return false;
100 return true;
104 SlideSorterModel::SlideSorterModel (SlideSorter& rSlideSorter)
105 : maMutex(),
106 mrSlideSorter(rSlideSorter),
107 mxSlides(),
108 meEditMode(EditMode::Page),
109 maPageDescriptors(0)
113 SlideSorterModel::~SlideSorterModel()
115 ClearDescriptorList ();
118 void SlideSorterModel::Dispose()
120 ClearDescriptorList ();
123 SdDrawDocument* SlideSorterModel::GetDocument()
125 if (mrSlideSorter.GetViewShellBase() != nullptr)
126 return mrSlideSorter.GetViewShellBase()->GetDocument();
127 else
128 return nullptr;
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 == nullptr && 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() != nullptr
189 && pDescriptor->GetXDrawPage() == rxSlide)
191 return nNumber;
194 catch (uno::Exception&)
196 DBG_UNHANDLED_EXCEPTION("sd");
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() == nullptr)
211 // Call GetPageDescriptor() to create the missing descriptor.
212 pDescriptor = GetPageDescriptor(nIndex);
215 if (pDescriptor->GetXDrawPage() == rxSlide)
216 return nIndex;
219 return -1;
222 sal_Int32 SlideSorterModel::GetIndex (const SdrPage* pPage) const
224 if (pPage == nullptr)
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() != nullptr
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() == nullptr)
249 // Call GetPageDescriptor() to create the missing descriptor.
250 pDescriptor = GetPageDescriptor(nIndex);
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!=nullptr && maPageDescriptors.size()==pDocument->GetSdPageCount(PageKind::Standard))
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;
302 if ( ! bIsUpToDate)
304 SynchronizeDocumentSelection(); // Try to make the current selection persistent.
305 ClearDescriptorList ();
306 AdaptSize();
307 SynchronizeModelSelection();
308 mrSlideSorter.GetController().GetPageSelector().CountSelectedPages();
310 CheckModel(*this);
313 void SlideSorterModel::ClearDescriptorList()
315 ::std::vector<SharedPageDescriptor> aDescriptors;
318 ::osl::MutexGuard aGuard (maMutex);
319 aDescriptors.swap(maPageDescriptors);
322 for (auto& rxDescriptor : aDescriptors)
324 if (rxDescriptor != nullptr)
326 if (rxDescriptor.use_count() > 1)
328 SAL_INFO(
329 "sd.sls",
330 "trying to delete page descriptor that is still used with"
331 " count " << rxDescriptor.use_count());
332 // No assertion here because that can hang the office when
333 // opening a dialog from here.
335 rxDescriptor.reset();
340 void SlideSorterModel::SynchronizeDocumentSelection()
342 ::osl::MutexGuard aGuard (maMutex);
344 PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
345 while (aAllPages.HasMoreElements())
347 SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
348 const bool bIsSelected (pDescriptor->HasState(PageDescriptor::ST_Selected));
349 pDescriptor->GetPage()->SetSelected(bIsSelected);
353 void SlideSorterModel::SynchronizeModelSelection()
355 ::osl::MutexGuard aGuard (maMutex);
357 PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
358 while (aAllPages.HasMoreElements())
360 SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
361 const bool bIsSelected (pDescriptor->GetPage()->IsSelected());
362 pDescriptor->SetState(PageDescriptor::ST_Selected, bIsSelected);
366 void SlideSorterModel::SetDocumentSlides (
367 const Reference<container::XIndexAccess>& rxSlides)
369 ::osl::MutexGuard aGuard (maMutex);
371 // Make the current selection persistent and then release the
372 // current set of pages.
373 SynchronizeDocumentSelection();
374 mxSlides = nullptr;
375 ClearDescriptorList ();
377 // Reset the current page to cause everybody to release references to it.
378 mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(-1);
380 // Set the new set of pages.
381 mxSlides = rxSlides;
382 AdaptSize();
383 SynchronizeModelSelection();
384 mrSlideSorter.GetController().GetPageSelector().CountSelectedPages();
386 model::PageEnumeration aSelectedPages (
387 model::PageEnumerationProvider::CreateSelectedPagesEnumeration(*this));
388 if (aSelectedPages.HasMoreElements())
390 SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
391 mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
392 pDescriptor->GetPage());
395 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
396 if (pViewShell != nullptr)
398 SdPage* pPage = pViewShell->getCurrentPage();
399 if (pPage != nullptr)
400 mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
401 pPage);
402 else
404 // No current page. This can only be when the slide sorter is
405 // the main view shell. Get current slide form frame view.
406 const FrameView* pFrameView = pViewShell->GetFrameView();
407 if (pFrameView != nullptr)
408 mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
409 pFrameView->GetSelectedPage());
410 else
412 // No frame view. As a last resort use the first slide as
413 // current slide.
414 mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
415 sal_Int32(0));
420 mrSlideSorter.GetController().GetSlotManager()->NotifyEditModeChange();
423 Reference<container::XIndexAccess> SlideSorterModel::GetDocumentSlides() const
425 ::osl::MutexGuard aGuard (maMutex);
426 return mxSlides;
429 void SlideSorterModel::UpdatePageList()
431 ::osl::MutexGuard aGuard (maMutex);
433 Reference<container::XIndexAccess> xPages;
435 // Get the list of pages according to the edit mode.
436 Reference<frame::XController> xController (mrSlideSorter.GetXController());
437 if (xController.is())
439 switch (meEditMode)
441 case EditMode::MasterPage:
443 Reference<drawing::XMasterPagesSupplier> xSupplier (
444 xController->getModel(), UNO_QUERY);
445 if (xSupplier.is())
447 xPages.set( xSupplier->getMasterPages(), UNO_QUERY);
450 break;
452 case EditMode::Page:
454 Reference<drawing::XDrawPagesSupplier> xSupplier (
455 xController->getModel(), UNO_QUERY);
456 if (xSupplier.is())
458 xPages.set( xSupplier->getDrawPages(), UNO_QUERY);
461 break;
463 default:
464 // We should never get here.
465 assert(false);
466 break;
470 mrSlideSorter.GetController().SetDocumentSlides(xPages);
473 void SlideSorterModel::AdaptSize()
475 if (mxSlides.is())
476 maPageDescriptors.resize(mxSlides->getCount());
477 else
478 maPageDescriptors.resize(0);
481 bool SlideSorterModel::IsReadOnly() const
483 if (mrSlideSorter.GetViewShellBase() != nullptr
484 && mrSlideSorter.GetViewShellBase()->GetDocShell())
485 return mrSlideSorter.GetViewShellBase()->GetDocShell()->IsReadOnly();
486 else
487 return true;
490 void SlideSorterModel::SaveCurrentSelection()
492 PageEnumeration aPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
493 while (aPages.HasMoreElements())
495 SharedPageDescriptor pDescriptor (aPages.GetNextElement());
496 pDescriptor->SetState(
497 PageDescriptor::ST_WasSelected,
498 pDescriptor->HasState(PageDescriptor::ST_Selected));
502 vcl::Region SlideSorterModel::RestoreSelection()
504 vcl::Region aRepaintRegion;
505 PageEnumeration aPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
506 while (aPages.HasMoreElements())
508 SharedPageDescriptor pDescriptor (aPages.GetNextElement());
509 if (pDescriptor->SetState(
510 PageDescriptor::ST_Selected,
511 pDescriptor->HasState(PageDescriptor::ST_WasSelected)))
513 aRepaintRegion.Union(pDescriptor->GetBoundingBox());
516 return aRepaintRegion;
519 bool SlideSorterModel::NotifyPageEvent (const SdrPage* pSdrPage)
521 ::osl::MutexGuard aGuard (maMutex);
523 SdPage* pPage = const_cast<SdPage*>(dynamic_cast<const SdPage*>(pSdrPage));
524 if (pPage == nullptr)
525 return false;
527 // We are only interested in pages that are currently served by this
528 // model.
529 if (pPage->GetPageKind() != PageKind::Standard)
530 return false;
531 if (pPage->IsMasterPage() != (meEditMode==EditMode::MasterPage))
532 return false;
534 //NotifyPageEvent is called for add, remove, *and* change position so for
535 //the change position case we must ensure we don't end up with the slide
536 //duplicated in our list
537 bool bSelected = DeleteSlide(pPage);
538 if (pPage->IsInserted())
540 InsertSlide(pPage, bSelected);
542 CheckModel(*this);
544 return true;
547 void SlideSorterModel::InsertSlide(SdPage* pPage, bool bMarkSelected)
549 // Find the index at which to insert the given page.
550 sal_uInt16 nCoreIndex (pPage->GetPageNum());
551 sal_Int32 nIndex (FromCoreIndex(nCoreIndex));
552 if (pPage != GetPage(nIndex))
553 return;
555 // Check that the pages in the document before and after the given page
556 // are present in this model.
557 if (nIndex>0)
558 if (GetPage(nIndex-1) != GetPageDescriptor(nIndex-1)->GetPage())
559 return;
560 if (nIndex < static_cast<sal_Int32>(maPageDescriptors.size()) -1)
561 if (GetPage(nIndex+1) != GetPageDescriptor(nIndex)->GetPage())
562 return;
564 auto iter = maPageDescriptors.begin() + nIndex;
566 // Insert the given page at index nIndex
567 iter = maPageDescriptors.insert(
568 iter,
569 std::make_shared<PageDescriptor>(
570 Reference<drawing::XDrawPage>(mxSlides->getByIndex(nIndex),UNO_QUERY),
571 pPage,
572 nIndex));
574 if (bMarkSelected)
575 (*iter)->SetState(PageDescriptor::ST_Selected, true);
577 // Update page indices.
578 UpdateIndices(nIndex+1);
581 bool SlideSorterModel::DeleteSlide (const SdPage* pPage)
583 sal_Int32 nIndex(0);
585 // Caution, GetIndex() may be negative since it uses GetPageNumber()-1
586 // for calculation, so do this only when page is inserted, else the
587 // GetPageNumber() will be zero and thus GetIndex() == -1
588 if(pPage->IsInserted())
590 nIndex = GetIndex(pPage);
592 else
594 // if not inserted, search for page
595 for(; nIndex < static_cast<sal_Int32>(maPageDescriptors.size()); nIndex++)
597 if(maPageDescriptors[nIndex]->GetPage() == pPage)
599 break;
604 bool bMarkedSelected(false);
606 if(nIndex >= 0 && nIndex < static_cast<sal_Int32>(maPageDescriptors.size()))
608 if (maPageDescriptors[nIndex])
609 if (maPageDescriptors[nIndex]->GetPage() != pPage)
610 return false;
612 auto iter = maPageDescriptors.begin() + nIndex;
613 bMarkedSelected = (*iter)->HasState(PageDescriptor::ST_Selected);
614 maPageDescriptors.erase(iter);
615 UpdateIndices(nIndex);
618 return bMarkedSelected;
621 void SlideSorterModel::UpdateIndices (const sal_Int32 nFirstIndex)
623 for (sal_Int32 nDescriptorIndex=0,nCount=maPageDescriptors.size();
624 nDescriptorIndex<nCount;
625 ++nDescriptorIndex)
627 SharedPageDescriptor& rpDescriptor (maPageDescriptors[nDescriptorIndex]);
628 if (rpDescriptor)
630 if (nDescriptorIndex < nFirstIndex)
632 if (rpDescriptor->GetPageIndex()!=nDescriptorIndex)
634 assert(rpDescriptor->GetPageIndex()==nDescriptorIndex);
637 else
639 rpDescriptor->SetPageIndex(nDescriptorIndex);
645 SdPage* SlideSorterModel::GetPage (const sal_Int32 nSdIndex) const
647 SdDrawDocument* pModel = const_cast<SlideSorterModel*>(this)->GetDocument();
648 if (pModel != nullptr)
650 if (meEditMode == EditMode::Page)
651 return pModel->GetSdPage (static_cast<sal_uInt16>(nSdIndex), PageKind::Standard);
652 else
653 return pModel->GetMasterSdPage (static_cast<sal_uInt16>(nSdIndex), PageKind::Standard);
655 else
656 return nullptr;
659 } } } // end of namespace ::sd::slidesorter::model
661 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */