merge the formfield patch from ooo-build
[ooovba.git] / sd / source / ui / slidesorter / controller / SlsSelectionManager.cxx
blob2eac8b757780cba9c368360cdcdfd67e587ac1ee
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: SlsSelectionManager.cxx,v $
11 * $Revision: 1.4 $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************/
32 #include "precompiled_sd.hxx"
34 #include "controller/SlsSelectionManager.hxx"
36 #include "SlideSorter.hxx"
37 #include "SlsSelectionCommand.hxx"
38 #include "controller/SlideSorterController.hxx"
39 #include "controller/SlsAnimator.hxx"
40 #include "controller/SlsCurrentSlideManager.hxx"
41 #include "controller/SlsFocusManager.hxx"
42 #include "controller/SlsProperties.hxx"
43 #include "controller/SlsScrollBarManager.hxx"
44 #include "controller/SlsSlotManager.hxx"
45 #include "model/SlideSorterModel.hxx"
46 #include "model/SlsPageEnumerationProvider.hxx"
47 #include "model/SlsPageDescriptor.hxx"
48 #include "view/SlideSorterView.hxx"
49 #include "drawdoc.hxx"
50 #include "Window.hxx"
51 #include <svx/svxids.hrc>
52 #include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
53 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
55 #include "res_bmp.hrc"
56 #include "sdresid.hxx"
57 #include "strings.hrc"
58 #include "app.hrc"
59 #include "glob.hrc"
62 using namespace ::com::sun::star;
63 using namespace ::com::sun::star::drawing;
64 using namespace ::com::sun::star::uno;
65 using namespace ::sd::slidesorter::model;
66 using namespace ::sd::slidesorter::view;
67 using namespace ::sd::slidesorter::controller;
69 namespace sd { namespace slidesorter { namespace controller {
72 namespace {
73 class VerticalVisibleAreaScroller
75 public:
76 VerticalVisibleAreaScroller (SlideSorter& rSlideSorter,
77 const double nStart, const double nEnd);
78 void operator() (const double nValue);
79 private:
80 SlideSorter& mrSlideSorter;
81 double mnStart;
82 double mnEnd;
84 class HorizontalVisibleAreaScroller
86 public:
87 HorizontalVisibleAreaScroller (SlideSorter& rSlideSorter,
88 const double nStart, const double nEnd);
89 void operator() (const double nValue);
90 private:
91 SlideSorter& mrSlideSorter;
92 double mnStart;
93 double mnEnd;
100 SelectionManager::SelectionManager (SlideSorter& rSlideSorter)
101 : mrSlideSorter(rSlideSorter),
102 mrController(rSlideSorter.GetController()),
103 maSelectionBeforeSwitch(),
104 mbIsMakeSelectionVisiblePending(true)
111 SelectionManager::~SelectionManager (void)
118 void SelectionManager::DeleteSelectedPages (void)
120 SlideSorterController::ModelChangeLock aLock (mrController);
122 // Hide focus.
123 bool bIsFocusShowing = mrController.GetFocusManager().IsFocusShowing();
124 if (bIsFocusShowing)
125 mrController.GetFocusManager().ToggleFocus();
127 // Store pointers to all selected page descriptors. This is necessary
128 // because the pages get deselected when the first one is deleted.
129 model::PageEnumeration aPageEnumeration (
130 PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel()));
131 ::std::vector<SdPage*> aSelectedPages;
132 while (aPageEnumeration.HasMoreElements())
133 aSelectedPages.push_back (aPageEnumeration.GetNextElement()->GetPage());
135 // The actual deletion of the selected pages is done in one of two
136 // helper functions. They are specialized for normal respectively for
137 // master pages.
138 mrSlideSorter.GetView().BegUndo (SdResId(STR_UNDO_DELETEPAGES));
139 if (mrSlideSorter.GetModel().GetEditMode() == EM_PAGE)
140 DeleteSelectedNormalPages(aSelectedPages);
141 else
142 DeleteSelectedMasterPages(aSelectedPages);
143 mrSlideSorter.GetView().EndUndo ();
145 mrController.HandleModelChange();
146 aLock.Release();
148 // Show focus and move it to next valid location.
149 if (bIsFocusShowing)
150 mrController.GetFocusManager().ToggleFocus ();
151 mrController.GetFocusManager().MoveFocus (FocusManager::FMD_NONE);
157 void SelectionManager::DeleteSelectedNormalPages (const ::std::vector<SdPage*>& rSelectedPages)
159 // Prepare the deletion via the UNO API.
160 OSL_ASSERT(mrSlideSorter.GetModel().GetEditMode() == EM_PAGE);
164 Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier( mrSlideSorter.GetModel().GetDocument()->getUnoModel(), UNO_QUERY_THROW );
165 Reference<drawing::XDrawPages> xPages( xDrawPagesSupplier->getDrawPages(), UNO_QUERY_THROW );
167 // Iterate over all pages that where seleted when this method was called
168 // and delete the draw page the notes page. The iteration is done in
169 // reverse order so that when one slide is not deleted (to avoid an
170 // empty document) the remaining slide is the first one.
171 ::std::vector<SdPage*>::const_reverse_iterator aI;
172 for (aI=rSelectedPages.rbegin(); aI!=rSelectedPages.rend(); aI++)
174 // Do not delete the last slide in the document.
175 if (xPages->getCount() <= 1)
176 break;
178 USHORT nPage = ((*aI)->GetPageNum()-1) / 2;
180 Reference< XDrawPage > xPage( xPages->getByIndex( nPage ), UNO_QUERY_THROW );
181 xPages->remove(xPage);
184 catch( Exception& )
186 DBG_ERROR("SelectionManager::DeleteSelectedNormalPages(), exception caught!");
193 void SelectionManager::DeleteSelectedMasterPages (const ::std::vector<SdPage*>& rSelectedPages)
195 // Prepare the deletion via the UNO API.
196 OSL_ASSERT(mrSlideSorter.GetModel().GetEditMode() == EM_MASTERPAGE);
200 Reference<drawing::XMasterPagesSupplier> xDrawPagesSupplier( mrSlideSorter.GetModel().GetDocument()->getUnoModel(), UNO_QUERY_THROW );
201 Reference<drawing::XDrawPages> xPages( xDrawPagesSupplier->getMasterPages(), UNO_QUERY_THROW );
203 // Iterate over all pages that where seleted when this method was called
204 // and delete the draw page the notes page. The iteration is done in
205 // reverse order so that when one slide is not deleted (to avoid an
206 // empty document) the remaining slide is the first one.
207 ::std::vector<SdPage*>::const_reverse_iterator aI;
208 for (aI=rSelectedPages.rbegin(); aI!=rSelectedPages.rend(); aI++)
210 // Do not delete the last slide in the document.
211 if (xPages->getCount() <= 1)
212 break;
214 USHORT nPage = ((*aI)->GetPageNum()-1) / 2;
216 Reference< XDrawPage > xPage( xPages->getByIndex( nPage ), UNO_QUERY_THROW );
217 xPages->remove(xPage);
220 catch( Exception& )
222 DBG_ERROR("SelectionManager::DeleteSelectedMasterPages(), exception caught!");
229 bool SelectionManager::MoveSelectedPages (const sal_Int32 nTargetPageIndex)
231 bool bMoved (false);
232 PageSelector& rSelector (mrController.GetPageSelector());
234 mrSlideSorter.GetView().LockRedraw (TRUE);
235 SlideSorterController::ModelChangeLock aLock (mrController);
237 // Transfer selection of the slide sorter to the document.
238 mrSlideSorter.GetModel().SynchronizeDocumentSelection ();
240 // Detect how many pages lie between document start and insertion
241 // position.
242 sal_Int32 nPageCountBeforeTarget (0);
243 ::boost::shared_ptr<PageSelector::PageSelection> pSelection (rSelector.GetPageSelection());
244 PageSelector::PageSelection::const_iterator iSelectedPage (pSelection->begin());
245 PageSelector::PageSelection::const_iterator iSelectionEnd (pSelection->end());
246 for ( ; iSelectedPage!=iSelectionEnd; ++iSelectedPage)
248 if (*iSelectedPage==NULL)
249 continue;
250 if (((*iSelectedPage)->GetPageNum()-1)/2 <= nTargetPageIndex)
251 ++nPageCountBeforeTarget;
252 else
253 break;
256 // Prepare to select the moved pages.
257 SelectionCommand* pCommand = new SelectionCommand(
258 rSelector,mrController.GetCurrentSlideManager(),mrSlideSorter.GetModel());
259 sal_Int32 nSelectedPageCount (rSelector.GetSelectedPageCount());
260 for (sal_Int32 nOffset=0; nOffset<nSelectedPageCount; ++nOffset)
261 pCommand->AddSlide(sal::static_int_cast<USHORT>(
262 nTargetPageIndex + nOffset - nPageCountBeforeTarget + 1));
264 // At the moment we can not move master pages.
265 if (nTargetPageIndex>=0)
267 if (mrSlideSorter.GetModel().GetEditMode() == EM_PAGE)
268 bMoved = mrSlideSorter.GetModel().GetDocument()->MovePages(
269 sal::static_int_cast<sal_uInt16>(nTargetPageIndex));
271 if (bMoved)
272 mrController.GetSlotManager()->ExecuteCommandAsynchronously(
273 ::std::auto_ptr<controller::Command>(pCommand));
275 mrSlideSorter.GetView().LockRedraw (FALSE);
277 return bMoved;
283 void SelectionManager::SelectionHasChanged (const bool bMakeSelectionVisible)
285 if (bMakeSelectionVisible)
286 mbIsMakeSelectionVisiblePending = true;
288 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
289 if (pViewShell != NULL)
291 pViewShell->Invalidate (SID_EXPAND_PAGE);
292 pViewShell->Invalidate (SID_SUMMARY_PAGE);
293 pViewShell->Invalidate(SID_SHOW_SLIDE);
294 pViewShell->Invalidate(SID_HIDE_SLIDE);
295 pViewShell->Invalidate(SID_DELETE_PAGE);
296 pViewShell->Invalidate(SID_DELETE_MASTER_PAGE);
298 // StatusBar
299 pViewShell->Invalidate (SID_STATUS_PAGE);
300 pViewShell->Invalidate (SID_STATUS_LAYOUT);
302 OSL_ASSERT(mrController.GetCurrentSlideManager());
303 SharedPageDescriptor pDescriptor(mrController.GetCurrentSlideManager()->GetCurrentSlide());
304 if (pDescriptor.get() != NULL)
305 pViewShell->UpdatePreview(pDescriptor->GetPage());
307 // Tell the slection change listeners that the selection has changed.
308 ::std::vector<Link>::iterator iListener (maSelectionChangeListeners.begin());
309 ::std::vector<Link>::iterator iEnd (maSelectionChangeListeners.end());
310 for (; iListener!=iEnd; ++iListener)
312 iListener->Call(NULL);
315 // Reset the insertion position: until set again it is calculated from
316 // the current selection.
317 mnInsertionPosition = -1;
324 bool SelectionManager::IsMakeSelectionVisiblePending (void) const
326 return mbIsMakeSelectionVisiblePending;
332 /** We have to distinguish three cases: 1) the selection is empty, 2) the
333 selection fits completely into the visible area, 3) it does not.
334 1) The visible area is not modified.
335 2) When the selection fits completely into the visible area we have to
336 decide how to align it. It is done by scrolling it there and thus when
337 we scoll up the (towards the end of the document) the bottom of the
338 selection is aligned with the bottom of the window. When we scroll
339 down (towards the beginning of the document) the top of the selection is
340 aligned with the top of the window.
341 3) We have to decide what part of the selection to make visible. Here
342 we use the eSelectionHint and concentrate on either the first, the last,
343 or the most recently selected page. We then again apply the algorithm
344 of a).
347 Size SelectionManager::MakeSelectionVisible (const SelectionHint eSelectionHint)
349 ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow();
350 if (pWindow == NULL)
351 return Size(0,0);
353 mbIsMakeSelectionVisiblePending = false;
355 // Determine the descriptors of the first and last selected page and the
356 // bounding box that encloses their page objects.
357 model::SharedPageDescriptor pFirst;
358 model::SharedPageDescriptor pLast;
359 Rectangle aSelectionBox;
360 model::PageEnumeration aSelectedPages (
361 PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel()));
362 while (aSelectedPages.HasMoreElements())
364 model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
366 if (pFirst.get() == NULL)
367 pFirst = pDescriptor;
368 pLast = pDescriptor;
370 aSelectionBox.Union (mrSlideSorter.GetView().GetPageBoundingBox (
371 pDescriptor,
372 view::SlideSorterView::CS_MODEL,
373 view::SlideSorterView::BBT_INFO));
376 if (pFirst != NULL)
378 // Determine scroll direction and the position in model coordinates
379 // that will be aligned with the top/left or bottom/right window
380 // border.
381 if (DoesSelectionExceedVisibleArea(aSelectionBox))
383 // We can show only a part of the selection.
384 aSelectionBox = ResolveLargeSelection(pFirst,pLast, eSelectionHint);
387 return MakeRectangleVisible(aSelectionBox);
390 return Size(0,0);
396 Size SelectionManager::MakeRectangleVisible (const Rectangle& rBox)
398 ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow();
399 if (pWindow == NULL)
400 return Size(0,0);
402 Rectangle aVisibleArea (pWindow->PixelToLogic(
403 Rectangle(
404 Point(0,0),
405 pWindow->GetOutputSizePixel())));
407 if (mrSlideSorter.GetView().GetOrientation() == SlideSorterView::VERTICAL)
409 // Scroll the visible area to make aSelectionBox visible.
410 sal_Int32 nNewTop (aVisibleArea.Top());
411 if (mrSlideSorter.GetController().GetProperties()->IsCenterSelection())
413 nNewTop = rBox.Top() - (aVisibleArea.GetHeight() - rBox.GetHeight()) / 2;
415 else
417 if (rBox.Top() < aVisibleArea.Top())
418 nNewTop = rBox.Top();
419 else if (rBox.Bottom() > aVisibleArea.Bottom())
420 nNewTop = rBox.Bottom() - aVisibleArea.GetHeight();
421 // otherwise we do not modify the visible area.
424 // Make some corrections of the new visible area.
425 Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea());
426 if (nNewTop + aVisibleArea.GetHeight() > aModelArea.Bottom())
427 nNewTop = aModelArea.GetHeight() - aVisibleArea.GetHeight();
428 if (nNewTop < aModelArea.Top())
429 nNewTop = aModelArea.Top();
431 // Scroll.
432 if (nNewTop != aVisibleArea.Top())
434 mrController.GetAnimator()->AddAnimation(
435 VerticalVisibleAreaScroller(mrSlideSorter, aVisibleArea.Top(), nNewTop),
436 mrSlideSorter.GetController().GetProperties()->IsSmoothSelectionScrolling() ?
437 1000 : 0
441 return Size(0,aVisibleArea.Top() - nNewTop);
443 else
445 // Scroll the visible area to make aSelectionBox visible.
446 sal_Int32 nNewLeft (aVisibleArea.Left());
447 if (mrSlideSorter.GetController().GetProperties()->IsCenterSelection())
449 nNewLeft = rBox.Left() - (aVisibleArea.GetWidth() - rBox.GetWidth()) / 2;
451 else
453 if (rBox.Left() < aVisibleArea.Left())
454 nNewLeft = rBox.Left();
455 else if (rBox.Right() > aVisibleArea.Right())
456 nNewLeft = rBox.Right() - aVisibleArea.GetWidth();
457 // otherwise we do not modify the visible area.
460 // Make some corrections of the new visible area.
461 Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea());
462 if (nNewLeft + aVisibleArea.GetWidth() > aModelArea.Right())
463 nNewLeft = aModelArea.GetWidth() - aVisibleArea.GetWidth();
464 if (nNewLeft < aModelArea.Left())
465 nNewLeft = aModelArea.Left();
467 // Scroll.
468 if (nNewLeft != aVisibleArea.Left())
470 mrController.GetAnimator()->AddAnimation(
471 HorizontalVisibleAreaScroller(mrSlideSorter, aVisibleArea.Left(), nNewLeft),
472 mrSlideSorter.GetController().GetProperties()->IsSmoothSelectionScrolling() ?
473 1000 : 0
477 return Size(aVisibleArea.Left() - nNewLeft, 0);
484 void SelectionManager::AddSelectionChangeListener (const Link& rListener)
486 if (::std::find (
487 maSelectionChangeListeners.begin(),
488 maSelectionChangeListeners.end(),
489 rListener) == maSelectionChangeListeners.end())
491 maSelectionChangeListeners.push_back (rListener);
498 void SelectionManager::RemoveSelectionChangeListener(const Link&rListener)
500 maSelectionChangeListeners.erase (
501 ::std::find (
502 maSelectionChangeListeners.begin(),
503 maSelectionChangeListeners.end(),
504 rListener));
510 bool SelectionManager::DoesSelectionExceedVisibleArea (const Rectangle& rSelectionBox) const
512 ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow();
513 if (pWindow == NULL)
514 return true;
516 Rectangle aVisibleArea (pWindow->PixelToLogic(
517 Rectangle(
518 Point(0,0),
519 pWindow->GetOutputSizePixel())));
520 if (mrSlideSorter.GetView().GetOrientation() == SlideSorterView::VERTICAL)
521 return rSelectionBox.GetHeight() > aVisibleArea.GetHeight();
522 else
523 return rSelectionBox.GetWidth() > aVisibleArea.GetWidth();
529 Rectangle SelectionManager::ResolveLargeSelection (
530 const SharedPageDescriptor& rpFirst,
531 const SharedPageDescriptor& rpLast,
532 const SelectionHint eSelectionHint)
534 OSL_ASSERT(rpFirst.get()!=NULL);
535 OSL_ASSERT(rpLast.get()!=NULL);
537 // The mose recently selected page is assumed to lie in the range
538 // between first and last selected page. Therefore the bounding box is
539 // not modified.
540 model::SharedPageDescriptor pRecent (
541 mrController.GetPageSelector().GetMostRecentlySelectedPage());
543 // Get the bounding box of the page object on which to concentrate.
544 model::SharedPageDescriptor pRepresentative;
545 switch (eSelectionHint)
547 case SH_FIRST:
548 pRepresentative = rpFirst;
549 break;
551 case SH_LAST:
552 pRepresentative = rpLast;
553 break;
555 case SH_RECENT:
556 default:
557 if (pRecent.get() == NULL)
558 pRepresentative = rpFirst;
559 else
560 pRepresentative = pRecent;
561 break;
563 OSL_ASSERT(pRepresentative.get() != NULL);
565 return mrSlideSorter.GetView().GetPageBoundingBox (
566 pRepresentative,
567 view::SlideSorterView::CS_MODEL,
568 view::SlideSorterView::BBT_INFO);
574 sal_Int32 SelectionManager::GetInsertionPosition (void) const
576 sal_Int32 nInsertionPosition (mnInsertionPosition);
577 if (nInsertionPosition < 0)
579 model::PageEnumeration aSelectedPages
580 (model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
581 mrSlideSorter.GetModel()));
582 // Initialize (for the case of an empty selection) with the position
583 // at the end of the document.
584 nInsertionPosition = mrSlideSorter.GetModel().GetPageCount();
585 while (aSelectedPages.HasMoreElements())
587 const sal_Int32 nPosition (aSelectedPages.GetNextElement()->GetPage()->GetPageNum());
588 // Convert *2+1 index to straight index (n-1)/2 after the page
589 // (+1).
590 nInsertionPosition = (nPosition-1)/2 + 1;
594 return nInsertionPosition;
600 void SelectionManager::SetInsertionPosition (const sal_Int32 nInsertionPosition)
602 if (nInsertionPosition < 0)
603 mnInsertionPosition = -1;
604 else if (nInsertionPosition > mrSlideSorter.GetModel().GetPageCount())
606 // Assert but then ignore invalid values.
607 OSL_ASSERT(nInsertionPosition<=mrSlideSorter.GetModel().GetPageCount());
608 return;
610 else
611 mnInsertionPosition = nInsertionPosition;
617 //===== VerticalVisibleAreaScroller ===========================================
619 namespace {
621 VerticalVisibleAreaScroller::VerticalVisibleAreaScroller (
622 SlideSorter& rSlideSorter,
623 const double nStart,
624 const double nEnd)
625 : mrSlideSorter(rSlideSorter),
626 mnStart(nStart),
627 mnEnd(nEnd)
633 void VerticalVisibleAreaScroller::operator() (const double nValue)
635 mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
636 mrSlideSorter.GetController().GetScrollBarManager().SetTop(
637 int(mnStart * (1.0 - nValue) + mnEnd * nValue));
643 HorizontalVisibleAreaScroller::HorizontalVisibleAreaScroller (
644 SlideSorter& rSlideSorter,
645 const double nStart,
646 const double nEnd)
647 : mrSlideSorter(rSlideSorter),
648 mnStart(nStart),
649 mnEnd(nEnd)
656 void HorizontalVisibleAreaScroller::operator() (const double nValue)
658 mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
659 mrSlideSorter.GetController().GetScrollBarManager().SetLeft(
660 int(mnStart * (1.0 - nValue) + mnEnd * nValue));
663 } // end of anonymous namespace
665 } } } // end of namespace ::sd::slidesorter