1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "precompiled_sd.hxx"
29 
30 #include "controller/SlsSelectionManager.hxx"
31 
32 #include "SlideSorter.hxx"
33 #include "SlsCommand.hxx"
34 #include "controller/SlideSorterController.hxx"
35 #include "controller/SlsAnimator.hxx"
36 #include "controller/SlsAnimationFunction.hxx"
37 #include "controller/SlsCurrentSlideManager.hxx"
38 #include "controller/SlsFocusManager.hxx"
39 #include "controller/SlsPageSelector.hxx"
40 #include "controller/SlsProperties.hxx"
41 #include "controller/SlsScrollBarManager.hxx"
42 #include "controller/SlsSlotManager.hxx"
43 #include "controller/SlsSelectionObserver.hxx"
44 #include "model/SlideSorterModel.hxx"
45 #include "model/SlsPageEnumerationProvider.hxx"
46 #include "model/SlsPageDescriptor.hxx"
47 #include "view/SlideSorterView.hxx"
48 #include "view/SlsLayouter.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>
54 
55 #include "res_bmp.hrc"
56 #include "sdresid.hxx"
57 #include "strings.hrc"
58 #include "app.hrc"
59 #include "glob.hrc"
60 
61 
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;
68 
69 namespace sd { namespace slidesorter { namespace controller {
70 
71 
72 class SelectionManager::PageInsertionListener
73     : public SfxListener
74 {
75 public:
76 
77 };
78 
79 
80 SelectionManager::SelectionManager (SlideSorter& rSlideSorter)
81     : mrSlideSorter(rSlideSorter),
82       mrController(rSlideSorter.GetController()),
83       maSelectionBeforeSwitch(),
84       mbIsMakeSelectionVisiblePending(true),
85       mnInsertionPosition(-1),
86       mnAnimationId(Animator::NotAnAnimationId),
87       maRequestedTopLeft(),
88       mpPageInsertionListener(),
89       mpSelectionObserver(new SelectionObserver(rSlideSorter))
90 {
91 }
92 
93 
94 
95 
96 SelectionManager::~SelectionManager (void)
97 {
98     if (mnAnimationId != Animator::NotAnAnimationId)
99         mrController.GetAnimator()->RemoveAnimation(mnAnimationId);
100 }
101 
102 
103 
104 
105 void SelectionManager::DeleteSelectedPages (const bool bSelectFollowingPage)
106 {
107     // Create some locks to prevent updates of the model, view, selection
108     // state while modifying any of them.
109     SlideSorterController::ModelChangeLock aLock (mrController);
110     SlideSorterView::DrawLock aDrawLock (mrSlideSorter);
111     PageSelector::UpdateLock aSelectionLock (mrSlideSorter);
112 
113     // Hide focus.
114     bool bIsFocusShowing = mrController.GetFocusManager().IsFocusShowing();
115     if (bIsFocusShowing)
116         mrController.GetFocusManager().ToggleFocus();
117 
118     // Store pointers to all selected page descriptors.  This is necessary
119     // because the pages get deselected when the first one is deleted.
120     model::PageEnumeration aPageEnumeration (
121         PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel()));
122     ::std::vector<SdPage*> aSelectedPages;
123     sal_Int32 nNewCurrentSlide (-1);
124     while (aPageEnumeration.HasMoreElements())
125     {
126         SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement());
127         aSelectedPages.push_back(pDescriptor->GetPage());
128         if (bSelectFollowingPage || nNewCurrentSlide<0)
129             nNewCurrentSlide = pDescriptor->GetPageIndex();
130     }
131     if (aSelectedPages.empty())
132         return;
133 
134     // Determine the slide to select (and thereby make the current slide)
135     // after the deletion.
136     if (bSelectFollowingPage)
137         nNewCurrentSlide -= aSelectedPages.size() - 1;
138     else
139         --nNewCurrentSlide;
140 
141     // The actual deletion of the selected pages is done in one of two
142     // helper functions.  They are specialized for normal respectively for
143     // master pages.
144     mrSlideSorter.GetView().BegUndo (SdResId(STR_UNDO_DELETEPAGES));
145     if (mrSlideSorter.GetModel().GetEditMode() == EM_PAGE)
146         DeleteSelectedNormalPages(aSelectedPages);
147     else
148         DeleteSelectedMasterPages(aSelectedPages);
149     mrSlideSorter.GetView().EndUndo ();
150 
151     mrController.HandleModelChange();
152     aLock.Release();
153 
154     // Show focus and move it to next valid location.
155     if (bIsFocusShowing)
156         mrController.GetFocusManager().ToggleFocus();
157 
158     // Set the new current slide.
159     if (nNewCurrentSlide < 0)
160         nNewCurrentSlide = 0;
161     else if (nNewCurrentSlide >= mrSlideSorter.GetModel().GetPageCount())
162         nNewCurrentSlide = mrSlideSorter.GetModel().GetPageCount()-1;
163     mrController.GetPageSelector().CountSelectedPages();
164     mrController.GetPageSelector().SelectPage(nNewCurrentSlide);
165     mrController.GetFocusManager().SetFocusedPage(nNewCurrentSlide);
166 }
167 
168 
169 
170 
171 void SelectionManager::DeleteSelectedNormalPages (const ::std::vector<SdPage*>& rSelectedPages)
172 {
173     // Prepare the deletion via the UNO API.
174 	OSL_ASSERT(mrSlideSorter.GetModel().GetEditMode() == EM_PAGE);
175 
176 	try
177 	{
178 	    Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier( mrSlideSorter.GetModel().GetDocument()->getUnoModel(), UNO_QUERY_THROW );
179 	    Reference<drawing::XDrawPages> xPages( xDrawPagesSupplier->getDrawPages(), UNO_QUERY_THROW );
180 
181 		// Iterate over all pages that where seleted when this method was called
182 		// and delete the draw page the notes page.  The iteration is done in
183 		// reverse order so that when one slide is not deleted (to avoid an
184 		// empty document) the remaining slide is the first one.
185 		::std::vector<SdPage*>::const_reverse_iterator aI;
186 		for (aI=rSelectedPages.rbegin(); aI!=rSelectedPages.rend(); aI++)
187 		{
188 			// Do not delete the last slide in the document.
189 			if (xPages->getCount() <= 1)
190 				break;
191 
192 			const sal_uInt16 nPage (model::FromCoreIndex((*aI)->GetPageNum()));
193 
194 			Reference< XDrawPage > xPage( xPages->getByIndex( nPage ), UNO_QUERY_THROW );
195 			xPages->remove(xPage);
196 		}
197 	}
198 	catch( Exception& )
199 	{
200 		DBG_ERROR("SelectionManager::DeleteSelectedNormalPages(), exception caught!");
201 	}
202 }
203 
204 
205 
206 
207 void SelectionManager::DeleteSelectedMasterPages (const ::std::vector<SdPage*>& rSelectedPages)
208 {
209     // Prepare the deletion via the UNO API.
210     OSL_ASSERT(mrSlideSorter.GetModel().GetEditMode() == EM_MASTERPAGE);
211 
212 	try
213 	{
214 	    Reference<drawing::XMasterPagesSupplier> xDrawPagesSupplier( mrSlideSorter.GetModel().GetDocument()->getUnoModel(), UNO_QUERY_THROW );
215 	    Reference<drawing::XDrawPages> xPages( xDrawPagesSupplier->getMasterPages(), UNO_QUERY_THROW );
216 
217 		// Iterate over all pages that where seleted when this method was called
218 		// and delete the draw page the notes page.  The iteration is done in
219 		// reverse order so that when one slide is not deleted (to avoid an
220 		// empty document) the remaining slide is the first one.
221 		::std::vector<SdPage*>::const_reverse_iterator aI;
222 		for (aI=rSelectedPages.rbegin(); aI!=rSelectedPages.rend(); aI++)
223 		{
224 			// Do not delete the last slide in the document.
225 			if (xPages->getCount() <= 1)
226 				break;
227 
228 			const sal_uInt16 nPage (model::FromCoreIndex((*aI)->GetPageNum()));
229 
230 			Reference< XDrawPage > xPage( xPages->getByIndex( nPage ), UNO_QUERY_THROW );
231 			xPages->remove(xPage);
232 		}
233 	}
234 	catch( Exception& )
235 	{
236 		DBG_ERROR("SelectionManager::DeleteSelectedMasterPages(), exception caught!");
237 	}
238 }
239 
240 
241 
242 
243 void SelectionManager::SelectionHasChanged (const bool bMakeSelectionVisible)
244 {
245     if (bMakeSelectionVisible)
246         mbIsMakeSelectionVisiblePending = true;
247 
248     ViewShell* pViewShell = mrSlideSorter.GetViewShell();
249     if (pViewShell != NULL)
250     {
251         pViewShell->Invalidate (SID_EXPAND_PAGE);
252         pViewShell->Invalidate (SID_SUMMARY_PAGE);
253         pViewShell->Invalidate(SID_SHOW_SLIDE);
254         pViewShell->Invalidate(SID_HIDE_SLIDE);
255         pViewShell->Invalidate(SID_DELETE_PAGE);
256         pViewShell->Invalidate(SID_DELETE_MASTER_PAGE);
257 		pViewShell->Invalidate(SID_ASSIGN_LAYOUT);
258 
259         // StatusBar
260         pViewShell->Invalidate (SID_STATUS_PAGE);
261         pViewShell->Invalidate (SID_STATUS_LAYOUT);
262 
263         OSL_ASSERT(mrController.GetCurrentSlideManager());
264         SharedPageDescriptor pDescriptor(mrController.GetCurrentSlideManager()->GetCurrentSlide());
265         if (pDescriptor.get() != NULL)
266             pViewShell->UpdatePreview(pDescriptor->GetPage());
267 
268         // Tell the slection change listeners that the selection has changed.
269         ::std::vector<Link>::iterator iListener (maSelectionChangeListeners.begin());
270         ::std::vector<Link>::iterator iEnd (maSelectionChangeListeners.end());
271         for (; iListener!=iEnd; ++iListener)
272         {
273             iListener->Call(NULL);
274         }
275 
276         // Reset the insertion position: until set again it is calculated from
277         // the current selection.
278         mnInsertionPosition = -1;
279     }
280 }
281 
282 
283 
284 
285 void SelectionManager::AddSelectionChangeListener (const Link& rListener)
286 {
287     if (::std::find (
288         maSelectionChangeListeners.begin(),
289         maSelectionChangeListeners.end(),
290         rListener) == maSelectionChangeListeners.end())
291     {
292         maSelectionChangeListeners.push_back (rListener);
293     }
294 }
295 
296 
297 
298 
299 void SelectionManager::RemoveSelectionChangeListener(const Link&rListener)
300 {
301     maSelectionChangeListeners.erase (
302         ::std::find (
303             maSelectionChangeListeners.begin(),
304             maSelectionChangeListeners.end(),
305             rListener));
306 }
307 
308 
309 
310 
311 sal_Int32 SelectionManager::GetInsertionPosition (void) const
312 {
313     sal_Int32 nInsertionPosition (mnInsertionPosition);
314     if (nInsertionPosition < 0)
315     {
316         model::PageEnumeration aSelectedPages
317             (model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
318                 mrSlideSorter.GetModel()));
319         // Initialize (for the case of an empty selection) with the position
320         // at the end of the document.
321         nInsertionPosition = mrSlideSorter.GetModel().GetPageCount();
322         while (aSelectedPages.HasMoreElements())
323         {
324             const sal_Int32 nPosition (aSelectedPages.GetNextElement()->GetPage()->GetPageNum());
325             // Convert *2+1 index to straight index (n-1)/2 after the page
326             // (+1).
327             nInsertionPosition = model::FromCoreIndex(nPosition) + 1;
328         }
329 
330     }
331     return nInsertionPosition;
332 }
333 
334 
335 
336 
337 void SelectionManager::SetInsertionPosition (const sal_Int32 nInsertionPosition)
338 {
339     if (nInsertionPosition < 0)
340         mnInsertionPosition = -1;
341     else if (nInsertionPosition > mrSlideSorter.GetModel().GetPageCount())
342     {
343         // Assert but then ignore invalid values.
344         OSL_ASSERT(nInsertionPosition<=mrSlideSorter.GetModel().GetPageCount());
345         return;
346     }
347     else
348         mnInsertionPosition = nInsertionPosition;
349 }
350 
351 
352 
353 
354 ::boost::shared_ptr<SelectionObserver> SelectionManager::GetSelectionObserver (void) const
355 {
356     return mpSelectionObserver;
357 }
358 
359 } } } // end of namespace ::sd::slidesorter
360