summaryrefslogtreecommitdiff
path: root/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx')
-rwxr-xr-xsd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx1317
1 files changed, 1317 insertions, 0 deletions
diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx
new file mode 100755
index 000000000000..c1d742ce7158
--- /dev/null
+++ b/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx
@@ -0,0 +1,1317 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_sd.hxx"
+
+#include "controller/SlsSelectionFunction.hxx"
+
+#include "SlideSorter.hxx"
+#include "SlideSorterViewShell.hxx"
+#include "controller/SlideSorterController.hxx"
+#include "controller/SlsPageSelector.hxx"
+#include "controller/SlsFocusManager.hxx"
+#include "controller/SlsScrollBarManager.hxx"
+#include "controller/SlsClipboard.hxx"
+#include "controller/SlsCurrentSlideManager.hxx"
+#include "controller/SlsSelectionManager.hxx"
+#include "controller/SlsProperties.hxx"
+#include "model/SlideSorterModel.hxx"
+#include "model/SlsPageDescriptor.hxx"
+#include "model/SlsPageEnumerationProvider.hxx"
+#include "view/SlideSorterView.hxx"
+#include "view/SlsViewOverlay.hxx"
+#include "view/SlsLayouter.hxx"
+#include "view/SlsPageObjectViewObjectContact.hxx"
+#include "framework/FrameworkHelper.hxx"
+#include "ViewShellBase.hxx"
+#include "DrawController.hxx"
+#include <vcl/sound.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/svdpagv.hxx>
+#include <vcl/msgbox.hxx>
+#include "Window.hxx"
+#include "sdpage.hxx"
+#include "drawdoc.hxx"
+#include "ViewShell.hxx"
+#include "ViewShellBase.hxx"
+#include "FrameView.hxx"
+#include "app.hrc"
+#include "sdresid.hxx"
+#include "strings.hrc"
+
+namespace {
+static const sal_uInt32 SINGLE_CLICK (0x00000001);
+static const sal_uInt32 DOUBLE_CLICK (0x00000002);
+static const sal_uInt32 LEFT_BUTTON (0x00000010);
+static const sal_uInt32 RIGHT_BUTTON (0x00000020);
+static const sal_uInt32 MIDDLE_BUTTON (0x00000040);
+static const sal_uInt32 BUTTON_DOWN (0x00000100);
+static const sal_uInt32 BUTTON_UP (0x00000200);
+static const sal_uInt32 MOUSE_MOTION (0x00000400);
+// The rest leaves the lower 16 bit untouched so that it can be used with
+// key codes.
+static const sal_uInt32 OVER_SELECTED_PAGE (0x00010000);
+static const sal_uInt32 OVER_UNSELECTED_PAGE (0x00020000);
+static const sal_uInt32 OVER_FADE_INDICATOR (0x00040000);
+static const sal_uInt32 SHIFT_MODIFIER (0x00100000);
+static const sal_uInt32 CONTROL_MODIFIER (0x00200000);
+static const sal_uInt32 SUBSTITUTION_VISIBLE (0x01000000);
+static const sal_uInt32 RECTANGLE_VISIBLE (0x02000000);
+
+static const sal_uInt32 KEY_EVENT (0x10000000);
+
+// Some absent events are defined so they can be expressed explicitly.
+static const sal_uInt32 NO_MODIFIER (0x00000000);
+static const sal_uInt32 SUBSTITUTION_NOT_VISIBLE (0x00000000);
+static const sal_uInt32 NOT_OVER_PAGE (0x00000000);
+
+
+} // end of anonymous namespace
+
+
+namespace sd { namespace slidesorter { namespace controller {
+
+class SelectionFunction::SubstitutionHandler
+{
+public:
+ SubstitutionHandler (SlideSorter& rSlideSorter);
+ ~SubstitutionHandler (void);
+
+ /** Create a substitution display of the currently selected pages and
+ use the given position as the anchor point.
+ */
+ void Start (const Point& rMouseModelPosition);
+
+ /** Move the substitution display by the distance the mouse has
+ travelled since the last call to this method or to
+ CreateSubstitution(). The given point becomes the new anchor.
+ */
+ void UpdatePosition (const Point& rMouseModelPosition);
+
+ /** Move the substitution display of the currently selected pages.
+ */
+ void Process (void);
+
+ void End (void);
+
+ bool HasBeenMoved (void) const;
+
+private:
+ SlideSorter& mrSlideSorter;
+
+ bool mbHasBeenMoved;
+
+ /** Determine whether there is a) a substitution and b) its insertion at
+ the current position of the insertion marker would alter the
+ document. This would be the case when the substitution has been
+ moved or is not consecutive.
+ */
+ bool IsSubstitutionInsertionNonTrivial (void) const;
+};
+
+
+class SelectionFunction::EventDescriptor
+{
+public:
+
+ Point maMousePosition;
+ Point maMouseModelPosition;
+ ::boost::weak_ptr<model::PageDescriptor> mpHitDescriptor;
+ SdrPage* mpHitPage;
+ sal_uInt32 mnEventCode;
+
+ EventDescriptor (
+ sal_uInt32 nEventType,
+ const MouseEvent& rEvent,
+ SlideSorter& rSlideSorter);
+ EventDescriptor (
+ const KeyEvent& rEvent,
+ SlideSorter& rSlideSorter);
+};
+
+
+TYPEINIT1(SelectionFunction, FuPoor);
+
+
+SelectionFunction::SelectionFunction (
+ SlideSorter& rSlideSorter,
+ SfxRequest& rRequest)
+ : SlideFunction (rSlideSorter, rRequest),
+ mrSlideSorter(rSlideSorter),
+ mrController(mrSlideSorter.GetController()),
+ mbDragSelection(false),
+ maInsertionMarkerBox(),
+ mbProcessingMouseButtonDown(false),
+ mpSubstitutionHandler(new SubstitutionHandler(mrSlideSorter))
+{
+ //af aDelayToScrollTimer.SetTimeout(50);
+ aDragTimer.SetTimeoutHdl( LINK( this, SelectionFunction, DragSlideHdl ) );
+}
+
+SelectionFunction::~SelectionFunction (void)
+{
+ aDragTimer.Stop();
+}
+
+
+
+
+FunctionReference SelectionFunction::Create(
+ SlideSorter& rSlideSorter,
+ SfxRequest& rRequest)
+{
+ FunctionReference xFunc( new SelectionFunction( rSlideSorter, rRequest ) );
+ return xFunc;
+}
+
+
+
+
+BOOL SelectionFunction::MouseButtonDown (const MouseEvent& rEvent)
+{
+ // #95491# remember button state for creation of own MouseEvents
+ SetMouseButtonCode (rEvent.GetButtons());
+ mbProcessingMouseButtonDown = true;
+
+ mpWindow->CaptureMouse();
+
+ ProcessMouseEvent(BUTTON_DOWN, rEvent);
+
+ return TRUE;
+}
+
+
+
+
+BOOL SelectionFunction::MouseMove (const MouseEvent& rEvent)
+{
+ Point aMousePosition (rEvent.GetPosPixel());
+
+ // Determine page under mouse and show the mouse over effect.
+ model::SharedPageDescriptor pHitDescriptor (mrController.GetPageAt(aMousePosition));
+ view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
+ rOverlay.GetMouseOverIndicatorOverlay().SetSlideUnderMouse(
+ rEvent.IsLeaveWindow() ? model::SharedPageDescriptor() : pHitDescriptor);
+ if (pHitDescriptor.get() != NULL)
+ rOverlay.GetMouseOverIndicatorOverlay().setVisible(true);
+ else
+ rOverlay.GetMouseOverIndicatorOverlay().setVisible(false);
+
+ // Allow one mouse move before the drag timer is disabled.
+ if (aDragTimer.IsActive())
+ {
+ if (bFirstMouseMove)
+ bFirstMouseMove = FALSE;
+ else
+ aDragTimer.Stop();
+ }
+
+ Rectangle aRectangle (Point(0,0),mpWindow->GetOutputSizePixel());
+ if ( ! aRectangle.IsInside(aMousePosition)
+ && rOverlay.GetSubstitutionOverlay().isVisible())
+ {
+ // Mouse left the window with pressed left button. Make it a drag.
+ StartDrag();
+ }
+ else
+ {
+ // Call ProcessMouseEvent() only when one of the buttons is
+ // pressed. This prevents calling the method on every motion.
+ if (rEvent.GetButtons() != 0
+ && mbProcessingMouseButtonDown)
+ {
+ ProcessMouseEvent(MOUSE_MOTION, rEvent);
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+
+BOOL SelectionFunction::MouseButtonUp (const MouseEvent& rEvent)
+{
+ mrController.GetScrollBarManager().StopAutoScroll ();
+
+ // #95491# remember button state for creation of own MouseEvents
+ SetMouseButtonCode (rEvent.GetButtons());
+
+ if (aDragTimer.IsActive())
+ aDragTimer.Stop();
+
+ ProcessMouseEvent(BUTTON_UP, rEvent);
+
+ mbProcessingMouseButtonDown = false;
+ mpWindow->ReleaseMouse();
+
+ return TRUE;
+}
+
+
+
+
+BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent)
+{
+ FocusManager& rFocusManager (mrController.GetFocusManager());
+ BOOL bResult = FALSE;
+
+ switch (rEvent.GetKeyCode().GetCode())
+ {
+ case KEY_RETURN:
+ if (rFocusManager.HasFocus())
+ {
+ model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor());
+ if (pDescriptor.get() != NULL)
+ {
+ SetCurrentPage(pDescriptor);
+ SwitchView(pDescriptor);
+ }
+ bResult = TRUE;
+ }
+ break;
+
+ case KEY_TAB:
+ if ( ! rFocusManager.IsFocusShowing())
+ rFocusManager.ShowFocus();
+ else
+ if (rEvent.GetKeyCode().IsShift())
+ rFocusManager.MoveFocus (FocusManager::FMD_LEFT);
+ else
+ rFocusManager.MoveFocus (FocusManager::FMD_RIGHT);
+ bResult = TRUE;
+ break;
+
+ case KEY_ESCAPE:
+ rFocusManager.SetFocusToToolBox();
+ bResult = TRUE;
+ break;
+
+ case KEY_SPACE:
+ {
+ // Toggle the selection state.
+ model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor());
+ if (pDescriptor.get() != NULL)
+ {
+ // Doing a multi selection by default. Can we ask the event
+ // for the state of the shift key?
+ if (pDescriptor->IsSelected())
+ mrController.GetPageSelector().DeselectPage(pDescriptor);
+ else
+ mrController.GetPageSelector().SelectPage(pDescriptor);
+ }
+ bResult = TRUE;
+ }
+ break;
+
+
+ // Move the focus indicator left.
+ case KEY_LEFT:
+ rFocusManager.MoveFocus (FocusManager::FMD_LEFT);
+ bResult = TRUE;
+ break;
+
+ // Move the focus indicator right.
+ case KEY_RIGHT:
+ rFocusManager.MoveFocus (FocusManager::FMD_RIGHT);
+ bResult = TRUE;
+ break;
+
+ // Move the focus indicator up.
+ case KEY_UP:
+ rFocusManager.MoveFocus (FocusManager::FMD_UP);
+ bResult = TRUE;
+ break;
+
+ // Move the focus indicator down.
+ case KEY_DOWN:
+ rFocusManager.MoveFocus (FocusManager::FMD_DOWN);
+ bResult = TRUE;
+ break;
+
+ // Go to previous page. No wrap around.
+ case KEY_PAGEUP:
+ GotoNextPage(-1);
+ bResult = TRUE;
+ break;
+
+ // Go to next page. No wrap around..
+ case KEY_PAGEDOWN:
+ GotoNextPage(+1);
+ bResult = TRUE;
+ break;
+
+ case KEY_DELETE:
+ case KEY_BACKSPACE:
+ {
+ if (mrController.GetProperties()->IsUIReadOnly())
+ break;
+
+ int nSelectedPagesCount = 0;
+
+ // Count the selected pages and look if there any objects on any
+ // of the selected pages so that we can warn the user and
+ // prevent an accidental deletion.
+ model::PageEnumeration aSelectedPages (
+ model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ while (aSelectedPages.HasMoreElements())
+ {
+ nSelectedPagesCount++;
+ aSelectedPages.GetNextElement();
+ }
+
+ if (nSelectedPagesCount > 0)
+ mrController.GetSelectionManager()->DeleteSelectedPages();
+
+ bResult = TRUE;
+ }
+ break;
+
+ case KEY_F10:
+ if (rEvent.GetKeyCode().IsShift())
+ ProcessKeyEvent(rEvent);
+ break;
+
+ default:
+ break;
+ }
+
+ if ( ! bResult)
+ bResult = SlideFunction::KeyInput (rEvent);
+
+ return bResult;
+}
+
+
+
+
+void SelectionFunction::Activate()
+{
+ FuPoor::Activate();
+}
+
+
+
+
+void SelectionFunction::Deactivate()
+{
+ FuPoor::Deactivate();
+}
+
+
+
+void SelectionFunction::ScrollStart (void)
+{
+}
+
+
+
+
+void SelectionFunction::ScrollEnd (void)
+{
+}
+
+
+
+
+void SelectionFunction::DoCut (void)
+{
+ if ( ! mrController.GetProperties()->IsUIReadOnly())
+ {
+ mrController.GetClipboard().DoCut();
+ }
+}
+
+
+
+
+void SelectionFunction::DoCopy (void)
+{
+ mrController.GetClipboard().DoCopy();
+}
+
+
+
+
+void SelectionFunction::DoPaste (void)
+{
+ if ( ! mrController.GetProperties()->IsUIReadOnly())
+ {
+ mrController.GetClipboard().DoPaste();
+ }
+}
+
+
+
+
+void SelectionFunction::Paint (const Rectangle&, ::sd::Window* )
+{
+}
+
+
+
+
+IMPL_LINK( SelectionFunction, DragSlideHdl, Timer*, EMPTYARG )
+{
+ StartDrag();
+ return 0;
+}
+
+
+
+
+void SelectionFunction::StartDrag (void)
+{
+ if (mbPageHit
+ && ! mrController.GetProperties()->IsUIReadOnly())
+ {
+ view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
+ mpSubstitutionHandler->Start(rOverlay.GetSubstitutionOverlay().GetPosition());
+ mbPageHit = false;
+ mpWindow->ReleaseMouse();
+
+ if (mrSlideSorter.GetViewShell() != NULL)
+ {
+ SlideSorterViewShell* pSlideSorterViewShell
+ = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell());
+ pSlideSorterViewShell->StartDrag (
+ rOverlay.GetSubstitutionOverlay().GetPosition(),
+ mpWindow);
+ }
+ }
+}
+
+
+
+
+bool SelectionFunction::cancel (void)
+{
+ mrController.GetFocusManager().ToggleFocus();
+ return true;
+}
+
+
+
+
+void SelectionFunction::SelectHitPage (const model::SharedPageDescriptor& rpDescriptor)
+{
+ mrController.GetPageSelector().SelectPage(rpDescriptor);
+}
+
+
+
+
+void SelectionFunction::DeselectHitPage (const model::SharedPageDescriptor& rpDescriptor)
+{
+ mrController.GetPageSelector().DeselectPage(rpDescriptor);
+}
+
+
+
+
+void SelectionFunction::DeselectAllPages (void)
+{
+ mrController.GetPageSelector().DeselectAllPages();
+}
+
+
+
+
+void SelectionFunction::StartRectangleSelection (const Point& rMouseModelPosition)
+{
+ if (mrController.GetProperties()->IsShowSelection())
+ {
+ mrSlideSorter.GetView().GetOverlay().GetSelectionRectangleOverlay().Start(
+ rMouseModelPosition);
+ }
+}
+
+
+
+
+void SelectionFunction::UpdateRectangleSelection (const Point& rMouseModelPosition)
+{
+ if (mrController.GetProperties()->IsShowSelection())
+ {
+ mrSlideSorter.GetView().GetOverlay().GetSelectionRectangleOverlay().Update(
+ rMouseModelPosition);
+ }
+}
+
+
+
+
+void SelectionFunction::ProcessRectangleSelection (bool bToggleSelection)
+{
+ if ( ! mrController.GetProperties()->IsShowSelection())
+ return;
+
+ view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
+ if (rOverlay.GetSelectionRectangleOverlay().isVisible())
+ {
+ PageSelector& rSelector (mrController.GetPageSelector());
+
+ rOverlay.GetSelectionRectangleOverlay().setVisible(false);
+
+ // Select all pages whose page object lies completly inside the drag
+ // rectangle.
+ const Rectangle& rSelectionRectangle (
+ rOverlay.GetSelectionRectangleOverlay().GetSelectionRectangle());
+ model::PageEnumeration aPages (
+ model::PageEnumerationProvider::CreateAllPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ while (aPages.HasMoreElements())
+ {
+ model::SharedPageDescriptor pDescriptor (aPages.GetNextElement());
+ Rectangle aPageBox (mrSlideSorter.GetView().GetPageBoundingBox(
+ pDescriptor,
+ view::SlideSorterView::CS_MODEL,
+ view::SlideSorterView::BBT_SHAPE));
+ if (rSelectionRectangle.IsOver(aPageBox))
+ {
+ // When we are extending the selection (shift key is
+ // pressed) then toggle the selection state of the page.
+ // Otherwise select it: this results in the previously
+ // selected pages becoming deslected.
+ if (bToggleSelection && pDescriptor->IsSelected())
+ rSelector.DeselectPage(pDescriptor);
+ else
+ rSelector.SelectPage(pDescriptor);
+ }
+ }
+ }
+}
+
+
+
+
+void SelectionFunction::PrepareMouseMotion (const Point& )
+{
+ if ( ! mrController.GetProperties()->IsUIReadOnly())
+ {
+ bFirstMouseMove = TRUE;
+ aDragTimer.Start();
+ }
+}
+
+
+
+
+void SelectionFunction::RangeSelect (const model::SharedPageDescriptor& rpDescriptor)
+{
+ PageSelector& rSelector (mrController.GetPageSelector());
+
+ model::SharedPageDescriptor pAnchor (rSelector.GetSelectionAnchor());
+ DeselectAllPages();
+
+ if (pAnchor.get() != NULL)
+ {
+ // Select all pages between the anchor and the given one, including
+ // the two.
+ USHORT nAnchorIndex ((pAnchor->GetPage()->GetPageNum()-1) / 2);
+ USHORT nOtherIndex ((rpDescriptor->GetPage()->GetPageNum()-1) / 2);
+
+ // Iterate over all pages in the range. Start with the anchor
+ // page. This way the PageSelector will recognize it again as
+ // anchor (the first selected page after a DeselectAllPages()
+ // becomes the anchor.)
+ USHORT nStep = (nAnchorIndex < nOtherIndex) ? +1 : -1;
+ USHORT nIndex = nAnchorIndex;
+ while (true)
+ {
+ rSelector.SelectPage(nIndex);
+ if (nIndex == nOtherIndex)
+ break;
+ nIndex = nIndex + nStep;
+ }
+ }
+}
+
+
+
+
+void SelectionFunction::GotoNextPage (int nOffset)
+{
+ model::SharedPageDescriptor pDescriptor
+ = mrController.GetCurrentSlideManager()->GetCurrentSlide();
+ if (pDescriptor.get() != NULL)
+ {
+ SdPage* pPage = pDescriptor->GetPage();
+ OSL_ASSERT(pPage!=NULL);
+ sal_Int32 nIndex = (pPage->GetPageNum()-1) / 2;
+ nIndex += nOffset;
+ USHORT nPageCount = (USHORT)mrSlideSorter.GetModel().GetPageCount();
+
+ if (nIndex >= nPageCount)
+ nIndex = nPageCount - 1;
+ if (nIndex < 0)
+ nIndex = 0;
+
+ mrController.GetFocusManager().SetFocusedPage(nIndex);
+ model::SharedPageDescriptor pNextPageDescriptor (
+ mrSlideSorter.GetModel().GetPageDescriptor (nIndex));
+ if (pNextPageDescriptor.get() != NULL)
+ SetCurrentPage(pNextPageDescriptor);
+ else
+ {
+ OSL_ASSERT(pNextPageDescriptor.get() != NULL);
+ }
+ }
+}
+
+
+
+
+void SelectionFunction::ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent)
+{
+ // #95491# remember button state for creation of own MouseEvents
+ SetMouseButtonCode (rEvent.GetButtons());
+
+ // 1. Compute some frequently used values relating to the event.
+ ::std::auto_ptr<EventDescriptor> pEventDescriptor (
+ new EventDescriptor(nEventType, rEvent, mrSlideSorter));
+
+ // 2. Compute a numerical code that describes the event and that is used
+ // for fast look-up of the associated reaction.
+ pEventDescriptor->mnEventCode = EncodeMouseEvent(*pEventDescriptor, rEvent);
+
+ // 3. Process the event.
+ EventPreprocessing(*pEventDescriptor);
+ if ( ! EventProcessing(*pEventDescriptor))
+ {
+ OSL_TRACE ("can not handle event code %x", pEventDescriptor->mnEventCode);
+ }
+ EventPostprocessing(*pEventDescriptor);
+
+ if (nEventType == BUTTON_UP)
+ mbPageHit = false;
+}
+
+
+
+
+sal_uInt32 SelectionFunction::EncodeMouseEvent (
+ const EventDescriptor& rDescriptor,
+ const MouseEvent& rEvent) const
+{
+ // Initialize with the type of mouse event.
+ sal_uInt32 nEventCode (rDescriptor.mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION));
+
+ // Detect the affected button.
+ switch (rEvent.GetButtons())
+ {
+ case MOUSE_LEFT: nEventCode |= LEFT_BUTTON; break;
+ case MOUSE_RIGHT: nEventCode |= RIGHT_BUTTON; break;
+ case MOUSE_MIDDLE: nEventCode |= MIDDLE_BUTTON; break;
+ }
+
+ // Detect the number of clicks.
+ switch (rEvent.GetClicks())
+ {
+ case 1: nEventCode |= SINGLE_CLICK; break;
+ case 2: nEventCode |= DOUBLE_CLICK; break;
+ }
+
+ // Detect whether the event has happened over a page object.
+ if (rDescriptor.mpHitPage != NULL && ! rDescriptor.mpHitDescriptor.expired())
+ {
+ model::SharedPageDescriptor pHitDescriptor (rDescriptor.mpHitDescriptor);
+ if (pHitDescriptor->IsSelected())
+ nEventCode |= OVER_SELECTED_PAGE;
+ else
+ nEventCode |= OVER_UNSELECTED_PAGE;
+ }
+
+ // Detect pressed modifier keys.
+ if (rEvent.IsShift())
+ nEventCode |= SHIFT_MODIFIER;
+ if (rEvent.IsMod1())
+ nEventCode |= CONTROL_MODIFIER;
+
+ // Detect whether we are dragging pages or dragging a selection rectangle.
+ view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
+ if (rOverlay.GetSubstitutionOverlay().isVisible())
+ nEventCode |= SUBSTITUTION_VISIBLE;
+ if (rOverlay.GetSelectionRectangleOverlay().isVisible())
+ nEventCode |= RECTANGLE_VISIBLE;
+
+ return nEventCode;
+}
+
+
+
+
+void SelectionFunction::ProcessKeyEvent (const KeyEvent& rEvent)
+{
+ // 1. Compute some frequently used values relating to the event.
+ ::std::auto_ptr<EventDescriptor> pEventDescriptor (
+ new EventDescriptor(rEvent, mrSlideSorter));
+
+ // 2. Encode the event.
+ pEventDescriptor->mnEventCode = EncodeKeyEvent(*pEventDescriptor, rEvent);
+
+ // 3. Process the event.
+ EventPreprocessing(*pEventDescriptor);
+ if ( ! EventProcessing(*pEventDescriptor))
+ OSL_TRACE ("can not handle event code %x", pEventDescriptor->mnEventCode);
+ EventPostprocessing(*pEventDescriptor);
+}
+
+
+
+
+sal_uInt32 SelectionFunction::EncodeKeyEvent (
+ const EventDescriptor& rDescriptor,
+ const KeyEvent& rEvent) const
+{
+ // Initialize as key event.
+ sal_uInt32 nEventCode (KEY_EVENT);
+
+ // Add the actual key code in the lower 16 bit.
+ nEventCode |= rEvent.GetKeyCode().GetCode();
+
+ // Detect pressed modifier keys.
+ if (rEvent.GetKeyCode().IsShift())
+ nEventCode |= SHIFT_MODIFIER;
+ if (rEvent.GetKeyCode().IsMod1())
+ nEventCode |= CONTROL_MODIFIER;
+
+ // Detect whether the event has happened over a page object.
+ if (rDescriptor.mpHitPage != NULL && ! rDescriptor.mpHitDescriptor.expired())
+ {
+ model::SharedPageDescriptor pHitDescriptor (rDescriptor.mpHitDescriptor);
+ if (pHitDescriptor->IsSelected())
+ nEventCode |= OVER_SELECTED_PAGE;
+ else
+ nEventCode |= OVER_UNSELECTED_PAGE;
+ }
+
+ // Detect whether we are dragging pages or dragging a selection rectangle.
+ view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
+ if (rOverlay.GetSubstitutionOverlay().isVisible())
+ nEventCode |= SUBSTITUTION_VISIBLE;
+ if (rOverlay.GetSelectionRectangleOverlay().isVisible())
+ nEventCode |= RECTANGLE_VISIBLE;
+
+ return nEventCode;
+}
+
+
+
+void SelectionFunction::EventPreprocessing (const EventDescriptor& rDescriptor)
+{
+ // Some general processing that is not specific to the exact event code.
+ if (rDescriptor.mnEventCode & BUTTON_DOWN)
+ mbPageHit = (rDescriptor.mpHitPage!=NULL);
+
+ // Set the focus to the slide under the mouse.
+ if (rDescriptor.mpHitPage != NULL)
+ mrController.GetFocusManager().FocusPage((rDescriptor.mpHitPage->GetPageNum()-1)/2);
+}
+
+
+
+
+bool SelectionFunction::EventProcessing (const EventDescriptor& rDescriptor)
+{
+ // Define some macros to make the following switch statement more readable.
+#define ANY_MODIFIER(code) \
+ code|NO_MODIFIER: \
+ case code|SHIFT_MODIFIER: \
+ case code|CONTROL_MODIFIER
+#define ANY_PAGE(code) \
+ code|NOT_OVER_PAGE: \
+ case code|OVER_UNSELECTED_PAGE: \
+ case code|OVER_SELECTED_PAGE
+#define ANY_PAGE_AND_MODIFIER(code) \
+ ANY_PAGE(code|NO_MODIFIER): \
+ case ANY_PAGE(code|SHIFT_MODIFIER): \
+ case ANY_PAGE(code|CONTROL_MODIFIER)
+
+
+ bool bResult (true);
+ bool bMakeSelectionVisible (true);
+
+ mrController.GetPageSelector().DisableBroadcasting();
+
+ // 2b. With the event code determine the type of operation with which to
+ // react to the event.
+
+ // Acquire a shared_ptr to the hit page descriptor.
+ model::SharedPageDescriptor pHitDescriptor;
+ if ( ! rDescriptor.mpHitDescriptor.expired())
+ pHitDescriptor = model::SharedPageDescriptor(rDescriptor.mpHitDescriptor);
+
+ switch (rDescriptor.mnEventCode)
+ {
+ case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE:
+ SetCurrentPage(pHitDescriptor);
+ PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition));
+ mpSubstitutionHandler->Start(rDescriptor.maMouseModelPosition);
+ break;
+
+ case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
+ SetCurrentPage(pHitDescriptor);
+ mpSubstitutionHandler->End();
+ break;
+
+ case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
+ PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition));
+ mpSubstitutionHandler->Start(rDescriptor.maMouseModelPosition);
+ break;
+
+ case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_SELECTED_PAGE:
+ case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_UNSELECTED_PAGE:
+ // A double click allways shows the selected slide in the center
+ // pane in an edit view.
+ SetCurrentPage(pHitDescriptor);
+ SwitchView(pHitDescriptor);
+ break;
+
+ // Multi selection with the control modifier.
+ case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | CONTROL_MODIFIER:
+ DeselectHitPage(pHitDescriptor);
+ PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition));
+ break;
+
+ case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | CONTROL_MODIFIER:
+ SelectHitPage(pHitDescriptor);
+ PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition));
+
+ break;
+
+ // Range selection with the shift modifier.
+ case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | SHIFT_MODIFIER:
+ case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | SHIFT_MODIFIER:
+ RangeSelect(pHitDescriptor);
+ break;
+
+ // Was: Preview of the page transition effect.
+ case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_FADE_INDICATOR:
+ // No action.
+ break;
+
+ // Right button for context menu.
+ case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE:
+ case KEY_EVENT | KEY_F10 | SHIFT_MODIFIER | OVER_UNSELECTED_PAGE:
+ // Single right click and shift+F10 select as preparation to
+ // show the context menu. Change the selection only when the
+ // page under the mouse is not selected. In this case the
+ // selection is set to this single page. Otherwise the
+ // selection is not modified.
+ DeselectAllPages();
+ SelectHitPage(pHitDescriptor);
+ SetCurrentPage(pHitDescriptor);
+ bMakeSelectionVisible = false;
+ break;
+
+ case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE:
+ case KEY_EVENT | KEY_F10 | OVER_SELECTED_PAGE | SHIFT_MODIFIER:
+ // Do not change the selection. Just adjust the insertion indicator.
+ bMakeSelectionVisible = false;
+ break;
+
+ case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE:
+ // The Shift+F10 key event is here just for completeness. It should
+ // not be possible to really receive this (not being over a page.)
+ case KEY_EVENT | KEY_F10 | SHIFT_MODIFIER | NOT_OVER_PAGE:
+ DeselectAllPages();
+ bMakeSelectionVisible = false;
+ break;
+
+ // A mouse motion without visible substitution starts that.
+ case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE):
+ mrController.GetScrollBarManager().AutoScroll(rDescriptor.maMousePosition);
+ mpSubstitutionHandler->Start(rDescriptor.maMouseModelPosition);
+ break;
+
+ // Move substitution.
+ case ANY_PAGE_AND_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | SUBSTITUTION_VISIBLE):
+ if ((rDescriptor.mnEventCode & CONTROL_MODIFIER) != 0)
+ StartDrag();
+ mrController.GetScrollBarManager().AutoScroll(rDescriptor.maMousePosition);
+ mpSubstitutionHandler->UpdatePosition(rDescriptor.maMouseModelPosition);
+ break;
+
+ // Place substitution.
+ case ANY_PAGE_AND_MODIFIER(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | SUBSTITUTION_VISIBLE):
+ // When the substitution has not been moved the button up event
+ // is taken to be part of a single click. The selected pages
+ // are therefore not moved (which technically would be necessary
+ // for unconsecutive multi selections). Instead the page under
+ // the mouse becomes the only selected page.
+ if (mpSubstitutionHandler->HasBeenMoved())
+ {
+ // The following Process() call may lead to the desctruction
+ // of pHitDescriptor so release our reference to it.
+ pHitDescriptor.reset();
+ mpSubstitutionHandler->Process();
+ }
+ else
+ if (pHitDescriptor != NULL)
+ SetCurrentPage(pHitDescriptor);
+ mpSubstitutionHandler->End();
+ break;
+
+ // Rectangle selection.
+ case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE | NO_MODIFIER:
+ DeselectAllPages();
+ StartRectangleSelection(rDescriptor.maMouseModelPosition);
+ break;
+
+ case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE | SHIFT_MODIFIER:
+ case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE | CONTROL_MODIFIER:
+ StartRectangleSelection(rDescriptor.maMouseModelPosition);
+ break;
+
+ case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE):
+ case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE):
+ case ANY_PAGE_AND_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE):
+ mrController.GetScrollBarManager().AutoScroll(rDescriptor.maMousePosition);
+ UpdateRectangleSelection(rDescriptor.maMouseModelPosition);
+ break;
+
+ case ANY_PAGE(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE | NO_MODIFIER):
+ ProcessRectangleSelection(false);
+ break;
+
+ case ANY_PAGE(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE | SHIFT_MODIFIER):
+ case ANY_PAGE(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE | CONTROL_MODIFIER):
+ ProcessRectangleSelection(true);
+ break;
+
+ default:
+ bResult = false;
+ break;
+ }
+ mrController.GetPageSelector().EnableBroadcasting(bMakeSelectionVisible);
+
+ return bResult;
+}
+
+
+
+
+void SelectionFunction::EventPostprocessing (const EventDescriptor& rDescriptor)
+{
+ if (rDescriptor.mnEventCode & BUTTON_UP)
+ {
+ view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
+
+ mpWindow->ReleaseMouse();
+
+ // The overlays should not be visible anymore. Warn when one of
+ // them still is. An exception is th insertion indicator in the
+ // case that the context menu is visible.
+ DBG_ASSERT(
+ mrController.IsContextMenuOpen()
+ || !rOverlay.GetInsertionIndicatorOverlay().isVisible(),
+ "slidesorter::SelectionFunction: insertion indicator still visible");
+ DBG_ASSERT(
+ !rOverlay.GetSubstitutionOverlay().isVisible(),
+ "slidesorter::SelectionFunction: substitution still visible");
+ DBG_ASSERT(
+ !rOverlay.GetSelectionRectangleOverlay().isVisible(),
+ "slidesorter::SelectionFunction: selection rectangle still visible");
+
+ // Now turn them off.
+ if ( ! mrController.IsContextMenuOpen())
+ rOverlay.GetInsertionIndicatorOverlay().setVisible(false);
+ rOverlay.GetSubstitutionOverlay().setVisible(false);
+ rOverlay.GetSelectionRectangleOverlay().setVisible(false);
+ }
+}
+
+
+
+
+void SelectionFunction::SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor)
+{
+ PageSelector& rSelector (mrController.GetPageSelector());
+ rSelector.DeselectAllPages ();
+ rSelector.SelectPage(rpDescriptor);
+
+ mrController.GetCurrentSlideManager()->SwitchCurrentSlide(rpDescriptor);
+}
+
+
+
+
+void SelectionFunction::SwitchView (const model::SharedPageDescriptor& rpDescriptor)
+{
+ // Switch to the draw view. This is done only when the current
+ // view is the main view.
+ ViewShell* pViewShell = mrSlideSorter.GetViewShell();
+ if (pViewShell!=NULL && pViewShell->IsMainViewShell())
+ {
+ if (rpDescriptor.get()!=NULL && rpDescriptor->GetPage()!=NULL)
+ {
+ mrSlideSorter.GetModel().GetDocument()->SetSelected(rpDescriptor->GetPage(), TRUE);
+ mpViewShell->GetFrameView()->SetSelectedPage(
+ (rpDescriptor->GetPage()->GetPageNum()-1)/2);
+ }
+ if (mrSlideSorter.GetViewShellBase() != NULL)
+ framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase())->RequestView(
+ framework::FrameworkHelper::msImpressViewURL,
+ framework::FrameworkHelper::msCenterPaneURL);
+ }
+}
+
+
+
+
+//===== EventDescriptor =======================================================
+
+SelectionFunction::EventDescriptor::EventDescriptor (
+ sal_uInt32 nEventType,
+ const MouseEvent& rEvent,
+ SlideSorter& rSlideSorter)
+ : maMousePosition(),
+ maMouseModelPosition(),
+ mpHitDescriptor(),
+ mpHitPage(),
+ mnEventCode(nEventType)
+{
+ ::Window* pWindow = rSlideSorter.GetActiveWindow();
+
+ maMousePosition = rEvent.GetPosPixel();
+ maMouseModelPosition = pWindow->PixelToLogic(maMousePosition);
+ model::SharedPageDescriptor pHitDescriptor (
+ rSlideSorter.GetController().GetPageAt(maMousePosition));
+ if (pHitDescriptor.get() != NULL)
+ {
+ mpHitDescriptor = pHitDescriptor;
+ mpHitPage = pHitDescriptor->GetPage();
+ }
+}
+
+
+
+
+
+SelectionFunction::EventDescriptor::EventDescriptor (
+ const KeyEvent&,
+ SlideSorter& rSlideSorter)
+ : maMousePosition(),
+ maMouseModelPosition(),
+ mpHitDescriptor(),
+ mpHitPage(),
+ mnEventCode(0)
+{
+ mpHitDescriptor = rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor();
+ model::SharedPageDescriptor pHitDescriptor (
+ rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor());
+ if (pHitDescriptor.get() != NULL)
+ {
+ mpHitPage = pHitDescriptor->GetPage();
+ mpHitDescriptor = pHitDescriptor;
+ }
+}
+
+
+
+
+
+//===== SubstitutionHandler ===================================================
+
+SelectionFunction::SubstitutionHandler::SubstitutionHandler (SlideSorter& rSlideSorter)
+ : mrSlideSorter(rSlideSorter),
+ mbHasBeenMoved(false)
+{
+}
+
+
+
+
+SelectionFunction::SubstitutionHandler::~SubstitutionHandler (void)
+{
+ if (mrSlideSorter.IsValid())
+ {
+ view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
+ rOverlay.GetSubstitutionOverlay().setVisible(false);
+ rOverlay.GetSubstitutionOverlay().Clear();
+ }
+}
+
+
+
+
+void SelectionFunction::SubstitutionHandler::Start (const Point& rMouseModelPosition)
+{
+ // No Drag-and-Drop for master pages.
+ if (mrSlideSorter.GetModel().GetEditMode() != EM_PAGE)
+ return;
+
+ if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly())
+ return;
+
+ view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
+
+ if ( ! rOverlay.GetSubstitutionOverlay().isVisible())
+ {
+ // Show a new substitution for the selected page objects.
+ model::PageEnumeration aSelectedPages(
+ model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ rOverlay.GetSubstitutionOverlay().Create(aSelectedPages, rMouseModelPosition);
+ rOverlay.GetSubstitutionOverlay().setVisible(true);
+ mbHasBeenMoved = false;
+ }
+ else
+ UpdatePosition(rMouseModelPosition);
+}
+
+
+
+
+void SelectionFunction::SubstitutionHandler::UpdatePosition (const Point& rMouseModelPosition)
+{
+ if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly())
+ return;
+
+ view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
+
+ // Move the existing substitution to the new position.
+ rOverlay.GetSubstitutionOverlay().SetPosition(rMouseModelPosition);
+
+ rOverlay.GetInsertionIndicatorOverlay().SetPosition(rMouseModelPosition);
+ rOverlay.GetInsertionIndicatorOverlay().setVisible(true);
+
+ mbHasBeenMoved = true;
+}
+
+
+
+
+void SelectionFunction::SubstitutionHandler::Process (void)
+{
+ if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly())
+ return;
+
+ view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
+
+ if (IsSubstitutionInsertionNonTrivial())
+ {
+ // Tell the model to move the selected pages behind the one with the
+ // index mnInsertionIndex which first has to transformed into an index
+ // understandable by the document.
+ sal_Int32 nInsertionIndex = rOverlay.GetInsertionIndicatorOverlay().GetInsertionPageIndex();
+ if (nInsertionIndex >= 0)
+ {
+ USHORT nDocumentIndex = (USHORT)nInsertionIndex-1;
+ mrSlideSorter.GetController().GetSelectionManager()->MoveSelectedPages(nDocumentIndex);
+ }
+
+ ViewShell* pViewShell = mrSlideSorter.GetViewShell();
+ if (pViewShell != NULL)
+ pViewShell->GetViewFrame()->GetBindings().Invalidate(SID_STATUS_PAGE);
+ }
+}
+
+
+
+
+void SelectionFunction::SubstitutionHandler::End (void)
+{
+ view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
+ rOverlay.GetSubstitutionOverlay().setVisible(false);
+ rOverlay.GetSubstitutionOverlay().Clear();
+ rOverlay.GetInsertionIndicatorOverlay().setVisible(false);
+}
+
+
+
+
+bool SelectionFunction::SubstitutionHandler::HasBeenMoved (void) const
+{
+ return mbHasBeenMoved;
+}
+
+
+
+
+bool SelectionFunction::SubstitutionHandler::IsSubstitutionInsertionNonTrivial (void) const
+{
+ bool bIsNonTrivial = false;
+
+ do
+ {
+ view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
+
+ // Make sure that the substitution and the insertion indicator are visible.
+ if ( ! rOverlay.GetSubstitutionOverlay().isVisible())
+ break;
+ if ( ! rOverlay.GetInsertionIndicatorOverlay().isVisible())
+ break;
+
+ // Iterate over all selected pages and check whether there are
+ // holes. While we do this we remember the indices of the first and
+ // last selected page as preparation for the next step.
+ sal_Int32 nCurrentIndex = -1;
+ sal_Int32 nFirstIndex = -1;
+ sal_Int32 nLastIndex = -1;
+ model::PageEnumeration aSelectedPages (
+ model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
+ mrSlideSorter.GetModel()));
+ while (aSelectedPages.HasMoreElements() && ! bIsNonTrivial)
+ {
+ model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
+ SdPage* pPage = pDescriptor->GetPage();
+ if (pPage != NULL)
+ {
+ // Get the page number and compare it to the last one.
+ sal_Int32 nPageNumber = (pPage->GetPageNum()-1)/2;
+ if (nCurrentIndex>=0 && nPageNumber>(nCurrentIndex+1))
+ bIsNonTrivial = true;
+ else
+ nCurrentIndex = nPageNumber;
+
+ // Remember indices of the first and last page of the selection.
+ if (nFirstIndex == -1)
+ nFirstIndex = nPageNumber;
+ nLastIndex = nPageNumber;
+ }
+ }
+ if (bIsNonTrivial)
+ break;
+
+ // When we come here then the selection is consecutive. We still
+ // have to check that the insertion position is not directly in
+ // front or directly behind the selection and thus moving the
+ // selection there would not change the model.
+ sal_Int32 nInsertionIndex = rOverlay.GetInsertionIndicatorOverlay().GetInsertionPageIndex();
+ if (nInsertionIndex<nFirstIndex || nInsertionIndex>(nLastIndex+1))
+ bIsNonTrivial = true;
+ }
+ while (false);
+
+ return bIsNonTrivial;
+}
+
+} } } // end of namespace ::sd::slidesorter::controller