diff options
Diffstat (limited to 'sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx')
-rw-r--r--[-rwxr-xr-x] | sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx | 1989 |
1 files changed, 1348 insertions, 641 deletions
diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx index c1d742ce7158..1d4d075fc3ce 100755..100644 --- a/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx +++ b/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx @@ -31,38 +31,49 @@ #include "SlideSorter.hxx" #include "SlideSorterViewShell.hxx" +#include "SlsDragAndDropContext.hxx" +#include "controller/SlsTransferable.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/SlsInsertionIndicatorHandler.hxx" #include "controller/SlsSelectionManager.hxx" #include "controller/SlsProperties.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsSlotManager.hxx" +#include "controller/SlsVisibleAreaManager.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 "view/SlsPageObjectLayouter.hxx" +#include "view/SlsButtonBar.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 "DrawDocShell.hxx" +#include "sdxfer.hxx" #include "ViewShell.hxx" #include "ViewShellBase.hxx" #include "FrameView.hxx" #include "app.hrc" #include "sdresid.hxx" #include "strings.hrc" +#include <vcl/sound.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/svdpagv.hxx> +#include <vcl/msgbox.hxx> +#include <svx/svxids.hrc> +#include <boost/bind.hpp> +#include <boost/optional.hpp> namespace { static const sal_uInt32 SINGLE_CLICK (0x00000001); @@ -73,109 +84,304 @@ 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); +static const sal_uInt32 MOUSE_DRAG (0x00000800); // 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 OVER_BUTTON_AREA (0x00080000); +static const sal_uInt32 OVER_BUTTON (0x00100000); +static const sal_uInt32 SHIFT_MODIFIER (0x00200000); +static const sal_uInt32 CONTROL_MODIFIER (0x00400000); 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); +// Masks +static const sal_uInt32 MODIFIER_MASK (SHIFT_MODIFIER | CONTROL_MODIFIER); +static const sal_uInt32 BUTTON_MASK (LEFT_BUTTON | RIGHT_BUTTON | MIDDLE_BUTTON); } // end of anonymous namespace + +// 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 + namespace sd { namespace slidesorter { namespace controller { -class SelectionFunction::SubstitutionHandler +//===== SelectionFunction::EventDescriptor ==================================== + +class SelectionFunction::EventDescriptor { public: - SubstitutionHandler (SlideSorter& rSlideSorter); - ~SubstitutionHandler (void); + Point maMousePosition; + Point maMouseModelPosition; + model::SharedPageDescriptor mpHitDescriptor; + SdrPage* mpHitPage; + sal_uInt32 mnEventCode; + bool mbIsOverButton; + InsertionIndicatorHandler::Mode meDragMode; + bool mbMakeSelectionVisible; + bool mbIsLeaving; - /** Create a substitution display of the currently selected pages and - use the given position as the anchor point. + EventDescriptor ( + sal_uInt32 nEventType, + const MouseEvent& rEvent, + SlideSorter& rSlideSorter); + EventDescriptor ( + sal_uInt32 nEventType, + const AcceptDropEvent& rEvent, + const sal_Int8 nDragAction, + SlideSorter& rSlideSorter); + EventDescriptor ( + const KeyEvent& rEvent, + SlideSorter& rSlideSorter); + + void SetDragMode (const InsertionIndicatorHandler::Mode eMode); + +private: + /** Compute a numerical code that describes a mouse event and that can + be used for fast look up of the appropriate reaction. */ - void Start (const Point& rMouseModelPosition); + sal_uInt32 EncodeMouseEvent (const MouseEvent& rEvent) const; - /** 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. + /** Compute a numerical code that describes a key event and that can + be used for fast look up of the appropriate reaction. */ - void UpdatePosition (const Point& rMouseModelPosition); + sal_uInt32 EncodeKeyEvent (const KeyEvent& rEvent) const; - /** Move the substitution display of the currently selected pages. + /** Compute a numerical code that describes the current state like + whether the selection rectangle is visible or whether the page under + the mouse or the one that has the focus is selected. */ - void Process (void); + sal_uInt32 EncodeState (void) const; +}; - void End (void); - bool HasBeenMoved (void) const; -private: + +//===== SelectionFunction::ModeHandler ======================================== + +class SelectionFunction::ModeHandler +{ +public: + ModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const bool bIsMouseOverIndicatorAllowed); + virtual ~ModeHandler (void); + + virtual Mode GetMode (void) const = 0; + virtual void Abort (void) = 0; + virtual void ProcessEvent (EventDescriptor& rDescriptor); + + /** Set the selection to exactly the specified page and also set it as + the current page. + */ + void SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor); + + /// Deselect all pages. + void DeselectAllPages (void); + void SelectOnePage (const model::SharedPageDescriptor& rpDescriptor); + + /** When the view on which this selection function is working is the + main view then the view is switched to the regular editing view. + */ + void SwitchView (const model::SharedPageDescriptor& rpDescriptor); + + void StartDrag ( + const Point& rMousePosition, + const InsertionIndicatorHandler::Mode eMode); + + bool IsMouseOverIndicatorAllowed (void) const; + +protected: SlideSorter& mrSlideSorter; + SelectionFunction& mrSelectionFunction; + + virtual bool ProcessButtonDownEvent (EventDescriptor& rDescriptor); + virtual bool ProcessButtonUpEvent (EventDescriptor& rDescriptor); + virtual bool ProcessMotionEvent (EventDescriptor& rDescriptor); + virtual bool ProcessDragEvent (EventDescriptor& rDescriptor); + virtual bool HandleUnprocessedEvent (EventDescriptor& rDescriptor); - bool mbHasBeenMoved; + void ReprocessEvent (EventDescriptor& rDescriptor); - /** 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. +private: + const bool mbIsMouseOverIndicatorAllowed; +}; + + +/** This is the default handler for processing events. It activates the + multi selection or drag-and-drop when the right conditions are met. +*/ +class NormalModeHandler : public SelectionFunction::ModeHandler +{ +public: + NormalModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction); + virtual ~NormalModeHandler (void); + + virtual SelectionFunction::Mode GetMode (void) const; + virtual void Abort (void); + + void ResetButtonDownLocation (void); + +protected: + virtual bool ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor); + +private: + ::boost::optional<Point> maButtonDownLocation; + + /** Select all pages between and including the selection anchor and the + specified page. */ - bool IsSubstitutionInsertionNonTrivial (void) const; + void RangeSelect (const model::SharedPageDescriptor& rpDescriptor); }; -class SelectionFunction::EventDescriptor +/** Handle events during a multi selection, which typically is started by + pressing the left mouse button when not over a page. +*/ +class MultiSelectionModeHandler : public SelectionFunction::ModeHandler { public: + /** Start a rectangle selection at the given position. + */ + MultiSelectionModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const Point& rMouseModelPosition, + const sal_uInt32 nEventCode); + virtual ~MultiSelectionModeHandler (void); - Point maMousePosition; - Point maMouseModelPosition; - ::boost::weak_ptr<model::PageDescriptor> mpHitDescriptor; - SdrPage* mpHitPage; - sal_uInt32 mnEventCode; + virtual SelectionFunction::Mode GetMode (void) const; + virtual void Abort (void); + virtual void ProcessEvent (SelectionFunction::EventDescriptor& rDescriptor); - EventDescriptor ( - sal_uInt32 nEventType, - const MouseEvent& rEvent, - SlideSorter& rSlideSorter); - EventDescriptor ( - const KeyEvent& rEvent, - SlideSorter& rSlideSorter); + enum SelectionMode { SM_Normal, SM_Add, SM_Toggle }; + + void SetSelectionMode (const SelectionMode eSelectionMode); + void SetSelectionModeFromModifier (const sal_uInt32 nEventCode); + +protected: + virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool HandleUnprocessedEvent (SelectionFunction::EventDescriptor& rDescriptor); + +private: + SelectionMode meSelectionMode; + Point maSecondCorner; + Pointer maSavedPointer; + sal_Int32 mnAnchorIndex; + sal_Int32 mnSecondIndex; + view::ButtonBar::Lock maButtonBarLock; + + virtual void UpdateModelPosition (const Point& rMouseModelPosition); + virtual void UpdateSelection (void); + + /** Update the rectangle selection so that the given position becomes + the new second point of the selection rectangle. + */ + void UpdatePosition ( + const Point& rMousePosition, + const bool bAllowAutoScroll); + + void UpdateSelectionState ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bIsInSelection) const; }; +/** Handle events during drag-and-drop. +*/ +class DragAndDropModeHandler : public SelectionFunction::ModeHandler +{ +public: + DragAndDropModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const Point& rMousePosition, + ::Window* pWindow); + virtual ~DragAndDropModeHandler (void); + + virtual SelectionFunction::Mode GetMode (void) const; + virtual void Abort (void); + +protected: + virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor); + +private: + ::boost::scoped_ptr<DragAndDropContext> mpDragAndDropContext; +}; + + +/** Handle events while the left mouse button is pressed over the button + bar. +*/ +class ButtonModeHandler : public SelectionFunction::ModeHandler +{ +public: + ButtonModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction); + virtual ~ButtonModeHandler (void); + virtual void Abort (void); + + virtual SelectionFunction::Mode GetMode (void) const; + +protected: + virtual bool ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor); +}; + + + + +//===== SelectionFunction ===================================================== + TYPEINIT1(SelectionFunction, FuPoor); SelectionFunction::SelectionFunction ( SlideSorter& rSlideSorter, SfxRequest& rRequest) - : SlideFunction (rSlideSorter, rRequest), + : FuPoor ( + rSlideSorter.GetViewShell(), + rSlideSorter.GetContentWindow().get(), + &rSlideSorter.GetView(), + rSlideSorter.GetModel().GetDocument(), + rRequest), mrSlideSorter(rSlideSorter), mrController(mrSlideSorter.GetController()), mbDragSelection(false), maInsertionMarkerBox(), mbProcessingMouseButtonDown(false), - mpSubstitutionHandler(new SubstitutionHandler(mrSlideSorter)) + mnShiftKeySelectionAnchor(-1), + mpModeHandler(new NormalModeHandler(rSlideSorter, *this)) { - //af aDelayToScrollTimer.SetTimeout(50); - aDragTimer.SetTimeoutHdl( LINK( this, SelectionFunction, DragSlideHdl ) ); } + + + SelectionFunction::~SelectionFunction (void) { - aDragTimer.Stop(); + mpModeHandler.reset(); } @@ -196,9 +402,10 @@ BOOL SelectionFunction::MouseButtonDown (const MouseEvent& rEvent) { // #95491# remember button state for creation of own MouseEvents SetMouseButtonCode (rEvent.GetButtons()); + aMDPos = rEvent.GetPosPixel(); mbProcessingMouseButtonDown = true; - mpWindow->CaptureMouse(); + // mpWindow->CaptureMouse(); ProcessMouseEvent(BUTTON_DOWN, rEvent); @@ -210,45 +417,7 @@ BOOL SelectionFunction::MouseButtonDown (const MouseEvent& rEvent) 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); - } - } - + ProcessMouseEvent(MOUSE_MOTION, rEvent); return TRUE; } @@ -259,16 +428,10 @@ 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(); +// mpWindow->ReleaseMouse(); return TRUE; } @@ -276,39 +439,62 @@ BOOL SelectionFunction::MouseButtonUp (const MouseEvent& rEvent) +void SelectionFunction::NotifyDragFinished (void) +{ + SwitchToNormalMode(); +} + + + + BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent) { + view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + PageSelector::UpdateLock aLock (mrSlideSorter); FocusManager& rFocusManager (mrController.GetFocusManager()); BOOL bResult = FALSE; - switch (rEvent.GetKeyCode().GetCode()) + const KeyCode& rCode (rEvent.GetKeyCode()); + switch (rCode.GetCode()) { case KEY_RETURN: - if (rFocusManager.HasFocus()) + { + model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor()); + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (rFocusManager.HasFocus() && pDescriptor && pViewShell!=NULL) { - model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor()); - if (pDescriptor.get() != NULL) + // The Return key triggers different functions depending on + // whether the slide sorter is the main view or displayed in + // the right pane. + if (pViewShell->IsMainViewShell()) + { + mpModeHandler->SetCurrentPage(pDescriptor); + mpModeHandler->SwitchView(pDescriptor); + } + else { - SetCurrentPage(pDescriptor); - SwitchView(pDescriptor); + pViewShell->GetDispatcher()->Execute( + SID_INSERTPAGE, + SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD); } 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; + bResult = TRUE; + } break; case KEY_ESCAPE: - rFocusManager.SetFocusToToolBox(); + // When there is an active multiselection or drag-and-drop + // operation then stop that. + mpModeHandler->Abort(); + SwitchToNormalMode(); bResult = TRUE; break; @@ -316,12 +502,10 @@ BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent) { // Toggle the selection state. model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor()); - if (pDescriptor.get() != NULL) + if (pDescriptor && rCode.IsMod1()) { - // 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); + if (pDescriptor->HasState(model::PageDescriptor::ST_Selected)) + mrController.GetPageSelector().DeselectPage(pDescriptor, false); else mrController.GetPageSelector().SelectPage(pDescriptor); } @@ -332,25 +516,25 @@ BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent) // Move the focus indicator left. case KEY_LEFT: - rFocusManager.MoveFocus (FocusManager::FMD_LEFT); + MoveFocus(FocusManager::FMD_LEFT, rCode.IsShift(), rCode.IsMod1()); bResult = TRUE; break; // Move the focus indicator right. case KEY_RIGHT: - rFocusManager.MoveFocus (FocusManager::FMD_RIGHT); + MoveFocus(FocusManager::FMD_RIGHT, rCode.IsShift(), rCode.IsMod1()); bResult = TRUE; break; // Move the focus indicator up. case KEY_UP: - rFocusManager.MoveFocus (FocusManager::FMD_UP); + MoveFocus(FocusManager::FMD_UP, rCode.IsShift(), rCode.IsMod1()); bResult = TRUE; break; // Move the focus indicator down. case KEY_DOWN: - rFocusManager.MoveFocus (FocusManager::FMD_DOWN); + MoveFocus(FocusManager::FMD_DOWN, rCode.IsShift(), rCode.IsMod1()); bResult = TRUE; break; @@ -366,36 +550,35 @@ BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent) bResult = TRUE; break; + case KEY_HOME: + GotoPage(0); + bResult = TRUE; + break; + + case KEY_END: + GotoPage(mrSlideSorter.GetModel().GetPageCount()-1); + bResult = TRUE; + break; + case KEY_DELETE: case KEY_BACKSPACE: { - if (mrController.GetProperties()->IsUIReadOnly()) + if (mrSlideSorter.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(); + mrController.GetSelectionManager()->DeleteSelectedPages(rCode.GetCode()==KEY_DELETE); + mnShiftKeySelectionAnchor = -1; bResult = TRUE; } break; case KEY_F10: - if (rEvent.GetKeyCode().IsShift()) - ProcessKeyEvent(rEvent); + if (rCode.IsShift()) + { + mpModeHandler->SelectOnePage( + mrSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor()); + } break; default: @@ -403,7 +586,7 @@ BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent) } if ( ! bResult) - bResult = SlideFunction::KeyInput (rEvent); + bResult = FuPoor::KeyInput(rEvent); return bResult; } @@ -411,6 +594,73 @@ BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent) +void SelectionFunction::MoveFocus ( + const FocusManager::FocusMoveDirection eDirection, + const bool bIsShiftDown, + const bool bIsControlDown) +{ + // Remember the anchor of shift key multi selection. + if (bIsShiftDown) + { + if (mnShiftKeySelectionAnchor<0) + { + model::SharedPageDescriptor pFocusedDescriptor ( + mrController.GetFocusManager().GetFocusedPageDescriptor()); + mnShiftKeySelectionAnchor = pFocusedDescriptor->GetPageIndex(); + } + } + else if ( ! bIsControlDown) + ResetShiftKeySelectionAnchor(); + + mrController.GetFocusManager().MoveFocus(eDirection); + + PageSelector& rSelector (mrController.GetPageSelector()); + model::SharedPageDescriptor pFocusedDescriptor ( + mrController.GetFocusManager().GetFocusedPageDescriptor()); + if (bIsShiftDown) + { + // When shift is pressed then select all pages in the range between + // the currently and the previously focused pages, including them. + if (pFocusedDescriptor) + { + sal_Int32 nPageRangeEnd (pFocusedDescriptor->GetPageIndex()); + model::PageEnumeration aPages ( + model::PageEnumerationProvider::CreateAllPagesEnumeration( + mrSlideSorter.GetModel())); + while (aPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aPages.GetNextElement()); + if (pDescriptor) + { + const sal_Int32 nPageIndex(pDescriptor->GetPageIndex()); + if ((nPageIndex>=mnShiftKeySelectionAnchor && nPageIndex<=nPageRangeEnd) + || (nPageIndex<=mnShiftKeySelectionAnchor && nPageIndex>=nPageRangeEnd)) + { + rSelector.SelectPage(pDescriptor); + } + else + { + rSelector.DeselectPage(pDescriptor); + } + } + } + } + } + else if (bIsControlDown) + { + // When control is pressed then do not alter the selection or the + // current page, just move the focus. + } + else + { + // Without shift just select the focused page. + mpModeHandler->SelectOnePage(pFocusedDescriptor); + } +} + + + + void SelectionFunction::Activate() { FuPoor::Activate(); @@ -442,7 +692,7 @@ void SelectionFunction::ScrollEnd (void) void SelectionFunction::DoCut (void) { - if ( ! mrController.GetProperties()->IsUIReadOnly()) + if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly()) { mrController.GetClipboard().DoCut(); } @@ -461,7 +711,7 @@ void SelectionFunction::DoCopy (void) void SelectionFunction::DoPaste (void) { - if ( ! mrController.GetProperties()->IsUIReadOnly()) + if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly()) { mrController.GetClipboard().DoPaste(); } @@ -470,258 +720,316 @@ void SelectionFunction::DoPaste (void) -void SelectionFunction::Paint (const Rectangle&, ::sd::Window* ) +bool SelectionFunction::cancel (void) { + mrController.GetFocusManager().ToggleFocus(); + return true; } -IMPL_LINK( SelectionFunction, DragSlideHdl, Timer*, EMPTYARG ) +void SelectionFunction::GotoNextPage (int nOffset) { - StartDrag(); - return 0; + 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; + GotoPage(nIndex + nOffset); + } + ResetShiftKeySelectionAnchor(); } -void SelectionFunction::StartDrag (void) +void SelectionFunction::GotoPage (int nIndex) { - if (mbPageHit - && ! mrController.GetProperties()->IsUIReadOnly()) + 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) + mpModeHandler->SetCurrentPage(pNextPageDescriptor); + else { - 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); - } + OSL_ASSERT(pNextPageDescriptor.get() != NULL); } + ResetShiftKeySelectionAnchor(); } -bool SelectionFunction::cancel (void) +void SelectionFunction::ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent) { - mrController.GetFocusManager().ToggleFocus(); - return true; + // #95491# remember button state for creation of own MouseEvents + SetMouseButtonCode (rEvent.GetButtons()); + + EventDescriptor aEventDescriptor (nEventType, rEvent, mrSlideSorter); + ProcessEvent(aEventDescriptor); } -void SelectionFunction::SelectHitPage (const model::SharedPageDescriptor& rpDescriptor) +void SelectionFunction::MouseDragged ( + const AcceptDropEvent& rEvent, + const sal_Int8 nDragAction) { - mrController.GetPageSelector().SelectPage(rpDescriptor); + EventDescriptor aEventDescriptor (MOUSE_DRAG, rEvent, nDragAction, mrSlideSorter); + ProcessEvent(aEventDescriptor); } -void SelectionFunction::DeselectHitPage (const model::SharedPageDescriptor& rpDescriptor) +void SelectionFunction::ProcessKeyEvent (const KeyEvent& rEvent) { - mrController.GetPageSelector().DeselectPage(rpDescriptor); + EventDescriptor aEventDescriptor (rEvent, mrSlideSorter); + ProcessEvent(aEventDescriptor); } -void SelectionFunction::DeselectAllPages (void) +void SelectionFunction::ProcessEvent (EventDescriptor& rDescriptor) { - mrController.GetPageSelector().DeselectAllPages(); + // The call to ProcessEvent may switch to another mode handler. + // Prevent the untimely destruction of the called handler by aquiring a + // temporary reference here. + ::boost::shared_ptr<ModeHandler> pModeHandler (mpModeHandler); + pModeHandler->ProcessEvent(rDescriptor); } -void SelectionFunction::StartRectangleSelection (const Point& rMouseModelPosition) +bool Match ( + const sal_uInt32 nEventCode, + const sal_uInt32 nPositivePattern) { - if (mrController.GetProperties()->IsShowSelection()) - { - mrSlideSorter.GetView().GetOverlay().GetSelectionRectangleOverlay().Start( - rMouseModelPosition); - } + return (nEventCode & nPositivePattern)==nPositivePattern; +} + + + + +void SelectionFunction::SwitchToNormalMode (void) +{ + if (mpModeHandler->GetMode() != NormalMode) + SwitchMode(::boost::shared_ptr<ModeHandler>( + new NormalModeHandler(mrSlideSorter, *this))); } -void SelectionFunction::UpdateRectangleSelection (const Point& rMouseModelPosition) +void SelectionFunction::SwitchToDragAndDropMode (const Point aMousePosition) { - if (mrController.GetProperties()->IsShowSelection()) + if (mpModeHandler->GetMode() != DragAndDropMode) { - mrSlideSorter.GetView().GetOverlay().GetSelectionRectangleOverlay().Update( - rMouseModelPosition); + SwitchMode(::boost::shared_ptr<ModeHandler>( + new DragAndDropModeHandler(mrSlideSorter, *this, aMousePosition, mpWindow))); } } -void SelectionFunction::ProcessRectangleSelection (bool bToggleSelection) +void SelectionFunction::SwitchToMultiSelectionMode ( + const Point aMousePosition, + const sal_uInt32 nEventCode) { - if ( ! mrController.GetProperties()->IsShowSelection()) - return; + if (mpModeHandler->GetMode() != MultiSelectionMode) + SwitchMode(::boost::shared_ptr<ModeHandler>( + new MultiSelectionModeHandler(mrSlideSorter, *this, aMousePosition, nEventCode))); +} - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - if (rOverlay.GetSelectionRectangleOverlay().isVisible()) + + + +bool SelectionFunction::SwitchToButtonMode (void) +{ + // Do not show the buttons for draw pages. + ::boost::shared_ptr<ViewShell> pMainViewShell (mrSlideSorter.GetViewShellBase()->GetMainViewShell()); + if (pMainViewShell + && pMainViewShell->GetShellType()!=ViewShell::ST_DRAW + && mpModeHandler->GetMode() != ButtonMode) { - 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); - } - } + SwitchMode(::boost::shared_ptr<ModeHandler>(new ButtonModeHandler(mrSlideSorter, *this))); + return true; } + else + return false; } -void SelectionFunction::PrepareMouseMotion (const Point& ) +void SelectionFunction::SwitchMode (const ::boost::shared_ptr<ModeHandler>& rpHandler) { - if ( ! mrController.GetProperties()->IsUIReadOnly()) + // Not all modes allow mouse over indicator. + if (mpModeHandler->IsMouseOverIndicatorAllowed() != rpHandler->IsMouseOverIndicatorAllowed()) { - bFirstMouseMove = TRUE; - aDragTimer.Start(); + if ( ! rpHandler->IsMouseOverIndicatorAllowed()) + { + mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor()); + mrSlideSorter.GetView().GetButtonBar().ResetPage(); + } + else + mrSlideSorter.GetView().UpdatePageUnderMouse(false); } + + mpModeHandler = rpHandler; } -void SelectionFunction::RangeSelect (const model::SharedPageDescriptor& rpDescriptor) +void SelectionFunction::ResetShiftKeySelectionAnchor (void) { - PageSelector& rSelector (mrController.GetPageSelector()); + mnShiftKeySelectionAnchor = -1; +} - 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::ResetMouseAnchor (void) +{ + if (mpModeHandler && mpModeHandler->GetMode() == NormalMode) + { + ::boost::shared_ptr<NormalModeHandler> pHandler ( + ::boost::dynamic_pointer_cast<NormalModeHandler>(mpModeHandler)); + if (pHandler) + pHandler->ResetButtonDownLocation(); } } -void SelectionFunction::GotoNextPage (int nOffset) +//===== EventDescriptor ======================================================= + +SelectionFunction::EventDescriptor::EventDescriptor ( + const sal_uInt32 nEventType, + const MouseEvent& rEvent, + SlideSorter& rSlideSorter) + : maMousePosition(rEvent.GetPosPixel()), + maMouseModelPosition(), + mpHitDescriptor(), + mpHitPage(), + mnEventCode(nEventType), + mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()), + meDragMode(InsertionIndicatorHandler::MoveMode), + mbMakeSelectionVisible(true), + mbIsLeaving(false) { - model::SharedPageDescriptor pDescriptor - = mrController.GetCurrentSlideManager()->GetCurrentSlide(); - if (pDescriptor.get() != NULL) + maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition); + mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition); + if (mpHitDescriptor) { - 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); - } + mpHitPage = mpHitDescriptor->GetPage(); } + + mnEventCode |= EncodeMouseEvent(rEvent); + mnEventCode |= EncodeState(); + + // Detect the mouse leaving the window. When not button is pressed then + // we can call IsLeaveWindow at the event. Otherwise we have to make an + // explicit test. + mbIsLeaving = rEvent.IsLeaveWindow() + || ! Rectangle(Point(0,0), + rSlideSorter.GetContentWindow()->GetOutputSizePixel()).IsInside(maMousePosition); } -void SelectionFunction::ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent) +SelectionFunction::EventDescriptor::EventDescriptor ( + const sal_uInt32 nEventType, + const AcceptDropEvent& rEvent, + const sal_Int8 nDragAction, + SlideSorter& rSlideSorter) + : maMousePosition(rEvent.maPosPixel), + maMouseModelPosition(), + mpHitDescriptor(), + mpHitPage(), + mnEventCode(nEventType), + mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()), + meDragMode(InsertionIndicatorHandler::GetModeFromDndAction(nDragAction)), + mbMakeSelectionVisible(true), + mbIsLeaving(false) { - // #95491# remember button state for creation of own MouseEvents - SetMouseButtonCode (rEvent.GetButtons()); + maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition); + mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition); + if (mpHitDescriptor) + { + mpHitPage = mpHitDescriptor->GetPage(); + } + + mnEventCode |= EncodeState(); + + // Detect the mouse leaving the window. When not button is pressed then + // we can call IsLeaveWindow at the event. Otherwise we have to make an + // explicit test. + mbIsLeaving = rEvent.mbLeaving + || ! Rectangle(Point(0,0), + rSlideSorter.GetContentWindow()->GetOutputSizePixel()).IsInside(maMousePosition); +} - // 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)) + +SelectionFunction::EventDescriptor::EventDescriptor ( + const KeyEvent& rEvent, + SlideSorter& rSlideSorter) + : maMousePosition(), + maMouseModelPosition(), + mpHitDescriptor(), + mpHitPage(), + mnEventCode(KEY_EVENT), + mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()), + meDragMode(InsertionIndicatorHandler::MoveMode), + mbMakeSelectionVisible(true), + mbIsLeaving(false) +{ + model::SharedPageDescriptor pHitDescriptor ( + rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor()); + if (pHitDescriptor.get() != NULL) { - OSL_TRACE ("can not handle event code %x", pEventDescriptor->mnEventCode); + mpHitPage = pHitDescriptor->GetPage(); + mpHitDescriptor = pHitDescriptor; } - EventPostprocessing(*pEventDescriptor); - if (nEventType == BUTTON_UP) - mbPageHit = false; + mnEventCode |= EncodeKeyEvent(rEvent) | EncodeState(); } -sal_uInt32 SelectionFunction::EncodeMouseEvent ( - const EventDescriptor& rDescriptor, +void SelectionFunction::EventDescriptor::SetDragMode (const InsertionIndicatorHandler::Mode eMode) +{ + meDragMode = eMode; +} + + + + +sal_uInt32 SelectionFunction::EventDescriptor::EncodeMouseEvent ( const MouseEvent& rEvent) const { // Initialize with the type of mouse event. - sal_uInt32 nEventCode (rDescriptor.mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION)); + sal_uInt32 nEventCode (mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION)); // Detect the affected button. switch (rEvent.GetButtons()) @@ -738,28 +1046,16 @@ sal_uInt32 SelectionFunction::EncodeMouseEvent ( 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; + // Detect whether the mouse is over one of the active elements inside a + // page object. + if (mbIsOverButton) + nEventCode |= OVER_BUTTON; return nEventCode; } @@ -767,551 +1063,962 @@ sal_uInt32 SelectionFunction::EncodeMouseEvent ( -void SelectionFunction::ProcessKeyEvent (const KeyEvent& rEvent) +sal_uInt32 SelectionFunction::EventDescriptor::EncodeKeyEvent (const KeyEvent& rEvent) const { - // 1. Compute some frequently used values relating to the event. - ::std::auto_ptr<EventDescriptor> pEventDescriptor ( - new EventDescriptor(rEvent, mrSlideSorter)); + // The key code in the lower 16 bit. + sal_uInt32 nEventCode (rEvent.GetKeyCode().GetCode()); - // 2. Encode the event. - pEventDescriptor->mnEventCode = EncodeKeyEvent(*pEventDescriptor, rEvent); + // Detect pressed modifier keys. + if (rEvent.GetKeyCode().IsShift()) + nEventCode |= SHIFT_MODIFIER; + if (rEvent.GetKeyCode().IsMod1()) + nEventCode |= CONTROL_MODIFIER; - // 3. Process the event. - EventPreprocessing(*pEventDescriptor); - if ( ! EventProcessing(*pEventDescriptor)) - OSL_TRACE ("can not handle event code %x", pEventDescriptor->mnEventCode); - EventPostprocessing(*pEventDescriptor); + return nEventCode; } -sal_uInt32 SelectionFunction::EncodeKeyEvent ( - const EventDescriptor& rDescriptor, - const KeyEvent& rEvent) const +sal_uInt32 SelectionFunction::EventDescriptor::EncodeState (void) 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; + sal_uInt32 nEventCode (0); // Detect whether the event has happened over a page object. - if (rDescriptor.mpHitPage != NULL && ! rDescriptor.mpHitDescriptor.expired()) + if (mpHitPage!=NULL && mpHitDescriptor) { - model::SharedPageDescriptor pHitDescriptor (rDescriptor.mpHitDescriptor); - if (pHitDescriptor->IsSelected()) + if (mpHitDescriptor->HasState(model::PageDescriptor::ST_Selected)) 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; + // Detect whether the mouse is over one of the active elements + // inside a page object. + if (mbIsOverButton) + nEventCode |= OVER_BUTTON; + } return nEventCode; } -void SelectionFunction::EventPreprocessing (const EventDescriptor& rDescriptor) + +//===== SelectionFunction::ModeHandler ======================================== + +SelectionFunction::ModeHandler::ModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const bool bIsMouseOverIndicatorAllowed) + : mrSlideSorter(rSlideSorter), + mrSelectionFunction(rSelectionFunction), + mbIsMouseOverIndicatorAllowed(bIsMouseOverIndicatorAllowed) +{ +} + + + + +SelectionFunction::ModeHandler::~ModeHandler (void) { - // 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); + +void SelectionFunction::ModeHandler::ReprocessEvent (EventDescriptor& rDescriptor) +{ + mrSelectionFunction.ProcessEvent(rDescriptor); } -bool SelectionFunction::EventProcessing (const EventDescriptor& rDescriptor) +void SelectionFunction::ModeHandler::ProcessEvent ( + SelectionFunction::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) + PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + + bool bIsProcessed (false); + switch (rDescriptor.mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION | MOUSE_DRAG)) + { + case BUTTON_DOWN: + bIsProcessed = ProcessButtonDownEvent(rDescriptor); + break; + + case BUTTON_UP: + bIsProcessed = ProcessButtonUpEvent(rDescriptor); + break; + + case MOUSE_MOTION: + bIsProcessed = ProcessMotionEvent(rDescriptor); + break; + + case MOUSE_DRAG: + bIsProcessed = ProcessDragEvent(rDescriptor); + break; + } + + if ( ! bIsProcessed) + HandleUnprocessedEvent(rDescriptor); +} + + + + +bool SelectionFunction::ModeHandler::ProcessButtonDownEvent (EventDescriptor&) +{ + return false; +} + + + + +bool SelectionFunction::ModeHandler::ProcessButtonUpEvent (EventDescriptor&) +{ + mrSelectionFunction.SwitchToNormalMode(); + return false; +} + + + + +bool SelectionFunction::ModeHandler::ProcessMotionEvent (EventDescriptor& rDescriptor) +{ + if (mbIsMouseOverIndicatorAllowed) + mrSlideSorter.GetView().UpdatePageUnderMouse( + rDescriptor.maMousePosition, + (rDescriptor.mnEventCode & LEFT_BUTTON) != 0, + true); + + if (rDescriptor.mbIsLeaving) + { + mrSelectionFunction.SwitchToNormalMode(); + mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor()); + + return true; + } + else + return false; +} + + + + +bool SelectionFunction::ModeHandler::ProcessDragEvent (EventDescriptor&) +{ + return false; +} + + + + +bool SelectionFunction::ModeHandler::HandleUnprocessedEvent (EventDescriptor&) +{ + return false; +} + + + + +void SelectionFunction::ModeHandler::SetCurrentPage ( + const model::SharedPageDescriptor& rpDescriptor) +{ + SelectOnePage(rpDescriptor); + mrSlideSorter.GetController().GetCurrentSlideManager()->SwitchCurrentSlide(rpDescriptor); +} + + - bool bResult (true); - bool bMakeSelectionVisible (true); +void SelectionFunction::ModeHandler::DeselectAllPages (void) +{ + mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); + mrSelectionFunction.ResetShiftKeySelectionAnchor(); +} + + + + +void SelectionFunction::ModeHandler::SelectOnePage ( + const model::SharedPageDescriptor& rpDescriptor) +{ + DeselectAllPages(); + mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor); +} + + + + +void SelectionFunction::ModeHandler::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); + pViewShell->GetFrameView()->SetSelectedPage( + (rpDescriptor->GetPage()->GetPageNum()-1)/2); + } + if (mrSlideSorter.GetViewShellBase() != NULL) + framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase())->RequestView( + framework::FrameworkHelper::msImpressViewURL, + framework::FrameworkHelper::msCenterPaneURL); + } +} + + + + +void SelectionFunction::ModeHandler::StartDrag ( + const Point& rMousePosition, + const InsertionIndicatorHandler::Mode eMode) +{ + (void)eMode; + // Do not start a drag-and-drop operation when one is already active. + // (when dragging pages from one document into another, pressing a + // modifier key can trigger a MouseMotion event in the originating + // window (focus still in there). Together with the mouse button pressed + // (drag-and-drop is active) this triggers the start of drag-and-drop.) + if (SD_MOD()->pTransferDrag != NULL) + return; + + if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly()) + { + mrSelectionFunction.SwitchToDragAndDropMode(rMousePosition); + } +} + + + + +bool SelectionFunction::ModeHandler::IsMouseOverIndicatorAllowed (void) const +{ + return mbIsMouseOverIndicatorAllowed; +} + + + + +//===== NormalModeHandler ===================================================== + +NormalModeHandler::NormalModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction) + : ModeHandler(rSlideSorter, rSelectionFunction, true), + maButtonDownLocation() +{ +} + + + + +NormalModeHandler::~NormalModeHandler (void) +{ +} + + + + +SelectionFunction::Mode NormalModeHandler::GetMode (void) const +{ + return SelectionFunction::NormalMode; +} + + + + +void NormalModeHandler::Abort (void) +{ +} + - 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); +bool NormalModeHandler::ProcessButtonDownEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + // Remember the location where the left button is pressed. With + // that we can filter away motion events that are caused by key + // presses. We also can tune the minimal motion distance that + // triggers a drag-and-drop operation. + if ((rDescriptor.mnEventCode & BUTTON_DOWN) != 0) + maButtonDownLocation = rDescriptor.maMousePosition; 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(); + SetCurrentPage(rDescriptor.mpHitDescriptor); 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)); - + SetCurrentPage(rDescriptor.mpHitDescriptor); + SwitchView(rDescriptor.mpHitDescriptor); 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); + // Range selection with the shift modifier. + RangeSelect(rDescriptor.mpHitDescriptor); break; - // Was: Preview of the page transition effect. - case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_FADE_INDICATOR: - // No action. + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | OVER_BUTTON: + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | OVER_BUTTON: + OSL_ASSERT(mrSlideSorter.GetView().GetButtonBar().IsMouseOverButton()); + + // Switch to button mode only when the buttons are visible + // (or being faded in.) + if (mrSlideSorter.GetView().GetButtonBar().IsVisible(rDescriptor.mpHitDescriptor)) + { + if (mrSelectionFunction.SwitchToButtonMode()) + ReprocessEvent(rDescriptor); + } + else + { + // When the buttons are not (yet) visible then behave like + // the left button had been clicked over any other part of + // the slide. + SetCurrentPage(rDescriptor.mpHitDescriptor); + } break; - // Right button for context menu. + // 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; + SetCurrentPage(rDescriptor.mpHitDescriptor); + rDescriptor.mbMakeSelectionVisible = 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; + rDescriptor.mbMakeSelectionVisible = 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: + // Remember the current selection so that when a multi selection + // is started, we can restore the previous selection. + mrSlideSorter.GetModel().SaveCurrentSelection(); 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); + case ANY_MODIFIER(BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE): + // Remember the current selection so that when a multi selection + // is started, we can restore the previous selection. + mrSlideSorter.GetModel().SaveCurrentSelection(); + DeselectAllPages(); 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); + default: + return false; + } + return true; +} + + + + +bool NormalModeHandler::ProcessButtonUpEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + bool bIsProcessed (true); + switch (rDescriptor.mnEventCode) + { + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: + SetCurrentPage(rDescriptor.mpHitDescriptor); 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(); + // Multi selection with the control modifier. + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | CONTROL_MODIFIER: + mrSlideSorter.GetController().GetPageSelector().DeselectPage( + rDescriptor.mpHitDescriptor); break; - // Rectangle selection. - case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE | NO_MODIFIER: - DeselectAllPages(); - StartRectangleSelection(rDescriptor.maMouseModelPosition); + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | CONTROL_MODIFIER: + mrSlideSorter.GetController().GetPageSelector().SelectPage( + rDescriptor.mpHitDescriptor); + mrSlideSorter.GetView().UpdatePageUnderMouse( + rDescriptor.mpHitDescriptor, + rDescriptor.maMousePosition, + false); + break; + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE: 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); + default: + bIsProcessed = false; break; + } + mrSelectionFunction.SwitchToNormalMode(); + return bIsProcessed; +} - case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE): + + + + +bool NormalModeHandler::ProcessMotionEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + if (ModeHandler::ProcessMotionEvent(rDescriptor)) + return true; + + bool bIsProcessed (true); + switch (rDescriptor.mnEventCode) + { 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; + // SetCurrentPage(rDescriptor.mpHitDescriptor); + // Fallthrough - case ANY_PAGE(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE | NO_MODIFIER): - ProcessRectangleSelection(false); - break; + // A mouse motion without visible substitution starts that. + case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE): + { + if (maButtonDownLocation) + { + const sal_Int32 nDistance (maButtonDownLocation + ? ::std::max ( + abs(maButtonDownLocation->X() - rDescriptor.maMousePosition.X()), + abs(maButtonDownLocation->Y() - rDescriptor.maMousePosition.Y())) + : 0); + if (nDistance > 3) + StartDrag( + rDescriptor.maMousePosition, + (rDescriptor.mnEventCode & CONTROL_MODIFIER) != 0 + ? InsertionIndicatorHandler::CopyMode + : InsertionIndicatorHandler::MoveMode); + } + } + 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); + // A mouse motion not over a page starts a rectangle selection. + case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE): + mrSelectionFunction.SwitchToMultiSelectionMode( + rDescriptor.maMouseModelPosition, + rDescriptor.mnEventCode); break; default: - bResult = false; + bIsProcessed = false; break; } - mrController.GetPageSelector().EnableBroadcasting(bMakeSelectionVisible); + return bIsProcessed; +} - return bResult; + + + +bool NormalModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + mrSelectionFunction.SwitchToDragAndDropMode(rDescriptor.maMousePosition); + ReprocessEvent(rDescriptor); + return true; } -void SelectionFunction::EventPostprocessing (const EventDescriptor& rDescriptor) +void NormalModeHandler::RangeSelect (const model::SharedPageDescriptor& rpDescriptor) { - if (rDescriptor.mnEventCode & BUTTON_UP) + PageSelector::UpdateLock aLock (mrSlideSorter); + PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); + + model::SharedPageDescriptor pAnchor (rSelector.GetSelectionAnchor()); + DeselectAllPages(); + + if (pAnchor.get() != NULL) { - 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); + // Select all pages between the anchor and the given one, including + // the two. + const USHORT nAnchorIndex ((pAnchor->GetPage()->GetPageNum()-1) / 2); + const 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.) + const USHORT nStep ((nAnchorIndex < nOtherIndex) ? +1 : -1); + USHORT nIndex (nAnchorIndex); + while (true) + { + rSelector.SelectPage(nIndex); + if (nIndex == nOtherIndex) + break; + nIndex = nIndex + nStep; + } } } -void SelectionFunction::SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor) +void NormalModeHandler::ResetButtonDownLocation (void) { - PageSelector& rSelector (mrController.GetPageSelector()); - rSelector.DeselectAllPages (); - rSelector.SelectPage(rpDescriptor); + maButtonDownLocation = ::boost::optional<Point>(); +} + + - mrController.GetCurrentSlideManager()->SwitchCurrentSlide(rpDescriptor); + +//===== MultiSelectionModeHandler ============================================= + +MultiSelectionModeHandler::MultiSelectionModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const Point& rMouseModelPosition, + const sal_uInt32 nEventCode) + : ModeHandler(rSlideSorter, rSelectionFunction, false), + meSelectionMode(SM_Normal), + maSecondCorner(rMouseModelPosition), + maSavedPointer(mrSlideSorter.GetContentWindow()->GetPointer()), + mnAnchorIndex(-1), + mnSecondIndex(-1), + maButtonBarLock(rSlideSorter) +{ + const Pointer aSelectionPointer (POINTER_TEXT); + mrSlideSorter.GetContentWindow()->SetPointer(aSelectionPointer); + SetSelectionModeFromModifier(nEventCode); } -void SelectionFunction::SwitchView (const model::SharedPageDescriptor& rpDescriptor) + +MultiSelectionModeHandler::~MultiSelectionModeHandler (void) { - // 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()) + mrSlideSorter.GetContentWindow()->SetPointer(maSavedPointer); +} + + + + +SelectionFunction::Mode MultiSelectionModeHandler::GetMode (void) const +{ + return SelectionFunction::MultiSelectionMode; +} + + + + +void MultiSelectionModeHandler::Abort (void) +{ + mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection()); +} + + + + +void MultiSelectionModeHandler::ProcessEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + // During a multi selection we do not want sudden jumps of the + // visible area caused by moving newly selected pages into view. + // Therefore disable that temporarily. The disabler object is + // released at the end of the event processing, after the focus and + // current slide have been updated. + VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter); + + ModeHandler::ProcessEvent(rDescriptor); +} + + + + +bool MultiSelectionModeHandler::ProcessButtonUpEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK)) { - 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); + mrSelectionFunction.SwitchToNormalMode(); + return true; } + else + return false; } -//===== EventDescriptor ======================================================= +bool MultiSelectionModeHandler::ProcessMotionEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + // The selection rectangle is visible. Handle events accordingly. + if (Match(rDescriptor.mnEventCode, MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK)) + { + SetSelectionModeFromModifier(rDescriptor.mnEventCode); + UpdatePosition(rDescriptor.maMousePosition, true); + rDescriptor.mbMakeSelectionVisible = false; + return true; + } + else + return false; +} -SelectionFunction::EventDescriptor::EventDescriptor ( - sal_uInt32 nEventType, - const MouseEvent& rEvent, - SlideSorter& rSlideSorter) - : maMousePosition(), - maMouseModelPosition(), - mpHitDescriptor(), - mpHitPage(), - mnEventCode(nEventType) + + +bool MultiSelectionModeHandler::HandleUnprocessedEvent ( + SelectionFunction::EventDescriptor& rDescriptor) { - ::Window* pWindow = rSlideSorter.GetActiveWindow(); + if ( ! ModeHandler::HandleUnprocessedEvent(rDescriptor)) + { + // If the event has not been processed then stop multi selection. + mrSelectionFunction.SwitchToNormalMode(); + ReprocessEvent(rDescriptor); + } + return true; +} - maMousePosition = rEvent.GetPosPixel(); - maMouseModelPosition = pWindow->PixelToLogic(maMousePosition); - model::SharedPageDescriptor pHitDescriptor ( - rSlideSorter.GetController().GetPageAt(maMousePosition)); - if (pHitDescriptor.get() != NULL) + + + +void MultiSelectionModeHandler::UpdatePosition ( + const Point& rMousePosition, + const bool bAllowAutoScroll) +{ + VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter); + + // Convert window coordinates into model coordinates (we need the + // window coordinates for auto-scrolling because that remains + // constant while scrolling.) + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition)); + + if ( ! (bAllowAutoScroll && mrSlideSorter.GetController().GetScrollBarManager().AutoScroll( + rMousePosition, + ::boost::bind( + &MultiSelectionModeHandler::UpdatePosition, + this, + rMousePosition, + false)))) { - mpHitDescriptor = pHitDescriptor; - mpHitPage = pHitDescriptor->GetPage(); + UpdateModelPosition(aMouseModelPosition); } } +void MultiSelectionModeHandler::SetSelectionModeFromModifier ( + const sal_uInt32 nEventCode) +{ + switch (nEventCode & MODIFIER_MASK) + { + case NO_MODIFIER: + SetSelectionMode(SM_Normal); + break; -SelectionFunction::EventDescriptor::EventDescriptor ( - const KeyEvent&, - SlideSorter& rSlideSorter) - : maMousePosition(), - maMouseModelPosition(), - mpHitDescriptor(), - mpHitPage(), - mnEventCode(0) + case SHIFT_MODIFIER: + SetSelectionMode(SM_Add); + break; + + case CONTROL_MODIFIER: + SetSelectionMode(SM_Toggle); + break; + } +} + + + + +void MultiSelectionModeHandler::SetSelectionMode (const SelectionMode eSelectionMode) { - mpHitDescriptor = rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor(); - model::SharedPageDescriptor pHitDescriptor ( - rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor()); - if (pHitDescriptor.get() != NULL) + if (meSelectionMode != eSelectionMode) { - mpHitPage = pHitDescriptor->GetPage(); - mpHitDescriptor = pHitDescriptor; + meSelectionMode = eSelectionMode; + UpdateSelection(); } } +void MultiSelectionModeHandler::UpdateSelectionState ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bIsInSelection) const +{ + // Determine whether the page was selected before the rectangle + // selection was started. + const bool bWasSelected (rpDescriptor->HasState(model::PageDescriptor::ST_WasSelected)); + + // Combine the two selection states depending on the selection mode. + bool bSelect (false); + switch(meSelectionMode) + { + case SM_Normal: + bSelect = bIsInSelection; + break; -//===== SubstitutionHandler =================================================== + case SM_Add: + bSelect = bIsInSelection || bWasSelected; + break; -SelectionFunction::SubstitutionHandler::SubstitutionHandler (SlideSorter& rSlideSorter) - : mrSlideSorter(rSlideSorter), - mbHasBeenMoved(false) + case SM_Toggle: + if (bIsInSelection) + bSelect = !bWasSelected; + else + bSelect = bWasSelected; + break; + } + + // Set the new selection state. + if (bSelect) + mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor); + else + mrSlideSorter.GetController().GetPageSelector().DeselectPage(rpDescriptor); +} + + + + +void MultiSelectionModeHandler::UpdateModelPosition (const Point& rMouseModelPosition) { + maSecondCorner = rMouseModelPosition; + UpdateSelection(); } -SelectionFunction::SubstitutionHandler::~SubstitutionHandler (void) +void MultiSelectionModeHandler::UpdateSelection (void) { - if (mrSlideSorter.IsValid()) + view::SlideSorterView::DrawLock aLock (mrSlideSorter); + + model::SlideSorterModel& rModel (mrSlideSorter.GetModel()); + const sal_Int32 nPageCount (rModel.GetPageCount()); + + const sal_Int32 nIndexUnderMouse ( + mrSlideSorter.GetView().GetLayouter().GetIndexAtPoint ( + maSecondCorner, + false, + false)); + if (nIndexUnderMouse>=0 && nIndexUnderMouse<nPageCount) { - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - rOverlay.GetSubstitutionOverlay().setVisible(false); - rOverlay.GetSubstitutionOverlay().Clear(); + if (mnAnchorIndex < 0) + mnAnchorIndex = nIndexUnderMouse; + mnSecondIndex = nIndexUnderMouse; + + Range aRange (mnAnchorIndex, mnSecondIndex); + aRange.Justify(); + + for (sal_Int32 nIndex=0; nIndex<nPageCount; ++nIndex) + { + UpdateSelectionState(rModel.GetPageDescriptor(nIndex), aRange.IsInside(nIndex)); + } } } -void SelectionFunction::SubstitutionHandler::Start (const Point& rMouseModelPosition) +//===== DragAndDropModeHandler ================================================ + +DragAndDropModeHandler::DragAndDropModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const Point& rMousePosition, + ::Window* pWindow) + : ModeHandler(rSlideSorter, rSelectionFunction, false) { - // No Drag-and-Drop for master pages. - if (mrSlideSorter.GetModel().GetEditMode() != EM_PAGE) - return; + SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; + if (pDragTransferable==NULL && mrSlideSorter.GetViewShell() != NULL) + { + SlideSorterViewShell* pSlideSorterViewShell + = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()); + if (pSlideSorterViewShell != NULL) + pSlideSorterViewShell->StartDrag(rMousePosition, pWindow); + pDragTransferable = SD_MOD()->pTransferDrag; + } - if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly()) - return; + mpDragAndDropContext.reset(new DragAndDropContext(mrSlideSorter)); + mrSlideSorter.GetController().GetInsertionIndicatorHandler()->Start( + pDragTransferable != NULL + && pDragTransferable->GetView()==&mrSlideSorter.GetView()); +} - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - if ( ! rOverlay.GetSubstitutionOverlay().isVisible()) + + +DragAndDropModeHandler::~DragAndDropModeHandler (void) +{ + if (mpDragAndDropContext) { - // 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; + // Disconnect the substitution handler from this selection function. + mpDragAndDropContext->SetTargetSlideSorter(); + mpDragAndDropContext.reset(); } - else - UpdatePosition(rMouseModelPosition); + mrSlideSorter.GetController().GetInsertionIndicatorHandler()->End(Animator::AM_Animated); } -void SelectionFunction::SubstitutionHandler::UpdatePosition (const Point& rMouseModelPosition) +SelectionFunction::Mode DragAndDropModeHandler::GetMode (void) const { - if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly()) - return; + return SelectionFunction::DragAndDropMode; +} - 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 DragAndDropModeHandler::Abort (void) +{ + mrSlideSorter.GetController().GetClipboard().Abort(); + if (mpDragAndDropContext) + mpDragAndDropContext->Dispose(); + // mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection()); } -void SelectionFunction::SubstitutionHandler::Process (void) +bool DragAndDropModeHandler::ProcessButtonUpEvent ( + SelectionFunction::EventDescriptor& rDescriptor) { - if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly()) - return; + if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON)) + { + // The following Process() call may lead to the desctruction + // of rDescriptor.mpHitDescriptor so release our reference to it. + rDescriptor.mpHitDescriptor.reset(); + mrSelectionFunction.SwitchToNormalMode(); + return true; + } + else + return false; +} - 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); + +bool DragAndDropModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + OSL_ASSERT(mpDragAndDropContext); + + if (rDescriptor.mbIsLeaving) + { + mrSelectionFunction.SwitchToNormalMode(); + } + else if (mpDragAndDropContext) + { + mpDragAndDropContext->UpdatePosition( + rDescriptor.maMousePosition, + rDescriptor.meDragMode); } + + return true; } -void SelectionFunction::SubstitutionHandler::End (void) +//===== ButtonModeHandler ===================================================== + +ButtonModeHandler::ButtonModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction) + : ModeHandler(rSlideSorter, rSelectionFunction, true) { - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - rOverlay.GetSubstitutionOverlay().setVisible(false); - rOverlay.GetSubstitutionOverlay().Clear(); - rOverlay.GetInsertionIndicatorOverlay().setVisible(false); } -bool SelectionFunction::SubstitutionHandler::HasBeenMoved (void) const +ButtonModeHandler::~ButtonModeHandler (void) { - return mbHasBeenMoved; } -bool SelectionFunction::SubstitutionHandler::IsSubstitutionInsertionNonTrivial (void) const +SelectionFunction::Mode ButtonModeHandler::GetMode (void) const { - bool bIsNonTrivial = false; + return SelectionFunction::ButtonMode; +} + + + - do +void ButtonModeHandler::Abort (void) +{ +} + + + + +bool ButtonModeHandler::ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + switch (rDescriptor.mnEventCode) { - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | OVER_BUTTON: + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | OVER_BUTTON: + // Remember page and button index. When mouse button is + // released over same page and button then invoke action of that + // button. + mrSlideSorter.GetView().GetButtonBar().ProcessButtonDownEvent( + rDescriptor.mpHitDescriptor, + rDescriptor.maMouseModelPosition); + return true; + + default: + return false; + } +} - // 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; +bool ButtonModeHandler::ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + switch (rDescriptor.mnEventCode & BUTTON_MASK) + { + case LEFT_BUTTON: + mrSlideSorter.GetView().GetButtonBar().ProcessButtonUpEvent( + rDescriptor.mpHitDescriptor, + rDescriptor.maMouseModelPosition); + mrSelectionFunction.SwitchToNormalMode(); + return true; } - while (false); - return bIsNonTrivial; + return false; } + + + +bool ButtonModeHandler::ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + switch (rDescriptor.mnEventCode & (MOUSE_MOTION | BUTTON_MASK)) + { + case MOUSE_MOTION | LEFT_BUTTON: + mrSlideSorter.GetView().GetButtonBar().ProcessMouseMotionEvent( + rDescriptor.mpHitDescriptor, + rDescriptor.maMouseModelPosition, + true); + return true; + + case MOUSE_MOTION: + mrSlideSorter.GetView().GetButtonBar().ProcessMouseMotionEvent( + rDescriptor.mpHitDescriptor, + rDescriptor.maMouseModelPosition, + false); + return true; + } + + return false; +} + + + + } } } // end of namespace ::sd::slidesorter::controller |