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