bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / slidesorter / controller / SlsSelectionFunction.cxx
blob7a456824b01a3e040a91dbf7660e487b10ff848a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <cstdlib>
24 #include "controller/SlsSelectionFunction.hxx"
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/SlsSlotManager.hxx"
40 #include "controller/SlsVisibleAreaManager.hxx"
41 #include "model/SlideSorterModel.hxx"
42 #include "model/SlsPageDescriptor.hxx"
43 #include "model/SlsPageEnumerationProvider.hxx"
44 #include "view/SlideSorterView.hxx"
45 #include "view/SlsLayouter.hxx"
46 #include "view/SlsPageObjectLayouter.hxx"
47 #include "framework/FrameworkHelper.hxx"
48 #include "ViewShellBase.hxx"
49 #include "DrawController.hxx"
50 #include "Window.hxx"
51 #include "sdpage.hxx"
52 #include "drawdoc.hxx"
53 #include "DrawDocShell.hxx"
54 #include "sdxfer.hxx"
55 #include "ViewShell.hxx"
56 #include "FrameView.hxx"
57 #include "app.hrc"
58 #include "sdresid.hxx"
59 #include "strings.hrc"
60 #include <sfx2/viewfrm.hxx>
61 #include <sfx2/dispatch.hxx>
62 #include <svx/svdpagv.hxx>
63 #include <vcl/msgbox.hxx>
64 #include <svx/svxids.hrc>
65 #include <boost/bind.hpp>
66 #include <boost/optional.hpp>
68 namespace {
69 static const sal_uInt32 SINGLE_CLICK (0x00000001);
70 static const sal_uInt32 DOUBLE_CLICK (0x00000002);
71 static const sal_uInt32 LEFT_BUTTON (0x00000010);
72 static const sal_uInt32 RIGHT_BUTTON (0x00000020);
73 static const sal_uInt32 MIDDLE_BUTTON (0x00000040);
74 static const sal_uInt32 BUTTON_DOWN (0x00000100);
75 static const sal_uInt32 BUTTON_UP (0x00000200);
76 static const sal_uInt32 MOUSE_MOTION (0x00000400);
77 static const sal_uInt32 MOUSE_DRAG (0x00000800);
78 // The rest leaves the lower 16 bit untouched so that it can be used with
79 // key codes.
80 static const sal_uInt32 OVER_SELECTED_PAGE (0x00010000);
81 static const sal_uInt32 OVER_UNSELECTED_PAGE (0x00020000);
82 static const sal_uInt32 SHIFT_MODIFIER (0x00200000);
83 static const sal_uInt32 CONTROL_MODIFIER (0x00400000);
85 // Some absent events are defined so they can be expressed explicitly.
86 static const sal_uInt32 NO_MODIFIER (0x00000000);
87 static const sal_uInt32 NOT_OVER_PAGE (0x00000000);
89 // Masks
90 static const sal_uInt32 MODIFIER_MASK (SHIFT_MODIFIER | CONTROL_MODIFIER);
92 } // end of anonymous namespace
94 // Define some macros to make the following switch statement more readable.
95 #define ANY_MODIFIER(code) \
96 code|NO_MODIFIER: \
97 case code|SHIFT_MODIFIER: \
98 case code|CONTROL_MODIFIER
100 namespace sd { namespace slidesorter { namespace controller {
102 //===== SelectionFunction::EventDescriptor ====================================
104 class SelectionFunction::EventDescriptor
106 public:
107 Point maMousePosition;
108 Point maMouseModelPosition;
109 model::SharedPageDescriptor mpHitDescriptor;
110 SdrPage* mpHitPage;
111 sal_uInt32 mnEventCode;
112 InsertionIndicatorHandler::Mode meDragMode;
113 bool mbMakeSelectionVisible;
114 bool mbIsLeaving;
116 EventDescriptor (
117 sal_uInt32 nEventType,
118 const MouseEvent& rEvent,
119 SlideSorter& rSlideSorter);
120 EventDescriptor (
121 sal_uInt32 nEventType,
122 const AcceptDropEvent& rEvent,
123 const sal_Int8 nDragAction,
124 SlideSorter& rSlideSorter);
126 private:
127 /** Compute a numerical code that describes a mouse event and that can
128 be used for fast look up of the appropriate reaction.
130 sal_uInt32 EncodeMouseEvent (const MouseEvent& rEvent) const;
132 /** Compute a numerical code that describes the current state like
133 whether the selection rectangle is visible or whether the page under
134 the mouse or the one that has the focus is selected.
136 sal_uInt32 EncodeState() const;
139 //===== SelectionFunction::ModeHandler ========================================
141 class SelectionFunction::ModeHandler
143 public:
144 ModeHandler (
145 SlideSorter& rSlideSorter,
146 SelectionFunction& rSelectionFunction,
147 const bool bIsMouseOverIndicatorAllowed);
148 virtual ~ModeHandler();
150 virtual Mode GetMode() const = 0;
151 virtual void Abort() = 0;
152 virtual void ProcessEvent (EventDescriptor& rDescriptor);
154 /** Set the selection to exactly the specified page and also set it as
155 the current page.
157 void SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor);
159 /// Deselect all pages.
160 void DeselectAllPages();
161 void SelectOnePage (const model::SharedPageDescriptor& rpDescriptor);
163 /** When the view on which this selection function is working is the
164 main view then the view is switched to the regular editing view.
166 void SwitchView (const model::SharedPageDescriptor& rpDescriptor);
168 void StartDrag (
169 const Point& rMousePosition,
170 const InsertionIndicatorHandler::Mode eMode);
172 bool IsMouseOverIndicatorAllowed() const { return mbIsMouseOverIndicatorAllowed;}
174 protected:
175 SlideSorter& mrSlideSorter;
176 SelectionFunction& mrSelectionFunction;
178 virtual bool ProcessButtonDownEvent (EventDescriptor& rDescriptor);
179 virtual bool ProcessButtonUpEvent (EventDescriptor& rDescriptor);
180 virtual bool ProcessMotionEvent (EventDescriptor& rDescriptor);
181 virtual bool ProcessDragEvent (EventDescriptor& rDescriptor);
182 virtual bool HandleUnprocessedEvent (EventDescriptor& rDescriptor);
184 void ReprocessEvent (EventDescriptor& rDescriptor);
186 private:
187 const bool mbIsMouseOverIndicatorAllowed;
190 /** This is the default handler for processing events. It activates the
191 multi selection or drag-and-drop when the right conditions are met.
193 class NormalModeHandler : public SelectionFunction::ModeHandler
195 public:
196 NormalModeHandler (
197 SlideSorter& rSlideSorter,
198 SelectionFunction& rSelectionFunction);
199 virtual ~NormalModeHandler();
201 virtual SelectionFunction::Mode GetMode() const SAL_OVERRIDE;
202 virtual void Abort() SAL_OVERRIDE;
204 void ResetButtonDownLocation();
206 protected:
207 virtual bool ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor) SAL_OVERRIDE;
208 virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor) SAL_OVERRIDE;
209 virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor) SAL_OVERRIDE;
210 virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) SAL_OVERRIDE;
212 private:
213 ::boost::optional<Point> maButtonDownLocation;
215 /** Select all pages between and including the selection anchor and the
216 specified page.
218 void RangeSelect (const model::SharedPageDescriptor& rpDescriptor);
221 /** Handle events during a multi selection, which typically is started by
222 pressing the left mouse button when not over a page.
224 class MultiSelectionModeHandler : public SelectionFunction::ModeHandler
226 public:
227 /** Start a rectangle selection at the given position.
229 MultiSelectionModeHandler (
230 SlideSorter& rSlideSorter,
231 SelectionFunction& rSelectionFunction,
232 #ifndef MACOSX
233 const Point& rMouseModelPosition);
234 #else
235 const Point& rMouseModelPosition,
236 const sal_uInt32 nEventCode);
237 #endif
238 virtual ~MultiSelectionModeHandler();
240 #ifndef MACOSX
241 void Initialize(const sal_uInt32 nEventCode);
242 #endif
244 virtual SelectionFunction::Mode GetMode() const SAL_OVERRIDE;
245 virtual void Abort() SAL_OVERRIDE;
246 virtual void ProcessEvent (SelectionFunction::EventDescriptor& rDescriptor) SAL_OVERRIDE;
248 enum SelectionMode { SM_Normal, SM_Add, SM_Toggle };
250 void SetSelectionMode (const SelectionMode eSelectionMode);
251 void SetSelectionModeFromModifier (const sal_uInt32 nEventCode);
253 protected:
254 virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor) SAL_OVERRIDE;
255 virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor) SAL_OVERRIDE;
256 virtual bool HandleUnprocessedEvent (SelectionFunction::EventDescriptor& rDescriptor) SAL_OVERRIDE;
258 private:
259 SelectionMode meSelectionMode;
260 Point maSecondCorner;
261 Pointer maSavedPointer;
262 bool mbAutoScrollInstalled;
263 sal_Int32 mnAnchorIndex;
264 sal_Int32 mnSecondIndex;
266 void UpdateModelPosition (const Point& rMouseModelPosition);
267 void UpdateSelection();
269 /** Update the rectangle selection so that the given position becomes
270 the new second point of the selection rectangle.
272 void UpdatePosition (
273 const Point& rMousePosition,
274 const bool bAllowAutoScroll);
276 void UpdateSelectionState (
277 const model::SharedPageDescriptor& rpDescriptor,
278 const bool bIsInSelection) const;
281 /** Handle events during drag-and-drop.
283 class DragAndDropModeHandler : public SelectionFunction::ModeHandler
285 public:
286 DragAndDropModeHandler (
287 SlideSorter& rSlideSorter,
288 #ifndef MACOSX
289 SelectionFunction& rSelectionFunction);
290 #else
291 SelectionFunction& rSelectionFunction,
292 const Point& rMousePosition,
293 vcl::Window* pWindow);
294 #endif
295 virtual ~DragAndDropModeHandler();
297 #ifndef MACOSX
298 void Initialize(const Point& rMousePosition, vcl::Window* pWindow);
299 #endif
301 virtual SelectionFunction::Mode GetMode() const SAL_OVERRIDE;
302 virtual void Abort() SAL_OVERRIDE;
304 protected:
305 virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor) SAL_OVERRIDE;
306 virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) SAL_OVERRIDE;
308 private:
309 ::boost::scoped_ptr<DragAndDropContext> mpDragAndDropContext;
312 //===== SelectionFunction =====================================================
314 TYPEINIT1(SelectionFunction, FuPoor);
316 SelectionFunction::SelectionFunction (
317 SlideSorter& rSlideSorter,
318 SfxRequest& rRequest)
319 : FuPoor (
320 rSlideSorter.GetViewShell(),
321 rSlideSorter.GetContentWindow(),
322 &rSlideSorter.GetView(),
323 rSlideSorter.GetModel().GetDocument(),
324 rRequest),
325 mrSlideSorter(rSlideSorter),
326 mrController(mrSlideSorter.GetController()),
327 mbDragSelection(false),
328 maInsertionMarkerBox(),
329 mbProcessingMouseButtonDown(false),
330 mnShiftKeySelectionAnchor(-1),
331 mpModeHandler(new NormalModeHandler(rSlideSorter, *this))
335 SelectionFunction::~SelectionFunction()
337 mpModeHandler.reset();
340 rtl::Reference<FuPoor> SelectionFunction::Create(
341 SlideSorter& rSlideSorter,
342 SfxRequest& rRequest)
344 rtl::Reference<FuPoor> xFunc( new SelectionFunction( rSlideSorter, rRequest ) );
345 return xFunc;
348 bool SelectionFunction::MouseButtonDown (const MouseEvent& rEvent)
350 // remember button state for creation of own MouseEvents
351 SetMouseButtonCode (rEvent.GetButtons());
352 aMDPos = rEvent.GetPosPixel();
353 mbProcessingMouseButtonDown = true;
355 // mpWindow->CaptureMouse();
357 ProcessMouseEvent(BUTTON_DOWN, rEvent);
359 return true;
362 bool SelectionFunction::MouseMove (const MouseEvent& rEvent)
364 ProcessMouseEvent(MOUSE_MOTION, rEvent);
365 return true;
368 bool SelectionFunction::MouseButtonUp (const MouseEvent& rEvent)
370 mrController.GetScrollBarManager().StopAutoScroll ();
372 ProcessMouseEvent(BUTTON_UP, rEvent);
374 mbProcessingMouseButtonDown = false;
376 return true;
379 void SelectionFunction::NotifyDragFinished()
381 SwitchToNormalMode();
384 bool SelectionFunction::KeyInput (const KeyEvent& rEvent)
386 view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter);
387 PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter);
388 PageSelector::UpdateLock aLock (mrSlideSorter);
389 FocusManager& rFocusManager (mrController.GetFocusManager());
390 bool bResult = false;
392 const vcl::KeyCode& rCode (rEvent.GetKeyCode());
393 switch (rCode.GetCode())
395 case KEY_RETURN:
397 model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor());
398 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
399 if (rFocusManager.HasFocus() && pDescriptor && pViewShell!=NULL)
401 // The Return key triggers different functions depending on
402 // whether the slide sorter is the main view or displayed in
403 // the right pane.
404 if (pViewShell->IsMainViewShell())
406 mpModeHandler->SetCurrentPage(pDescriptor);
407 mpModeHandler->SwitchView(pDescriptor);
409 else if (pViewShell->GetDispatcher() != NULL)
411 pViewShell->GetDispatcher()->Execute(
412 SID_INSERTPAGE,
413 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
415 bResult = true;
417 break;
420 case KEY_TAB:
421 if ( ! rFocusManager.IsFocusShowing())
423 rFocusManager.ShowFocus();
424 bResult = true;
426 break;
428 case KEY_ESCAPE:
429 // When there is an active multiselection or drag-and-drop
430 // operation then stop that.
431 mpModeHandler->Abort();
432 SwitchToNormalMode();
433 bResult = true;
434 break;
436 case KEY_SPACE:
438 // Toggle the selection state.
439 model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor());
440 if (pDescriptor && rCode.IsMod1())
442 if (pDescriptor->HasState(model::PageDescriptor::ST_Selected))
443 mrController.GetPageSelector().DeselectPage(pDescriptor, false);
444 else
445 mrController.GetPageSelector().SelectPage(pDescriptor);
447 bResult = true;
449 break;
451 // Move the focus indicator left.
452 case KEY_LEFT:
453 MoveFocus(FocusManager::FMD_LEFT, rCode.IsShift(), rCode.IsMod1());
454 bResult = true;
455 break;
457 // Move the focus indicator right.
458 case KEY_RIGHT:
459 MoveFocus(FocusManager::FMD_RIGHT, rCode.IsShift(), rCode.IsMod1());
460 bResult = true;
461 break;
463 // Move the focus indicator up.
464 case KEY_UP:
465 MoveFocus(FocusManager::FMD_UP, rCode.IsShift(), rCode.IsMod1());
466 bResult = true;
467 break;
469 // Move the focus indicator down.
470 case KEY_DOWN:
471 MoveFocus(FocusManager::FMD_DOWN, rCode.IsShift(), rCode.IsMod1());
472 bResult = true;
473 break;
475 // Go to previous page. No wrap around.
476 case KEY_PAGEUP:
477 GotoNextPage(-1);
478 bResult = true;
479 break;
481 // Go to next page. No wrap around..
482 case KEY_PAGEDOWN:
483 GotoNextPage(+1);
484 bResult = true;
485 break;
487 case KEY_HOME:
488 GotoPage(0);
489 bResult = true;
490 break;
492 case KEY_END:
493 GotoPage(mrSlideSorter.GetModel().GetPageCount()-1);
494 bResult = true;
495 break;
497 case KEY_DELETE:
498 case KEY_BACKSPACE:
500 if (mrSlideSorter.GetProperties()->IsUIReadOnly())
501 break;
503 mrController.GetSelectionManager()->DeleteSelectedPages(rCode.GetCode()==KEY_DELETE);
505 mnShiftKeySelectionAnchor = -1;
506 bResult = true;
508 break;
510 case KEY_F10:
511 if (rCode.IsShift())
513 mpModeHandler->SelectOnePage(
514 mrSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor());
516 break;
518 default:
519 break;
522 if ( ! bResult)
523 bResult = FuPoor::KeyInput(rEvent);
525 return bResult;
528 void SelectionFunction::MoveFocus (
529 const FocusManager::FocusMoveDirection eDirection,
530 const bool bIsShiftDown,
531 const bool bIsControlDown)
533 // Remember the anchor of shift key multi selection.
534 if (bIsShiftDown)
536 if (mnShiftKeySelectionAnchor<0)
538 model::SharedPageDescriptor pFocusedDescriptor (
539 mrController.GetFocusManager().GetFocusedPageDescriptor());
540 mnShiftKeySelectionAnchor = pFocusedDescriptor->GetPageIndex();
543 else if ( ! bIsControlDown)
544 ResetShiftKeySelectionAnchor();
546 mrController.GetFocusManager().MoveFocus(eDirection);
548 PageSelector& rSelector (mrController.GetPageSelector());
549 model::SharedPageDescriptor pFocusedDescriptor (
550 mrController.GetFocusManager().GetFocusedPageDescriptor());
551 if (bIsShiftDown)
553 // When shift is pressed then select all pages in the range between
554 // the currently and the previously focused pages, including them.
555 if (pFocusedDescriptor)
557 sal_Int32 nPageRangeEnd (pFocusedDescriptor->GetPageIndex());
558 model::PageEnumeration aPages (
559 model::PageEnumerationProvider::CreateAllPagesEnumeration(
560 mrSlideSorter.GetModel()));
561 while (aPages.HasMoreElements())
563 model::SharedPageDescriptor pDescriptor (aPages.GetNextElement());
564 if (pDescriptor)
566 const sal_Int32 nPageIndex(pDescriptor->GetPageIndex());
567 if ((nPageIndex>=mnShiftKeySelectionAnchor && nPageIndex<=nPageRangeEnd)
568 || (nPageIndex<=mnShiftKeySelectionAnchor && nPageIndex>=nPageRangeEnd))
570 rSelector.SelectPage(pDescriptor);
572 else
574 rSelector.DeselectPage(pDescriptor);
580 else if (bIsControlDown)
582 // When control is pressed then do not alter the selection or the
583 // current page, just move the focus.
585 else
587 // Without shift just select the focused page.
588 mpModeHandler->SelectOnePage(pFocusedDescriptor);
592 void SelectionFunction::Activate()
594 FuPoor::Activate();
597 void SelectionFunction::Deactivate()
599 FuPoor::Deactivate();
602 void SelectionFunction::DoCut()
604 if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly())
606 mrController.GetClipboard().DoCut();
610 void SelectionFunction::DoCopy()
612 mrController.GetClipboard().DoCopy();
615 void SelectionFunction::DoPaste()
617 if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly())
619 mrController.GetClipboard().DoPaste();
623 bool SelectionFunction::cancel()
625 mrController.GetFocusManager().ToggleFocus();
626 return true;
629 void SelectionFunction::GotoNextPage (int nOffset)
631 model::SharedPageDescriptor pDescriptor
632 = mrController.GetCurrentSlideManager()->GetCurrentSlide();
633 if (pDescriptor.get() != NULL)
635 SdPage* pPage = pDescriptor->GetPage();
636 OSL_ASSERT(pPage!=NULL);
637 sal_Int32 nIndex = (pPage->GetPageNum()-1) / 2;
638 GotoPage(nIndex + nOffset);
640 ResetShiftKeySelectionAnchor();
643 void SelectionFunction::GotoPage (int nIndex)
645 sal_uInt16 nPageCount = (sal_uInt16)mrSlideSorter.GetModel().GetPageCount();
647 if (nIndex >= nPageCount)
648 nIndex = nPageCount - 1;
649 if (nIndex < 0)
650 nIndex = 0;
652 mrController.GetFocusManager().SetFocusedPage(nIndex);
653 model::SharedPageDescriptor pNextPageDescriptor (
654 mrSlideSorter.GetModel().GetPageDescriptor (nIndex));
655 if (pNextPageDescriptor.get() != NULL)
656 mpModeHandler->SetCurrentPage(pNextPageDescriptor);
657 else
659 OSL_ASSERT(pNextPageDescriptor.get() != NULL);
661 ResetShiftKeySelectionAnchor();
664 void SelectionFunction::ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent)
666 // #95491# remember button state for creation of own MouseEvents
667 SetMouseButtonCode (rEvent.GetButtons());
669 EventDescriptor aEventDescriptor (nEventType, rEvent, mrSlideSorter);
670 ProcessEvent(aEventDescriptor);
673 void SelectionFunction::MouseDragged (
674 const AcceptDropEvent& rEvent,
675 const sal_Int8 nDragAction)
677 EventDescriptor aEventDescriptor (MOUSE_DRAG, rEvent, nDragAction, mrSlideSorter);
678 ProcessEvent(aEventDescriptor);
681 void SelectionFunction::ProcessEvent (EventDescriptor& rDescriptor)
683 // The call to ProcessEvent may switch to another mode handler.
684 // Prevent the untimely destruction of the called handler by acquiring a
685 // temporary reference here.
686 ::boost::shared_ptr<ModeHandler> pModeHandler (mpModeHandler);
687 pModeHandler->ProcessEvent(rDescriptor);
690 bool Match (
691 const sal_uInt32 nEventCode,
692 const sal_uInt32 nPositivePattern)
694 return (nEventCode & nPositivePattern)==nPositivePattern;
697 void SelectionFunction::SwitchToNormalMode()
699 if (mpModeHandler->GetMode() != NormalMode)
700 SwitchMode(::boost::shared_ptr<ModeHandler>(
701 new NormalModeHandler(mrSlideSorter, *this)));
704 void SelectionFunction::SwitchToDragAndDropMode (const Point& rMousePosition)
706 if (mpModeHandler->GetMode() != DragAndDropMode)
708 #ifndef MACOSX
709 ::boost::shared_ptr<DragAndDropModeHandler> handler(
710 new DragAndDropModeHandler(mrSlideSorter, *this));
711 SwitchMode(handler);
712 // Delayed initialization, only after mpModeHanler is set, otherwise DND initialization
713 // could already trigger DND events, which would recursively trigger this code again,
714 // and without mpModeHandler set it would again try to set a new handler.
715 handler->Initialize(rMousePosition, mpWindow);
716 #else
717 SwitchMode(::boost::shared_ptr<ModeHandler>(
718 new DragAndDropModeHandler(mrSlideSorter, *this, rMousePosition, mpWindow)));
719 #endif
723 void SelectionFunction::SwitchToMultiSelectionMode (
724 const Point& rMousePosition,
725 const sal_uInt32 nEventCode)
727 if (mpModeHandler->GetMode() != MultiSelectionMode)
728 #ifndef MACOSX
730 ::boost::shared_ptr<MultiSelectionModeHandler> handler(
731 new MultiSelectionModeHandler(mrSlideSorter, *this, rMousePosition));
732 SwitchMode(handler);
733 // Delayed initialization, only after mpModeHanler is set, the handle ctor
734 // is non-trivial, so it could possibly recurse just like the DND handler above.
735 handler->Initialize(nEventCode);
737 #else
738 SwitchMode(::boost::shared_ptr<ModeHandler>(
739 new MultiSelectionModeHandler(mrSlideSorter, *this, rMousePosition, nEventCode)));
740 #endif
743 void SelectionFunction::SwitchMode (const ::boost::shared_ptr<ModeHandler>& rpHandler)
745 // Not all modes allow mouse over indicator.
746 if (mpModeHandler->IsMouseOverIndicatorAllowed() != rpHandler->IsMouseOverIndicatorAllowed())
748 if ( ! rpHandler->IsMouseOverIndicatorAllowed())
750 mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor());
752 else
753 mrSlideSorter.GetView().UpdatePageUnderMouse();
756 mpModeHandler = rpHandler;
759 void SelectionFunction::ResetShiftKeySelectionAnchor()
761 mnShiftKeySelectionAnchor = -1;
764 void SelectionFunction::ResetMouseAnchor()
766 if (mpModeHandler && mpModeHandler->GetMode() == NormalMode)
768 ::boost::shared_ptr<NormalModeHandler> pHandler (
769 ::boost::dynamic_pointer_cast<NormalModeHandler>(mpModeHandler));
770 if (pHandler)
771 pHandler->ResetButtonDownLocation();
775 //===== EventDescriptor =======================================================
777 SelectionFunction::EventDescriptor::EventDescriptor (
778 const sal_uInt32 nEventType,
779 const MouseEvent& rEvent,
780 SlideSorter& rSlideSorter)
781 : maMousePosition(rEvent.GetPosPixel()),
782 maMouseModelPosition(),
783 mpHitDescriptor(),
784 mpHitPage(),
785 mnEventCode(nEventType),
786 meDragMode(InsertionIndicatorHandler::MoveMode),
787 mbMakeSelectionVisible(true),
788 mbIsLeaving(false)
790 maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition);
791 mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition);
792 if (mpHitDescriptor)
794 mpHitPage = mpHitDescriptor->GetPage();
797 mnEventCode |= EncodeMouseEvent(rEvent);
798 mnEventCode |= EncodeState();
800 // Detect the mouse leaving the window. When not button is pressed then
801 // we can call IsLeaveWindow at the event. Otherwise we have to make an
802 // explicit test.
803 mbIsLeaving = rEvent.IsLeaveWindow()
804 || ! Rectangle(Point(0,0),
805 rSlideSorter.GetContentWindow()->GetOutputSizePixel()).IsInside(maMousePosition);
808 SelectionFunction::EventDescriptor::EventDescriptor (
809 const sal_uInt32 nEventType,
810 const AcceptDropEvent& rEvent,
811 const sal_Int8 nDragAction,
812 SlideSorter& rSlideSorter)
813 : maMousePosition(rEvent.maPosPixel),
814 maMouseModelPosition(),
815 mpHitDescriptor(),
816 mpHitPage(),
817 mnEventCode(nEventType),
818 meDragMode(InsertionIndicatorHandler::GetModeFromDndAction(nDragAction)),
819 mbMakeSelectionVisible(true),
820 mbIsLeaving(false)
822 maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition);
823 mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition);
824 if (mpHitDescriptor)
826 mpHitPage = mpHitDescriptor->GetPage();
829 mnEventCode |= EncodeState();
831 // Detect the mouse leaving the window. When not button is pressed then
832 // we can call IsLeaveWindow at the event. Otherwise we have to make an
833 // explicit test.
834 mbIsLeaving = rEvent.mbLeaving
835 || ! Rectangle(Point(0,0),
836 rSlideSorter.GetContentWindow()->GetOutputSizePixel()).IsInside(maMousePosition);
839 sal_uInt32 SelectionFunction::EventDescriptor::EncodeMouseEvent (
840 const MouseEvent& rEvent) const
842 // Initialize with the type of mouse event.
843 sal_uInt32 nEventCode (mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION));
845 // Detect the affected button.
846 switch (rEvent.GetButtons())
848 case MOUSE_LEFT: nEventCode |= LEFT_BUTTON; break;
849 case MOUSE_RIGHT: nEventCode |= RIGHT_BUTTON; break;
850 case MOUSE_MIDDLE: nEventCode |= MIDDLE_BUTTON; break;
853 // Detect the number of clicks.
854 switch (rEvent.GetClicks())
856 case 1: nEventCode |= SINGLE_CLICK; break;
857 case 2: nEventCode |= DOUBLE_CLICK; break;
860 // Detect pressed modifier keys.
861 if (rEvent.IsShift())
862 nEventCode |= SHIFT_MODIFIER;
863 if (rEvent.IsMod1())
864 nEventCode |= CONTROL_MODIFIER;
866 return nEventCode;
869 sal_uInt32 SelectionFunction::EventDescriptor::EncodeState() const
871 sal_uInt32 nEventCode (0);
873 // Detect whether the event has happened over a page object.
874 if (mpHitPage!=NULL && mpHitDescriptor)
876 if (mpHitDescriptor->HasState(model::PageDescriptor::ST_Selected))
877 nEventCode |= OVER_SELECTED_PAGE;
878 else
879 nEventCode |= OVER_UNSELECTED_PAGE;
882 return nEventCode;
885 //===== SelectionFunction::ModeHandler ========================================
887 SelectionFunction::ModeHandler::ModeHandler (
888 SlideSorter& rSlideSorter,
889 SelectionFunction& rSelectionFunction,
890 const bool bIsMouseOverIndicatorAllowed)
891 : mrSlideSorter(rSlideSorter),
892 mrSelectionFunction(rSelectionFunction),
893 mbIsMouseOverIndicatorAllowed(bIsMouseOverIndicatorAllowed)
897 SelectionFunction::ModeHandler::~ModeHandler()
901 void SelectionFunction::ModeHandler::ReprocessEvent (EventDescriptor& rDescriptor)
903 mrSelectionFunction.ProcessEvent(rDescriptor);
906 void SelectionFunction::ModeHandler::ProcessEvent (
907 SelectionFunction::EventDescriptor& rDescriptor)
909 PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter);
910 PageSelector::UpdateLock aUpdateLock (mrSlideSorter);
912 bool bIsProcessed (false);
913 switch (rDescriptor.mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION | MOUSE_DRAG))
915 case BUTTON_DOWN:
916 bIsProcessed = ProcessButtonDownEvent(rDescriptor);
917 break;
919 case BUTTON_UP:
920 bIsProcessed = ProcessButtonUpEvent(rDescriptor);
921 break;
923 case MOUSE_MOTION:
924 bIsProcessed = ProcessMotionEvent(rDescriptor);
925 break;
927 case MOUSE_DRAG:
928 bIsProcessed = ProcessDragEvent(rDescriptor);
929 break;
932 if ( ! bIsProcessed)
933 HandleUnprocessedEvent(rDescriptor);
936 bool SelectionFunction::ModeHandler::ProcessButtonDownEvent (EventDescriptor&)
938 return false;
941 bool SelectionFunction::ModeHandler::ProcessButtonUpEvent (EventDescriptor&)
943 mrSelectionFunction.SwitchToNormalMode();
944 return false;
947 bool SelectionFunction::ModeHandler::ProcessMotionEvent (EventDescriptor& rDescriptor)
949 if (mbIsMouseOverIndicatorAllowed)
950 mrSlideSorter.GetView().UpdatePageUnderMouse(rDescriptor.maMousePosition);
952 if (rDescriptor.mbIsLeaving)
954 mrSelectionFunction.SwitchToNormalMode();
955 mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor());
957 return true;
959 else
960 return false;
963 bool SelectionFunction::ModeHandler::ProcessDragEvent (EventDescriptor&)
965 return false;
968 bool SelectionFunction::ModeHandler::HandleUnprocessedEvent (EventDescriptor&)
970 return false;
973 void SelectionFunction::ModeHandler::SetCurrentPage (
974 const model::SharedPageDescriptor& rpDescriptor)
976 SelectOnePage(rpDescriptor);
977 mrSlideSorter.GetController().GetCurrentSlideManager()->SwitchCurrentSlide(rpDescriptor);
980 void SelectionFunction::ModeHandler::DeselectAllPages()
982 mrSlideSorter.GetController().GetPageSelector().DeselectAllPages();
983 mrSelectionFunction.ResetShiftKeySelectionAnchor();
986 void SelectionFunction::ModeHandler::SelectOnePage (
987 const model::SharedPageDescriptor& rpDescriptor)
989 DeselectAllPages();
990 mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor);
993 void SelectionFunction::ModeHandler::SwitchView (const model::SharedPageDescriptor& rpDescriptor)
995 // Switch to the draw view. This is done only when the current
996 // view is the main view.
997 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
998 if (pViewShell!=NULL && pViewShell->IsMainViewShell())
1000 if (rpDescriptor.get()!=NULL && rpDescriptor->GetPage()!=NULL)
1002 mrSlideSorter.GetModel().GetDocument()->SetSelected(rpDescriptor->GetPage(), true);
1003 pViewShell->GetFrameView()->SetSelectedPage(
1004 (rpDescriptor->GetPage()->GetPageNum()-1)/2);
1006 if (mrSlideSorter.GetViewShellBase() != NULL)
1007 framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase())->RequestView(
1008 framework::FrameworkHelper::msImpressViewURL,
1009 framework::FrameworkHelper::msCenterPaneURL);
1013 void SelectionFunction::ModeHandler::StartDrag (
1014 const Point& rMousePosition,
1015 const InsertionIndicatorHandler::Mode eMode)
1017 (void)eMode;
1018 // Do not start a drag-and-drop operation when one is already active.
1019 // (when dragging pages from one document into another, pressing a
1020 // modifier key can trigger a MouseMotion event in the originating
1021 // window (focus still in there). Together with the mouse button pressed
1022 // (drag-and-drop is active) this triggers the start of drag-and-drop.)
1023 if (SD_MOD()->pTransferDrag != NULL)
1024 return;
1026 if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly())
1028 mrSelectionFunction.SwitchToDragAndDropMode(rMousePosition);
1032 //===== NormalModeHandler =====================================================
1034 NormalModeHandler::NormalModeHandler (
1035 SlideSorter& rSlideSorter,
1036 SelectionFunction& rSelectionFunction)
1037 : ModeHandler(rSlideSorter, rSelectionFunction, true),
1038 maButtonDownLocation()
1042 NormalModeHandler::~NormalModeHandler()
1046 SelectionFunction::Mode NormalModeHandler::GetMode() const
1048 return SelectionFunction::NormalMode;
1051 void NormalModeHandler::Abort()
1055 bool NormalModeHandler::ProcessButtonDownEvent (
1056 SelectionFunction::EventDescriptor& rDescriptor)
1058 // Remember the location where the left button is pressed. With
1059 // that we can filter away motion events that are caused by key
1060 // presses. We also can tune the minimal motion distance that
1061 // triggers a drag-and-drop operation.
1062 if ((rDescriptor.mnEventCode & BUTTON_DOWN) != 0)
1063 maButtonDownLocation = rDescriptor.maMousePosition;
1065 switch (rDescriptor.mnEventCode)
1067 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE:
1068 SetCurrentPage(rDescriptor.mpHitDescriptor);
1069 break;
1071 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
1072 break;
1074 case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_SELECTED_PAGE:
1075 case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_UNSELECTED_PAGE:
1076 // A double click always shows the selected slide in the center
1077 // pane in an edit view.
1078 SetCurrentPage(rDescriptor.mpHitDescriptor);
1079 SwitchView(rDescriptor.mpHitDescriptor);
1080 break;
1082 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | SHIFT_MODIFIER:
1083 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | SHIFT_MODIFIER:
1084 // Range selection with the shift modifier.
1085 RangeSelect(rDescriptor.mpHitDescriptor);
1086 break;
1088 // Right button for context menu.
1089 case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE:
1090 // Single right click and shift+F10 select as preparation to
1091 // show the context menu. Change the selection only when the
1092 // page under the mouse is not selected. In this case the
1093 // selection is set to this single page. Otherwise the
1094 // selection is not modified.
1095 SetCurrentPage(rDescriptor.mpHitDescriptor);
1096 rDescriptor.mbMakeSelectionVisible = false;
1097 break;
1099 case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
1100 // Do not change the selection. Just adjust the insertion indicator.
1101 rDescriptor.mbMakeSelectionVisible = false;
1102 break;
1104 case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE:
1105 // Remember the current selection so that when a multi selection
1106 // is started, we can restore the previous selection.
1107 mrSlideSorter.GetModel().SaveCurrentSelection();
1108 DeselectAllPages();
1109 break;
1111 case ANY_MODIFIER(BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE):
1112 // Remember the current selection so that when a multi selection
1113 // is started, we can restore the previous selection.
1114 mrSlideSorter.GetModel().SaveCurrentSelection();
1115 DeselectAllPages();
1116 break;
1118 case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | NOT_OVER_PAGE:
1120 // Insert a new slide:
1121 // First of all we need to set the insertion indicator which sets the
1122 // position where the new slide will be inserted.
1123 ::boost::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler
1124 = mrSlideSorter.GetController().GetInsertionIndicatorHandler();
1126 pInsertionIndicatorHandler->Start(false);
1127 pInsertionIndicatorHandler->UpdatePosition(
1128 rDescriptor.maMousePosition,
1129 InsertionIndicatorHandler::MoveMode);
1130 mrSlideSorter.GetController().GetSelectionManager()->SetInsertionPosition(
1131 pInsertionIndicatorHandler->GetInsertionPageIndex());
1133 mrSlideSorter.GetViewShell()->GetDispatcher()->Execute(
1134 SID_INSERTPAGE,
1135 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
1136 break;
1139 default:
1140 return false;
1142 return true;
1145 bool NormalModeHandler::ProcessButtonUpEvent (
1146 SelectionFunction::EventDescriptor& rDescriptor)
1148 bool bIsProcessed (true);
1149 switch (rDescriptor.mnEventCode)
1151 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
1152 SetCurrentPage(rDescriptor.mpHitDescriptor);
1153 break;
1155 // Multi selection with the control modifier.
1156 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | CONTROL_MODIFIER:
1157 mrSlideSorter.GetController().GetPageSelector().DeselectPage(
1158 rDescriptor.mpHitDescriptor);
1159 break;
1161 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | CONTROL_MODIFIER:
1162 mrSlideSorter.GetController().GetPageSelector().SelectPage(
1163 rDescriptor.mpHitDescriptor);
1164 mrSlideSorter.GetView().SetPageUnderMouse(rDescriptor.mpHitDescriptor);
1165 break;
1166 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE:
1167 break;
1169 default:
1170 bIsProcessed = false;
1171 break;
1173 mrSelectionFunction.SwitchToNormalMode();
1174 return bIsProcessed;
1177 bool NormalModeHandler::ProcessMotionEvent (
1178 SelectionFunction::EventDescriptor& rDescriptor)
1180 if (ModeHandler::ProcessMotionEvent(rDescriptor))
1181 return true;
1183 bool bIsProcessed (true);
1184 switch (rDescriptor.mnEventCode)
1186 case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE):
1187 // SetCurrentPage(rDescriptor.mpHitDescriptor);
1188 // Fallthrough
1190 // A mouse motion without visible substitution starts that.
1191 case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE):
1193 if (maButtonDownLocation)
1195 const sal_Int32 nDistance (maButtonDownLocation
1196 ? ::std::max (
1197 std::abs(maButtonDownLocation->X() - rDescriptor.maMousePosition.X()),
1198 std::abs(maButtonDownLocation->Y() - rDescriptor.maMousePosition.Y()))
1199 : 0);
1200 if (nDistance > 3)
1201 StartDrag(
1202 rDescriptor.maMousePosition,
1203 (rDescriptor.mnEventCode & CONTROL_MODIFIER) != 0
1204 ? InsertionIndicatorHandler::CopyMode
1205 : InsertionIndicatorHandler::MoveMode);
1208 break;
1210 // A mouse motion not over a page starts a rectangle selection.
1211 case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE):
1212 mrSelectionFunction.SwitchToMultiSelectionMode(
1213 rDescriptor.maMouseModelPosition,
1214 rDescriptor.mnEventCode);
1215 break;
1217 default:
1218 bIsProcessed = false;
1219 break;
1221 return bIsProcessed;
1224 bool NormalModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor)
1226 mrSelectionFunction.SwitchToDragAndDropMode(rDescriptor.maMousePosition);
1227 ReprocessEvent(rDescriptor);
1228 return true;
1231 void NormalModeHandler::RangeSelect (const model::SharedPageDescriptor& rpDescriptor)
1233 PageSelector::UpdateLock aLock (mrSlideSorter);
1234 PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector());
1236 model::SharedPageDescriptor pAnchor (rSelector.GetSelectionAnchor());
1237 DeselectAllPages();
1239 if (pAnchor.get() != NULL)
1241 // Select all pages between the anchor and the given one, including
1242 // the two.
1243 const sal_uInt16 nAnchorIndex ((pAnchor->GetPage()->GetPageNum()-1) / 2);
1244 const sal_uInt16 nOtherIndex ((rpDescriptor->GetPage()->GetPageNum()-1) / 2);
1246 // Iterate over all pages in the range. Start with the anchor
1247 // page. This way the PageSelector will recognize it again as
1248 // anchor (the first selected page after a DeselectAllPages()
1249 // becomes the anchor.)
1250 const sal_uInt16 nStep ((nAnchorIndex < nOtherIndex) ? +1 : -1);
1251 sal_uInt16 nIndex (nAnchorIndex);
1252 while (true)
1254 rSelector.SelectPage(nIndex);
1255 if (nIndex == nOtherIndex)
1256 break;
1257 nIndex = nIndex + nStep;
1262 void NormalModeHandler::ResetButtonDownLocation()
1264 maButtonDownLocation = ::boost::optional<Point>();
1267 //===== MultiSelectionModeHandler =============================================
1269 MultiSelectionModeHandler::MultiSelectionModeHandler (
1270 SlideSorter& rSlideSorter,
1271 SelectionFunction& rSelectionFunction,
1272 #ifndef MACOSX
1273 const Point& rMouseModelPosition)
1274 #else
1275 const Point& rMouseModelPosition,
1276 const sal_uInt32 nEventCode)
1277 #endif
1278 : ModeHandler(rSlideSorter, rSelectionFunction, false),
1279 meSelectionMode(SM_Normal),
1280 maSecondCorner(rMouseModelPosition),
1281 maSavedPointer(mrSlideSorter.GetContentWindow()->GetPointer()),
1282 mbAutoScrollInstalled(false),
1283 mnAnchorIndex(-1),
1284 mnSecondIndex(-1)
1286 #ifndef MACOSX
1289 void MultiSelectionModeHandler::Initialize(const sal_uInt32 nEventCode)
1291 #endif
1292 const Pointer aSelectionPointer (PointerStyle::Text);
1293 mrSlideSorter.GetContentWindow()->SetPointer(aSelectionPointer);
1294 SetSelectionModeFromModifier(nEventCode);
1297 MultiSelectionModeHandler::~MultiSelectionModeHandler()
1299 if (mbAutoScrollInstalled)
1301 //a call to this handler's MultiSelectionModeHandler::UpdatePosition
1302 //may be still waiting to be called back
1303 mrSlideSorter.GetController().GetScrollBarManager().clearAutoScrollFunctor();
1305 mrSlideSorter.GetContentWindow()->SetPointer(maSavedPointer);
1308 SelectionFunction::Mode MultiSelectionModeHandler::GetMode() const
1310 return SelectionFunction::MultiSelectionMode;
1313 void MultiSelectionModeHandler::Abort()
1315 mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection());
1318 void MultiSelectionModeHandler::ProcessEvent (
1319 SelectionFunction::EventDescriptor& rDescriptor)
1321 // During a multi selection we do not want sudden jumps of the
1322 // visible area caused by moving newly selected pages into view.
1323 // Therefore disable that temporarily. The disabler object is
1324 // released at the end of the event processing, after the focus and
1325 // current slide have been updated.
1326 VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter);
1328 ModeHandler::ProcessEvent(rDescriptor);
1331 bool MultiSelectionModeHandler::ProcessButtonUpEvent (
1332 SelectionFunction::EventDescriptor& rDescriptor)
1334 if (mbAutoScrollInstalled)
1336 //a call to this handler's MultiSelectionModeHandler::UpdatePosition
1337 //may be still waiting to be called back
1338 mrSlideSorter.GetController().GetScrollBarManager().clearAutoScrollFunctor();
1339 mbAutoScrollInstalled = false;
1342 if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK))
1344 mrSelectionFunction.SwitchToNormalMode();
1345 return true;
1347 else
1348 return false;
1351 bool MultiSelectionModeHandler::ProcessMotionEvent (
1352 SelectionFunction::EventDescriptor& rDescriptor)
1354 // The selection rectangle is visible. Handle events accordingly.
1355 if (Match(rDescriptor.mnEventCode, MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK))
1357 SetSelectionModeFromModifier(rDescriptor.mnEventCode);
1358 UpdatePosition(rDescriptor.maMousePosition, true);
1359 rDescriptor.mbMakeSelectionVisible = false;
1360 return true;
1362 else
1363 return false;
1366 bool MultiSelectionModeHandler::HandleUnprocessedEvent (
1367 SelectionFunction::EventDescriptor& rDescriptor)
1369 if ( ! ModeHandler::HandleUnprocessedEvent(rDescriptor))
1371 // If the event has not been processed then stop multi selection.
1372 mrSelectionFunction.SwitchToNormalMode();
1373 ReprocessEvent(rDescriptor);
1375 return true;
1378 void MultiSelectionModeHandler::UpdatePosition (
1379 const Point& rMousePosition,
1380 const bool bAllowAutoScroll)
1382 VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter);
1384 // Convert window coordinates into model coordinates (we need the
1385 // window coordinates for auto-scrolling because that remains
1386 // constant while scrolling.)
1387 sd::Window *pWindow (mrSlideSorter.GetContentWindow());
1388 const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition));
1390 bool bDoAutoScroll = bAllowAutoScroll && mrSlideSorter.GetController().GetScrollBarManager().AutoScroll(
1391 rMousePosition,
1392 ::boost::bind(
1393 &MultiSelectionModeHandler::UpdatePosition,
1394 this,
1395 rMousePosition,
1396 false));
1398 if (!bDoAutoScroll)
1399 UpdateModelPosition(aMouseModelPosition);
1401 mbAutoScrollInstalled |= bDoAutoScroll;
1404 void MultiSelectionModeHandler::SetSelectionModeFromModifier (
1405 const sal_uInt32 nEventCode)
1407 switch (nEventCode & MODIFIER_MASK)
1409 case NO_MODIFIER:
1410 SetSelectionMode(SM_Normal);
1411 break;
1413 case SHIFT_MODIFIER:
1414 SetSelectionMode(SM_Add);
1415 break;
1417 case CONTROL_MODIFIER:
1418 SetSelectionMode(SM_Toggle);
1419 break;
1423 void MultiSelectionModeHandler::SetSelectionMode (const SelectionMode eSelectionMode)
1425 if (meSelectionMode != eSelectionMode)
1427 meSelectionMode = eSelectionMode;
1428 UpdateSelection();
1432 void MultiSelectionModeHandler::UpdateSelectionState (
1433 const model::SharedPageDescriptor& rpDescriptor,
1434 const bool bIsInSelection) const
1436 // Determine whether the page was selected before the rectangle
1437 // selection was started.
1438 const bool bWasSelected (rpDescriptor->HasState(model::PageDescriptor::ST_WasSelected));
1440 // Combine the two selection states depending on the selection mode.
1441 bool bSelect (false);
1442 switch(meSelectionMode)
1444 case SM_Normal:
1445 bSelect = bIsInSelection;
1446 break;
1448 case SM_Add:
1449 bSelect = bIsInSelection || bWasSelected;
1450 break;
1452 case SM_Toggle:
1453 if (bIsInSelection)
1454 bSelect = !bWasSelected;
1455 else
1456 bSelect = bWasSelected;
1457 break;
1460 // Set the new selection state.
1461 if (bSelect)
1462 mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor);
1463 else
1464 mrSlideSorter.GetController().GetPageSelector().DeselectPage(rpDescriptor);
1467 void MultiSelectionModeHandler::UpdateModelPosition (const Point& rMouseModelPosition)
1469 maSecondCorner = rMouseModelPosition;
1470 UpdateSelection();
1473 void MultiSelectionModeHandler::UpdateSelection()
1475 view::SlideSorterView::DrawLock aLock (mrSlideSorter);
1477 model::SlideSorterModel& rModel (mrSlideSorter.GetModel());
1478 const sal_Int32 nPageCount (rModel.GetPageCount());
1480 const sal_Int32 nIndexUnderMouse (
1481 mrSlideSorter.GetView().GetLayouter().GetIndexAtPoint (
1482 maSecondCorner,
1483 false,
1484 false));
1485 if (nIndexUnderMouse>=0 && nIndexUnderMouse<nPageCount)
1487 if (mnAnchorIndex < 0)
1488 mnAnchorIndex = nIndexUnderMouse;
1489 mnSecondIndex = nIndexUnderMouse;
1491 Range aRange (mnAnchorIndex, mnSecondIndex);
1492 aRange.Justify();
1494 for (sal_Int32 nIndex=0; nIndex<nPageCount; ++nIndex)
1496 UpdateSelectionState(rModel.GetPageDescriptor(nIndex), aRange.IsInside(nIndex));
1501 //===== DragAndDropModeHandler ================================================
1503 DragAndDropModeHandler::DragAndDropModeHandler (
1504 SlideSorter& rSlideSorter,
1505 #ifndef MACOSX
1506 SelectionFunction& rSelectionFunction)
1507 #else
1508 SelectionFunction& rSelectionFunction,
1509 const Point& rMousePosition,
1510 vcl::Window* pWindow)
1511 #endif
1512 : ModeHandler(rSlideSorter, rSelectionFunction, false)
1514 #ifndef MACOSX
1517 void DragAndDropModeHandler::Initialize(const Point& rMousePosition, vcl::Window* pWindow)
1519 #endif
1520 SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
1521 if (pDragTransferable==NULL && mrSlideSorter.GetViewShell() != NULL)
1523 SlideSorterViewShell* pSlideSorterViewShell
1524 = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell());
1525 if (pSlideSorterViewShell != NULL)
1526 pSlideSorterViewShell->StartDrag(rMousePosition, pWindow);
1527 pDragTransferable = SD_MOD()->pTransferDrag;
1530 mpDragAndDropContext.reset(new DragAndDropContext(mrSlideSorter));
1531 mrSlideSorter.GetController().GetInsertionIndicatorHandler()->Start(
1532 pDragTransferable != NULL
1533 && pDragTransferable->GetView()==&mrSlideSorter.GetView());
1536 DragAndDropModeHandler::~DragAndDropModeHandler()
1538 if (mpDragAndDropContext)
1540 // Disconnect the substitution handler from this selection function.
1541 mpDragAndDropContext->SetTargetSlideSorter();
1542 mpDragAndDropContext.reset();
1544 mrSlideSorter.GetController().GetInsertionIndicatorHandler()->End(Animator::AM_Animated);
1547 SelectionFunction::Mode DragAndDropModeHandler::GetMode() const
1549 return SelectionFunction::DragAndDropMode;
1552 void DragAndDropModeHandler::Abort()
1554 mrSlideSorter.GetController().GetClipboard().Abort();
1555 if (mpDragAndDropContext)
1556 mpDragAndDropContext->Dispose();
1557 // mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection());
1560 bool DragAndDropModeHandler::ProcessButtonUpEvent (
1561 SelectionFunction::EventDescriptor& rDescriptor)
1563 if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON))
1565 // The following Process() call may lead to the destruction
1566 // of rDescriptor.mpHitDescriptor so release our reference to it.
1567 rDescriptor.mpHitDescriptor.reset();
1568 mrSelectionFunction.SwitchToNormalMode();
1569 return true;
1571 else
1572 return false;
1575 bool DragAndDropModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor)
1577 OSL_ASSERT(mpDragAndDropContext);
1579 if (rDescriptor.mbIsLeaving)
1581 mrSelectionFunction.SwitchToNormalMode();
1583 else if (mpDragAndDropContext)
1585 mpDragAndDropContext->UpdatePosition(
1586 rDescriptor.maMousePosition,
1587 rDescriptor.meDragMode);
1590 return true;
1593 } } } // end of namespace ::sd::slidesorter::controller
1595 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */