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