blob: b88e3fbaee18db6bf4eed0bb37624de6129f56b8 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#include "precompiled_sd.hxx"
#include "view/SlideSorterView.hxx"
#include "ViewShellBase.hxx"
#include "SlideSorter.hxx"
#include "SlideSorterViewShell.hxx"
#include "ViewShell.hxx"
#include "SlsViewCacheContext.hxx"
#include "SlsLayeredDevice.hxx"
#include "view/SlsLayouter.hxx"
#include "view/SlsPageObjectLayouter.hxx"
#include "view/SlsPageObjectPainter.hxx"
#include "view/SlsILayerPainter.hxx"
#include "view/SlsButtonBar.hxx"
#include "view/SlsToolTip.hxx"
#include "controller/SlideSorterController.hxx"
#include "controller/SlsProperties.hxx"
#include "controller/SlsClipboard.hxx"
#include "model/SlideSorterModel.hxx"
#include "model/SlsPageEnumerationProvider.hxx"
#include "model/SlsPageDescriptor.hxx"
#include "cache/SlsPageCache.hxx"
#include "cache/SlsPageCacheManager.hxx"
#include "cache/SlsCacheContext.hxx"
#include "taskpane/SlideSorterCacheDisplay.hxx"
#include "DrawDocShell.hxx"
#include "PaneDockingWindow.hxx"
#include "drawdoc.hxx"
#include "sdpage.hxx"
#include "Window.hxx"
#include "sdresid.hxx"
#include "glob.hrc"
#include <svl/itempool.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svdopage.hxx>
#include <svx/xlndsit.hxx>
#include <svx/xlnclit.hxx>
#include <vcl/svapp.hxx>
#include <vcl/scrbar.hxx>
#include <tools/poly.hxx>
#include <vcl/lineinfo.hxx>
#include <algorithm>
#include <svx/sdrpagewindow.hxx>
#include <svl/itempool.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <drawinglayer/geometry/viewinformation2d.hxx>
#include <canvas/elapsedtime.hxx>
//#define DEBUG_TIMING
#include <svl/itempool.hxx>
#ifdef DEBUG_TIMING
#include <vector>
#endif
#include <boost/foreach.hpp>
using namespace std;
using namespace ::sd::slidesorter::model;
using namespace ::drawinglayer::primitive2d;
namespace sd { namespace slidesorter { namespace view {
namespace {
/** Wrapper around the SlideSorterView that supports the IPainter
interface and that allows the LayeredDevice to hold the
SlideSorterView (held as scoped_ptr by the SlideSorter) as
shared_ptr.
*/
class Painter : public ILayerPainter
{
public:
Painter (SlideSorterView& rView) : mrView(rView) {}
virtual ~Painter (void) {}
virtual void Paint (OutputDevice& rDevice, const Rectangle& rRepaintArea)
{
mrView.Paint(rDevice,rRepaintArea);
}
virtual void SetLayerInvalidator (const SharedILayerInvalidator&) {}
private:
SlideSorterView& mrView;
};
}
class BackgroundPainter
: public ILayerPainter,
public ::boost::noncopyable
{
public:
BackgroundPainter (const Color aBackgroundColor) : maBackgroundColor(aBackgroundColor) {}
virtual ~BackgroundPainter (void) {}
virtual void Paint (OutputDevice& rDevice, const Rectangle& rRepaintArea)
{
rDevice.SetFillColor(maBackgroundColor);
rDevice.SetLineColor();
rDevice.DrawRect(rRepaintArea);
}
virtual void SetLayerInvalidator (const SharedILayerInvalidator&) {}
void SetColor (const Color aColor) { maBackgroundColor = aColor; }
private:
Color maBackgroundColor;
};
TYPEINIT1(SlideSorterView, ::sd::View);
SlideSorterView::SlideSorterView (SlideSorter& rSlideSorter)
: ::sd::View (
rSlideSorter.GetModel().GetDocument(),
rSlideSorter.GetContentWindow().get(),
rSlideSorter.GetViewShell()),
mrSlideSorter(rSlideSorter),
mrModel(rSlideSorter.GetModel()),
mbIsDisposed(false),
mpLayouter (new Layouter(rSlideSorter.GetContentWindow(), rSlideSorter.GetTheme())),
mbPageObjectVisibilitiesValid (false),
mpPreviewCache(),
mpLayeredDevice(new LayeredDevice(rSlideSorter.GetContentWindow())),
maVisiblePageRange(-1,-1),
mbModelChangedWhileModifyEnabled(true),
maPreviewSize(0,0),
mbPreciousFlagUpdatePending(true),
meOrientation(Layouter::GRID),
mpProperties(rSlideSorter.GetProperties()),
mpPageUnderMouse(),
mnButtonUnderMouse(-1),
mpPageObjectPainter(),
mpSelectionPainter(),
mpBackgroundPainter(
new BackgroundPainter(mrSlideSorter.GetTheme()->GetColor(Theme::Color_Background))),
mpButtonBar(new ButtonBar(mrSlideSorter)),
mpToolTip(new ToolTip(mrSlideSorter)),
mbIsRearrangePending(true),
maVisibilityChangeListeners()
{
// Hide the page that contains the page objects.
SetPageVisible (sal_False);
// Register the background painter on level 1 to avoid the creation of a
// background buffer.
mpLayeredDevice->RegisterPainter(mpBackgroundPainter, 1);
// Wrap a shared_ptr-held-wrapper around this view and register it as
// painter at the layered device. There is no explicit destruction: in
// the SlideSorterView destructor the layered device is destroyed and
// with it the only reference to the wrapper which therefore is also
// destroyed.
SharedILayerPainter pPainter (new Painter(*this));
// The painter is placed on level 1 to avoid buffering. This should be
// a little faster during animations because the previews are painted
// directly into the window, not via the buffer.
mpLayeredDevice->RegisterPainter(pPainter, 1);
}
SlideSorterView::~SlideSorterView (void)
{
if ( ! mbIsDisposed)
{
OSL_ASSERT(mbIsDisposed);
Dispose();
}
}
void SlideSorterView::Init (void)
{
HandleModelChange();
}
void SlideSorterView::Dispose (void)
{
mpSelectionPainter.reset();
mpLayeredDevice->Dispose();
mpPreviewCache.reset();
SetPageUnderMouse(SharedPageDescriptor(),false);
// Hide the page to avoid problems in the view when deleting
// visualized objects
HideSdrPage();
// Deletion of the objects and the page will be done in SdrModel
// destructor (as long as objects and pages are added)
OSL_ASSERT(mpLayeredDevice.unique());
mpLayeredDevice.reset();
mbIsDisposed = true;
}
sal_Int32 SlideSorterView::GetPageIndexAtPoint (const Point& rWindowPosition) const
{
sal_Int32 nIndex (-1);
SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
if (pWindow)
{
nIndex = mpLayouter->GetIndexAtPoint(pWindow->PixelToLogic(rWindowPosition), false, false);
// Clip the page index against the page count.
if (nIndex >= mrModel.GetPageCount())
nIndex = -1;
}
return nIndex;
}
Layouter& SlideSorterView::GetLayouter (void)
{
return *mpLayouter.get();
}
void SlideSorterView::ModelHasChanged (void)
{
// Ignore this call. Rely on hints sent by the model to get informed of
// model changes.
}
void SlideSorterView::LocalModelHasChanged(void)
{
mbModelChangedWhileModifyEnabled = false;
// First call our base class.
View::ModelHasChanged ();
}
void SlideSorterView::PreModelChange (void)
{
// Reset the slide under the mouse. It will be re-set in PostModelChange().
SetPageUnderMouse(SharedPageDescriptor());
}
void SlideSorterView::PostModelChange (void)
{
// In PreModelChange() the page objects have been released. Here we
// create new ones.
::osl::MutexGuard aGuard (mrModel.GetMutex());
model::PageEnumeration aPageEnumeration (
model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
// The new page objects have to be scaled and positioned.
RequestRearrange();
RequestRepaint();
}
/** At the moment for every model change all page objects are destroyed and
re-created again. This can be optimized by accepting hints that
describe the type of change so that existing page objects can be
reused.
*/
void SlideSorterView::HandleModelChange (void)
{
PreModelChange ();
PostModelChange();
}
void SlideSorterView::HandleDrawModeChange (void)
{
// Replace the preview cache with a new and empty one. The
// PreviewRenderer that is used by the cache is replaced by this as
// well.
mpPreviewCache.reset();
GetPreviewCache()->InvalidateCache(true);
RequestRepaint();
}
void SlideSorterView::HandleDataChangeEvent (void)
{
GetPageObjectPainter()->SetTheme(mrSlideSorter.GetTheme());
// Update the color used by the background painter.
::boost::shared_ptr<BackgroundPainter> pPainter (
::boost::dynamic_pointer_cast<BackgroundPainter>(mpBackgroundPainter));
if (pPainter)
pPainter->SetColor(mrSlideSorter.GetTheme()->GetColor(Theme::Color_Background));
if (mpButtonBar)
mpButtonBar->HandleDataChangeEvent();
RequestRepaint();
}
void SlideSorterView::Resize (void)
{
UpdateOrientation();
mpLayeredDevice->Resize();
RequestRearrange();
}
void SlideSorterView::RequestRearrange (void)
{
mbIsRearrangePending = true;
Rearrange();
}
void SlideSorterView::Rearrange (void)
{
if ( ! mbIsRearrangePending)
return;
if (mrModel.GetPageCount() <= 0)
return;
SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
if ( ! pWindow)
return;
const Size aWindowSize (pWindow->GetSizePixel());
if (aWindowSize.Width()<=0 || aWindowSize.Height()<=0)
return;
const bool bRearrangeSuccess (
mpLayouter->Rearrange (
meOrientation,
aWindowSize,
mrModel.GetPageDescriptor(0)->GetPage()->GetSize(),
mrModel.GetPageCount()));
if (bRearrangeSuccess)
{
mbIsRearrangePending = false;
Layout();
UpdatePageUnderMouse(false);
// RequestRepaint();
}
}
void SlideSorterView::UpdateOrientation (void)
{
// The layout of slides depends on whether the slide sorter is
// displayed in the center or the side pane.
if (mrSlideSorter.GetViewShell()->IsMainViewShell())
SetOrientation(Layouter::GRID);
else
{
// Get access to the docking window.
::Window* pWindow = mrSlideSorter.GetContentWindow().get();
PaneDockingWindow* pDockingWindow = NULL;
while (pWindow!=NULL && pDockingWindow==NULL)
{
pDockingWindow = dynamic_cast<PaneDockingWindow*>(pWindow);
pWindow = pWindow->GetParent();
}
if (pDockingWindow != NULL)
{
const long nScrollBarSize (
Application::GetSettings().GetStyleSettings().GetScrollBarSize());
switch (pDockingWindow->GetOrientation())
{
case PaneDockingWindow::HorizontalOrientation:
if (SetOrientation(Layouter::HORIZONTAL))
{
const Range aRange (mpLayouter->GetValidVerticalSizeRange());
pDockingWindow->SetValidSizeRange(Range(
aRange.Min() + nScrollBarSize,
aRange.Max() + nScrollBarSize));
}
break;
case PaneDockingWindow::VerticalOrientation:
if (SetOrientation(Layouter::VERTICAL))
{
const Range aRange (mpLayouter->GetValidHorizontalSizeRange());
pDockingWindow->SetValidSizeRange(Range(
aRange.Min() + nScrollBarSize,
aRange.Max() + nScrollBarSize));
}
break;
case PaneDockingWindow::UnknownOrientation:
if (SetOrientation(Layouter::GRID))
{
const sal_Int32 nAdditionalSize (10);
pDockingWindow->SetMinOutputSizePixel(Size(
mpLayouter->GetValidHorizontalSizeRange().Min()
+ nScrollBarSize
+ nAdditionalSize,
mpLayouter->GetValidVerticalSizeRange().Min()
+ nScrollBarSize
+ nAdditionalSize));
}
return;
}
}
else
{
// We are not placed in a docking window. One possible reason
// is that the slide sorter is temporarily into a cache and was
// reparented to a non-docking window.
SetOrientation(Layouter::GRID);
}
}
}
void SlideSorterView::Layout ()
{
SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
if (pWindow)
{
// Set the model area, i.e. the smallest rectangle that includes all
// page objects.
const Rectangle aViewBox (mpLayouter->GetTotalBoundingBox());
pWindow->SetViewOrigin (aViewBox.TopLeft());
pWindow->SetViewSize (aViewBox.GetSize());
::boost::shared_ptr<PageObjectLayouter> pPageObjectLayouter(
mpLayouter->GetPageObjectLayouter());
if (pPageObjectLayouter)
{
const Size aNewPreviewSize (mpLayouter->GetPageObjectLayouter()->GetSize(
PageObjectLayouter::Preview,
PageObjectLayouter::WindowCoordinateSystem));
if (maPreviewSize != aNewPreviewSize && GetPreviewCache())
{
mpPreviewCache->ChangeSize(aNewPreviewSize, true);
maPreviewSize = aNewPreviewSize;
}
}
// Iterate over all page objects and place them relative to the
// containing page.
model::PageEnumeration aPageEnumeration (
model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
while (aPageEnumeration.HasMoreElements())
{
model::SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement());
pDescriptor->SetBoundingBox(mpLayouter->GetPageObjectBox(pDescriptor->GetPageIndex()));
}
GetPageObjectPainter()->NotifyResize();
}
InvalidatePageObjectVisibilities ();
}
void SlideSorterView::InvalidatePageObjectVisibilities (void)
{
mbPageObjectVisibilitiesValid = false;
}
void SlideSorterView::DeterminePageObjectVisibilities (void)
{
SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
if (pWindow)
{
// Set this flag to true here so that an invalidate during the
// visibility calculation can correctly invalidate it again.
mbPageObjectVisibilitiesValid = true;
Rectangle aViewArea (pWindow->PixelToLogic(Rectangle(Point(0,0),pWindow->GetSizePixel())));
const Range aRange (mpLayouter->GetRangeOfVisiblePageObjects(aViewArea));
const Range aUnion(
::std::min(maVisiblePageRange.Min(), aRange.Min()),
::std::max(maVisiblePageRange.Max(), aRange.Max()));
// For page objects that just dropped off the visible area we
// decrease the priority of pending requests for preview bitmaps.
if (maVisiblePageRange != aRange)
mbPreciousFlagUpdatePending |= true;
model::SharedPageDescriptor pDescriptor;
for (int nIndex=aUnion.Min(); nIndex<=aUnion.Max(); nIndex++)
{
pDescriptor = mrModel.GetPageDescriptor(nIndex);
if (pDescriptor.get() != NULL)
SetState(
pDescriptor,
PageDescriptor::ST_Visible,
aRange.IsInside(nIndex));
}
// Broadcast a change of the set of visible page objects.
if (maVisiblePageRange != aRange)
{
maVisiblePageRange = aRange;
// Tell the listeners that the visibility of some objects has
// changed.
::std::vector<Link>& aChangeListeners (maVisibilityChangeListeners);
for (::std::vector<Link>::const_iterator
iLink(aChangeListeners.begin()),
iEnd(aChangeListeners.end());
iLink!=iEnd;
++iLink)
{
iLink->Call(NULL);
}
}
// Restore the mouse over state.
UpdatePageUnderMouse(true);
}
}
void SlideSorterView::UpdatePreciousFlags (void)
{
if (mbPreciousFlagUpdatePending)
{
mbPreciousFlagUpdatePending = false;
model::SharedPageDescriptor pDescriptor;
::boost::shared_ptr<cache::PageCache> pCache = GetPreviewCache();
sal_Int32 nPageCount (mrModel.GetPageCount());
for (int nIndex=0; nIndex<=nPageCount; ++nIndex)
{
pDescriptor = mrModel.GetPageDescriptor(nIndex);
if (pDescriptor.get() != NULL)
{
pCache->SetPreciousFlag(
pDescriptor->GetPage(),
maVisiblePageRange.IsInside(nIndex));
SSCD_SET_VISIBILITY(mrModel.GetDocument(), nIndex,
maVisiblePageRange.IsInside(nIndex));
}
else
{
// At least one cache entry can not be updated. Remember to
// repeat the whole updating later and leave the loop now.
mbPreciousFlagUpdatePending = true;
break;
}
}
}
}
bool SlideSorterView::SetOrientation (const Layouter::Orientation eOrientation)
{
if (meOrientation != eOrientation)
{
meOrientation = eOrientation;
return true;
}
else
return false;
}
Layouter::Orientation SlideSorterView::GetOrientation (void) const
{
return meOrientation;
}
void SlideSorterView::RequestRepaint (void)
{
SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
if (pWindow)
{
mpLayeredDevice->InvalidateAllLayers(
Rectangle(
pWindow->PixelToLogic(Point(0,0)),
pWindow->PixelToLogic(pWindow->GetSizePixel())));
pWindow->Invalidate();
}
}
void SlideSorterView::RequestRepaint (const model::SharedPageDescriptor& rpDescriptor)
{
if (rpDescriptor)
RequestRepaint(rpDescriptor->GetBoundingBox());
}
void SlideSorterView::RequestRepaint (const Rectangle& rRepaintBox)
{
SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
if (pWindow)
{
mpLayeredDevice->InvalidateAllLayers(rRepaintBox);
pWindow->Invalidate(rRepaintBox);
}
}
void SlideSorterView::RequestRepaint (const Region& rRepaintRegion)
{
SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
if (pWindow)
{
mpLayeredDevice->InvalidateAllLayers(rRepaintRegion);
pWindow->Invalidate(rRepaintRegion);
}
}
Rectangle SlideSorterView::GetModelArea (void)
{
return mpLayouter->GetTotalBoundingBox();
}
#ifdef DEBUG_TIMING
static ::canvas::tools::ElapsedTime gaTimer;
static const size_t gFrameTimeCount (10);
static size_t gFrameTimeIndex (0);
static ::std::vector<double> gFrameTimes (gFrameTimeCount, 0);
static double gFrameTimeSum (0);
static const Rectangle gFrameTimeBox (10,10,150,20);
static double gnLastFrameStart = 0;
#endif
void SlideSorterView::CompleteRedraw (
OutputDevice* pDevice,
const Region& rPaintArea,
sdr::contact::ViewObjectContactRedirector* pRedirector)
{
(void)pRedirector;
#ifdef DEBUG_TIMING
const double nStartTime (gaTimer.getElapsedTime());
OSL_TRACE("SlideSorterView::CompleteRedraw start at %f, %s",
nStartTime,
mnLockRedrawSmph ? "locked" : "");
#endif
if (pDevice == NULL || pDevice!=mrSlideSorter.GetContentWindow().get())
return;
// The parent implementation of CompleteRedraw is called only when
// painting is locked. We do all the painting ourself. When painting
// is locked the parent implementation keeps track of the repaint
// requests and later, when painting is unlocked, calls CompleteRedraw
// for all missed repaints.
if (mnLockRedrawSmph == 0)
{
mrSlideSorter.GetContentWindow()->IncrementLockCount();
if (mpLayeredDevice->HandleMapModeChange())
DeterminePageObjectVisibilities();
mpLayeredDevice->Repaint(rPaintArea);
mrSlideSorter.GetContentWindow()->DecrementLockCount();
}
else
{
maRedrawRegion.Union(rPaintArea);
}
#ifdef DEBUG_TIMING
const double nEndTime (gaTimer.getElapsedTime());
OSL_TRACE("SlideSorterView::CompleteRedraw end at %f after %fms", nEndTime, (nEndTime-nStartTime)*1000);
gFrameTimeSum -= gFrameTimes[gFrameTimeIndex];
gFrameTimes[gFrameTimeIndex] = nStartTime - gnLastFrameStart;
gnLastFrameStart = nStartTime;
gFrameTimeSum += gFrameTimes[gFrameTimeIndex];
gFrameTimeIndex = (gFrameTimeIndex+1) % gFrameTimeCount;
mrSlideSorter.GetContentWindow()->SetFillColor(COL_BLUE);
mrSlideSorter.GetContentWindow()->DrawRect(gFrameTimeBox);
mrSlideSorter.GetContentWindow()->SetTextColor(COL_WHITE);
mrSlideSorter.GetContentWindow()->DrawText(
gFrameTimeBox,
::rtl::OUString::valueOf(1 / (gFrameTimeSum / gFrameTimeCount)),
TEXT_DRAW_RIGHT | TEXT_DRAW_VCENTER);
// mrSlideSorter.GetContentWindow()->Invalidate(gFrameTimeBox);
#endif
}
void SlideSorterView::Paint (
OutputDevice& rDevice,
const Rectangle& rRepaintArea)
{
if ( ! mpPageObjectPainter)
if ( ! GetPageObjectPainter())
return;
// Update the page visibilities when they have been invalidated.
if ( ! mbPageObjectVisibilitiesValid)
DeterminePageObjectVisibilities();
if (mbPreciousFlagUpdatePending)
UpdatePreciousFlags();
if (mbIsRearrangePending)
Rearrange();
// Paint all page objects that are fully or partially inside the
// repaint region.
const Range aRange (mpLayouter->GetRangeOfVisiblePageObjects(rRepaintArea));
for (sal_Int32 nIndex=aRange.Min(); nIndex<=aRange.Max(); ++nIndex)
{
model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex));
if (!pDescriptor || ! pDescriptor->HasState(PageDescriptor::ST_Visible))
continue;
mpPageObjectPainter->PaintPageObject(rDevice, pDescriptor);
}
}
void SlideSorterView::ConfigurationChanged (
utl::ConfigurationBroadcaster* pBroadcaster,
sal_uInt32 nHint)
{
// Some changes of the configuration (some of the colors for example)
// may affect the previews. Throw away the old ones and create new ones.
cache::PageCacheManager::Instance()->InvalidateAllCaches();
::sd::View::ConfigurationChanged(pBroadcaster, nHint);
RequestRepaint();
}
::boost::shared_ptr<cache::PageCache> SlideSorterView::GetPreviewCache (void)
{
SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
if (pWindow && mpPreviewCache.get() == NULL)
{
mpPreviewCache.reset(
new cache::PageCache(
mpLayouter->GetPageObjectSize(),
false,
cache::SharedCacheContext(new ViewCacheContext(mrSlideSorter))));
}
return mpPreviewCache;
}
Pair SlideSorterView::GetVisiblePageRange (void)
{
if ( ! mbPageObjectVisibilitiesValid)
DeterminePageObjectVisibilities();
return maVisiblePageRange;
}
void SlideSorterView::AddVisibilityChangeListener (const Link& rListener)
{
if (::std::find (
maVisibilityChangeListeners.begin(),
maVisibilityChangeListeners.end(),
rListener) == maVisibilityChangeListeners.end())
{
maVisibilityChangeListeners.push_back(rListener);
}
}
void SlideSorterView::RemoveVisibilityChangeListener(const Link&rListener)
{
maVisibilityChangeListeners.erase (
::std::find (
maVisibilityChangeListeners.begin(),
maVisibilityChangeListeners.end(),
rListener));
}
ButtonBar& SlideSorterView::GetButtonBar (void) const
{
OSL_ASSERT(mpButtonBar);
return *mpButtonBar;
}
ToolTip& SlideSorterView::GetToolTip (void) const
{
OSL_ASSERT(mpToolTip);
return *mpToolTip;
}
void SlideSorterView::DragFinished (sal_Int8 nDropAction)
{
mrSlideSorter.GetController().GetClipboard().DragFinished(nDropAction);
View::DragFinished(nDropAction);
}
void SlideSorterView::Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint)
{
::sd::DrawDocShell* pDocShell = mrModel.GetDocument()->GetDocSh();
if (pDocShell!=NULL && pDocShell->IsEnableSetModified())
mbModelChangedWhileModifyEnabled = true;
::sd::View::Notify(rBroadcaster, rHint);
}
void SlideSorterView::UpdatePageUnderMouse (bool bAnimate)
{
::boost::shared_ptr<ScrollBar> pVScrollBar (mrSlideSorter.GetVerticalScrollBar());
::boost::shared_ptr<ScrollBar> pHScrollBar (mrSlideSorter.GetHorizontalScrollBar());
if ((pVScrollBar && pVScrollBar->IsVisible() && pVScrollBar->IsTracking())
|| (pHScrollBar && pHScrollBar->IsVisible() && pHScrollBar->IsTracking()))
{
// One of the scroll bars is tracking mouse movement. Do not
// highlight the slide under the mouse in this case.
SetPageUnderMouse(SharedPageDescriptor(),false);
return;
}
SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
if (pWindow && pWindow->IsVisible() && ! pWindow->IsMouseCaptured())
{
const Window::PointerState aPointerState (pWindow->GetPointerState());
const Rectangle aWindowBox (pWindow->GetPosPixel(), pWindow->GetSizePixel());
if (aWindowBox.IsInside(aPointerState.maPos))
{
UpdatePageUnderMouse (
aPointerState.maPos,
(aPointerState.mnState & MOUSE_LEFT)!=0,
bAnimate);
return;
}
}
SetPageUnderMouse(SharedPageDescriptor(),false);
}
void SlideSorterView::UpdatePageUnderMouse (
const Point& rMousePosition,
const bool bIsMouseButtonDown,
const bool bAnimate)
{
UpdatePageUnderMouse(
mrSlideSorter.GetController().GetPageAt(rMousePosition),
rMousePosition,
bIsMouseButtonDown,
bAnimate);
}
void SlideSorterView::UpdatePageUnderMouse (
const model::SharedPageDescriptor& rpDescriptor,
const Point& rMousePosition,
const bool bIsMouseButtonDown,
const bool bAnimate)
{
// Update the page under the mouse.
SetPageUnderMouse(rpDescriptor, bAnimate);
// Tell the button bar about the new mouse position.
SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition));
::boost::shared_ptr<ViewShell> pMainViewShell (mrSlideSorter.GetViewShellBase()->GetMainViewShell());
if (pMainViewShell
&& pMainViewShell->GetShellType()!=ViewShell::ST_DRAW)
{
const bool bIsMouseOverButtonBar (GetButtonBar().IsMouseOverBar());
GetButtonBar().ProcessMouseMotionEvent(rpDescriptor, aMouseModelPosition, bIsMouseButtonDown);
// Set the help text of the slide when the mouse was moved from the
// button bar back over the preview.
if (rpDescriptor
&& GetButtonBar().IsMouseOverBar() != bIsMouseOverButtonBar
&& bIsMouseOverButtonBar)
{
mpToolTip->ShowDefaultHelpText();
}
}
}
void SlideSorterView::SetPageUnderMouse (
const model::SharedPageDescriptor& rpDescriptor,
const bool bAnimate)
{
if (mpPageUnderMouse != rpDescriptor)
{
if (mpPageUnderMouse)
SetState(mpPageUnderMouse, PageDescriptor::ST_MouseOver, false, bAnimate);
mpPageUnderMouse = rpDescriptor;
if (mpPageUnderMouse)
SetState(mpPageUnderMouse, PageDescriptor::ST_MouseOver, true, bAnimate);
// Change the quick help text to display the name of the page under
// the mouse.
mpToolTip->SetPage(rpDescriptor);
}
}
bool SlideSorterView::SetState (
const model::SharedPageDescriptor& rpDescriptor,
const PageDescriptor::State eState,
const bool bStateValue,
const bool bAnimate)
{
model::SharedPageDescriptor pDescriptor (rpDescriptor);
if ( ! pDescriptor)
return false;
const bool bModified (pDescriptor->SetState(eState, bStateValue));
if ( ! bModified)
return false;
// When the page object is not visible (i.e. not on the screen then
// nothing has to be painted.
if (pDescriptor->HasState(PageDescriptor::ST_Visible))
{
// For most states a change of that state leads to visible
// difference and we have to request a repaint.
if (eState != PageDescriptor::ST_WasSelected)
RequestRepaint(pDescriptor);
}
::boost::shared_ptr<ViewShell> pMainViewShell(mrSlideSorter.GetViewShellBase()->GetMainViewShell());
if (pMainViewShell
&& pMainViewShell->GetShellType()!=ViewShell::ST_DRAW)
{
// Fade in or out the buttons.
if (eState == PageDescriptor::ST_MouseOver)
{
if (bStateValue)
GetButtonBar().RequestFadeIn(rpDescriptor, bAnimate);
else
GetButtonBar().RequestFadeOut(rpDescriptor, bAnimate);
}
}
return bModified;
}
::boost::shared_ptr<PageObjectPainter> SlideSorterView::GetPageObjectPainter (void)
{
if ( ! mpPageObjectPainter)
mpPageObjectPainter.reset(new PageObjectPainter(mrSlideSorter));
return mpPageObjectPainter;
}
::boost::shared_ptr<LayeredDevice> SlideSorterView::GetLayeredDevice (void) const
{
return mpLayeredDevice;
}
//===== SlideSorterView::DrawLock =============================================
SlideSorterView::DrawLock::DrawLock (
view::SlideSorterView& rView,
const SharedSdWindow& rpWindow)
: mrView(rView),
mpWindow(rpWindow)
{
if (mrView.mnLockRedrawSmph == 0)
mrView.maRedrawRegion.SetEmpty();
++mrView.mnLockRedrawSmph;
}
SlideSorterView::DrawLock::DrawLock (SlideSorter& rSlideSorter)
: mrView(rSlideSorter.GetView()),
mpWindow(rSlideSorter.GetContentWindow())
{
if (mrView.mnLockRedrawSmph == 0)
mrView.maRedrawRegion.SetEmpty();
++mrView.mnLockRedrawSmph;
}
SlideSorterView::DrawLock::~DrawLock (void)
{
OSL_ASSERT(mrView.mnLockRedrawSmph>0);
--mrView.mnLockRedrawSmph;
if (mrView.mnLockRedrawSmph == 0)
if (mpWindow)
{
mpWindow->Invalidate(mrView.maRedrawRegion);
mpWindow->Update();
}
}
void SlideSorterView::DrawLock::Dispose (void)
{
mpWindow.reset();
}
} } } // end of namespace ::sd::slidesorter::view