diff options
Diffstat (limited to '')
-rw-r--r-- | sd/source/ui/slidesorter/view/SlideSorterView.cxx | 856 |
1 files changed, 856 insertions, 0 deletions
diff --git a/sd/source/ui/slidesorter/view/SlideSorterView.cxx b/sd/source/ui/slidesorter/view/SlideSorterView.cxx new file mode 100644 index 000000000..390541e37 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlideSorterView.cxx @@ -0,0 +1,856 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <view/SlideSorterView.hxx> + +#include <SlideSorter.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/SlsToolTip.hxx> +#include <controller/SlideSorterController.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 <PaneDockingWindow.hxx> + +#include <sdpage.hxx> +#include <Window.hxx> + +#include <comphelper/lok.hxx> +#include <osl/diagnose.h> +#include <vcl/svapp.hxx> +#include <vcl/scrbar.hxx> +#include <vcl/settings.hxx> +#include <vcl/graphicfilter.hxx> + +#include <algorithm> + +//#define DEBUG_TIMING +#ifdef DEBUG_TIMING +#include <memory> +#include <vector> +#endif + +using namespace ::sd::slidesorter::model; +using namespace ::drawinglayer::primitive2d; + +namespace sd::slidesorter::view { + +namespace { + /** Wrapper around the SlideSorterView that supports the IPainter + interface and that allows the LayeredDevice to hold the + SlideSorterView (held as unique_ptr by the SlideSorter) as + shared_ptr. + */ + class Painter : public ILayerPainter + { + public: + explicit Painter (SlideSorterView& rView) : mrView(rView) {} + + virtual void Paint (OutputDevice& rDevice, const ::tools::Rectangle& rRepaintArea) override + { + mrView.Paint(rDevice,rRepaintArea); + } + + virtual void SetLayerInvalidator (const SharedILayerInvalidator&) override {} + + private: + SlideSorterView& mrView; + }; +} + +namespace { + +class BackgroundPainter + : public ILayerPainter +{ +public: + explicit BackgroundPainter (const Color& rBackgroundColor) : maBackgroundColor(rBackgroundColor) {} + BackgroundPainter(const BackgroundPainter&) = delete; + BackgroundPainter& operator=(const BackgroundPainter&) = delete; + + virtual void Paint (OutputDevice& rDevice, const ::tools::Rectangle& rRepaintArea) override + { + rDevice.SetFillColor(maBackgroundColor); + rDevice.SetLineColor(); + rDevice.DrawRect(rRepaintArea); + } + + virtual void SetLayerInvalidator (const SharedILayerInvalidator&) override {} + + void SetColor (const Color& rColor) { maBackgroundColor = rColor; } + +private: + Color maBackgroundColor; +}; + +} + +SlideSorterView::SlideSorterView (SlideSorter& rSlideSorter) + : ::sd::View ( + *rSlideSorter.GetModel().GetDocument(), + rSlideSorter.GetContentWindow()->GetOutDev(), + rSlideSorter.GetViewShell()), + mrSlideSorter(rSlideSorter), + mrModel(rSlideSorter.GetModel()), + mbIsDisposed(false), + mpLayouter (new Layouter(rSlideSorter.GetContentWindow(), rSlideSorter.GetTheme())), + mbPageObjectVisibilitiesValid (false), + mpLayeredDevice(std::make_shared<LayeredDevice>(rSlideSorter.GetContentWindow())), + maVisiblePageRange(-1,-1), + maPreviewSize(0,0), + mbPreciousFlagUpdatePending(true), + meOrientation(Layouter::GRID), + mpBackgroundPainter( + std::make_shared<BackgroundPainter>(mrSlideSorter.GetTheme()->GetColor(Theme::Color_Background))), + mpToolTip(new ToolTip(mrSlideSorter)), + mbIsRearrangePending(true) +{ + // Hide the page that contains the page objects. + SetPageVisible (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 = std::make_shared<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() +{ + if ( ! mbIsDisposed) + { + OSL_ASSERT(mbIsDisposed); + Dispose(); + } +} + +void SlideSorterView::Init() +{ + HandleModelChange(); +} + +void SlideSorterView::Dispose() +{ + mpLayeredDevice->Dispose(); + mpPreviewCache.reset(); + + SetPageUnderMouse(SharedPageDescriptor()); + + // 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.use_count() == 1); + mpLayeredDevice.reset(); + + mbIsDisposed = true; +} + +sal_Int32 SlideSorterView::GetPageIndexAtPoint (const Point& rWindowPosition) const +{ + sal_Int32 nIndex (-1); + + sd::Window *pWindow (mrSlideSorter.GetContentWindow().get()); + 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() { return *mpLayouter; } + +void SlideSorterView::ModelHasChanged() +{ + // Ignore this call. Rely on hints sent by the model to get informed of + // model changes. +} + +void SlideSorterView::PreModelChange() +{ + // Reset the slide under the mouse. It will be re-set in PostModelChange(). + SetPageUnderMouse(SharedPageDescriptor()); +} + +void SlideSorterView::PostModelChange() +{ + // In PreModelChange() the page objects have been released. Here we + // create new ones. + ::osl::MutexGuard aGuard (mrModel.GetMutex()); + + 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() +{ + PreModelChange (); + PostModelChange(); +} + +void SlideSorterView::HandleDrawModeChange() +{ + // 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(); + + RequestRepaint(); +} + +void SlideSorterView::HandleDataChangeEvent() +{ + GetPageObjectPainter()->SetTheme(mrSlideSorter.GetTheme()); + + // Update the color used by the background painter. + std::shared_ptr<BackgroundPainter> pPainter ( + std::dynamic_pointer_cast<BackgroundPainter>(mpBackgroundPainter)); + if (pPainter) + pPainter->SetColor(mrSlideSorter.GetTheme()->GetColor(Theme::Color_Background)); + + RequestRepaint(); +} + +void SlideSorterView::Resize() +{ + UpdateOrientation(); + + mpLayeredDevice->Resize(); + RequestRearrange(); +} + +void SlideSorterView::RequestRearrange() +{ + mbIsRearrangePending = true; + Rearrange(); +} + +void SlideSorterView::Rearrange() +{ + if ( ! mbIsRearrangePending) + return; + if (mrModel.GetPageCount() <= 0) + return; + + sd::Window *pWindow (mrSlideSorter.GetContentWindow().get()); + if ( ! pWindow) + return; + const Size aWindowSize (pWindow->GetSizePixel()); + if (aWindowSize.IsEmpty()) + return; + + const bool bRearrangeSuccess ( + mpLayouter->Rearrange ( + meOrientation, + aWindowSize, + mrModel.GetPageDescriptor(0)->GetPage()->GetSize(), + mrModel.GetPageCount())); + if (bRearrangeSuccess) + { + mbIsRearrangePending = false; + Layout(); + UpdatePageUnderMouse(); + // RequestRepaint(); + } +} + +void SlideSorterView::UpdateOrientation() +{ + // 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. + vcl::Window* pWindow = mrSlideSorter.GetContentWindow(); + PaneDockingWindow* pDockingWindow = nullptr; + while (pWindow!=nullptr && pDockingWindow==nullptr) + { + pDockingWindow = dynamic_cast<PaneDockingWindow*>(pWindow); + pWindow = pWindow->GetParent(); + } + + if (pDockingWindow != nullptr) + { + const ::tools::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 () +{ + sd::Window *pWindow (mrSlideSorter.GetContentWindow().get()); + if (pWindow) + { + // Set the model area, i.e. the smallest rectangle that includes all + // page objects. + const ::tools::Rectangle aViewBox (mpLayouter->GetTotalBoundingBox()); + pWindow->SetViewOrigin (aViewBox.TopLeft()); + pWindow->SetViewSize (aViewBox.GetSize()); + + std::shared_ptr<PageObjectLayouter> pPageObjectLayouter( + mpLayouter->GetPageObjectLayouter()); + if (pPageObjectLayouter) + { + const Size aNewPreviewSize (mpLayouter->GetPageObjectLayouter()->GetPreviewSize()); + if (maPreviewSize != aNewPreviewSize && GetPreviewCache()) + { + mpPreviewCache->ChangeSize(aNewPreviewSize, Bitmap::HasFastScale()); + 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(), false)); + } + } + + InvalidatePageObjectVisibilities (); +} + +void SlideSorterView::InvalidatePageObjectVisibilities() +{ + mbPageObjectVisibilitiesValid = false; +} + +void SlideSorterView::DeterminePageObjectVisibilities() +{ + sd::Window *pWindow (mrSlideSorter.GetContentWindow().get()); + if (!pWindow) + return; + + // Set this flag to true here so that an invalidate during the + // visibility calculation can correctly invalidate it again. + mbPageObjectVisibilitiesValid = true; + + ::tools::Rectangle aViewArea (pWindow->PixelToLogic(::tools::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 (::tools::Long nIndex=aUnion.Min(); nIndex<=aUnion.Max(); nIndex++) + { + pDescriptor = mrModel.GetPageDescriptor(nIndex); + if (pDescriptor) + SetState( + pDescriptor, + PageDescriptor::ST_Visible, + aRange.Contains(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<LinkParamNone*,void>>& aChangeListeners (maVisibilityChangeListeners); + for (const auto& rLink : aChangeListeners) + { + rLink.Call(nullptr); + } + } + + // Restore the mouse over state. + UpdatePageUnderMouse(); +} + +void SlideSorterView::UpdatePreciousFlags() +{ + if (!mbPreciousFlagUpdatePending) + return; + + mbPreciousFlagUpdatePending = false; + + model::SharedPageDescriptor pDescriptor; + std::shared_ptr<cache::PageCache> pCache = GetPreviewCache(); + sal_Int32 nPageCount (mrModel.GetPageCount()); + + for (int nIndex=0; nIndex<=nPageCount; ++nIndex) + { + pDescriptor = mrModel.GetPageDescriptor(nIndex); + if (pDescriptor) + { + pCache->SetPreciousFlag( + pDescriptor->GetPage(), + maVisiblePageRange.Contains(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; +} + +void SlideSorterView::RequestRepaint() +{ + sd::Window *pWindow (mrSlideSorter.GetContentWindow().get()); + if (pWindow) + { + mpLayeredDevice->InvalidateAllLayers( + ::tools::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 ::tools::Rectangle& rRepaintBox) +{ + sd::Window *pWindow (mrSlideSorter.GetContentWindow().get()); + if (pWindow) + { + mpLayeredDevice->InvalidateAllLayers(rRepaintBox); + pWindow->Invalidate(rRepaintBox); + } +} + +void SlideSorterView::RequestRepaint (const vcl::Region& rRepaintRegion) +{ + sd::Window *pWindow (mrSlideSorter.GetContentWindow().get()); + if (pWindow) + { + mpLayeredDevice->InvalidateAllLayers(rRepaintRegion); + pWindow->Invalidate(rRepaintRegion); + } +} + +::tools::Rectangle SlideSorterView::GetModelArea() const +{ + 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 ::tools::Rectangle gFrameTimeBox (10,10,150,20); +static double gnLastFrameStart = 0; +#endif + +void SlideSorterView::CompleteRedraw ( + OutputDevice* pDevice, + const vcl::Region& rPaintArea, + sdr::contact::ViewObjectContactRedirector* pRedirector) +{ + (void)pRedirector; + + if (comphelper::LibreOfficeKit::isActive()) + return; + + if (pDevice == nullptr || pDevice!=mrSlideSorter.GetContentWindow()->GetOutDev()) + return; + +#ifdef DEBUG_TIMING + const double nStartTime (gaTimer.getElapsedTime()); + SAL_INFO("sd.timing", "SlideSorterView::CompleteRedraw start" << (mnLockRedrawSmph ? " locked" : "")); +#endif + + // 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) + { + if (mpLayeredDevice->HandleMapModeChange()) + DeterminePageObjectVisibilities(); + mpLayeredDevice->Repaint(rPaintArea); + } + else + { + maRedrawRegion.Union(rPaintArea); + } + +#ifdef DEBUG_TIMING + const double nEndTime (gaTimer.getElapsedTime()); + SAL_INFO("sd.timing", "SlideSorterView::CompleteRedraw end after " << (nEndTime-nStartTime)*1000 << " ms"); + 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, + OUString::number(1 / (gFrameTimeSum / gFrameTimeCount)), + DrawTextFlags::Right | DrawTextFlags::VCenter); + // mrSlideSorter.GetContentWindow()->Invalidate(gFrameTimeBox); +#endif +} + +void SlideSorterView::Paint ( + OutputDevice& rDevice, + const ::tools::Rectangle& rRepaintArea) +{ + if (rRepaintArea.IsEmpty()) + return; + + 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)); + // Try to prefetch all graphics from the pages to paint. This will be done + // in threads to be more efficient than loading them on-demand one by one. + std::vector<Graphic*> graphics; + for (::tools::Long nIndex=aRange.Min(); nIndex<=aRange.Max(); ++nIndex) + { + model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex)); + if (!pDescriptor || ! pDescriptor->HasState(PageDescriptor::ST_Visible)) + continue; + pDescriptor->GetPage()->getGraphicsForPrefetch(graphics); + } + // Handle also one page before and after to have those in advance on scrolling. + for (::tools::Long nIndex : { aRange.Min() - 1, aRange.Max() + 1 }) + { + model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex)); + if (!pDescriptor) + continue; + pDescriptor->GetPage()->getGraphicsForPrefetch(graphics); + } + if(graphics.size() > 1) // threading does not help with loading just one + GraphicFilter::GetGraphicFilter().MakeGraphicsAvailableThreaded(graphics); + + for (::tools::Long 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, + ConfigurationHints 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(); + +} + +std::shared_ptr<cache::PageCache> const & SlideSorterView::GetPreviewCache() +{ + sd::Window *pWindow (mrSlideSorter.GetContentWindow().get()); + if (pWindow && mpPreviewCache == nullptr) + { + mpPreviewCache = + std::make_shared<cache::PageCache>( + mpLayouter->GetPageObjectSize(), + Bitmap::HasFastScale(), + std::make_shared<ViewCacheContext>(mrSlideSorter)); + } + + return mpPreviewCache; +} + +Range const & SlideSorterView::GetVisiblePageRange() +{ + if ( ! mbPageObjectVisibilitiesValid) + DeterminePageObjectVisibilities(); + return maVisiblePageRange; +} + +void SlideSorterView::AddVisibilityChangeListener (const Link<LinkParamNone*,void>& rListener) +{ + if (::std::find ( + maVisibilityChangeListeners.begin(), + maVisibilityChangeListeners.end(), + rListener) == maVisibilityChangeListeners.end()) + { + maVisibilityChangeListeners.push_back(rListener); + } +} + +void SlideSorterView::RemoveVisibilityChangeListener(const Link<LinkParamNone*,void>&rListener) +{ + maVisibilityChangeListeners.erase ( + ::std::find ( + maVisibilityChangeListeners.begin(), + maVisibilityChangeListeners.end(), + rListener)); +} + +ToolTip& SlideSorterView::GetToolTip() const +{ + OSL_ASSERT(mpToolTip); + return *mpToolTip; +} + +void SlideSorterView::DragFinished (sal_Int8 nDropAction) +{ + mrSlideSorter.GetController().GetClipboard().DragFinished(nDropAction); + + View::DragFinished(nDropAction); +} + +void SlideSorterView::UpdatePageUnderMouse () +{ + VclPtr<ScrollBar> pVScrollBar (mrSlideSorter.GetVerticalScrollBar()); + VclPtr<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()); + return; + } + + sd::Window *pWindow (mrSlideSorter.GetContentWindow().get()); + if (pWindow && pWindow->IsVisible() && ! pWindow->IsMouseCaptured()) + { + const Window::PointerState aPointerState (pWindow->GetPointerState()); + const ::tools::Rectangle aWindowBox (pWindow->GetPosPixel(), pWindow->GetSizePixel()); + if (aWindowBox.Contains(aPointerState.maPos)) + { + UpdatePageUnderMouse(aPointerState.maPos); + return; + } + } + + SetPageUnderMouse(SharedPageDescriptor()); +} + +void SlideSorterView::UpdatePageUnderMouse ( + const Point& rMousePosition) +{ + SetPageUnderMouse(mrSlideSorter.GetController().GetPageAt(rMousePosition)); +} + +void SlideSorterView::SetPageUnderMouse ( + const model::SharedPageDescriptor& rpDescriptor) +{ + if (mpPageUnderMouse == rpDescriptor) + return; + + if (mpPageUnderMouse) + SetState(mpPageUnderMouse, PageDescriptor::ST_MouseOver, false); + + mpPageUnderMouse = rpDescriptor; + + if (mpPageUnderMouse) + SetState(mpPageUnderMouse, PageDescriptor::ST_MouseOver, true); + + // 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) +{ + if ( ! rpDescriptor) + return false; + + const bool bModified (rpDescriptor->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 (rpDescriptor->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(rpDescriptor); + } + + return bModified; +} + +std::shared_ptr<PageObjectPainter> const & SlideSorterView::GetPageObjectPainter() +{ + if ( ! mpPageObjectPainter) + mpPageObjectPainter = std::make_shared<PageObjectPainter>(mrSlideSorter); + return mpPageObjectPainter; +} + +//===== SlideSorterView::DrawLock ============================================= + +SlideSorterView::DrawLock::DrawLock (SlideSorter const & rSlideSorter) + : mrView(rSlideSorter.GetView()), + mpWindow(rSlideSorter.GetContentWindow()) +{ + if (mrView.mnLockRedrawSmph == 0) + mrView.maRedrawRegion.SetEmpty(); + ++mrView.mnLockRedrawSmph; +} + +SlideSorterView::DrawLock::~DrawLock() +{ + OSL_ASSERT(mrView.mnLockRedrawSmph>0); + --mrView.mnLockRedrawSmph; + if (mrView.mnLockRedrawSmph == 0) + if (mpWindow) + { + mpWindow->Invalidate(mrView.maRedrawRegion); + } +} + +void SlideSorterView::DrawLock::Dispose() +{ + mpWindow.reset(); +} + +} // end of namespace ::sd::slidesorter::view + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |