diff options
Diffstat (limited to 'sd/source/ui/slidesorter/controller')
24 files changed, 4671 insertions, 1820 deletions
diff --git a/sd/source/ui/slidesorter/controller/SlideSorterController.cxx b/sd/source/ui/slidesorter/controller/SlideSorterController.cxx index 69c2a02ddc24..8018c71e2b88 100755..100644 --- a/sd/source/ui/slidesorter/controller/SlideSorterController.cxx +++ b/sd/source/ui/slidesorter/controller/SlideSorterController.cxx @@ -39,17 +39,22 @@ #include "SlsSelectionCommand.hxx" #include "controller/SlsAnimator.hxx" #include "controller/SlsClipboard.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" #include "controller/SlsScrollBarManager.hxx" -#include "controller/SlsPageObjectFactory.hxx" #include "controller/SlsSelectionManager.hxx" #include "controller/SlsSlotManager.hxx" +#include "controller/SlsTransferable.hxx" +#include "controller/SlsVisibleAreaManager.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageEnumerationProvider.hxx" #include "model/SlsPageDescriptor.hxx" #include "view/SlideSorterView.hxx" #include "view/SlsLayouter.hxx" -#include "view/SlsViewOverlay.hxx" #include "view/SlsFontProvider.hxx" +#include "view/SlsPageObjectLayouter.hxx" +#include "view/SlsPageObjectPainter.hxx" +#include "view/SlsTheme.hxx" +#include "view/SlsToolTip.hxx" #include "cache/SlsPageCache.hxx" #include "cache/SlsPageCacheManager.hxx" @@ -91,12 +96,12 @@ #include <com/sun/star/drawing/XDrawPages.hpp> #include <com/sun/star/accessibility/AccessibleEventId.hpp> - using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::sd::slidesorter::model; using namespace ::sd::slidesorter::view; using namespace ::sd::slidesorter::controller; +using namespace ::basegfx; namespace sd { namespace slidesorter { namespace controller { @@ -112,9 +117,12 @@ SlideSorterController::SlideSorterController (SlideSorter& rSlideSorter) mpScrollBarManager(), mpCurrentSlideManager(), mpSelectionManager(), + mpInsertionIndicatorHandler(new InsertionIndicatorHandler(rSlideSorter)), mpAnimator(new Animator(rSlideSorter)), + mpVisibleAreaManager(new VisibleAreaManager(rSlideSorter)), mpListener(), mnModelChangeLockCount(0), + mbIsForcedRearrangePending(false), mbPreModelChangeDone(false), mbPostModelChangePending(false), maSelectionBeforeSwitch(), @@ -122,12 +130,11 @@ SlideSorterController::SlideSorterController (SlideSorter& rSlideSorter) mpEditModeChangeMasterPage(NULL), maTotalWindowArea(), mnPaintEntranceCount(0), - mbIsContextMenuOpen(false), - mpProperties(new Properties()) + mbIsContextMenuOpen(false) { - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - OSL_ASSERT(pWindow!=NULL); - if (pWindow != NULL) + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + OSL_ASSERT(pWindow); + if (pWindow) { // The whole background is painted by the view and controls. ::Window* pParentWindow = pWindow->GetParent(); @@ -136,22 +143,10 @@ SlideSorterController::SlideSorterController (SlideSorter& rSlideSorter) // Connect the view with the window that has been created by our base // class. - pWindow->SetBackground (Wallpaper()); - mrView.AddWindowToPaintView(pWindow); - mrView.SetActualWin(pWindow); - pWindow->SetCenterAllowed (false); - pWindow->SetViewSize (mrView.GetModelArea().GetSize()); - pWindow->EnableRTL(FALSE); - - // Reinitialize colors in Properties with window specific values. - mpProperties->SetBackgroundColor( - pWindow->GetSettings().GetStyleSettings().GetWindowColor()); - mpProperties->SetTextColor( - pWindow->GetSettings().GetStyleSettings().GetWindowTextColor()); - mpProperties->SetSelectionColor( - pWindow->GetSettings().GetStyleSettings().GetMenuHighlightColor()); - mpProperties->SetHighlightColor( - pWindow->GetSettings().GetStyleSettings().GetMenuHighlightColor()); + pWindow->SetBackground(Wallpaper()); + pWindow->SetCenterAllowed(false); + pWindow->SetMapMode(MapMode(MAP_PIXEL)); + pWindow->SetViewSize(mrView.GetModelArea().GetSize()); } } @@ -160,8 +155,6 @@ SlideSorterController::SlideSorterController (SlideSorter& rSlideSorter) void SlideSorterController::Init (void) { - mrView.HandleModelChange(); - mpCurrentSlideManager.reset(new CurrentSlideManager(mrSlideSorter)); mpPageSelector.reset(new PageSelector(mrSlideSorter)); mpFocusManager.reset(new FocusManager(mrSlideSorter)); @@ -181,7 +174,7 @@ void SlideSorterController::Init (void) mpListener = new Listener(mrSlideSorter); - mpPageSelector->UpdateAllPages(); + mpPageSelector->GetCoreSelection(); GetSelectionManager()->SelectionHasChanged(); } @@ -210,17 +203,48 @@ SlideSorterController::~SlideSorterController (void) +void SlideSorterController::Dispose (void) +{ + mpInsertionIndicatorHandler->End(Animator::AM_Immediate); + mpSelectionManager.reset(); + mpAnimator->Dispose(); +} + + + + model::SharedPageDescriptor SlideSorterController::GetPageAt ( - const Point& aPixelPosition) + const Point& aWindowPosition) { - sal_Int32 nHitPageIndex (mrView.GetPageIndexAtPoint(aPixelPosition)); + sal_Int32 nHitPageIndex (mrView.GetPageIndexAtPoint(aWindowPosition)); model::SharedPageDescriptor pDescriptorAtPoint; if (nHitPageIndex >= 0) + { pDescriptorAtPoint = mrModel.GetPageDescriptor(nHitPageIndex); + // Depending on a property we may have to check that the mouse is no + // just over the page object but over the preview area. + if (pDescriptorAtPoint + && mrSlideSorter.GetProperties()->IsOnlyPreviewTriggersMouseOver() + && ! pDescriptorAtPoint->HasState(PageDescriptor::ST_Selected)) + { + // Make sure that the mouse is over the preview area. + if ( ! mrView.GetLayouter().GetPageObjectLayouter()->GetBoundingBox( + pDescriptorAtPoint, + view::PageObjectLayouter::Preview, + view::PageObjectLayouter::WindowCoordinateSystem).IsInside(aWindowPosition)) + { + pDescriptorAtPoint.reset(); + } + } + } + return pDescriptorAtPoint; } + + + PageSelector& SlideSorterController::GetPageSelector (void) { OSL_ASSERT(mpPageSelector.get()!=NULL); @@ -284,10 +308,11 @@ ScrollBarManager& SlideSorterController::GetScrollBarManager (void) -void SlideSorterController::PrePaint() +::boost::shared_ptr<InsertionIndicatorHandler> + SlideSorterController::GetInsertionIndicatorHandler (void) const { - // forward VCLs PrePaint window event to DrawingLayer - mrView.PrePaint(); + OSL_ASSERT(mpInsertionIndicatorHandler.get()!=NULL); + return mpInsertionIndicatorHandler; } @@ -297,16 +322,12 @@ void SlideSorterController::Paint ( const Rectangle& rBBox, ::Window* pWindow) { - // if (mnPaintEntranceCount == 0) + if (mnPaintEntranceCount == 0) { ++mnPaintEntranceCount; try { - if (GetSelectionManager()->IsMakeSelectionVisiblePending()) - GetSelectionManager()->MakeSelectionVisible(); - - mrView.SetApplicationDocumentColor(GetProperties()->GetBackgroundColor()); mrView.CompleteRedraw(pWindow, Region(rBBox), 0); } catch (const Exception&) @@ -394,50 +415,64 @@ bool SlideSorterController::Command ( else nPopupId = RID_SLIDE_SORTER_MASTER_NOSEL_POPUP; } - + ::boost::scoped_ptr<InsertionIndicatorHandler::ForceShowContext> pContext; if (pPage == NULL) { // When there is no selection, then we show the insertion // indicator so that the user knows where a page insertion // would take place. - mrView.GetOverlay().GetInsertionIndicatorOverlay().SetPosition( - pWindow->PixelToLogic(rEvent.GetMousePosPixel())); - mrView.GetOverlay().GetInsertionIndicatorOverlay().setVisible(true); + mpInsertionIndicatorHandler->Start(false); + mpInsertionIndicatorHandler->UpdateIndicatorIcon( + dynamic_cast<Transferable*>(SD_MOD()->pTransferClip)); + mpInsertionIndicatorHandler->UpdatePosition( + pWindow->PixelToLogic(rEvent.GetMousePosPixel()), + InsertionIndicatorHandler::MoveMode); + pContext.reset(new InsertionIndicatorHandler::ForceShowContext( + mpInsertionIndicatorHandler)); } pWindow->ReleaseMouse(); + + Point aMenuLocation (0,0); if (rEvent.IsMouseEvent()) { - mbIsContextMenuOpen = true; - if (pViewShell != NULL) - { - SfxDispatcher* pDispatcher = pViewShell->GetDispatcher(); - if (pDispatcher != NULL) - pDispatcher->ExecutePopup(SdResId(nPopupId)); - } + // We have to explicitly specify the location of the menu + // when the slide sorter is placed in an undocked child + // menu. But when it is docked it does not hurt, so we + // specify the location always. + aMenuLocation = rEvent.GetMousePosPixel(); } else { // The event is not a mouse event. Use the center of the // focused page as top left position of the context menu. - if (pPage != NULL) + model::SharedPageDescriptor pDescriptor ( + GetFocusManager().GetFocusedPageDescriptor()); + if (pDescriptor.get() != NULL) { - model::SharedPageDescriptor pDescriptor ( - GetFocusManager().GetFocusedPageDescriptor()); - if (pDescriptor.get() != NULL) - { - Rectangle aBBox (mrView.GetPageBoundingBox ( + Rectangle aBBox ( + mrView.GetLayouter().GetPageObjectLayouter()->GetBoundingBox ( pDescriptor, - view::SlideSorterView::CS_SCREEN, - view::SlideSorterView::BBT_SHAPE)); - Point aPosition (aBBox.Center()); - mbIsContextMenuOpen = true; - if (pViewShell != NULL) - pViewShell->GetViewFrame()->GetDispatcher()->ExecutePopup( - SdResId(nPopupId), - pWindow, - &aPosition); - } + PageObjectLayouter::PageObject, + PageObjectLayouter::ModelCoordinateSystem)); + aMenuLocation = aBBox.Center(); + } + } + + mbIsContextMenuOpen = true; + if (pViewShell != NULL) + { + SfxDispatcher* pDispatcher = pViewShell->GetDispatcher(); + if (pDispatcher != NULL) + { + pDispatcher->ExecutePopup( + SdResId(nPopupId), + pWindow, + &aMenuLocation); + mrSlideSorter.GetView().UpdatePageUnderMouse(false); + ::rtl::Reference<SelectionFunction> pFunction(GetCurrentSelectionFunction()); + if (pFunction.is()) + pFunction->ResetMouseAnchor(); } } mbIsContextMenuOpen = false; @@ -447,19 +482,44 @@ bool SlideSorterController::Command ( // it is hidden, so that a pending slide insertion slot call // finds the right place to insert a new slide. GetSelectionManager()->SetInsertionPosition( - mrView.GetOverlay().GetInsertionIndicatorOverlay().GetInsertionPageIndex()); - mrView.GetOverlay().GetInsertionIndicatorOverlay().setVisible(false); + GetInsertionIndicatorHandler()->GetInsertionPageIndex()); } + pContext.reset(); bEventHasBeenHandled = true; } break; case COMMAND_WHEEL: { - // We ignore zooming with control+mouse wheel. const CommandWheelData* pData = rEvent.GetWheelData(); - if (pData!=NULL && pData->IsMod1()) - bEventHasBeenHandled = true; + if (pData == NULL) + return false; + if (pData->IsMod1()) + { + // We do not support zooming with control+mouse wheel. + return false; + } + // Determine whether to scroll horizontally or vertically. This + // depends on the orientation of the scroll bar and the + // IsHoriz() flag of the event. + if ((mrSlideSorter.GetView().GetOrientation()==view::Layouter::HORIZONTAL) + == pData->IsHorz()) + { + GetScrollBarManager().Scroll( + ScrollBarManager::Orientation_Vertical, + ScrollBarManager::Unit_Slide, + -pData->GetNotchDelta()); + } + else + { + GetScrollBarManager().Scroll( + ScrollBarManager::Orientation_Horizontal, + ScrollBarManager::Unit_Slide, + -pData->GetNotchDelta()); + } + mrSlideSorter.GetView().UpdatePageUnderMouse(rEvent.GetMousePosPixel(), false); + + bEventHasBeenHandled = true; } break; } @@ -482,7 +542,9 @@ void SlideSorterController::UnlockModelChange (void) { mnModelChangeLockCount -= 1; if (mnModelChangeLockCount==0 && mbPostModelChangePending) + { PostModelChange(); + } } @@ -499,11 +561,9 @@ void SlideSorterController::PreModelChange (void) mrSlideSorter.GetViewShell()->Broadcast( ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_START)); - mpPageSelector->PrepareModelChange(); GetCurrentSlideManager()->PrepareModelChange(); - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - if (pWindow != NULL) + if (mrSlideSorter.GetContentWindow()) mrView.PreModelChange(); mbPostModelChangePending = true; @@ -517,8 +577,8 @@ void SlideSorterController::PostModelChange (void) mbPostModelChangePending = false; mrModel.Resync(); - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - if (pWindow != NULL) + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) { GetCurrentSlideManager()->HandleModelChange(); @@ -530,11 +590,9 @@ void SlideSorterController::PostModelChange (void) // The visibility of the scroll bars may have to be changed. Then // the size of the view has to change, too. Let Rearrange() handle // that. - Rearrange(); + Rearrange(mbIsForcedRearrangePending); } - mpPageSelector->HandleModelChange (); - if (mrSlideSorter.GetViewShell() != NULL) mrSlideSorter.GetViewShell()->Broadcast( ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_END)); @@ -564,23 +622,36 @@ IMPL_LINK(SlideSorterController, WindowEventHandler, VclWindowEvent*, pEvent) if (pEvent != NULL) { ::Window* pWindow = pEvent->GetWindow(); - ::sd::Window* pActiveWindow = mrSlideSorter.GetActiveWindow(); + SharedSdWindow pActiveWindow (mrSlideSorter.GetContentWindow()); switch (pEvent->GetId()) { case VCLEVENT_WINDOW_ACTIVATE: case VCLEVENT_WINDOW_SHOW: - if (pActiveWindow != NULL && pWindow == pActiveWindow->GetParent()) + if (pActiveWindow && pWindow == pActiveWindow->GetParent()) mrView.RequestRepaint(); break; + case VCLEVENT_WINDOW_HIDE: + if (pActiveWindow && pWindow == pActiveWindow->GetParent()) + mrView.SetPageUnderMouse(SharedPageDescriptor()); + break; + case VCLEVENT_WINDOW_GETFOCUS: - if (pActiveWindow != NULL && pWindow == pActiveWindow) - GetFocusManager().ShowFocus(false); + if (pActiveWindow) + if (pWindow == pActiveWindow.get()) + GetFocusManager().ShowFocus(false); break; case VCLEVENT_WINDOW_LOSEFOCUS: - if (pActiveWindow != NULL && pWindow == pActiveWindow) + if (pActiveWindow && pWindow == pActiveWindow.get()) + { GetFocusManager().HideFocus(); + mrView.GetToolTip().Hide(); + + // Select the current slide so that it is properly + // visualized when the focus is moved to the edit view. + GetPageSelector().SelectPage(GetCurrentSlideManager()->GetCurrentSlide()); + } break; case VCLEVENT_APPLICATION_DATACHANGED: @@ -601,6 +672,11 @@ IMPL_LINK(SlideSorterController, WindowEventHandler, VclWindowEvent*, pEvent) // When the system font has changed a layout has to be done. mrView.Resize(); FontProvider::Instance().Invalidate(); + + // Update theme colors. + mrSlideSorter.GetProperties()->HandleDataChangeEvent(); + mrSlideSorter.GetTheme()->Update(mrSlideSorter.GetProperties()); + mrView.HandleDataChangeEvent(); } break; @@ -639,10 +715,9 @@ void SlideSorterController::GetCtrlState (SfxItemSet& rSet) ||rSet.GetItemState(SID_OUTPUT_QUALITY_BLACKWHITE)==SFX_ITEM_AVAILABLE ||rSet.GetItemState(SID_OUTPUT_QUALITY_CONTRAST)==SFX_ITEM_AVAILABLE) { - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - if (pWindow != NULL) + if (mrSlideSorter.GetContentWindow()) { - ULONG nMode = pWindow->GetDrawMode(); + ULONG nMode = mrSlideSorter.GetContentWindow()->GetDrawMode(); UINT16 nQuality = 0; switch (nMode) @@ -715,7 +790,7 @@ void SlideSorterController::ExecStatusBar (SfxRequest& ) void SlideSorterController::UpdateAllPages (void) { // Do a redraw. - mrView.InvalidateAllWin(); + mrSlideSorter.GetContentWindow()->Invalidate(); } @@ -741,20 +816,35 @@ Rectangle SlideSorterController::Rearrange (bool bForce) { Rectangle aNewContentArea (maTotalWindowArea); - ::boost::shared_ptr<sd::Window> pWindow = mrSlideSorter.GetContentWindow(); - if (pWindow.get() != NULL) + if (aNewContentArea.IsEmpty()) + return aNewContentArea; + + if (mnModelChangeLockCount>0) { + mbIsForcedRearrangePending |= bForce; + return aNewContentArea; + } + else + mbIsForcedRearrangePending = false; + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) + { + if (bForce) + mrView.UpdateOrientation(); + // Place the scroll bars. - aNewContentArea = GetScrollBarManager().PlaceScrollBars(maTotalWindowArea); + aNewContentArea = GetScrollBarManager().PlaceScrollBars( + maTotalWindowArea, + mrView.GetOrientation() != view::Layouter::VERTICAL, + mrView.GetOrientation() != view::Layouter::HORIZONTAL); bool bSizeHasChanged (false); // Only when bForce is not true we have to test for a size change in // order to determine whether the window and the view have to be resized. if ( ! bForce) { - Rectangle aCurrentContentArea ( - pWindow->GetPosPixel(), - pWindow->GetOutputSizePixel()); + Rectangle aCurrentContentArea (pWindow->GetPosPixel(), pWindow->GetOutputSizePixel()); bSizeHasChanged = (aNewContentArea != aCurrentContentArea); } if (bForce || bSizeHasChanged) @@ -767,6 +857,11 @@ Rectangle SlideSorterController::Rearrange (bool bForce) // Adapt the scroll bars to the new zoom factor of the browser // window and the arrangement of the page objects. GetScrollBarManager().UpdateScrollBars(false, !bForce); + + // Keep the current slide in the visible area. + GetVisibleAreaManager().RequestCurrentSlideVisible(); + + mrView.RequestRepaint(); } return aNewContentArea; @@ -784,6 +879,15 @@ FunctionReference SlideSorterController::CreateSelectionFunction (SfxRequest& rR +::rtl::Reference<SelectionFunction> SlideSorterController::GetCurrentSelectionFunction (void) +{ + FunctionReference pFunction (mrSlideSorter.GetViewShell()->GetCurrentFunction()); + return ::rtl::Reference<SelectionFunction>(dynamic_cast<SelectionFunction*>(pFunction.get())); +} + + + + void SlideSorterController::PrepareEditModeChange (void) { // Before we throw away the page descriptors we prepare for selecting @@ -887,8 +991,8 @@ void SlideSorterController::PageNameHasChanged (int nPageIndex, const String& rs // that of the name change. do { - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - if (pWindow == NULL) + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if ( ! pWindow) break; ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > @@ -937,14 +1041,6 @@ bool SlideSorterController::IsContextMenuOpen (void) const -::boost::shared_ptr<Properties> SlideSorterController::GetProperties (void) const -{ - return mpProperties; -} - - - - void SlideSorterController::SetDocumentSlides (const Reference<container::XIndexAccess>& rxSlides) { if (mrModel.GetDocumentSlides() != rxSlides) @@ -954,6 +1050,11 @@ void SlideSorterController::SetDocumentSlides (const Reference<container::XIndex mrModel.SetDocumentSlides(rxSlides); mrView.Layout(); + + // Select just the current slide. + PageSelector::BroadcastLock aBroadcastLock (*mpPageSelector); + mpPageSelector->DeselectAllPages(); + mpPageSelector->SelectPage(mpCurrentSlideManager->GetCurrentSlide()); } } @@ -968,6 +1069,35 @@ void SlideSorterController::SetDocumentSlides (const Reference<container::XIndex +VisibleAreaManager& SlideSorterController::GetVisibleAreaManager (void) const +{ + OSL_ASSERT(mpVisibleAreaManager); + return *mpVisibleAreaManager; +} + + + + +void SlideSorterController::CheckForMasterPageAssignment (void) +{ + if (mrModel.GetPageCount()%2==0) + return; + PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + while (aAllPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + if (pDescriptor->UpdateMasterPage()) + { + mrView.GetPreviewCache()->InvalidatePreviewBitmap ( + pDescriptor->GetPage(), + true); + } + } +} + + + + //===== SlideSorterController::ModelChangeLock ================================ SlideSorterController::ModelChangeLock::ModelChangeLock ( diff --git a/sd/source/ui/slidesorter/controller/SlsAnimationFunction.cxx b/sd/source/ui/slidesorter/controller/SlsAnimationFunction.cxx new file mode 100644 index 000000000000..71b6c024ae7a --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsAnimationFunction.cxx @@ -0,0 +1,294 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" +#include "controller/SlsAnimationFunction.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" + + +#include <osl/diagnose.hxx> +#include <rtl/math.hxx> + +namespace sd { namespace slidesorter { namespace controller { + + +double AnimationFunction::Linear (const double nTime) +{ + OSL_ASSERT(nTime>=0.0 && nTime<=1.0); + return nTime; +} + + + + +double AnimationFunction::FastInSlowOut_Sine (const double nTime) +{ + OSL_ASSERT(nTime>=0.0 && nTime<=1.0); + + const double nResult (sin(nTime * M_PI/2)); + + OSL_ASSERT(nResult>=0.0 && nResult<=1.0); + return nResult; +} + + + + +double AnimationFunction::FastInSlowOut_Root (const double nTime) +{ + OSL_ASSERT(nTime>=0.0 && nTime<=1.0); + + const double nResult (sqrt(nTime)); + + OSL_ASSERT(nResult>=0.0 && nResult<=1.0); + return nResult; +} + + + + +double AnimationFunction::SlowInSlowOut_0to0_Sine (const double nTime) +{ + OSL_ASSERT(nTime>=0.0 && nTime<=1.0); + + const double nResult (sin(nTime * M_PI)); + + OSL_ASSERT(nResult>=0.0 && nResult<=1.0); + return nResult; +} + + + + +double AnimationFunction::Vibrate_Sine (const double nTime) +{ + return sin(nTime*M_PI*8); +} + + + + +Point AnimationFunction::ScalePoint (const Point& rPoint, const double nTime) +{ + return Point( + sal_Int32(::rtl::math::round(rPoint.X() * nTime)), + sal_Int32(::rtl::math::round(rPoint.Y() * nTime))); +} + + + + +double AnimationFunction::Blend ( + const double nStartValue, + const double nEndValue, + const double nTime) +{ + return nStartValue*(1-nTime) + nEndValue*nTime; +} + + + + +void AnimationFunction::ApplyVisualStateChange ( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const double nTime) +{ + if (rpDescriptor) + { + rpDescriptor->GetVisualState().SetVisualStateBlend(nTime); + rView.RequestRepaint(rpDescriptor); + } +} + + + + +void AnimationFunction::ApplyLocationOffsetChange ( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const Point aLocationOffset) +{ + if (rpDescriptor) + { + const Rectangle aOldBoundingBox(rpDescriptor->GetBoundingBox()); + rpDescriptor->GetVisualState().SetLocationOffset(aLocationOffset); + rView.RequestRepaint(aOldBoundingBox); + rView.RequestRepaint(rpDescriptor); + } +} + + + + +void AnimationFunction::ApplyButtonAlphaChange( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const double nButtonAlpha, + const double nButtonBarAlpha) +{ + if (rpDescriptor) + { + rpDescriptor->GetVisualState().SetButtonAlpha(nButtonAlpha); + rpDescriptor->GetVisualState().SetButtonBarAlpha(nButtonBarAlpha); + rView.RequestRepaint(rpDescriptor); + } +} + + + + +//===== AnimationBezierFunction =============================================== + +AnimationBezierFunction::AnimationBezierFunction ( + const double nX1, + const double nY1, + const double nX2, + const double nY2) + : mnX1(nX1), + mnY1(nY1), + mnX2(nX2), + mnY2(nY2) +{ +} + + + + +AnimationBezierFunction::AnimationBezierFunction ( + const double nX1, + const double nY1) + : mnX1(nX1), + mnY1(nY1), + mnX2(1-nY1), + mnY2(1-nX1) +{ +} + + + + +::basegfx::B2DPoint AnimationBezierFunction::operator() (const double nT) +{ + return ::basegfx::B2DPoint( + EvaluateComponent(nT, mnX1, mnX2), + EvaluateComponent(nT, mnY1, mnY2)); +} + + + + +double AnimationBezierFunction::EvaluateComponent ( + const double nT, + const double nV1, + const double nV2) +{ + const double nS (1-nT); + + // While the control point values 1 and 2 are explicitly given the start + // and end values are implicitly given. + const double nV0 (0); + const double nV3 (1); + + const double nV01 (nS*nV0 + nT*nV1); + const double nV12 (nS*nV1 + nT*nV2); + const double nV23 (nS*nV2 + nT*nV3); + + const double nV012 (nS*nV01 + nT*nV12); + const double nV123 (nS*nV12 + nT*nV23); + + const double nV0123 (nS*nV012 + nT*nV123); + + return nV0123; +} + + + + +//===== AnimationParametricFunction =========================================== + +AnimationParametricFunction::AnimationParametricFunction (const ParametricFunction& rFunction) + : maY() +{ + const sal_Int32 nSampleCount (64); + + // Sample the given parametric function. + ::std::vector<basegfx::B2DPoint> aPoints; + aPoints.reserve(nSampleCount); + for (sal_Int32 nIndex=0; nIndex<nSampleCount; ++nIndex) + { + const double nT (nIndex/double(nSampleCount-1)); + aPoints.push_back(basegfx::B2DPoint(rFunction(nT))); + } + + // Interpolate at evenly spaced points. + maY.clear(); + maY.reserve(nSampleCount); + double nX0 (aPoints[0].getX()); + double nY0 (aPoints[0].getY()); + double nX1 (aPoints[1].getX()); + double nY1 (aPoints[1].getY()); + sal_Int32 nIndex (1); + for (sal_Int32 nIndex2=0; nIndex2<nSampleCount; ++nIndex2) + { + const double nX (nIndex2 / double(nSampleCount-1)); + while (nX > nX1 && nIndex<nSampleCount) + { + nX0 = nX1; + nY0 = nY1; + nX1 = aPoints[nIndex].getX(); + nY1 = aPoints[nIndex].getY(); + ++nIndex; + } + const double nU ((nX-nX1) / (nX0 - nX1)); + const double nY (nY0*nU + nY1*(1-nU)); + maY.push_back(nY); + } +} + + + + +double AnimationParametricFunction::operator() (const double nX) +{ + const sal_Int32 nIndex0 (nX * maY.size()); + const double nX0 (nIndex0 / double(maY.size()-1)); + const sal_uInt32 nIndex1 (nIndex0 + 1); + const double nX1 (nIndex1 / double(maY.size()-1)); + + if (nIndex0<=0) + return maY[0]; + else if (sal_uInt32(nIndex0)>=maY.size() || nIndex1>=maY.size()) + return maY[maY.size()-1]; + + const double nU ((nX-nX1) / (nX0 - nX1)); + return maY[nIndex0]*nU + maY[nIndex1]*(1-nU); +} + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsAnimator.cxx b/sd/source/ui/slidesorter/controller/SlsAnimator.cxx index 56505d9756e6..28756b3766d9 100644..100755 --- a/sd/source/ui/slidesorter/controller/SlsAnimator.cxx +++ b/sd/source/ui/slidesorter/controller/SlsAnimator.cxx @@ -29,6 +29,7 @@ #include "controller/SlsAnimator.hxx" #include "view/SlideSorterView.hxx" #include "View.hxx" +#include <boost/bind.hpp> namespace sd { namespace slidesorter { namespace controller { @@ -42,27 +43,32 @@ class Animator::Animation { public: Animation ( - const Animator::AnimationFunction& rAnimation, - const double nDelta); + const Animator::AnimationFunctor& rAnimation, + const double nStartOffset, + const double nDuration, + const double nGlobalTime, + const Animator::AnimationId nAnimationId, + const Animator::FinishFunctor& rFinishFunctor); ~Animation (void); - bool Run (void); + /** Run next animation step. If animation has reached its end it is + expired. + */ + bool Run (const double nGlobalTime); + + /** Typically called when an animation has finished, but also from + Animator::Disposed(). The finish functor is called and the + animation is marked as expired to prevent another run. + */ + void Expire (void); bool IsExpired (void); - Animator::AnimationFunction maAnimation; - double mnValue; - double mnDelta; -}; - - - - -class Animator::DrawLock -{ -public: - DrawLock (View& rView); - ~DrawLock (void); -private: - View& mrView; + Animator::AnimationFunctor maAnimation; + Animator::FinishFunctor maFinishFunctor; + const Animator::AnimationId mnAnimationId; + const double mnDuration; + const double mnEnd; + const double mnGlobalTimeAtStart; + bool mbIsExpired; }; @@ -71,8 +77,11 @@ private: Animator::Animator (SlideSorter& rSlideSorter) : mrSlideSorter(rSlideSorter), maTimer(), + mbIsDisposed(false), maAnimations(), - mpDrawLock() + maElapsedTime(), + mpDrawLock(), + mnNextAnimationId(0) { maTimer.SetTimeout(gnResolution); maTimer.SetTimeoutHdl(LINK(this,Animator,TimeoutHandler)); @@ -83,39 +92,161 @@ Animator::Animator (SlideSorter& rSlideSorter) Animator::~Animator (void) { + if ( ! mbIsDisposed) + { + OSL_ASSERT(mbIsDisposed); + Dispose(); + } +} + + + + +void Animator::Dispose (void) +{ + mbIsDisposed = true; + + AnimationList aCopy (maAnimations); + AnimationList::const_iterator iAnimation; + for (iAnimation=aCopy.begin(); iAnimation!=aCopy.end(); ++iAnimation) + (*iAnimation)->Expire(); + maTimer.Stop(); - mpDrawLock.reset(); + if (mpDrawLock) + { + mpDrawLock->Dispose(); + mpDrawLock.reset(); + } } -void Animator::AddAnimation ( - const AnimationFunction& rAnimation, - const sal_Int32 nDuration) +Animator::AnimationId Animator::AddAnimation ( + const AnimationFunctor& rAnimation, + const sal_Int32 nStartOffset, + const sal_Int32 nDuration, + const FinishFunctor& rFinishFunctor) { - const double nDelta = double(gnResolution) / double(nDuration); - maAnimations.push_back(boost::shared_ptr<Animation>(new Animation(rAnimation, nDelta))); + // When the animator is already disposed then ignore this call + // silently (well, we show an assertion, but do not throw an exception.) + OSL_ASSERT( ! mbIsDisposed); + if (mbIsDisposed) + return -1; + + boost::shared_ptr<Animation> pAnimation ( + new Animation( + rAnimation, + nStartOffset / 1000.0, + nDuration / 1000.0, + maElapsedTime.getElapsedTime(), + ++mnNextAnimationId, + rFinishFunctor)); + maAnimations.push_back(pAnimation); + + RequestNextFrame(); + + return pAnimation->mnAnimationId; +} + - // Prevent redraws except for the ones in TimeoutHandler. - // While the Animator is active it will schedule repaints regularly. - // Repaints in between would only lead to visual artifacts. - mpDrawLock.reset(new DrawLock(mrSlideSorter.GetView())); - maTimer.Start(); + + +Animator::AnimationId Animator::AddInfiniteAnimation ( + const AnimationFunctor& rAnimation, + const double nDelta) +{ + (void)nDelta; + + // When the animator is already disposed then ignore this call + // silently (well, we show an assertion, but do not throw an exception.) + OSL_ASSERT( ! mbIsDisposed); + if (mbIsDisposed) + return -1; + + boost::shared_ptr<Animation> pAnimation ( + new Animation( + rAnimation, + 0, + -1, + maElapsedTime.getElapsedTime(), + mnNextAnimationId++, + FinishFunctor())); + maAnimations.push_back(pAnimation); + + RequestNextFrame(); + + return pAnimation->mnAnimationId; } -bool Animator::ServeAnimations (void) +void Animator::RemoveAnimation (const Animator::AnimationId nId) +{ + OSL_ASSERT( ! mbIsDisposed); + + const AnimationList::iterator iAnimation (::std::find_if( + maAnimations.begin(), + maAnimations.end(), + ::boost::bind( + ::std::equal_to<Animator::AnimationId>(), + nId, + ::boost::bind(&Animation::mnAnimationId, _1)))); + if (iAnimation != maAnimations.end()) + { + OSL_ASSERT((*iAnimation)->mnAnimationId == nId); + (*iAnimation)->Expire(); + maAnimations.erase(iAnimation); + } + + if (maAnimations.empty()) + { + // Reset the animation id when we can. + mnNextAnimationId = 0; + + // No more animations => we do not have to suppress painting + // anymore. + mpDrawLock.reset(); + } +} + + + + +void Animator::RemoveAllAnimations (void) +{ + ::std::for_each( + maAnimations.begin(), + maAnimations.end(), + ::boost::bind( + &Animation::Expire, + _1)); + maAnimations.clear(); + mnNextAnimationId = 0; + + // No more animations => we do not have to suppress painting + // anymore. + mpDrawLock.reset(); +} + + + + +bool Animator::ProcessAnimations (const double nTime) { bool bExpired (false); + OSL_ASSERT( ! mbIsDisposed); + if (mbIsDisposed) + return bExpired; + + AnimationList aCopy (maAnimations); AnimationList::const_iterator iAnimation; for (iAnimation=aCopy.begin(); iAnimation!=aCopy.end(); ++iAnimation) { - bExpired |= (*iAnimation)->Run(); + bExpired |= (*iAnimation)->Run(nTime); } return bExpired; @@ -126,6 +257,10 @@ bool Animator::ServeAnimations (void) void Animator::CleanUpAnimationList (void) { + OSL_ASSERT( ! mbIsDisposed); + if (mbIsDisposed) + return; + AnimationList aActiveAnimations; AnimationList::const_iterator iAnimation; @@ -141,19 +276,35 @@ void Animator::CleanUpAnimationList (void) +void Animator::RequestNextFrame (const double nFrameStart) +{ + (void)nFrameStart; + if ( ! maTimer.IsActive()) + { + // Prevent redraws except for the ones in TimeoutHandler. While the + // Animator is active it will schedule repaints regularly. Repaints + // in between would only lead to visual artifacts. + mpDrawLock.reset(new view::SlideSorterView::DrawLock(mrSlideSorter)); + maTimer.Start(); + } +} + + + + IMPL_LINK(Animator, TimeoutHandler, Timer*, EMPTYARG) { - if (ServeAnimations()) + if (mbIsDisposed) + return 0; + + if (ProcessAnimations(maElapsedTime.getElapsedTime())) CleanUpAnimationList(); // Unlock the draw lock. This should lead to a repaint. mpDrawLock.reset(); if (maAnimations.size() > 0) - { - mpDrawLock.reset(new DrawLock(mrSlideSorter.GetView())); - maTimer.Start(); - } + RequestNextFrame(); return 0; } @@ -164,16 +315,21 @@ IMPL_LINK(Animator, TimeoutHandler, Timer*, EMPTYARG) //===== Animator::Animation =================================================== Animator::Animation::Animation ( - const Animator::AnimationFunction& rAnimation, - const double nDelta) + const Animator::AnimationFunctor& rAnimation, + const double nStartOffset, + const double nDuration, + const double nGlobalTime, + const Animator::AnimationId nId, + const Animator::FinishFunctor& rFinishFunctor) : maAnimation(rAnimation), - mnValue(0), - mnDelta(nDelta) + maFinishFunctor(rFinishFunctor), + mnAnimationId(nId), + mnDuration(nDuration), + mnEnd(nGlobalTime + nDuration + nStartOffset), + mnGlobalTimeAtStart(nGlobalTime + nStartOffset), + mbIsExpired(false) { - - maAnimation(mnValue); - mnValue = mnDelta; - + Run(nGlobalTime); } @@ -186,47 +342,54 @@ Animator::Animation::~Animation (void) -bool Animator::Animation::Run (void) +bool Animator::Animation::Run (const double nGlobalTime) { - if (mnValue < 1.0) + if ( ! mbIsExpired) { - maAnimation(mnValue); - mnValue += mnDelta; - return false; - } - else - { - maAnimation(1.0); - return true; + if (mnDuration > 0) + { + if (nGlobalTime >= mnEnd) + { + maAnimation(1.0); + Expire(); + } + else if (nGlobalTime >= mnGlobalTimeAtStart) + { + maAnimation((nGlobalTime - mnGlobalTimeAtStart) / mnDuration); + } + } + else if (mnDuration < 0) + { + // Animations without end have to be expired by their owner. + maAnimation(nGlobalTime); + } } + + return mbIsExpired; } -bool Animator::Animation::IsExpired (void) +void Animator::Animation::Expire (void) { - return mnValue >= 1.0; + if ( ! mbIsExpired) + { + mbIsExpired = true; + if (maFinishFunctor) + maFinishFunctor(); + } } -//===== Animator::DrawLock ==================================================== - -Animator::DrawLock::DrawLock (View& rView) - : mrView(rView) +bool Animator::Animation::IsExpired (void) { - mrView.LockRedraw(TRUE); + return mbIsExpired; } -Animator::DrawLock::~DrawLock (void) -{ - mrView.LockRedraw(FALSE); -} - - } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsClipboard.cxx b/sd/source/ui/slidesorter/controller/SlsClipboard.cxx index d226a8c2e294..68ae50e091e7 100644..100755 --- a/sd/source/ui/slidesorter/controller/SlsClipboard.cxx +++ b/sd/source/ui/slidesorter/controller/SlsClipboard.cxx @@ -35,16 +35,18 @@ #include "model/SlsPageDescriptor.hxx" #include "model/SlsPageEnumerationProvider.hxx" #include "view/SlideSorterView.hxx" -#include "view/SlsViewOverlay.hxx" -#include "view/SlsPageObject.hxx" +#include "view/SlsTheme.hxx" #include "controller/SlideSorterController.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" #include "controller/SlsPageSelector.hxx" #include "controller/SlsSelectionFunction.hxx" #include "controller/SlsCurrentSlideManager.hxx" #include "controller/SlsScrollBarManager.hxx" #include "controller/SlsFocusManager.hxx" #include "controller/SlsSelectionManager.hxx" -#include "SlsTransferable.hxx" +#include "controller/SlsTransferable.hxx" +#include "controller/SlsSelectionObserver.hxx" +#include "cache/SlsPageCache.hxx" #include "ViewShellBase.hxx" #include "DrawViewShell.hxx" @@ -74,6 +76,7 @@ #include <sfx2/bindings.hxx> #include <sfx2/docfile.hxx> #include <svx/svxids.hrc> +#include <svx/svdstr.hrc> #include <vcl/msgbox.hxx> #include <tools/urlobj.hxx> #include <rtl/ustring.hxx> @@ -82,6 +85,43 @@ namespace sd { namespace slidesorter { namespace controller { +class Clipboard::UndoContext +{ +public: + UndoContext ( + SdDrawDocument* pDocument, + const ::boost::shared_ptr<ViewShell>& rpMainViewShell, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : mpDocument(pDocument), + mpMainViewShell(rpMainViewShell) + { + if (mpDocument!=NULL && mpDocument->IsUndoEnabled()) + { + if (mpMainViewShell && mpMainViewShell->GetShellType() == ViewShell::ST_DRAW) + mpDocument->BegUndo(rpTheme->GetString(view::Theme::String_DragAndDropPages)); + else + mpDocument->BegUndo(rpTheme->GetString(view::Theme::String_DragAndDropSlides)); + } + } + + ~UndoContext (void) + { + if (mpDocument!=NULL && mpDocument->IsUndoEnabled()) + mpDocument->EndUndo(); + if (mpMainViewShell && mpMainViewShell->GetViewFrame()!=NULL) + { + SfxBindings& rBindings = mpMainViewShell->GetViewFrame()->GetBindings(); + rBindings.Invalidate(SID_UNDO); + rBindings.Invalidate(SID_REDO); + } + } +private: + SdDrawDocument* mpDocument; + ::boost::shared_ptr<ViewShell> mpMainViewShell; +}; + + + Clipboard::Clipboard (SlideSorter& rSlideSorter) : ViewClipboard(rSlideSorter.GetView()), @@ -89,7 +129,10 @@ Clipboard::Clipboard (SlideSorter& rSlideSorter) mrController(mrSlideSorter.GetController()), maPagesToRemove(), maPagesToSelect(), - mbUpdateSelectionPending(false) + mbUpdateSelectionPending(false), + mpUndoContext(), + mpSelectionObserverContext(), + mnDragFinishedUserEventId(0) { } @@ -98,6 +141,8 @@ Clipboard::Clipboard (SlideSorter& rSlideSorter) Clipboard::~Clipboard (void) { + if (mnDragFinishedUserEventId != 0) + Application::RemoveUserEvent(mnDragFinishedUserEventId); } @@ -143,13 +188,12 @@ void Clipboard::HandleSlotCall (SfxRequest& rRequest) // a crash. if (mrSlideSorter.GetModel().GetEditMode() != EM_MASTERPAGE) { - mrSlideSorter.GetView().LockRedraw (TRUE); + view::SlideSorterView::DrawLock aLock (mrSlideSorter); + SelectionObserver::Context aContext (mrSlideSorter); if(xFunc.is()) xFunc->DoPaste(); else DoPaste(); - mrController.GetSelectionManager()->MakeSelectionVisible(); - mrSlideSorter.GetView().LockRedraw(FALSE); } rRequest.Done(); break; @@ -209,7 +253,7 @@ void Clipboard::DoPaste (::Window* pWindow) sal_Int32 nInsertPageCount = PasteTransferable(nInsertPosition); // Select the pasted pages and make the first of them the // current page. - mrSlideSorter.GetView().GetWindow()->GrabFocus(); + mrSlideSorter.GetContentWindow()->GrabFocus(); SelectPageRange(nInsertPosition, nInsertPageCount); } } @@ -230,14 +274,22 @@ sal_Int32 Clipboard::GetInsertionPosition (::Window* pWindow) // selection. // d) After the last page when there is no selection and no focus. - view::InsertionIndicatorOverlay& rInsertionIndicatorOverlay ( - mrSlideSorter.GetView().GetOverlay().GetInsertionIndicatorOverlay()); - if (rInsertionIndicatorOverlay.isVisible()) + ::boost::shared_ptr<controller::InsertionIndicatorHandler> pInsertionIndicatorHandler ( + mrController.GetInsertionIndicatorHandler()); + if (pInsertionIndicatorHandler->IsActive()) + { + // Use the insertion index of an active insertion indicator. + nInsertPosition = pInsertionIndicatorHandler->GetInsertionPageIndex(); + } + else if (mrController.GetSelectionManager()->GetInsertionPosition() >= 0) { - nInsertPosition = rInsertionIndicatorOverlay.GetInsertionPageIndex(); + // Use the insertion index of an insertion indicator that has been + // deactivated a short while ago. + nInsertPosition = mrController.GetSelectionManager()->GetInsertionPosition(); } else if (mrController.GetFocusManager().IsFocusShowing()) { + // Use the focus to determine the insertion position. SdInsertPasteDlg aDialog (pWindow); if (aDialog.Execute() == RET_OK) { @@ -246,10 +298,6 @@ sal_Int32 Clipboard::GetInsertionPosition (::Window* pWindow) nInsertPosition ++; } } - else - { - nInsertPosition = mrController.GetSelectionManager()->GetInsertionPosition(); - } return nInsertPosition; } @@ -260,9 +308,9 @@ sal_Int32 Clipboard::GetInsertionPosition (::Window* pWindow) sal_Int32 Clipboard::PasteTransferable (sal_Int32 nInsertPosition) { SdTransferable* pClipTransferable = SD_MOD()->pTransferClip; - bool bMergeMasterPages = !pClipTransferable->HasSourceDoc ( - mrSlideSorter.GetModel().GetDocument()); - USHORT nInsertIndex ((USHORT)(nInsertPosition * 2 + 1)); + model::SlideSorterModel& rModel (mrSlideSorter.GetModel()); + bool bMergeMasterPages = !pClipTransferable->HasSourceDoc (rModel.GetDocument()); + USHORT nInsertIndex (rModel.GetCoreIndex(nInsertPosition)); sal_Int32 nInsertPageCount (0); if (pClipTransferable->HasPageBookmarks()) { @@ -270,7 +318,7 @@ sal_Int32 Clipboard::PasteTransferable (sal_Int32 nInsertPosition) const ::vos::OGuard aGuard (Application::GetSolarMutex()); nInsertPageCount = (USHORT) rBookmarkList.Count(); - mrSlideSorter.GetModel().GetDocument()->InsertBookmarkAsPage( + rModel.GetDocument()->InsertBookmarkAsPage( const_cast<List*>(&rBookmarkList), NULL, FALSE, @@ -293,9 +341,9 @@ sal_Int32 Clipboard::PasteTransferable (sal_Int32 nInsertPosition) { const ::vos::OGuard aGuard (Application::GetSolarMutex()); - bMergeMasterPages = (pDataDoc != mrSlideSorter.GetModel().GetDocument()); + bMergeMasterPages = (pDataDoc != rModel.GetDocument()); nInsertPageCount = pDataDoc->GetSdPageCount( PK_STANDARD ); - mrSlideSorter.GetModel().GetDocument()->InsertBookmarkAsPage( + rModel.GetDocument()->InsertBookmarkAsPage( NULL, NULL, FALSE, @@ -332,7 +380,6 @@ void Clipboard::SelectPageRange (sal_Int32 nFirstIndex, sal_Int32 nPageCount) if (i == 0) { mrController.GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor); - mrController.GetFocusManager().SetFocusedPage(pDescriptor); } } } @@ -361,6 +408,27 @@ void Clipboard::CreateSlideTransferable ( maPagesToRemove.push_back (pDescriptor->GetPage()); } + // Create a small set of representatives of the selection for which + // previews are included into the transferable so that an insertion + // indicator can be rendered. + aSelectedPages.Rewind(); + ::std::vector<Transferable::Representative> aRepresentatives; + aRepresentatives.reserve(3); + ::boost::shared_ptr<cache::PageCache> pPreviewCache ( + mrSlideSorter.GetView().GetPreviewCache()); + while (aSelectedPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + if ( ! pDescriptor || pDescriptor->GetPage()==NULL) + continue; + Bitmap aPreview (pPreviewCache->GetPreviewBitmap(pDescriptor->GetPage(), false)); + aRepresentatives.push_back(Transferable::Representative( + aPreview, + pDescriptor->HasState(model::PageDescriptor::ST_Excluded))); + if (aRepresentatives.size() >= 3) + break; + } + if (aBookmarkList.Count() > 0) { mrSlideSorter.GetView().BrkAction(); @@ -369,7 +437,8 @@ void Clipboard::CreateSlideTransferable ( pDocument, NULL, FALSE, - dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell())); + dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()), + aRepresentatives); if (bDrag) SD_MOD()->pTransferDrag = pTransferable; @@ -423,13 +492,17 @@ void Clipboard::CreateSlideTransferable ( void Clipboard::StartDrag ( - const Point&, + const Point& rPosition, ::Window* pWindow) { maPagesToRemove.clear(); maPagesToSelect.clear(); mbUpdateSelectionPending = false; - CreateSlideTransferable (pWindow, TRUE); + CreateSlideTransferable(pWindow, TRUE); + + mrController.GetInsertionIndicatorHandler()->UpdatePosition( + rPosition, + InsertionIndicatorHandler::UnknownMode); } @@ -437,15 +510,36 @@ void Clipboard::StartDrag ( void Clipboard::DragFinished (sal_Int8 nDropAction) { - // Hide the substitution display and insertion indicator. - mrSlideSorter.GetView().GetOverlay().GetSubstitutionOverlay().setVisible(false); - mrSlideSorter.GetView().GetOverlay().GetInsertionIndicatorOverlay().setVisible(false); - SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; - if (pDragTransferable != NULL) pDragTransferable->SetView (NULL); + if (mnDragFinishedUserEventId == 0) + { + if ( ! Application::PostUserEvent( + mnDragFinishedUserEventId, + LINK(this, Clipboard, ProcessDragFinished), + reinterpret_cast<void*>(nDropAction))) + { + mnDragFinishedUserEventId = 0; + } + } +} + + + + +IMPL_LINK(Clipboard, ProcessDragFinished, void*, pUserData) +{ + const sal_Int8 nDropAction (static_cast<sal_Int8>(reinterpret_cast<sal_IntPtr>(pUserData))); + + mnDragFinishedUserEventId = 0; + + // Hide the substitution display and insertion indicator. + ::rtl::Reference<SelectionFunction> pFunction (mrController.GetCurrentSelectionFunction()); + if (pFunction.is()) + pFunction->NotifyDragFinished(); + PageSelector& rSelector (mrController.GetPageSelector()); if ((nDropAction & DND_ACTION_MOVE) != 0 && ! maPagesToRemove.empty()) @@ -458,12 +552,14 @@ void Clipboard::DragFinished (sal_Int8 nDropAction) aDraggedPage!=maPagesToRemove.end(); aDraggedPage++) { - rSelector.SelectPage (*aDraggedPage); + rSelector.SelectPage(*aDraggedPage); } - mrController.GetSelectionManager()->DeleteSelectedPages (); + mrController.GetSelectionManager()->DeleteSelectedPages(); } + mpUndoContext.reset(); + mpSelectionObserverContext.reset(); - SelectPages(); + return 1; } @@ -492,14 +588,16 @@ sal_Int8 Clipboard::AcceptDrop ( USHORT nPage, USHORT nLayer) { - sal_Int8 nResult = DND_ACTION_NONE; + sal_Int8 nAction (DND_ACTION_NONE); - switch (IsDropAccepted()) + const Clipboard::DropType eDropType (IsDropAccepted()); + + switch (eDropType) { case DT_PAGE: { // Accept a drop. - nResult = rEvent.mnAction; + nAction = rEvent.mnAction; // Use the copy action when the drop action is the default, i.e. not // explicitly set to move or link, and when the source and @@ -512,23 +610,27 @@ sal_Int8 Clipboard::AcceptDrop ( && (mrSlideSorter.GetModel().GetDocument()->GetDocSh() != pDragTransferable->GetPageDocShell())) { - nResult = DND_ACTION_COPY; + nAction = DND_ACTION_COPY; + } + else if (mrController.GetInsertionIndicatorHandler()->IsInsertionTrivial(nAction)) + { + nAction = DND_ACTION_NONE; } // Show the insertion marker and the substitution for a drop. Point aPosition = pTargetWindow->PixelToLogic (rEvent.maPosPixel); - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - rOverlay.GetInsertionIndicatorOverlay().SetPosition (aPosition); - rOverlay.GetInsertionIndicatorOverlay().setVisible(true); - rOverlay.GetSubstitutionOverlay().SetPosition (aPosition); + SelectionFunction* pSelectionFunction = dynamic_cast<SelectionFunction*>( + mrSlideSorter.GetViewShell()->GetCurrentFunction().get()); + if (pSelectionFunction != NULL) + pSelectionFunction->MouseDragged(rEvent, nAction); // Scroll the window when the mouse reaches the window border. - mrController.GetScrollBarManager().AutoScroll (rEvent.maPosPixel); + // mrController.GetScrollBarManager().AutoScroll (rEvent.maPosPixel); } break; case DT_SHAPE: - nResult = ExecuteOrAcceptShapeDrop( + nAction = ExecuteOrAcceptShapeDrop( DC_ACCEPT, rEvent.maPosPixel, &rEvent, @@ -537,11 +639,13 @@ sal_Int8 Clipboard::AcceptDrop ( nPage, nLayer); break; + default: + nAction = DND_ACTION_NONE; break; } - return nResult; + return nAction; } @@ -555,6 +659,7 @@ sal_Int8 Clipboard::ExecuteDrop ( USHORT nLayer) { sal_Int8 nResult = DND_ACTION_NONE; + mpUndoContext.reset(); switch (IsDropAccepted()) { @@ -563,54 +668,57 @@ sal_Int8 Clipboard::ExecuteDrop ( const SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; const Point aEventModelPosition ( pTargetWindow->PixelToLogic (rEvent.maPosPixel)); - long int nXOffset = labs (pDragTransferable->GetStartPos().X() - - aEventModelPosition.X()); - long int nYOffset = labs (pDragTransferable->GetStartPos().Y() - - aEventModelPosition.Y()); - const bool bContinue = + const sal_Int32 nXOffset (labs (pDragTransferable->GetStartPos().X() + - aEventModelPosition.X())); + const sal_Int32 nYOffset (labs (pDragTransferable->GetStartPos().Y() + - aEventModelPosition.Y())); + bool bContinue = ( pDragTransferable->GetView() != &mrSlideSorter.GetView() ) || ( nXOffset >= 2 && nYOffset >= 2 ); + ::boost::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler( + mrController.GetInsertionIndicatorHandler()); // Get insertion position and then turn off the insertion indicator. - view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); - rOverlay.GetInsertionIndicatorOverlay().SetPosition( - aEventModelPosition); - USHORT nIndex = DetermineInsertPosition (*pDragTransferable); - OSL_TRACE ("Clipboard::AcceptDrop() called for index %d", - nIndex); - rOverlay.GetInsertionIndicatorOverlay().setVisible(false); + pInsertionIndicatorHandler->UpdatePosition(aEventModelPosition, rEvent.mnAction); + // USHORT nIndex = DetermineInsertPosition(*pDragTransferable); + + // Do not process the insertion when it is trivial, + // i.e. would insert pages at their original place. + if (pInsertionIndicatorHandler->IsInsertionTrivial(rEvent.mnAction)) + bContinue = false; + + // Tell the insertion indicator handler to hide before the model + // is modified. Doing it later may result in page objects whose + // animation state is not properly reset because they are then + // in another run then before the model change. + pInsertionIndicatorHandler->End(Animator::AM_Immediate); if (bContinue) { SlideSorterController::ModelChangeLock aModelChangeLock (mrController); - if (pDragTransferable->GetView() == &mrSlideSorter.GetView() - && rEvent.mnAction == DND_ACTION_MOVE) - { - // We are asked to move pages inside one view. For this we - // call MoveSelectedPages() which is faster than going the - // generic way. - - // Remember to select the moved pages afterwards. - maPagesToRemove.swap(maPagesToSelect); - maPagesToRemove.clear(); - - USHORT nSdrModelIndex; - if (nIndex != SDRPAGE_NOTFOUND) - nSdrModelIndex = nIndex / 2 - 1; - else - nSdrModelIndex = SDRPAGE_NOTFOUND; - mrController.GetSelectionManager()->MoveSelectedPages(nSdrModelIndex); - mbUpdateSelectionPending = true; - nResult = DND_ACTION_NONE; - } - else - { - // Handle a general drop operation. - HandlePageDrop (*pDragTransferable); - nResult = rEvent.mnAction; - } + // Handle a general drop operation. + mpUndoContext.reset(new UndoContext ( + mrSlideSorter.GetModel().GetDocument(), + mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell(), + mrSlideSorter.GetTheme())); + mpSelectionObserverContext.reset(new SelectionObserver::Context(mrSlideSorter)); + + HandlePageDrop(*pDragTransferable); + nResult = rEvent.mnAction; + + // We leave the undo context alive for when moving or + // copying inside one view then the actions in + // NotifyDragFinished should be covered as well as + // well as the ones above. } + + // Notify the receiving selection function that drag-and-drop is + // finished and the substitution handler can be released. + ::rtl::Reference<SelectionFunction> pFunction ( + mrController.GetCurrentSelectionFunction()); + if (pFunction.is()) + pFunction->NotifyDragFinished(); } break; @@ -634,23 +742,31 @@ sal_Int8 Clipboard::ExecuteDrop ( -USHORT Clipboard::DetermineInsertPosition (const SdTransferable& ) +void Clipboard::Abort (void) { - USHORT nInsertPosition = SDRPAGE_NOTFOUND; + if (mpSelectionObserverContext) + { + mpSelectionObserverContext->Abort(); + mpSelectionObserverContext.reset(); + } +} + + + +USHORT Clipboard::DetermineInsertPosition (const SdTransferable& ) +{ // Tell the model to move the dragged pages behind the one with the // index nInsertionIndex which first has to be transformed into an index // understandable by the document. - view::InsertionIndicatorOverlay& rOverlay ( - mrSlideSorter.GetView().GetOverlay().GetInsertionIndicatorOverlay()); - sal_Int32 nInsertionIndex (rOverlay.GetInsertionPageIndex()); + const sal_Int32 nInsertionIndex ( + mrController.GetInsertionIndicatorHandler()->GetInsertionPageIndex()); - // The index returned by the overlay starts with 1 for the first slide. - // This is now converted that to an SdModel index that also starts with 1. + // Convert to insertion index to that of an SdModel. if (nInsertionIndex >= 0) - nInsertPosition = (USHORT)nInsertionIndex * 2 + 1; - - return nInsertPosition; + return mrSlideSorter.GetModel().GetCoreIndex(nInsertionIndex); + else + return 0; } @@ -666,14 +782,12 @@ USHORT Clipboard::InsertSlides ( // Remember the inserted pages so that they can be selected when the // operation is finished. - int nDocumentIndex = nInsertPosition / 2 - 1; - for (USHORT i=1; i<=nInsertedPageCount; i++) - { - model::SharedPageDescriptor pDescriptor ( - mrSlideSorter.GetModel().GetPageDescriptor(nDocumentIndex + i)); - if (pDescriptor.get() != NULL) - maPagesToSelect.push_back (pDescriptor->GetPage()); - } + maPagesToSelect.clear(); + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + if (pDocument != NULL) + for (sal_Int32 i=0; i<=nInsertedPageCount; i+=2) + maPagesToSelect.push_back( + dynamic_cast<SdPage*>(pDocument->GetPage(nInsertPosition+i))); mbUpdateSelectionPending |= (nInsertedPageCount>0); @@ -739,8 +853,8 @@ sal_Int8 Clipboard::ExecuteOrAcceptShapeDrop ( model::SharedPageDescriptor pDescriptor ( mrSlideSorter.GetModel().GetPageDescriptor( mrSlideSorter.GetView().GetPageIndexAtPoint(rPosition))); - if (pDescriptor.get() != NULL && pDescriptor->GetPage()!=NULL) - nPage = (pDescriptor->GetPage()->GetPageNum() - 1) / 2; + if (pDescriptor) + nPage = pDescriptor->GetPageIndex(); } // Now comes the code that is different for the Execute and Accept: diff --git a/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx b/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx index f5864c3307a1..7b2ca60cb4f0 100755..100644 --- a/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx +++ b/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx @@ -33,8 +33,8 @@ #include "controller/SlsPageSelector.hxx" #include "controller/SlideSorterController.hxx" #include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsFocusManager.hxx" #include "view/SlideSorterView.hxx" -#include "view/SlsPageObjectViewObjectContact.hxx" #include "ViewShellBase.hxx" #include "ViewShell.hxx" #include "DrawViewShell.hxx" @@ -47,13 +47,18 @@ using namespace ::com::sun::star::uno; using namespace ::sd::slidesorter::model; + namespace sd { namespace slidesorter { namespace controller { + CurrentSlideManager::CurrentSlideManager (SlideSorter& rSlideSorter) : mrSlideSorter(rSlideSorter), mnCurrentSlideIndex(-1), - mpCurrentSlide() + mpCurrentSlide(), + maSwitchPageDelayTimer() { + maSwitchPageDelayTimer.SetTimeout(100); + maSwitchPageDelayTimer.SetTimeoutHdl(LINK(this,CurrentSlideManager,SwitchPageCallback)); } @@ -66,7 +71,22 @@ CurrentSlideManager::~CurrentSlideManager (void) -void CurrentSlideManager::CurrentSlideHasChanged (const sal_Int32 nSlideIndex) +void CurrentSlideManager::NotifyCurrentSlideChange (const SdPage* pPage) +{ + if (pPage != NULL) + NotifyCurrentSlideChange( + mrSlideSorter.GetModel().GetIndex( + Reference<drawing::XDrawPage>( + const_cast<SdPage*>(pPage)->getUnoPage(), + UNO_QUERY))); + else + NotifyCurrentSlideChange(-1); +} + + + + +void CurrentSlideManager::NotifyCurrentSlideChange (const sal_Int32 nSlideIndex) { if (mnCurrentSlideIndex != nSlideIndex) { @@ -75,8 +95,11 @@ void CurrentSlideManager::CurrentSlideHasChanged (const sal_Int32 nSlideIndex) // Update the selection. mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); - if (mpCurrentSlide.get() != NULL) + if (mpCurrentSlide) + { mrSlideSorter.GetController().GetPageSelector().SelectPage(mpCurrentSlide); + mrSlideSorter.GetController().GetFocusManager().SetFocusedPage(mpCurrentSlide); + } } } @@ -86,10 +109,7 @@ void CurrentSlideManager::CurrentSlideHasChanged (const sal_Int32 nSlideIndex) void CurrentSlideManager::ReleaseCurrentSlide (void) { if (mpCurrentSlide.get() != NULL) - { - mpCurrentSlide->SetIsCurrentPage(false); - mrSlideSorter.GetView().RequestRepaint(mpCurrentSlide); - } + mrSlideSorter.GetView().SetState(mpCurrentSlide, PageDescriptor::ST_Current, false); mpCurrentSlide.reset(); mnCurrentSlideIndex = -1; @@ -117,48 +137,64 @@ void CurrentSlideManager::AcquireCurrentSlide (const sal_Int32 nSlideIndex) // document. mpCurrentSlide = mrSlideSorter.GetModel().GetPageDescriptor(mnCurrentSlideIndex); if (mpCurrentSlide.get() != NULL) - { - mpCurrentSlide->SetIsCurrentPage(true); - mrSlideSorter.GetView().RequestRepaint(mpCurrentSlide); - } + mrSlideSorter.GetView().SetState(mpCurrentSlide, PageDescriptor::ST_Current, true); } } -void CurrentSlideManager::SwitchCurrentSlide (const sal_Int32 nSlideIndex) +void CurrentSlideManager::SwitchCurrentSlide ( + const sal_Int32 nSlideIndex, + const bool bUpdateSelection) { - SwitchCurrentSlide(mrSlideSorter.GetModel().GetPageDescriptor(nSlideIndex)); + SwitchCurrentSlide(mrSlideSorter.GetModel().GetPageDescriptor(nSlideIndex), bUpdateSelection); } -void CurrentSlideManager::SwitchCurrentSlide (const SharedPageDescriptor& rpDescriptor) +void CurrentSlideManager::SwitchCurrentSlide ( + const SharedPageDescriptor& rpDescriptor, + const bool bUpdateSelection) { - if (rpDescriptor.get() != NULL) + if (rpDescriptor.get() != NULL && mpCurrentSlide!=rpDescriptor) { - mpCurrentSlide = rpDescriptor; - mnCurrentSlideIndex = (rpDescriptor->GetPage()->GetPageNum()-1)/2; + ReleaseCurrentSlide(); + AcquireCurrentSlide((rpDescriptor->GetPage()->GetPageNum()-1)/2); ViewShell* pViewShell = mrSlideSorter.GetViewShell(); if (pViewShell != NULL && pViewShell->IsMainViewShell()) { + // The slide sorter is the main view. FrameView* pFrameView = pViewShell->GetFrameView(); if (pFrameView != NULL) pFrameView->SetSelectedPage(sal::static_int_cast<USHORT>(mnCurrentSlideIndex)); + mrSlideSorter.GetController().GetPageSelector().SetCoreSelection(); } - else + + // We do not tell the XController/ViewShellBase about the new + // slide right away. This is done asynchronously after a short + // delay to allow for more slide switches in the slide sorter. + // This goes under the assumption that slide switching inside + // the slide sorter is fast (no expensive redraw of the new page + // (unless the preview of the new slide is not yet preset)) and + // that slide switching in the edit view is slow (all shapes of + // the new slide have to be repainted.) + maSwitchPageDelayTimer.Start(); + + // We have to store the (index of the) new current slide at + // the tab control because there are other asynchronous + // notifications of the slide switching that otherwise + // overwrite the correct value. + SetCurrentSlideAtTabControl(mpCurrentSlide); + + if (bUpdateSelection) { - // Set current page. At the moment we have to do this in two - // different ways. The UNO way is the preferable one but, alas, - // it does not work always correctly (after some kinds of model - // changes). Therefore, we call DrawViewShell::SwitchPage(), - // too. - SetCurrentSlideAtViewShellBase(rpDescriptor); - SetCurrentSlideAtXController(rpDescriptor); + mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); + mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor); } + mrSlideSorter.GetController().GetFocusManager().SetFocusedPage(rpDescriptor); } } @@ -180,19 +216,26 @@ void CurrentSlideManager::SetCurrentSlideAtViewShellBase (const SharedPageDescri pDrawViewShell->SwitchPage(nPageNumber); pDrawViewShell->GetPageTabControl()->SetCurPageId(nPageNumber+1); } - /* - else + } +} + + + + +void CurrentSlideManager::SetCurrentSlideAtTabControl (const SharedPageDescriptor& rpDescriptor) +{ + OSL_ASSERT(rpDescriptor.get() != NULL); + + ViewShellBase* pBase = mrSlideSorter.GetViewShellBase(); + if (pBase != NULL) + { + ::boost::shared_ptr<DrawViewShell> pDrawViewShell ( + ::boost::dynamic_pointer_cast<DrawViewShell>(pBase->GetMainViewShell())); + if (pDrawViewShell) { - presenter::PresenterViewShell* pPresenterViewShell - = dynamic_cast<presenter::PresenterViewShell*>(pBase->GetMainViewShell()); - if (pPresenterViewShell != NULL) - { - pPresenterViewShell->SetCurrentSlide( - Reference<drawing::XDrawPage>( - rpDescriptor->GetPage()->getUnoPage(), UNO_QUERY)); - } + USHORT nPageNumber = (rpDescriptor->GetPage()->GetPageNum()-1)/2; + pDrawViewShell->GetPageTabControl()->SetCurPageId(nPageNumber+1); } - */ } } @@ -215,7 +258,7 @@ void CurrentSlideManager::SetCurrentSlideAtXController (const SharedPageDescript aPage); } } - catch (beans::UnknownPropertyException aException) + catch (Exception aException) { // We have not been able to set the current page at the main view. // This is sad but still leaves us in a valid state. Therefore, @@ -246,11 +289,31 @@ void CurrentSlideManager::HandleModelChange (void) { if (mnCurrentSlideIndex >= 0) { - mpCurrentSlide = mrSlideSorter.GetModel().GetPageDescriptor( - mnCurrentSlideIndex); + mpCurrentSlide = mrSlideSorter.GetModel().GetPageDescriptor(mnCurrentSlideIndex); if (mpCurrentSlide.get() != NULL) - mpCurrentSlide->SetIsCurrentPage(true); + mrSlideSorter.GetView().SetState(mpCurrentSlide, PageDescriptor::ST_Current, true); } } + + + +IMPL_LINK(CurrentSlideManager, SwitchPageCallback, void*, EMPTYARG) +{ + if (mpCurrentSlide) + { + // Set current page. At the moment we have to do this in two + // different ways. The UNO way is the preferable one but, alas, + // it does not work always correctly (after some kinds of model + // changes). Therefore, we call DrawViewShell::SwitchPage(), + // too. + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell==NULL || ! pViewShell->IsMainViewShell()) + SetCurrentSlideAtViewShellBase(mpCurrentSlide); + SetCurrentSlideAtXController(mpCurrentSlide); + } + + return 1; +} + } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.cxx b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.cxx new file mode 100644 index 000000000000..88b294f3202f --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.cxx @@ -0,0 +1,199 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlsDragAndDropContext.hxx" + +#include "SlideSorter.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "view/SlideSorterView.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" +#include "controller/SlsScrollBarManager.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsSelectionFunction.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsTransferable.hxx" +#include "DrawDocShell.hxx" +#include "drawdoc.hxx" +#include "app.hrc" +#include <sfx2/bindings.hxx> +#include <boost/bind.hpp> + +namespace sd { namespace slidesorter { namespace controller { + +DragAndDropContext::DragAndDropContext (SlideSorter& rSlideSorter) + : mpTargetSlideSorter(&rSlideSorter), + mnInsertionIndex(-1) +{ + ::std::vector<const SdPage*> aPages; + + // No Drag-and-Drop for master pages. + if (rSlideSorter.GetModel().GetEditMode() != EM_PAGE) + return; + + rSlideSorter.GetController().GetInsertionIndicatorHandler()->UpdateIndicatorIcon( + dynamic_cast<Transferable*>(SD_MOD()->pTransferDrag)); +} + + + + +DragAndDropContext::~DragAndDropContext (void) +{ + SetTargetSlideSorter (NULL, Point(0,0), InsertionIndicatorHandler::UnknownMode, false); +} + + + + +void DragAndDropContext::GetPagesFromBookmarks ( + ::std::vector<const SdPage*>& rPages, + sal_Int32& rnSelectionCount, + DrawDocShell* pDocShell, + const List& rBookmarks) const +{ + if (pDocShell == NULL) + return; + + const SdDrawDocument* pDocument = pDocShell->GetDoc(); + if (pDocument == NULL) + return; + + for (ULONG nIndex=0,nCount=rBookmarks.Count(); nIndex<nCount; ++nIndex) + { + const String sPageName (*static_cast<String*>(rBookmarks.GetObject(nIndex))); + BOOL bIsMasterPage (FALSE); + const USHORT nPageIndex (pDocument->GetPageByName(sPageName, bIsMasterPage)); + if (nPageIndex == SDRPAGE_NOTFOUND) + continue; + + const SdPage* pPage = dynamic_cast<const SdPage*>(pDocument->GetPage(nPageIndex)); + if (pPage != NULL) + rPages.push_back(pPage); + } + rnSelectionCount = rBookmarks.Count(); +} + + + + +void DragAndDropContext::GetPagesFromSelection ( + ::std::vector<const SdPage*>& rPages, + sal_Int32& rnSelectionCount, + model::PageEnumeration& rSelection) const +{ + // Show a new substitution for the selected page objects. + rnSelectionCount = 0; + + while (rSelection.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (rSelection.GetNextElement()); + if (rPages.size() < 3) + rPages.push_back(pDescriptor->GetPage()); + ++rnSelectionCount; + } +} + + + + +void DragAndDropContext::Dispose (void) +{ + mnInsertionIndex = -1; +} + + + + +void DragAndDropContext::UpdatePosition ( + const Point& rMousePosition, + const InsertionIndicatorHandler::Mode eMode, + const bool bAllowAutoScroll) +{ + if (mpTargetSlideSorter == NULL) + return; + + if (mpTargetSlideSorter->GetProperties()->IsUIReadOnly()) + return; + + // Convert window coordinates into model coordinates (we need the + // window coordinates for auto-scrolling because that remains + // constant while scrolling.) + SharedSdWindow pWindow (mpTargetSlideSorter->GetContentWindow()); + const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition)); + ::boost::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler ( + mpTargetSlideSorter->GetController().GetInsertionIndicatorHandler()); + + if ( ! (bAllowAutoScroll + && mpTargetSlideSorter->GetController().GetScrollBarManager().AutoScroll( + rMousePosition, + ::boost::bind( + &DragAndDropContext::UpdatePosition, this, rMousePosition, eMode, false)))) + { + pInsertionIndicatorHandler->UpdatePosition(aMouseModelPosition, eMode); + + // Remember the new insertion index. + mnInsertionIndex = pInsertionIndicatorHandler->GetInsertionPageIndex(); + if (pInsertionIndicatorHandler->IsInsertionTrivial(mnInsertionIndex, eMode)) + mnInsertionIndex = -1; + } +} + + + + +void DragAndDropContext::SetTargetSlideSorter ( + SlideSorter* pSlideSorter, + const Point aMousePosition, + const InsertionIndicatorHandler::Mode eMode, + const bool bIsOverSourceView) +{ + if (mpTargetSlideSorter != NULL) + { + mpTargetSlideSorter->GetController().GetScrollBarManager().StopAutoScroll(); + mpTargetSlideSorter->GetController().GetInsertionIndicatorHandler()->End( + Animator::AM_Animated); + } + + mpTargetSlideSorter = pSlideSorter; + + if (mpTargetSlideSorter != NULL) + { + mpTargetSlideSorter->GetController().GetInsertionIndicatorHandler()->Start( + bIsOverSourceView); + mpTargetSlideSorter->GetController().GetInsertionIndicatorHandler()->UpdatePosition( + aMousePosition, + eMode); + + } +} + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.hxx b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.hxx new file mode 100644 index 000000000000..7536f88d9474 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.hxx @@ -0,0 +1,100 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_SUBSTITUTION_HANDLER_HXX +#define SD_SLIDESORTER_SUBSTITUTION_HANDLER_HXX + +#include <tools/gen.hxx> + +#include "model/SlsSharedPageDescriptor.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" +#include <vector> + + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + + + +namespace sd { namespace slidesorter { namespace controller { + +/** A DragAndDropContext object handles an active drag and drop operation. + When the mouse is moved from one slide sorter window to another the + target SlideSorter object is exchanged accordingly. +*/ +class DragAndDropContext +{ +public: + /** Create a substitution display of the currently selected pages or, + when provided, the pages in the transferable. + */ + DragAndDropContext (SlideSorter& rSlideSorter); + ~DragAndDropContext (void); + + /** Call this method (for example as reaction to ESC key press) to avoid + processing (ie moving or inserting) the substition when the called + DragAndDropContext object is destroyed. + */ + void Dispose (void); + + /** Move the substitution display by the distance the mouse has + travelled since the last call to this method or to + CreateSubstitution(). The given point becomes the new anchor. + */ + void UpdatePosition ( + const Point& rMousePosition, + const InsertionIndicatorHandler::Mode eMode, + const bool bAllowAutoScroll = true); + + void SetTargetSlideSorter ( + SlideSorter* pSlideSorter = NULL, + const Point aMousePosition = Point(0,0), + const InsertionIndicatorHandler::Mode eMode = InsertionIndicatorHandler::UnknownMode, + const bool bIsOverSourceView = false); + +private: + SlideSorter* mpTargetSlideSorter; + model::SharedPageDescriptor mpHitDescriptor; + sal_Int32 mnInsertionIndex; + + void GetPagesFromBookmarks ( + ::std::vector<const SdPage*>& rPages, + sal_Int32& rnSelectionCount, + DrawDocShell* pDocShell, + const List& rBookmarks) const; + void GetPagesFromSelection ( + ::std::vector<const SdPage*>& rPages, + sal_Int32& rnSelectionCount, + model::PageEnumeration& rSelection) const; +}; + + + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx b/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx index dcda73d38dba..445354cd9830 100755 --- a/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx +++ b/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx @@ -31,7 +31,8 @@ #include "SlideSorter.hxx" #include "PaneDockingWindow.hxx" #include "controller/SlideSorterController.hxx" -#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsVisibleAreaManager.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageDescriptor.hxx" #include "view/SlideSorterView.hxx" @@ -41,12 +42,15 @@ #include "Window.hxx" #include "sdpage.hxx" +#define UNIFY_FOCUS_AND_CURRENT_PAGE + namespace sd { namespace slidesorter { namespace controller { FocusManager::FocusManager (SlideSorter& rSlideSorter) : mrSlideSorter(rSlideSorter), mnPageIndex(0), - mbPageIsFocused(false) + mbPageIsFocused(false), + mbIsVerticalWrapActive(false) { if (mrSlideSorter.GetModel().GetPageCount() > 0) mnPageIndex = 0; @@ -68,69 +72,101 @@ void FocusManager::MoveFocus (FocusMoveDirection eDirection) { HideFocusIndicator (GetFocusedPageDescriptor()); - int nColumnCount (mrSlideSorter.GetView().GetLayouter().GetColumnCount()); + const sal_Int32 nColumnCount (mrSlideSorter.GetView().GetLayouter().GetColumnCount()); + const sal_Int32 nPageCount (mrSlideSorter.GetModel().GetPageCount()); switch (eDirection) { case FMD_NONE: - if (mnPageIndex >= mrSlideSorter.GetModel().GetPageCount()) - mnPageIndex = mrSlideSorter.GetModel().GetPageCount() - 1; + // Nothing to be done. break; case FMD_LEFT: - mnPageIndex -= 1; - if (mnPageIndex < 0) - { - mnPageIndex = mrSlideSorter.GetModel().GetPageCount() - 1; - SetFocusToToolBox(); - } + if (mnPageIndex > 0) + mnPageIndex -= 1; + else if (mbIsVerticalWrapActive) + mnPageIndex = nPageCount-1; break; case FMD_RIGHT: - mnPageIndex += 1; - if (mnPageIndex >= mrSlideSorter.GetModel().GetPageCount()) - { + if (mnPageIndex < nPageCount-1) + mnPageIndex += 1; + else if (mbIsVerticalWrapActive) mnPageIndex = 0; - SetFocusToToolBox(); - } break; case FMD_UP: { - int nColumn = mnPageIndex % nColumnCount; - mnPageIndex -= nColumnCount; - if (mnPageIndex < 0) + const sal_Int32 nCandidate (mnPageIndex - nColumnCount); + if (nCandidate < 0) { - // Wrap arround to the bottom row or the one above and - // go to the correct column. - int nCandidate = mrSlideSorter.GetModel().GetPageCount()-1; - int nCandidateColumn = nCandidate % nColumnCount; - if (nCandidateColumn > nColumn) - mnPageIndex = nCandidate - (nCandidateColumn-nColumn); - else if (nCandidateColumn < nColumn) - mnPageIndex = nCandidate - - nColumnCount - + (nColumn - nCandidateColumn); - else - mnPageIndex = nCandidate; + if (mbIsVerticalWrapActive) + { + // Wrap arround to the bottom row or the one above + // and go to the correct column. + const sal_Int32 nLastIndex (nPageCount-1); + const sal_Int32 nLastColumn (nLastIndex % nColumnCount); + const sal_Int32 nCurrentColumn (mnPageIndex%nColumnCount); + if (nLastColumn >= nCurrentColumn) + { + // The last row contains the current column. + mnPageIndex = nLastIndex - (nLastColumn-nCurrentColumn); + } + else + { + // Only the second to last row contains the current column. + mnPageIndex = nLastIndex - nLastColumn + - nColumnCount + + nCurrentColumn; + } + } + } + else + { + // Move the focus the previous row. + mnPageIndex = nCandidate; } } break; case FMD_DOWN: { - int nColumn = mnPageIndex % nColumnCount; - mnPageIndex += nColumnCount; - if (mnPageIndex >= mrSlideSorter.GetModel().GetPageCount()) + const sal_Int32 nCandidate (mnPageIndex + nColumnCount); + if (nCandidate >= nPageCount) + { + if (mbIsVerticalWrapActive) + { + // Wrap arround to the correct column. + mnPageIndex = mnPageIndex % nColumnCount; + } + else + { + // Do not move the focus. + } + } + else { - // Wrap arround to the correct column. - mnPageIndex = nColumn; + // Move the focus to the next row. + mnPageIndex = nCandidate; } } break; } + if (mnPageIndex < 0) + { + OSL_ASSERT(mnPageIndex>=0); + mnPageIndex = 0; + } + else if (mnPageIndex >= nPageCount) + { + OSL_ASSERT(mnPageIndex<nPageCount); + mnPageIndex = nPageCount - 1; + } + if (mbPageIsFocused) + { ShowFocusIndicator(GetFocusedPageDescriptor(), true); + } } } @@ -172,7 +208,7 @@ bool FocusManager::ToggleFocus (void) bool FocusManager::HasFocus (void) const { - return mrSlideSorter.GetView().GetWindow()->HasFocus(); + return mrSlideSorter.GetContentWindow()->HasFocus(); } @@ -193,7 +229,7 @@ sal_Int32 FocusManager::GetFocusedPageIndex (void) const - +/* void FocusManager::FocusPage (sal_Int32 nPageIndex) { if (nPageIndex != mnPageIndex) @@ -206,7 +242,7 @@ void FocusManager::FocusPage (sal_Int32 nPageIndex) if (HasFocus() && !IsFocusShowing()) ShowFocus(); } - +*/ @@ -231,6 +267,14 @@ void FocusManager::SetFocusedPage (sal_Int32 nPageIndex) +void FocusManager::SetFocusedPageToCurrentPage (void) +{ + SetFocusedPage(mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide()); +} + + + + bool FocusManager::IsFocusShowing (void) const { return HasFocus() && mbPageIsFocused; @@ -243,8 +287,7 @@ void FocusManager::HideFocusIndicator (const model::SharedPageDescriptor& rpDesc { if (rpDescriptor.get() != NULL) { - rpDescriptor->RemoveFocus(); - mrSlideSorter.GetView().RequestRepaint(rpDescriptor); + mrSlideSorter.GetView().SetState(rpDescriptor, model::PageDescriptor::ST_Focused, false); } } @@ -257,21 +300,16 @@ void FocusManager::ShowFocusIndicator ( { if (rpDescriptor.get() != NULL) { - rpDescriptor->SetFocus (); + mrSlideSorter.GetView().SetState(rpDescriptor, model::PageDescriptor::ST_Focused, true); if (bScrollToFocus) { // Scroll the focused page object into the visible area and repaint // it, so that the focus indicator becomes visible. - view::SlideSorterView& rView (mrSlideSorter.GetView()); - mrSlideSorter.GetController().GetSelectionManager()->MakeRectangleVisible ( - rView.GetPageBoundingBox ( - GetFocusedPageDescriptor(), - view::SlideSorterView::CS_MODEL, - view::SlideSorterView::BBT_INFO)); + mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor,true); } + mrSlideSorter.GetView().RequestRepaint(rpDescriptor); - mrSlideSorter.GetView().RequestRepaint (rpDescriptor); NotifyFocusChangeListeners(); } } diff --git a/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.cxx b/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.cxx index 666d4b017302..dbb65b0f657a 100644..100755 --- a/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.cxx +++ b/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.cxx @@ -109,8 +109,10 @@ void HideSlideFunction::DoExecute (SfxRequest& rRequest) while (aSelectedPages.HasMoreElements()) { model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); - pDescriptor->GetPage()->SetExcluded (eState==EXCLUDED); - static_cast<view::SlideSorterView*>(mpView)->RequestRepaint(pDescriptor); + static_cast<view::SlideSorterView*>(mpView)->SetState( + pDescriptor, + model::PageDescriptor::ST_Excluded, + eState==EXCLUDED); } } diff --git a/sd/source/ui/slidesorter/controller/SlsInsertionIndicatorHandler.cxx b/sd/source/ui/slidesorter/controller/SlsInsertionIndicatorHandler.cxx new file mode 100644 index 000000000000..882adab932a8 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsInsertionIndicatorHandler.cxx @@ -0,0 +1,327 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "controller/SlsInsertionIndicatorHandler.hxx" +#include "controller/SlsProperties.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsInsertionIndicatorOverlay.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> + +#include "SlideSorter.hxx" + +using namespace ::com::sun::star::datatransfer::dnd::DNDConstants; + +namespace sd { namespace slidesorter { namespace controller { + + +InsertionIndicatorHandler::InsertionIndicatorHandler (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mpInsertAnimator(), + mpInsertionIndicatorOverlay(new view::InsertionIndicatorOverlay(rSlideSorter)), + maInsertPosition(), + meMode(MoveMode), + mbIsActive(false), + mbIsReadOnly(mrSlideSorter.GetModel().IsReadOnly()), + mbIsOverSourceView(true), + maIconSize(0,0), + mbIsForcedShow(false) +{ +} + + + + +InsertionIndicatorHandler::~InsertionIndicatorHandler (void) +{ +} + + + + +void InsertionIndicatorHandler::Start (const bool bIsOverSourceView) +{ + if (mbIsActive) + { + OSL_ASSERT(!mbIsActive); + } + + mbIsReadOnly = mrSlideSorter.GetModel().IsReadOnly(); + if (mbIsReadOnly) + return; + + mbIsActive = true; + mbIsOverSourceView = bIsOverSourceView; +} + + + + +void InsertionIndicatorHandler::End (const controller::Animator::AnimationMode eMode) +{ + if (mbIsForcedShow || ! mbIsActive || mbIsReadOnly) + return; + + GetInsertAnimator()->Reset(eMode); + + mbIsActive = false; + // maInsertPosition = view::InsertPosition(); + meMode = UnknownMode; + + mpInsertionIndicatorOverlay->Hide(); + mpInsertionIndicatorOverlay.reset(new view::InsertionIndicatorOverlay(mrSlideSorter)); +} + + + + +void InsertionIndicatorHandler::ForceShow (void) +{ + mbIsForcedShow = true; +} + + + + +void InsertionIndicatorHandler::ForceEnd (void) +{ + mbIsForcedShow = false; + End(Animator::AM_Immediate); +} + + + + +void InsertionIndicatorHandler::UpdateIndicatorIcon (const Transferable* pTransferable) +{ + mpInsertionIndicatorOverlay->Create(pTransferable); + maIconSize = mpInsertionIndicatorOverlay->GetSize(); +} + + + + +InsertionIndicatorHandler::Mode InsertionIndicatorHandler::GetModeFromDndAction ( + const sal_Int8 nDndAction) +{ + if ((nDndAction & ACTION_MOVE) != 0) + return MoveMode; + else if ((nDndAction & ACTION_COPY) != 0) + return CopyMode; + else + return UnknownMode; +} + + + + +void InsertionIndicatorHandler::UpdatePosition ( + const Point& rMouseModelPosition, + const Mode eMode) +{ + if ( ! mbIsActive) + return; + + if (mbIsReadOnly) + return; + + SetPosition(rMouseModelPosition, eMode); +} + + + + +void InsertionIndicatorHandler::UpdatePosition ( + const Point& rMouseModelPosition, + const sal_Int8 nDndAction) +{ + UpdatePosition(rMouseModelPosition, GetModeFromDndAction(nDndAction)); +} + + + + +bool InsertionIndicatorHandler::IsActive (void) const +{ + return mbIsActive; +} + + + + +sal_Int32 InsertionIndicatorHandler::GetInsertionPageIndex (void) const +{ + if (mbIsReadOnly) + return -1; + else + return maInsertPosition.GetIndex(); +} + + + + +void InsertionIndicatorHandler::SetPosition ( + const Point& rPoint, + const Mode eMode) +{ + view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter()); + + const view::InsertPosition aInsertPosition (rLayouter.GetInsertPosition( + rPoint, + maIconSize, + mrSlideSorter.GetModel())); + + static sal_Int32 TargetIndex (1); + if (aInsertPosition.GetIndex() == TargetIndex) + { + const view::InsertPosition aPosition (rLayouter.GetInsertPosition( + rPoint, + maIconSize, + mrSlideSorter.GetModel())); + const view::InsertPosition aPosition2 (rLayouter.GetInsertPosition( + rPoint, + maIconSize, + mrSlideSorter.GetModel())); + } + + if (maInsertPosition != aInsertPosition + || meMode != eMode + // || ! mpInsertionIndicatorOverlay->IsVisible() + ) + { + maInsertPosition = aInsertPosition; + meMode = eMode; + mbIsInsertionTrivial = IsInsertionTrivial(maInsertPosition.GetIndex(), eMode); + if (maInsertPosition.GetIndex()>=0 && ! mbIsInsertionTrivial) + { + mpInsertionIndicatorOverlay->SetLocation(maInsertPosition.GetLocation()); + + GetInsertAnimator()->SetInsertPosition(maInsertPosition); + mpInsertionIndicatorOverlay->Show(); + } + else + { + GetInsertAnimator()->Reset(Animator::AM_Animated); + mpInsertionIndicatorOverlay->Hide(); + } + } +} + + + + +::boost::shared_ptr<view::InsertAnimator> InsertionIndicatorHandler::GetInsertAnimator (void) +{ + if ( ! mpInsertAnimator) + mpInsertAnimator.reset(new view::InsertAnimator(mrSlideSorter)); + return mpInsertAnimator; +} + + + + +bool InsertionIndicatorHandler::IsInsertionTrivial ( + const sal_Int32 nInsertionIndex, + const Mode eMode) const +{ + if (eMode == CopyMode) + return false; + else if (eMode == UnknownMode) + return true; + + if ( ! mbIsOverSourceView) + return false; + + // 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()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + + // Get the page number and compare it to the last one. + const sal_Int32 nPageNumber (pDescriptor->GetPageIndex()); + if (nCurrentIndex>=0 && nPageNumber>(nCurrentIndex+1)) + return false; + else + nCurrentIndex = nPageNumber; + + // Remember indices of the first and last page of the selection. + if (nFirstIndex == -1) + nFirstIndex = nPageNumber; + nLastIndex = nPageNumber; + } + + // When we come here then the selection has no holes. 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. + if (nInsertionIndex<nFirstIndex || nInsertionIndex>(nLastIndex+1)) + return false; + + return true; +} + + + + +bool InsertionIndicatorHandler::IsInsertionTrivial (const sal_Int8 nDndAction) +{ + return IsInsertionTrivial(GetInsertionPageIndex(), GetModeFromDndAction(nDndAction)); +} + + + + +//===== InsertionIndicatorHandler::ForceShowContext =========================== + +InsertionIndicatorHandler::ForceShowContext::ForceShowContext ( + const ::boost::shared_ptr<InsertionIndicatorHandler>& rpHandler) + : mpHandler(rpHandler) +{ + mpHandler->ForceShow(); +} + + + + +InsertionIndicatorHandler::ForceShowContext::~ForceShowContext (void) +{ + mpHandler->ForceEnd(); +} + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsListener.cxx b/sd/source/ui/slidesorter/controller/SlsListener.cxx index 94b3b4afe717..9f1218013e16 100755 --- a/sd/source/ui/slidesorter/controller/SlsListener.cxx +++ b/sd/source/ui/slidesorter/controller/SlsListener.cxx @@ -25,8 +25,8 @@ * ************************************************************************/ -// MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sd.hxx" + #include "SlsListener.hxx" #include "SlideSorter.hxx" @@ -35,9 +35,15 @@ #include "controller/SlideSorterController.hxx" #include "controller/SlsPageSelector.hxx" #include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsSelectionObserver.hxx" #include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" #include "view/SlideSorterView.hxx" +#include "cache/SlsPageCache.hxx" +#include "cache/SlsPageCacheManager.hxx" #include "drawdoc.hxx" +#include "DrawDocShell.hxx" #include "glob.hrc" #include "ViewShellBase.hxx" @@ -75,7 +81,8 @@ Listener::Listener ( mxFrameWeak(), mpModelChangeLock() { - StartListening (*mrSlideSorter.GetModel().GetDocument()); + StartListening(*mrSlideSorter.GetModel().GetDocument()); + StartListening(*mrSlideSorter.GetModel().GetDocument()->GetDocSh()); mbListeningToDocument = true; // Connect to the UNO document. @@ -127,7 +134,7 @@ Listener::Listener ( if (pMainViewShell != NULL && pMainViewShell!=pViewShell) { - StartListening (*pMainViewShell); + StartListening(*pMainViewShell); } Link aLink (LINK(this, Listener, EventMultiplexerCallback)); @@ -157,7 +164,8 @@ void Listener::ReleaseListeners (void) { if (mbListeningToDocument) { - EndListening (*mrSlideSorter.GetModel().GetDocument()); + EndListening(*mrSlideSorter.GetModel().GetDocument()->GetDocSh()); + EndListening(*mrSlideSorter.GetModel().GetDocument()); mbListeningToDocument = false; } @@ -303,18 +311,15 @@ void Listener::Notify ( if (rHint.ISA(SdrHint)) { SdrHint& rSdrHint (*PTR_CAST(SdrHint,&rHint)); - if(rSdrHint.GetKind() == HINT_PAGEORDERCHG ) + switch (rSdrHint.GetKind()) { - if (rBroadcaster.ISA(SdDrawDocument)) - { - SdDrawDocument& rDocument ( - static_cast<SdDrawDocument&>(rBroadcaster)); - if (rDocument.GetMasterSdPageCount(PK_STANDARD) - == rDocument.GetMasterSdPageCount(PK_NOTES)) - { - mrController.HandleModelChange(); - } - } + case HINT_PAGEORDERCHG: + if (&rBroadcaster == mrSlideSorter.GetModel().GetDocument()) + HandleModelChange(rSdrHint.GetPage()); + break; + + default: + break; } } else if (rHint.ISA(ViewShellHint)) @@ -351,6 +356,16 @@ void Listener::Notify ( break; } } + else if (rHint.ISA(SfxSimpleHint)) + { + SfxSimpleHint& rSfxSimpleHint (*PTR_CAST(SfxSimpleHint,&rHint)); + switch (rSfxSimpleHint.GetId()) + { + case SFX_HINT_DOCCHANGED: + mrController.CheckForMasterPageAssignment(); + break; + } + } } @@ -392,7 +407,7 @@ IMPL_LINK(Listener, EventMultiplexerCallback, ::sd::tools::EventMultiplexerEvent case tools::EventMultiplexerEvent::EID_CONTROLLER_ATTACHED: { ConnectToController(); - mrController.GetPageSelector().UpdateAllPages(); + // mrController.GetPageSelector().GetCoreSelection(); UpdateEditMode(); } break; @@ -402,6 +417,12 @@ IMPL_LINK(Listener, EventMultiplexerCallback, ::sd::tools::EventMultiplexerEvent DisconnectFromController(); break; + case tools::EventMultiplexerEvent::EID_SHAPE_CHANGED: + case tools::EventMultiplexerEvent::EID_SHAPE_INSERTED: + case tools::EventMultiplexerEvent::EID_SHAPE_REMOVED: + HandleShapeModification(static_cast<const SdrPage*>(pEvent->mpUserData)); + break; + default: break; } @@ -463,7 +484,7 @@ void SAL_CALL Listener::propertyChange ( static const ::rtl::OUString sEditModePropertyName ( RTL_CONSTASCII_USTRINGPARAM("IsMasterPageMode")); - if (rEvent.PropertyName.equals (sCurrentPagePropertyName)) + if (rEvent.PropertyName.equals(sCurrentPagePropertyName)) { Any aCurrentPage = rEvent.NewValue; Reference<beans::XPropertySet> xPageSet (aCurrentPage, UNO_QUERY); @@ -475,13 +496,13 @@ void SAL_CALL Listener::propertyChange ( String(RTL_CONSTASCII_USTRINGPARAM("Number"))); sal_Int32 nCurrentPage = 0; aPageNumber >>= nCurrentPage; - mrController.GetPageSelector().UpdateAllPages (); + mrController.GetPageSelector().GetCoreSelection(); // The selection is already set but we call SelectPage() // nevertheless in order to make the new current page the // last recently selected page of the PageSelector. This is // used when making the selection visible. mrController.GetPageSelector().SelectPage(nCurrentPage-1); - mrController.GetCurrentSlideManager()->CurrentSlideHasChanged(nCurrentPage-1); + mrController.GetCurrentSlideManager()->NotifyCurrentSlideChange(nCurrentPage-1); } catch (beans::UnknownPropertyException aEvent) { @@ -520,7 +541,7 @@ void SAL_CALL Listener::frameAction (const frame::FrameActionEvent& rEvent) case frame::FrameAction_COMPONENT_REATTACHED: { ConnectToController(); - mrController.GetPageSelector().UpdateAllPages(); + mrController.GetPageSelector().GetCoreSelection(); UpdateEditMode(); } break; @@ -580,6 +601,84 @@ void Listener::UpdateEditMode (void) +void Listener::HandleModelChange (const SdrPage* pPage) +{ + // Notify model and selection observer about the page. The return value + // of the model call acts as filter as to which events to pass to the + // selection observer. + if (mrSlideSorter.GetModel().NotifyPageEvent(pPage)) + { + // The page of the hint belongs (or belonged) to the model. + + // Tell the cache manager that the preview bitmaps for a deleted + // page can be removed from all caches. + if (pPage!=NULL && ! pPage->IsInserted()) + cache::PageCacheManager::Instance()->ReleasePreviewBitmap(pPage); + + mrController.GetSelectionManager()->GetSelectionObserver()->NotifyPageEvent(pPage); + } + + // Tell the controller about the model change only when the document is + // in a sane state, not just in the middle of a larger change. + SdDrawDocument* pDocument (mrSlideSorter.GetModel().GetDocument()); + if (pDocument != NULL + && pDocument->GetMasterSdPageCount(PK_STANDARD) == pDocument->GetMasterSdPageCount(PK_NOTES)) + { + // A model change can make updates of some text fields necessary + // (like page numbers and page count.) Invalidate all previews in + // the cache to cope with this. Doing this on demand would be a + // nice optimization. + cache::PageCacheManager::Instance()->InvalidateAllPreviewBitmaps(pDocument->getUnoModel()); + + mrController.HandleModelChange(); + } +} + + + +void Listener::HandleShapeModification (const SdrPage* pPage) +{ + if (pPage == NULL) + return; + + // Invalidate the preview of the page (in all slide sorters that display + // it.) + ::boost::shared_ptr<cache::PageCacheManager> pCacheManager (cache::PageCacheManager::Instance()); + if ( ! pCacheManager) + return; + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + if (pDocument == NULL) + { + OSL_ASSERT(pDocument!=NULL); + return; + } + pCacheManager->InvalidatePreviewBitmap(pDocument->getUnoModel(), pPage); + mrSlideSorter.GetView().GetPreviewCache()->RequestPreviewBitmap(pPage); + + // When the page is a master page then invalidate the previews of all + // pages that are linked to this master page. + if (pPage->IsMasterPage()) + { + for (USHORT nIndex=0,nCount=pDocument->GetSdPageCount(PK_STANDARD); + nIndex<nCount; + ++nIndex) + { + const SdPage* pCandidate = pDocument->GetSdPage(nIndex, PK_STANDARD); + if (pCandidate!=NULL && pCandidate->TRG_HasMasterPage()) + { + if (&pCandidate->TRG_GetMasterPage() == pPage) + pCacheManager->InvalidatePreviewBitmap(pDocument->getUnoModel(), pCandidate); + } + else + { + OSL_ASSERT(pCandidate!=NULL && pCandidate->TRG_HasMasterPage()); + } + } + } +} + + + void Listener::ThrowIfDisposed (void) throw (::com::sun::star::lang::DisposedException) diff --git a/sd/source/ui/slidesorter/controller/SlsListener.hxx b/sd/source/ui/slidesorter/controller/SlsListener.hxx index 5613452a1b59..7f65435ff738 100644..100755 --- a/sd/source/ui/slidesorter/controller/SlsListener.hxx +++ b/sd/source/ui/slidesorter/controller/SlsListener.hxx @@ -31,9 +31,7 @@ #include "MutexOwner.hxx" #include "controller/SlideSorterController.hxx" #include <com/sun/star/document/XEventListener.hpp> -#ifndef _COM_SUN_STAR_DOCUMENT_XPROPERTYCHANGELISTENER_HPP_ #include <com/sun/star/beans/XPropertyChangeListener.hpp> -#endif #include <com/sun/star/accessibility/XAccessibleEventListener.hpp> #include <com/sun/star/lang/DisposedException.hpp> #include <com/sun/star/beans/XPropertySet.hpp> @@ -171,6 +169,17 @@ private: */ void UpdateEditMode (void); + /** Handle a change in the order of slides or when the set of slides has + changed, i.e. a slide has been created. + */ + void HandleModelChange (const SdrPage* pPage); + + /** Handle a modification to a shape on the given page. When this is a + regular page then update its preview. When it is a master page then + additionally update the previews of all pages linked to it. + */ + void HandleShapeModification (const SdrPage* pPage); + /** This method throws a DisposedException when the object has already been disposed. */ diff --git a/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx b/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx index 0e8f5e100d1c..51eb81fae214 100755..100644 --- a/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx +++ b/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx @@ -33,6 +33,9 @@ #include "SlideSorterViewShell.hxx" #include "controller/SlideSorterController.hxx" #include "controller/SlsSelectionManager.hxx" +#include "controller/SlsAnimator.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsVisibleAreaManager.hxx" #include "model/SlsPageDescriptor.hxx" #include "model/SlsPageEnumerationProvider.hxx" #include "model/SlideSorterModel.hxx" @@ -44,14 +47,16 @@ #include "ViewShellBase.hxx" #include <com/sun/star/drawing/XDrawView.hpp> #include <com/sun/star/beans/XPropertySet.hpp> +#include <boost/bind.hpp> + using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::sd::slidesorter::model; using namespace ::sd::slidesorter::view; -namespace sd { namespace slidesorter { namespace controller { +namespace sd { namespace slidesorter { namespace controller { PageSelector::PageSelector (SlideSorter& rSlideSorter) : mrModel(rSlideSorter.GetModel()), @@ -61,7 +66,10 @@ PageSelector::PageSelector (SlideSorter& rSlideSorter) mnBroadcastDisableLevel(0), mbSelectionChangeBroadcastPending(false), mpMostRecentlySelectedPage(), - mpSelectionAnchor() + mpSelectionAnchor(), + mpCurrentPage(), + mnUpdateLockCount(0), + mbIsUpdateCurrentPagePending(false) { CountSelectedPages (); } @@ -71,9 +79,12 @@ PageSelector::PageSelector (SlideSorter& rSlideSorter) void PageSelector::SelectAllPages (void) { + VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter); + PageSelector::UpdateLock aLock (*this); + int nPageCount = mrModel.GetPageCount(); for (int nPageIndex=0; nPageIndex<nPageCount; nPageIndex++) - SelectPage (nPageIndex); + SelectPage(nPageIndex); } @@ -81,21 +92,26 @@ void PageSelector::SelectAllPages (void) void PageSelector::DeselectAllPages (void) { + VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter); + PageSelector::UpdateLock aLock (*this); + int nPageCount = mrModel.GetPageCount(); for (int nPageIndex=0; nPageIndex<nPageCount; nPageIndex++) - DeselectPage (nPageIndex); + DeselectPage(nPageIndex); + DBG_ASSERT (mnSelectedPageCount==0, "PageSelector::DeselectAllPages: the selected pages counter is not 0"); mnSelectedPageCount = 0; - mpMostRecentlySelectedPage.reset(); mpSelectionAnchor.reset(); } -void PageSelector::UpdateAllPages (void) +void PageSelector::GetCoreSelection (void) { + PageSelector::UpdateLock aLock (*this); + bool bSelectionHasChanged (true); mnSelectedPageCount = 0; model::PageEnumeration aAllPages ( @@ -103,13 +119,14 @@ void PageSelector::UpdateAllPages (void) while (aAllPages.HasMoreElements()) { model::SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); - if (pDescriptor->UpdateSelection()) + if (pDescriptor->GetCoreSelection()) { + mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(pDescriptor); mrSlideSorter.GetView().RequestRepaint(pDescriptor); bSelectionHasChanged = true; } - if (pDescriptor->IsSelected()) + if (pDescriptor->HasState(PageDescriptor::ST_Selected)) mnSelectedPageCount++; } @@ -125,6 +142,20 @@ void PageSelector::UpdateAllPages (void) +void PageSelector::SetCoreSelection (void) +{ + model::PageEnumeration aAllPages ( + model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + while (aAllPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + pDescriptor->SetCoreSelection(); + } +} + + + + void PageSelector::SelectPage (int nPageIndex) { SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); @@ -137,7 +168,7 @@ void PageSelector::SelectPage (int nPageIndex) void PageSelector::SelectPage (const SdPage* pPage) { - int nPageIndex = (pPage->GetPageNum()-1) / 2; + const sal_Int32 nPageIndex (mrModel.GetIndex(pPage)); SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); if (pDescriptor.get()!=NULL && pDescriptor->GetPage()==pPage) SelectPage(pDescriptor); @@ -148,9 +179,11 @@ void PageSelector::SelectPage (const SdPage* pPage) void PageSelector::SelectPage (const SharedPageDescriptor& rpDescriptor) { - if (rpDescriptor.get()!=NULL && rpDescriptor->Select()) + if (rpDescriptor.get()!=NULL + && mrSlideSorter.GetView().SetState(rpDescriptor, PageDescriptor::ST_Selected, true)) { - mnSelectedPageCount ++; + ++mnSelectedPageCount; + mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor,true); mrSlideSorter.GetView().RequestRepaint(rpDescriptor); mpMostRecentlySelectedPage = rpDescriptor; @@ -161,27 +194,49 @@ void PageSelector::SelectPage (const SharedPageDescriptor& rpDescriptor) mbSelectionChangeBroadcastPending = true; else mrController.GetSelectionManager()->SelectionHasChanged(); + UpdateCurrentPage(); + + CheckConsistency(); } } -void PageSelector::DeselectPage (int nPageIndex) +void PageSelector::DeselectPage ( + int nPageIndex, + const bool bUpdateCurrentPage) { model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); if (pDescriptor.get() != NULL) - DeselectPage(pDescriptor); + DeselectPage(pDescriptor, bUpdateCurrentPage); } -void PageSelector::DeselectPage (const SharedPageDescriptor& rpDescriptor) +void PageSelector::DeselectPage ( + const SdPage* pPage, + const bool bUpdateCurrentPage) { - if (rpDescriptor.get()!=NULL && rpDescriptor->Deselect()) + const sal_Int32 nPageIndex (mrModel.GetIndex(pPage)); + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); + if (pDescriptor.get()!=NULL && pDescriptor->GetPage()==pPage) + DeselectPage(pDescriptor, bUpdateCurrentPage); +} + + + + +void PageSelector::DeselectPage ( + const SharedPageDescriptor& rpDescriptor, + const bool bUpdateCurrentPage) +{ + if (rpDescriptor.get()!=NULL + && mrSlideSorter.GetView().SetState(rpDescriptor, PageDescriptor::ST_Selected, false)) { - mnSelectedPageCount --; + --mnSelectedPageCount; + mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor); mrSlideSorter.GetView().RequestRepaint(rpDescriptor); if (mpMostRecentlySelectedPage == rpDescriptor) mpMostRecentlySelectedPage.reset(); @@ -189,6 +244,29 @@ void PageSelector::DeselectPage (const SharedPageDescriptor& rpDescriptor) mbSelectionChangeBroadcastPending = true; else mrController.GetSelectionManager()->SelectionHasChanged(); + if (bUpdateCurrentPage) + UpdateCurrentPage(); + + CheckConsistency(); + } +} + + + + +void PageSelector::CheckConsistency (void) const +{ + int nSelectionCount (0); + for (int nPageIndex=0,nPageCount=mrModel.GetPageCount(); nPageIndex<nPageCount; nPageIndex++) + { + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); + assert(pDescriptor); + if (pDescriptor->HasState(PageDescriptor::ST_Selected)) + ++nSelectionCount; + } + if (nSelectionCount!=mnSelectedPageCount) + { + assert(nSelectionCount==mnSelectedPageCount); } } @@ -199,7 +277,7 @@ bool PageSelector::IsPageSelected (int nPageIndex) { SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); if (pDescriptor.get() != NULL) - return pDescriptor->IsSelected(); + return pDescriptor->HasState(PageDescriptor::ST_Selected); else return false; } @@ -223,30 +301,6 @@ int PageSelector::GetSelectedPageCount (void) const -void PageSelector::PrepareModelChange (void) -{ - DeselectAllPages (); -} - - - - -void PageSelector::HandleModelChange (void) -{ - UpdateAllPages(); -} - - - - -SharedPageDescriptor PageSelector::GetMostRecentlySelectedPage (void) const -{ - return mpMostRecentlySelectedPage; -} - - - - SharedPageDescriptor PageSelector::GetSelectionAnchor (void) const { return mpSelectionAnchor; @@ -270,13 +324,13 @@ void PageSelector::CountSelectedPages (void) -void PageSelector::EnableBroadcasting (bool bMakeSelectionVisible) +void PageSelector::EnableBroadcasting (void) { if (mnBroadcastDisableLevel > 0) mnBroadcastDisableLevel --; if (mnBroadcastDisableLevel==0 && mbSelectionChangeBroadcastPending) { - mrController.GetSelectionManager()->SelectionHasChanged(bMakeSelectionVisible); + mrController.GetSelectionManager()->SelectionHasChanged(); mbSelectionChangeBroadcastPending = false; } } @@ -301,7 +355,7 @@ void PageSelector::DisableBroadcasting (void) for (int nIndex=0; nIndex<nPageCount; nIndex++) { SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex)); - if (pDescriptor.get()!=NULL && pDescriptor->IsSelected()) + if (pDescriptor.get()!=NULL && pDescriptor->HasState(PageDescriptor::ST_Selected)) pSelection->push_back(pDescriptor->GetPage()); } @@ -311,14 +365,124 @@ void PageSelector::DisableBroadcasting (void) -void PageSelector::SetPageSelection (const ::boost::shared_ptr<PageSelection>& rpSelection) +void PageSelector::SetPageSelection ( + const ::boost::shared_ptr<PageSelection>& rpSelection, + const bool bUpdateCurrentPage) { PageSelection::const_iterator iPage; for (iPage=rpSelection->begin(); iPage!=rpSelection->end(); ++iPage) SelectPage(*iPage); + if (bUpdateCurrentPage) + UpdateCurrentPage(); } +void PageSelector::UpdateCurrentPage (const bool bUpdateOnlyWhenPending) +{ + if (mnUpdateLockCount > 0) + { + mbIsUpdateCurrentPagePending = true; + return; + } + + if ( ! mbIsUpdateCurrentPagePending && bUpdateOnlyWhenPending) + return; + + mbIsUpdateCurrentPagePending = false; + + // Make the first selected page the current page. + const sal_Int32 nPageCount (GetPageCount()); + for (sal_Int32 nIndex=0; nIndex<nPageCount; ++nIndex) + { + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex)); + if (pDescriptor && pDescriptor->HasState(PageDescriptor::ST_Selected)) + { + // Switching the current slide normally sets also the selection + // to just the new current slide. To prevent that, we store + // (and at the end of this scope restore) the current selection. + ::boost::shared_ptr<PageSelection> pSelection (GetPageSelection()); + + mrController.GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor); + + // Restore the selection and prevent a recursive call to + // UpdateCurrentPage(). + SetPageSelection(pSelection, false); + return; + } + } + + // No page is selected. Do not change the current slide. +} + + + + +//===== PageSelector::UpdateLock ============================================== + +PageSelector::UpdateLock::UpdateLock (SlideSorter& rSlideSorter) + : mpSelector(&rSlideSorter.GetController().GetPageSelector()) +{ + ++mpSelector->mnUpdateLockCount; +} + + + + +PageSelector::UpdateLock::UpdateLock (PageSelector& rSelector) + : mpSelector(&rSelector) +{ + ++mpSelector->mnUpdateLockCount; +} + + + + +PageSelector::UpdateLock::~UpdateLock (void) +{ + Release(); +} + +void PageSelector::UpdateLock::Release (void) +{ + if (mpSelector != NULL) + { + --mpSelector->mnUpdateLockCount; + OSL_ASSERT(mpSelector->mnUpdateLockCount >= 0); + if (mpSelector->mnUpdateLockCount == 0) + mpSelector->UpdateCurrentPage(true); + + mpSelector = NULL; + } +} + + + + +//===== PageSelector::BroadcastLock ============================================== + +PageSelector::BroadcastLock::BroadcastLock (SlideSorter& rSlideSorter) + : mrSelector(rSlideSorter.GetController().GetPageSelector()) +{ + mrSelector.DisableBroadcasting(); +} + + + + +PageSelector::BroadcastLock::BroadcastLock (PageSelector& rSelector) + : mrSelector(rSelector) +{ + mrSelector.DisableBroadcasting(); +} + + + + +PageSelector::BroadcastLock::~BroadcastLock (void) +{ + mrSelector.EnableBroadcasting(); +} + } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsProperties.cxx b/sd/source/ui/slidesorter/controller/SlsProperties.cxx index 7382d769bbe2..532047cfaefe 100644..100755 --- a/sd/source/ui/slidesorter/controller/SlsProperties.cxx +++ b/sd/source/ui/slidesorter/controller/SlsProperties.cxx @@ -37,13 +37,16 @@ Properties::Properties (void) mbIsShowSelection(true), mbIsShowFocus(true), mbIsCenterSelection(false), - mbIsSmoothSelectionScrolling(false), + mbIsSmoothSelectionScrolling(true), mbIsSuspendPreviewUpdatesDuringFullScreenPresentation(true), maBackgroundColor(Application::GetSettings().GetStyleSettings().GetWindowColor()), maTextColor(Application::GetSettings().GetStyleSettings().GetActiveTextColor()), - maSelectionColor(Application::GetSettings().GetStyleSettings().GetMenuHighlightColor()), + maSelectionColor(Application::GetSettings().GetStyleSettings().GetHighlightColor()), maHighlightColor(Application::GetSettings().GetStyleSettings().GetMenuHighlightColor()), - mbIsUIReadOnly(false) + mbIsUIReadOnly(false), + mbIsOnlyPreviewTriggersMouseOver(true), + mbIsHighContrastModeActive( + Application::GetSettings().GetStyleSettings().GetHighContrastMode()) { } @@ -57,6 +60,19 @@ Properties::~Properties (void) +void Properties::HandleDataChangeEvent (void) +{ + maBackgroundColor = Application::GetSettings().GetStyleSettings().GetWindowColor(); + maTextColor = Application::GetSettings().GetStyleSettings().GetActiveTextColor(); + maSelectionColor = Application::GetSettings().GetStyleSettings().GetHighlightColor(); + maHighlightColor = Application::GetSettings().GetStyleSettings().GetMenuHighlightColor(); + mbIsHighContrastModeActive + = Application::GetSettings().GetStyleSettings().GetHighContrastMode(); +} + + + + bool Properties::IsHighlightCurrentSlide (void) const { return mbIsHighlightCurrentSlide; @@ -230,4 +246,28 @@ void Properties::SetUIReadOnly (const bool bIsUIReadOnly) } + + +bool Properties::IsOnlyPreviewTriggersMouseOver (void) const +{ + return mbIsOnlyPreviewTriggersMouseOver; +} + + + + +void Properties::SetOnlyPreviewTriggersMouseOver (const bool bFlag) +{ + mbIsOnlyPreviewTriggersMouseOver = bFlag; +} + + + + +bool Properties::IsHighContrastModeActive (void) const +{ + return mbIsHighContrastModeActive; +} + + } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx b/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx index 5ee7f6f58b82..c94dd6d550b0 100755..100644 --- a/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx +++ b/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx @@ -31,11 +31,12 @@ #include "SlideSorter.hxx" #include "controller/SlideSorterController.hxx" +#include "controller/SlsVisibleAreaManager.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageDescriptor.hxx" #include "view/SlideSorterView.hxx" #include "view/SlsLayouter.hxx" -#include "view/SlsViewOverlay.hxx" +#include "view/SlsTheme.hxx" #include "Window.hxx" #include "sdpage.hxx" @@ -51,11 +52,15 @@ ScrollBarManager::ScrollBarManager (SlideSorter& rSlideSorter) mpVerticalScrollBar(mrSlideSorter.GetVerticalScrollBar()), mnHorizontalPosition (0), mnVerticalPosition (0), - maScrollBorder (10,10), - mnHorizontalScrollFactor (0.1), - mnVerticalScrollFactor (0.1), + maScrollBorder (20,20), + mnHorizontalScrollFactor (0.15), + mnVerticalScrollFactor (0.25), mpScrollBarFiller(mrSlideSorter.GetScrollBarFiller()), - mpContentWindow(mrSlideSorter.GetContentWindow()) + maAutoScrollTimer(), + maAutoScrollOffset(0,0), + mbIsAutoScrollActive(false), + mpContentWindow(mrSlideSorter.GetContentWindow()), + maAutoScrollFunctor() { // Hide the scroll bars by default to prevent display errors while // switching between view shells: In the short time between initiating @@ -66,7 +71,7 @@ ScrollBarManager::ScrollBarManager (SlideSorter& rSlideSorter) mpVerticalScrollBar->Hide(); mpScrollBarFiller->Hide(); - maAutoScrollTimer.SetTimeout(50); + maAutoScrollTimer.SetTimeout(25); maAutoScrollTimer.SetTimeoutHdl ( LINK(this, ScrollBarManager, AutoScrollTimeoutHandler)); } @@ -91,17 +96,15 @@ void ScrollBarManager::LateInitialization (void) void ScrollBarManager::Connect (void) { if (mpVerticalScrollBar != NULL) + { mpVerticalScrollBar->SetScrollHdl ( - LINK( - this, - ScrollBarManager, - VerticalScrollBarHandler)); + LINK(this, ScrollBarManager, VerticalScrollBarHandler)); + } if (mpHorizontalScrollBar != NULL) - mpHorizontalScrollBar->SetScrollHdl ( - LINK( - this, - ScrollBarManager, - HorizontalScrollBarHandler)); + { + mpHorizontalScrollBar->SetScrollHdl( + LINK(this, ScrollBarManager, HorizontalScrollBarHandler)); + } } @@ -110,9 +113,13 @@ void ScrollBarManager::Connect (void) void ScrollBarManager::Disconnect (void) { if (mpVerticalScrollBar != NULL) + { mpVerticalScrollBar->SetScrollHdl (Link()); + } if (mpHorizontalScrollBar != NULL) + { mpHorizontalScrollBar->SetScrollHdl (Link()); + } } @@ -129,12 +136,24 @@ void ScrollBarManager::Disconnect (void) window changes and a second call to the layouter becomes necessary. That call is made anyway after this method returns. */ -Rectangle ScrollBarManager::PlaceScrollBars (const Rectangle& rAvailableArea) +Rectangle ScrollBarManager::PlaceScrollBars ( + const Rectangle& rAvailableArea, + const bool bIsHorizontalScrollBarAllowed, + const bool bIsVerticalScrollBarAllowed) { - Rectangle aRemainingSpace (DetermineScrollBarVisibilities(rAvailableArea)); - PlaceHorizontalScrollBar (rAvailableArea); - PlaceVerticalScrollBar (rAvailableArea); - PlaceFiller (rAvailableArea); + Rectangle aRemainingSpace (DetermineScrollBarVisibilities( + rAvailableArea, + bIsHorizontalScrollBarAllowed, + bIsVerticalScrollBarAllowed)); + + if (mpHorizontalScrollBar!=NULL && mpHorizontalScrollBar->IsVisible()) + PlaceHorizontalScrollBar (rAvailableArea); + + if (mpVerticalScrollBar!=NULL && mpVerticalScrollBar->IsVisible()) + PlaceVerticalScrollBar (rAvailableArea); + + if (mpScrollBarFiller!=NULL && mpScrollBarFiller->IsVisible()) + PlaceFiller (rAvailableArea); return aRemainingSpace; } @@ -144,25 +163,21 @@ Rectangle ScrollBarManager::PlaceScrollBars (const Rectangle& rAvailableArea) void ScrollBarManager::PlaceHorizontalScrollBar (const Rectangle& aAvailableArea) { - if (mpHorizontalScrollBar != NULL - && mpHorizontalScrollBar->IsVisible()) - { - // Save the current relative position. - mnHorizontalPosition = double(mpHorizontalScrollBar->GetThumbPos()) - / double(mpHorizontalScrollBar->GetRange().Len()); - - // Place the scroll bar. - Size aScrollBarSize (mpHorizontalScrollBar->GetSizePixel()); - mpHorizontalScrollBar->SetPosSizePixel ( - Point(aAvailableArea.Left(), - aAvailableArea.Bottom()-aScrollBarSize.Height()+1), - Size (aAvailableArea.GetWidth() - GetVerticalScrollBarWidth(), - aScrollBarSize.Height())); - - // Restore the relative position. - mpHorizontalScrollBar->SetThumbPos( - (long)(0.5 + mnHorizontalPosition * mpHorizontalScrollBar->GetRange().Len())); - } + // Save the current relative position. + mnHorizontalPosition = double(mpHorizontalScrollBar->GetThumbPos()) + / double(mpHorizontalScrollBar->GetRange().Len()); + + // Place the scroll bar. + Size aScrollBarSize (mpHorizontalScrollBar->GetSizePixel()); + mpHorizontalScrollBar->SetPosSizePixel ( + Point(aAvailableArea.Left(), + aAvailableArea.Bottom()-aScrollBarSize.Height()+1), + Size (aAvailableArea.GetWidth() - GetVerticalScrollBarWidth(), + aScrollBarSize.Height())); + + // Restore the relative position. + mpHorizontalScrollBar->SetThumbPos( + (long)(0.5 + mnHorizontalPosition * mpHorizontalScrollBar->GetRange().Len())); } @@ -170,26 +185,17 @@ void ScrollBarManager::PlaceHorizontalScrollBar (const Rectangle& aAvailableArea void ScrollBarManager::PlaceVerticalScrollBar (const Rectangle& aArea) { - if (mpVerticalScrollBar != NULL - && mpVerticalScrollBar->IsVisible()) - { - view::Layouter::DoublePoint aLayouterPosition - = mrSlideSorter.GetView().GetLayouter().ConvertModelToLayouterCoordinates ( - Point (0, mpVerticalScrollBar->GetThumbPos())); - - // Place the scroll bar. - Size aScrollBarSize (mpVerticalScrollBar->GetSizePixel()); - Point aPosition (aArea.Right()-aScrollBarSize.Width()+1, aArea.Top()); - Size aSize (aScrollBarSize.Width(), aArea.GetHeight() - GetHorizontalScrollBarHeight()); - mpVerticalScrollBar->SetPosSizePixel(aPosition, aSize); - - // Restore the position. - mpVerticalScrollBar->SetThumbPos( - mrSlideSorter.GetView().GetLayouter().ConvertLayouterToModelCoordinates( - aLayouterPosition).Y()); - mnVerticalPosition = double(mpVerticalScrollBar->GetThumbPos()) - / double(mpVerticalScrollBar->GetRange().Len()); - } + const double nThumbPosition (mpVerticalScrollBar->GetThumbPos()); + + // Place the scroll bar. + Size aScrollBarSize (mpVerticalScrollBar->GetSizePixel()); + Point aPosition (aArea.Right()-aScrollBarSize.Width()+1, aArea.Top()); + Size aSize (aScrollBarSize.Width(), aArea.GetHeight() - GetHorizontalScrollBarHeight()); + mpVerticalScrollBar->SetPosSizePixel(aPosition, aSize); + + // Restore the position. + mpVerticalScrollBar->SetThumbPos(nThumbPosition); + mnVerticalPosition = nThumbPosition / double(mpVerticalScrollBar->GetRange().Len()); } @@ -197,23 +203,13 @@ void ScrollBarManager::PlaceVerticalScrollBar (const Rectangle& aArea) void ScrollBarManager::PlaceFiller (const Rectangle& aArea) { - // Place the filler when both scroll bars are visible. - if (mpHorizontalScrollBar != NULL - && mpVerticalScrollBar != NULL - && mpHorizontalScrollBar->IsVisible() - && mpVerticalScrollBar->IsVisible()) - { - mpScrollBarFiller->SetPosSizePixel( - Point( - aArea.Right()-mpVerticalScrollBar->GetSizePixel().Width()+1, - aArea.Bottom()-mpHorizontalScrollBar->GetSizePixel().Height()+1), - Size ( - mpVerticalScrollBar->GetSizePixel().Width(), - mpHorizontalScrollBar->GetSizePixel().Height())); - mpScrollBarFiller->Show(); - } - else - mpScrollBarFiller->Hide(); + mpScrollBarFiller->SetPosSizePixel( + Point( + aArea.Right()-mpVerticalScrollBar->GetSizePixel().Width()+1, + aArea.Bottom()-mpHorizontalScrollBar->GetSizePixel().Height()+1), + Size ( + mpVerticalScrollBar->GetSizePixel().Width(), + mpHorizontalScrollBar->GetSizePixel().Height())); } @@ -222,7 +218,7 @@ void ScrollBarManager::PlaceFiller (const Rectangle& aArea) void ScrollBarManager::UpdateScrollBars (bool bResetThumbPosition, bool bUseScrolling) { Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea()); - ::sd::Window* pWindow = mrSlideSorter.GetView().GetWindow(); + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); Size aWindowModelSize (pWindow->PixelToLogic(pWindow->GetSizePixel())); // The horizontal scroll bar is only shown when the window is @@ -306,14 +302,13 @@ IMPL_LINK(ScrollBarManager, VerticalScrollBarHandler, ScrollBar*, pScrollBar) if (pScrollBar!=NULL && pScrollBar==mpVerticalScrollBar.get() && pScrollBar->IsVisible() - && mrSlideSorter.GetView().GetWindow()!=NULL) + && mrSlideSorter.GetContentWindow()!=NULL) { double nRelativePosition = double(pScrollBar->GetThumbPos()) / double(pScrollBar->GetRange().Len()); mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); - mrSlideSorter.GetView().GetWindow()->SetVisibleXY ( - -1, - nRelativePosition); + mrSlideSorter.GetContentWindow()->SetVisibleXY(-1, nRelativePosition); + mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking(); } return TRUE; } @@ -326,12 +321,13 @@ IMPL_LINK(ScrollBarManager, HorizontalScrollBarHandler, ScrollBar*, pScrollBar) if (pScrollBar!=NULL && pScrollBar==mpHorizontalScrollBar.get() && pScrollBar->IsVisible() - && mrSlideSorter.GetView().GetWindow()!=NULL) + && mrSlideSorter.GetContentWindow()!=NULL) { double nRelativePosition = double(pScrollBar->GetThumbPos()) / double(pScrollBar->GetRange().Len()); mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); - mrSlideSorter.GetView().GetWindow()->SetVisibleXY (nRelativePosition, -1); + mrSlideSorter.GetContentWindow()->SetVisibleXY(nRelativePosition, -1); + mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking(); } return TRUE; } @@ -346,7 +342,7 @@ void ScrollBarManager::SetWindowOrigin ( mnHorizontalPosition = nHorizontalPosition; mnVerticalPosition = nVerticalPosition; - ::sd::Window* pWindow = mrSlideSorter.GetView().GetWindow(); + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); Size aViewSize (pWindow->GetViewSize()); Point aOrigin ( (long int) (mnHorizontalPosition * aViewSize.Width()), @@ -371,31 +367,42 @@ void ScrollBarManager::SetWindowOrigin ( b) when not showing a scroll bar the area used by the page objects fits into the available area in the scroll bars orientation. */ -Rectangle ScrollBarManager::DetermineScrollBarVisibilities (const Rectangle& rAvailableArea) +Rectangle ScrollBarManager::DetermineScrollBarVisibilities ( + const Rectangle& rAvailableArea, + const bool bIsHorizontalScrollBarAllowed, + const bool bIsVerticalScrollBarAllowed) { // Test which combination of scroll bars is the best. bool bShowHorizontal = false; bool bShowVertical = false; - do + if (mrSlideSorter.GetModel().GetPageCount() == 0) { - if (mrSlideSorter.GetModel().GetPageCount() == 0) - // No pages => no scroll bars. - break; - - if (TestScrollBarVisibilities(bShowHorizontal=false, bShowVertical=false, rAvailableArea)) - break; - if (TestScrollBarVisibilities(bShowHorizontal=true, bShowVertical=false, rAvailableArea)) - break; - if (TestScrollBarVisibilities(bShowHorizontal=false, bShowVertical=true, rAvailableArea)) - break; - if (TestScrollBarVisibilities(bShowHorizontal=true, bShowVertical=true, rAvailableArea)) - break; + // No pages => no scroll bars. + } + else if (TestScrollBarVisibilities(false, false, rAvailableArea)) + { + // Nothing to be done. + } + else if (bIsHorizontalScrollBarAllowed + && TestScrollBarVisibilities(true, false, rAvailableArea)) + { + bShowHorizontal = true; + } + else if (bIsVerticalScrollBarAllowed + && TestScrollBarVisibilities(false, true, rAvailableArea)) + { + bShowVertical = true; + } + else + { + bShowHorizontal = true; + bShowVertical = true; } - while (false); // Make the visibility of the scroll bars permanent. mpVerticalScrollBar->Show(bShowVertical); mpHorizontalScrollBar->Show(bShowHorizontal); + mpScrollBarFiller->Show(bShowVertical && bShowHorizontal); // Adapt the remaining space accordingly. Rectangle aRemainingSpace (rAvailableArea); @@ -415,7 +422,7 @@ bool ScrollBarManager::TestScrollBarVisibilities ( bool bVerticalScrollBarVisible, const Rectangle& rAvailableArea) { - bool bAreVisibilitiesOK = true; + model::SlideSorterModel& rModel (mrSlideSorter.GetModel()); // Adapt the available size by subtracting the sizes of the scroll bars // visible in this combination. @@ -427,74 +434,81 @@ bool ScrollBarManager::TestScrollBarVisibilities ( // Tell the view to rearrange its page objects and check whether the // page objects can be shown without clipping. - bool bRearrangeSuccess (false); - if (mrSlideSorter.GetView().GetOrientation() == view::SlideSorterView::HORIZONTAL) - { - bRearrangeSuccess = mrSlideSorter.GetView().GetLayouter().RearrangeHorizontal ( - aBrowserSize, - mrSlideSorter.GetModel().GetPageDescriptor(0)->GetPage()->GetSize(), - mpContentWindow.get(), - mrSlideSorter.GetModel().GetPageCount()); - } - else - { - bRearrangeSuccess = mrSlideSorter.GetView().GetLayouter().RearrangeVertical ( - aBrowserSize, - mrSlideSorter.GetModel().GetPageDescriptor(0)->GetPage()->GetSize(), - mpContentWindow.get()); - } + bool bRearrangeSuccess (mrSlideSorter.GetView().GetLayouter().Rearrange ( + mrSlideSorter.GetView().GetOrientation(), + aBrowserSize, + rModel.GetPageDescriptor(0)->GetPage()->GetSize(), + rModel.GetPageCount())); if (bRearrangeSuccess) { - Size aPageSize = mrSlideSorter.GetView().GetLayouter().GetPageBox ( - mrSlideSorter.GetModel().GetPageCount()).GetSize(); + Size aPageSize = mrSlideSorter.GetView().GetLayouter().GetTotalBoundingBox().GetSize(); Size aWindowModelSize = mpContentWindow->PixelToLogic(aBrowserSize); - bool bHorizontallyClipped = (aPageSize.Width() > aWindowModelSize.Width()); - bool bVerticallyClipped = (aPageSize.Height() > aWindowModelSize.Height()); - bAreVisibilitiesOK = (bHorizontallyClipped == bHorizontalScrollBarVisible) - && (bVerticallyClipped == bVerticalScrollBarVisible); + // The content may be clipped, i.e. not fully visible, in one + // direction only when the scroll bar is visible in that direction. + if (aPageSize.Width() > aWindowModelSize.Width()) + if ( ! bHorizontalScrollBarVisible) + return false; + if (aPageSize.Height() > aWindowModelSize.Height()) + if ( ! bVerticalScrollBarVisible) + return false; + + return true; } else - bAreVisibilitiesOK = false; - - return bAreVisibilitiesOK; + return false; } -void ScrollBarManager::SetTop (const sal_Int32 nNewTop) +void ScrollBarManager::SetTopLeft (const Point aNewTopLeft) { - if (mpVerticalScrollBar != NULL - && mpVerticalScrollBar->GetThumbPos() != nNewTop) - { - // Flush pending repaints before scrolling to avoid temporary artifacts. - mrSlideSorter.GetView().GetWindow()->Update(); + if (( ! mpVerticalScrollBar + || mpVerticalScrollBar->GetThumbPos() == aNewTopLeft.Y()) + && ( ! mpHorizontalScrollBar + || mpHorizontalScrollBar->GetThumbPos() == aNewTopLeft.X())) + return; + + // Flush pending repaints before scrolling to avoid temporary artifacts. + mrSlideSorter.GetContentWindow()->Update(); - mpVerticalScrollBar->SetThumbPos(nNewTop); - mnVerticalPosition = double(nNewTop) / double(mpVerticalScrollBar->GetRange().Len()); - mrSlideSorter.GetView().GetWindow()->SetVisibleXY ( - mnHorizontalPosition, mnVerticalPosition); + if (mpVerticalScrollBar) + { + mpVerticalScrollBar->SetThumbPos(aNewTopLeft.Y()); + mnVerticalPosition = aNewTopLeft.Y() / double(mpVerticalScrollBar->GetRange().Len()); + } + if (mpHorizontalScrollBar) + { + mpHorizontalScrollBar->SetThumbPos(aNewTopLeft.X()); + mnHorizontalPosition = aNewTopLeft.X() / double(mpHorizontalScrollBar->GetRange().Len()); } + + mrSlideSorter.GetContentWindow()->SetVisibleXY(mnHorizontalPosition, mnVerticalPosition); + mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); } -void ScrollBarManager::SetLeft (const sal_Int32 nNewLeft) +sal_Int32 ScrollBarManager::GetTop (void) const { - if (mpHorizontalScrollBar != NULL - && mpHorizontalScrollBar->GetThumbPos() != nNewLeft) - { - // Flush pending repaints before scrolling to avoid temporary artifacts. - mrSlideSorter.GetView().GetWindow()->Update(); + if (mpVerticalScrollBar != NULL) + return mpVerticalScrollBar->GetThumbPos(); + else + return 0; +} - mpHorizontalScrollBar->SetThumbPos(nNewLeft); - mnHorizontalPosition = double(nNewLeft) / double(mpHorizontalScrollBar->GetRange().Len()); - mrSlideSorter.GetView().GetWindow()->SetVisibleXY ( - mnHorizontalPosition, mnVerticalPosition); - } + + + +sal_Int32 ScrollBarManager::GetLeft (void) const +{ + if (mpHorizontalScrollBar != NULL) + return mpHorizontalScrollBar->GetThumbPos(); + else + return 0; } @@ -524,7 +538,7 @@ int ScrollBarManager::GetHorizontalScrollBarHeight (void) const void ScrollBarManager::CalcAutoScrollOffset (const Point& rMouseWindowPosition) { - ::sd::Window* pWindow = mrSlideSorter.GetView().GetWindow(); + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); int nDx = 0; int nDy = 0; @@ -579,14 +593,16 @@ void ScrollBarManager::CalcAutoScrollOffset (const Point& rMouseWindowPosition) -bool ScrollBarManager::AutoScroll (const Point& rMouseWindowPosition) +bool ScrollBarManager::AutoScroll ( + const Point& rMouseWindowPosition, + const ::boost::function<void(void)>& rAutoScrollFunctor) { - CalcAutoScrollOffset (rMouseWindowPosition); - bool bResult = RepeatAutoScroll(); - if (bResult) - { - maAutoScrollTimer.Start(); - } + maAutoScrollFunctor = rAutoScrollFunctor; + CalcAutoScrollOffset(rMouseWindowPosition); + bool bResult (true); + if ( ! mbIsAutoScrollActive) + bResult = RepeatAutoScroll(); + return bResult; } @@ -596,6 +612,7 @@ bool ScrollBarManager::AutoScroll (const Point& rMouseWindowPosition) void ScrollBarManager::StopAutoScroll (void) { maAutoScrollTimer.Stop(); + mbIsAutoScrollActive = false; } @@ -607,13 +624,23 @@ bool ScrollBarManager::RepeatAutoScroll (void) { if (mrSlideSorter.GetViewShell() != NULL) { - mrSlideSorter.GetViewShell()->ScrollLines( + mrSlideSorter.GetViewShell()->Scroll( maAutoScrollOffset.Width(), - maAutoScrollOffset.Height()); + maAutoScrollOffset.Height()); + mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); + + if (maAutoScrollFunctor) + maAutoScrollFunctor(); + + mbIsAutoScrollActive = true; + maAutoScrollTimer.Start(); + return true; } } + maAutoScrollFunctor = ::boost::function<void(void)>(); + mbIsAutoScrollActive = false; return false; } @@ -628,4 +655,83 @@ IMPL_LINK(ScrollBarManager, AutoScrollTimeoutHandler, Timer *, EMPTYARG) } + + +void ScrollBarManager::Scroll( + const Orientation eOrientation, + const Unit eUnit, + const sal_Int32 nDistance) +{ + bool bIsVertical (false); + switch (eOrientation) + { + case Orientation_Horizontal: bIsVertical = false; break; + case Orientation_Vertical: bIsVertical = true; break; + default: + OSL_ASSERT(eOrientation==Orientation_Horizontal || eOrientation==Orientation_Vertical); + return; + } + + Point aNewTopLeft ( + mpHorizontalScrollBar ? mpHorizontalScrollBar->GetThumbPos() : 0, + mpVerticalScrollBar ? mpVerticalScrollBar->GetThumbPos() : 0); + switch (eUnit) + { + case Unit_Pixel: + if (bIsVertical) + aNewTopLeft.Y() += nDistance; + else + aNewTopLeft.X() += nDistance; + break; + + case Unit_Slide: + { + view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter()); + + // Calculate estimate of new location. + if (bIsVertical) + aNewTopLeft.Y() += nDistance * rLayouter.GetPageObjectSize().Height(); + else + aNewTopLeft.X() += nDistance * rLayouter.GetPageObjectSize().Width(); + + // Adapt location to show whole slides. + if (bIsVertical) + if (nDistance > 0) + { + const sal_Int32 nIndex (rLayouter.GetIndexAtPoint( + Point(aNewTopLeft.X(), aNewTopLeft.Y()+mpVerticalScrollBar->GetVisibleSize()), + true)); + aNewTopLeft.Y() = rLayouter.GetPageObjectBox(nIndex,true).Bottom() + - mpVerticalScrollBar->GetVisibleSize(); + } + else + { + const sal_Int32 nIndex (rLayouter.GetIndexAtPoint( + Point(aNewTopLeft.X(), aNewTopLeft.Y()), + true)); + aNewTopLeft.Y() = rLayouter.GetPageObjectBox(nIndex,true).Top(); + } + else + if (nDistance > 0) + { + const sal_Int32 nIndex (rLayouter.GetIndexAtPoint( + Point(aNewTopLeft.X()+mpVerticalScrollBar->GetVisibleSize(), aNewTopLeft.Y()), + true)); + aNewTopLeft.X() = rLayouter.GetPageObjectBox(nIndex,true).Right() + - mpVerticalScrollBar->GetVisibleSize(); + } + else + { + const sal_Int32 nIndex (rLayouter.GetIndexAtPoint( + Point(aNewTopLeft.X(), aNewTopLeft.Y()), + true)); + aNewTopLeft.X() = rLayouter.GetPageObjectBox(nIndex,true).Left(); + } + } + } + mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking(); + SetTopLeft(aNewTopLeft); +} + + } } } // end of namespace ::sd::slidesorter::controller 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 diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx index f1b4cb6c39be..d9062a4ef2b1 100755 --- a/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx +++ b/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx @@ -30,18 +30,22 @@ #include "controller/SlsSelectionManager.hxx" #include "SlideSorter.hxx" -#include "SlsSelectionCommand.hxx" +#include "SlsCommand.hxx" #include "controller/SlideSorterController.hxx" #include "controller/SlsAnimator.hxx" +#include "controller/SlsAnimationFunction.hxx" #include "controller/SlsCurrentSlideManager.hxx" #include "controller/SlsFocusManager.hxx" +#include "controller/SlsPageSelector.hxx" #include "controller/SlsProperties.hxx" #include "controller/SlsScrollBarManager.hxx" #include "controller/SlsSlotManager.hxx" +#include "controller/SlsSelectionObserver.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageEnumerationProvider.hxx" #include "model/SlsPageDescriptor.hxx" #include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" #include "drawdoc.hxx" #include "Window.hxx" #include <svx/svxids.hrc> @@ -65,39 +69,24 @@ using namespace ::sd::slidesorter::controller; namespace sd { namespace slidesorter { namespace controller { -namespace { - class VerticalVisibleAreaScroller - { - public: - VerticalVisibleAreaScroller (SlideSorter& rSlideSorter, - const double nStart, const double nEnd); - void operator() (const double nValue); - private: - SlideSorter& mrSlideSorter; - double mnStart; - double mnEnd; - }; - class HorizontalVisibleAreaScroller - { - public: - HorizontalVisibleAreaScroller (SlideSorter& rSlideSorter, - const double nStart, const double nEnd); - void operator() (const double nValue); - private: - SlideSorter& mrSlideSorter; - double mnStart; - double mnEnd; - }; -} - +class SelectionManager::PageInsertionListener + : public SfxListener +{ +public: +}; SelectionManager::SelectionManager (SlideSorter& rSlideSorter) : mrSlideSorter(rSlideSorter), mrController(rSlideSorter.GetController()), maSelectionBeforeSwitch(), - mbIsMakeSelectionVisiblePending(true) + mbIsMakeSelectionVisiblePending(true), + mnInsertionPosition(-1), + mnAnimationId(Animator::NotAnAnimationId), + maRequestedTopLeft(), + mpPageInsertionListener(), + mpSelectionObserver(new SelectionObserver(rSlideSorter)) { } @@ -106,14 +95,20 @@ SelectionManager::SelectionManager (SlideSorter& rSlideSorter) SelectionManager::~SelectionManager (void) { + if (mnAnimationId != Animator::NotAnAnimationId) + mrController.GetAnimator()->RemoveAnimation(mnAnimationId); } -void SelectionManager::DeleteSelectedPages (void) +void SelectionManager::DeleteSelectedPages (const bool bSelectFollowingPage) { + // Create some locks to prevent updates of the model, view, selection + // state while modifying any of them. SlideSorterController::ModelChangeLock aLock (mrController); + SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + PageSelector::UpdateLock aSelectionLock (mrSlideSorter); // Hide focus. bool bIsFocusShowing = mrController.GetFocusManager().IsFocusShowing(); @@ -125,8 +120,23 @@ void SelectionManager::DeleteSelectedPages (void) model::PageEnumeration aPageEnumeration ( PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel())); ::std::vector<SdPage*> aSelectedPages; + sal_Int32 nNewCurrentSlide (-1); while (aPageEnumeration.HasMoreElements()) - aSelectedPages.push_back (aPageEnumeration.GetNextElement()->GetPage()); + { + SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement()); + aSelectedPages.push_back(pDescriptor->GetPage()); + if (bSelectFollowingPage || nNewCurrentSlide<0) + nNewCurrentSlide = pDescriptor->GetPageIndex(); + } + if (aSelectedPages.empty()) + return; + + // Determine the slide to select (and thereby make the current slide) + // after the deletion. + if (bSelectFollowingPage) + nNewCurrentSlide -= aSelectedPages.size() - 1; + else + --nNewCurrentSlide; // The actual deletion of the selected pages is done in one of two // helper functions. They are specialized for normal respectively for @@ -143,8 +153,16 @@ void SelectionManager::DeleteSelectedPages (void) // Show focus and move it to next valid location. if (bIsFocusShowing) - mrController.GetFocusManager().ToggleFocus (); - mrController.GetFocusManager().MoveFocus (FocusManager::FMD_NONE); + mrController.GetFocusManager().ToggleFocus(); + + // Set the new current slide. + if (nNewCurrentSlide < 0) + nNewCurrentSlide = 0; + else if (nNewCurrentSlide >= mrSlideSorter.GetModel().GetPageCount()) + nNewCurrentSlide = mrSlideSorter.GetModel().GetPageCount()-1; + mrController.GetPageSelector().CountSelectedPages(); + mrController.GetPageSelector().SelectPage(nNewCurrentSlide); + mrController.GetFocusManager().SetFocusedPage(nNewCurrentSlide); } @@ -171,7 +189,7 @@ void SelectionManager::DeleteSelectedNormalPages (const ::std::vector<SdPage*>& if (xPages->getCount() <= 1) break; - USHORT nPage = ((*aI)->GetPageNum()-1) / 2; + const USHORT nPage (model::FromCoreIndex((*aI)->GetPageNum())); Reference< XDrawPage > xPage( xPages->getByIndex( nPage ), UNO_QUERY_THROW ); xPages->remove(xPage); @@ -207,7 +225,7 @@ void SelectionManager::DeleteSelectedMasterPages (const ::std::vector<SdPage*>& if (xPages->getCount() <= 1) break; - USHORT nPage = ((*aI)->GetPageNum()-1) / 2; + const USHORT nPage (model::FromCoreIndex((*aI)->GetPageNum())); Reference< XDrawPage > xPage( xPages->getByIndex( nPage ), UNO_QUERY_THROW ); xPages->remove(xPage); @@ -222,60 +240,6 @@ void SelectionManager::DeleteSelectedMasterPages (const ::std::vector<SdPage*>& -bool SelectionManager::MoveSelectedPages (const sal_Int32 nTargetPageIndex) -{ - bool bMoved (false); - PageSelector& rSelector (mrController.GetPageSelector()); - - mrSlideSorter.GetView().LockRedraw (TRUE); - SlideSorterController::ModelChangeLock aLock (mrController); - - // Transfer selection of the slide sorter to the document. - mrSlideSorter.GetModel().SynchronizeDocumentSelection (); - - // Detect how many pages lie between document start and insertion - // position. - sal_Int32 nPageCountBeforeTarget (0); - ::boost::shared_ptr<PageSelector::PageSelection> pSelection (rSelector.GetPageSelection()); - PageSelector::PageSelection::const_iterator iSelectedPage (pSelection->begin()); - PageSelector::PageSelection::const_iterator iSelectionEnd (pSelection->end()); - for ( ; iSelectedPage!=iSelectionEnd; ++iSelectedPage) - { - if (*iSelectedPage==NULL) - continue; - if (((*iSelectedPage)->GetPageNum()-1)/2 <= nTargetPageIndex) - ++nPageCountBeforeTarget; - else - break; - } - - // Prepare to select the moved pages. - SelectionCommand* pCommand = new SelectionCommand( - rSelector,mrController.GetCurrentSlideManager(),mrSlideSorter.GetModel()); - sal_Int32 nSelectedPageCount (rSelector.GetSelectedPageCount()); - for (sal_Int32 nOffset=0; nOffset<nSelectedPageCount; ++nOffset) - pCommand->AddSlide(sal::static_int_cast<USHORT>( - nTargetPageIndex + nOffset - nPageCountBeforeTarget + 1)); - - // At the moment we can not move master pages. - if (nTargetPageIndex>=0) - { - if (mrSlideSorter.GetModel().GetEditMode() == EM_PAGE) - bMoved = mrSlideSorter.GetModel().GetDocument()->MovePages( - sal::static_int_cast<sal_uInt16>(nTargetPageIndex)); - } - if (bMoved) - mrController.GetSlotManager()->ExecuteCommandAsynchronously( - ::std::auto_ptr<controller::Command>(pCommand)); - - mrSlideSorter.GetView().LockRedraw (FALSE); - - return bMoved; -} - - - - void SelectionManager::SelectionHasChanged (const bool bMakeSelectionVisible) { if (bMakeSelectionVisible) @@ -318,166 +282,6 @@ void SelectionManager::SelectionHasChanged (const bool bMakeSelectionVisible) -bool SelectionManager::IsMakeSelectionVisiblePending (void) const -{ - return mbIsMakeSelectionVisiblePending; -} - - - - -/** We have to distinguish three cases: 1) the selection is empty, 2) the - selection fits completely into the visible area, 3) it does not. - 1) The visible area is not modified. - 2) When the selection fits completely into the visible area we have to - decide how to align it. It is done by scrolling it there and thus when - we scoll up the (towards the end of the document) the bottom of the - selection is aligned with the bottom of the window. When we scroll - down (towards the beginning of the document) the top of the selection is - aligned with the top of the window. - 3) We have to decide what part of the selection to make visible. Here - we use the eSelectionHint and concentrate on either the first, the last, - or the most recently selected page. We then again apply the algorithm - of a). - -*/ -Size SelectionManager::MakeSelectionVisible (const SelectionHint eSelectionHint) -{ - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - if (pWindow == NULL) - return Size(0,0); - - mbIsMakeSelectionVisiblePending = false; - - // Determine the descriptors of the first and last selected page and the - // bounding box that encloses their page objects. - model::SharedPageDescriptor pFirst; - model::SharedPageDescriptor pLast; - Rectangle aSelectionBox; - model::PageEnumeration aSelectedPages ( - PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel())); - while (aSelectedPages.HasMoreElements()) - { - model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); - - if (pFirst.get() == NULL) - pFirst = pDescriptor; - pLast = pDescriptor; - - aSelectionBox.Union (mrSlideSorter.GetView().GetPageBoundingBox ( - pDescriptor, - view::SlideSorterView::CS_MODEL, - view::SlideSorterView::BBT_INFO)); - } - - if (pFirst != NULL) - { - // Determine scroll direction and the position in model coordinates - // that will be aligned with the top/left or bottom/right window - // border. - if (DoesSelectionExceedVisibleArea(aSelectionBox)) - { - // We can show only a part of the selection. - aSelectionBox = ResolveLargeSelection(pFirst,pLast, eSelectionHint); - } - - return MakeRectangleVisible(aSelectionBox); - } - - return Size(0,0); -} - - - - -Size SelectionManager::MakeRectangleVisible (const Rectangle& rBox) -{ - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - if (pWindow == NULL) - return Size(0,0); - - Rectangle aVisibleArea (pWindow->PixelToLogic( - Rectangle( - Point(0,0), - pWindow->GetOutputSizePixel()))); - - if (mrSlideSorter.GetView().GetOrientation() == SlideSorterView::VERTICAL) - { - // Scroll the visible area to make aSelectionBox visible. - sal_Int32 nNewTop (aVisibleArea.Top()); - if (mrSlideSorter.GetController().GetProperties()->IsCenterSelection()) - { - nNewTop = rBox.Top() - (aVisibleArea.GetHeight() - rBox.GetHeight()) / 2; - } - else - { - if (rBox.Top() < aVisibleArea.Top()) - nNewTop = rBox.Top(); - else if (rBox.Bottom() > aVisibleArea.Bottom()) - nNewTop = rBox.Bottom() - aVisibleArea.GetHeight(); - // otherwise we do not modify the visible area. - } - - // Make some corrections of the new visible area. - Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea()); - if (nNewTop + aVisibleArea.GetHeight() > aModelArea.Bottom()) - nNewTop = aModelArea.GetHeight() - aVisibleArea.GetHeight(); - if (nNewTop < aModelArea.Top()) - nNewTop = aModelArea.Top(); - - // Scroll. - if (nNewTop != aVisibleArea.Top()) - { - mrController.GetAnimator()->AddAnimation( - VerticalVisibleAreaScroller(mrSlideSorter, aVisibleArea.Top(), nNewTop), - mrSlideSorter.GetController().GetProperties()->IsSmoothSelectionScrolling() ? - 1000 : 0 - ); - } - - return Size(0,aVisibleArea.Top() - nNewTop); - } - else - { - // Scroll the visible area to make aSelectionBox visible. - sal_Int32 nNewLeft (aVisibleArea.Left()); - if (mrSlideSorter.GetController().GetProperties()->IsCenterSelection()) - { - nNewLeft = rBox.Left() - (aVisibleArea.GetWidth() - rBox.GetWidth()) / 2; - } - else - { - if (rBox.Left() < aVisibleArea.Left()) - nNewLeft = rBox.Left(); - else if (rBox.Right() > aVisibleArea.Right()) - nNewLeft = rBox.Right() - aVisibleArea.GetWidth(); - // otherwise we do not modify the visible area. - } - - // Make some corrections of the new visible area. - Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea()); - if (nNewLeft + aVisibleArea.GetWidth() > aModelArea.Right()) - nNewLeft = aModelArea.GetWidth() - aVisibleArea.GetWidth(); - if (nNewLeft < aModelArea.Left()) - nNewLeft = aModelArea.Left(); - - // Scroll. - if (nNewLeft != aVisibleArea.Left()) - { - mrController.GetAnimator()->AddAnimation( - HorizontalVisibleAreaScroller(mrSlideSorter, aVisibleArea.Left(), nNewLeft), - mrSlideSorter.GetController().GetProperties()->IsSmoothSelectionScrolling() ? - 1000 : 0 - ); - } - - return Size(aVisibleArea.Left() - nNewLeft, 0); - } -} - - - - void SelectionManager::AddSelectionChangeListener (const Link& rListener) { if (::std::find ( @@ -504,70 +308,6 @@ void SelectionManager::RemoveSelectionChangeListener(const Link&rListener) -bool SelectionManager::DoesSelectionExceedVisibleArea (const Rectangle& rSelectionBox) const -{ - ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); - if (pWindow == NULL) - return true; - - Rectangle aVisibleArea (pWindow->PixelToLogic( - Rectangle( - Point(0,0), - pWindow->GetOutputSizePixel()))); - if (mrSlideSorter.GetView().GetOrientation() == SlideSorterView::VERTICAL) - return rSelectionBox.GetHeight() > aVisibleArea.GetHeight(); - else - return rSelectionBox.GetWidth() > aVisibleArea.GetWidth(); -} - - - - -Rectangle SelectionManager::ResolveLargeSelection ( - const SharedPageDescriptor& rpFirst, - const SharedPageDescriptor& rpLast, - const SelectionHint eSelectionHint) -{ - OSL_ASSERT(rpFirst.get()!=NULL); - OSL_ASSERT(rpLast.get()!=NULL); - - // The mose recently selected page is assumed to lie in the range - // between first and last selected page. Therefore the bounding box is - // not modified. - model::SharedPageDescriptor pRecent ( - mrController.GetPageSelector().GetMostRecentlySelectedPage()); - - // Get the bounding box of the page object on which to concentrate. - model::SharedPageDescriptor pRepresentative; - switch (eSelectionHint) - { - case SH_FIRST: - pRepresentative = rpFirst; - break; - - case SH_LAST: - pRepresentative = rpLast; - break; - - case SH_RECENT: - default: - if (pRecent.get() == NULL) - pRepresentative = rpFirst; - else - pRepresentative = pRecent; - break; - } - OSL_ASSERT(pRepresentative.get() != NULL); - - return mrSlideSorter.GetView().GetPageBoundingBox ( - pRepresentative, - view::SlideSorterView::CS_MODEL, - view::SlideSorterView::BBT_INFO); -} - - - - sal_Int32 SelectionManager::GetInsertionPosition (void) const { sal_Int32 nInsertionPosition (mnInsertionPosition); @@ -584,7 +324,7 @@ sal_Int32 SelectionManager::GetInsertionPosition (void) const const sal_Int32 nPosition (aSelectedPages.GetNextElement()->GetPage()->GetPageNum()); // Convert *2+1 index to straight index (n-1)/2 after the page // (+1). - nInsertionPosition = (nPosition-1)/2 + 1; + nInsertionPosition = model::FromCoreIndex(nPosition) + 1; } } @@ -611,52 +351,9 @@ void SelectionManager::SetInsertionPosition (const sal_Int32 nInsertionPosition) -//===== VerticalVisibleAreaScroller =========================================== - -namespace { - -VerticalVisibleAreaScroller::VerticalVisibleAreaScroller ( - SlideSorter& rSlideSorter, - const double nStart, - const double nEnd) - : mrSlideSorter(rSlideSorter), - mnStart(nStart), - mnEnd(nEnd) +::boost::shared_ptr<SelectionObserver> SelectionManager::GetSelectionObserver (void) const { + return mpSelectionObserver; } - - -void VerticalVisibleAreaScroller::operator() (const double nValue) -{ - mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); - mrSlideSorter.GetController().GetScrollBarManager().SetTop( - int(mnStart * (1.0 - nValue) + mnEnd * nValue)); -} - - - - -HorizontalVisibleAreaScroller::HorizontalVisibleAreaScroller ( - SlideSorter& rSlideSorter, - const double nStart, - const double nEnd) - : mrSlideSorter(rSlideSorter), - mnStart(nStart), - mnEnd(nEnd) -{ -} - - - - -void HorizontalVisibleAreaScroller::operator() (const double nValue) -{ - mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); - mrSlideSorter.GetController().GetScrollBarManager().SetLeft( - int(mnStart * (1.0 - nValue) + mnEnd * nValue)); -} - -} // end of anonymous namespace - } } } // end of namespace ::sd::slidesorter diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionObserver.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionObserver.cxx new file mode 100644 index 000000000000..b40bd667131c --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSelectionObserver.cxx @@ -0,0 +1,173 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlideSorter.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsSelectionObserver.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsFocusManager.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include <svx/svdmodel.hxx> +#include "drawdoc.hxx" + + +namespace sd { namespace slidesorter { namespace controller { + +SelectionObserver::Context::Context (SlideSorter& rSlideSorter) + : mpSelectionObserver( + rSlideSorter.GetController().GetSelectionManager()->GetSelectionObserver()) +{ + if (mpSelectionObserver) + mpSelectionObserver->StartObservation(); +} + + + + +SelectionObserver::Context::~Context(void) +{ + if (mpSelectionObserver) + mpSelectionObserver->EndObservation(); +} + + + + +void SelectionObserver::Context::Abort(void) +{ + if (mpSelectionObserver) + { + mpSelectionObserver->AbortObservation(); + mpSelectionObserver.reset(); + } +} + + + + +//===== SelectionObserver ===================================================== + +SelectionObserver::SelectionObserver (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mpDocument(mrSlideSorter.GetModel().GetDocument()), + mbIsOvservationActive(false), + maInsertedPages(), + maDeletedPages() +{ +} + + + + +SelectionObserver::~SelectionObserver (void) +{ +} + + + + +void SelectionObserver::NotifyPageEvent (const SdrPage* pSdrPage) +{ + if ( ! mbIsOvservationActive) + return; + + const SdPage* pPage = dynamic_cast<const SdPage*>(pSdrPage); + if (pPage == NULL) + return; + + if (pPage->IsInserted()) + maInsertedPages.push_back(pPage); + else + { + ::std::vector<const SdPage*>::iterator iPage( + ::std::find(maInsertedPages.begin(), maInsertedPages.end(), pPage)); + if (iPage != maInsertedPages.end()) + maInsertedPages.erase(iPage); + + maDeletedPages.push_back(pPage->GetPageNum()); + } +} + + + +void SelectionObserver::StartObservation (void) +{ + OSL_ASSERT(!mbIsOvservationActive); + maInsertedPages.clear(); + maDeletedPages.clear(); + mbIsOvservationActive = true; +} + + + + +void SelectionObserver::AbortObservation (void) +{ + OSL_ASSERT(mbIsOvservationActive); + mbIsOvservationActive = false; + maInsertedPages.clear(); + maDeletedPages.clear(); +} + + + + +void SelectionObserver::EndObservation (void) +{ + OSL_ASSERT(mbIsOvservationActive); + mbIsOvservationActive = false; + + PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + rSelector.DeselectAllPages(); + if ( ! maInsertedPages.empty()) + { + // Select the inserted pages. + for (::std::vector<const SdPage*>::const_iterator + iPage(maInsertedPages.begin()), + iEnd(maInsertedPages.end()); + iPage!=iEnd; + ++iPage) + { + rSelector.SelectPage(*iPage); + } + maInsertedPages.clear(); + } + maDeletedPages.clear(); + + aUpdateLock.Release(); + mrSlideSorter.GetController().GetFocusManager().SetFocusedPageToCurrentPage(); + +} + + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsSlideFunction.cxx b/sd/source/ui/slidesorter/controller/SlsSlideFunction.cxx index 7fe090ad5541..1af831c2ad8a 100755 --- a/sd/source/ui/slidesorter/controller/SlsSlideFunction.cxx +++ b/sd/source/ui/slidesorter/controller/SlsSlideFunction.cxx @@ -46,7 +46,7 @@ SlideFunction::SlideFunction ( SfxRequest& rRequest) : FuPoor ( rSlideSorter.GetViewShell(), - rSlideSorter.GetView().GetWindow(), + rSlideSorter.GetContentWindow().get(), &rSlideSorter.GetView(), rSlideSorter.GetModel().GetDocument(), rRequest) diff --git a/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx b/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx index e571a765bdad..ded7c2ebfdde 100755..100644 --- a/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx +++ b/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx @@ -33,20 +33,20 @@ #include "SlideSorter.hxx" #include "SlideSorterViewShell.hxx" #include "controller/SlideSorterController.hxx" -#include "controller/SlsPageSelector.hxx" #include "controller/SlsClipboard.hxx" -#include "controller/SlsSelectionFunction.hxx" -#include "controller/SlsFocusManager.hxx" #include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsFocusManager.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsSelectionFunction.hxx" #include "controller/SlsSelectionManager.hxx" -#include "SlsHideSlideFunction.hxx" +#include "controller/SlsSelectionObserver.hxx" #include "SlsCommand.hxx" #include "model/SlideSorterModel.hxx" #include "model/SlsPageEnumerationProvider.hxx" #include "model/SlsPageDescriptor.hxx" #include "view/SlideSorterView.hxx" #include "view/SlsLayouter.hxx" -#include "view/SlsViewOverlay.hxx" #include "framework/FrameworkHelper.hxx" #include "Window.hxx" #include "fupoor.hxx" @@ -92,12 +92,30 @@ #include <com/sun/star/drawing/XDrawPages.hpp> #include <vcl/svapp.hxx> +#include <boost/bind.hpp> + using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::presentation; namespace sd { namespace slidesorter { namespace controller { +namespace { + +/** The state of a set of slides with respect to being excluded from the + slide show. +*/ +enum SlideExclusionState {UNDEFINED, EXCLUDED, INCLUDED, MIXED}; + +/** Return for the given set of slides whether they included are + excluded from the slide show. +*/ +SlideExclusionState GetSlideExclusionState (model::PageEnumeration& rPageSet); + +} // end of anonymous namespace + + + SlotManager::SlotManager (SlideSorter& rSlideSorter) : mrSlideSorter(rSlideSorter), maCommandQueue() @@ -133,8 +151,11 @@ void SlotManager::FuTemporary (SfxRequest& rRequest) break; case SID_HIDE_SLIDE: + ChangeSlideExclusionState(model::SharedPageDescriptor(), true); + break; + case SID_SHOW_SLIDE: - HideSlideFunction::Create(mrSlideSorter, rRequest); + ChangeSlideExclusionState(model::SharedPageDescriptor(), false); break; case SID_PAGES_PER_ROW: @@ -145,15 +166,16 @@ void SlotManager::FuTemporary (SfxRequest& rRequest) if (pPagesPerRow != NULL) { sal_Int32 nColumnCount = pPagesPerRow->GetValue(); - // Force the given number of columns by setting the - // minimal and maximal number of columns to the same - // value. + // Force the given number of columns by setting + // the minimal and maximal number of columns to + // the same value. mrSlideSorter.GetView().GetLayouter().SetColumnCount ( nColumnCount, nColumnCount); // Force a repaint and re-layout. pShell->ArrangeGUIElements (); // Rearrange the UI-elements controlled by the - // controller and force a rearrangement of the view. + // controller and force a rearrangement of the + // view. mrSlideSorter.GetController().Rearrange(true); } } @@ -167,11 +189,11 @@ void SlotManager::FuTemporary (SfxRequest& rRequest) case SID_SLIDE_TRANSITIONS_PANEL: { - // Make the slide transition panel visible (expand it) in the - // tool pane. + // Make the slide transition panel visible (expand it) + // in the tool pane. if (mrSlideSorter.GetViewShellBase() != NULL) - framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase()) - ->RequestTaskPanel(sd::framework::FrameworkHelper::msSlideTransitionTaskPanelURL); + framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase()) + ->RequestTaskPanel(sd::framework::FrameworkHelper::msSlideTransitionTaskPanelURL); rRequest.Ignore (); break; } @@ -179,7 +201,7 @@ void SlotManager::FuTemporary (SfxRequest& rRequest) case SID_PRESENTATION_DLG: FuSlideShowDlg::Create ( pShell, - mrSlideSorter.GetView().GetWindow(), + mrSlideSorter.GetContentWindow().get(), &mrSlideSorter.GetView(), pDocument, rRequest); @@ -188,16 +210,16 @@ void SlotManager::FuTemporary (SfxRequest& rRequest) case SID_CUSTOMSHOW_DLG: FuCustomShowDlg::Create ( pShell, - mrSlideSorter.GetView().GetWindow(), + mrSlideSorter.GetContentWindow().get(), &mrSlideSorter.GetView(), pDocument, rRequest); - break; + break; case SID_EXPAND_PAGE: FuExpandPage::Create ( pShell, - mrSlideSorter.GetView().GetWindow(), + mrSlideSorter.GetContentWindow().get(), &mrSlideSorter.GetView(), pDocument, rRequest); @@ -206,7 +228,7 @@ void SlotManager::FuTemporary (SfxRequest& rRequest) case SID_SUMMARY_PAGE: FuSummaryPage::Create ( pShell, - mrSlideSorter.GetView().GetWindow(), + mrSlideSorter.GetContentWindow().get(), &mrSlideSorter.GetView(), pDocument, rRequest); @@ -218,17 +240,22 @@ void SlotManager::FuTemporary (SfxRequest& rRequest) rRequest.Done(); break; + case SID_DUPLICATE_PAGE: + DuplicateSelectedSlides(rRequest); + rRequest.Done(); + break; + case SID_DELETE_PAGE: case SID_DELETE_MASTER_PAGE: case SID_DELETE: // we need SID_CUT to handle the delete key - // (DEL -> accelerator -> SID_CUT). - if (mrSlideSorter.GetModel().GetPageCount() > 1) - { - mrSlideSorter.GetController().GetSelectionManager()->DeleteSelectedPages(); - } + // (DEL -> accelerator -> SID_CUT). + if (mrSlideSorter.GetModel().GetPageCount() > 1) + { + mrSlideSorter.GetController().GetSelectionManager()->DeleteSelectedPages(); + } - rRequest.Done(); - break; + rRequest.Done(); + break; case SID_RENAMEPAGE: case SID_RENAME_MASTER_PAGE: @@ -361,21 +388,33 @@ void SlotManager::FuSupport (SfxRequest& rRequest) break; } - case SID_UNDO : + case SID_UNDO: { SlideSorterViewShell* pViewShell = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()); if (pViewShell != NULL) + { + view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + SlideSorterController::ModelChangeLock aModelLock (mrSlideSorter.GetController()); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + SelectionObserver::Context aContext (mrSlideSorter); pViewShell->ImpSidUndo (FALSE, rRequest); + } break; } - case SID_REDO : + case SID_REDO: { SlideSorterViewShell* pViewShell = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()); if (pViewShell != NULL) + { + view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + SlideSorterController::ModelChangeLock aModelLock (mrSlideSorter.GetController()); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + SelectionObserver::Context aContext (mrSlideSorter); pViewShell->ImpSidRedo (FALSE, rRequest); + } break; } @@ -477,7 +516,7 @@ void SlotManager::GetAttrState (SfxItemSet& rSet) } } -void SlotManager::GetMenuState ( SfxItemSet& rSet) +void SlotManager::GetMenuState (SfxItemSet& rSet) { EditMode eEditMode = mrSlideSorter.GetModel().GetEditMode(); ViewShell* pShell = mrSlideSorter.GetViewShell(); @@ -592,39 +631,48 @@ void SlotManager::GetMenuState ( SfxItemSet& rSet) model::PageEnumeration aSelectedPages ( model::PageEnumerationProvider::CreateSelectedPagesEnumeration( mrSlideSorter.GetModel())); - HideSlideFunction::ExclusionState eState ( - HideSlideFunction::GetExclusionState(aSelectedPages)); + const SlideExclusionState eState (GetSlideExclusionState(aSelectedPages)); switch (eState) { - case HideSlideFunction::MIXED: + case MIXED: // Show both entries. break; - case HideSlideFunction::EXCLUDED: + case EXCLUDED: rSet.DisableItem(SID_HIDE_SLIDE); break; - case HideSlideFunction::INCLUDED: + case INCLUDED: rSet.DisableItem(SID_SHOW_SLIDE); break; - case HideSlideFunction::UNDEFINED: + case UNDEFINED: rSet.DisableItem(SID_HIDE_SLIDE); rSet.DisableItem(SID_SHOW_SLIDE); break; } } + PageKind ePageKind = mrSlideSorter.GetModel().GetPageType(); - if( (eEditMode == EM_MASTERPAGE) && (ePageKind != PK_HANDOUT ) ) + if ((eEditMode == EM_MASTERPAGE) && (ePageKind != PK_HANDOUT)) { rSet.DisableItem(SID_ASSIGN_LAYOUT); } - if( (eEditMode == EM_MASTERPAGE) || (ePageKind==PK_NOTES) ) + if ((eEditMode == EM_MASTERPAGE) || (ePageKind==PK_NOTES)) { rSet.DisableItem(SID_INSERTPAGE); } + + // Disable some slots when in master page mode. + if (eEditMode == EM_MASTERPAGE) + { + if (rSet.GetItemState(SID_INSERTPAGE) == SFX_ITEM_AVAILABLE) + rSet.DisableItem(SID_INSERTPAGE); + if (rSet.GetItemState(SID_DUPLICATE_PAGE) == SFX_ITEM_AVAILABLE) + rSet.DisableItem(SID_DUPLICATE_PAGE); + } } @@ -774,18 +822,22 @@ void SlotManager::GetStatusBarState (SfxItemSet& rSet) model::PageEnumeration aSelectedPages ( model::PageEnumerationProvider::CreateSelectedPagesEnumeration( mrSlideSorter.GetModel())); - pPage = aSelectedPages.GetNextElement()->GetPage(); - nFirstPage = pPage->GetPageNum()/2; - pFirstPage = pPage; - - aPageStr += sal_Unicode(' '); - aPageStr += String::CreateFromInt32( nFirstPage + 1 ); - aPageStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( " / " )); - aPageStr += String::CreateFromInt32( - mrSlideSorter.GetModel().GetPageCount()); - - aLayoutStr = pFirstPage->GetLayoutName(); - aLayoutStr.Erase( aLayoutStr.SearchAscii( SD_LT_SEPARATOR ) ); + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + if (pDescriptor) + { + pPage = pDescriptor->GetPage(); + nFirstPage = pPage->GetPageNum()/2; + pFirstPage = pPage; + + aPageStr += sal_Unicode(' '); + aPageStr += String::CreateFromInt32( nFirstPage + 1 ); + aPageStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( " / " )); + aPageStr += String::CreateFromInt32( + mrSlideSorter.GetModel().GetPageCount()); + + aLayoutStr = pFirstPage->GetLayoutName(); + aLayoutStr.Erase( aLayoutStr.SearchAscii( SD_LT_SEPARATOR ) ); + } } rSet.Put( SfxStringItem( SID_STATUS_PAGE, aPageStr ) ); @@ -836,7 +888,7 @@ void SlotManager::RenameSlide (void) SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); DBG_ASSERT(pFact, "Dialogdiet fail!"); AbstractSvxNameDialog* aNameDlg = pFact->CreateSvxNameDialog( - mrSlideSorter.GetActiveWindow(), + mrSlideSorter.GetContentWindow().get(), aPageName, aDescr); DBG_ASSERT(aNameDlg, "Dialogdiet fail!"); aNameDlg->SetText( aTitle ); @@ -984,123 +1036,110 @@ bool SlotManager::RenameSlideFromDrawViewShell( USHORT nPageId, const String & r */ void SlotManager::InsertSlide (SfxRequest& rRequest) { - PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); - // The fallback insertion position is after the last slide. - sal_Int32 nInsertionIndex (rSelector.GetPageCount() - 1); - if (rSelector.GetSelectedPageCount() > 0) + const sal_Int32 nInsertionIndex (GetInsertionPosition()); + + PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter); + + SdPage* pNewPage = NULL; + if (mrSlideSorter.GetModel().GetEditMode() == EM_PAGE) { - // Deselect all but the last selected slide. - bool bLastSelectedSlideSeen (false); - for (int nIndex=rSelector.GetPageCount()-1; nIndex>=0; --nIndex) + SlideSorterViewShell* pShell = dynamic_cast<SlideSorterViewShell*>( + mrSlideSorter.GetViewShell()); + if (pShell != NULL) { - if (rSelector.IsPageSelected(nIndex)) - { - if (bLastSelectedSlideSeen) - rSelector.DeselectPage (nIndex); - else - { - nInsertionIndex = nIndex; - bLastSelectedSlideSeen = true; - } - } + pNewPage = pShell->CreateOrDuplicatePage ( + rRequest, + mrSlideSorter.GetModel().GetPageType(), + nInsertionIndex>=0 + ? mrSlideSorter.GetModel().GetPageDescriptor(nInsertionIndex)->GetPage() + : NULL); } } - - // No selection. Is there an insertion indicator? - else if (mrSlideSorter.GetView().GetOverlay() - .GetInsertionIndicatorOverlay().isVisible()) - { - // Select the page before the insertion indicator. - nInsertionIndex = mrSlideSorter.GetView().GetOverlay() - .GetInsertionIndicatorOverlay().GetInsertionPageIndex(); - nInsertionIndex --; - rSelector.SelectPage (nInsertionIndex); - } - - // Is there a stored insertion position? - else if (mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() >= 0) + else { - nInsertionIndex - = mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() - 1; - rSelector.SelectPage(nInsertionIndex); - } + // Use the API to create a new page. + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + Reference<drawing::XMasterPagesSupplier> xMasterPagesSupplier ( + pDocument->getUnoModel(), UNO_QUERY); + if (xMasterPagesSupplier.is()) + { + Reference<drawing::XDrawPages> xMasterPages ( + xMasterPagesSupplier->getMasterPages()); + if (xMasterPages.is()) + { + xMasterPages->insertNewByIndex (nInsertionIndex+1); - // Select the last page when there is at least one page. - else if (rSelector.GetPageCount() > 0) - { - nInsertionIndex = rSelector.GetPageCount() - 1; - rSelector.SelectPage (nInsertionIndex); + // Create shapes for the default layout. + pNewPage = pDocument->GetMasterSdPage( + (USHORT)(nInsertionIndex+1), PK_STANDARD); + pNewPage->CreateTitleAndLayout (TRUE,TRUE); + } + } } + if (pNewPage == NULL) + return; - // Hope for the best that CreateOrDuplicatePage() can cope with an empty - // selection. - else - { - nInsertionIndex = -1; - } + // When a new page has been inserted then select it, make it the + // current page, and focus it. + view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); + mrSlideSorter.GetController().GetPageSelector().SelectPage(pNewPage); +} - USHORT nPageCount ((USHORT)mrSlideSorter.GetModel().GetPageCount()); - rSelector.DisableBroadcasting(); - // In order for SlideSorterController::GetActualPage() to select the - // selected page as current page we have to turn off the focus - // temporarily. - { - FocusManager::FocusHider aTemporaryFocusHider ( - mrSlideSorter.GetController().GetFocusManager()); - SdPage* pPreviousPage = NULL; - if (nInsertionIndex >= 0) - pPreviousPage = mrSlideSorter.GetModel() - .GetPageDescriptor(nInsertionIndex)->GetPage(); - if (mrSlideSorter.GetModel().GetEditMode() == EM_PAGE) - { - SlideSorterViewShell* pShell = dynamic_cast<SlideSorterViewShell*>( - mrSlideSorter.GetViewShell()); - if (pShell != NULL) - { - pShell->CreateOrDuplicatePage ( - rRequest, - mrSlideSorter.GetModel().GetPageType(), - pPreviousPage); - } - } - else +void SlotManager::DuplicateSelectedSlides (SfxRequest& rRequest) +{ + // Create a list of the pages that are to be duplicated. The process of + // duplication alters the selection. + sal_Int32 nInsertPosition (0); + ::std::vector<SdPage*> aPagesToDuplicate; + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel())); + while (aSelectedPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + if (pDescriptor && pDescriptor->GetPage()) { - // Use the API to create a new page. - SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); - Reference<drawing::XMasterPagesSupplier> xMasterPagesSupplier ( - pDocument->getUnoModel(), UNO_QUERY); - if (xMasterPagesSupplier.is()) - { - Reference<drawing::XDrawPages> xMasterPages ( - xMasterPagesSupplier->getMasterPages()); - if (xMasterPages.is()) - { - xMasterPages->insertNewByIndex (nInsertionIndex+1); - - // Create shapes for the default layout. - SdPage* pMasterPage = pDocument->GetMasterSdPage( - (USHORT)(nInsertionIndex+1), PK_STANDARD); - pMasterPage->CreateTitleAndLayout (TRUE,TRUE); - } - } + aPagesToDuplicate.push_back(pDescriptor->GetPage()); + nInsertPosition = pDescriptor->GetPage()->GetPageNum()+2; } } - // When a new page has been inserted then select it and make it the - // current page. - mrSlideSorter.GetView().LockRedraw(TRUE); - if (mrSlideSorter.GetModel().GetPageCount() > nPageCount) + // Duplicate the pages in aPagesToDuplicate and collect the newly + // created pages in aPagesToSelect. + const bool bUndo (aPagesToDuplicate.size()>1 && mrSlideSorter.GetView().IsUndoEnabled()); + if (bUndo) + mrSlideSorter.GetView().BegUndo(String(SdResId(STR_INSERTPAGE))); + + ::std::vector<SdPage*> aPagesToSelect; + for(::std::vector<SdPage*>::const_iterator + iPage(aPagesToDuplicate.begin()), + iEnd(aPagesToDuplicate.end()); + iPage!=iEnd; + ++iPage, nInsertPosition+=2) { - nInsertionIndex++; - model::SharedPageDescriptor pDescriptor = mrSlideSorter.GetModel().GetPageDescriptor(nInsertionIndex); - if (pDescriptor.get() != NULL) - mrSlideSorter.GetController().GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor); + aPagesToSelect.push_back( + mrSlideSorter.GetViewShell()->CreateOrDuplicatePage( + rRequest, PK_STANDARD, *iPage, nInsertPosition)); } - rSelector.EnableBroadcasting(); - mrSlideSorter.GetView().LockRedraw(FALSE); + aPagesToDuplicate.clear(); + + if (bUndo) + mrSlideSorter.GetView().EndUndo(); + + // Set the selection to the pages in aPagesToSelect. + PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); + rSelector.DeselectAllPages(); + ::std::for_each ( + aPagesToSelect.begin(), + aPagesToSelect.end(), + ::boost::bind( + static_cast<void (PageSelector::*)(const SdPage*)>(&PageSelector::SelectPage), + rSelector, + _1)); } void SlotManager::ExecuteCommandAsynchronously (::std::auto_ptr<Command> pCommand) @@ -1130,5 +1169,154 @@ IMPL_LINK(SlotManager, UserEventCallback, void*, EMPTYARG) return 1; } + + + +void SlotManager::ChangeSlideExclusionState ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bExcludeSlide) +{ + if (rpDescriptor) + { + mrSlideSorter.GetView().SetState( + rpDescriptor, + model::PageDescriptor::ST_Excluded, + bExcludeSlide); + } + else + { + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + while (aSelectedPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + mrSlideSorter.GetView().SetState( + pDescriptor, + model::PageDescriptor::ST_Excluded, + bExcludeSlide); + } + } + + SfxBindings& rBindings (mrSlideSorter.GetViewShell()->GetViewFrame()->GetBindings()); + rBindings.Invalidate(SID_PRESENTATION); + rBindings.Invalidate(SID_REHEARSE_TIMINGS); + rBindings.Invalidate(SID_HIDE_SLIDE); + rBindings.Invalidate(SID_SHOW_SLIDE); + mrSlideSorter.GetModel().GetDocument()->SetChanged(); +} + + + + +sal_Int32 SlotManager::GetInsertionPosition (void) +{ + PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); + + // The insertion indicator is preferred. After all the user explicitly + // used it to define the insertion position. + if (mrSlideSorter.GetController().GetInsertionIndicatorHandler()->IsActive()) + { + // Select the page before the insertion indicator. + return mrSlideSorter.GetController().GetInsertionIndicatorHandler()->GetInsertionPageIndex() + - 1; + } + + // Is there a stored insertion position? + else if (mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() >= 0) + { + return mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() - 1; + } + + // Use the index of the last selected slide. + else if (rSelector.GetSelectedPageCount() > 0) + { + for (int nIndex=rSelector.GetPageCount()-1; nIndex>=0; --nIndex) + if (rSelector.IsPageSelected(nIndex)) + return nIndex; + + // We should never get here. + OSL_ASSERT(false); + return rSelector.GetPageCount() - 1; + } + + // Select the last page when there is at least one page. + else if (rSelector.GetPageCount() > 0) + { + return rSelector.GetPageCount() - 1; + } + + // Hope for the best that CreateOrDuplicatePage() can cope with an empty + // selection. + else + { + // We should never get here because there has to be at least one page. + OSL_ASSERT(false); + return -1; + } +} + + + + +void SlotManager::NotifyEditModeChange (void) +{ + SfxBindings& rBindings (mrSlideSorter.GetViewShell()->GetViewFrame()->GetBindings()); + rBindings.Invalidate(SID_PRESENTATION); + rBindings.Invalidate(SID_INSERTPAGE); + rBindings.Invalidate(SID_DUPLICATE_PAGE); +} + + + + +//----------------------------------------------------------------------------- + +namespace { + + + +SlideExclusionState GetSlideExclusionState (model::PageEnumeration& rPageSet) +{ + SlideExclusionState eState (UNDEFINED); + BOOL bState; + + // Get toggle state of the selected pages. + while (rPageSet.HasMoreElements() && eState!=MIXED) + { + bState = rPageSet.GetNextElement()->GetPage()->IsExcluded(); + switch (eState) + { + case UNDEFINED: + // Use the first selected page to set the inital value. + eState = bState ? EXCLUDED : INCLUDED; + break; + + case EXCLUDED: + // The pages before where all not part of the show, + // this one is. + if ( ! bState) + eState = MIXED; + break; + + case INCLUDED: + // The pages before where all part of the show, + // this one is not. + if (bState) + eState = MIXED; + break; + + case MIXED: + default: + // No need to change anything. + break; + } + } + + return eState; +} + +} // end of anonymous namespace + } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsTransferable.cxx b/sd/source/ui/slidesorter/controller/SlsTransferable.cxx index 20ddc937469c..efda2eb1e4eb 100644..100755 --- a/sd/source/ui/slidesorter/controller/SlsTransferable.cxx +++ b/sd/source/ui/slidesorter/controller/SlsTransferable.cxx @@ -28,7 +28,7 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sd.hxx" -#include "SlsTransferable.hxx" +#include "controller/SlsTransferable.hxx" #include "SlideSorterViewShell.hxx" #include "View.hxx" @@ -39,9 +39,11 @@ Transferable::Transferable ( SdDrawDocument* pSrcDoc, ::sd::View* pWorkView, BOOL bInitOnGetData, - SlideSorterViewShell* pViewShell) + SlideSorterViewShell* pViewShell, + const ::std::vector<Representative>& rRepresentatives) : SdTransferable (pSrcDoc, pWorkView, bInitOnGetData), - mpViewShell(pViewShell) + mpViewShell(pViewShell), + maRepresentatives(rRepresentatives) { if (mpViewShell != NULL) StartListening(*mpViewShell); @@ -49,6 +51,7 @@ Transferable::Transferable ( + Transferable::~Transferable (void) { if (mpViewShell != NULL) @@ -89,4 +92,10 @@ void Transferable::Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) +const ::std::vector<Transferable::Representative>& Transferable::GetRepresentatives (void) const +{ + return maRepresentatives; +} + + } } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsTransferable.hxx b/sd/source/ui/slidesorter/controller/SlsTransferable.hxx deleted file mode 100644 index f527fd4768b9..000000000000 --- a/sd/source/ui/slidesorter/controller/SlsTransferable.hxx +++ /dev/null @@ -1,70 +0,0 @@ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -#ifndef SD_SLIDESORTER_TRANSFERABLE_HXX -#define SD_SLIDESORTER_TRANSFERABLE_HXX - -#include "sdxfer.hxx" - -class SdDrawDocument; -namespace sd -{ - class pWorkView; - namespace slidesorter - { - class SlideSorterViewShell; - } -} - -namespace sd { namespace slidesorter { namespace controller { - -/** This class exists to have DragFinished call the correct object: the - SlideSorterViewShell instead of the old SlideView. -*/ -class Transferable - : public SdTransferable -{ -public: - Transferable ( - SdDrawDocument* pSrcDoc, - ::sd::View* pWorkView, - BOOL bInitOnGetData, - SlideSorterViewShell* pViewShell); - - virtual ~Transferable (void); - - virtual void DragFinished (sal_Int8 nDropAction); - -private: - SlideSorterViewShell* mpViewShell; - - virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint); -}; - -} } } // end of namespace ::sd::slidesorter::controller - -#endif diff --git a/sd/source/ui/slidesorter/controller/SlsVisibleAreaManager.cxx b/sd/source/ui/slidesorter/controller/SlsVisibleAreaManager.cxx new file mode 100644 index 000000000000..6a85192f8418 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsVisibleAreaManager.cxx @@ -0,0 +1,301 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "controller/SlsVisibleAreaManager.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsAnimationFunction.hxx" +#include "controller/SlsScrollBarManager.hxx" +#include "controller/SlsCurrentSlideManager.hxx" + + +namespace sd { namespace slidesorter { namespace controller { + +namespace { + class VisibleAreaScroller + { + public: + VisibleAreaScroller ( + SlideSorter& rSlideSorter, + const Point aStart, + const Point aEnd); + void operator() (const double nValue); + private: + SlideSorter& mrSlideSorter; + Point maStart; + const Point maEnd; + const ::boost::function<double(double)> maAccelerationFunction; + }; + +} // end of anonymous namespace + + + +VisibleAreaManager::VisibleAreaManager (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + maVisibleRequests(), + mnScrollAnimationId(Animator::NotAnAnimationId), + maRequestedVisibleTopLeft(), + meRequestedAnimationMode(Animator::AM_Immediate), + mbIsCurrentSlideTrackingActive(true), + mnDisableCount(0) +{ +} + + + + +VisibleAreaManager::~VisibleAreaManager (void) +{ +} + + + + +void VisibleAreaManager::ActivateCurrentSlideTracking (void) +{ + mbIsCurrentSlideTrackingActive = true; +} + + + + +void VisibleAreaManager::DeactivateCurrentSlideTracking (void) +{ + mbIsCurrentSlideTrackingActive = false; +} + + + + +void VisibleAreaManager::RequestVisible ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bForce) +{ + if (rpDescriptor) + { + if (mnDisableCount == 0) + { + maVisibleRequests.push_back( + mrSlideSorter.GetView().GetLayouter().GetPageObjectBox( + rpDescriptor->GetPageIndex(), + true)); + } + if (bForce && ! mbIsCurrentSlideTrackingActive) + ActivateCurrentSlideTracking(); + MakeVisible(); + } +} + + + + +void VisibleAreaManager::RequestCurrentSlideVisible (void) +{ + if (mbIsCurrentSlideTrackingActive && mnDisableCount==0) + RequestVisible( + mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide()); +} + + + + +void VisibleAreaManager::MakeVisible (void) +{ + if (maVisibleRequests.empty()) + return; + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if ( ! pWindow) + return; + const Point aCurrentTopLeft (pWindow->PixelToLogic(Point(0,0))); + + const ::boost::optional<Point> aNewVisibleTopLeft (GetRequestedTopLeft()); + maVisibleRequests.clear(); + if ( ! aNewVisibleTopLeft) + return; + + // We now know what the visible area shall be. Scroll accordingly + // unless that is not already the visible area or a running scroll + // animation has it as its target area. + if (mnScrollAnimationId!=Animator::NotAnAnimationId + && maRequestedVisibleTopLeft==aNewVisibleTopLeft) + return; + + // Stop a running animation. + if (mnScrollAnimationId != Animator::NotAnAnimationId) + mrSlideSorter.GetController().GetAnimator()->RemoveAnimation(mnScrollAnimationId); + + maRequestedVisibleTopLeft = aNewVisibleTopLeft.get(); + VisibleAreaScroller aAnimation( + mrSlideSorter, + aCurrentTopLeft, + maRequestedVisibleTopLeft); + if (meRequestedAnimationMode==Animator::AM_Animated + && mrSlideSorter.GetProperties()->IsSmoothSelectionScrolling()) + { + mnScrollAnimationId = mrSlideSorter.GetController().GetAnimator()->AddAnimation( + aAnimation, + 0, + 300); + } + else + { + // Execute the animation at its final value. + aAnimation(1.0); + } + meRequestedAnimationMode = Animator::AM_Immediate; +} + + + + +::boost::optional<Point> VisibleAreaManager::GetRequestedTopLeft (void) const +{ + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if ( ! pWindow) + return ::boost::optional<Point>(); + + // Get the currently visible area and the model area. + const Rectangle aVisibleArea (pWindow->PixelToLogic( + Rectangle( + Point(0,0), + pWindow->GetOutputSizePixel()))); + const Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea()); + + sal_Int32 nVisibleTop (aVisibleArea.Top()); + const sal_Int32 nVisibleWidth (aVisibleArea.GetWidth()); + sal_Int32 nVisibleLeft (aVisibleArea.Left()); + const sal_Int32 nVisibleHeight (aVisibleArea.GetHeight()); + + // Find the longest run of boxes whose union fits into the visible area. + Rectangle aBoundingBox; + for (::std::vector<Rectangle>::const_iterator + iBox(maVisibleRequests.begin()), + iEnd(maVisibleRequests.end()); + iBox!=iEnd; + ++iBox) + { + if (nVisibleTop+nVisibleHeight <= iBox->Bottom()) + nVisibleTop = iBox->Bottom()-nVisibleHeight; + if (nVisibleTop > iBox->Top()) + nVisibleTop = iBox->Top(); + + if (nVisibleLeft+nVisibleWidth <= iBox->Right()) + nVisibleLeft = iBox->Right()-nVisibleWidth; + if (nVisibleLeft > iBox->Left()) + nVisibleLeft = iBox->Left(); + + // Make sure the visible area does not move outside the model area. + if (nVisibleTop + nVisibleHeight > aModelArea.Bottom()) + nVisibleTop = aModelArea.Bottom() - nVisibleHeight; + if (nVisibleTop < aModelArea.Top()) + nVisibleTop = aModelArea.Top(); + + if (nVisibleLeft + nVisibleWidth > aModelArea.Right()) + nVisibleLeft = aModelArea.Right() - nVisibleWidth; + if (nVisibleLeft < aModelArea.Left()) + nVisibleLeft = aModelArea.Left(); + } + + const Point aRequestedTopLeft (nVisibleLeft, nVisibleTop); + if (aRequestedTopLeft == aVisibleArea.TopLeft()) + return ::boost::optional<Point>(); + else + return ::boost::optional<Point>(aRequestedTopLeft); +} + + + + +//===== VisibleAreaManager::TemporaryDisabler ================================= + +VisibleAreaManager::TemporaryDisabler::TemporaryDisabler (SlideSorter& rSlideSorter) + : mrVisibleAreaManager(rSlideSorter.GetController().GetVisibleAreaManager()) +{ + ++mrVisibleAreaManager.mnDisableCount; +} + + + + +VisibleAreaManager::TemporaryDisabler::~TemporaryDisabler (void) +{ + --mrVisibleAreaManager.mnDisableCount; +} + + + +//===== VerticalVisibleAreaScroller =========================================== + +namespace { + +const static sal_Int32 gnMaxScrollDistance = 300; + +VisibleAreaScroller::VisibleAreaScroller ( + SlideSorter& rSlideSorter, + const Point aStart, + const Point aEnd) + : mrSlideSorter(rSlideSorter), + maStart(aStart), + maEnd(aEnd), + maAccelerationFunction( + controller::AnimationParametricFunction( + controller::AnimationBezierFunction (0.1,0.6))) +{ + // When the distance to scroll is larger than a threshold then first + // jump to within this distance of the final value and start the + // animation from there. + if (abs(aStart.X()-aEnd.X()) > gnMaxScrollDistance) + if (aStart.X() < aEnd.X()) + maStart.X() = aEnd.X()-gnMaxScrollDistance; + else + maStart.X() = aEnd.X()+gnMaxScrollDistance; + if (abs(aStart.Y()-aEnd.Y()) > gnMaxScrollDistance) + if (aStart.Y() < aEnd.Y()) + maStart.Y() = aEnd.Y()-gnMaxScrollDistance; + else + maStart.Y() = aEnd.Y()+gnMaxScrollDistance; +} + + + + +void VisibleAreaScroller::operator() (const double nTime) +{ + const double nLocalTime (maAccelerationFunction(nTime)); + mrSlideSorter.GetController().GetScrollBarManager().SetTopLeft( + Point( + sal_Int32(0.5 + maStart.X() * (1.0 - nLocalTime) + maEnd.X() * nLocalTime), + sal_Int32 (0.5 + maStart.Y() * (1.0 - nLocalTime) + maEnd.Y() * nLocalTime))); +} + +} // end of anonymous namespace + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/makefile.mk b/sd/source/ui/slidesorter/controller/makefile.mk index 8ab63ddf776c..460ef16ed3f1 100644..100755 --- a/sd/source/ui/slidesorter/controller/makefile.mk +++ b/sd/source/ui/slidesorter/controller/makefile.mk @@ -45,25 +45,23 @@ PRJINC=..$/.. SLOFILES = \ $(SLO)$/SlideSorterController.obj \ $(SLO)$/SlsAnimator.obj \ + $(SLO)$/SlsAnimationFunction.obj \ $(SLO)$/SlsClipboard.obj \ $(SLO)$/SlsCurrentSlideManager.obj \ + $(SLO)$/SlsDragAndDropContext.obj \ $(SLO)$/SlsFocusManager.obj \ + $(SLO)$/SlsInsertionIndicatorHandler.obj\ $(SLO)$/SlsListener.obj \ - $(SLO)$/SlsPageObjectFactory.obj \ $(SLO)$/SlsPageSelector.obj \ $(SLO)$/SlsProperties.obj \ $(SLO)$/SlsScrollBarManager.obj \ $(SLO)$/SlsSelectionCommand.obj \ + $(SLO)$/SlsSelectionFunction.obj \ $(SLO)$/SlsSelectionManager.obj \ + $(SLO)$/SlsSelectionObserver.obj \ $(SLO)$/SlsSlotManager.obj \ $(SLO)$/SlsTransferable.obj \ - \ - $(SLO)$/SlsHideSlideFunction.obj \ - $(SLO)$/SlsSelectionFunction.obj \ - $(SLO)$/SlsSlideFunction.obj - -EXCEPTIONSFILES= \ - $(SLO)$/SlideSorterController.obj + $(SLO)$/SlsVisibleAreaManager.obj # --- Tagets ------------------------------------------------------- |