| /************************************************************** |
| * |
| * 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 |