xref: /trunk/main/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx (revision 989b13ef2270bbb43d1b5fb03162470a47d7f4cc)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 #include "precompiled_sd.hxx"
23 
24 #include "controller/SlsSelectionFunction.hxx"
25 
26 #include "SlideSorter.hxx"
27 #include "SlideSorterViewShell.hxx"
28 #include "SlsDragAndDropContext.hxx"
29 #include "controller/SlsTransferableData.hxx"
30 #include "controller/SlideSorterController.hxx"
31 #include "controller/SlsPageSelector.hxx"
32 #include "controller/SlsFocusManager.hxx"
33 #include "controller/SlsScrollBarManager.hxx"
34 #include "controller/SlsClipboard.hxx"
35 #include "controller/SlsCurrentSlideManager.hxx"
36 #include "controller/SlsInsertionIndicatorHandler.hxx"
37 #include "controller/SlsSelectionManager.hxx"
38 #include "controller/SlsProperties.hxx"
39 #include "controller/SlsProperties.hxx"
40 #include "controller/SlsSlotManager.hxx"
41 #include "controller/SlsVisibleAreaManager.hxx"
42 #include "model/SlideSorterModel.hxx"
43 #include "model/SlsPageDescriptor.hxx"
44 #include "model/SlsPageEnumerationProvider.hxx"
45 #include "view/SlideSorterView.hxx"
46 #include "view/SlsLayouter.hxx"
47 #include "view/SlsPageObjectLayouter.hxx"
48 #include "view/SlsButtonBar.hxx"
49 #include "framework/FrameworkHelper.hxx"
50 #include "ViewShellBase.hxx"
51 #include "DrawController.hxx"
52 #include "Window.hxx"
53 #include "sdpage.hxx"
54 #include "drawdoc.hxx"
55 #include "DrawDocShell.hxx"
56 #include "sdxfer.hxx"
57 #include "ViewShell.hxx"
58 #include "ViewShellBase.hxx"
59 #include "FrameView.hxx"
60 #include "app.hrc"
61 #include "sdresid.hxx"
62 #include "strings.hrc"
63 #include <sfx2/viewfrm.hxx>
64 #include <sfx2/dispatch.hxx>
65 #include <svx/svdpagv.hxx>
66 #include <vcl/msgbox.hxx>
67 #include <svx/svxids.hrc>
68 #include <boost/bind.hpp>
69 #include <boost/optional.hpp>
70 
71 namespace {
72 static const sal_uInt32 SINGLE_CLICK            (0x00000001);
73 static const sal_uInt32 DOUBLE_CLICK            (0x00000002);
74 static const sal_uInt32 LEFT_BUTTON             (0x00000010);
75 static const sal_uInt32 RIGHT_BUTTON            (0x00000020);
76 static const sal_uInt32 MIDDLE_BUTTON           (0x00000040);
77 static const sal_uInt32 BUTTON_DOWN             (0x00000100);
78 static const sal_uInt32 BUTTON_UP               (0x00000200);
79 static const sal_uInt32 MOUSE_MOTION            (0x00000400);
80 static const sal_uInt32 MOUSE_DRAG              (0x00000800);
81 // The rest leaves the lower 16 bit untouched so that it can be used with
82 // key codes.
83 static const sal_uInt32 OVER_SELECTED_PAGE      (0x00010000);
84 static const sal_uInt32 OVER_UNSELECTED_PAGE    (0x00020000);
85 static const sal_uInt32 OVER_FADE_INDICATOR     (0x00040000);
86 static const sal_uInt32 OVER_BUTTON_AREA        (0x00080000);
87 static const sal_uInt32 OVER_BUTTON             (0x00100000);
88 static const sal_uInt32 SHIFT_MODIFIER          (0x00200000);
89 static const sal_uInt32 CONTROL_MODIFIER        (0x00400000);
90 
91 static const sal_uInt32 KEY_EVENT               (0x10000000);
92 
93 // Some absent events are defined so they can be expressed explicitly.
94 static const sal_uInt32 NO_MODIFIER             (0x00000000);
95 static const sal_uInt32 NOT_OVER_PAGE           (0x00000000);
96 
97 // Masks
98 static const sal_uInt32 MODIFIER_MASK           (SHIFT_MODIFIER | CONTROL_MODIFIER);
99 static const sal_uInt32 BUTTON_MASK             (LEFT_BUTTON | RIGHT_BUTTON | MIDDLE_BUTTON);
100 
101 } // end of anonymous namespace
102 
103 // Define some macros to make the following switch statement more readable.
104 #define ANY_MODIFIER(code)      \
105          code|NO_MODIFIER:      \
106     case code|SHIFT_MODIFIER:   \
107     case code|CONTROL_MODIFIER
108 
109 namespace sd { namespace slidesorter { namespace controller {
110 
111 //===== SelectionFunction::EventDescriptor ====================================
112 
113 class SelectionFunction::EventDescriptor
114 {
115 public:
116     Point maMousePosition;
117     Point maMouseModelPosition;
118     model::SharedPageDescriptor mpHitDescriptor;
119     SdrPage* mpHitPage;
120     sal_uInt32 mnEventCode;
121     bool mbIsOverButton;
122     InsertionIndicatorHandler::Mode meDragMode;
123     bool mbMakeSelectionVisible;
124     bool mbIsLeaving;
125 
126     EventDescriptor (
127         sal_uInt32 nEventType,
128         const MouseEvent& rEvent,
129         SlideSorter& rSlideSorter);
130     EventDescriptor (
131         sal_uInt32 nEventType,
132         const AcceptDropEvent& rEvent,
133         const sal_Int8 nDragAction,
134         SlideSorter& rSlideSorter);
135     EventDescriptor (
136         const KeyEvent& rEvent,
137         SlideSorter& rSlideSorter);
138 
139     void SetDragMode (const InsertionIndicatorHandler::Mode eMode);
140 
141 private:
142     /** Compute a numerical code that describes a mouse event and that can
143         be used for fast look up of the appropriate reaction.
144     */
145     sal_uInt32 EncodeMouseEvent (const MouseEvent& rEvent) const;
146 
147     /** Compute a numerical code that describes a key event and that can
148         be used for fast look up of the appropriate reaction.
149     */
150     sal_uInt32 EncodeKeyEvent (const KeyEvent& rEvent) const;
151 
152     /** Compute a numerical code that describes the current state like
153         whether the selection rectangle is visible or whether the page under
154         the mouse or the one that has the focus is selected.
155     */
156     sal_uInt32 EncodeState (void) const;
157 };
158 
159 //===== SelectionFunction::ModeHandler ========================================
160 
161 class SelectionFunction::ModeHandler
162 {
163 public:
164     ModeHandler (
165         SlideSorter& rSlideSorter,
166         SelectionFunction& rSelectionFunction,
167         const bool bIsMouseOverIndicatorAllowed);
168     virtual ~ModeHandler (void);
169 
170     virtual Mode GetMode (void) const = 0;
171     virtual void Abort (void) = 0;
172     virtual void ProcessEvent (EventDescriptor& rDescriptor);
173 
174     /** Set the selection to exactly the specified page and also set it as
175         the current page.
176     */
177     void SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor);
178 
179     /// Deselect all pages.
180     void DeselectAllPages (void);
181     void SelectOnePage (const model::SharedPageDescriptor& rpDescriptor);
182 
183         /** When the view on which this selection function is working is the
184         main view then the view is switched to the regular editing view.
185     */
186     void SwitchView (const model::SharedPageDescriptor& rpDescriptor);
187 
188     void StartDrag (
189         const Point& rMousePosition,
190         const InsertionIndicatorHandler::Mode eMode);
191 
192     bool IsMouseOverIndicatorAllowed (void) const;
193 
194 protected:
195     SlideSorter& mrSlideSorter;
196     SelectionFunction& mrSelectionFunction;
197 
198     virtual bool ProcessButtonDownEvent (EventDescriptor& rDescriptor);
199     virtual bool ProcessButtonUpEvent (EventDescriptor& rDescriptor);
200     virtual bool ProcessMotionEvent (EventDescriptor& rDescriptor);
201     virtual bool ProcessDragEvent (EventDescriptor& rDescriptor);
202     virtual bool HandleUnprocessedEvent (EventDescriptor& rDescriptor);
203 
204     void ReprocessEvent (EventDescriptor& rDescriptor);
205 
206 private:
207     const bool mbIsMouseOverIndicatorAllowed;
208 };
209 
210 /** This is the default handler for processing events. It activates the
211     multi selection or drag-and-drop when the right conditions are met.
212 */
213 class NormalModeHandler : public SelectionFunction::ModeHandler
214 {
215 public:
216     NormalModeHandler (
217         SlideSorter& rSlideSorter,
218         SelectionFunction& rSelectionFunction);
219     virtual ~NormalModeHandler (void);
220 
221     virtual SelectionFunction::Mode GetMode (void) const;
222     virtual void Abort (void);
223 
224     void ResetButtonDownLocation (void);
225 
226 protected:
227     virtual bool ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor);
228     virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor);
229     virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor);
230     virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor);
231 
232 private:
233     ::boost::optional<Point> maButtonDownLocation;
234 
235     /** Select all pages between and including the selection anchor and the
236         specified page.
237     */
238     void RangeSelect (const model::SharedPageDescriptor& rpDescriptor);
239 };
240 
241 /** Handle events during a multi selection, which typically is started by
242     pressing the left mouse button when not over a page.
243 */
244 class MultiSelectionModeHandler : public SelectionFunction::ModeHandler
245 {
246 public:
247     /** Start a rectangle selection at the given position.
248     */
249     MultiSelectionModeHandler (
250         SlideSorter& rSlideSorter,
251         SelectionFunction& rSelectionFunction,
252         const Point& rMouseModelPosition,
253         const sal_uInt32 nEventCode);
254     virtual ~MultiSelectionModeHandler (void);
255 
256     virtual SelectionFunction::Mode GetMode (void) const;
257     virtual void Abort (void);
258     virtual void ProcessEvent (SelectionFunction::EventDescriptor& rDescriptor);
259 
260     enum SelectionMode { SM_Normal, SM_Add, SM_Toggle };
261 
262     void SetSelectionMode (const SelectionMode eSelectionMode);
263     void SetSelectionModeFromModifier (const sal_uInt32 nEventCode);
264 
265 protected:
266     virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor);
267     virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor);
268     virtual bool HandleUnprocessedEvent (SelectionFunction::EventDescriptor& rDescriptor);
269 
270 private:
271     SelectionMode meSelectionMode;
272     Point maSecondCorner;
273     Pointer maSavedPointer;
274     sal_Int32 mnAnchorIndex;
275     sal_Int32 mnSecondIndex;
276     view::ButtonBar::Lock maButtonBarLock;
277 
278     virtual void UpdateModelPosition (const Point& rMouseModelPosition);
279     virtual void UpdateSelection (void);
280 
281     /** Update the rectangle selection so that the given position becomes
282         the new second point of the selection rectangle.
283     */
284     void UpdatePosition (
285         const Point& rMousePosition,
286         const bool bAllowAutoScroll);
287 
288     void UpdateSelectionState (
289         const model::SharedPageDescriptor& rpDescriptor,
290         const bool bIsInSelection) const;
291 };
292 
293 /** Handle events during drag-and-drop.
294 */
295 class DragAndDropModeHandler : public SelectionFunction::ModeHandler
296 {
297 public:
298     DragAndDropModeHandler (
299         SlideSorter& rSlideSorter,
300         SelectionFunction& rSelectionFunction,
301         const Point& rMousePosition,
302         ::Window* pWindow);
303     virtual ~DragAndDropModeHandler (void);
304 
305     virtual SelectionFunction::Mode GetMode (void) const;
306     virtual void Abort (void);
307 
308 protected:
309     virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor);
310     virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor);
311 
312 private:
313     ::boost::scoped_ptr<DragAndDropContext> mpDragAndDropContext;
314 };
315 
316 /** Handle events while the left mouse button is pressed over the button
317     bar.
318 */
319 class ButtonModeHandler : public SelectionFunction::ModeHandler
320 {
321 public:
322     ButtonModeHandler (
323         SlideSorter& rSlideSorter,
324         SelectionFunction& rSelectionFunction);
325     virtual ~ButtonModeHandler (void);
326     virtual void Abort (void);
327 
328     virtual SelectionFunction::Mode GetMode (void) const;
329 
330 protected:
331     virtual bool ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor);
332     virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor);
333     virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor);
334 };
335 
336 //===== SelectionFunction =====================================================
337 
338 TYPEINIT1(SelectionFunction, FuPoor);
339 
340 SelectionFunction::SelectionFunction (
341     SlideSorter& rSlideSorter,
342     SfxRequest& rRequest)
343     : FuPoor (
344         rSlideSorter.GetViewShell(),
345         rSlideSorter.GetContentWindow().get(),
346         &rSlideSorter.GetView(),
347         rSlideSorter.GetModel().GetDocument(),
348         rRequest),
349       mrSlideSorter(rSlideSorter),
350       mrController(mrSlideSorter.GetController()),
351       mbDragSelection(false),
352       maInsertionMarkerBox(),
353       mbProcessingMouseButtonDown(false),
354       mnShiftKeySelectionAnchor(-1),
355       mpModeHandler(new NormalModeHandler(rSlideSorter, *this))
356 {
357 }
358 
359 SelectionFunction::~SelectionFunction (void)
360 {
361     mpModeHandler.reset();
362 }
363 
364 FunctionReference SelectionFunction::Create(
365     SlideSorter& rSlideSorter,
366     SfxRequest& rRequest)
367 {
368     FunctionReference xFunc( new SelectionFunction( rSlideSorter, rRequest ) );
369     return xFunc;
370 }
371 
372 sal_Bool SelectionFunction::MouseButtonDown (const MouseEvent& rEvent)
373 {
374     // #95491# remember button state for creation of own MouseEvents
375     SetMouseButtonCode (rEvent.GetButtons());
376     aMDPos = rEvent.GetPosPixel();
377     mbProcessingMouseButtonDown = true;
378 
379     //  mpWindow->CaptureMouse();
380 
381     ProcessMouseEvent(BUTTON_DOWN, rEvent);
382 
383     return sal_True;
384 }
385 
386 sal_Bool SelectionFunction::MouseMove (const MouseEvent& rEvent)
387 {
388     ProcessMouseEvent(MOUSE_MOTION, rEvent);
389     return sal_True;
390 }
391 
392 sal_Bool SelectionFunction::MouseButtonUp (const MouseEvent& rEvent)
393 {
394     mrController.GetScrollBarManager().StopAutoScroll ();
395 
396     ProcessMouseEvent(BUTTON_UP, rEvent);
397 
398     mbProcessingMouseButtonDown = false;
399 //  mpWindow->ReleaseMouse();
400 
401     return sal_True;
402 }
403 
404 void SelectionFunction::NotifyDragFinished (void)
405 {
406     SwitchToNormalMode();
407 }
408 
409 sal_Bool SelectionFunction::KeyInput (const KeyEvent& rEvent)
410 {
411     view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter);
412     PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter);
413     PageSelector::UpdateLock aLock (mrSlideSorter);
414     FocusManager& rFocusManager (mrController.GetFocusManager());
415     sal_Bool bResult = sal_False;
416 
417     const KeyCode& rCode (rEvent.GetKeyCode());
418     switch (rCode.GetCode())
419     {
420         case KEY_RETURN:
421         {
422             model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor());
423             ViewShell* pViewShell = mrSlideSorter.GetViewShell();
424             if (rFocusManager.HasFocus() && pDescriptor && pViewShell!=NULL)
425             {
426                 // The Return key triggers different functions depending on
427                 // whether the slide sorter is the main view or displayed in
428                 // the right pane.
429                 if (pViewShell->IsMainViewShell())
430                 {
431                     mpModeHandler->SetCurrentPage(pDescriptor);
432                     mpModeHandler->SwitchView(pDescriptor);
433                 }
434                 else
435                 {
436                     pViewShell->GetDispatcher()->Execute(
437                         SID_INSERTPAGE,
438                         SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD);
439                 }
440                 bResult = sal_True;
441             }
442             break;
443         }
444 
445         case KEY_TAB:
446             if ( ! rFocusManager.IsFocusShowing())
447             {
448                 rFocusManager.ShowFocus();
449                 bResult = sal_True;
450             }
451             break;
452 
453         case KEY_ESCAPE:
454             // When there is an active multiselection or drag-and-drop
455             // operation then stop that.
456             mpModeHandler->Abort();
457             SwitchToNormalMode();
458             bResult = sal_True;
459             break;
460 
461         case KEY_SPACE:
462         {
463             // Toggle the selection state.
464             model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor());
465             if (pDescriptor && rCode.IsMod1())
466             {
467                 if (pDescriptor->HasState(model::PageDescriptor::ST_Selected))
468                     mrController.GetPageSelector().DeselectPage(pDescriptor, false);
469                 else
470                     mrController.GetPageSelector().SelectPage(pDescriptor);
471             }
472             bResult = sal_True;
473         }
474         break;
475 
476         // Move the focus indicator left.
477         case KEY_LEFT:
478             MoveFocus(FocusManager::FMD_LEFT, rCode.IsShift(), rCode.IsMod1());
479             bResult = sal_True;
480             break;
481 
482         // Move the focus indicator right.
483         case KEY_RIGHT:
484             MoveFocus(FocusManager::FMD_RIGHT, rCode.IsShift(), rCode.IsMod1());
485             bResult = sal_True;
486             break;
487 
488         // Move the focus indicator up.
489         case KEY_UP:
490             MoveFocus(FocusManager::FMD_UP, rCode.IsShift(), rCode.IsMod1());
491             bResult = sal_True;
492             break;
493 
494         // Move the focus indicator down.
495         case KEY_DOWN:
496             MoveFocus(FocusManager::FMD_DOWN, rCode.IsShift(), rCode.IsMod1());
497             bResult = sal_True;
498             break;
499 
500         // Go to previous page. No wrap around.
501         case KEY_PAGEUP:
502             GotoNextPage(-1);
503             bResult = sal_True;
504             break;
505 
506         // Go to next page. No wrap around..
507         case KEY_PAGEDOWN:
508             GotoNextPage(+1);
509             bResult = sal_True;
510             break;
511 
512         case KEY_HOME:
513             GotoPage(0);
514             bResult = sal_True;
515             break;
516 
517         case KEY_END:
518             GotoPage(mrSlideSorter.GetModel().GetPageCount()-1);
519             bResult = sal_True;
520             break;
521 
522         case KEY_DELETE:
523         case KEY_BACKSPACE:
524         {
525             if (mrSlideSorter.GetProperties()->IsUIReadOnly())
526                 break;
527 
528             mrController.GetSelectionManager()->DeleteSelectedPages(rCode.GetCode()==KEY_DELETE);
529 
530             mnShiftKeySelectionAnchor = -1;
531             bResult = sal_True;
532         }
533         break;
534 
535         case KEY_F10:
536             if (rCode.IsShift())
537             {
538                 mpModeHandler->SelectOnePage(
539                     mrSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor());
540             }
541             break;
542 
543         default:
544             break;
545     }
546 
547     if ( ! bResult)
548         bResult = FuPoor::KeyInput(rEvent);
549 
550     return bResult;
551 }
552 
553 void SelectionFunction::MoveFocus (
554     const FocusManager::FocusMoveDirection eDirection,
555     const bool bIsShiftDown,
556     const bool bIsControlDown)
557 {
558     // Remember the anchor of shift key multi selection.
559     if (bIsShiftDown)
560     {
561         if (mnShiftKeySelectionAnchor<0)
562         {
563             model::SharedPageDescriptor pFocusedDescriptor (
564                 mrController.GetFocusManager().GetFocusedPageDescriptor());
565             mnShiftKeySelectionAnchor = pFocusedDescriptor->GetPageIndex();
566         }
567     }
568     else if ( ! bIsControlDown)
569         ResetShiftKeySelectionAnchor();
570 
571     mrController.GetFocusManager().MoveFocus(eDirection);
572 
573     PageSelector& rSelector (mrController.GetPageSelector());
574     model::SharedPageDescriptor pFocusedDescriptor (
575         mrController.GetFocusManager().GetFocusedPageDescriptor());
576     if (bIsShiftDown)
577     {
578         // When shift is pressed then select all pages in the range between
579         // the currently and the previously focused pages, including them.
580         if (pFocusedDescriptor)
581         {
582             sal_Int32 nPageRangeEnd (pFocusedDescriptor->GetPageIndex());
583             model::PageEnumeration aPages (
584                 model::PageEnumerationProvider::CreateAllPagesEnumeration(
585                     mrSlideSorter.GetModel()));
586             while (aPages.HasMoreElements())
587             {
588                 model::SharedPageDescriptor pDescriptor (aPages.GetNextElement());
589                 if (pDescriptor)
590                 {
591                     const sal_Int32 nPageIndex(pDescriptor->GetPageIndex());
592                     if ((nPageIndex>=mnShiftKeySelectionAnchor && nPageIndex<=nPageRangeEnd)
593                         || (nPageIndex<=mnShiftKeySelectionAnchor && nPageIndex>=nPageRangeEnd))
594                     {
595                         rSelector.SelectPage(pDescriptor);
596                     }
597                     else
598                     {
599                         rSelector.DeselectPage(pDescriptor);
600                     }
601                 }
602             }
603         }
604     }
605     else if (bIsControlDown)
606     {
607         // When control is pressed then do not alter the selection or the
608         // current page, just move the focus.
609     }
610     else
611     {
612         // Without shift just select the focused page.
613         mpModeHandler->SelectOnePage(pFocusedDescriptor);
614     }
615 }
616 
617 void SelectionFunction::Activate()
618 {
619     FuPoor::Activate();
620 }
621 
622 void SelectionFunction::Deactivate()
623 {
624     FuPoor::Deactivate();
625 }
626 
627 void SelectionFunction::ScrollStart (void)
628 {
629 }
630 
631 void SelectionFunction::ScrollEnd (void)
632 {
633 }
634 
635 void SelectionFunction::DoCut (void)
636 {
637     if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly())
638     {
639         mrController.GetClipboard().DoCut();
640     }
641 }
642 
643 void SelectionFunction::DoCopy (void)
644 {
645     mrController.GetClipboard().DoCopy();
646 }
647 
648 void SelectionFunction::DoPaste (void)
649 {
650     if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly())
651     {
652         mrController.GetClipboard().DoPaste();
653     }
654 }
655 
656 bool SelectionFunction::cancel (void)
657 {
658     mrController.GetFocusManager().ToggleFocus();
659     return true;
660 }
661 
662 void SelectionFunction::GotoNextPage (int nOffset)
663 {
664     model::SharedPageDescriptor pDescriptor
665         = mrController.GetCurrentSlideManager()->GetCurrentSlide();
666     if (pDescriptor.get() != NULL)
667     {
668         SdPage* pPage = pDescriptor->GetPage();
669         OSL_ASSERT(pPage!=NULL);
670         sal_Int32 nIndex = (pPage->GetPageNum()-1) / 2;
671         GotoPage(nIndex + nOffset);
672     }
673     ResetShiftKeySelectionAnchor();
674 }
675 
676 void SelectionFunction::GotoPage (int nIndex)
677 {
678     sal_uInt16 nPageCount = (sal_uInt16)mrSlideSorter.GetModel().GetPageCount();
679 
680     if (nIndex >= nPageCount)
681         nIndex = nPageCount - 1;
682     if (nIndex < 0)
683         nIndex = 0;
684 
685     mrController.GetFocusManager().SetFocusedPage(nIndex);
686     model::SharedPageDescriptor pNextPageDescriptor (
687         mrSlideSorter.GetModel().GetPageDescriptor (nIndex));
688     if (pNextPageDescriptor.get() != NULL)
689         mpModeHandler->SetCurrentPage(pNextPageDescriptor);
690     else
691     {
692         OSL_ASSERT(pNextPageDescriptor.get() != NULL);
693     }
694     ResetShiftKeySelectionAnchor();
695 }
696 
697 void SelectionFunction::ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent)
698 {
699     // #95491# remember button state for creation of own MouseEvents
700     SetMouseButtonCode (rEvent.GetButtons());
701 
702     EventDescriptor aEventDescriptor (nEventType, rEvent, mrSlideSorter);
703     ProcessEvent(aEventDescriptor);
704 }
705 
706 void SelectionFunction::MouseDragged (
707     const AcceptDropEvent& rEvent,
708     const sal_Int8 nDragAction)
709 {
710     EventDescriptor aEventDescriptor (MOUSE_DRAG, rEvent, nDragAction, mrSlideSorter);
711     ProcessEvent(aEventDescriptor);
712 }
713 
714 void SelectionFunction::ProcessKeyEvent (const KeyEvent& rEvent)
715 {
716     EventDescriptor aEventDescriptor (rEvent, mrSlideSorter);
717     ProcessEvent(aEventDescriptor);
718 }
719 
720 void SelectionFunction::ProcessEvent (EventDescriptor& rDescriptor)
721 {
722     // The call to ProcessEvent may switch to another mode handler.
723     // Prevent the untimely destruction of the called handler by acquiring a
724     // temporary reference here.
725     ::boost::shared_ptr<ModeHandler> pModeHandler (mpModeHandler);
726     pModeHandler->ProcessEvent(rDescriptor);
727 }
728 
729 bool Match (
730     const sal_uInt32 nEventCode,
731     const sal_uInt32 nPositivePattern)
732 {
733     return (nEventCode & nPositivePattern)==nPositivePattern;
734 }
735 
736 void SelectionFunction::SwitchToNormalMode (void)
737 {
738     if (mpModeHandler->GetMode() != NormalMode)
739         SwitchMode(::boost::shared_ptr<ModeHandler>(
740             new NormalModeHandler(mrSlideSorter, *this)));
741 }
742 
743 void SelectionFunction::SwitchToDragAndDropMode (const Point aMousePosition)
744 {
745     if (mpModeHandler->GetMode() != DragAndDropMode)
746     {
747         SwitchMode(::boost::shared_ptr<ModeHandler>(
748             new DragAndDropModeHandler(mrSlideSorter, *this, aMousePosition, mpWindow)));
749     }
750 }
751 
752 void SelectionFunction::SwitchToMultiSelectionMode (
753     const Point aMousePosition,
754     const sal_uInt32 nEventCode)
755 {
756     if (mpModeHandler->GetMode() != MultiSelectionMode)
757         SwitchMode(::boost::shared_ptr<ModeHandler>(
758             new MultiSelectionModeHandler(mrSlideSorter, *this, aMousePosition, nEventCode)));
759 }
760 
761 bool SelectionFunction::SwitchToButtonMode (void)
762 {
763     // Do not show the buttons for draw pages.
764     ::boost::shared_ptr<ViewShell> pMainViewShell (mrSlideSorter.GetViewShellBase()->GetMainViewShell());
765     if (pMainViewShell
766         && pMainViewShell->GetShellType()!=ViewShell::ST_DRAW
767         && mpModeHandler->GetMode() != ButtonMode)
768     {
769         SwitchMode(::boost::shared_ptr<ModeHandler>(new ButtonModeHandler(mrSlideSorter, *this)));
770         return true;
771     }
772     else
773         return false;
774 }
775 
776 void SelectionFunction::SwitchMode (const ::boost::shared_ptr<ModeHandler>& rpHandler)
777 {
778     // Not all modes allow mouse over indicator.
779     if (mpModeHandler->IsMouseOverIndicatorAllowed() != rpHandler->IsMouseOverIndicatorAllowed())
780     {
781         if ( ! rpHandler->IsMouseOverIndicatorAllowed())
782         {
783             mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor());
784             mrSlideSorter.GetView().GetButtonBar().ResetPage();
785         }
786         else
787             mrSlideSorter.GetView().UpdatePageUnderMouse(false);
788     }
789 
790     mpModeHandler = rpHandler;
791 }
792 
793 void SelectionFunction::ResetShiftKeySelectionAnchor (void)
794 {
795     mnShiftKeySelectionAnchor = -1;
796 }
797 
798 void SelectionFunction::ResetMouseAnchor (void)
799 {
800     if (mpModeHandler && mpModeHandler->GetMode() == NormalMode)
801     {
802         ::boost::shared_ptr<NormalModeHandler> pHandler (
803             ::boost::dynamic_pointer_cast<NormalModeHandler>(mpModeHandler));
804         if (pHandler)
805             pHandler->ResetButtonDownLocation();
806     }
807 }
808 
809 //===== EventDescriptor =======================================================
810 
811 SelectionFunction::EventDescriptor::EventDescriptor (
812     const sal_uInt32 nEventType,
813     const MouseEvent& rEvent,
814     SlideSorter& rSlideSorter)
815     : maMousePosition(rEvent.GetPosPixel()),
816       maMouseModelPosition(),
817       mpHitDescriptor(),
818       mpHitPage(),
819       mnEventCode(nEventType),
820       mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()),
821       meDragMode(InsertionIndicatorHandler::MoveMode),
822       mbMakeSelectionVisible(true),
823       mbIsLeaving(false)
824 {
825     maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition);
826     mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition);
827     if (mpHitDescriptor)
828     {
829         mpHitPage = mpHitDescriptor->GetPage();
830     }
831 
832     mnEventCode |= EncodeMouseEvent(rEvent);
833     mnEventCode |= EncodeState();
834 
835     // Detect the mouse leaving the window. When not button is pressed then
836     // we can call IsLeaveWindow at the event. Otherwise we have to make an
837     // explicit test.
838     mbIsLeaving = rEvent.IsLeaveWindow()
839         || ! Rectangle(Point(0,0),
840              rSlideSorter.GetContentWindow()->GetOutputSizePixel()).IsInside(maMousePosition);
841 }
842 
843 SelectionFunction::EventDescriptor::EventDescriptor (
844     const sal_uInt32 nEventType,
845     const AcceptDropEvent& rEvent,
846     const sal_Int8 nDragAction,
847     SlideSorter& rSlideSorter)
848     : maMousePosition(rEvent.maPosPixel),
849       maMouseModelPosition(),
850       mpHitDescriptor(),
851       mpHitPage(),
852       mnEventCode(nEventType),
853       mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()),
854       meDragMode(InsertionIndicatorHandler::GetModeFromDndAction(nDragAction)),
855       mbMakeSelectionVisible(true),
856       mbIsLeaving(false)
857 {
858     maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition);
859     mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition);
860     if (mpHitDescriptor)
861     {
862         mpHitPage = mpHitDescriptor->GetPage();
863     }
864 
865     mnEventCode |= EncodeState();
866 
867     // Detect the mouse leaving the window. When not button is pressed then
868     // we can call IsLeaveWindow at the event. Otherwise we have to make an
869     // explicit test.
870     mbIsLeaving = rEvent.mbLeaving
871         || ! Rectangle(Point(0,0),
872              rSlideSorter.GetContentWindow()->GetOutputSizePixel()).IsInside(maMousePosition);
873 }
874 
875 SelectionFunction::EventDescriptor::EventDescriptor (
876     const KeyEvent& rEvent,
877     SlideSorter& rSlideSorter)
878     : maMousePosition(),
879       maMouseModelPosition(),
880       mpHitDescriptor(),
881       mpHitPage(),
882       mnEventCode(KEY_EVENT),
883       mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()),
884       meDragMode(InsertionIndicatorHandler::MoveMode),
885       mbMakeSelectionVisible(true),
886       mbIsLeaving(false)
887 {
888     model::SharedPageDescriptor pHitDescriptor (
889         rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor());
890     if (pHitDescriptor.get() != NULL)
891     {
892         mpHitPage = pHitDescriptor->GetPage();
893         mpHitDescriptor = pHitDescriptor;
894     }
895 
896     mnEventCode |= EncodeKeyEvent(rEvent) | EncodeState();
897 }
898 
899 void SelectionFunction::EventDescriptor::SetDragMode (const InsertionIndicatorHandler::Mode eMode)
900 {
901     meDragMode = eMode;
902 }
903 
904 sal_uInt32 SelectionFunction::EventDescriptor::EncodeMouseEvent (
905     const MouseEvent& rEvent) const
906 {
907     // Initialize with the type of mouse event.
908     sal_uInt32 nEventCode (mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION));
909 
910     // Detect the affected button.
911     switch (rEvent.GetButtons())
912     {
913         case MOUSE_LEFT:   nEventCode |= LEFT_BUTTON; break;
914         case MOUSE_RIGHT:  nEventCode |= RIGHT_BUTTON; break;
915         case MOUSE_MIDDLE: nEventCode |= MIDDLE_BUTTON; break;
916     }
917 
918     // Detect the number of clicks.
919     switch (rEvent.GetClicks())
920     {
921         case 1: nEventCode |= SINGLE_CLICK; break;
922         case 2: nEventCode |= DOUBLE_CLICK; break;
923     }
924 
925     // Detect pressed modifier keys.
926     if (rEvent.IsShift())
927         nEventCode |= SHIFT_MODIFIER;
928     if (rEvent.IsMod1())
929         nEventCode |= CONTROL_MODIFIER;
930 
931     // Detect whether the mouse is over one of the active elements inside a
932     // page object.
933     if (mbIsOverButton)
934         nEventCode |= OVER_BUTTON;
935 
936     return nEventCode;
937 }
938 
939 sal_uInt32 SelectionFunction::EventDescriptor::EncodeKeyEvent (const KeyEvent& rEvent) const
940 {
941     // The key code in the lower 16 bit.
942     sal_uInt32 nEventCode (rEvent.GetKeyCode().GetCode());
943 
944     // Detect pressed modifier keys.
945     if (rEvent.GetKeyCode().IsShift())
946         nEventCode |= SHIFT_MODIFIER;
947     if (rEvent.GetKeyCode().IsMod1())
948         nEventCode |= CONTROL_MODIFIER;
949 
950     return nEventCode;
951 }
952 
953 sal_uInt32 SelectionFunction::EventDescriptor::EncodeState (void) const
954 {
955     sal_uInt32 nEventCode (0);
956 
957     // Detect whether the event has happened over a page object.
958     if (mpHitPage!=NULL && mpHitDescriptor)
959     {
960         if (mpHitDescriptor->HasState(model::PageDescriptor::ST_Selected))
961             nEventCode |= OVER_SELECTED_PAGE;
962         else
963             nEventCode |= OVER_UNSELECTED_PAGE;
964 
965         // Detect whether the mouse is over one of the active elements
966         // inside a page object.
967         if (mbIsOverButton)
968             nEventCode |= OVER_BUTTON;
969     }
970 
971     return nEventCode;
972 }
973 
974 //===== SelectionFunction::ModeHandler ========================================
975 
976 SelectionFunction::ModeHandler::ModeHandler (
977     SlideSorter& rSlideSorter,
978     SelectionFunction& rSelectionFunction,
979     const bool bIsMouseOverIndicatorAllowed)
980     : mrSlideSorter(rSlideSorter),
981       mrSelectionFunction(rSelectionFunction),
982       mbIsMouseOverIndicatorAllowed(bIsMouseOverIndicatorAllowed)
983 {
984 }
985 
986 SelectionFunction::ModeHandler::~ModeHandler (void)
987 {
988 }
989 
990 void SelectionFunction::ModeHandler::ReprocessEvent (EventDescriptor& rDescriptor)
991 {
992     mrSelectionFunction.ProcessEvent(rDescriptor);
993 }
994 
995 void SelectionFunction::ModeHandler::ProcessEvent (
996     SelectionFunction::EventDescriptor& rDescriptor)
997 {
998     PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter);
999     PageSelector::UpdateLock aUpdateLock (mrSlideSorter);
1000 
1001     bool bIsProcessed (false);
1002     switch (rDescriptor.mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION | MOUSE_DRAG))
1003     {
1004         case BUTTON_DOWN:
1005             bIsProcessed = ProcessButtonDownEvent(rDescriptor);
1006             break;
1007 
1008         case BUTTON_UP:
1009             bIsProcessed = ProcessButtonUpEvent(rDescriptor);
1010             break;
1011 
1012         case MOUSE_MOTION:
1013             bIsProcessed = ProcessMotionEvent(rDescriptor);
1014             break;
1015 
1016         case MOUSE_DRAG:
1017             bIsProcessed = ProcessDragEvent(rDescriptor);
1018             break;
1019     }
1020 
1021     if ( ! bIsProcessed)
1022         HandleUnprocessedEvent(rDescriptor);
1023 }
1024 
1025 bool SelectionFunction::ModeHandler::ProcessButtonDownEvent (EventDescriptor&)
1026 {
1027     return false;
1028 }
1029 
1030 bool SelectionFunction::ModeHandler::ProcessButtonUpEvent (EventDescriptor&)
1031 {
1032     mrSelectionFunction.SwitchToNormalMode();
1033     return false;
1034 }
1035 
1036 bool SelectionFunction::ModeHandler::ProcessMotionEvent (EventDescriptor& rDescriptor)
1037 {
1038     if (mbIsMouseOverIndicatorAllowed)
1039         mrSlideSorter.GetView().UpdatePageUnderMouse(
1040             rDescriptor.maMousePosition,
1041             (rDescriptor.mnEventCode & LEFT_BUTTON) != 0,
1042             true);
1043 
1044     if (rDescriptor.mbIsLeaving)
1045     {
1046         mrSelectionFunction.SwitchToNormalMode();
1047         mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor());
1048 
1049         return true;
1050     }
1051     else
1052         return false;
1053 }
1054 
1055 bool SelectionFunction::ModeHandler::ProcessDragEvent (EventDescriptor&)
1056 {
1057     return false;
1058 }
1059 
1060 bool SelectionFunction::ModeHandler::HandleUnprocessedEvent (EventDescriptor&)
1061 {
1062     return false;
1063 }
1064 
1065 void SelectionFunction::ModeHandler::SetCurrentPage (
1066     const model::SharedPageDescriptor& rpDescriptor)
1067 {
1068     SelectOnePage(rpDescriptor);
1069     mrSlideSorter.GetController().GetCurrentSlideManager()->SwitchCurrentSlide(rpDescriptor);
1070 }
1071 
1072 void SelectionFunction::ModeHandler::DeselectAllPages (void)
1073 {
1074     mrSlideSorter.GetController().GetPageSelector().DeselectAllPages();
1075     mrSelectionFunction.ResetShiftKeySelectionAnchor();
1076 }
1077 
1078 void SelectionFunction::ModeHandler::SelectOnePage (
1079     const model::SharedPageDescriptor& rpDescriptor)
1080 {
1081     DeselectAllPages();
1082     mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor);
1083 }
1084 
1085 void SelectionFunction::ModeHandler::SwitchView (const model::SharedPageDescriptor& rpDescriptor)
1086 {
1087     // Switch to the draw view. This is done only when the current
1088     // view is the main view.
1089     ViewShell* pViewShell = mrSlideSorter.GetViewShell();
1090     if (pViewShell!=NULL && pViewShell->IsMainViewShell())
1091     {
1092         if (rpDescriptor.get()!=NULL && rpDescriptor->GetPage()!=NULL)
1093         {
1094             mrSlideSorter.GetModel().GetDocument()->SetSelected(rpDescriptor->GetPage(), sal_True);
1095             pViewShell->GetFrameView()->SetSelectedPage(
1096                 (rpDescriptor->GetPage()->GetPageNum()-1)/2);
1097         }
1098         if (mrSlideSorter.GetViewShellBase() != NULL)
1099         framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase())->RequestView(
1100             framework::FrameworkHelper::msImpressViewURL,
1101             framework::FrameworkHelper::msCenterPaneURL);
1102     }
1103 }
1104 
1105 void SelectionFunction::ModeHandler::StartDrag (
1106     const Point& rMousePosition,
1107     const InsertionIndicatorHandler::Mode eMode)
1108 {
1109     (void)eMode;
1110     // Do not start a drag-and-drop operation when one is already active.
1111     // (when dragging pages from one document into another, pressing a
1112     // modifier key can trigger a MouseMotion event in the originating
1113     // window (focus still in there). Together with the mouse button pressed
1114     // (drag-and-drop is active) this triggers the start of drag-and-drop.)
1115     if (SD_MOD()->pTransferDrag != NULL)
1116         return;
1117 
1118     if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly())
1119     {
1120         mrSelectionFunction.SwitchToDragAndDropMode(rMousePosition);
1121     }
1122 }
1123 
1124 bool SelectionFunction::ModeHandler::IsMouseOverIndicatorAllowed (void) const
1125 {
1126     return mbIsMouseOverIndicatorAllowed;
1127 }
1128 
1129 //===== NormalModeHandler =====================================================
1130 
1131 NormalModeHandler::NormalModeHandler (
1132     SlideSorter& rSlideSorter,
1133     SelectionFunction& rSelectionFunction)
1134     : ModeHandler(rSlideSorter, rSelectionFunction, true),
1135       maButtonDownLocation()
1136 {
1137 }
1138 
1139 NormalModeHandler::~NormalModeHandler (void)
1140 {
1141 }
1142 
1143 SelectionFunction::Mode NormalModeHandler::GetMode (void) const
1144 {
1145     return SelectionFunction::NormalMode;
1146 }
1147 
1148 void NormalModeHandler::Abort (void)
1149 {
1150 }
1151 
1152 bool NormalModeHandler::ProcessButtonDownEvent (
1153     SelectionFunction::EventDescriptor& rDescriptor)
1154 {
1155     // Remember the location where the left button is pressed. With
1156     // that we can filter away motion events that are caused by key
1157     // presses. We also can tune the minimal motion distance that
1158     // triggers a drag-and-drop operation.
1159     if ((rDescriptor.mnEventCode & BUTTON_DOWN) != 0)
1160         maButtonDownLocation = rDescriptor.maMousePosition;
1161 
1162     switch (rDescriptor.mnEventCode)
1163     {
1164         case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE:
1165             SetCurrentPage(rDescriptor.mpHitDescriptor);
1166             break;
1167 
1168         case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
1169             break;
1170 
1171         case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_SELECTED_PAGE:
1172         case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_UNSELECTED_PAGE:
1173             // A double click always shows the selected slide in the center
1174             // pane in an edit view.
1175             SetCurrentPage(rDescriptor.mpHitDescriptor);
1176             SwitchView(rDescriptor.mpHitDescriptor);
1177             break;
1178 
1179         case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | SHIFT_MODIFIER:
1180         case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | SHIFT_MODIFIER:
1181             // Range selection with the shift modifier.
1182             RangeSelect(rDescriptor.mpHitDescriptor);
1183             break;
1184 
1185         case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | OVER_BUTTON:
1186         case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | OVER_BUTTON:
1187             OSL_ASSERT(mrSlideSorter.GetView().GetButtonBar().IsMouseOverButton());
1188 
1189             // Switch to button mode only when the buttons are visible
1190             // (or being faded in.)
1191             if (mrSlideSorter.GetView().GetButtonBar().IsVisible(rDescriptor.mpHitDescriptor))
1192             {
1193                 if (mrSelectionFunction.SwitchToButtonMode())
1194                     ReprocessEvent(rDescriptor);
1195             }
1196             else
1197             {
1198                 // When the buttons are not (yet) visible then behave like
1199                 // the left button had been clicked over any other part of
1200                 // the slide.
1201                 SetCurrentPage(rDescriptor.mpHitDescriptor);
1202             }
1203             break;
1204 
1205             // Right button for context menu.
1206         case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE:
1207             // Single right click and shift+F10 select as preparation to
1208             // show the context menu. Change the selection only when the
1209             // page under the mouse is not selected. In this case the
1210             // selection is set to this single page. Otherwise the
1211             // selection is not modified.
1212             SetCurrentPage(rDescriptor.mpHitDescriptor);
1213             rDescriptor.mbMakeSelectionVisible = false;
1214             break;
1215 
1216         case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
1217             // Do not change the selection. Just adjust the insertion indicator.
1218             rDescriptor.mbMakeSelectionVisible = false;
1219             break;
1220 
1221         case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE:
1222             // Remember the current selection so that when a multi selection
1223             // is started, we can restore the previous selection.
1224             mrSlideSorter.GetModel().SaveCurrentSelection();
1225             DeselectAllPages();
1226             break;
1227 
1228         case ANY_MODIFIER(BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE):
1229             // Remember the current selection so that when a multi selection
1230             // is started, we can restore the previous selection.
1231             mrSlideSorter.GetModel().SaveCurrentSelection();
1232             DeselectAllPages();
1233             break;
1234 
1235         default:
1236             return false;
1237     }
1238     return true;
1239 }
1240 
1241 bool NormalModeHandler::ProcessButtonUpEvent (
1242     SelectionFunction::EventDescriptor& rDescriptor)
1243 {
1244     bool bIsProcessed (true);
1245     switch (rDescriptor.mnEventCode)
1246     {
1247         case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
1248             SetCurrentPage(rDescriptor.mpHitDescriptor);
1249             break;
1250 
1251             // Multi selection with the control modifier.
1252         case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | CONTROL_MODIFIER:
1253             mrSlideSorter.GetController().GetPageSelector().DeselectPage(
1254                 rDescriptor.mpHitDescriptor);
1255             break;
1256 
1257         case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | CONTROL_MODIFIER:
1258             mrSlideSorter.GetController().GetPageSelector().SelectPage(
1259                 rDescriptor.mpHitDescriptor);
1260             mrSlideSorter.GetView().UpdatePageUnderMouse(
1261                 rDescriptor.mpHitDescriptor,
1262                 rDescriptor.maMousePosition,
1263                 false);
1264             break;
1265         case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE:
1266             break;
1267 
1268         default:
1269             bIsProcessed = false;
1270             break;
1271     }
1272     mrSelectionFunction.SwitchToNormalMode();
1273     return bIsProcessed;
1274 }
1275 
1276 bool NormalModeHandler::ProcessMotionEvent (
1277     SelectionFunction::EventDescriptor& rDescriptor)
1278 {
1279     if (ModeHandler::ProcessMotionEvent(rDescriptor))
1280         return true;
1281 
1282     bool bIsProcessed (true);
1283     switch (rDescriptor.mnEventCode)
1284     {
1285         case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE):
1286 //          SetCurrentPage(rDescriptor.mpHitDescriptor);
1287             // Fallthrough
1288 
1289         // A mouse motion without visible substitution starts that.
1290         case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE):
1291         {
1292             if (maButtonDownLocation)
1293             {
1294                 const sal_Int32 nDistance (maButtonDownLocation
1295                     ? ::std::max (
1296                         abs(maButtonDownLocation->X() - rDescriptor.maMousePosition.X()),
1297                         abs(maButtonDownLocation->Y() - rDescriptor.maMousePosition.Y()))
1298                     : 0);
1299                 if (nDistance > 3)
1300                     StartDrag(
1301                         rDescriptor.maMousePosition,
1302                         (rDescriptor.mnEventCode & CONTROL_MODIFIER) != 0
1303                             ? InsertionIndicatorHandler::CopyMode
1304                             : InsertionIndicatorHandler::MoveMode);
1305             }
1306         }
1307         break;
1308 
1309             // A mouse motion not over a page starts a rectangle selection.
1310         case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE):
1311             mrSelectionFunction.SwitchToMultiSelectionMode(
1312                 rDescriptor.maMouseModelPosition,
1313                 rDescriptor.mnEventCode);
1314             break;
1315 
1316         default:
1317             bIsProcessed = false;
1318             break;
1319     }
1320     return bIsProcessed;
1321 }
1322 
1323 bool NormalModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor)
1324 {
1325     mrSelectionFunction.SwitchToDragAndDropMode(rDescriptor.maMousePosition);
1326     ReprocessEvent(rDescriptor);
1327     return true;
1328 }
1329 
1330 void NormalModeHandler::RangeSelect (const model::SharedPageDescriptor& rpDescriptor)
1331 {
1332     PageSelector::UpdateLock aLock (mrSlideSorter);
1333     PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector());
1334 
1335     model::SharedPageDescriptor pAnchor (rSelector.GetSelectionAnchor());
1336     DeselectAllPages();
1337 
1338     if (pAnchor.get() != NULL)
1339     {
1340         // Select all pages between the anchor and the given one, including
1341         // the two.
1342         const sal_uInt16 nAnchorIndex ((pAnchor->GetPage()->GetPageNum()-1) / 2);
1343         const sal_uInt16 nOtherIndex ((rpDescriptor->GetPage()->GetPageNum()-1) / 2);
1344 
1345         // Iterate over all pages in the range. Start with the anchor
1346         // page. This way the PageSelector will recognize it again as
1347         // anchor (the first selected page after a DeselectAllPages()
1348         // becomes the anchor.)
1349         const sal_uInt16 nStep ((nAnchorIndex < nOtherIndex) ? +1 : -1);
1350         sal_uInt16 nIndex (nAnchorIndex);
1351         while (true)
1352         {
1353             rSelector.SelectPage(nIndex);
1354             if (nIndex == nOtherIndex)
1355                 break;
1356             nIndex = nIndex + nStep;
1357         }
1358     }
1359 }
1360 
1361 void NormalModeHandler::ResetButtonDownLocation (void)
1362 {
1363     maButtonDownLocation = ::boost::optional<Point>();
1364 }
1365 
1366 //===== MultiSelectionModeHandler =============================================
1367 
1368 MultiSelectionModeHandler::MultiSelectionModeHandler (
1369     SlideSorter& rSlideSorter,
1370     SelectionFunction& rSelectionFunction,
1371     const Point& rMouseModelPosition,
1372     const sal_uInt32 nEventCode)
1373     : ModeHandler(rSlideSorter, rSelectionFunction, false),
1374       meSelectionMode(SM_Normal),
1375       maSecondCorner(rMouseModelPosition),
1376       maSavedPointer(mrSlideSorter.GetContentWindow()->GetPointer()),
1377       mnAnchorIndex(-1),
1378       mnSecondIndex(-1),
1379       maButtonBarLock(rSlideSorter)
1380 {
1381     const Pointer aSelectionPointer (POINTER_TEXT);
1382     mrSlideSorter.GetContentWindow()->SetPointer(aSelectionPointer);
1383     SetSelectionModeFromModifier(nEventCode);
1384 }
1385 
1386 MultiSelectionModeHandler::~MultiSelectionModeHandler (void)
1387 {
1388     mrSlideSorter.GetContentWindow()->SetPointer(maSavedPointer);
1389 }
1390 
1391 SelectionFunction::Mode MultiSelectionModeHandler::GetMode (void) const
1392 {
1393     return SelectionFunction::MultiSelectionMode;
1394 }
1395 
1396 void MultiSelectionModeHandler::Abort (void)
1397 {
1398     mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection());
1399 }
1400 
1401 void MultiSelectionModeHandler::ProcessEvent (
1402     SelectionFunction::EventDescriptor& rDescriptor)
1403 {
1404     // During a multi selection we do not want sudden jumps of the
1405     // visible area caused by moving newly selected pages into view.
1406     // Therefore disable that temporarily. The disabler object is
1407     // released at the end of the event processing, after the focus and
1408     // current slide have been updated.
1409     VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter);
1410 
1411     ModeHandler::ProcessEvent(rDescriptor);
1412 }
1413 
1414 bool MultiSelectionModeHandler::ProcessButtonUpEvent (
1415     SelectionFunction::EventDescriptor& rDescriptor)
1416 {
1417     if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK))
1418     {
1419         mrSelectionFunction.SwitchToNormalMode();
1420         return true;
1421     }
1422     else
1423         return false;
1424 }
1425 
1426 bool MultiSelectionModeHandler::ProcessMotionEvent (
1427     SelectionFunction::EventDescriptor& rDescriptor)
1428 {
1429     // The selection rectangle is visible. Handle events accordingly.
1430     if (Match(rDescriptor.mnEventCode, MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK))
1431     {
1432         SetSelectionModeFromModifier(rDescriptor.mnEventCode);
1433         UpdatePosition(rDescriptor.maMousePosition, true);
1434         rDescriptor.mbMakeSelectionVisible = false;
1435         return true;
1436     }
1437     else
1438         return false;
1439 }
1440 
1441 bool MultiSelectionModeHandler::HandleUnprocessedEvent (
1442     SelectionFunction::EventDescriptor& rDescriptor)
1443 {
1444     if ( ! ModeHandler::HandleUnprocessedEvent(rDescriptor))
1445     {
1446         // If the event has not been processed then stop multi selection.
1447         mrSelectionFunction.SwitchToNormalMode();
1448         ReprocessEvent(rDescriptor);
1449     }
1450     return true;
1451 }
1452 
1453 void MultiSelectionModeHandler::UpdatePosition (
1454     const Point& rMousePosition,
1455     const bool bAllowAutoScroll)
1456 {
1457     VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter);
1458 
1459     // Convert window coordinates into model coordinates (we need the
1460     // window coordinates for auto-scrolling because that remains
1461     // constant while scrolling.)
1462     SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
1463     const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition));
1464 
1465     if ( ! (bAllowAutoScroll && mrSlideSorter.GetController().GetScrollBarManager().AutoScroll(
1466         rMousePosition,
1467         ::boost::bind(
1468             &MultiSelectionModeHandler::UpdatePosition,
1469             this,
1470             rMousePosition,
1471             false))))
1472     {
1473         UpdateModelPosition(aMouseModelPosition);
1474     }
1475 }
1476 
1477 void MultiSelectionModeHandler::SetSelectionModeFromModifier (
1478     const sal_uInt32 nEventCode)
1479 {
1480     switch (nEventCode & MODIFIER_MASK)
1481     {
1482         case NO_MODIFIER:
1483             SetSelectionMode(SM_Normal);
1484             break;
1485 
1486         case SHIFT_MODIFIER:
1487             SetSelectionMode(SM_Add);
1488             break;
1489 
1490         case CONTROL_MODIFIER:
1491             SetSelectionMode(SM_Toggle);
1492             break;
1493     }
1494 }
1495 
1496 void MultiSelectionModeHandler::SetSelectionMode (const SelectionMode eSelectionMode)
1497 {
1498     if (meSelectionMode != eSelectionMode)
1499     {
1500         meSelectionMode = eSelectionMode;
1501         UpdateSelection();
1502     }
1503 }
1504 
1505 void MultiSelectionModeHandler::UpdateSelectionState (
1506     const model::SharedPageDescriptor& rpDescriptor,
1507     const bool bIsInSelection) const
1508 {
1509     // Determine whether the page was selected before the rectangle
1510     // selection was started.
1511     const bool bWasSelected (rpDescriptor->HasState(model::PageDescriptor::ST_WasSelected));
1512 
1513     // Combine the two selection states depending on the selection mode.
1514     bool bSelect (false);
1515     switch(meSelectionMode)
1516     {
1517         case SM_Normal:
1518             bSelect = bIsInSelection;
1519             break;
1520 
1521         case SM_Add:
1522             bSelect = bIsInSelection || bWasSelected;
1523             break;
1524 
1525         case SM_Toggle:
1526             if (bIsInSelection)
1527                 bSelect = !bWasSelected;
1528             else
1529                 bSelect = bWasSelected;
1530             break;
1531     }
1532 
1533     // Set the new selection state.
1534     if (bSelect)
1535         mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor);
1536     else
1537         mrSlideSorter.GetController().GetPageSelector().DeselectPage(rpDescriptor);
1538 }
1539 
1540 void MultiSelectionModeHandler::UpdateModelPosition (const Point& rMouseModelPosition)
1541 {
1542     maSecondCorner = rMouseModelPosition;
1543     UpdateSelection();
1544 }
1545 
1546 void MultiSelectionModeHandler::UpdateSelection (void)
1547 {
1548     view::SlideSorterView::DrawLock aLock (mrSlideSorter);
1549 
1550     model::SlideSorterModel& rModel (mrSlideSorter.GetModel());
1551     const sal_Int32 nPageCount (rModel.GetPageCount());
1552 
1553     const sal_Int32 nIndexUnderMouse (
1554         mrSlideSorter.GetView().GetLayouter().GetIndexAtPoint (
1555             maSecondCorner,
1556             false,
1557             false));
1558     if (nIndexUnderMouse>=0 && nIndexUnderMouse<nPageCount)
1559     {
1560         if (mnAnchorIndex < 0)
1561             mnAnchorIndex = nIndexUnderMouse;
1562         mnSecondIndex = nIndexUnderMouse;
1563 
1564         Range aRange (mnAnchorIndex, mnSecondIndex);
1565         aRange.Justify();
1566 
1567         for (sal_Int32 nIndex=0; nIndex<nPageCount; ++nIndex)
1568         {
1569             UpdateSelectionState(rModel.GetPageDescriptor(nIndex), aRange.IsInside(nIndex));
1570         }
1571     }
1572 }
1573 
1574 //===== DragAndDropModeHandler ================================================
1575 
1576 DragAndDropModeHandler::DragAndDropModeHandler (
1577     SlideSorter& rSlideSorter,
1578     SelectionFunction& rSelectionFunction,
1579     const Point& rMousePosition,
1580     ::Window* pWindow)
1581     : ModeHandler(rSlideSorter, rSelectionFunction, false)
1582 {
1583     SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
1584     if (pDragTransferable==NULL && mrSlideSorter.GetViewShell() != NULL)
1585     {
1586         SlideSorterViewShell* pSlideSorterViewShell
1587             = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell());
1588         if (pSlideSorterViewShell != NULL)
1589             pSlideSorterViewShell->StartDrag(rMousePosition, pWindow);
1590         pDragTransferable = SD_MOD()->pTransferDrag;
1591     }
1592 
1593     mpDragAndDropContext.reset(new DragAndDropContext(mrSlideSorter));
1594     mrSlideSorter.GetController().GetInsertionIndicatorHandler()->Start(
1595         pDragTransferable != NULL
1596             && pDragTransferable->GetView()==&mrSlideSorter.GetView());
1597 }
1598 
1599 DragAndDropModeHandler::~DragAndDropModeHandler (void)
1600 {
1601     if (mpDragAndDropContext)
1602     {
1603         // Disconnect the substitution handler from this selection function.
1604         mpDragAndDropContext->SetTargetSlideSorter();
1605         mpDragAndDropContext.reset();
1606     }
1607     mrSlideSorter.GetController().GetInsertionIndicatorHandler()->End(Animator::AM_Animated);
1608 }
1609 
1610 SelectionFunction::Mode DragAndDropModeHandler::GetMode (void) const
1611 {
1612     return SelectionFunction::DragAndDropMode;
1613 }
1614 
1615 void DragAndDropModeHandler::Abort (void)
1616 {
1617     mrSlideSorter.GetController().GetClipboard().Abort();
1618     if (mpDragAndDropContext)
1619         mpDragAndDropContext->Dispose();
1620 //  mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection());
1621 }
1622 
1623 bool DragAndDropModeHandler::ProcessButtonUpEvent (
1624     SelectionFunction::EventDescriptor& rDescriptor)
1625 {
1626     if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON))
1627     {
1628         // The following Process() call may lead to the destruction
1629         // of rDescriptor.mpHitDescriptor so release our reference to it.
1630         rDescriptor.mpHitDescriptor.reset();
1631         mrSelectionFunction.SwitchToNormalMode();
1632         return true;
1633     }
1634     else
1635         return false;
1636 }
1637 
1638 bool DragAndDropModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor)
1639 {
1640     OSL_ASSERT(mpDragAndDropContext);
1641 
1642     if (rDescriptor.mbIsLeaving)
1643     {
1644         mrSelectionFunction.SwitchToNormalMode();
1645     }
1646     else if (mpDragAndDropContext)
1647     {
1648         mpDragAndDropContext->UpdatePosition(
1649             rDescriptor.maMousePosition,
1650             rDescriptor.meDragMode);
1651     }
1652 
1653     return true;
1654 }
1655 
1656 //===== ButtonModeHandler =====================================================
1657 
1658 ButtonModeHandler::ButtonModeHandler (
1659     SlideSorter& rSlideSorter,
1660     SelectionFunction& rSelectionFunction)
1661     : ModeHandler(rSlideSorter, rSelectionFunction, true)
1662 {
1663 }
1664 
1665 ButtonModeHandler::~ButtonModeHandler (void)
1666 {
1667 }
1668 
1669 SelectionFunction::Mode ButtonModeHandler::GetMode (void) const
1670 {
1671     return SelectionFunction::ButtonMode;
1672 }
1673 
1674 void ButtonModeHandler::Abort (void)
1675 {
1676 }
1677 
1678 bool ButtonModeHandler::ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor)
1679 {
1680     switch (rDescriptor.mnEventCode)
1681     {
1682         case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | OVER_BUTTON:
1683         case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | OVER_BUTTON:
1684             // Remember page and button index. When mouse button is released
1685             // over same page and button then invoke action of that button.
1686             mrSlideSorter.GetView().GetButtonBar().ProcessButtonDownEvent(
1687                 rDescriptor.mpHitDescriptor,
1688                 rDescriptor.maMouseModelPosition);
1689             return true;
1690 
1691         default:
1692             return false;
1693     }
1694 }
1695 
1696 bool ButtonModeHandler::ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor)
1697 {
1698     switch (rDescriptor.mnEventCode & BUTTON_MASK)
1699     {
1700         case LEFT_BUTTON:
1701             mrSlideSorter.GetView().GetButtonBar().ProcessButtonUpEvent(
1702                 rDescriptor.mpHitDescriptor,
1703                 rDescriptor.maMouseModelPosition);
1704             mrSelectionFunction.SwitchToNormalMode();
1705             return true;
1706     }
1707 
1708     return false;
1709 }
1710 
1711 bool ButtonModeHandler::ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor)
1712 {
1713     switch (rDescriptor.mnEventCode & (MOUSE_MOTION | BUTTON_MASK))
1714     {
1715         case MOUSE_MOTION | LEFT_BUTTON:
1716             mrSlideSorter.GetView().GetButtonBar().ProcessMouseMotionEvent(
1717                 rDescriptor.mpHitDescriptor,
1718                 rDescriptor.maMouseModelPosition,
1719                 true);
1720             return true;
1721 
1722         case MOUSE_MOTION:
1723             mrSlideSorter.GetView().GetButtonBar().ProcessMouseMotionEvent(
1724                 rDescriptor.mpHitDescriptor,
1725                 rDescriptor.maMouseModelPosition,
1726                 false);
1727             return true;
1728     }
1729 
1730      return false;
1731 }
1732 
1733 } } } // end of namespace ::sd::slidesorter::controller
1734 
1735 /* vim: set noet sw=4 ts=4: */
1736