android: Update app-specific/MIME type icons
[LibreOffice.git] / sd / source / ui / slidesorter / controller / SlsSelectionFunction.cxx
blob450fdd294a559372dddbabe9f061d3f319750f98
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 <memory>
21 #include <sal/config.h>
23 #include <controller/SlsSelectionFunction.hxx>
25 #include <SlideSorter.hxx>
26 #include <SlideSorterViewShell.hxx>
27 #include "SlsDragAndDropContext.hxx"
28 #include <controller/SlideSorterController.hxx>
29 #include <controller/SlsPageSelector.hxx>
30 #include <controller/SlsFocusManager.hxx>
31 #include <controller/SlsScrollBarManager.hxx>
32 #include <controller/SlsClipboard.hxx>
33 #include <controller/SlsCurrentSlideManager.hxx>
34 #include <controller/SlsInsertionIndicatorHandler.hxx>
35 #include <controller/SlsSelectionManager.hxx>
36 #include <controller/SlsProperties.hxx>
37 #include <controller/SlsVisibleAreaManager.hxx>
38 #include <model/SlideSorterModel.hxx>
39 #include <model/SlsPageDescriptor.hxx>
40 #include <model/SlsPageEnumerationProvider.hxx>
41 #include <view/SlideSorterView.hxx>
42 #include <view/SlsLayouter.hxx>
43 #include <framework/FrameworkHelper.hxx>
44 #include <osl/diagnose.h>
45 #include <Window.hxx>
46 #include <sdpage.hxx>
47 #include <drawdoc.hxx>
48 #include <sdxfer.hxx>
49 #include <ViewShell.hxx>
50 #include <FrameView.hxx>
51 #include <app.hrc>
52 #include <o3tl/deleter.hxx>
53 #include <sfx2/dispatch.hxx>
54 #include <vcl/ptrstyle.hxx>
55 #include <optional>
56 #include <sdmod.hxx>
58 namespace {
59 const sal_uInt32 SINGLE_CLICK (0x00000001);
60 const sal_uInt32 DOUBLE_CLICK (0x00000002);
61 const sal_uInt32 LEFT_BUTTON (0x00000010);
62 const sal_uInt32 RIGHT_BUTTON (0x00000020);
63 const sal_uInt32 MIDDLE_BUTTON (0x00000040);
64 const sal_uInt32 BUTTON_DOWN (0x00000100);
65 const sal_uInt32 BUTTON_UP (0x00000200);
66 const sal_uInt32 MOUSE_MOTION (0x00000400);
67 const sal_uInt32 MOUSE_DRAG (0x00000800);
68 // The rest leaves the lower 16 bit untouched so that it can be used with
69 // key codes.
70 const sal_uInt32 OVER_SELECTED_PAGE (0x00010000);
71 const sal_uInt32 OVER_UNSELECTED_PAGE (0x00020000);
72 const sal_uInt32 SHIFT_MODIFIER (0x00200000);
73 const sal_uInt32 CONTROL_MODIFIER (0x00400000);
75 // Some absent events are defined so they can be expressed explicitly.
76 const sal_uInt32 NO_MODIFIER (0x00000000);
77 const sal_uInt32 NOT_OVER_PAGE (0x00000000);
79 // Masks
80 const sal_uInt32 MODIFIER_MASK (SHIFT_MODIFIER | CONTROL_MODIFIER);
82 } // end of anonymous namespace
84 // Define some macros to make the following switch statement more readable.
85 #define ANY_MODIFIER(code) \
86 code|NO_MODIFIER: \
87 case code|SHIFT_MODIFIER: \
88 case code|CONTROL_MODIFIER
90 namespace sd::slidesorter::controller {
92 //===== SelectionFunction::EventDescriptor ====================================
94 class SelectionFunction::EventDescriptor
96 public:
97 Point maMousePosition;
98 Point maMouseModelPosition;
99 model::SharedPageDescriptor mpHitDescriptor;
100 SdrPage* mpHitPage;
101 sal_uInt32 mnEventCode;
102 InsertionIndicatorHandler::Mode meDragMode;
103 bool mbIsLeaving;
105 EventDescriptor (
106 sal_uInt32 nEventType,
107 const MouseEvent& rEvent,
108 SlideSorter const & rSlideSorter);
109 EventDescriptor (
110 sal_uInt32 nEventType,
111 const AcceptDropEvent& rEvent,
112 const sal_Int8 nDragAction,
113 SlideSorter const & rSlideSorter);
115 private:
116 /** Compute a numerical code that describes a mouse event and that can
117 be used for fast look up of the appropriate reaction.
119 sal_uInt32 EncodeMouseEvent (const MouseEvent& rEvent) const;
121 /** Compute a numerical code that describes the current state like
122 whether the selection rectangle is visible or whether the page under
123 the mouse or the one that has the focus is selected.
125 sal_uInt32 EncodeState() const;
128 //===== SelectionFunction::ModeHandler ========================================
130 class SelectionFunction::ModeHandler
132 public:
133 ModeHandler (
134 SlideSorter& rSlideSorter,
135 SelectionFunction& rSelectionFunction,
136 const bool bIsMouseOverIndicatorAllowed);
137 virtual ~ModeHandler() COVERITY_NOEXCEPT_FALSE;
139 virtual Mode GetMode() const = 0;
140 virtual void Abort() = 0;
141 virtual void ProcessEvent (EventDescriptor& rDescriptor);
143 /** Set the selection to exactly the specified page and also set it as
144 the current page.
146 void SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor);
148 /// Deselect all pages.
149 void DeselectAllPages();
150 void SelectOnePage (const model::SharedPageDescriptor& rpDescriptor);
152 /** When the view on which this selection function is working is the
153 main view then the view is switched to the regular editing view.
155 void SwitchView (const model::SharedPageDescriptor& rpDescriptor);
157 void StartDrag (
158 const Point& rMousePosition);
160 bool IsMouseOverIndicatorAllowed() const { return mbIsMouseOverIndicatorAllowed;}
162 protected:
163 SlideSorter& mrSlideSorter;
164 SelectionFunction& mrSelectionFunction;
166 virtual bool ProcessButtonDownEvent (EventDescriptor& rDescriptor);
167 virtual bool ProcessButtonUpEvent (EventDescriptor& rDescriptor);
168 virtual bool ProcessMotionEvent (EventDescriptor& rDescriptor);
169 virtual bool ProcessDragEvent (EventDescriptor& rDescriptor);
170 virtual bool HandleUnprocessedEvent (EventDescriptor& rDescriptor);
172 void ReprocessEvent (EventDescriptor& rDescriptor);
174 private:
175 const bool mbIsMouseOverIndicatorAllowed;
178 namespace {
180 /** This is the default handler for processing events. It activates the
181 multi selection or drag-and-drop when the right conditions are met.
183 class NormalModeHandler : public SelectionFunction::ModeHandler
185 public:
186 NormalModeHandler (
187 SlideSorter& rSlideSorter,
188 SelectionFunction& rSelectionFunction);
190 virtual SelectionFunction::Mode GetMode() const override;
191 virtual void Abort() override;
193 void ResetButtonDownLocation();
195 protected:
196 virtual bool ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
197 virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
198 virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
199 virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
201 private:
202 ::std::optional<Point> maButtonDownLocation;
204 /** Select all pages between and including the selection anchor and the
205 specified page.
207 void RangeSelect (const model::SharedPageDescriptor& rpDescriptor);
210 /** Handle events during a multi selection, which typically is started by
211 pressing the left mouse button when not over a page.
213 class MultiSelectionModeHandler : public SelectionFunction::ModeHandler
215 public:
216 /** Start a rectangle selection at the given position.
218 MultiSelectionModeHandler (
219 SlideSorter& rSlideSorter,
220 SelectionFunction& rSelectionFunction,
221 const Point& rMouseModelPosition,
222 const sal_uInt32 nEventCode);
224 virtual ~MultiSelectionModeHandler() override;
226 virtual SelectionFunction::Mode GetMode() const override;
227 virtual void Abort() override;
228 virtual void ProcessEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
230 enum SelectionMode { SM_Normal, SM_Add, SM_Toggle };
232 void SetSelectionMode (const SelectionMode eSelectionMode);
233 void SetSelectionModeFromModifier (const sal_uInt32 nEventCode);
235 protected:
236 virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
237 virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
238 virtual bool HandleUnprocessedEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
240 private:
241 SelectionMode meSelectionMode;
242 Point maSecondCorner;
243 PointerStyle maSavedPointer;
244 bool mbAutoScrollInstalled;
245 sal_Int32 mnAnchorIndex;
246 sal_Int32 mnSecondIndex;
248 void UpdateModelPosition (const Point& rMouseModelPosition);
249 void UpdateSelection();
251 /** Update the rectangle selection so that the given position becomes
252 the new second point of the selection rectangle.
254 void UpdatePosition (
255 const Point& rMousePosition,
256 const bool bAllowAutoScroll);
258 void UpdateSelectionState (
259 const model::SharedPageDescriptor& rpDescriptor,
260 const bool bIsInSelection) const;
263 /** Handle events during drag-and-drop.
265 class DragAndDropModeHandler : public SelectionFunction::ModeHandler
267 public:
268 DragAndDropModeHandler (
269 SlideSorter& rSlideSorter,
270 SelectionFunction& rSelectionFunction,
271 const Point& rMousePosition,
272 vcl::Window* pWindow);
273 virtual ~DragAndDropModeHandler() override;
275 virtual SelectionFunction::Mode GetMode() const override;
276 virtual void Abort() override;
278 protected:
279 virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
280 virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) override;
282 private:
283 std::unique_ptr<DragAndDropContext, o3tl::default_delete<DragAndDropContext>> mpDragAndDropContext;
288 //===== SelectionFunction =====================================================
291 SelectionFunction::SelectionFunction (
292 SlideSorter& rSlideSorter,
293 SfxRequest& rRequest)
294 : FuPoor (
295 rSlideSorter.GetViewShell(),
296 rSlideSorter.GetContentWindow(),
297 &rSlideSorter.GetView(),
298 rSlideSorter.GetModel().GetDocument(),
299 rRequest),
300 mrSlideSorter(rSlideSorter),
301 mrController(mrSlideSorter.GetController()),
302 mnShiftKeySelectionAnchor(-1),
303 mpModeHandler(std::make_shared<NormalModeHandler>(rSlideSorter, *this))
307 SelectionFunction::~SelectionFunction()
309 mpModeHandler.reset();
312 rtl::Reference<FuPoor> SelectionFunction::Create(
313 SlideSorter& rSlideSorter,
314 SfxRequest& rRequest)
316 rtl::Reference<FuPoor> xFunc( new SelectionFunction( rSlideSorter, rRequest ) );
317 return xFunc;
320 bool SelectionFunction::MouseButtonDown (const MouseEvent& rEvent)
322 // remember button state for creation of own MouseEvents
323 SetMouseButtonCode (rEvent.GetButtons());
324 aMDPos = rEvent.GetPosPixel();
326 // mpWindow->CaptureMouse();
328 ProcessMouseEvent(BUTTON_DOWN, rEvent);
330 return true;
333 bool SelectionFunction::MouseMove (const MouseEvent& rEvent)
335 ProcessMouseEvent(MOUSE_MOTION, rEvent);
336 return true;
339 bool SelectionFunction::MouseButtonUp (const MouseEvent& rEvent)
341 mrController.GetScrollBarManager().StopAutoScroll ();
343 ProcessMouseEvent(BUTTON_UP, rEvent);
345 return true;
348 void SelectionFunction::NotifyDragFinished()
350 SwitchToNormalMode();
353 bool SelectionFunction::KeyInput (const KeyEvent& rEvent)
355 view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter);
356 PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter);
357 PageSelector::UpdateLock aLock (mrSlideSorter);
358 FocusManager& rFocusManager (mrController.GetFocusManager());
359 bool bResult = false;
361 const vcl::KeyCode& rCode (rEvent.GetKeyCode());
362 switch (rCode.GetCode())
364 case KEY_RETURN:
366 model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor());
367 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
368 if (rFocusManager.HasFocus() && pDescriptor && pViewShell!=nullptr)
370 // The Return key triggers different functions depending on
371 // whether the slide sorter is the main view or displayed in
372 // the right pane.
373 if (pViewShell->IsMainViewShell())
375 mpModeHandler->SetCurrentPage(pDescriptor);
376 mpModeHandler->SwitchView(pDescriptor);
378 else if (pViewShell->GetDispatcher() != nullptr)
380 pViewShell->GetDispatcher()->Execute(
381 SID_INSERTPAGE,
382 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
384 bResult = true;
386 break;
389 case KEY_TAB:
390 if ( ! rFocusManager.IsFocusShowing())
392 rFocusManager.ShowFocus();
393 bResult = true;
395 break;
397 case KEY_ESCAPE:
398 // When there is an active multiselection or drag-and-drop
399 // operation then stop that.
400 mpModeHandler->Abort();
401 SwitchToNormalMode();
402 bResult = true;
403 break;
405 case KEY_SPACE:
407 // Toggle the selection state.
408 model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor());
409 if (pDescriptor && rCode.IsMod1())
411 if (pDescriptor->HasState(model::PageDescriptor::ST_Selected))
412 mrController.GetPageSelector().DeselectPage(pDescriptor, false);
413 else
414 mrController.GetPageSelector().SelectPage(pDescriptor);
416 bResult = true;
418 break;
420 // Move the focus indicator left.
421 case KEY_LEFT:
422 MoveFocus(FocusManager::FocusMoveDirection::Left, rCode.IsShift(), rCode.IsMod1());
423 bResult = true;
424 break;
426 // Move the focus indicator right.
427 case KEY_RIGHT:
428 MoveFocus(FocusManager::FocusMoveDirection::Right, rCode.IsShift(), rCode.IsMod1());
429 bResult = true;
430 break;
432 // Move the focus indicator up.
433 case KEY_UP:
434 MoveFocus(FocusManager::FocusMoveDirection::Up, rCode.IsShift(), rCode.IsMod1());
435 bResult = true;
436 break;
438 // Move the focus indicator down.
439 case KEY_DOWN:
440 MoveFocus(FocusManager::FocusMoveDirection::Down, rCode.IsShift(), rCode.IsMod1());
441 bResult = true;
442 break;
444 // Go to previous page. No wrap around.
445 case KEY_PAGEUP:
446 GotoNextPage(-1);
447 bResult = true;
448 break;
450 // Go to next page. No wrap around...
451 case KEY_PAGEDOWN:
452 GotoNextPage(+1);
453 bResult = true;
454 break;
456 case KEY_HOME:
457 GotoPage(0);
458 bResult = true;
459 break;
461 case KEY_END:
462 GotoPage(mrSlideSorter.GetModel().GetPageCount()-1);
463 bResult = true;
464 break;
466 case KEY_DELETE:
467 case KEY_BACKSPACE:
469 if (mrSlideSorter.GetProperties()->IsUIReadOnly())
470 break;
472 mrController.GetSelectionManager()->DeleteSelectedPages(rCode.GetCode()==KEY_DELETE);
474 mnShiftKeySelectionAnchor = -1;
475 bResult = true;
477 break;
479 case KEY_F10:
480 if (rCode.IsShift())
482 mpModeHandler->SelectOnePage(
483 mrSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor());
485 break;
487 default:
488 break;
491 if ( ! bResult)
492 bResult = FuPoor::KeyInput(rEvent);
494 return bResult;
497 void SelectionFunction::MoveFocus (
498 const FocusManager::FocusMoveDirection eDirection,
499 const bool bIsShiftDown,
500 const bool bIsControlDown)
502 // Remember the anchor of shift key multi selection.
503 if (bIsShiftDown)
505 if (mnShiftKeySelectionAnchor<0)
507 model::SharedPageDescriptor pFocusedDescriptor (
508 mrController.GetFocusManager().GetFocusedPageDescriptor());
509 mnShiftKeySelectionAnchor = pFocusedDescriptor->GetPageIndex();
512 else if ( ! bIsControlDown)
513 ResetShiftKeySelectionAnchor();
515 mrController.GetFocusManager().MoveFocus(eDirection);
517 PageSelector& rSelector (mrController.GetPageSelector());
518 model::SharedPageDescriptor pFocusedDescriptor (
519 mrController.GetFocusManager().GetFocusedPageDescriptor());
520 if (bIsShiftDown)
522 // When shift is pressed then select all pages in the range between
523 // the currently and the previously focused pages, including them.
524 if (pFocusedDescriptor)
526 sal_Int32 nPageRangeEnd (pFocusedDescriptor->GetPageIndex());
527 model::PageEnumeration aPages (
528 model::PageEnumerationProvider::CreateAllPagesEnumeration(
529 mrSlideSorter.GetModel()));
530 while (aPages.HasMoreElements())
532 model::SharedPageDescriptor pDescriptor (aPages.GetNextElement());
533 if (pDescriptor)
535 const sal_Int32 nPageIndex(pDescriptor->GetPageIndex());
536 if ((nPageIndex>=mnShiftKeySelectionAnchor && nPageIndex<=nPageRangeEnd)
537 || (nPageIndex<=mnShiftKeySelectionAnchor && nPageIndex>=nPageRangeEnd))
539 rSelector.SelectPage(pDescriptor);
541 else
543 rSelector.DeselectPage(pDescriptor);
549 else if (bIsControlDown)
551 // When control is pressed then do not alter the selection or the
552 // current page, just move the focus.
554 else
556 // Without shift just select the focused page.
557 mpModeHandler->SelectOnePage(pFocusedDescriptor);
561 void SelectionFunction::DoCut()
563 if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly())
565 mrController.GetClipboard().DoCut();
569 void SelectionFunction::DoCopy()
571 mrController.GetClipboard().DoCopy();
574 void SelectionFunction::DoPaste()
576 if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly())
578 mrController.GetClipboard().DoPaste();
582 bool SelectionFunction::cancel()
584 mrController.GetFocusManager().ToggleFocus();
585 return true;
588 void SelectionFunction::GotoNextPage (int nOffset)
590 model::SharedPageDescriptor pDescriptor
591 = mrController.GetCurrentSlideManager()->GetCurrentSlide();
592 if (pDescriptor)
594 SdPage* pPage = pDescriptor->GetPage();
595 OSL_ASSERT(pPage!=nullptr);
596 sal_Int32 nIndex = (pPage->GetPageNum()-1) / 2;
597 GotoPage(nIndex + nOffset);
599 ResetShiftKeySelectionAnchor();
602 void SelectionFunction::GotoPage (int nIndex)
604 sal_uInt16 nPageCount = static_cast<sal_uInt16>(mrSlideSorter.GetModel().GetPageCount());
606 if (nIndex >= nPageCount)
607 nIndex = nPageCount - 1;
608 if (nIndex < 0)
609 nIndex = 0;
611 mrController.GetFocusManager().SetFocusedPage(nIndex);
612 model::SharedPageDescriptor pNextPageDescriptor (
613 mrSlideSorter.GetModel().GetPageDescriptor (nIndex));
614 if (pNextPageDescriptor)
615 mpModeHandler->SetCurrentPage(pNextPageDescriptor);
616 else
618 OSL_ASSERT(pNextPageDescriptor);
620 ResetShiftKeySelectionAnchor();
623 void SelectionFunction::ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent)
625 // #95491# remember button state for creation of own MouseEvents
626 SetMouseButtonCode (rEvent.GetButtons());
628 EventDescriptor aEventDescriptor (nEventType, rEvent, mrSlideSorter);
629 ProcessEvent(aEventDescriptor);
632 void SelectionFunction::MouseDragged (
633 const AcceptDropEvent& rEvent,
634 const sal_Int8 nDragAction)
636 EventDescriptor aEventDescriptor (MOUSE_DRAG, rEvent, nDragAction, mrSlideSorter);
637 ProcessEvent(aEventDescriptor);
640 void SelectionFunction::ProcessEvent (EventDescriptor& rDescriptor)
642 // The call to ProcessEvent may switch to another mode handler.
643 // Prevent the untimely destruction of the called handler by acquiring a
644 // temporary reference here.
645 std::shared_ptr<ModeHandler> pModeHandler (mpModeHandler);
646 pModeHandler->ProcessEvent(rDescriptor);
649 static bool Match (
650 const sal_uInt32 nEventCode,
651 const sal_uInt32 nPositivePattern)
653 return (nEventCode & nPositivePattern)==nPositivePattern;
656 void SelectionFunction::SwitchToNormalMode()
658 if (mpModeHandler->GetMode() != NormalMode)
659 SwitchMode(std::make_shared<NormalModeHandler>(mrSlideSorter, *this));
662 void SelectionFunction::SwitchToDragAndDropMode (const Point& rMousePosition)
664 if (mpModeHandler->GetMode() == DragAndDropMode)
665 return;
667 SwitchMode(std::make_shared<DragAndDropModeHandler>(mrSlideSorter, *this, rMousePosition, mpWindow));
670 void SelectionFunction::SwitchToMultiSelectionMode (
671 const Point& rMousePosition,
672 const sal_uInt32 nEventCode)
674 if (mpModeHandler->GetMode() != MultiSelectionMode)
675 SwitchMode(std::make_shared<MultiSelectionModeHandler>(mrSlideSorter, *this, rMousePosition, nEventCode));
678 void SelectionFunction::SwitchMode (const std::shared_ptr<ModeHandler>& rpHandler)
680 // Not all modes allow mouse over indicator.
681 if (mpModeHandler->IsMouseOverIndicatorAllowed() != rpHandler->IsMouseOverIndicatorAllowed())
683 if ( ! rpHandler->IsMouseOverIndicatorAllowed())
685 mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor());
687 else
688 mrSlideSorter.GetView().UpdatePageUnderMouse();
691 mpModeHandler = rpHandler;
694 void SelectionFunction::ResetShiftKeySelectionAnchor()
696 mnShiftKeySelectionAnchor = -1;
699 void SelectionFunction::ResetMouseAnchor()
701 if (mpModeHandler && mpModeHandler->GetMode() == NormalMode)
703 std::shared_ptr<NormalModeHandler> pHandler (
704 std::dynamic_pointer_cast<NormalModeHandler>(mpModeHandler));
705 if (pHandler)
706 pHandler->ResetButtonDownLocation();
710 //===== EventDescriptor =======================================================
712 SelectionFunction::EventDescriptor::EventDescriptor (
713 const sal_uInt32 nEventType,
714 const MouseEvent& rEvent,
715 SlideSorter const & rSlideSorter)
716 : maMousePosition(rEvent.GetPosPixel()),
717 mpHitPage(),
718 mnEventCode(nEventType),
719 meDragMode(InsertionIndicatorHandler::MoveMode),
720 mbIsLeaving(false)
722 maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition);
723 mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition);
724 if (mpHitDescriptor)
726 mpHitPage = mpHitDescriptor->GetPage();
729 mnEventCode |= EncodeMouseEvent(rEvent);
730 mnEventCode |= EncodeState();
732 // Detect the mouse leaving the window. When not button is pressed then
733 // we can call IsLeaveWindow at the event. Otherwise we have to make an
734 // explicit test.
735 mbIsLeaving = rEvent.IsLeaveWindow()
736 || ! ::tools::Rectangle(Point(0,0),
737 rSlideSorter.GetContentWindow()->GetOutputSizePixel()).Contains(maMousePosition);
740 SelectionFunction::EventDescriptor::EventDescriptor (
741 const sal_uInt32 nEventType,
742 const AcceptDropEvent& rEvent,
743 const sal_Int8 nDragAction,
744 SlideSorter const & rSlideSorter)
745 : maMousePosition(rEvent.maPosPixel),
746 mpHitPage(),
747 mnEventCode(nEventType),
748 meDragMode(InsertionIndicatorHandler::GetModeFromDndAction(nDragAction)),
749 mbIsLeaving(false)
751 maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition);
752 mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition);
753 if (mpHitDescriptor)
755 mpHitPage = mpHitDescriptor->GetPage();
758 mnEventCode |= EncodeState();
760 // Detect the mouse leaving the window. When not button is pressed then
761 // we can call IsLeaveWindow at the event. Otherwise we have to make an
762 // explicit test.
763 mbIsLeaving = rEvent.mbLeaving
764 || ! ::tools::Rectangle(Point(0,0),
765 rSlideSorter.GetContentWindow()->GetOutputSizePixel()).Contains(maMousePosition);
768 sal_uInt32 SelectionFunction::EventDescriptor::EncodeMouseEvent (
769 const MouseEvent& rEvent) const
771 // Initialize with the type of mouse event.
772 sal_uInt32 nEventCode (mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION));
774 // Detect the affected button.
775 switch (rEvent.GetButtons())
777 case MOUSE_LEFT: nEventCode |= LEFT_BUTTON; break;
778 case MOUSE_RIGHT: nEventCode |= RIGHT_BUTTON; break;
779 case MOUSE_MIDDLE: nEventCode |= MIDDLE_BUTTON; break;
782 // Detect the number of clicks.
783 switch (rEvent.GetClicks())
785 case 1: nEventCode |= SINGLE_CLICK; break;
786 case 2: nEventCode |= DOUBLE_CLICK; break;
789 // Detect pressed modifier keys.
790 if (rEvent.IsShift())
791 nEventCode |= SHIFT_MODIFIER;
792 if (rEvent.IsMod1())
793 nEventCode |= CONTROL_MODIFIER;
795 return nEventCode;
798 sal_uInt32 SelectionFunction::EventDescriptor::EncodeState() const
800 sal_uInt32 nEventCode (0);
802 // Detect whether the event has happened over a page object.
803 if (mpHitPage!=nullptr && mpHitDescriptor)
805 if (mpHitDescriptor->HasState(model::PageDescriptor::ST_Selected))
806 nEventCode |= OVER_SELECTED_PAGE;
807 else
808 nEventCode |= OVER_UNSELECTED_PAGE;
811 return nEventCode;
814 //===== SelectionFunction::ModeHandler ========================================
816 SelectionFunction::ModeHandler::ModeHandler (
817 SlideSorter& rSlideSorter,
818 SelectionFunction& rSelectionFunction,
819 const bool bIsMouseOverIndicatorAllowed)
820 : mrSlideSorter(rSlideSorter),
821 mrSelectionFunction(rSelectionFunction),
822 mbIsMouseOverIndicatorAllowed(bIsMouseOverIndicatorAllowed)
826 SelectionFunction::ModeHandler::~ModeHandler() COVERITY_NOEXCEPT_FALSE
830 void SelectionFunction::ModeHandler::ReprocessEvent (EventDescriptor& rDescriptor)
832 mrSelectionFunction.ProcessEvent(rDescriptor);
835 void SelectionFunction::ModeHandler::ProcessEvent (
836 SelectionFunction::EventDescriptor& rDescriptor)
838 PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter);
839 PageSelector::UpdateLock aUpdateLock (mrSlideSorter);
841 bool bIsProcessed (false);
842 switch (rDescriptor.mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION | MOUSE_DRAG))
844 case BUTTON_DOWN:
845 bIsProcessed = ProcessButtonDownEvent(rDescriptor);
846 break;
848 case BUTTON_UP:
849 bIsProcessed = ProcessButtonUpEvent(rDescriptor);
850 break;
852 case MOUSE_MOTION:
853 bIsProcessed = ProcessMotionEvent(rDescriptor);
854 break;
856 case MOUSE_DRAG:
857 bIsProcessed = ProcessDragEvent(rDescriptor);
858 break;
861 if ( ! bIsProcessed)
862 HandleUnprocessedEvent(rDescriptor);
865 bool SelectionFunction::ModeHandler::ProcessButtonDownEvent (EventDescriptor&)
867 return false;
870 bool SelectionFunction::ModeHandler::ProcessButtonUpEvent (EventDescriptor&)
872 mrSelectionFunction.SwitchToNormalMode();
873 return false;
876 bool SelectionFunction::ModeHandler::ProcessMotionEvent (EventDescriptor& rDescriptor)
878 if (mbIsMouseOverIndicatorAllowed)
879 mrSlideSorter.GetView().UpdatePageUnderMouse(rDescriptor.maMousePosition);
881 if (rDescriptor.mbIsLeaving)
883 mrSelectionFunction.SwitchToNormalMode();
884 mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor());
886 return true;
888 else
889 return false;
892 bool SelectionFunction::ModeHandler::ProcessDragEvent (EventDescriptor&)
894 return false;
897 bool SelectionFunction::ModeHandler::HandleUnprocessedEvent (EventDescriptor&)
899 return false;
902 void SelectionFunction::ModeHandler::SetCurrentPage (
903 const model::SharedPageDescriptor& rpDescriptor)
905 SelectOnePage(rpDescriptor);
906 mrSlideSorter.GetController().GetCurrentSlideManager()->SwitchCurrentSlide(rpDescriptor);
909 void SelectionFunction::ModeHandler::DeselectAllPages()
911 mrSlideSorter.GetController().GetPageSelector().DeselectAllPages();
912 mrSelectionFunction.ResetShiftKeySelectionAnchor();
915 void SelectionFunction::ModeHandler::SelectOnePage (
916 const model::SharedPageDescriptor& rpDescriptor)
918 DeselectAllPages();
919 mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor);
922 void SelectionFunction::ModeHandler::SwitchView (const model::SharedPageDescriptor& rpDescriptor)
924 // Switch to the draw view. This is done only when the current
925 // view is the main view.
926 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
927 if (pViewShell==nullptr || !pViewShell->IsMainViewShell())
928 return;
930 if (rpDescriptor && rpDescriptor->GetPage()!=nullptr)
932 mrSlideSorter.GetModel().GetDocument()->SetSelected(rpDescriptor->GetPage(), true);
933 pViewShell->GetFrameView()->SetSelectedPage(
934 (rpDescriptor->GetPage()->GetPageNum()-1)/2);
936 if (mrSlideSorter.GetViewShellBase() != nullptr)
937 framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase())->RequestView(
938 framework::FrameworkHelper::msImpressViewURL,
939 framework::FrameworkHelper::msCenterPaneURL);
942 void SelectionFunction::ModeHandler::StartDrag (
943 const Point& rMousePosition)
945 // Do not start a drag-and-drop operation when one is already active.
946 // (when dragging pages from one document into another, pressing a
947 // modifier key can trigger a MouseMotion event in the originating
948 // window (focus still in there). Together with the mouse button pressed
949 // (drag-and-drop is active) this triggers the start of drag-and-drop.)
950 if (SD_MOD()->pTransferDrag != nullptr)
951 return;
953 if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly())
955 mrSelectionFunction.SwitchToDragAndDropMode(rMousePosition);
959 //===== NormalModeHandler =====================================================
961 NormalModeHandler::NormalModeHandler (
962 SlideSorter& rSlideSorter,
963 SelectionFunction& rSelectionFunction)
964 : ModeHandler(rSlideSorter, rSelectionFunction, true)
968 SelectionFunction::Mode NormalModeHandler::GetMode() const
970 return SelectionFunction::NormalMode;
973 void NormalModeHandler::Abort()
977 bool NormalModeHandler::ProcessButtonDownEvent (
978 SelectionFunction::EventDescriptor& rDescriptor)
980 // Remember the location where the left button is pressed. With
981 // that we can filter away motion events that are caused by key
982 // presses. We also can tune the minimal motion distance that
983 // triggers a drag-and-drop operation.
984 if ((rDescriptor.mnEventCode & BUTTON_DOWN) != 0)
985 maButtonDownLocation = rDescriptor.maMousePosition;
987 switch (rDescriptor.mnEventCode)
989 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE:
990 SetCurrentPage(rDescriptor.mpHitDescriptor);
991 break;
993 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
994 break;
996 case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_SELECTED_PAGE:
997 case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_UNSELECTED_PAGE:
998 // A double click always shows the selected slide in the center
999 // pane in an edit view.
1000 SetCurrentPage(rDescriptor.mpHitDescriptor);
1001 SwitchView(rDescriptor.mpHitDescriptor);
1002 break;
1004 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | SHIFT_MODIFIER:
1005 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | SHIFT_MODIFIER:
1006 // Range selection with the shift modifier.
1007 RangeSelect(rDescriptor.mpHitDescriptor);
1008 break;
1010 // Right button for context menu.
1011 case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE:
1012 // Single right click and shift+F10 select as preparation to
1013 // show the context menu. Change the selection only when the
1014 // page under the mouse is not selected. In this case the
1015 // selection is set to this single page. Otherwise the
1016 // selection is not modified.
1017 SetCurrentPage(rDescriptor.mpHitDescriptor);
1018 break;
1020 case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
1021 // Do not change the selection. Just adjust the insertion indicator.
1022 break;
1024 case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE:
1025 // Remember the current selection so that when a multi selection
1026 // is started, we can restore the previous selection.
1027 mrSlideSorter.GetModel().SaveCurrentSelection();
1028 DeselectAllPages();
1029 break;
1031 case ANY_MODIFIER(BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE):
1032 // Remember the current selection so that when a multi selection
1033 // is started, we can restore the previous selection.
1034 mrSlideSorter.GetModel().SaveCurrentSelection();
1035 DeselectAllPages();
1036 break;
1038 case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | NOT_OVER_PAGE:
1040 // Insert a new slide:
1041 // First of all we need to set the insertion indicator which sets the
1042 // position where the new slide will be inserted.
1043 std::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler
1044 = mrSlideSorter.GetController().GetInsertionIndicatorHandler();
1046 pInsertionIndicatorHandler->Start(false);
1047 pInsertionIndicatorHandler->UpdatePosition(
1048 rDescriptor.maMousePosition,
1049 InsertionIndicatorHandler::MoveMode);
1051 mrSlideSorter.GetController().GetSelectionManager()->SetInsertionPosition(
1052 pInsertionIndicatorHandler->GetInsertionPageIndex());
1054 mrSlideSorter.GetViewShell()->GetDispatcher()->Execute(
1055 SID_INSERTPAGE,
1056 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
1058 pInsertionIndicatorHandler->End(Animator::AM_Immediate);
1060 break;
1063 default:
1064 return false;
1066 return true;
1069 bool NormalModeHandler::ProcessButtonUpEvent (
1070 SelectionFunction::EventDescriptor& rDescriptor)
1072 bool bIsProcessed (true);
1073 switch (rDescriptor.mnEventCode)
1075 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
1076 SetCurrentPage(rDescriptor.mpHitDescriptor);
1077 break;
1079 // Multi selection with the control modifier.
1080 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | CONTROL_MODIFIER:
1081 mrSlideSorter.GetController().GetPageSelector().DeselectPage(
1082 rDescriptor.mpHitDescriptor);
1083 break;
1085 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | CONTROL_MODIFIER:
1086 mrSlideSorter.GetController().GetPageSelector().SelectPage(
1087 rDescriptor.mpHitDescriptor);
1088 mrSlideSorter.GetView().SetPageUnderMouse(rDescriptor.mpHitDescriptor);
1089 break;
1090 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE:
1091 break;
1093 default:
1094 bIsProcessed = false;
1095 break;
1097 mrSelectionFunction.SwitchToNormalMode();
1098 return bIsProcessed;
1101 bool NormalModeHandler::ProcessMotionEvent (
1102 SelectionFunction::EventDescriptor& rDescriptor)
1104 if (ModeHandler::ProcessMotionEvent(rDescriptor))
1105 return true;
1107 bool bIsProcessed (true);
1108 switch (rDescriptor.mnEventCode)
1110 // A mouse motion without visible substitution starts that.
1111 case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE):
1112 case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE):
1114 if (maButtonDownLocation)
1116 const sal_Int32 nDistance(std::max(
1117 std::abs(maButtonDownLocation->X() - rDescriptor.maMousePosition.X()),
1118 std::abs(maButtonDownLocation->Y() - rDescriptor.maMousePosition.Y())));
1119 if (nDistance > 3)
1120 StartDrag(rDescriptor.maMousePosition);
1122 break;
1125 // A mouse motion not over a page starts a rectangle selection.
1126 case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE):
1127 mrSelectionFunction.SwitchToMultiSelectionMode(
1128 rDescriptor.maMouseModelPosition,
1129 rDescriptor.mnEventCode);
1130 break;
1132 default:
1133 bIsProcessed = false;
1134 break;
1136 return bIsProcessed;
1139 bool NormalModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor)
1141 mrSelectionFunction.SwitchToDragAndDropMode(rDescriptor.maMousePosition);
1142 ReprocessEvent(rDescriptor);
1143 return true;
1146 void NormalModeHandler::RangeSelect (const model::SharedPageDescriptor& rpDescriptor)
1148 PageSelector::UpdateLock aLock (mrSlideSorter);
1149 PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector());
1151 model::SharedPageDescriptor pAnchor (rSelector.GetSelectionAnchor());
1152 DeselectAllPages();
1154 if (!pAnchor)
1155 return;
1157 // Select all pages between the anchor and the given one, including
1158 // the two.
1159 const sal_uInt16 nAnchorIndex ((pAnchor->GetPage()->GetPageNum()-1) / 2);
1160 const sal_uInt16 nOtherIndex ((rpDescriptor->GetPage()->GetPageNum()-1) / 2);
1162 // Iterate over all pages in the range. Start with the anchor
1163 // page. This way the PageSelector will recognize it again as
1164 // anchor (the first selected page after a DeselectAllPages()
1165 // becomes the anchor.)
1166 const sal_uInt16 nStep ((nAnchorIndex < nOtherIndex) ? +1 : -1);
1167 sal_uInt16 nIndex (nAnchorIndex);
1168 while (true)
1170 rSelector.SelectPage(nIndex);
1171 if (nIndex == nOtherIndex)
1172 break;
1173 nIndex = nIndex + nStep;
1177 void NormalModeHandler::ResetButtonDownLocation()
1179 maButtonDownLocation = ::std::optional<Point>();
1182 //===== MultiSelectionModeHandler =============================================
1184 MultiSelectionModeHandler::MultiSelectionModeHandler (
1185 SlideSorter& rSlideSorter,
1186 SelectionFunction& rSelectionFunction,
1187 const Point& rMouseModelPosition,
1188 const sal_uInt32 nEventCode)
1189 : ModeHandler(rSlideSorter, rSelectionFunction, false),
1190 meSelectionMode(SM_Normal),
1191 maSecondCorner(rMouseModelPosition),
1192 maSavedPointer(mrSlideSorter.GetContentWindow()->GetPointer()),
1193 mbAutoScrollInstalled(false),
1194 mnAnchorIndex(-1),
1195 mnSecondIndex(-1)
1198 mrSlideSorter.GetContentWindow()->SetPointer(PointerStyle::Text);
1199 SetSelectionModeFromModifier(nEventCode);
1202 MultiSelectionModeHandler::~MultiSelectionModeHandler()
1204 if (mbAutoScrollInstalled)
1206 //a call to this handler's MultiSelectionModeHandler::UpdatePosition
1207 //may be still waiting to be called back
1208 mrSlideSorter.GetController().GetScrollBarManager().clearAutoScrollFunctor();
1210 mrSlideSorter.GetContentWindow()->SetPointer(maSavedPointer);
1213 SelectionFunction::Mode MultiSelectionModeHandler::GetMode() const
1215 return SelectionFunction::MultiSelectionMode;
1218 void MultiSelectionModeHandler::Abort()
1220 mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection());
1223 void MultiSelectionModeHandler::ProcessEvent (
1224 SelectionFunction::EventDescriptor& rDescriptor)
1226 // During a multi selection we do not want sudden jumps of the
1227 // visible area caused by moving newly selected pages into view.
1228 // Therefore disable that temporarily. The disabled object is
1229 // released at the end of the event processing, after the focus and
1230 // current slide have been updated.
1231 VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter);
1233 ModeHandler::ProcessEvent(rDescriptor);
1236 bool MultiSelectionModeHandler::ProcessButtonUpEvent (
1237 SelectionFunction::EventDescriptor& rDescriptor)
1239 if (mbAutoScrollInstalled)
1241 //a call to this handler's MultiSelectionModeHandler::UpdatePosition
1242 //may be still waiting to be called back
1243 mrSlideSorter.GetController().GetScrollBarManager().clearAutoScrollFunctor();
1244 mbAutoScrollInstalled = false;
1247 if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK))
1249 mrSelectionFunction.SwitchToNormalMode();
1250 return true;
1252 else
1253 return false;
1256 bool MultiSelectionModeHandler::ProcessMotionEvent (
1257 SelectionFunction::EventDescriptor& rDescriptor)
1259 // The selection rectangle is visible. Handle events accordingly.
1260 if (Match(rDescriptor.mnEventCode, MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK))
1262 SetSelectionModeFromModifier(rDescriptor.mnEventCode);
1263 UpdatePosition(rDescriptor.maMousePosition, true);
1264 return true;
1266 else
1267 return false;
1270 bool MultiSelectionModeHandler::HandleUnprocessedEvent (
1271 SelectionFunction::EventDescriptor& rDescriptor)
1273 if ( ! ModeHandler::HandleUnprocessedEvent(rDescriptor))
1275 // If the event has not been processed then stop multi selection.
1276 mrSelectionFunction.SwitchToNormalMode();
1277 ReprocessEvent(rDescriptor);
1279 return true;
1282 void MultiSelectionModeHandler::UpdatePosition (
1283 const Point& rMousePosition,
1284 const bool bAllowAutoScroll)
1286 VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter);
1288 // Convert window coordinates into model coordinates (we need the
1289 // window coordinates for auto-scrolling because that remains
1290 // constant while scrolling.)
1291 sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
1292 const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition));
1294 bool bDoAutoScroll = bAllowAutoScroll && mrSlideSorter.GetController().GetScrollBarManager().AutoScroll(
1295 rMousePosition,
1296 [this, &rMousePosition] () { return this->UpdatePosition(rMousePosition, false); });
1298 if (!bDoAutoScroll)
1299 UpdateModelPosition(aMouseModelPosition);
1301 mbAutoScrollInstalled |= bDoAutoScroll;
1304 void MultiSelectionModeHandler::SetSelectionModeFromModifier (
1305 const sal_uInt32 nEventCode)
1307 switch (nEventCode & MODIFIER_MASK)
1309 case NO_MODIFIER:
1310 SetSelectionMode(SM_Normal);
1311 break;
1313 case SHIFT_MODIFIER:
1314 SetSelectionMode(SM_Add);
1315 break;
1317 case CONTROL_MODIFIER:
1318 SetSelectionMode(SM_Toggle);
1319 break;
1323 void MultiSelectionModeHandler::SetSelectionMode (const SelectionMode eSelectionMode)
1325 if (meSelectionMode != eSelectionMode)
1327 meSelectionMode = eSelectionMode;
1328 UpdateSelection();
1332 void MultiSelectionModeHandler::UpdateSelectionState (
1333 const model::SharedPageDescriptor& rpDescriptor,
1334 const bool bIsInSelection) const
1336 // Determine whether the page was selected before the rectangle
1337 // selection was started.
1338 const bool bWasSelected (rpDescriptor->HasState(model::PageDescriptor::ST_WasSelected));
1340 // Combine the two selection states depending on the selection mode.
1341 bool bSelect (false);
1342 switch(meSelectionMode)
1344 case SM_Normal:
1345 bSelect = bIsInSelection;
1346 break;
1348 case SM_Add:
1349 bSelect = bIsInSelection || bWasSelected;
1350 break;
1352 case SM_Toggle:
1353 if (bIsInSelection)
1354 bSelect = !bWasSelected;
1355 else
1356 bSelect = bWasSelected;
1357 break;
1360 // Set the new selection state.
1361 if (bSelect)
1362 mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor);
1363 else
1364 mrSlideSorter.GetController().GetPageSelector().DeselectPage(rpDescriptor);
1367 void MultiSelectionModeHandler::UpdateModelPosition (const Point& rMouseModelPosition)
1369 maSecondCorner = rMouseModelPosition;
1370 UpdateSelection();
1373 void MultiSelectionModeHandler::UpdateSelection()
1375 view::SlideSorterView::DrawLock aLock (mrSlideSorter);
1377 model::SlideSorterModel& rModel (mrSlideSorter.GetModel());
1378 const sal_Int32 nPageCount (rModel.GetPageCount());
1380 const sal_Int32 nIndexUnderMouse (
1381 mrSlideSorter.GetView().GetLayouter().GetIndexAtPoint (
1382 maSecondCorner,
1383 false,
1384 false));
1385 if (nIndexUnderMouse < 0 || nIndexUnderMouse >= nPageCount)
1386 return;
1388 if (mnAnchorIndex < 0)
1389 mnAnchorIndex = nIndexUnderMouse;
1390 mnSecondIndex = nIndexUnderMouse;
1392 Range aRange (mnAnchorIndex, mnSecondIndex);
1393 aRange.Normalize();
1395 for (sal_Int32 nIndex=0; nIndex<nPageCount; ++nIndex)
1397 UpdateSelectionState(rModel.GetPageDescriptor(nIndex), aRange.Contains(nIndex));
1401 //===== DragAndDropModeHandler ================================================
1403 DragAndDropModeHandler::DragAndDropModeHandler (
1404 SlideSorter& rSlideSorter,
1405 SelectionFunction& rSelectionFunction,
1406 const Point& rMousePosition,
1407 vcl::Window* pWindow)
1408 : ModeHandler(rSlideSorter, rSelectionFunction, false)
1410 SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
1411 if (pDragTransferable==nullptr && mrSlideSorter.GetViewShell() != nullptr)
1413 SlideSorterViewShell* pSlideSorterViewShell
1414 = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell());
1415 if (pSlideSorterViewShell != nullptr)
1416 pSlideSorterViewShell->StartDrag(rMousePosition, pWindow);
1417 pDragTransferable = SD_MOD()->pTransferDrag;
1420 mpDragAndDropContext.reset(new DragAndDropContext(mrSlideSorter));
1421 mrSlideSorter.GetController().GetInsertionIndicatorHandler()->Start(
1422 pDragTransferable != nullptr
1423 && pDragTransferable->GetView()==&mrSlideSorter.GetView());
1426 DragAndDropModeHandler::~DragAndDropModeHandler()
1428 if (mpDragAndDropContext)
1430 // Disconnect the substitution handler from this selection function.
1431 mpDragAndDropContext->SetTargetSlideSorter();
1432 mpDragAndDropContext.reset();
1434 mrSlideSorter.GetController().GetInsertionIndicatorHandler()->End(Animator::AM_Animated);
1437 SelectionFunction::Mode DragAndDropModeHandler::GetMode() const
1439 return SelectionFunction::DragAndDropMode;
1442 void DragAndDropModeHandler::Abort()
1444 mrSlideSorter.GetController().GetClipboard().Abort();
1445 if (mpDragAndDropContext)
1446 mpDragAndDropContext->Dispose();
1447 // mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection());
1450 bool DragAndDropModeHandler::ProcessButtonUpEvent (
1451 SelectionFunction::EventDescriptor& rDescriptor)
1453 if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON))
1455 // The following Process() call may lead to the destruction
1456 // of rDescriptor.mpHitDescriptor so release our reference to it.
1457 rDescriptor.mpHitDescriptor.reset();
1458 mrSelectionFunction.SwitchToNormalMode();
1459 return true;
1461 else
1462 return false;
1465 bool DragAndDropModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor)
1467 OSL_ASSERT(mpDragAndDropContext);
1469 if (rDescriptor.mbIsLeaving)
1471 mrSelectionFunction.SwitchToNormalMode();
1473 else if (mpDragAndDropContext)
1475 mpDragAndDropContext->UpdatePosition(
1476 rDescriptor.maMousePosition,
1477 rDescriptor.meDragMode, true);
1480 return true;
1483 } // end of namespace ::sd::slidesorter::controller
1485 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */