renaissance1: #i107215# Improved drag and drop.

This commit is contained in:
Andre Fischer
2010-02-23 16:56:05 +01:00
parent 2318e08d02
commit 3c7bf4b67d
26 changed files with 800 additions and 320 deletions

View File

@@ -34,6 +34,8 @@
#include "SlideSorter.hxx"
#include "SlideSorterViewShell.hxx"
#include "SlsSubstitutionHandler.hxx"
#include "SlsTransferable.hxx"
#include "controller/SlideSorterController.hxx"
#include "controller/SlsPageSelector.hxx"
#include "controller/SlsFocusManager.hxx"
@@ -43,6 +45,7 @@
#include "controller/SlsInsertionIndicatorHandler.hxx"
#include "controller/SlsSelectionManager.hxx"
#include "controller/SlsProperties.hxx"
#include "controller/SlsProperties.hxx"
#include "model/SlideSorterModel.hxx"
#include "model/SlsPageDescriptor.hxx"
#include "model/SlsPageEnumerationProvider.hxx"
@@ -57,6 +60,8 @@
#include "Window.hxx"
#include "sdpage.hxx"
#include "drawdoc.hxx"
#include "DrawDocShell.hxx"
#include "sdxfer.hxx"
#include "ViewShell.hxx"
#include "ViewShellBase.hxx"
#include "FrameView.hxx"
@@ -108,49 +113,6 @@ static const sal_uInt32 MODIFIER_MASK (SHIFT_MODIFIER | CONTROL_MODIF
namespace sd { namespace slidesorter { namespace controller {
/** A SubstitutionHandler object handles the display of a number of selected
slides at the mouse position and the insertion or (with or without
removing the pages at their original position) when the object is
destoyed.
*/
class SelectionFunction::SubstitutionHandler
{
public:
/** Create a substitution display of the currently selected pages and
use the given position as the anchor point.
*/
SubstitutionHandler (
SlideSorter& rSlideSorter,
const model::SharedPageDescriptor& rpHitDescriptor,
const Point& rMouseModelPosition);
~SubstitutionHandler (void);
/** Call this method (for example as reaction to ESC key press) to avoid
processing (ie moving or inserting) the substition when the called
SubstitutionHandler 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 bool bAllowAutoScroll = true);
private:
SlideSorter& mrSlideSorter;
model::SharedPageDescriptor mpHitDescriptor;
sal_Int32 mnInsertionIndex;
/** Move the substitution display of the currently selected pages.
*/
void Process (void);
};
class SelectionFunction::MouseMultiSelector
{
@@ -241,13 +203,13 @@ namespace {
class SelectionFunction::EventDescriptor
{
public:
Point maMousePosition;
Point maMouseModelPosition;
::boost::weak_ptr<model::PageDescriptor> mpHitDescriptor;
SdrPage* mpHitPage;
sal_uInt32 mnEventCode;
sal_Int32 mnButtonIndex;
InsertionIndicatorHandler::Mode meDragMode;
EventDescriptor (
sal_uInt32 nEventType,
@@ -260,6 +222,8 @@ public:
const AcceptDropEvent& rEvent,
SlideSorter& rSlideSorter);
EventDescriptor (const EventDescriptor& rDescriptor);
void SetDragMode (const InsertionIndicatorHandler::Mode eMode);
};
@@ -290,6 +254,9 @@ SelectionFunction::SelectionFunction (
aDragTimer.SetTimeoutHdl(LINK(this, SelectionFunction, DragSlideHdl));
}
SelectionFunction::~SelectionFunction (void)
{
aDragTimer.Stop();
@@ -353,14 +320,18 @@ BOOL SelectionFunction::MouseMove (const MouseEvent& rEvent)
(rEvent.GetButtons() & MOUSE_LEFT)!=0);
}
if (rEvent.IsLeaveWindow())
// 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.
if (rEvent.IsLeaveWindow()
|| ! Rectangle(Point(0,0),mpWindow->GetOutputSizePixel()).IsInside(aMousePosition))
{
// Rectangle aRectangle (Point(0,0),mpWindow->GetOutputSizePixel());
// if ( ! aRectangle.IsInside(aMousePosition)
if (mpSubstitutionHandler)
{
// Mouse left the window with pressed left button. Make it a drag.
StartDrag(aMousePosition);
StartDrag(aMousePosition, InsertionIndicatorHandler::MoveMode);
mpSubstitutionHandler->Hide();
mpSubstitutionHandler.reset();
}
mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor());
}
@@ -404,18 +375,59 @@ BOOL SelectionFunction::MouseButtonUp (const MouseEvent& rEvent)
void SelectionFunction::MouseDragged (const AcceptDropEvent& rEvent)
{
if (rEvent.mbLeaving)
{
if (mpSubstitutionHandler)
{
// Disconnect the substitution handler from this selection function.
mpSubstitutionHandler->Hide();
mpSubstitutionHandler->SetTargetSlideSorter();
mpSubstitutionHandler.reset();
}
}
else if ( ! mpSubstitutionHandler)
{
const SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
const Transferable* pSlideSorterTransferable
= dynamic_cast<const Transferable*>(pDragTransferable);
if (pSlideSorterTransferable != NULL)
{
// Connect the substitution handler to this selection function.
mpSubstitutionHandler = pSlideSorterTransferable->GetSubstitutionHandler();
if (mpSubstitutionHandler)
{
mpSubstitutionHandler->SetTargetSlideSorter(
&mrSlideSorter,
rEvent.maPosPixel,
InsertionIndicatorHandler::GetModeFromDndAction(rEvent.mnAction),
pSlideSorterTransferable->GetView() == &mrSlideSorter.GetView());
mpSubstitutionHandler->Show();
}
}
else
mpSubstitutionHandler.reset(
new SubstitutionHandler(
mrSlideSorter,
mrSlideSorter.GetController().GetPageAt(rEvent.maPosPixel),
rEvent.maPosPixel));
}
// 1. Compute some frequently used values relating to the event.
::std::auto_ptr<EventDescriptor> pEventDescriptor (
new EventDescriptor(rEvent, mrSlideSorter));
// 2. Detect whether we are dragging pages or dragging a selection rectangle.
view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
if (rOverlay.GetSubstitutionOverlay()->IsVisible())
if (mpSubstitutionHandler)
pEventDescriptor->mnEventCode |= SUBSTITUTION_VISIBLE;
if (mpMouseMultiSelector)
pEventDescriptor->mnEventCode |= RECTANGLE_VISIBLE;
// 3. Process the event.
// 3. Set the drag mode.
pEventDescriptor->SetDragMode(
InsertionIndicatorHandler::GetModeFromDndAction(rEvent.mnAction));
// 4. Process the event.
EventPreprocessing(*pEventDescriptor);
if ( ! EventProcessing(*pEventDescriptor))
{
@@ -427,6 +439,27 @@ void SelectionFunction::MouseDragged (const AcceptDropEvent& rEvent)
void SelectionFunction::NotifyDragFinished (void)
{
if (mpSubstitutionHandler)
{
mpSubstitutionHandler->Dispose();
mpSubstitutionHandler.reset();
}
mrController.GetInsertionIndicatorHandler()->End();
}
::boost::shared_ptr<SubstitutionHandler> SelectionFunction::GetSubstitutionHandler (void) const
{
return mpSubstitutionHandler;
}
BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent)
{
PageSelector::UpdateLock aLock (mrSlideSorter);
@@ -717,14 +750,16 @@ void SelectionFunction::StartDragTimer (void)
IMPL_LINK( SelectionFunction, DragSlideHdl, Timer*, EMPTYARG )
{
StartDrag(aMDPos);
StartDrag(aMDPos, InsertionIndicatorHandler::MoveMode);
return 0;
}
void SelectionFunction::StartDrag (const Point& rMousePosition)
void SelectionFunction::StartDrag (
const Point& rMousePosition,
const InsertionIndicatorHandler::Mode eMode)
{
if (mbPageHit
&& ! mrSlideSorter.GetProperties()->IsUIReadOnly())
@@ -736,7 +771,9 @@ void SelectionFunction::StartDrag (const Point& rMousePosition)
mrSlideSorter.GetController().GetPageAt(rMousePosition),
rMousePosition));
else
mpSubstitutionHandler->UpdatePosition(rMousePosition);
mpSubstitutionHandler->UpdatePosition(
rMousePosition,
eMode);
mbPageHit = false;
mpWindow->ReleaseMouse();
@@ -1053,16 +1090,21 @@ bool SelectionFunction::EventProcessing (const EventDescriptor& rDescriptor)
switch (rDescriptor.mnEventCode & (SUBSTITUTION_VISIBLE | RECTANGLE_VISIBLE))
{
case SUBSTITUTION_VISIBLE:
OSL_ASSERT(mpSubstitutionHandler);
// The substitution is visible. Handle events accordingly.
if (Match(rDescriptor.mnEventCode, MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK))
{
if ((rDescriptor.mnEventCode & CONTROL_MODIFIER) != 0)
StartDrag(rDescriptor.maMousePosition);
mpSubstitutionHandler->UpdatePosition(rDescriptor.maMousePosition);
StartDrag(rDescriptor.maMousePosition, InsertionIndicatorHandler::CopyMode);
mpSubstitutionHandler->UpdatePosition(
rDescriptor.maMousePosition,
rDescriptor.meDragMode);
}
else if (Match(rDescriptor.mnEventCode, MOUSE_DRAG))
{
mpSubstitutionHandler->UpdatePosition(rDescriptor.maMousePosition);
mpSubstitutionHandler->UpdatePosition(
rDescriptor.maMousePosition,
rDescriptor.meDragMode);
}
else if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON))
{
@@ -1395,7 +1437,8 @@ SelectionFunction::EventDescriptor::EventDescriptor (
mpHitDescriptor(),
mpHitPage(),
mnEventCode(0),
mnButtonIndex(-1)
mnButtonIndex(-1),
meDragMode(InsertionIndicatorHandler::MoveMode)
{
model::SharedPageDescriptor pHitDescriptor (
rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor());
@@ -1418,7 +1461,8 @@ SelectionFunction::EventDescriptor::EventDescriptor (
mpHitDescriptor(),
mpHitPage(),
mnEventCode(MOUSE_DRAG),
mnButtonIndex(-1)
mnButtonIndex(-1),
meDragMode(InsertionIndicatorHandler::MoveMode)
{
SharedSdWindow pWindow (rSlideSorter.GetContentWindow());
@@ -1441,132 +1485,17 @@ SelectionFunction::EventDescriptor::EventDescriptor (const EventDescriptor& rDes
mpHitDescriptor(rDescriptor.mpHitDescriptor),
mpHitPage(rDescriptor.mpHitPage),
mnEventCode(rDescriptor.mnEventCode),
mnButtonIndex(rDescriptor.mnButtonIndex)
mnButtonIndex(rDescriptor.mnButtonIndex),
meDragMode(InsertionIndicatorHandler::MoveMode)
{
}
//===== SubstitutionHandler ===================================================
SelectionFunction::SubstitutionHandler::SubstitutionHandler (
SlideSorter& rSlideSorter,
const model::SharedPageDescriptor& rpHitDescriptor,
const Point& rMouseModelPosition)
: mrSlideSorter(rSlideSorter),
mpHitDescriptor(rpHitDescriptor),
mnInsertionIndex(-1)
void SelectionFunction::EventDescriptor::SetDragMode (const InsertionIndicatorHandler::Mode eMode)
{
mnInsertionIndex = -1;
// No Drag-and-Drop for master pages.
if (mrSlideSorter.GetModel().GetEditMode() != EM_PAGE)
return;
if (mrSlideSorter.GetProperties()->IsUIReadOnly())
return;
view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
if ( ! rOverlay.GetSubstitutionOverlay()->IsVisible())
{
// Show a new substitution for the selected page objects.
model::PageEnumeration aSelectedPages(
model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
mrSlideSorter.GetModel()));
rOverlay.GetSubstitutionOverlay()->Create(
aSelectedPages,
rMouseModelPosition,
mpHitDescriptor);
rOverlay.GetSubstitutionOverlay()->SetIsVisible(true);
mrSlideSorter.GetController().GetInsertionIndicatorHandler()->Start(rMouseModelPosition);
}
}
SelectionFunction::SubstitutionHandler::~SubstitutionHandler (void)
{
Process();
view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
rOverlay.GetSubstitutionOverlay()->SetIsVisible(false);
rOverlay.GetSubstitutionOverlay()->Clear();
mrSlideSorter.GetController().GetInsertionIndicatorHandler()->End();
mpHitDescriptor.reset();
}
void SelectionFunction::SubstitutionHandler::Dispose (void)
{
mnInsertionIndex = -1;
}
void SelectionFunction::SubstitutionHandler::UpdatePosition (
const Point& rMousePosition,
const bool bAllowAutoScroll)
{
if (mrSlideSorter.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 (mrSlideSorter.GetContentWindow());
const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition));
if ( ! (bAllowAutoScroll && mrSlideSorter.GetController().GetScrollBarManager().AutoScroll(
rMousePosition,
::boost::bind(
&SelectionFunction::SubstitutionHandler::UpdatePosition,
this,
rMousePosition,
false))))
{
view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay());
// Move the existing substitution to the new position.
rOverlay.GetSubstitutionOverlay()->SetPosition(aMouseModelPosition);
mrSlideSorter.GetController().GetInsertionIndicatorHandler()->UpdatePosition(
aMouseModelPosition);
// Remember the new insertion index.
if (mrSlideSorter.GetController().GetInsertionIndicatorHandler()->IsInsertionTrivial())
mnInsertionIndex = -1;
else
mnInsertionIndex = mrSlideSorter.GetController().GetInsertionIndicatorHandler()
->GetInsertionPageIndex();
}
}
void SelectionFunction::SubstitutionHandler::Process (void)
{
if (mrSlideSorter.GetProperties()->IsUIReadOnly())
return;
if (mnInsertionIndex >= 0)
{
// 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.
USHORT nDocumentIndex = (USHORT)mnInsertionIndex-1;
mrSlideSorter.GetController().GetSelectionManager()->MoveSelectedPages(nDocumentIndex);
ViewShell* pViewShell = mrSlideSorter.GetViewShell();
if (pViewShell != NULL)
pViewShell->GetViewFrame()->GetBindings().Invalidate(SID_STATUS_PAGE);
}
meDragMode = eMode;
}
@@ -1849,11 +1778,14 @@ void RangeSelector::UpdateSelection (void)
{
view::SlideSorterView::DrawLock aLock (mrSlideSorter);
model::SlideSorterModel& rModel (mrSlideSorter.GetModel());
const sal_Int32 nPageCount (rModel.GetPageCount());
const sal_Int32 nIndexUnderMouse (
mrSlideSorter.GetView().GetLayouter().GetIndexAtPoint (
maSecondCorner,
false));
if (nIndexUnderMouse >= 0)
if (nIndexUnderMouse>=0 && nIndexUnderMouse<nPageCount)
{
if (mnAnchorIndex < 0)
mnAnchorIndex = nIndexUnderMouse;
@@ -1862,8 +1794,7 @@ void RangeSelector::UpdateSelection (void)
Range aRange (mnAnchorIndex, mnSecondIndex);
aRange.Justify();
model::SlideSorterModel& rModel (mrSlideSorter.GetModel());
for (sal_Int32 nIndex=0,nCount(rModel.GetPageCount()); nIndex<nCount; ++nIndex)
for (sal_Int32 nIndex=0; nIndex<nPageCount; ++nIndex)
{
model::SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));