1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "precompiled_sd.hxx"
25 
26 #include "view/SlideSorterView.hxx"
27 
28 #include "ViewShellBase.hxx"
29 #include "SlideSorter.hxx"
30 #include "SlideSorterViewShell.hxx"
31 #include "ViewShell.hxx"
32 #include "SlsViewCacheContext.hxx"
33 #include "SlsLayeredDevice.hxx"
34 #include "view/SlsLayouter.hxx"
35 #include "view/SlsPageObjectLayouter.hxx"
36 #include "view/SlsPageObjectPainter.hxx"
37 #include "view/SlsILayerPainter.hxx"
38 #include "view/SlsButtonBar.hxx"
39 #include "view/SlsToolTip.hxx"
40 #include "controller/SlideSorterController.hxx"
41 #include "controller/SlsProperties.hxx"
42 #include "controller/SlsClipboard.hxx"
43 #include "model/SlideSorterModel.hxx"
44 #include "model/SlsPageEnumerationProvider.hxx"
45 #include "model/SlsPageDescriptor.hxx"
46 #include "cache/SlsPageCache.hxx"
47 #include "cache/SlsPageCacheManager.hxx"
48 #include "cache/SlsCacheContext.hxx"
49 #include "taskpane/SlideSorterCacheDisplay.hxx"
50 #include "DrawDocShell.hxx"
51 #include "PaneDockingWindow.hxx"
52 
53 #include "drawdoc.hxx"
54 #include "sdpage.hxx"
55 #include "Window.hxx"
56 #include "sdresid.hxx"
57 #include "glob.hrc"
58 
59 #include <svl/itempool.hxx>
60 #include <svx/svdpagv.hxx>
61 #include <svx/svdopage.hxx>
62 #include <svx/xlndsit.hxx>
63 #include <svx/xlnclit.hxx>
64 #include <vcl/svapp.hxx>
65 #include <vcl/scrbar.hxx>
66 #include <tools/poly.hxx>
67 #include <vcl/lineinfo.hxx>
68 #include <algorithm>
69 #include <svx/sdrpagewindow.hxx>
70 #include <svl/itempool.hxx>
71 #include <basegfx/matrix/b2dhommatrix.hxx>
72 #include <basegfx/polygon/b2dpolygontools.hxx>
73 #include <basegfx/polygon/b2dpolygon.hxx>
74 #include <drawinglayer/geometry/viewinformation2d.hxx>
75 #include <canvas/elapsedtime.hxx>
76 
77 //#define DEBUG_TIMING
78 #include <svl/itempool.hxx>
79 #ifdef DEBUG_TIMING
80 #include <vector>
81 #endif
82 #include <boost/foreach.hpp>
83 
84 
85 using namespace std;
86 using namespace ::sd::slidesorter::model;
87 using namespace ::drawinglayer::primitive2d;
88 
89 
90 namespace sd { namespace slidesorter { namespace view {
91 
92 namespace {
93     /** Wrapper around the SlideSorterView that supports the IPainter
94         interface and that allows the LayeredDevice to hold the
95         SlideSorterView (held as scoped_ptr by the SlideSorter) as
96         shared_ptr.
97     */
98     class Painter : public ILayerPainter
99     {
100     public:
Painter(SlideSorterView & rView)101         Painter (SlideSorterView& rView) : mrView(rView) {}
~Painter(void)102         virtual ~Painter (void) {}
103 
Paint(OutputDevice & rDevice,const Rectangle & rRepaintArea)104         virtual void Paint (OutputDevice& rDevice, const Rectangle& rRepaintArea)
105         {
106             mrView.Paint(rDevice,rRepaintArea);
107         }
108 
SetLayerInvalidator(const SharedILayerInvalidator &)109         virtual void SetLayerInvalidator (const SharedILayerInvalidator&) {}
110 
111     private:
112         SlideSorterView& mrView;
113     };
114 }
115 
116 
117 
118 class BackgroundPainter
119     : public ILayerPainter,
120       public ::boost::noncopyable
121 {
122 public:
BackgroundPainter(const Color aBackgroundColor)123     BackgroundPainter (const Color aBackgroundColor) : maBackgroundColor(aBackgroundColor) {}
~BackgroundPainter(void)124     virtual ~BackgroundPainter (void) {}
125 
Paint(OutputDevice & rDevice,const Rectangle & rRepaintArea)126     virtual void Paint (OutputDevice& rDevice, const Rectangle& rRepaintArea)
127     {
128         rDevice.SetFillColor(maBackgroundColor);
129         rDevice.SetLineColor();
130         rDevice.DrawRect(rRepaintArea);
131     }
132 
SetLayerInvalidator(const SharedILayerInvalidator &)133     virtual void SetLayerInvalidator (const SharedILayerInvalidator&) {}
134 
SetColor(const Color aColor)135     void SetColor (const Color aColor) { maBackgroundColor = aColor; }
136 
137 private:
138     Color maBackgroundColor;
139 };
140 
141 
142 
143 TYPEINIT1(SlideSorterView, ::sd::View);
144 
SlideSorterView(SlideSorter & rSlideSorter)145 SlideSorterView::SlideSorterView (SlideSorter& rSlideSorter)
146     : ::sd::View (
147           rSlideSorter.GetModel().GetDocument(),
148           rSlideSorter.GetContentWindow().get(),
149           rSlideSorter.GetViewShell()),
150       mrSlideSorter(rSlideSorter),
151       mrModel(rSlideSorter.GetModel()),
152       mbIsDisposed(false),
153       mpLayouter (new Layouter(rSlideSorter.GetContentWindow(), rSlideSorter.GetTheme())),
154       mbPageObjectVisibilitiesValid (false),
155       mpPreviewCache(),
156       mpLayeredDevice(new LayeredDevice(rSlideSorter.GetContentWindow())),
157       maVisiblePageRange(-1,-1),
158       mbModelChangedWhileModifyEnabled(true),
159       maPreviewSize(0,0),
160       mbPreciousFlagUpdatePending(true),
161       meOrientation(Layouter::GRID),
162       mpProperties(rSlideSorter.GetProperties()),
163       mpPageUnderMouse(),
164       mnButtonUnderMouse(-1),
165       mpPageObjectPainter(),
166       mpSelectionPainter(),
167       mpBackgroundPainter(
168           new BackgroundPainter(mrSlideSorter.GetTheme()->GetColor(Theme::Color_Background))),
169       mpButtonBar(new ButtonBar(mrSlideSorter)),
170       mpToolTip(new ToolTip(mrSlideSorter)),
171       mbIsRearrangePending(true),
172       maVisibilityChangeListeners()
173 {
174 	// Hide the page that contains the page objects.
175     SetPageVisible (sal_False);
176 
177     // Register the background painter on level 1 to avoid the creation of a
178     // background buffer.
179     mpLayeredDevice->RegisterPainter(mpBackgroundPainter, 1);
180 
181     // Wrap a shared_ptr-held-wrapper around this view and register it as
182     // painter at the layered device.  There is no explicit destruction: in
183     // the SlideSorterView destructor the layered device is destroyed and
184     // with it the only reference to the wrapper which therefore is also
185     // destroyed.
186     SharedILayerPainter pPainter (new Painter(*this));
187 
188     // The painter is placed on level 1 to avoid buffering.  This should be
189     // a little faster during animations because the previews are painted
190     // directly into the window, not via the buffer.
191     mpLayeredDevice->RegisterPainter(pPainter, 1);
192 }
193 
194 
195 
196 
~SlideSorterView(void)197 SlideSorterView::~SlideSorterView (void)
198 {
199     if ( ! mbIsDisposed)
200     {
201         OSL_ASSERT(mbIsDisposed);
202         Dispose();
203     }
204 }
205 
206 
207 
208 
Init(void)209 void SlideSorterView::Init (void)
210 {
211     HandleModelChange();
212 }
213 
214 
215 
216 
Dispose(void)217 void SlideSorterView::Dispose (void)
218 {
219     mpSelectionPainter.reset();
220 
221     mpLayeredDevice->Dispose();
222     mpPreviewCache.reset();
223 
224     SetPageUnderMouse(SharedPageDescriptor(),false);
225 
226 	// Hide the page to avoid problems in the view when deleting
227 	// visualized objects
228 	HideSdrPage();
229 
230     // Deletion of the objects and the page will be done in SdrModel
231 	// destructor (as long as objects and pages are added)
232 
233     OSL_ASSERT(mpLayeredDevice.unique());
234     mpLayeredDevice.reset();
235 
236     mbIsDisposed = true;
237 }
238 
239 
240 
241 
GetPageIndexAtPoint(const Point & rWindowPosition) const242 sal_Int32 SlideSorterView::GetPageIndexAtPoint (const Point& rWindowPosition) const
243 {
244     sal_Int32 nIndex (-1);
245 
246     SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
247     if (pWindow)
248     {
249         nIndex = mpLayouter->GetIndexAtPoint(pWindow->PixelToLogic(rWindowPosition), false, false);
250 
251         // Clip the page index against the page count.
252         if (nIndex >= mrModel.GetPageCount())
253             nIndex = -1;
254     }
255 
256     return nIndex;
257 }
258 
259 
260 
261 
GetLayouter(void)262 Layouter& SlideSorterView::GetLayouter (void)
263 {
264     return *mpLayouter.get();
265 }
266 
267 
268 
269 
ModelHasChanged(void)270 void SlideSorterView::ModelHasChanged (void)
271 {
272     // Ignore this call.  Rely on hints sent by the model to get informed of
273     // model changes.
274 }
275 
276 
277 
278 
LocalModelHasChanged(void)279 void SlideSorterView::LocalModelHasChanged(void)
280 {
281     mbModelChangedWhileModifyEnabled = false;
282 
283     // First call our base class.
284     View::ModelHasChanged ();
285 }
286 
287 
288 
289 
PreModelChange(void)290 void SlideSorterView::PreModelChange (void)
291 {
292     // Reset the slide under the mouse.  It will be re-set in PostModelChange().
293     SetPageUnderMouse(SharedPageDescriptor());
294 }
295 
296 
297 
298 
PostModelChange(void)299 void SlideSorterView::PostModelChange (void)
300 {
301     // In PreModelChange() the page objects have been released.  Here we
302     // create new ones.
303     ::osl::MutexGuard aGuard (mrModel.GetMutex());
304 
305     model::PageEnumeration aPageEnumeration (
306         model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
307 
308     // The new page objects have to be scaled and positioned.
309     RequestRearrange();
310     RequestRepaint();
311 }
312 
313 
314 
315 
316 /** At the moment for every model change all page objects are destroyed and
317     re-created again.  This can be optimized by accepting hints that
318     describe the type of change so that existing page objects can be
319     reused.
320 */
HandleModelChange(void)321 void SlideSorterView::HandleModelChange (void)
322 {
323     PreModelChange ();
324     PostModelChange();
325 }
326 
327 
328 
329 
HandleDrawModeChange(void)330 void SlideSorterView::HandleDrawModeChange (void)
331 {
332     // Replace the preview cache with a new and empty one.  The
333     // PreviewRenderer that is used by the cache is replaced by this as
334     // well.
335     mpPreviewCache.reset();
336     GetPreviewCache()->InvalidateCache(true);
337 
338     RequestRepaint();
339 }
340 
341 
342 
343 
HandleDataChangeEvent(void)344 void SlideSorterView::HandleDataChangeEvent (void)
345 {
346     GetPageObjectPainter()->SetTheme(mrSlideSorter.GetTheme());
347 
348     // Update the color used by the background painter.
349     ::boost::shared_ptr<BackgroundPainter> pPainter (
350         ::boost::dynamic_pointer_cast<BackgroundPainter>(mpBackgroundPainter));
351     if (pPainter)
352         pPainter->SetColor(mrSlideSorter.GetTheme()->GetColor(Theme::Color_Background));
353 
354     if (mpButtonBar)
355         mpButtonBar->HandleDataChangeEvent();
356 
357     RequestRepaint();
358 }
359 
360 
361 
362 
Resize(void)363 void SlideSorterView::Resize (void)
364 {
365     UpdateOrientation();
366 
367     mpLayeredDevice->Resize();
368     RequestRearrange();
369 }
370 
371 
372 
373 
RequestRearrange(void)374 void SlideSorterView::RequestRearrange (void)
375 {
376     mbIsRearrangePending = true;
377     Rearrange();
378 }
379 
380 
381 
382 
Rearrange(void)383 void SlideSorterView::Rearrange (void)
384 {
385     if ( ! mbIsRearrangePending)
386         return;
387 	if (mrModel.GetPageCount() <= 0)
388         return;
389 
390     SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
391 	if ( ! pWindow)
392         return;
393     const Size aWindowSize (pWindow->GetSizePixel());
394     if (aWindowSize.Width()<=0 || aWindowSize.Height()<=0)
395         return;
396 
397     const bool bRearrangeSuccess (
398         mpLayouter->Rearrange (
399             meOrientation,
400             aWindowSize,
401             mrModel.GetPageDescriptor(0)->GetPage()->GetSize(),
402             mrModel.GetPageCount()));
403     if (bRearrangeSuccess)
404     {
405         mbIsRearrangePending = false;
406         Layout();
407         UpdatePageUnderMouse(false);
408         //        RequestRepaint();
409 	}
410 }
411 
412 
413 
414 
UpdateOrientation(void)415 void SlideSorterView::UpdateOrientation (void)
416 {
417     // The layout of slides depends on whether the slide sorter is
418     // displayed in the center or the side pane.
419     if (mrSlideSorter.GetViewShell()->IsMainViewShell())
420         SetOrientation(Layouter::GRID);
421     else
422     {
423         // Get access to the docking window.
424         ::Window* pWindow = mrSlideSorter.GetContentWindow().get();
425         PaneDockingWindow* pDockingWindow = NULL;
426         while (pWindow!=NULL && pDockingWindow==NULL)
427         {
428             pDockingWindow = dynamic_cast<PaneDockingWindow*>(pWindow);
429             pWindow = pWindow->GetParent();
430         }
431 
432         if (pDockingWindow != NULL)
433         {
434             const long nScrollBarSize (
435                 Application::GetSettings().GetStyleSettings().GetScrollBarSize());
436             switch (pDockingWindow->GetOrientation())
437             {
438                 case PaneDockingWindow::HorizontalOrientation:
439                     if (SetOrientation(Layouter::HORIZONTAL))
440                     {
441                         const Range aRange (mpLayouter->GetValidVerticalSizeRange());
442                         pDockingWindow->SetValidSizeRange(Range(
443                             aRange.Min() + nScrollBarSize,
444                             aRange.Max() + nScrollBarSize));
445                     }
446                     break;
447 
448                 case PaneDockingWindow::VerticalOrientation:
449                     if (SetOrientation(Layouter::VERTICAL))
450                     {
451                         const Range aRange (mpLayouter->GetValidHorizontalSizeRange());
452                         pDockingWindow->SetValidSizeRange(Range(
453                             aRange.Min() + nScrollBarSize,
454                             aRange.Max() + nScrollBarSize));
455                     }
456                     break;
457 
458                 case PaneDockingWindow::UnknownOrientation:
459                     if (SetOrientation(Layouter::GRID))
460                     {
461                         const sal_Int32 nAdditionalSize (10);
462                         pDockingWindow->SetMinOutputSizePixel(Size(
463                             mpLayouter->GetValidHorizontalSizeRange().Min()
464                                 + nScrollBarSize
465                                 + nAdditionalSize,
466                             mpLayouter->GetValidVerticalSizeRange().Min()
467                                 + nScrollBarSize
468                                 + nAdditionalSize));
469                     }
470                     return;
471             }
472         }
473         else
474         {
475             // We are not placed in a docking window.  One possible reason
476             // is that the slide sorter is temporarily into a cache and was
477             // reparented to a non-docking window.
478             SetOrientation(Layouter::GRID);
479         }
480     }
481 }
482 
483 
484 
485 
Layout()486 void SlideSorterView::Layout ()
487 {
488     SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
489     if (pWindow)
490     {
491         // Set the model area, i.e. the smallest rectangle that includes all
492         // page objects.
493         const Rectangle aViewBox (mpLayouter->GetTotalBoundingBox());
494         pWindow->SetViewOrigin (aViewBox.TopLeft());
495         pWindow->SetViewSize (aViewBox.GetSize());
496 
497         ::boost::shared_ptr<PageObjectLayouter> pPageObjectLayouter(
498             mpLayouter->GetPageObjectLayouter());
499         if (pPageObjectLayouter)
500         {
501             const Size aNewPreviewSize (mpLayouter->GetPageObjectLayouter()->GetSize(
502                 PageObjectLayouter::Preview,
503                 PageObjectLayouter::WindowCoordinateSystem));
504             if (maPreviewSize != aNewPreviewSize && GetPreviewCache())
505             {
506                 mpPreviewCache->ChangeSize(aNewPreviewSize, true);
507                 maPreviewSize = aNewPreviewSize;
508             }
509         }
510 
511         // Iterate over all page objects and place them relative to the
512         // containing page.
513         model::PageEnumeration aPageEnumeration (
514             model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
515         while (aPageEnumeration.HasMoreElements())
516         {
517             model::SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement());
518             pDescriptor->SetBoundingBox(mpLayouter->GetPageObjectBox(pDescriptor->GetPageIndex()));
519         }
520 
521         GetPageObjectPainter()->NotifyResize();
522     }
523 
524     InvalidatePageObjectVisibilities ();
525 }
526 
527 
528 
529 
InvalidatePageObjectVisibilities(void)530 void SlideSorterView::InvalidatePageObjectVisibilities (void)
531 {
532     mbPageObjectVisibilitiesValid = false;
533 }
534 
535 
536 
537 
DeterminePageObjectVisibilities(void)538 void SlideSorterView::DeterminePageObjectVisibilities (void)
539 {
540     SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
541     if (pWindow)
542     {
543         // Set this flag to true here so that an invalidate during the
544         // visibility calculation can correctly invalidate it again.
545         mbPageObjectVisibilitiesValid = true;
546 
547         Rectangle aViewArea (pWindow->PixelToLogic(Rectangle(Point(0,0),pWindow->GetSizePixel())));
548         const Range aRange (mpLayouter->GetRangeOfVisiblePageObjects(aViewArea));
549         const Range aUnion(
550             ::std::min(maVisiblePageRange.Min(), aRange.Min()),
551             ::std::max(maVisiblePageRange.Max(), aRange.Max()));
552 
553         // For page objects that just dropped off the visible area we
554         // decrease the priority of pending requests for preview bitmaps.
555         if (maVisiblePageRange != aRange)
556             mbPreciousFlagUpdatePending |= true;
557 
558         model::SharedPageDescriptor pDescriptor;
559         for (int nIndex=aUnion.Min(); nIndex<=aUnion.Max(); nIndex++)
560         {
561             pDescriptor = mrModel.GetPageDescriptor(nIndex);
562             if (pDescriptor.get() != NULL)
563                 SetState(
564                     pDescriptor,
565                     PageDescriptor::ST_Visible,
566                     aRange.IsInside(nIndex));
567         }
568 
569         // Broadcast a change of the set of visible page objects.
570         if (maVisiblePageRange != aRange)
571         {
572             maVisiblePageRange = aRange;
573 
574             // Tell the listeners that the visibility of some objects has
575             // changed.
576             ::std::vector<Link>& aChangeListeners (maVisibilityChangeListeners);
577             for (::std::vector<Link>::const_iterator
578                      iLink(aChangeListeners.begin()),
579                      iEnd(aChangeListeners.end());
580                  iLink!=iEnd;
581                  ++iLink)
582             {
583                 iLink->Call(NULL);
584             }
585         }
586 
587 
588         // Restore the mouse over state.
589         UpdatePageUnderMouse(true);
590     }
591 }
592 
593 
594 
595 
UpdatePreciousFlags(void)596 void SlideSorterView::UpdatePreciousFlags (void)
597 {
598     if (mbPreciousFlagUpdatePending)
599     {
600         mbPreciousFlagUpdatePending = false;
601 
602         model::SharedPageDescriptor pDescriptor;
603         ::boost::shared_ptr<cache::PageCache> pCache = GetPreviewCache();
604         sal_Int32 nPageCount (mrModel.GetPageCount());
605 
606         for (int nIndex=0; nIndex<=nPageCount; ++nIndex)
607         {
608             pDescriptor = mrModel.GetPageDescriptor(nIndex);
609             if (pDescriptor.get() != NULL)
610             {
611                 pCache->SetPreciousFlag(
612                     pDescriptor->GetPage(),
613                     maVisiblePageRange.IsInside(nIndex));
614                 SSCD_SET_VISIBILITY(mrModel.GetDocument(), nIndex,
615                     maVisiblePageRange.IsInside(nIndex));
616             }
617             else
618             {
619                 // At least one cache entry can not be updated.  Remember to
620                 // repeat the whole updating later and leave the loop now.
621                 mbPreciousFlagUpdatePending = true;
622                 break;
623             }
624         }
625     }
626 }
627 
628 
629 
630 
SetOrientation(const Layouter::Orientation eOrientation)631 bool SlideSorterView::SetOrientation (const Layouter::Orientation eOrientation)
632 {
633     if (meOrientation != eOrientation)
634     {
635         meOrientation = eOrientation;
636         return true;
637     }
638     else
639         return false;
640 }
641 
642 
643 
644 
GetOrientation(void) const645 Layouter::Orientation SlideSorterView::GetOrientation (void) const
646 {
647     return meOrientation;
648 }
649 
650 
651 
652 
RequestRepaint(void)653 void SlideSorterView::RequestRepaint (void)
654 {
655     SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
656     if (pWindow)
657     {
658         mpLayeredDevice->InvalidateAllLayers(
659             Rectangle(
660                 pWindow->PixelToLogic(Point(0,0)),
661                 pWindow->PixelToLogic(pWindow->GetSizePixel())));
662         pWindow->Invalidate();
663     }
664 }
665 
666 
667 
668 
RequestRepaint(const model::SharedPageDescriptor & rpDescriptor)669 void SlideSorterView::RequestRepaint (const model::SharedPageDescriptor& rpDescriptor)
670 {
671     if (rpDescriptor)
672         RequestRepaint(rpDescriptor->GetBoundingBox());
673 }
674 
675 
676 
677 
RequestRepaint(const Rectangle & rRepaintBox)678 void SlideSorterView::RequestRepaint (const Rectangle& rRepaintBox)
679 {
680     SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
681     if (pWindow)
682     {
683         mpLayeredDevice->InvalidateAllLayers(rRepaintBox);
684         pWindow->Invalidate(rRepaintBox);
685     }
686 }
687 
688 
689 
RequestRepaint(const Region & rRepaintRegion)690 void SlideSorterView::RequestRepaint (const Region& rRepaintRegion)
691 {
692     SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
693     if (pWindow)
694     {
695         mpLayeredDevice->InvalidateAllLayers(rRepaintRegion);
696         pWindow->Invalidate(rRepaintRegion);
697     }
698 }
699 
700 
701 
702 
GetModelArea(void)703 Rectangle SlideSorterView::GetModelArea (void)
704 {
705     return mpLayouter->GetTotalBoundingBox();
706 }
707 
708 
709 #ifdef DEBUG_TIMING
710 static ::canvas::tools::ElapsedTime gaTimer;
711 static const size_t gFrameTimeCount (10);
712 static size_t gFrameTimeIndex (0);
713 static ::std::vector<double> gFrameTimes (gFrameTimeCount, 0);
714 static double gFrameTimeSum (0);
715 static const Rectangle gFrameTimeBox (10,10,150,20);
716 static double gnLastFrameStart = 0;
717 #endif
718 
CompleteRedraw(OutputDevice * pDevice,const Region & rPaintArea,sdr::contact::ViewObjectContactRedirector * pRedirector)719 void SlideSorterView::CompleteRedraw (
720     OutputDevice* pDevice,
721     const Region& rPaintArea,
722     sdr::contact::ViewObjectContactRedirector* pRedirector)
723 {
724     (void)pRedirector;
725 #ifdef DEBUG_TIMING
726     const double nStartTime (gaTimer.getElapsedTime());
727     OSL_TRACE("SlideSorterView::CompleteRedraw start at %f, %s",
728         nStartTime,
729         mnLockRedrawSmph ? "locked" : "");
730 #endif
731 
732     if (pDevice == NULL || pDevice!=mrSlideSorter.GetContentWindow().get())
733         return;
734 
735     // The parent implementation of CompleteRedraw is called only when
736     // painting is locked.  We do all the painting ourself.  When painting
737     // is locked the parent implementation keeps track of the repaint
738     // requests and later, when painting is unlocked, calls CompleteRedraw
739     // for all missed repaints.
740 
741     if (mnLockRedrawSmph == 0)
742     {
743         mrSlideSorter.GetContentWindow()->IncrementLockCount();
744         if (mpLayeredDevice->HandleMapModeChange())
745             DeterminePageObjectVisibilities();
746         mpLayeredDevice->Repaint(rPaintArea);
747         mrSlideSorter.GetContentWindow()->DecrementLockCount();
748     }
749     else
750     {
751         maRedrawRegion.Union(rPaintArea);
752     }
753 
754 #ifdef DEBUG_TIMING
755     const double nEndTime (gaTimer.getElapsedTime());
756     OSL_TRACE("SlideSorterView::CompleteRedraw end at %f after %fms", nEndTime, (nEndTime-nStartTime)*1000);
757     gFrameTimeSum -= gFrameTimes[gFrameTimeIndex];
758     gFrameTimes[gFrameTimeIndex] = nStartTime - gnLastFrameStart;
759     gnLastFrameStart = nStartTime;
760     gFrameTimeSum += gFrameTimes[gFrameTimeIndex];
761     gFrameTimeIndex = (gFrameTimeIndex+1) % gFrameTimeCount;
762 
763 
764     mrSlideSorter.GetContentWindow()->SetFillColor(COL_BLUE);
765     mrSlideSorter.GetContentWindow()->DrawRect(gFrameTimeBox);
766     mrSlideSorter.GetContentWindow()->SetTextColor(COL_WHITE);
767     mrSlideSorter.GetContentWindow()->DrawText(
768         gFrameTimeBox,
769         ::rtl::OUString::valueOf(1 / (gFrameTimeSum / gFrameTimeCount)),
770         TEXT_DRAW_RIGHT | TEXT_DRAW_VCENTER);
771     //    mrSlideSorter.GetContentWindow()->Invalidate(gFrameTimeBox);
772 #endif
773 }
774 
775 
776 
777 
Paint(OutputDevice & rDevice,const Rectangle & rRepaintArea)778 void SlideSorterView::Paint (
779     OutputDevice& rDevice,
780     const Rectangle& rRepaintArea)
781 {
782     if ( ! mpPageObjectPainter)
783         if ( ! GetPageObjectPainter())
784             return;
785 
786     // Update the page visibilities when they have been invalidated.
787     if ( ! mbPageObjectVisibilitiesValid)
788         DeterminePageObjectVisibilities();
789 
790     if (mbPreciousFlagUpdatePending)
791         UpdatePreciousFlags();
792 
793     if (mbIsRearrangePending)
794         Rearrange();
795 
796     // Paint all page objects that are fully or partially inside the
797     // repaint region.
798     const Range aRange (mpLayouter->GetRangeOfVisiblePageObjects(rRepaintArea));
799     for (sal_Int32 nIndex=aRange.Min(); nIndex<=aRange.Max(); ++nIndex)
800     {
801         model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex));
802         if (!pDescriptor || ! pDescriptor->HasState(PageDescriptor::ST_Visible))
803             continue;
804 
805         mpPageObjectPainter->PaintPageObject(rDevice, pDescriptor);
806     }
807 }
808 
809 
810 
811 
ConfigurationChanged(utl::ConfigurationBroadcaster * pBroadcaster,sal_uInt32 nHint)812 void SlideSorterView::ConfigurationChanged (
813     utl::ConfigurationBroadcaster* pBroadcaster,
814     sal_uInt32 nHint)
815 {
816     // Some changes of the configuration (some of the colors for example)
817     // may affect the previews.  Throw away the old ones and create new ones.
818     cache::PageCacheManager::Instance()->InvalidateAllCaches();
819 
820     ::sd::View::ConfigurationChanged(pBroadcaster, nHint);
821     RequestRepaint();
822 
823 }
824 
825 
826 
827 
GetPreviewCache(void)828 ::boost::shared_ptr<cache::PageCache> SlideSorterView::GetPreviewCache (void)
829 {
830     SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
831     if (pWindow && mpPreviewCache.get() == NULL)
832     {
833         mpPreviewCache.reset(
834             new cache::PageCache(
835                 mpLayouter->GetPageObjectSize(),
836                 false,
837                 cache::SharedCacheContext(new ViewCacheContext(mrSlideSorter))));
838     }
839 
840     return mpPreviewCache;
841 }
842 
843 
844 
845 
GetVisiblePageRange(void)846 Pair SlideSorterView::GetVisiblePageRange (void)
847 {
848     if ( ! mbPageObjectVisibilitiesValid)
849         DeterminePageObjectVisibilities();
850     return maVisiblePageRange;
851 }
852 
853 
854 
855 
AddVisibilityChangeListener(const Link & rListener)856 void SlideSorterView::AddVisibilityChangeListener (const Link& rListener)
857 {
858     if (::std::find (
859         maVisibilityChangeListeners.begin(),
860         maVisibilityChangeListeners.end(),
861         rListener) == maVisibilityChangeListeners.end())
862     {
863         maVisibilityChangeListeners.push_back(rListener);
864     }
865 }
866 
867 
868 
869 
RemoveVisibilityChangeListener(const Link & rListener)870 void SlideSorterView::RemoveVisibilityChangeListener(const Link&rListener)
871 {
872     maVisibilityChangeListeners.erase (
873         ::std::find (
874             maVisibilityChangeListeners.begin(),
875             maVisibilityChangeListeners.end(),
876             rListener));
877 }
878 
879 
880 
881 
GetButtonBar(void) const882 ButtonBar& SlideSorterView::GetButtonBar (void) const
883 {
884     OSL_ASSERT(mpButtonBar);
885     return *mpButtonBar;
886 }
887 
888 
889 
890 
GetToolTip(void) const891 ToolTip& SlideSorterView::GetToolTip (void) const
892 {
893     OSL_ASSERT(mpToolTip);
894     return *mpToolTip;
895 }
896 
897 
898 
899 
DragFinished(sal_Int8 nDropAction)900 void SlideSorterView::DragFinished (sal_Int8 nDropAction)
901 {
902     mrSlideSorter.GetController().GetClipboard().DragFinished(nDropAction);
903 
904     View::DragFinished(nDropAction);
905 }
906 
907 
908 
909 
Notify(SfxBroadcaster & rBroadcaster,const SfxHint & rHint)910 void SlideSorterView::Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint)
911 {
912 	::sd::DrawDocShell* pDocShell = mrModel.GetDocument()->GetDocSh();
913     if (pDocShell!=NULL && pDocShell->IsEnableSetModified())
914         mbModelChangedWhileModifyEnabled = true;
915 
916     ::sd::View::Notify(rBroadcaster, rHint);
917 }
918 
919 
920 
921 
UpdatePageUnderMouse(bool bAnimate)922 void SlideSorterView::UpdatePageUnderMouse (bool bAnimate)
923 {
924     ::boost::shared_ptr<ScrollBar> pVScrollBar (mrSlideSorter.GetVerticalScrollBar());
925     ::boost::shared_ptr<ScrollBar> pHScrollBar (mrSlideSorter.GetHorizontalScrollBar());
926     if ((pVScrollBar && pVScrollBar->IsVisible() && pVScrollBar->IsTracking())
927         || (pHScrollBar && pHScrollBar->IsVisible() && pHScrollBar->IsTracking()))
928     {
929         // One of the scroll bars is tracking mouse movement.  Do not
930         // highlight the slide under the mouse in this case.
931         SetPageUnderMouse(SharedPageDescriptor(),false);
932         return;
933     }
934 
935     SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
936     if (pWindow && pWindow->IsVisible() && ! pWindow->IsMouseCaptured())
937     {
938         const Window::PointerState aPointerState (pWindow->GetPointerState());
939         const Rectangle aWindowBox (pWindow->GetPosPixel(), pWindow->GetSizePixel());
940         if (aWindowBox.IsInside(aPointerState.maPos))
941         {
942             UpdatePageUnderMouse (
943                 aPointerState.maPos,
944                 (aPointerState.mnState & MOUSE_LEFT)!=0,
945                 bAnimate);
946             return;
947         }
948     }
949 
950     SetPageUnderMouse(SharedPageDescriptor(),false);
951 }
952 
953 
954 
955 
UpdatePageUnderMouse(const Point & rMousePosition,const bool bIsMouseButtonDown,const bool bAnimate)956 void SlideSorterView::UpdatePageUnderMouse (
957     const Point& rMousePosition,
958     const bool bIsMouseButtonDown,
959     const bool bAnimate)
960 {
961     UpdatePageUnderMouse(
962         mrSlideSorter.GetController().GetPageAt(rMousePosition),
963         rMousePosition,
964         bIsMouseButtonDown,
965         bAnimate);
966 }
967 
968 
969 
970 
UpdatePageUnderMouse(const model::SharedPageDescriptor & rpDescriptor,const Point & rMousePosition,const bool bIsMouseButtonDown,const bool bAnimate)971 void SlideSorterView::UpdatePageUnderMouse (
972     const model::SharedPageDescriptor& rpDescriptor,
973     const Point& rMousePosition,
974     const bool bIsMouseButtonDown,
975     const bool bAnimate)
976 {
977     // Update the page under the mouse.
978     SetPageUnderMouse(rpDescriptor, bAnimate);
979 
980     // Tell the button bar about the new mouse position.
981     SharedSdWindow pWindow (mrSlideSorter.GetContentWindow());
982     const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition));
983 
984     ::boost::shared_ptr<ViewShell> pMainViewShell (mrSlideSorter.GetViewShellBase()->GetMainViewShell());
985     if (pMainViewShell
986         && pMainViewShell->GetShellType()!=ViewShell::ST_DRAW)
987     {
988         const bool bIsMouseOverButtonBar (GetButtonBar().IsMouseOverBar());
989         GetButtonBar().ProcessMouseMotionEvent(rpDescriptor, aMouseModelPosition, bIsMouseButtonDown);
990         // Set the help text of the slide when the mouse was moved from the
991         // button bar back over the preview.
992         if (rpDescriptor
993             && GetButtonBar().IsMouseOverBar() != bIsMouseOverButtonBar
994             && bIsMouseOverButtonBar)
995         {
996             mpToolTip->ShowDefaultHelpText();
997         }
998     }
999 }
1000 
1001 
1002 
1003 
SetPageUnderMouse(const model::SharedPageDescriptor & rpDescriptor,const bool bAnimate)1004 void SlideSorterView::SetPageUnderMouse (
1005     const model::SharedPageDescriptor& rpDescriptor,
1006     const bool bAnimate)
1007 {
1008     if (mpPageUnderMouse != rpDescriptor)
1009     {
1010         if (mpPageUnderMouse)
1011             SetState(mpPageUnderMouse, PageDescriptor::ST_MouseOver, false, bAnimate);
1012 
1013         mpPageUnderMouse = rpDescriptor;
1014 
1015         if (mpPageUnderMouse)
1016             SetState(mpPageUnderMouse, PageDescriptor::ST_MouseOver, true, bAnimate);
1017 
1018         // Change the quick help text to display the name of the page under
1019         // the mouse.
1020         mpToolTip->SetPage(rpDescriptor);
1021     }
1022 }
1023 
1024 
1025 
1026 
SetState(const model::SharedPageDescriptor & rpDescriptor,const PageDescriptor::State eState,const bool bStateValue,const bool bAnimate)1027 bool SlideSorterView::SetState (
1028     const model::SharedPageDescriptor& rpDescriptor,
1029     const PageDescriptor::State eState,
1030     const bool bStateValue,
1031     const bool bAnimate)
1032 {
1033     model::SharedPageDescriptor pDescriptor (rpDescriptor);
1034     if ( ! pDescriptor)
1035         return false;
1036 
1037     const bool bModified (pDescriptor->SetState(eState, bStateValue));
1038     if ( ! bModified)
1039         return false;
1040 
1041     // When the page object is not visible (i.e. not on the screen then
1042     // nothing has to be painted.
1043     if (pDescriptor->HasState(PageDescriptor::ST_Visible))
1044     {
1045         // For most states a change of that state leads to visible
1046         // difference and we have to request a repaint.
1047         if (eState != PageDescriptor::ST_WasSelected)
1048             RequestRepaint(pDescriptor);
1049     }
1050 
1051     ::boost::shared_ptr<ViewShell> pMainViewShell(mrSlideSorter.GetViewShellBase()->GetMainViewShell());
1052     if (pMainViewShell
1053         && pMainViewShell->GetShellType()!=ViewShell::ST_DRAW)
1054     {
1055         // Fade in or out the buttons.
1056         if (eState == PageDescriptor::ST_MouseOver)
1057         {
1058             if (bStateValue)
1059                 GetButtonBar().RequestFadeIn(rpDescriptor, bAnimate);
1060             else
1061                 GetButtonBar().RequestFadeOut(rpDescriptor, bAnimate);
1062         }
1063     }
1064 
1065     return bModified;
1066 }
1067 
1068 
1069 
1070 
GetPageObjectPainter(void)1071 ::boost::shared_ptr<PageObjectPainter> SlideSorterView::GetPageObjectPainter (void)
1072 {
1073     if ( ! mpPageObjectPainter)
1074         mpPageObjectPainter.reset(new PageObjectPainter(mrSlideSorter));
1075     return mpPageObjectPainter;
1076 }
1077 
1078 
1079 
1080 
GetLayeredDevice(void) const1081 ::boost::shared_ptr<LayeredDevice> SlideSorterView::GetLayeredDevice (void) const
1082 {
1083     return mpLayeredDevice;
1084 }
1085 
1086 
1087 
1088 
1089 //===== SlideSorterView::DrawLock =============================================
1090 
DrawLock(view::SlideSorterView & rView,const SharedSdWindow & rpWindow)1091 SlideSorterView::DrawLock::DrawLock (
1092     view::SlideSorterView& rView,
1093     const SharedSdWindow& rpWindow)
1094     : mrView(rView),
1095       mpWindow(rpWindow)
1096 {
1097     if (mrView.mnLockRedrawSmph == 0)
1098         mrView.maRedrawRegion.SetEmpty();
1099     ++mrView.mnLockRedrawSmph;
1100 }
1101 
1102 
1103 
1104 
DrawLock(SlideSorter & rSlideSorter)1105 SlideSorterView::DrawLock::DrawLock (SlideSorter& rSlideSorter)
1106     : mrView(rSlideSorter.GetView()),
1107       mpWindow(rSlideSorter.GetContentWindow())
1108 {
1109     if (mrView.mnLockRedrawSmph == 0)
1110         mrView.maRedrawRegion.SetEmpty();
1111     ++mrView.mnLockRedrawSmph;
1112 }
1113 
1114 
1115 
1116 
~DrawLock(void)1117 SlideSorterView::DrawLock::~DrawLock (void)
1118 {
1119     OSL_ASSERT(mrView.mnLockRedrawSmph>0);
1120     --mrView.mnLockRedrawSmph;
1121     if (mrView.mnLockRedrawSmph == 0)
1122         if (mpWindow)
1123         {
1124             mpWindow->Invalidate(mrView.maRedrawRegion);
1125             mpWindow->Update();
1126         }
1127 }
1128 
1129 
1130 
1131 
Dispose(void)1132 void SlideSorterView::DrawLock::Dispose (void)
1133 {
1134     mpWindow.reset();
1135 }
1136 
1137 
1138 } } } // end of namespace ::sd::slidesorter::view
1139