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 <controller/SlideSorterController.hxx>
21 
22 #include <SlideSorter.hxx>
23 #include <controller/SlsPageSelector.hxx>
24 #include <controller/SlsSelectionFunction.hxx>
25 #include <controller/SlsProperties.hxx>
26 #include <controller/SlsCurrentSlideManager.hxx>
27 #include "SlsListener.hxx"
28 #include <controller/SlsFocusManager.hxx>
29 #include <controller/SlsAnimator.hxx>
30 #include <controller/SlsClipboard.hxx>
31 #include <controller/SlsInsertionIndicatorHandler.hxx>
32 #include <controller/SlsScrollBarManager.hxx>
33 #include <controller/SlsSelectionManager.hxx>
34 #include <controller/SlsSlotManager.hxx>
35 #include <controller/SlsVisibleAreaManager.hxx>
36 #include <model/SlideSorterModel.hxx>
37 #include <model/SlsPageEnumerationProvider.hxx>
38 #include <model/SlsPageDescriptor.hxx>
39 #include <view/SlideSorterView.hxx>
40 #include <view/SlsLayouter.hxx>
41 #include <view/SlsPageObjectLayouter.hxx>
42 #include <view/SlsTheme.hxx>
43 #include <view/SlsToolTip.hxx>
44 #include <cache/SlsPageCache.hxx>
45 #include <cache/SlsPageCacheManager.hxx>
46 
47 #include <drawdoc.hxx>
48 #include <ViewShellBase.hxx>
49 #include <Window.hxx>
50 #include <FrameView.hxx>
51 #include <sdpage.hxx>
52 
53 #include <app.hrc>
54 #include <sdmod.hxx>
55 #include <ViewShellHint.hxx>
56 #include <AccessibleSlideSorterView.hxx>
57 #include <AccessibleSlideSorterObject.hxx>
58 
59 #include <vcl/window.hxx>
60 #include <svx/svxids.hrc>
61 #include <sfx2/request.hxx>
62 #include <sfx2/viewfrm.hxx>
63 #include <sfx2/dispatch.hxx>
64 #include <tools/debug.hxx>
65 #include <vcl/commandevent.hxx>
66 #include <vcl/svapp.hxx>
67 #include <vcl/settings.hxx>
68 
69 #include <com/sun/star/lang/XComponent.hpp>
70 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
71 
72 #include <memory>
73 
74 using namespace ::com::sun::star;
75 using namespace ::com::sun::star::uno;
76 using namespace ::sd::slidesorter::model;
77 using namespace ::sd::slidesorter::view;
78 using namespace ::sd::slidesorter::controller;
79 using namespace ::basegfx;
80 
81 namespace sd { namespace slidesorter { namespace controller {
82 
SlideSorterController(SlideSorter & rSlideSorter)83 SlideSorterController::SlideSorterController (SlideSorter& rSlideSorter)
84     : mrSlideSorter(rSlideSorter),
85       mrModel(mrSlideSorter.GetModel()),
86       mrView(mrSlideSorter.GetView()),
87       mpPageSelector(),
88       mpFocusManager(),
89       mpSlotManager(),
90       mpScrollBarManager(),
91       mpCurrentSlideManager(),
92       mpSelectionManager(),
93       mpClipboard(),
94       mpInsertionIndicatorHandler(new InsertionIndicatorHandler(rSlideSorter)),
95       mpAnimator(new Animator(rSlideSorter)),
96       mpVisibleAreaManager(new VisibleAreaManager(rSlideSorter)),
97       mpListener(),
98       mnModelChangeLockCount(0),
99       mbIsForcedRearrangePending(false),
100       mbContextMenuOpen(false),
101       mbPostModelChangePending(false),
102       maSelectionBeforeSwitch(),
103       mnCurrentPageBeforeSwitch(0),
104       mpEditModeChangeMasterPage(nullptr),
105       maTotalWindowArea(),
106       mnPaintEntranceCount(0)
107 {
108     sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
109     OSL_ASSERT(pWindow);
110     if (!pWindow)
111         return;
112 
113     // The whole background is painted by the view and controls.
114     vcl::Window* pParentWindow = pWindow->GetParent();
115     OSL_ASSERT(pParentWindow!=nullptr);
116     pParentWindow->SetBackground (Wallpaper());
117 
118     // Connect the view with the window that has been created by our base
119     // class.
120     pWindow->SetBackground(Wallpaper());
121     pWindow->SetCenterAllowed(false);
122     pWindow->SetMapMode(MapMode(MapUnit::MapPixel));
123     pWindow->SetViewSize(mrView.GetModelArea().GetSize());
124 }
125 
Init()126 void SlideSorterController::Init()
127 {
128     mpCurrentSlideManager.reset(new CurrentSlideManager(mrSlideSorter));
129     mpPageSelector.reset(new PageSelector(mrSlideSorter));
130     mpFocusManager.reset(new FocusManager(mrSlideSorter));
131     mpSlotManager.reset(new SlotManager(mrSlideSorter));
132     mpScrollBarManager.reset(new ScrollBarManager(mrSlideSorter));
133     mpSelectionManager.reset(new SelectionManager(mrSlideSorter));
134     mpClipboard.reset(new Clipboard(mrSlideSorter));
135 
136     // Create the selection function.
137     SfxRequest aRequest (
138         SID_OBJECT_SELECT,
139         SfxCallMode::SLOT,
140         mrModel.GetDocument()->GetItemPool());
141     mrSlideSorter.SetCurrentFunction(CreateSelectionFunction(aRequest));
142 
143     mpListener = new Listener(mrSlideSorter);
144 
145     mpPageSelector->GetCoreSelection();
146     GetSelectionManager()->SelectionHasChanged();
147 }
148 
~SlideSorterController()149 SlideSorterController::~SlideSorterController()
150 {
151     try
152     {
153         uno::Reference<lang::XComponent> xComponent (
154             static_cast<XWeak*>(mpListener.get()), uno::UNO_QUERY);
155         if (xComponent.is())
156             xComponent->dispose();
157     }
158     catch( uno::Exception& )
159     {
160         OSL_FAIL( "sd::SlideSorterController::~SlideSorterController(), exception caught!" );
161     }
162 
163     // dispose should have been called by now so that nothing is to be done
164     // to shut down cleanly.
165 }
166 
Dispose()167 void SlideSorterController::Dispose()
168 {
169     mpInsertionIndicatorHandler->End(Animator::AM_Immediate);
170     mpClipboard.reset();
171     mpSelectionManager.reset();
172     mpAnimator->Dispose();
173 }
174 
GetPageAt(const Point & aWindowPosition)175 model::SharedPageDescriptor SlideSorterController::GetPageAt (
176     const Point& aWindowPosition)
177 {
178     sal_Int32 nHitPageIndex (mrView.GetPageIndexAtPoint(aWindowPosition));
179     model::SharedPageDescriptor pDescriptorAtPoint;
180     if (nHitPageIndex >= 0)
181     {
182         pDescriptorAtPoint = mrModel.GetPageDescriptor(nHitPageIndex);
183 
184         // Depending on a property we may have to check that the mouse is no
185         // just over the page object but over the preview area.
186         if (pDescriptorAtPoint
187             && ! pDescriptorAtPoint->HasState(PageDescriptor::ST_Selected))
188         {
189             // Make sure that the mouse is over the preview area.
190             if ( ! mrView.GetLayouter().GetPageObjectLayouter()->GetBoundingBox(
191                 pDescriptorAtPoint,
192                 view::PageObjectLayouter::Part::Preview,
193                 view::PageObjectLayouter::WindowCoordinateSystem).IsInside(aWindowPosition))
194             {
195                 pDescriptorAtPoint.reset();
196             }
197         }
198     }
199 
200     return pDescriptorAtPoint;
201 }
202 
GetPageSelector()203 PageSelector& SlideSorterController::GetPageSelector()
204 {
205     OSL_ASSERT(mpPageSelector != nullptr);
206     return *mpPageSelector;
207 }
208 
GetFocusManager()209 FocusManager& SlideSorterController::GetFocusManager()
210 {
211     OSL_ASSERT(mpFocusManager != nullptr);
212     return *mpFocusManager;
213 }
214 
GetClipboard()215 Clipboard& SlideSorterController::GetClipboard()
216 {
217     OSL_ASSERT(mpClipboard != nullptr);
218     return *mpClipboard;
219 }
220 
GetScrollBarManager()221 ScrollBarManager& SlideSorterController::GetScrollBarManager()
222 {
223     OSL_ASSERT(mpScrollBarManager != nullptr);
224     return *mpScrollBarManager;
225 }
226 
GetCurrentSlideManager() const227 std::shared_ptr<CurrentSlideManager> const & SlideSorterController::GetCurrentSlideManager() const
228 {
229     OSL_ASSERT(mpCurrentSlideManager != nullptr);
230     return mpCurrentSlideManager;
231 }
232 
GetSlotManager() const233 std::shared_ptr<SlotManager> const & SlideSorterController::GetSlotManager() const
234 {
235     OSL_ASSERT(mpSlotManager != nullptr);
236     return mpSlotManager;
237 }
238 
GetSelectionManager() const239 std::shared_ptr<SelectionManager> const & SlideSorterController::GetSelectionManager() const
240 {
241     OSL_ASSERT(mpSelectionManager != nullptr);
242     return mpSelectionManager;
243 }
244 
245 std::shared_ptr<InsertionIndicatorHandler> const &
GetInsertionIndicatorHandler() const246     SlideSorterController::GetInsertionIndicatorHandler() const
247 {
248     OSL_ASSERT(mpInsertionIndicatorHandler != nullptr);
249     return mpInsertionIndicatorHandler;
250 }
251 
Paint(const::tools::Rectangle & rBBox,vcl::Window * pWindow)252 void SlideSorterController::Paint (
253     const ::tools::Rectangle& rBBox,
254     vcl::Window* pWindow)
255 {
256     if (mnPaintEntranceCount != 0)
257         return;
258 
259     ++mnPaintEntranceCount;
260 
261     try
262     {
263         mrView.CompleteRedraw(pWindow, vcl::Region(rBBox));
264     }
265     catch (const Exception&)
266     {
267         // Ignore all exceptions.
268     }
269 
270     --mnPaintEntranceCount;
271 }
272 
FuTemporary(SfxRequest & rRequest)273 void SlideSorterController::FuTemporary (SfxRequest& rRequest)
274 {
275     mpSlotManager->FuTemporary (rRequest);
276 }
277 
FuPermanent(SfxRequest & rRequest)278 void SlideSorterController::FuPermanent (SfxRequest &rRequest)
279 {
280     mpSlotManager->FuPermanent (rRequest);
281 }
282 
FuSupport(SfxRequest & rRequest)283 void SlideSorterController::FuSupport (SfxRequest &rRequest)
284 {
285     mpSlotManager->FuSupport (rRequest);
286 }
287 
Command(const CommandEvent & rEvent,::sd::Window * pWindow)288 bool SlideSorterController::Command (
289     const CommandEvent& rEvent,
290     ::sd::Window* pWindow)
291 {
292     bool bEventHasBeenHandled = false;
293 
294     if (pWindow == nullptr)
295         return false;
296 
297     ViewShell* pViewShell = mrSlideSorter.GetViewShell();
298     if (pViewShell == nullptr)
299         return false;
300 
301     switch (rEvent.GetCommand())
302     {
303         case CommandEventId::ContextMenu:
304         {
305             SdPage* pPage = nullptr;
306             OUString aPopupId;
307 
308             model::PageEnumeration aSelectedPages (
309                 PageEnumerationProvider::CreateSelectedPagesEnumeration(mrModel));
310             if (aSelectedPages.HasMoreElements())
311                 pPage = aSelectedPages.GetNextElement()->GetPage();
312 
313             if (mrModel.GetEditMode() == EditMode::Page)
314             {
315                 if (pPage != nullptr)
316                     aPopupId = "pagepane";
317                 else
318                     aPopupId = "pagepanenosel";
319             }
320             else if (pPage != nullptr)
321                 aPopupId = "pagepanemaster";
322             else
323                 aPopupId = "pagepanenoselmaster";
324 
325             std::unique_ptr<InsertionIndicatorHandler::ForceShowContext, o3tl::default_delete<InsertionIndicatorHandler::ForceShowContext>> xContext;
326             if (pPage == nullptr)
327             {
328                 // When there is no selection, then we show the insertion
329                 // indicator so that the user knows where a page insertion
330                 // would take place.
331                 mpInsertionIndicatorHandler->Start(false);
332                 mpInsertionIndicatorHandler->UpdateIndicatorIcon(SD_MOD()->pTransferClip);
333                 mpInsertionIndicatorHandler->UpdatePosition(
334                     pWindow->PixelToLogic(rEvent.GetMousePosPixel()),
335                     InsertionIndicatorHandler::MoveMode);
336                 xContext.reset(new InsertionIndicatorHandler::ForceShowContext(
337                     mpInsertionIndicatorHandler));
338             }
339 
340             pWindow->ReleaseMouse();
341 
342             Point aMenuLocation (0,0);
343             if (!rEvent.IsMouseEvent())
344             {
345                 // The event is not a mouse event.  Use the center of the
346                 // focused page as top left position of the context menu.
347                 model::SharedPageDescriptor pDescriptor (
348                     GetFocusManager().GetFocusedPageDescriptor());
349                 if (pDescriptor.get() != nullptr)
350                 {
351                     ::tools::Rectangle aBBox (
352                         mrView.GetLayouter().GetPageObjectLayouter()->GetBoundingBox (
353                             pDescriptor,
354                             PageObjectLayouter::Part::PageObject,
355                             PageObjectLayouter::ModelCoordinateSystem));
356                     aMenuLocation = aBBox.Center();
357                 }
358             }
359 
360             if (SfxDispatcher* pDispatcher = pViewShell->GetDispatcher())
361             {
362                 mbContextMenuOpen = true;
363                 if (!rEvent.IsMouseEvent())
364                     pDispatcher->ExecutePopup(aPopupId, pWindow, &aMenuLocation);
365                 else
366                     pDispatcher->ExecutePopup(aPopupId, pWindow);
367                 mbContextMenuOpen = false;
368                 mrSlideSorter.GetView().UpdatePageUnderMouse();
369                 ::rtl::Reference<SelectionFunction> pFunction(GetCurrentSelectionFunction());
370                 if (pFunction.is())
371                     pFunction->ResetMouseAnchor();
372             }
373             if (pPage == nullptr)
374             {
375                 // Remember the position of the insertion indicator before
376                 // it is hidden, so that a pending slide insertion slot call
377                 // finds the right place to insert a new slide.
378                 GetSelectionManager()->SetInsertionPosition(
379                     GetInsertionIndicatorHandler()->GetInsertionPageIndex());
380             }
381             xContext.reset();
382             bEventHasBeenHandled = true;
383         }
384         break;
385 
386         case CommandEventId::Wheel:
387         {
388             const CommandWheelData* pData = rEvent.GetWheelData();
389             if (pData == nullptr)
390                 return false;
391             if (pData->IsMod1())
392             {
393                 // We do not support zooming with control+mouse wheel.
394                 return false;
395             }
396             // Determine whether to scroll horizontally or vertically.  This
397             // depends on the orientation of the scroll bar and the
398             // IsHoriz() flag of the event.
399             if ((mrSlideSorter.GetView().GetOrientation()==view::Layouter::HORIZONTAL)
400                 == pData->IsHorz())
401             {
402                 GetScrollBarManager().Scroll(
403                     ScrollBarManager::Orientation_Vertical,
404                     -pData->GetNotchDelta());
405             }
406             else
407             {
408                 GetScrollBarManager().Scroll(
409                     ScrollBarManager::Orientation_Horizontal,
410                     -pData->GetNotchDelta());
411             }
412             mrSlideSorter.GetView().UpdatePageUnderMouse(rEvent.GetMousePosPixel());
413 
414             bEventHasBeenHandled = true;
415         }
416         break;
417 
418         default: break;
419     }
420 
421     return bEventHasBeenHandled;
422 }
423 
LockModelChange()424 void SlideSorterController::LockModelChange()
425 {
426     mnModelChangeLockCount += 1;
427 }
428 
UnlockModelChange()429 void SlideSorterController::UnlockModelChange()
430 {
431     mnModelChangeLockCount -= 1;
432     if (mnModelChangeLockCount==0 && mbPostModelChangePending)
433     {
434         PostModelChange();
435     }
436 }
437 
PreModelChange()438 void SlideSorterController::PreModelChange()
439 {
440     // Prevent PreModelChange to execute more than once per model lock.
441     if (mbPostModelChangePending)
442         return;
443 
444     if (mrSlideSorter.GetViewShell() != nullptr)
445         mrSlideSorter.GetViewShell()->Broadcast(
446             ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_START));
447 
448     GetCurrentSlideManager()->PrepareModelChange();
449 
450     if (mrSlideSorter.GetContentWindow())
451         mrView.PreModelChange();
452 
453     mbPostModelChangePending = true;
454 }
455 
PostModelChange()456 void SlideSorterController::PostModelChange()
457 {
458     mbPostModelChangePending = false;
459     mrModel.Resync();
460 
461     sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
462     if (pWindow)
463     {
464         GetCurrentSlideManager()->HandleModelChange();
465 
466         mrView.PostModelChange ();
467 
468         pWindow->SetViewOrigin (Point (0,0));
469         pWindow->SetViewSize (mrView.GetModelArea().GetSize());
470 
471         // The visibility of the scroll bars may have to be changed.  Then
472         // the size of the view has to change, too.  Let Rearrange() handle
473         // that.
474         Rearrange(mbIsForcedRearrangePending);
475     }
476 
477     if (mrSlideSorter.GetViewShell() != nullptr)
478         mrSlideSorter.GetViewShell()->Broadcast(
479             ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_END));
480 }
481 
HandleModelChange()482 void SlideSorterController::HandleModelChange()
483 {
484     // Ignore this call when the document is not in a valid state, i.e. has
485     // not the same number of regular and notes pages.
486     bool bIsDocumentValid = (mrModel.GetDocument()->GetPageCount() % 2 == 1);
487 
488     if (bIsDocumentValid)
489     {
490         ModelChangeLock aLock (*this);
491         PreModelChange();
492     }
493 }
494 
IMPL_LINK(SlideSorterController,ApplicationEventHandler,VclSimpleEvent &,rEvent,void)495 IMPL_LINK(SlideSorterController, ApplicationEventHandler, VclSimpleEvent&, rEvent, void)
496 {
497     auto windowEvent = dynamic_cast<VclWindowEvent *>(&rEvent);
498     if (windowEvent != nullptr) {
499         WindowEventHandler(*windowEvent);
500     }
501 }
IMPL_LINK(SlideSorterController,WindowEventHandler,VclWindowEvent &,rEvent,void)502 IMPL_LINK(SlideSorterController, WindowEventHandler, VclWindowEvent&, rEvent, void)
503 {
504         vcl::Window* pWindow = rEvent.GetWindow();
505         sd::Window *pActiveWindow (mrSlideSorter.GetContentWindow().get());
506         switch (rEvent.GetId())
507         {
508             case VclEventId::WindowActivate:
509             case VclEventId::WindowShow:
510                 if (pActiveWindow && pWindow == pActiveWindow->GetParent())
511                     mrView.RequestRepaint();
512                 break;
513 
514             case VclEventId::WindowHide:
515                 if (pActiveWindow && pWindow == pActiveWindow->GetParent())
516                     mrView.SetPageUnderMouse(SharedPageDescriptor());
517                 break;
518 
519             case VclEventId::WindowGetFocus:
520                 if (pActiveWindow)
521                     if (pWindow == pActiveWindow)
522                         GetFocusManager().ShowFocus(false);
523                 break;
524 
525             case VclEventId::WindowLoseFocus:
526                 if (pActiveWindow && pWindow == pActiveWindow)
527                 {
528                     GetFocusManager().HideFocus();
529                     mrView.GetToolTip().Hide();
530 
531                     //don't scroll back to the selected slide when we lose
532                     //focus due to a temporary active context menu
533                     if (!mbContextMenuOpen)
534                     {
535                         // Select the current slide so that it is properly
536                         // visualized when the focus is moved to the edit view.
537                         GetPageSelector().SelectPage(GetCurrentSlideManager()->GetCurrentSlide());
538                     }
539                 }
540                 break;
541 
542             case VclEventId::ApplicationDataChanged:
543             {
544                 // Invalidate the preview cache.
545                 cache::PageCacheManager::Instance()->InvalidateAllCaches();
546 
547                 // Update the draw mode.
548                 DrawModeFlags nDrawMode (Application::GetSettings().GetStyleSettings().GetHighContrastMode()
549                     ? sd::OUTPUT_DRAWMODE_CONTRAST
550                     : sd::OUTPUT_DRAWMODE_COLOR);
551                 if (mrSlideSorter.GetViewShell() != nullptr)
552                     mrSlideSorter.GetViewShell()->GetFrameView()->SetDrawMode(nDrawMode);
553                 if (pActiveWindow != nullptr)
554                     pActiveWindow->SetDrawMode(nDrawMode);
555                 mrView.HandleDrawModeChange();
556 
557                 // When the system font has changed a layout has to be done.
558                 mrView.Resize();
559 
560                 // Update theme colors.
561                 mrSlideSorter.GetProperties()->HandleDataChangeEvent();
562                 mrSlideSorter.GetTheme()->Update(mrSlideSorter.GetProperties());
563                 mrView.HandleDataChangeEvent();
564             }
565             break;
566 
567             default:
568                 break;
569         }
570 }
571 
GetCtrlState(SfxItemSet & rSet)572 void SlideSorterController::GetCtrlState (SfxItemSet& rSet)
573 {
574     if (rSet.GetItemState(SID_RELOAD) != SfxItemState::UNKNOWN)
575     {
576         // let SFx en-/disable "last version"
577         SfxViewFrame* pSlideViewFrame = SfxViewFrame::Current();
578         DBG_ASSERT(pSlideViewFrame!=nullptr,
579             "SlideSorterController::GetCtrlState: ViewFrame not found");
580         if (pSlideViewFrame)
581         {
582             pSlideViewFrame->GetSlotState (SID_RELOAD, nullptr, &rSet);
583         }
584         else        // MI says: no MDIFrame --> disable
585         {
586             rSet.DisableItem(SID_RELOAD);
587         }
588     }
589 
590     // Output quality.
591     if (rSet.GetItemState(SID_OUTPUT_QUALITY_COLOR)==SfxItemState::DEFAULT
592         ||rSet.GetItemState(SID_OUTPUT_QUALITY_GRAYSCALE)==SfxItemState::DEFAULT
593         ||rSet.GetItemState(SID_OUTPUT_QUALITY_BLACKWHITE)==SfxItemState::DEFAULT
594         ||rSet.GetItemState(SID_OUTPUT_QUALITY_CONTRAST)==SfxItemState::DEFAULT)
595     {
596         if (mrSlideSorter.GetContentWindow())
597         {
598             DrawModeFlags nMode = mrSlideSorter.GetContentWindow()->GetDrawMode();
599             sal_uInt16 nQuality = 0;
600 
601             if (nMode == sd::OUTPUT_DRAWMODE_COLOR) {
602                 nQuality = 0;
603             } else if (nMode == sd::OUTPUT_DRAWMODE_GRAYSCALE) {
604                 nQuality = 1;
605             } else if (nMode == sd::OUTPUT_DRAWMODE_BLACKWHITE) {
606                 nQuality = 2;
607             } else if (nMode == sd::OUTPUT_DRAWMODE_CONTRAST) {
608                 nQuality = 3;
609             }
610 
611             rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_COLOR, nQuality==0));
612             rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_GRAYSCALE, nQuality==1));
613             rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_BLACKWHITE, nQuality==2));
614             rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_CONTRAST, nQuality==3));
615         }
616     }
617 
618     if (rSet.GetItemState(SID_MAIL_SCROLLBODY_PAGEDOWN) == SfxItemState::DEFAULT)
619     {
620         rSet.Put (SfxBoolItem( SID_MAIL_SCROLLBODY_PAGEDOWN, true));
621     }
622 }
623 
GetStatusBarState(SfxItemSet & rSet)624 void SlideSorterController::GetStatusBarState (SfxItemSet& rSet)
625 {
626     mpSlotManager->GetStatusBarState (rSet);
627 }
628 
ExecCtrl(SfxRequest & rRequest)629 void SlideSorterController::ExecCtrl (SfxRequest& rRequest)
630 {
631     mpSlotManager->ExecCtrl (rRequest);
632 }
633 
GetAttrState(SfxItemSet & rSet)634 void SlideSorterController::GetAttrState (SfxItemSet& rSet)
635 {
636     mpSlotManager->GetAttrState (rSet);
637 }
638 
UpdateAllPages()639 void SlideSorterController::UpdateAllPages()
640 {
641     // Do a redraw.
642     mrSlideSorter.GetContentWindow()->Invalidate();
643 }
644 
Resize(const::tools::Rectangle & rAvailableSpace)645 void SlideSorterController::Resize (const ::tools::Rectangle& rAvailableSpace)
646 {
647     if (maTotalWindowArea != rAvailableSpace)
648     {
649         maTotalWindowArea = rAvailableSpace;
650         Rearrange(true);
651     }
652 }
653 
Rearrange(bool bForce)654 void  SlideSorterController::Rearrange (bool bForce)
655 {
656     if (maTotalWindowArea.IsEmpty())
657         return;
658 
659     if (mnModelChangeLockCount>0)
660     {
661         mbIsForcedRearrangePending |= bForce;
662         return;
663     }
664     else
665         mbIsForcedRearrangePending = false;
666 
667     sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
668     if (!pWindow)
669         return;
670 
671     if (bForce)
672         mrView.UpdateOrientation();
673 
674     // Place the scroll bars.
675     ::tools::Rectangle aNewContentArea = GetScrollBarManager().PlaceScrollBars(
676         maTotalWindowArea,
677         mrView.GetOrientation() != view::Layouter::VERTICAL,
678         mrView.GetOrientation() != view::Layouter::HORIZONTAL);
679 
680     bool bSizeHasChanged (false);
681     // Only when bForce is not true we have to test for a size change in
682     // order to determine whether the window and the view have to be resized.
683     if ( ! bForce)
684     {
685         ::tools::Rectangle aCurrentContentArea (pWindow->GetPosPixel(), pWindow->GetOutputSizePixel());
686         bSizeHasChanged = (aNewContentArea != aCurrentContentArea);
687     }
688     if (bForce || bSizeHasChanged)
689     {
690         // The browser window gets the remaining space.
691         pWindow->SetPosSizePixel (aNewContentArea.TopLeft(), aNewContentArea.GetSize());
692         mrView.Resize();
693     }
694 
695     // Adapt the scroll bars to the new zoom factor of the browser
696     // window and the arrangement of the page objects.
697     GetScrollBarManager().UpdateScrollBars(!bForce);
698 
699     // Keep the current slide in the visible area.
700     GetVisibleAreaManager().RequestCurrentSlideVisible();
701 
702     mrView.RequestRepaint();
703 }
704 
CreateSelectionFunction(SfxRequest & rRequest)705 rtl::Reference<FuPoor> SlideSorterController::CreateSelectionFunction (SfxRequest& rRequest)
706 {
707     rtl::Reference<FuPoor> xFunc( SelectionFunction::Create(mrSlideSorter, rRequest) );
708     return xFunc;
709 }
710 
GetCurrentSelectionFunction() const711 ::rtl::Reference<SelectionFunction> SlideSorterController::GetCurrentSelectionFunction() const
712 {
713     rtl::Reference<FuPoor> pFunction (mrSlideSorter.GetViewShell()->GetCurrentFunction());
714     return ::rtl::Reference<SelectionFunction>(dynamic_cast<SelectionFunction*>(pFunction.get()));
715 }
716 
PrepareEditModeChange()717 void SlideSorterController::PrepareEditModeChange()
718 {
719     //  Before we throw away the page descriptors we prepare for selecting
720     //  descriptors in the other mode and for restoring the current
721     //  selection when switching back to the current mode.
722     if (mrModel.GetEditMode() != EditMode::Page)
723         return;
724 
725     maSelectionBeforeSwitch.clear();
726 
727     // Search for the first selected page and determine the master page
728     // used by its page object.  It will be selected after the switch.
729     // In the same loop the current selection is stored.
730     PageEnumeration aSelectedPages (
731         PageEnumerationProvider::CreateSelectedPagesEnumeration(mrModel));
732     while (aSelectedPages.HasMoreElements())
733     {
734         SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
735         SdPage* pPage = pDescriptor->GetPage();
736         // Remember the master page of the first selected descriptor.
737         if (pPage!=nullptr && mpEditModeChangeMasterPage==nullptr)
738             mpEditModeChangeMasterPage = &static_cast<SdPage&>(
739                 pPage->TRG_GetMasterPage());
740 
741         maSelectionBeforeSwitch.push_back(pPage);
742     }
743 
744     // Remember the current page.
745     if (mrSlideSorter.GetViewShell() != nullptr)
746         mnCurrentPageBeforeSwitch = (mrSlideSorter.GetViewShell()->GetViewShellBase()
747         .GetMainViewShell()->GetActualPage()->GetPageNum()-1)/2;
748 }
749 
ChangeEditMode(EditMode eEditMode)750 void SlideSorterController::ChangeEditMode (EditMode eEditMode)
751 {
752     bool bResult (false);
753     if (mrModel.GetEditMode() != eEditMode)
754     {
755         ModelChangeLock aLock (*this);
756         PreModelChange();
757         // Do the actual edit mode switching.
758         bResult = mrModel.SetEditMode(eEditMode);
759         if (bResult)
760             HandleModelChange();
761     }
762 }
763 
FinishEditModeChange()764 void SlideSorterController::FinishEditModeChange()
765 {
766     if (mrModel.GetEditMode() == EditMode::MasterPage)
767     {
768         mpPageSelector->DeselectAllPages();
769 
770         // Search for the master page that was determined in
771         // PrepareEditModeChange() and make it the current page.
772         PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
773         while (aAllPages.HasMoreElements())
774         {
775             SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
776             if (pDescriptor->GetPage() == mpEditModeChangeMasterPage)
777             {
778                 GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor);
779                 mpPageSelector->SelectPage(pDescriptor);
780                 break;
781             }
782         }
783     }
784     else
785     {
786         PageSelector::BroadcastLock aBroadcastLock (*mpPageSelector);
787 
788         SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(mnCurrentPageBeforeSwitch));
789         GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor);
790 
791         // Restore the selection.
792         mpPageSelector->DeselectAllPages();
793         for (const auto& rpPage : maSelectionBeforeSwitch)
794         {
795             mpPageSelector->SelectPage(rpPage);
796         }
797         maSelectionBeforeSwitch.clear( );
798     }
799     mpEditModeChangeMasterPage = nullptr;
800 }
801 
PageNameHasChanged(int nPageIndex,const OUString & rsOldName)802 void SlideSorterController::PageNameHasChanged (int nPageIndex, const OUString& rsOldName)
803 {
804     // Request a repaint for the page object whose name has changed.
805     model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex));
806     if (pDescriptor.get() != nullptr)
807         mrView.RequestRepaint(pDescriptor);
808 
809     // Get a pointer to the corresponding accessible object and notify
810     // that of the name change.
811     sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
812     if ( ! pWindow)
813         return;
814 
815     css::uno::Reference< css::accessibility::XAccessible >
816         xAccessible (pWindow->GetAccessible(false));
817     if ( ! xAccessible.is())
818         return;
819 
820     // Now comes a small hack.  We assume that the accessible object is
821     // an instantiation of AccessibleSlideSorterView and cast it to that
822     // class.  The cleaner alternative to this cast would be a new member
823     // in which we would store the last AccessibleSlideSorterView object
824     // created by SlideSorterViewShell::CreateAccessibleDocumentView().
825     // But then there is no guaranty that the accessible object obtained
826     // from the window really is that instance last created by
827     // CreateAccessibleDocumentView().
828     // However, the dynamic cast together with the check of the result
829     // being NULL should be safe enough.
830     ::accessibility::AccessibleSlideSorterView* pAccessibleView
831             = dynamic_cast< ::accessibility::AccessibleSlideSorterView*>(xAccessible.get());
832     if (pAccessibleView == nullptr)
833         return;
834 
835     ::accessibility::AccessibleSlideSorterObject* pChild
836             = pAccessibleView->GetAccessibleChildImplementation(nPageIndex);
837     if (pChild == nullptr || pChild->GetPage() == nullptr)
838         return;
839 
840     OUString sNewName (pChild->GetPage()->GetName());
841     pChild->FireAccessibleEvent(
842         css::accessibility::AccessibleEventId::NAME_CHANGED,
843         makeAny(rsOldName),
844         makeAny(sNewName));
845 }
846 
SetDocumentSlides(const Reference<container::XIndexAccess> & rxSlides)847 void SlideSorterController::SetDocumentSlides (const Reference<container::XIndexAccess>& rxSlides)
848 {
849     if (mrModel.GetDocumentSlides() != rxSlides)
850     {
851         ModelChangeLock aLock (*this);
852         PreModelChange();
853 
854         mrModel.SetDocumentSlides(rxSlides);
855     }
856 }
857 
GetVisibleAreaManager() const858 VisibleAreaManager& SlideSorterController::GetVisibleAreaManager() const
859 {
860     OSL_ASSERT(mpVisibleAreaManager);
861     return *mpVisibleAreaManager;
862 }
863 
CheckForMasterPageAssignment()864 void SlideSorterController::CheckForMasterPageAssignment()
865 {
866     if (mrModel.GetPageCount()%2==0)
867         return;
868     PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
869     while (aAllPages.HasMoreElements())
870     {
871         SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
872         if (pDescriptor->UpdateMasterPage())
873         {
874             mrView.GetPreviewCache()->InvalidatePreviewBitmap (
875                 pDescriptor->GetPage());
876         }
877     }
878 }
879 
CheckForSlideTransitionAssignment()880 void SlideSorterController::CheckForSlideTransitionAssignment()
881 {
882     if (mrModel.GetPageCount()%2==0)
883         return;
884     PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(mrModel));
885     while (aAllPages.HasMoreElements())
886     {
887         SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
888         if (pDescriptor->UpdateTransitionFlag())
889         {
890             mrView.GetPreviewCache()->InvalidatePreviewBitmap (
891                 pDescriptor->GetPage());
892         }
893     }
894 }
895 
896 //===== SlideSorterController::ModelChangeLock ================================
897 
ModelChangeLock(SlideSorterController & rController)898 SlideSorterController::ModelChangeLock::ModelChangeLock (
899     SlideSorterController& rController)
900     : mpController(&rController)
901 {
902     mpController->LockModelChange();
903 }
904 
~ModelChangeLock()905 SlideSorterController::ModelChangeLock::~ModelChangeLock() COVERITY_NOEXCEPT_FALSE
906 {
907     Release();
908 }
909 
Release()910 void SlideSorterController::ModelChangeLock::Release()
911 {
912     if (mpController != nullptr)
913     {
914         mpController->UnlockModelChange();
915         mpController = nullptr;
916     }
917 }
918 
919 } } } // end of namespace ::sd::slidesorter
920 
921 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
922