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
SelectionFunction(SlideSorter & rSlideSorter,SfxRequest & rRequest)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
~SelectionFunction(void)359 SelectionFunction::~SelectionFunction (void)
360 {
361 mpModeHandler.reset();
362 }
363
Create(SlideSorter & rSlideSorter,SfxRequest & rRequest)364 FunctionReference SelectionFunction::Create(
365 SlideSorter& rSlideSorter,
366 SfxRequest& rRequest)
367 {
368 FunctionReference xFunc( new SelectionFunction( rSlideSorter, rRequest ) );
369 return xFunc;
370 }
371
MouseButtonDown(const MouseEvent & rEvent)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
MouseMove(const MouseEvent & rEvent)386 sal_Bool SelectionFunction::MouseMove (const MouseEvent& rEvent)
387 {
388 ProcessMouseEvent(MOUSE_MOTION, rEvent);
389 return sal_True;
390 }
391
MouseButtonUp(const MouseEvent & rEvent)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
NotifyDragFinished(void)404 void SelectionFunction::NotifyDragFinished (void)
405 {
406 SwitchToNormalMode();
407 }
408
KeyInput(const KeyEvent & rEvent)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
MoveFocus(const FocusManager::FocusMoveDirection eDirection,const bool bIsShiftDown,const bool bIsControlDown)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
Activate()617 void SelectionFunction::Activate()
618 {
619 FuPoor::Activate();
620 }
621
Deactivate()622 void SelectionFunction::Deactivate()
623 {
624 FuPoor::Deactivate();
625 }
626
ScrollStart(void)627 void SelectionFunction::ScrollStart (void)
628 {
629 }
630
ScrollEnd(void)631 void SelectionFunction::ScrollEnd (void)
632 {
633 }
634
DoCut(void)635 void SelectionFunction::DoCut (void)
636 {
637 if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly())
638 {
639 mrController.GetClipboard().DoCut();
640 }
641 }
642
DoCopy(void)643 void SelectionFunction::DoCopy (void)
644 {
645 mrController.GetClipboard().DoCopy();
646 }
647
DoPaste(void)648 void SelectionFunction::DoPaste (void)
649 {
650 if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly())
651 {
652 mrController.GetClipboard().DoPaste();
653 }
654 }
655
cancel(void)656 bool SelectionFunction::cancel (void)
657 {
658 mrController.GetFocusManager().ToggleFocus();
659 return true;
660 }
661
GotoNextPage(int nOffset)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
GotoPage(int nIndex)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
ProcessMouseEvent(sal_uInt32 nEventType,const MouseEvent & rEvent)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
MouseDragged(const AcceptDropEvent & rEvent,const sal_Int8 nDragAction)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
ProcessKeyEvent(const KeyEvent & rEvent)714 void SelectionFunction::ProcessKeyEvent (const KeyEvent& rEvent)
715 {
716 EventDescriptor aEventDescriptor (rEvent, mrSlideSorter);
717 ProcessEvent(aEventDescriptor);
718 }
719
ProcessEvent(EventDescriptor & rDescriptor)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
Match(const sal_uInt32 nEventCode,const sal_uInt32 nPositivePattern)729 bool Match (
730 const sal_uInt32 nEventCode,
731 const sal_uInt32 nPositivePattern)
732 {
733 return (nEventCode & nPositivePattern)==nPositivePattern;
734 }
735
SwitchToNormalMode(void)736 void SelectionFunction::SwitchToNormalMode (void)
737 {
738 if (mpModeHandler->GetMode() != NormalMode)
739 SwitchMode(::boost::shared_ptr<ModeHandler>(
740 new NormalModeHandler(mrSlideSorter, *this)));
741 }
742
SwitchToDragAndDropMode(const Point aMousePosition)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
SwitchToMultiSelectionMode(const Point aMousePosition,const sal_uInt32 nEventCode)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
SwitchToButtonMode(void)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
SwitchMode(const::boost::shared_ptr<ModeHandler> & rpHandler)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
ResetShiftKeySelectionAnchor(void)793 void SelectionFunction::ResetShiftKeySelectionAnchor (void)
794 {
795 mnShiftKeySelectionAnchor = -1;
796 }
797
ResetMouseAnchor(void)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
EventDescriptor(const sal_uInt32 nEventType,const MouseEvent & rEvent,SlideSorter & rSlideSorter)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
EventDescriptor(const sal_uInt32 nEventType,const AcceptDropEvent & rEvent,const sal_Int8 nDragAction,SlideSorter & rSlideSorter)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
EventDescriptor(const KeyEvent & rEvent,SlideSorter & rSlideSorter)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
SetDragMode(const InsertionIndicatorHandler::Mode eMode)899 void SelectionFunction::EventDescriptor::SetDragMode (const InsertionIndicatorHandler::Mode eMode)
900 {
901 meDragMode = eMode;
902 }
903
EncodeMouseEvent(const MouseEvent & rEvent) const904 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
EncodeKeyEvent(const KeyEvent & rEvent) const939 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
EncodeState(void) const953 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
ModeHandler(SlideSorter & rSlideSorter,SelectionFunction & rSelectionFunction,const bool bIsMouseOverIndicatorAllowed)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
~ModeHandler(void)986 SelectionFunction::ModeHandler::~ModeHandler (void)
987 {
988 }
989
ReprocessEvent(EventDescriptor & rDescriptor)990 void SelectionFunction::ModeHandler::ReprocessEvent (EventDescriptor& rDescriptor)
991 {
992 mrSelectionFunction.ProcessEvent(rDescriptor);
993 }
994
ProcessEvent(SelectionFunction::EventDescriptor & rDescriptor)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
ProcessButtonDownEvent(EventDescriptor &)1025 bool SelectionFunction::ModeHandler::ProcessButtonDownEvent (EventDescriptor&)
1026 {
1027 return false;
1028 }
1029
ProcessButtonUpEvent(EventDescriptor &)1030 bool SelectionFunction::ModeHandler::ProcessButtonUpEvent (EventDescriptor&)
1031 {
1032 mrSelectionFunction.SwitchToNormalMode();
1033 return false;
1034 }
1035
ProcessMotionEvent(EventDescriptor & rDescriptor)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
ProcessDragEvent(EventDescriptor &)1055 bool SelectionFunction::ModeHandler::ProcessDragEvent (EventDescriptor&)
1056 {
1057 return false;
1058 }
1059
HandleUnprocessedEvent(EventDescriptor &)1060 bool SelectionFunction::ModeHandler::HandleUnprocessedEvent (EventDescriptor&)
1061 {
1062 return false;
1063 }
1064
SetCurrentPage(const model::SharedPageDescriptor & rpDescriptor)1065 void SelectionFunction::ModeHandler::SetCurrentPage (
1066 const model::SharedPageDescriptor& rpDescriptor)
1067 {
1068 SelectOnePage(rpDescriptor);
1069 mrSlideSorter.GetController().GetCurrentSlideManager()->SwitchCurrentSlide(rpDescriptor);
1070 }
1071
DeselectAllPages(void)1072 void SelectionFunction::ModeHandler::DeselectAllPages (void)
1073 {
1074 mrSlideSorter.GetController().GetPageSelector().DeselectAllPages();
1075 mrSelectionFunction.ResetShiftKeySelectionAnchor();
1076 }
1077
SelectOnePage(const model::SharedPageDescriptor & rpDescriptor)1078 void SelectionFunction::ModeHandler::SelectOnePage (
1079 const model::SharedPageDescriptor& rpDescriptor)
1080 {
1081 DeselectAllPages();
1082 mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor);
1083 }
1084
SwitchView(const model::SharedPageDescriptor & rpDescriptor)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
StartDrag(const Point & rMousePosition,const InsertionIndicatorHandler::Mode eMode)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
IsMouseOverIndicatorAllowed(void) const1124 bool SelectionFunction::ModeHandler::IsMouseOverIndicatorAllowed (void) const
1125 {
1126 return mbIsMouseOverIndicatorAllowed;
1127 }
1128
1129 //===== NormalModeHandler =====================================================
1130
NormalModeHandler(SlideSorter & rSlideSorter,SelectionFunction & rSelectionFunction)1131 NormalModeHandler::NormalModeHandler (
1132 SlideSorter& rSlideSorter,
1133 SelectionFunction& rSelectionFunction)
1134 : ModeHandler(rSlideSorter, rSelectionFunction, true),
1135 maButtonDownLocation()
1136 {
1137 }
1138
~NormalModeHandler(void)1139 NormalModeHandler::~NormalModeHandler (void)
1140 {
1141 }
1142
GetMode(void) const1143 SelectionFunction::Mode NormalModeHandler::GetMode (void) const
1144 {
1145 return SelectionFunction::NormalMode;
1146 }
1147
Abort(void)1148 void NormalModeHandler::Abort (void)
1149 {
1150 }
1151
ProcessButtonDownEvent(SelectionFunction::EventDescriptor & rDescriptor)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
ProcessButtonUpEvent(SelectionFunction::EventDescriptor & rDescriptor)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
ProcessMotionEvent(SelectionFunction::EventDescriptor & rDescriptor)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
ProcessDragEvent(SelectionFunction::EventDescriptor & rDescriptor)1323 bool NormalModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor)
1324 {
1325 mrSelectionFunction.SwitchToDragAndDropMode(rDescriptor.maMousePosition);
1326 ReprocessEvent(rDescriptor);
1327 return true;
1328 }
1329
RangeSelect(const model::SharedPageDescriptor & rpDescriptor)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
ResetButtonDownLocation(void)1361 void NormalModeHandler::ResetButtonDownLocation (void)
1362 {
1363 maButtonDownLocation = ::boost::optional<Point>();
1364 }
1365
1366 //===== MultiSelectionModeHandler =============================================
1367
MultiSelectionModeHandler(SlideSorter & rSlideSorter,SelectionFunction & rSelectionFunction,const Point & rMouseModelPosition,const sal_uInt32 nEventCode)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
~MultiSelectionModeHandler(void)1386 MultiSelectionModeHandler::~MultiSelectionModeHandler (void)
1387 {
1388 mrSlideSorter.GetContentWindow()->SetPointer(maSavedPointer);
1389 }
1390
GetMode(void) const1391 SelectionFunction::Mode MultiSelectionModeHandler::GetMode (void) const
1392 {
1393 return SelectionFunction::MultiSelectionMode;
1394 }
1395
Abort(void)1396 void MultiSelectionModeHandler::Abort (void)
1397 {
1398 mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection());
1399 }
1400
ProcessEvent(SelectionFunction::EventDescriptor & rDescriptor)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
ProcessButtonUpEvent(SelectionFunction::EventDescriptor & rDescriptor)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
ProcessMotionEvent(SelectionFunction::EventDescriptor & rDescriptor)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
HandleUnprocessedEvent(SelectionFunction::EventDescriptor & rDescriptor)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
UpdatePosition(const Point & rMousePosition,const bool bAllowAutoScroll)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
SetSelectionModeFromModifier(const sal_uInt32 nEventCode)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
SetSelectionMode(const SelectionMode eSelectionMode)1496 void MultiSelectionModeHandler::SetSelectionMode (const SelectionMode eSelectionMode)
1497 {
1498 if (meSelectionMode != eSelectionMode)
1499 {
1500 meSelectionMode = eSelectionMode;
1501 UpdateSelection();
1502 }
1503 }
1504
UpdateSelectionState(const model::SharedPageDescriptor & rpDescriptor,const bool bIsInSelection) const1505 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
UpdateModelPosition(const Point & rMouseModelPosition)1540 void MultiSelectionModeHandler::UpdateModelPosition (const Point& rMouseModelPosition)
1541 {
1542 maSecondCorner = rMouseModelPosition;
1543 UpdateSelection();
1544 }
1545
UpdateSelection(void)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
DragAndDropModeHandler(SlideSorter & rSlideSorter,SelectionFunction & rSelectionFunction,const Point & rMousePosition,::Window * pWindow)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
~DragAndDropModeHandler(void)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
GetMode(void) const1610 SelectionFunction::Mode DragAndDropModeHandler::GetMode (void) const
1611 {
1612 return SelectionFunction::DragAndDropMode;
1613 }
1614
Abort(void)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
ProcessButtonUpEvent(SelectionFunction::EventDescriptor & rDescriptor)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
ProcessDragEvent(SelectionFunction::EventDescriptor & rDescriptor)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
ButtonModeHandler(SlideSorter & rSlideSorter,SelectionFunction & rSelectionFunction)1658 ButtonModeHandler::ButtonModeHandler (
1659 SlideSorter& rSlideSorter,
1660 SelectionFunction& rSelectionFunction)
1661 : ModeHandler(rSlideSorter, rSelectionFunction, true)
1662 {
1663 }
1664
~ButtonModeHandler(void)1665 ButtonModeHandler::~ButtonModeHandler (void)
1666 {
1667 }
1668
GetMode(void) const1669 SelectionFunction::Mode ButtonModeHandler::GetMode (void) const
1670 {
1671 return SelectionFunction::ButtonMode;
1672 }
1673
Abort(void)1674 void ButtonModeHandler::Abort (void)
1675 {
1676 }
1677
ProcessButtonDownEvent(SelectionFunction::EventDescriptor & rDescriptor)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
ProcessButtonUpEvent(SelectionFunction::EventDescriptor & rDescriptor)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
ProcessMotionEvent(SelectionFunction::EventDescriptor & rDescriptor)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