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