/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #include "precompiled_sd.hxx" #include "controller/SlsSelectionFunction.hxx" #include "SlideSorter.hxx" #include "SlideSorterViewShell.hxx" #include "SlsDragAndDropContext.hxx" #include "controller/SlsTransferableData.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/SlsLayouter.hxx" #include "view/SlsPageObjectLayouter.hxx" #include "view/SlsButtonBar.hxx" #include "framework/FrameworkHelper.hxx" #include "ViewShellBase.hxx" #include "DrawController.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 #include #include #include #include #include #include #include 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); 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 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 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 { //===== SelectionFunction::EventDescriptor ==================================== class SelectionFunction::EventDescriptor { public: Point maMousePosition; Point maMouseModelPosition; model::SharedPageDescriptor mpHitDescriptor; SdrPage* mpHitPage; sal_uInt32 mnEventCode; bool mbIsOverButton; InsertionIndicatorHandler::Mode meDragMode; bool mbMakeSelectionVisible; bool mbIsLeaving; 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. */ sal_uInt32 EncodeMouseEvent (const MouseEvent& rEvent) const; /** Compute a numerical code that describes a key event and that can be used for fast look up of the appropriate reaction. */ sal_uInt32 EncodeKeyEvent (const KeyEvent& rEvent) const; /** 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. */ sal_uInt32 EncodeState (void) const; }; //===== 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); void ReprocessEvent (EventDescriptor& rDescriptor); 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 maButtonDownLocation; /** Select all pages between and including the selection anchor and the specified page. */ void RangeSelect (const model::SharedPageDescriptor& rpDescriptor); }; /** 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); virtual SelectionFunction::Mode GetMode (void) const; virtual void Abort (void); virtual void ProcessEvent (SelectionFunction::EventDescriptor& rDescriptor); 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 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) : FuPoor ( rSlideSorter.GetViewShell(), rSlideSorter.GetContentWindow().get(), &rSlideSorter.GetView(), rSlideSorter.GetModel().GetDocument(), rRequest), mrSlideSorter(rSlideSorter), mrController(mrSlideSorter.GetController()), mbDragSelection(false), maInsertionMarkerBox(), mbProcessingMouseButtonDown(false), mnShiftKeySelectionAnchor(-1), mpModeHandler(new NormalModeHandler(rSlideSorter, *this)) { } SelectionFunction::~SelectionFunction (void) { mpModeHandler.reset(); } FunctionReference SelectionFunction::Create( SlideSorter& rSlideSorter, SfxRequest& rRequest) { FunctionReference xFunc( new SelectionFunction( rSlideSorter, rRequest ) ); return xFunc; } sal_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(); ProcessMouseEvent(BUTTON_DOWN, rEvent); return sal_True; } sal_Bool SelectionFunction::MouseMove (const MouseEvent& rEvent) { ProcessMouseEvent(MOUSE_MOTION, rEvent); return sal_True; } sal_Bool SelectionFunction::MouseButtonUp (const MouseEvent& rEvent) { mrController.GetScrollBarManager().StopAutoScroll (); ProcessMouseEvent(BUTTON_UP, rEvent); mbProcessingMouseButtonDown = false; // mpWindow->ReleaseMouse(); return sal_True; } void SelectionFunction::NotifyDragFinished (void) { SwitchToNormalMode(); } sal_Bool SelectionFunction::KeyInput (const KeyEvent& rEvent) { view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter); PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter); PageSelector::UpdateLock aLock (mrSlideSorter); FocusManager& rFocusManager (mrController.GetFocusManager()); sal_Bool bResult = sal_False; const KeyCode& rCode (rEvent.GetKeyCode()); switch (rCode.GetCode()) { case KEY_RETURN: { model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor()); ViewShell* pViewShell = mrSlideSorter.GetViewShell(); if (rFocusManager.HasFocus() && pDescriptor && pViewShell!=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 { pViewShell->GetDispatcher()->Execute( SID_INSERTPAGE, SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD); } bResult = sal_True; } break; } case KEY_TAB: if ( ! rFocusManager.IsFocusShowing()) { rFocusManager.ShowFocus(); bResult = sal_True; } break; case KEY_ESCAPE: // When there is an active multiselection or drag-and-drop // operation then stop that. mpModeHandler->Abort(); SwitchToNormalMode(); bResult = sal_True; break; case KEY_SPACE: { // Toggle the selection state. model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor()); if (pDescriptor && rCode.IsMod1()) { if (pDescriptor->HasState(model::PageDescriptor::ST_Selected)) mrController.GetPageSelector().DeselectPage(pDescriptor, false); else mrController.GetPageSelector().SelectPage(pDescriptor); } bResult = sal_True; } break; // Move the focus indicator left. case KEY_LEFT: MoveFocus(FocusManager::FMD_LEFT, rCode.IsShift(), rCode.IsMod1()); bResult = sal_True; break; // Move the focus indicator right. case KEY_RIGHT: MoveFocus(FocusManager::FMD_RIGHT, rCode.IsShift(), rCode.IsMod1()); bResult = sal_True; break; // Move the focus indicator up. case KEY_UP: MoveFocus(FocusManager::FMD_UP, rCode.IsShift(), rCode.IsMod1()); bResult = sal_True; break; // Move the focus indicator down. case KEY_DOWN: MoveFocus(FocusManager::FMD_DOWN, rCode.IsShift(), rCode.IsMod1()); bResult = sal_True; break; // Go to previous page. No wrap around. case KEY_PAGEUP: GotoNextPage(-1); bResult = sal_True; break; // Go to next page. No wrap around.. case KEY_PAGEDOWN: GotoNextPage(+1); bResult = sal_True; break; case KEY_HOME: GotoPage(0); bResult = sal_True; break; case KEY_END: GotoPage(mrSlideSorter.GetModel().GetPageCount()-1); bResult = sal_True; break; case KEY_DELETE: case KEY_BACKSPACE: { if (mrSlideSorter.GetProperties()->IsUIReadOnly()) break; mrController.GetSelectionManager()->DeleteSelectedPages(rCode.GetCode()==KEY_DELETE); mnShiftKeySelectionAnchor = -1; bResult = sal_True; } break; case KEY_F10: if (rCode.IsShift()) { mpModeHandler->SelectOnePage( mrSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor()); } break; default: break; } if ( ! bResult) bResult = FuPoor::KeyInput(rEvent); return bResult; } 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(); } void SelectionFunction::Deactivate() { FuPoor::Deactivate(); } void SelectionFunction::ScrollStart (void) { } void SelectionFunction::ScrollEnd (void) { } void SelectionFunction::DoCut (void) { if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly()) { mrController.GetClipboard().DoCut(); } } void SelectionFunction::DoCopy (void) { mrController.GetClipboard().DoCopy(); } void SelectionFunction::DoPaste (void) { if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly()) { mrController.GetClipboard().DoPaste(); } } bool SelectionFunction::cancel (void) { mrController.GetFocusManager().ToggleFocus(); return true; } 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; GotoPage(nIndex + nOffset); } ResetShiftKeySelectionAnchor(); } void SelectionFunction::GotoPage (int nIndex) { sal_uInt16 nPageCount = (sal_uInt16)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 { OSL_ASSERT(pNextPageDescriptor.get() != NULL); } ResetShiftKeySelectionAnchor(); } void SelectionFunction::ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent) { // #95491# remember button state for creation of own MouseEvents SetMouseButtonCode (rEvent.GetButtons()); EventDescriptor aEventDescriptor (nEventType, rEvent, mrSlideSorter); ProcessEvent(aEventDescriptor); } void SelectionFunction::MouseDragged ( const AcceptDropEvent& rEvent, const sal_Int8 nDragAction) { EventDescriptor aEventDescriptor (MOUSE_DRAG, rEvent, nDragAction, mrSlideSorter); ProcessEvent(aEventDescriptor); } void SelectionFunction::ProcessKeyEvent (const KeyEvent& rEvent) { EventDescriptor aEventDescriptor (rEvent, mrSlideSorter); ProcessEvent(aEventDescriptor); } void SelectionFunction::ProcessEvent (EventDescriptor& rDescriptor) { // 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 pModeHandler (mpModeHandler); pModeHandler->ProcessEvent(rDescriptor); } bool Match ( const sal_uInt32 nEventCode, const sal_uInt32 nPositivePattern) { return (nEventCode & nPositivePattern)==nPositivePattern; } void SelectionFunction::SwitchToNormalMode (void) { if (mpModeHandler->GetMode() != NormalMode) SwitchMode(::boost::shared_ptr( new NormalModeHandler(mrSlideSorter, *this))); } void SelectionFunction::SwitchToDragAndDropMode (const Point aMousePosition) { if (mpModeHandler->GetMode() != DragAndDropMode) { SwitchMode(::boost::shared_ptr( new DragAndDropModeHandler(mrSlideSorter, *this, aMousePosition, mpWindow))); } } void SelectionFunction::SwitchToMultiSelectionMode ( const Point aMousePosition, const sal_uInt32 nEventCode) { if (mpModeHandler->GetMode() != MultiSelectionMode) SwitchMode(::boost::shared_ptr( new MultiSelectionModeHandler(mrSlideSorter, *this, aMousePosition, nEventCode))); } bool SelectionFunction::SwitchToButtonMode (void) { // Do not show the buttons for draw pages. ::boost::shared_ptr pMainViewShell (mrSlideSorter.GetViewShellBase()->GetMainViewShell()); if (pMainViewShell && pMainViewShell->GetShellType()!=ViewShell::ST_DRAW && mpModeHandler->GetMode() != ButtonMode) { SwitchMode(::boost::shared_ptr(new ButtonModeHandler(mrSlideSorter, *this))); return true; } else return false; } void SelectionFunction::SwitchMode (const ::boost::shared_ptr& rpHandler) { // Not all modes allow mouse over indicator. if (mpModeHandler->IsMouseOverIndicatorAllowed() != rpHandler->IsMouseOverIndicatorAllowed()) { if ( ! rpHandler->IsMouseOverIndicatorAllowed()) { mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor()); mrSlideSorter.GetView().GetButtonBar().ResetPage(); } else mrSlideSorter.GetView().UpdatePageUnderMouse(false); } mpModeHandler = rpHandler; } void SelectionFunction::ResetShiftKeySelectionAnchor (void) { mnShiftKeySelectionAnchor = -1; } void SelectionFunction::ResetMouseAnchor (void) { if (mpModeHandler && mpModeHandler->GetMode() == NormalMode) { ::boost::shared_ptr pHandler ( ::boost::dynamic_pointer_cast(mpModeHandler)); if (pHandler) pHandler->ResetButtonDownLocation(); } } //===== 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) { maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition); mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition); if (mpHitDescriptor) { 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); } 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) { 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); } 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) { mpHitPage = pHitDescriptor->GetPage(); mpHitDescriptor = pHitDescriptor; } mnEventCode |= EncodeKeyEvent(rEvent) | EncodeState(); } 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 (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 pressed modifier keys. if (rEvent.IsShift()) nEventCode |= SHIFT_MODIFIER; if (rEvent.IsMod1()) nEventCode |= CONTROL_MODIFIER; // Detect whether the mouse is over one of the active elements inside a // page object. if (mbIsOverButton) nEventCode |= OVER_BUTTON; return nEventCode; } sal_uInt32 SelectionFunction::EventDescriptor::EncodeKeyEvent (const KeyEvent& rEvent) const { // The key code in the lower 16 bit. sal_uInt32 nEventCode (rEvent.GetKeyCode().GetCode()); // Detect pressed modifier keys. if (rEvent.GetKeyCode().IsShift()) nEventCode |= SHIFT_MODIFIER; if (rEvent.GetKeyCode().IsMod1()) nEventCode |= CONTROL_MODIFIER; return nEventCode; } sal_uInt32 SelectionFunction::EventDescriptor::EncodeState (void) const { sal_uInt32 nEventCode (0); // Detect whether the event has happened over a page object. if (mpHitPage!=NULL && mpHitDescriptor) { if (mpHitDescriptor->HasState(model::PageDescriptor::ST_Selected)) nEventCode |= OVER_SELECTED_PAGE; else nEventCode |= OVER_UNSELECTED_PAGE; // Detect whether the mouse is over one of the active elements // inside a page object. if (mbIsOverButton) nEventCode |= OVER_BUTTON; } return nEventCode; } //===== SelectionFunction::ModeHandler ======================================== SelectionFunction::ModeHandler::ModeHandler ( SlideSorter& rSlideSorter, SelectionFunction& rSelectionFunction, const bool bIsMouseOverIndicatorAllowed) : mrSlideSorter(rSlideSorter), mrSelectionFunction(rSelectionFunction), mbIsMouseOverIndicatorAllowed(bIsMouseOverIndicatorAllowed) { } SelectionFunction::ModeHandler::~ModeHandler (void) { } void SelectionFunction::ModeHandler::ReprocessEvent (EventDescriptor& rDescriptor) { mrSelectionFunction.ProcessEvent(rDescriptor); } void SelectionFunction::ModeHandler::ProcessEvent ( SelectionFunction::EventDescriptor& rDescriptor) { 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); } 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(), sal_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) { } 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(rDescriptor.mpHitDescriptor); break; case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: 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(rDescriptor.mpHitDescriptor); SwitchView(rDescriptor.mpHitDescriptor); break; case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | SHIFT_MODIFIER: case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | SHIFT_MODIFIER: // Range selection with the shift modifier. RangeSelect(rDescriptor.mpHitDescriptor); break; 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. case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | 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. SetCurrentPage(rDescriptor.mpHitDescriptor); rDescriptor.mbMakeSelectionVisible = false; break; case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: // Do not change the selection. Just adjust the insertion indicator. rDescriptor.mbMakeSelectionVisible = false; break; case BUTTON_DOWN | RIGHT_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; 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; 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; // 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; 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; default: bIsProcessed = false; break; } mrSelectionFunction.SwitchToNormalMode(); return bIsProcessed; } 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): // SetCurrentPage(rDescriptor.mpHitDescriptor); // Fallthrough // 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; // 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: bIsProcessed = false; break; } return bIsProcessed; } bool NormalModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) { mrSelectionFunction.SwitchToDragAndDropMode(rDescriptor.maMousePosition); ReprocessEvent(rDescriptor); return true; } void NormalModeHandler::RangeSelect (const model::SharedPageDescriptor& rpDescriptor) { PageSelector::UpdateLock aLock (mrSlideSorter); PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); model::SharedPageDescriptor pAnchor (rSelector.GetSelectionAnchor()); DeselectAllPages(); if (pAnchor.get() != NULL) { // Select all pages between the anchor and the given one, including // the two. const sal_uInt16 nAnchorIndex ((pAnchor->GetPage()->GetPageNum()-1) / 2); const sal_uInt16 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 sal_uInt16 nStep ((nAnchorIndex < nOtherIndex) ? +1 : -1); sal_uInt16 nIndex (nAnchorIndex); while (true) { rSelector.SelectPage(nIndex); if (nIndex == nOtherIndex) break; nIndex = nIndex + nStep; } } } void NormalModeHandler::ResetButtonDownLocation (void) { maButtonDownLocation = ::boost::optional(); } //===== 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); } MultiSelectionModeHandler::~MultiSelectionModeHandler (void) { 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)) { mrSelectionFunction.SwitchToNormalMode(); return true; } else return false; } 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; } bool MultiSelectionModeHandler::HandleUnprocessedEvent ( SelectionFunction::EventDescriptor& rDescriptor) { if ( ! ModeHandler::HandleUnprocessedEvent(rDescriptor)) { // If the event has not been processed then stop multi selection. mrSelectionFunction.SwitchToNormalMode(); ReprocessEvent(rDescriptor); } return true; } 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)))) { UpdateModelPosition(aMouseModelPosition); } } void MultiSelectionModeHandler::SetSelectionModeFromModifier ( const sal_uInt32 nEventCode) { switch (nEventCode & MODIFIER_MASK) { case NO_MODIFIER: SetSelectionMode(SM_Normal); break; case SHIFT_MODIFIER: SetSelectionMode(SM_Add); break; case CONTROL_MODIFIER: SetSelectionMode(SM_Toggle); break; } } void MultiSelectionModeHandler::SetSelectionMode (const SelectionMode eSelectionMode) { if (meSelectionMode != eSelectionMode) { 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; case SM_Add: bSelect = bIsInSelection || bWasSelected; break; 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(); } void MultiSelectionModeHandler::UpdateSelection (void) { 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 && nIndexUnderMousepTransferDrag; if (pDragTransferable==NULL && mrSlideSorter.GetViewShell() != NULL) { SlideSorterViewShell* pSlideSorterViewShell = dynamic_cast(mrSlideSorter.GetViewShell()); if (pSlideSorterViewShell != NULL) pSlideSorterViewShell->StartDrag(rMousePosition, pWindow); pDragTransferable = SD_MOD()->pTransferDrag; } mpDragAndDropContext.reset(new DragAndDropContext(mrSlideSorter)); mrSlideSorter.GetController().GetInsertionIndicatorHandler()->Start( pDragTransferable != NULL && pDragTransferable->GetView()==&mrSlideSorter.GetView()); } DragAndDropModeHandler::~DragAndDropModeHandler (void) { if (mpDragAndDropContext) { // Disconnect the substitution handler from this selection function. mpDragAndDropContext->SetTargetSlideSorter(); mpDragAndDropContext.reset(); } mrSlideSorter.GetController().GetInsertionIndicatorHandler()->End(Animator::AM_Animated); } SelectionFunction::Mode DragAndDropModeHandler::GetMode (void) const { return SelectionFunction::DragAndDropMode; } void DragAndDropModeHandler::Abort (void) { mrSlideSorter.GetController().GetClipboard().Abort(); if (mpDragAndDropContext) mpDragAndDropContext->Dispose(); // mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection()); } bool DragAndDropModeHandler::ProcessButtonUpEvent ( SelectionFunction::EventDescriptor& rDescriptor) { 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; } 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; } //===== ButtonModeHandler ===================================================== ButtonModeHandler::ButtonModeHandler ( SlideSorter& rSlideSorter, SelectionFunction& rSelectionFunction) : ModeHandler(rSlideSorter, rSelectionFunction, true) { } ButtonModeHandler::~ButtonModeHandler (void) { } SelectionFunction::Mode ButtonModeHandler::GetMode (void) const { return SelectionFunction::ButtonMode; } void ButtonModeHandler::Abort (void) { } bool ButtonModeHandler::ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor) { switch (rDescriptor.mnEventCode) { 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; } } 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; } 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