merge the formfield patch from ooo-build
[ooovba.git] / sd / source / ui / slidesorter / controller / SlsSelectionFunction.cxx
blobc674a4d3be6b64905129bbd0ed7eba19a2ecabea
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: SlsSelectionFunction.cxx,v $
10 * $Revision: 1.37 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "precompiled_sd.hxx"
33 #include "controller/SlsSelectionFunction.hxx"
35 #include "SlideSorter.hxx"
36 #include "SlideSorterViewShell.hxx"
37 #include "controller/SlideSorterController.hxx"
38 #include "controller/SlsPageSelector.hxx"
39 #include "controller/SlsFocusManager.hxx"
40 #include "controller/SlsScrollBarManager.hxx"
41 #include "controller/SlsClipboard.hxx"
42 #include "controller/SlsCurrentSlideManager.hxx"
43 #include "controller/SlsSelectionManager.hxx"
44 #include "controller/SlsProperties.hxx"
45 #include "model/SlideSorterModel.hxx"
46 #include "model/SlsPageDescriptor.hxx"
47 #include "model/SlsPageEnumerationProvider.hxx"
48 #include "view/SlideSorterView.hxx"
49 #include "view/SlsViewOverlay.hxx"
50 #include "view/SlsLayouter.hxx"
51 #include "view/SlsPageObjectViewObjectContact.hxx"
52 #include "framework/FrameworkHelper.hxx"
53 #include "showview.hxx"
54 #include "ViewShellBase.hxx"
55 #include "DrawController.hxx"
56 #include <vcl/sound.hxx>
57 #include <sfx2/viewfrm.hxx>
58 #include <sfx2/dispatch.hxx>
59 #include <svx/svdpagv.hxx>
60 #include <vcl/msgbox.hxx>
61 #include "Window.hxx"
62 #include "sdpage.hxx"
63 #include "drawdoc.hxx"
64 #include "ViewShell.hxx"
65 #include "ViewShellBase.hxx"
66 #include "FrameView.hxx"
67 #include "app.hrc"
68 #include "sdresid.hxx"
69 #include "strings.hrc"
71 namespace {
72 static const sal_uInt32 SINGLE_CLICK (0x00000001);
73 static const sal_uInt32 DOUBLE_CLICK (0x00000002);
74 static const sal_uInt32 LEFT_BUTTON (0x00000010);
75 static const sal_uInt32 RIGHT_BUTTON (0x00000020);
76 static const sal_uInt32 MIDDLE_BUTTON (0x00000040);
77 static const sal_uInt32 BUTTON_DOWN (0x00000100);
78 static const sal_uInt32 BUTTON_UP (0x00000200);
79 static const sal_uInt32 MOUSE_MOTION (0x00000400);
80 // The rest leaves the lower 16 bit untouched so that it can be used with
81 // key codes.
82 static const sal_uInt32 OVER_SELECTED_PAGE (0x00010000);
83 static const sal_uInt32 OVER_UNSELECTED_PAGE (0x00020000);
84 static const sal_uInt32 OVER_FADE_INDICATOR (0x00040000);
85 static const sal_uInt32 SHIFT_MODIFIER (0x00100000);
86 static const sal_uInt32 CONTROL_MODIFIER (0x00200000);
87 static const sal_uInt32 SUBSTITUTION_VISIBLE (0x01000000);
88 static const sal_uInt32 RECTANGLE_VISIBLE (0x02000000);
90 static const sal_uInt32 KEY_EVENT (0x10000000);
92 // Some absent events are defined so they can be expressed explicitly.
93 static const sal_uInt32 NO_MODIFIER (0x00000000);
94 static const sal_uInt32 SUBSTITUTION_NOT_VISIBLE (0x00000000);
95 static const sal_uInt32 NOT_OVER_PAGE (0x00000000);
98 } // end of anonymous namespace
101 namespace sd { namespace slidesorter { namespace controller {
103 class SelectionFunction::SubstitutionHandler
105 public:
106 SubstitutionHandler (SlideSorter& rSlideSorter);
107 ~SubstitutionHandler (void);
109 /** Create a substitution display of the currently selected pages and
110 use the given position as the anchor point.
112 void Start (const Point& rMouseModelPosition);
114 /** Move the substitution display by the distance the mouse has
115 travelled since the last call to this method or to
116 CreateSubstitution(). The given point becomes the new anchor.
118 void UpdatePosition (const Point& rMouseModelPosition);
120 /** Move the substitution display of the currently selected pages.
122 void Process (void);
124 void End (void);
126 bool HasBeenMoved (void) const;
128 private:
129 SlideSorter& mrSlideSorter;
131 bool mbHasBeenMoved;
133 /** Determine whether there is a) a substitution and b) its insertion at
134 the current position of the insertion marker would alter the
135 document. This would be the case when the substitution has been
136 moved or is not consecutive.
138 bool IsSubstitutionInsertionNonTrivial (void) const;
142 class SelectionFunction::InsertionIndicatorHandler
144 public:
145 InsertionIndicatorHandler (SlideSorter& rSlideSorter);
146 ~InsertionIndicatorHandler (void);
148 /** Show the insertion marker at the given coordinates.
150 void Start (const Point& rMouseModelPosition);
152 void UpdatePosition (const Point& rMouseModelPosition);
154 /** Hide the insertion marker.
156 void End (void);
158 private:
159 SlideSorter& mrSlideSorter;
162 class SelectionFunction::EventDescriptor
164 public:
166 Point maMousePosition;
167 Point maMouseModelPosition;
168 ::boost::weak_ptr<model::PageDescriptor> mpHitDescriptor;
169 SdrPage* mpHitPage;
170 sal_uInt32 mnEventCode;
172 EventDescriptor (
173 sal_uInt32 nEventType,
174 const MouseEvent& rEvent,
175 SlideSorter& rSlideSorter);
176 EventDescriptor (
177 const KeyEvent& rEvent,
178 SlideSorter& rSlideSorter);
182 TYPEINIT1(SelectionFunction, FuPoor);
185 SelectionFunction::SelectionFunction (
186 SlideSorter& rSlideSorter,
187 SfxRequest& rRequest)
188 : SlideFunction (rSlideSorter, rRequest),
189 mrSlideSorter(rSlideSorter),
190 mrController(mrSlideSorter.GetController()),
191 mbDragSelection(false),
192 maInsertionMarkerBox(),
193 mbProcessingMouseButtonDown(false),
194 mpSubstitutionHandler(new SubstitutionHandler(mrSlideSorter)),
195 mpInsertionIndicatorHandler(new InsertionIndicatorHandler(mrSlideSorter))
197 //af aDelayToScrollTimer.SetTimeout(50);
198 aDragTimer.SetTimeoutHdl( LINK( this, SelectionFunction, DragSlideHdl ) );
201 SelectionFunction::~SelectionFunction (void)
203 aDragTimer.Stop();
209 FunctionReference SelectionFunction::Create(
210 SlideSorter& rSlideSorter,
211 SfxRequest& rRequest)
213 FunctionReference xFunc( new SelectionFunction( rSlideSorter, rRequest ) );
214 return xFunc;
220 BOOL SelectionFunction::MouseButtonDown (const MouseEvent& rEvent)
222 // #95491# remember button state for creation of own MouseEvents
223 SetMouseButtonCode (rEvent.GetButtons());
224 mbProcessingMouseButtonDown = true;
226 mpWindow->CaptureMouse();
228 ProcessMouseEvent(BUTTON_DOWN, rEvent);
230 return TRUE;
236 BOOL SelectionFunction::MouseMove (const MouseEvent& rEvent)
238 Point aMousePosition (rEvent.GetPosPixel());
240 // Determine page under mouse and show the mouse over effect.
241 model::SharedPageDescriptor pHitDescriptor (mrController.GetPageAt(aMousePosition));
242 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
243 rOverlay.GetMouseOverIndicatorOverlay().SetSlideUnderMouse(
244 rEvent.IsLeaveWindow() ? model::SharedPageDescriptor() : pHitDescriptor);
245 if (pHitDescriptor.get() != NULL)
246 rOverlay.GetMouseOverIndicatorOverlay().setVisible(true);
247 else
248 rOverlay.GetMouseOverIndicatorOverlay().setVisible(false);
250 // Allow one mouse move before the drag timer is disabled.
251 if (aDragTimer.IsActive())
253 if (bFirstMouseMove)
254 bFirstMouseMove = FALSE;
255 else
256 aDragTimer.Stop();
259 Rectangle aRectangle (Point(0,0),mpWindow->GetOutputSizePixel());
260 if ( ! aRectangle.IsInside(aMousePosition)
261 && rOverlay.GetSubstitutionOverlay().isVisible())
263 // Mouse left the window with pressed left button. Make it a drag.
264 StartDrag();
266 else
268 // Call ProcessMouseEvent() only when one of the buttons is
269 // pressed. This prevents calling the method on every motion.
270 if (rEvent.GetButtons() != 0
271 && mbProcessingMouseButtonDown)
273 ProcessMouseEvent(MOUSE_MOTION, rEvent);
277 return TRUE;
283 BOOL SelectionFunction::MouseButtonUp (const MouseEvent& rEvent)
285 mrController.GetScrollBarManager().StopAutoScroll ();
287 // #95491# remember button state for creation of own MouseEvents
288 SetMouseButtonCode (rEvent.GetButtons());
290 if (aDragTimer.IsActive())
291 aDragTimer.Stop();
293 ProcessMouseEvent(BUTTON_UP, rEvent);
295 mbProcessingMouseButtonDown = false;
296 mpWindow->ReleaseMouse();
298 return TRUE;
304 BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent)
306 FocusManager& rFocusManager (mrController.GetFocusManager());
307 BOOL bResult = FALSE;
309 switch (rEvent.GetKeyCode().GetCode())
311 case KEY_RETURN:
312 if (rFocusManager.HasFocus())
314 model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor());
315 if (pDescriptor.get() != NULL)
317 SetCurrentPage(pDescriptor);
318 SwitchView(pDescriptor);
320 bResult = TRUE;
322 break;
324 case KEY_TAB:
325 if ( ! rFocusManager.IsFocusShowing())
326 rFocusManager.ShowFocus();
327 else
328 if (rEvent.GetKeyCode().IsShift())
329 rFocusManager.MoveFocus (FocusManager::FMD_LEFT);
330 else
331 rFocusManager.MoveFocus (FocusManager::FMD_RIGHT);
332 bResult = TRUE;
333 break;
335 case KEY_ESCAPE:
336 rFocusManager.SetFocusToToolBox();
337 bResult = TRUE;
338 break;
340 case KEY_SPACE:
342 // Toggle the selection state.
343 model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor());
344 if (pDescriptor.get() != NULL)
346 // Doing a multi selection by default. Can we ask the event
347 // for the state of the shift key?
348 if (pDescriptor->IsSelected())
349 mrController.GetPageSelector().DeselectPage(pDescriptor);
350 else
351 mrController.GetPageSelector().SelectPage(pDescriptor);
353 bResult = TRUE;
355 break;
358 // Move the focus indicator left.
359 case KEY_LEFT:
360 rFocusManager.MoveFocus (FocusManager::FMD_LEFT);
361 bResult = TRUE;
362 break;
364 // Move the focus indicator right.
365 case KEY_RIGHT:
366 rFocusManager.MoveFocus (FocusManager::FMD_RIGHT);
367 bResult = TRUE;
368 break;
370 // Move the focus indicator up.
371 case KEY_UP:
372 rFocusManager.MoveFocus (FocusManager::FMD_UP);
373 bResult = TRUE;
374 break;
376 // Move the focus indicator down.
377 case KEY_DOWN:
378 rFocusManager.MoveFocus (FocusManager::FMD_DOWN);
379 bResult = TRUE;
380 break;
382 // Go to previous page. No wrap around.
383 case KEY_PAGEUP:
384 GotoNextPage(-1);
385 bResult = TRUE;
386 break;
388 // Go to next page. No wrap around..
389 case KEY_PAGEDOWN:
390 GotoNextPage(+1);
391 bResult = TRUE;
392 break;
394 case KEY_DELETE:
395 case KEY_BACKSPACE:
397 if (mrController.GetProperties()->IsUIReadOnly())
398 break;
400 int nSelectedPagesCount = 0;
402 // Count the selected pages and look if there any objects on any
403 // of the selected pages so that we can warn the user and
404 // prevent an accidental deletion.
405 model::PageEnumeration aSelectedPages (
406 model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
407 mrSlideSorter.GetModel()));
408 while (aSelectedPages.HasMoreElements())
410 nSelectedPagesCount++;
411 aSelectedPages.GetNextElement();
414 if (nSelectedPagesCount > 0)
415 mrController.GetSelectionManager()->DeleteSelectedPages();
417 bResult = TRUE;
419 break;
421 case KEY_F10:
422 if (rEvent.GetKeyCode().IsShift())
423 ProcessKeyEvent(rEvent);
424 break;
426 default:
427 break;
430 if ( ! bResult)
431 bResult = SlideFunction::KeyInput (rEvent);
433 return bResult;
439 void SelectionFunction::Activate()
441 FuPoor::Activate();
447 void SelectionFunction::Deactivate()
449 FuPoor::Deactivate();
454 void SelectionFunction::ScrollStart (void)
461 void SelectionFunction::ScrollEnd (void)
468 void SelectionFunction::DoCut (void)
470 if ( ! mrController.GetProperties()->IsUIReadOnly())
472 mrController.GetClipboard().DoCut();
479 void SelectionFunction::DoCopy (void)
481 mrController.GetClipboard().DoCopy();
487 void SelectionFunction::DoPaste (void)
489 if ( ! mrController.GetProperties()->IsUIReadOnly())
491 mrController.GetClipboard().DoPaste();
498 void SelectionFunction::Paint (const Rectangle&, ::sd::Window* )
505 IMPL_LINK( SelectionFunction, DragSlideHdl, Timer*, EMPTYARG )
507 StartDrag();
508 return 0;
514 void SelectionFunction::StartDrag (void)
516 if (mbPageHit
517 && ! mrController.GetProperties()->IsUIReadOnly())
519 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
520 mpSubstitutionHandler->Start(rOverlay.GetSubstitutionOverlay().GetPosition());
521 mbPageHit = false;
522 mpWindow->ReleaseMouse();
524 if (mrSlideSorter.GetViewShell() != NULL)
526 SlideSorterViewShell* pSlideSorterViewShell
527 = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell());
528 pSlideSorterViewShell->StartDrag (
529 rOverlay.GetSubstitutionOverlay().GetPosition(),
530 mpWindow);
538 bool SelectionFunction::cancel (void)
540 mrController.GetFocusManager().ToggleFocus();
541 return true;
547 void SelectionFunction::SelectHitPage (const model::SharedPageDescriptor& rpDescriptor)
549 mrController.GetPageSelector().SelectPage(rpDescriptor);
555 void SelectionFunction::DeselectHitPage (const model::SharedPageDescriptor& rpDescriptor)
557 mrController.GetPageSelector().DeselectPage(rpDescriptor);
563 void SelectionFunction::DeselectAllPages (void)
565 mrController.GetPageSelector().DeselectAllPages();
571 void SelectionFunction::StartRectangleSelection (const Point& rMouseModelPosition)
573 if (mrController.GetProperties()->IsShowSelection())
575 mrSlideSorter.GetView().GetOverlay().GetSelectionRectangleOverlay().Start(
576 rMouseModelPosition);
583 void SelectionFunction::UpdateRectangleSelection (const Point& rMouseModelPosition)
585 if (mrController.GetProperties()->IsShowSelection())
587 mrSlideSorter.GetView().GetOverlay().GetSelectionRectangleOverlay().Update(
588 rMouseModelPosition);
595 void SelectionFunction::ProcessRectangleSelection (bool bToggleSelection)
597 if ( ! mrController.GetProperties()->IsShowSelection())
598 return;
600 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
601 if (rOverlay.GetSelectionRectangleOverlay().isVisible())
603 PageSelector& rSelector (mrController.GetPageSelector());
605 rOverlay.GetSelectionRectangleOverlay().setVisible(false);
607 // Select all pages whose page object lies completly inside the drag
608 // rectangle.
609 const Rectangle& rSelectionRectangle (
610 rOverlay.GetSelectionRectangleOverlay().GetSelectionRectangle());
611 model::PageEnumeration aPages (
612 model::PageEnumerationProvider::CreateAllPagesEnumeration(
613 mrSlideSorter.GetModel()));
614 while (aPages.HasMoreElements())
616 model::SharedPageDescriptor pDescriptor (aPages.GetNextElement());
617 Rectangle aPageBox (mrSlideSorter.GetView().GetPageBoundingBox(
618 pDescriptor,
619 view::SlideSorterView::CS_MODEL,
620 view::SlideSorterView::BBT_SHAPE));
621 if (rSelectionRectangle.IsOver(aPageBox))
623 // When we are extending the selection (shift key is
624 // pressed) then toggle the selection state of the page.
625 // Otherwise select it: this results in the previously
626 // selected pages becoming deslected.
627 if (bToggleSelection && pDescriptor->IsSelected())
628 rSelector.DeselectPage(pDescriptor);
629 else
630 rSelector.SelectPage(pDescriptor);
639 void SelectionFunction::PrepareMouseMotion (const Point& )
641 if ( ! mrController.GetProperties()->IsUIReadOnly())
643 bFirstMouseMove = TRUE;
644 aDragTimer.Start();
651 void SelectionFunction::RangeSelect (const model::SharedPageDescriptor& rpDescriptor)
653 PageSelector& rSelector (mrController.GetPageSelector());
655 model::SharedPageDescriptor pAnchor (rSelector.GetSelectionAnchor());
656 DeselectAllPages();
658 if (pAnchor.get() != NULL)
660 // Select all pages between the anchor and the given one, including
661 // the two.
662 USHORT nAnchorIndex ((pAnchor->GetPage()->GetPageNum()-1) / 2);
663 USHORT nOtherIndex ((rpDescriptor->GetPage()->GetPageNum()-1) / 2);
665 // Iterate over all pages in the range. Start with the anchor
666 // page. This way the PageSelector will recognize it again as
667 // anchor (the first selected page after a DeselectAllPages()
668 // becomes the anchor.)
669 USHORT nStep = (nAnchorIndex < nOtherIndex) ? +1 : -1;
670 USHORT nIndex = nAnchorIndex;
671 while (true)
673 rSelector.SelectPage(nIndex);
674 if (nIndex == nOtherIndex)
675 break;
676 nIndex = nIndex + nStep;
684 void SelectionFunction::GotoNextPage (int nOffset)
686 model::SharedPageDescriptor pDescriptor
687 = mrController.GetCurrentSlideManager()->GetCurrentSlide();
688 if (pDescriptor.get() != NULL)
690 SdPage* pPage = pDescriptor->GetPage();
691 OSL_ASSERT(pPage!=NULL);
692 sal_Int32 nIndex = (pPage->GetPageNum()-1) / 2;
693 nIndex += nOffset;
694 USHORT nPageCount = (USHORT)mrSlideSorter.GetModel().GetPageCount();
696 if (nIndex >= nPageCount)
697 nIndex = nPageCount - 1;
698 if (nIndex < 0)
699 nIndex = 0;
701 mrController.GetFocusManager().SetFocusedPage(nIndex);
702 model::SharedPageDescriptor pNextPageDescriptor (
703 mrSlideSorter.GetModel().GetPageDescriptor (nIndex));
704 if (pNextPageDescriptor.get() != NULL)
705 SetCurrentPage(pNextPageDescriptor);
706 else
708 OSL_ASSERT(pNextPageDescriptor.get() != NULL);
716 void SelectionFunction::ClearOverlays (void)
718 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
720 rOverlay.GetSubstitutionOverlay().setVisible(false);
721 rOverlay.GetSubstitutionOverlay().Clear();
723 mpInsertionIndicatorHandler->End();
724 rOverlay.GetMouseOverIndicatorOverlay().SetSlideUnderMouse(model::SharedPageDescriptor());
730 void SelectionFunction::ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent)
732 // #95491# remember button state for creation of own MouseEvents
733 SetMouseButtonCode (rEvent.GetButtons());
735 // 1. Compute some frequently used values relating to the event.
736 ::std::auto_ptr<EventDescriptor> pEventDescriptor (
737 new EventDescriptor(nEventType, rEvent, mrSlideSorter));
739 // 2. Compute a numerical code that describes the event and that is used
740 // for fast look-up of the associated reaction.
741 pEventDescriptor->mnEventCode = EncodeMouseEvent(*pEventDescriptor, rEvent);
743 // 3. Process the event.
744 EventPreprocessing(*pEventDescriptor);
745 if ( ! EventProcessing(*pEventDescriptor))
747 OSL_TRACE ("can not handle event code %x", pEventDescriptor->mnEventCode);
749 EventPostprocessing(*pEventDescriptor);
751 if (nEventType == BUTTON_UP)
752 mbPageHit = false;
758 sal_uInt32 SelectionFunction::EncodeMouseEvent (
759 const EventDescriptor& rDescriptor,
760 const MouseEvent& rEvent) const
762 // Initialize with the type of mouse event.
763 sal_uInt32 nEventCode (rDescriptor.mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION));
765 // Detect the affected button.
766 switch (rEvent.GetButtons())
768 case MOUSE_LEFT: nEventCode |= LEFT_BUTTON; break;
769 case MOUSE_RIGHT: nEventCode |= RIGHT_BUTTON; break;
770 case MOUSE_MIDDLE: nEventCode |= MIDDLE_BUTTON; break;
773 // Detect the number of clicks.
774 switch (rEvent.GetClicks())
776 case 1: nEventCode |= SINGLE_CLICK; break;
777 case 2: nEventCode |= DOUBLE_CLICK; break;
780 // Detect whether the event has happened over a page object.
781 if (rDescriptor.mpHitPage != NULL && ! rDescriptor.mpHitDescriptor.expired())
783 model::SharedPageDescriptor pHitDescriptor (rDescriptor.mpHitDescriptor);
784 if (pHitDescriptor->IsSelected())
785 nEventCode |= OVER_SELECTED_PAGE;
786 else
787 nEventCode |= OVER_UNSELECTED_PAGE;
790 // Detect pressed modifier keys.
791 if (rEvent.IsShift())
792 nEventCode |= SHIFT_MODIFIER;
793 if (rEvent.IsMod1())
794 nEventCode |= CONTROL_MODIFIER;
796 // Detect whether we are dragging pages or dragging a selection rectangle.
797 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
798 if (rOverlay.GetSubstitutionOverlay().isVisible())
799 nEventCode |= SUBSTITUTION_VISIBLE;
800 if (rOverlay.GetSelectionRectangleOverlay().isVisible())
801 nEventCode |= RECTANGLE_VISIBLE;
803 return nEventCode;
809 void SelectionFunction::ProcessKeyEvent (const KeyEvent& rEvent)
811 // 1. Compute some frequently used values relating to the event.
812 ::std::auto_ptr<EventDescriptor> pEventDescriptor (
813 new EventDescriptor(rEvent, mrSlideSorter));
815 // 2. Encode the event.
816 pEventDescriptor->mnEventCode = EncodeKeyEvent(*pEventDescriptor, rEvent);
818 // 3. Process the event.
819 EventPreprocessing(*pEventDescriptor);
820 if ( ! EventProcessing(*pEventDescriptor))
821 OSL_TRACE ("can not handle event code %x", pEventDescriptor->mnEventCode);
822 EventPostprocessing(*pEventDescriptor);
828 sal_uInt32 SelectionFunction::EncodeKeyEvent (
829 const EventDescriptor& rDescriptor,
830 const KeyEvent& rEvent) const
832 // Initialize as key event.
833 sal_uInt32 nEventCode (KEY_EVENT);
835 // Add the actual key code in the lower 16 bit.
836 nEventCode |= rEvent.GetKeyCode().GetCode();
838 // Detect pressed modifier keys.
839 if (rEvent.GetKeyCode().IsShift())
840 nEventCode |= SHIFT_MODIFIER;
841 if (rEvent.GetKeyCode().IsMod1())
842 nEventCode |= CONTROL_MODIFIER;
844 // Detect whether the event has happened over a page object.
845 if (rDescriptor.mpHitPage != NULL && ! rDescriptor.mpHitDescriptor.expired())
847 model::SharedPageDescriptor pHitDescriptor (rDescriptor.mpHitDescriptor);
848 if (pHitDescriptor->IsSelected())
849 nEventCode |= OVER_SELECTED_PAGE;
850 else
851 nEventCode |= OVER_UNSELECTED_PAGE;
854 // Detect whether we are dragging pages or dragging a selection rectangle.
855 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
856 if (rOverlay.GetSubstitutionOverlay().isVisible())
857 nEventCode |= SUBSTITUTION_VISIBLE;
858 if (rOverlay.GetSelectionRectangleOverlay().isVisible())
859 nEventCode |= RECTANGLE_VISIBLE;
861 return nEventCode;
866 void SelectionFunction::EventPreprocessing (const EventDescriptor& rDescriptor)
868 // Some general processing that is not specific to the exact event code.
869 if (rDescriptor.mnEventCode & BUTTON_DOWN)
870 mbPageHit = (rDescriptor.mpHitPage!=NULL);
872 // Set the focus to the slide under the mouse.
873 if (rDescriptor.mpHitPage != NULL)
874 mrController.GetFocusManager().FocusPage((rDescriptor.mpHitPage->GetPageNum()-1)/2);
880 bool SelectionFunction::EventProcessing (const EventDescriptor& rDescriptor)
882 // Define some macros to make the following switch statement more readable.
883 #define ANY_MODIFIER(code) \
884 code|NO_MODIFIER: \
885 case code|SHIFT_MODIFIER: \
886 case code|CONTROL_MODIFIER
887 #define ANY_PAGE(code) \
888 code|NOT_OVER_PAGE: \
889 case code|OVER_UNSELECTED_PAGE: \
890 case code|OVER_SELECTED_PAGE
891 #define ANY_PAGE_AND_MODIFIER(code) \
892 ANY_PAGE(code|NO_MODIFIER): \
893 case ANY_PAGE(code|SHIFT_MODIFIER): \
894 case ANY_PAGE(code|CONTROL_MODIFIER)
897 bool bResult (true);
898 bool bMakeSelectionVisible (true);
900 mrController.GetPageSelector().DisableBroadcasting();
902 // 2b. With the event code determine the type of operation with which to
903 // react to the event.
905 // Acquire a shared_ptr to the hit page descriptor.
906 model::SharedPageDescriptor pHitDescriptor;
907 if ( ! rDescriptor.mpHitDescriptor.expired())
908 pHitDescriptor = model::SharedPageDescriptor(rDescriptor.mpHitDescriptor);
910 switch (rDescriptor.mnEventCode)
912 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE:
913 SetCurrentPage(pHitDescriptor);
914 PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition));
915 mpSubstitutionHandler->Start(rDescriptor.maMouseModelPosition);
916 break;
918 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
919 SetCurrentPage(pHitDescriptor);
920 mpSubstitutionHandler->End();
921 break;
923 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
924 PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition));
925 mpSubstitutionHandler->Start(rDescriptor.maMouseModelPosition);
926 break;
928 case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_SELECTED_PAGE:
929 case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_UNSELECTED_PAGE:
930 // A double click allways shows the selected slide in the center
931 // pane in an edit view.
932 SetCurrentPage(pHitDescriptor);
933 SwitchView(pHitDescriptor);
934 break;
936 // Multi selection with the control modifier.
937 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | CONTROL_MODIFIER:
938 DeselectHitPage(pHitDescriptor);
939 PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition));
940 break;
942 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | CONTROL_MODIFIER:
943 SelectHitPage(pHitDescriptor);
944 PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition));
946 break;
948 // Range selection with the shift modifier.
949 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | SHIFT_MODIFIER:
950 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | SHIFT_MODIFIER:
951 RangeSelect(pHitDescriptor);
952 break;
954 // Was: Preview of the page transition effect.
955 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_FADE_INDICATOR:
956 // No action.
957 break;
959 // Right button for context menu.
960 case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE:
961 case KEY_EVENT | KEY_F10 | SHIFT_MODIFIER | OVER_UNSELECTED_PAGE:
962 // Single right click and shift+F10 select as preparation to
963 // show the context menu. Change the selection only when the
964 // page under the mouse is not selected. In this case the
965 // selection is set to this single page. Otherwise the
966 // selection is not modified.
967 DeselectAllPages();
968 SelectHitPage(pHitDescriptor);
969 SetCurrentPage(pHitDescriptor);
970 bMakeSelectionVisible = false;
971 break;
973 case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
974 case KEY_EVENT | KEY_F10 | OVER_SELECTED_PAGE | SHIFT_MODIFIER:
975 // Do not change the selection. Just adjust the insertion indicator.
976 bMakeSelectionVisible = false;
977 break;
979 case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE:
980 // The Shift+F10 key event is here just for completeness. It should
981 // not be possible to really receive this (not being over a page.)
982 case KEY_EVENT | KEY_F10 | SHIFT_MODIFIER | NOT_OVER_PAGE:
983 DeselectAllPages();
984 bMakeSelectionVisible = false;
985 break;
987 // A mouse motion without visible substitution starts that.
988 case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE):
989 mrController.GetScrollBarManager().AutoScroll(rDescriptor.maMousePosition);
990 mpSubstitutionHandler->Start(rDescriptor.maMouseModelPosition);
991 break;
993 // Move substitution.
994 case ANY_PAGE_AND_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | SUBSTITUTION_VISIBLE):
995 if ((rDescriptor.mnEventCode & CONTROL_MODIFIER) != 0)
996 StartDrag();
997 mrController.GetScrollBarManager().AutoScroll(rDescriptor.maMousePosition);
998 mpSubstitutionHandler->UpdatePosition(rDescriptor.maMouseModelPosition);
999 break;
1001 // Place substitution.
1002 case ANY_PAGE_AND_MODIFIER(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | SUBSTITUTION_VISIBLE):
1003 // When the substitution has not been moved the button up event
1004 // is taken to be part of a single click. The selected pages
1005 // are therefore not moved (which technically would be necessary
1006 // for unconsecutive multi selections). Instead the page under
1007 // the mouse becomes the only selected page.
1008 if (mpSubstitutionHandler->HasBeenMoved())
1010 // The following Process() call may lead to the desctruction
1011 // of pHitDescriptor so release our reference to it.
1012 pHitDescriptor.reset();
1013 mpSubstitutionHandler->Process();
1015 else
1016 if (pHitDescriptor != NULL)
1017 SetCurrentPage(pHitDescriptor);
1018 mpSubstitutionHandler->End();
1019 break;
1021 // Rectangle selection.
1022 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE | NO_MODIFIER:
1023 DeselectAllPages();
1024 StartRectangleSelection(rDescriptor.maMouseModelPosition);
1025 break;
1027 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE | SHIFT_MODIFIER:
1028 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE | CONTROL_MODIFIER:
1029 StartRectangleSelection(rDescriptor.maMouseModelPosition);
1030 break;
1032 case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE):
1033 case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE):
1034 case ANY_PAGE_AND_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE):
1035 mrController.GetScrollBarManager().AutoScroll(rDescriptor.maMousePosition);
1036 UpdateRectangleSelection(rDescriptor.maMouseModelPosition);
1037 break;
1039 case ANY_PAGE(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE | NO_MODIFIER):
1040 ProcessRectangleSelection(false);
1041 break;
1043 case ANY_PAGE(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE | SHIFT_MODIFIER):
1044 case ANY_PAGE(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE | CONTROL_MODIFIER):
1045 ProcessRectangleSelection(true);
1046 break;
1048 default:
1049 bResult = false;
1050 break;
1052 mrController.GetPageSelector().EnableBroadcasting(bMakeSelectionVisible);
1054 return bResult;
1060 void SelectionFunction::EventPostprocessing (const EventDescriptor& rDescriptor)
1062 if (rDescriptor.mnEventCode & BUTTON_UP)
1064 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
1066 mpWindow->ReleaseMouse();
1068 // The overlays should not be visible anymore. Warn when one of
1069 // them still is. An exception is th insertion indicator in the
1070 // case that the context menu is visible.
1071 DBG_ASSERT(
1072 mrController.IsContextMenuOpen()
1073 || !rOverlay.GetInsertionIndicatorOverlay().isVisible(),
1074 "slidesorter::SelectionFunction: insertion indicator still visible");
1075 DBG_ASSERT(
1076 !rOverlay.GetSubstitutionOverlay().isVisible(),
1077 "slidesorter::SelectionFunction: substitution still visible");
1078 DBG_ASSERT(
1079 !rOverlay.GetSelectionRectangleOverlay().isVisible(),
1080 "slidesorter::SelectionFunction: selection rectangle still visible");
1082 // Now turn them off.
1083 if ( ! mrController.IsContextMenuOpen())
1084 rOverlay.GetInsertionIndicatorOverlay().setVisible(false);
1085 rOverlay.GetSubstitutionOverlay().setVisible(false);
1086 rOverlay.GetSelectionRectangleOverlay().setVisible(false);
1093 void SelectionFunction::SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor)
1095 PageSelector& rSelector (mrController.GetPageSelector());
1096 rSelector.DeselectAllPages ();
1097 rSelector.SelectPage(rpDescriptor);
1099 mrController.GetCurrentSlideManager()->SwitchCurrentSlide(rpDescriptor);
1105 void SelectionFunction::SwitchView (const model::SharedPageDescriptor& rpDescriptor)
1107 // Switch to the draw view. This is done only when the current
1108 // view is the main view.
1109 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
1110 if (pViewShell!=NULL && pViewShell->IsMainViewShell())
1112 if (rpDescriptor.get()!=NULL && rpDescriptor->GetPage()!=NULL)
1114 mrSlideSorter.GetModel().GetDocument()->SetSelected(rpDescriptor->GetPage(), TRUE);
1115 mpViewShell->GetFrameView()->SetSelectedPage(
1116 (rpDescriptor->GetPage()->GetPageNum()-1)/2);
1118 if (mrSlideSorter.GetViewShellBase() != NULL)
1119 framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase())->RequestView(
1120 framework::FrameworkHelper::msImpressViewURL,
1121 framework::FrameworkHelper::msCenterPaneURL);
1128 //===== EventDescriptor =======================================================
1130 SelectionFunction::EventDescriptor::EventDescriptor (
1131 sal_uInt32 nEventType,
1132 const MouseEvent& rEvent,
1133 SlideSorter& rSlideSorter)
1134 : maMousePosition(),
1135 maMouseModelPosition(),
1136 mpHitDescriptor(),
1137 mpHitPage(),
1138 mnEventCode(nEventType)
1140 ::Window* pWindow = rSlideSorter.GetActiveWindow();
1142 maMousePosition = rEvent.GetPosPixel();
1143 maMouseModelPosition = pWindow->PixelToLogic(maMousePosition);
1144 model::SharedPageDescriptor pHitDescriptor (
1145 rSlideSorter.GetController().GetPageAt(maMousePosition));
1146 if (pHitDescriptor.get() != NULL)
1148 mpHitDescriptor = pHitDescriptor;
1149 mpHitPage = pHitDescriptor->GetPage();
1157 SelectionFunction::EventDescriptor::EventDescriptor (
1158 const KeyEvent&,
1159 SlideSorter& rSlideSorter)
1160 : maMousePosition(),
1161 maMouseModelPosition(),
1162 mpHitDescriptor(),
1163 mpHitPage(),
1164 mnEventCode(0)
1166 mpHitDescriptor = rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor();
1167 model::SharedPageDescriptor pHitDescriptor (
1168 rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor());
1169 if (pHitDescriptor.get() != NULL)
1171 mpHitPage = pHitDescriptor->GetPage();
1172 mpHitDescriptor = pHitDescriptor;
1180 //===== SubstitutionHandler ===================================================
1182 SelectionFunction::SubstitutionHandler::SubstitutionHandler (SlideSorter& rSlideSorter)
1183 : mrSlideSorter(rSlideSorter),
1184 mbHasBeenMoved(false)
1191 SelectionFunction::SubstitutionHandler::~SubstitutionHandler (void)
1193 if (mrSlideSorter.IsValid())
1195 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
1196 rOverlay.GetSubstitutionOverlay().setVisible(false);
1197 rOverlay.GetSubstitutionOverlay().Clear();
1204 void SelectionFunction::SubstitutionHandler::Start (const Point& rMouseModelPosition)
1206 // No Drag-and-Drop for master pages.
1207 if (mrSlideSorter.GetModel().GetEditMode() != EM_PAGE)
1208 return;
1210 if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly())
1211 return;
1213 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
1215 if ( ! rOverlay.GetSubstitutionOverlay().isVisible())
1217 // Show a new substitution for the selected page objects.
1218 model::PageEnumeration aSelectedPages(
1219 model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
1220 mrSlideSorter.GetModel()));
1221 rOverlay.GetSubstitutionOverlay().Create(aSelectedPages, rMouseModelPosition);
1222 rOverlay.GetSubstitutionOverlay().setVisible(true);
1223 mbHasBeenMoved = false;
1225 else
1226 UpdatePosition(rMouseModelPosition);
1232 void SelectionFunction::SubstitutionHandler::UpdatePosition (const Point& rMouseModelPosition)
1234 if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly())
1235 return;
1237 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
1239 // Move the existing substitution to the new position.
1240 rOverlay.GetSubstitutionOverlay().SetPosition(rMouseModelPosition);
1242 rOverlay.GetInsertionIndicatorOverlay().SetPosition(rMouseModelPosition);
1243 rOverlay.GetInsertionIndicatorOverlay().setVisible(true);
1245 mbHasBeenMoved = true;
1251 void SelectionFunction::SubstitutionHandler::Process (void)
1253 if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly())
1254 return;
1256 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
1258 if (IsSubstitutionInsertionNonTrivial())
1260 // Tell the model to move the selected pages behind the one with the
1261 // index mnInsertionIndex which first has to transformed into an index
1262 // understandable by the document.
1263 sal_Int32 nInsertionIndex = rOverlay.GetInsertionIndicatorOverlay().GetInsertionPageIndex();
1264 if (nInsertionIndex >= 0)
1266 USHORT nDocumentIndex = (USHORT)nInsertionIndex-1;
1267 mrSlideSorter.GetController().GetSelectionManager()->MoveSelectedPages(nDocumentIndex);
1270 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
1271 if (pViewShell != NULL)
1272 pViewShell->GetViewFrame()->GetBindings().Invalidate(SID_STATUS_PAGE);
1279 void SelectionFunction::SubstitutionHandler::End (void)
1281 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
1282 rOverlay.GetSubstitutionOverlay().setVisible(false);
1283 rOverlay.GetSubstitutionOverlay().Clear();
1284 rOverlay.GetInsertionIndicatorOverlay().setVisible(false);
1290 bool SelectionFunction::SubstitutionHandler::HasBeenMoved (void) const
1292 return mbHasBeenMoved;
1298 bool SelectionFunction::SubstitutionHandler::IsSubstitutionInsertionNonTrivial (void) const
1300 bool bIsNonTrivial = false;
1304 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
1306 // Make sure that the substitution and the insertion indicator are visible.
1307 if ( ! rOverlay.GetSubstitutionOverlay().isVisible())
1308 break;
1309 if ( ! rOverlay.GetInsertionIndicatorOverlay().isVisible())
1310 break;
1312 // Iterate over all selected pages and check whether there are
1313 // holes. While we do this we remember the indices of the first and
1314 // last selected page as preparation for the next step.
1315 sal_Int32 nCurrentIndex = -1;
1316 sal_Int32 nFirstIndex = -1;
1317 sal_Int32 nLastIndex = -1;
1318 model::PageEnumeration aSelectedPages (
1319 model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
1320 mrSlideSorter.GetModel()));
1321 while (aSelectedPages.HasMoreElements() && ! bIsNonTrivial)
1323 model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
1324 SdPage* pPage = pDescriptor->GetPage();
1325 if (pPage != NULL)
1327 // Get the page number and compare it to the last one.
1328 sal_Int32 nPageNumber = (pPage->GetPageNum()-1)/2;
1329 if (nCurrentIndex>=0 && nPageNumber>(nCurrentIndex+1))
1330 bIsNonTrivial = true;
1331 else
1332 nCurrentIndex = nPageNumber;
1334 // Remember indices of the first and last page of the selection.
1335 if (nFirstIndex == -1)
1336 nFirstIndex = nPageNumber;
1337 nLastIndex = nPageNumber;
1340 if (bIsNonTrivial)
1341 break;
1343 // When we come here then the selection is consecutive. We still
1344 // have to check that the insertion position is not directly in
1345 // front or directly behind the selection and thus moving the
1346 // selection there would not change the model.
1347 sal_Int32 nInsertionIndex = rOverlay.GetInsertionIndicatorOverlay().GetInsertionPageIndex();
1348 if (nInsertionIndex<nFirstIndex || nInsertionIndex>(nLastIndex+1))
1349 bIsNonTrivial = true;
1351 while (false);
1353 return bIsNonTrivial;
1359 //===== InsertionIndicatorHandler =============================================
1361 SelectionFunction::InsertionIndicatorHandler::InsertionIndicatorHandler (
1362 SlideSorter& rSlideSorter)
1363 : mrSlideSorter(rSlideSorter)
1370 SelectionFunction::InsertionIndicatorHandler::~InsertionIndicatorHandler (void)
1377 void SelectionFunction::InsertionIndicatorHandler::Start (const Point& rMouseModelPosition)
1379 if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly())
1380 return;
1382 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
1383 rOverlay.GetInsertionIndicatorOverlay().SetPosition(rMouseModelPosition);
1384 rOverlay.GetInsertionIndicatorOverlay().setVisible(true);
1390 void SelectionFunction::InsertionIndicatorHandler::UpdatePosition (const Point& rMouseModelPosition)
1392 if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly())
1393 return;
1395 view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
1396 rOverlay.GetInsertionIndicatorOverlay().SetPosition(rMouseModelPosition);
1402 void SelectionFunction::InsertionIndicatorHandler::End (void)
1404 mrSlideSorter.GetView().GetOverlay().GetInsertionIndicatorOverlay().setVisible(false);
1407 } } } // end of namespace ::sd::slidesorter::controller