1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <DrawController.hxx>
23 #include <ViewShell.hxx>
24 #include <ViewShellBase.hxx>
25 #include <ViewShellManager.hxx>
26 #include <FormShellManager.hxx>
28 #include <framework/ConfigurationController.hxx>
29 #include <framework/ModuleController.hxx>
31 #include <comphelper/processfactory.hxx>
32 #include <comphelper/sequence.hxx>
33 #include <comphelper/servicehelper.hxx>
34 #include <cppuhelper/supportsservice.hxx>
35 #include <cppuhelper/typeprovider.hxx>
37 #include <com/sun/star/beans/PropertyAttribute.hpp>
38 #include <com/sun/star/drawing/XDrawSubController.hpp>
39 #include <com/sun/star/drawing/XLayer.hpp>
41 #include <slideshow.hxx>
43 #include <sal/log.hxx>
44 #include <svx/fmshell.hxx>
45 #include <vcl/svapp.hxx>
46 #include <vcl/EnumContext.hxx>
47 #include <svx/sidebar/ContextChangeEventMultiplexer.hxx>
48 #include <comphelper/diagnose_ex.hxx>
52 using namespace ::cppu
;
53 using namespace ::com::sun::star
;
54 using namespace ::com::sun::star::uno
;
55 using namespace ::com::sun::star::drawing::framework
;
56 using vcl::EnumContext
;
60 DrawController::DrawController (ViewShellBase
& rBase
) noexcept
61 : DrawControllerInterfaceBase(&rBase
),
62 BroadcastHelperOwner(SfxBaseController::m_aMutex
),
63 OPropertySetHelper(BroadcastHelperOwner::maBroadcastHelper
),
64 mpCurrentLayer(nullptr),
65 m_aSelectionTypeIdentifier(
66 cppu::UnoType
<view::XSelectionChangeListener
>::get()),
68 mpCurrentPage(nullptr),
69 mbMasterPageMode(false),
73 ProvideFrameworkControllers();
76 DrawController::~DrawController() noexcept
80 void DrawController::SetSubController (
81 const Reference
<drawing::XDrawSubController
>& rxSubController
)
83 // Update the internal state.
84 mxSubController
= rxSubController
;
85 mpPropertyArrayHelper
.reset();
86 maLastVisArea
= ::tools::Rectangle();
88 // Inform listeners about the changed state.
89 FireSelectionChangeListener();
94 IMPLEMENT_FORWARD_XINTERFACE2(
96 DrawControllerInterfaceBase
,
101 Sequence
<Type
> SAL_CALL
DrawController::getTypes()
104 // OPropertySetHelper does not provide getTypes, so we have to
105 // implement this method manually and list its three interfaces.
106 OTypeCollection
aTypeCollection (
107 cppu::UnoType
<beans::XMultiPropertySet
>::get(),
108 cppu::UnoType
<beans::XFastPropertySet
>::get(),
109 cppu::UnoType
<beans::XPropertySet
>::get());
111 return ::comphelper::concatSequences(
112 SfxBaseController::getTypes(),
113 aTypeCollection
.getTypes(),
114 DrawControllerInterfaceBase::getTypes());
117 IMPLEMENT_GET_IMPLEMENTATION_ID(DrawController
);
121 void SAL_CALL
DrawController::dispose()
126 SolarMutexGuard aGuard
;
133 std::shared_ptr
<ViewShell
> pViewShell
;
135 pViewShell
= mpBase
->GetMainViewShell();
138 pViewShell
->DeactivateCurrentFunction();
139 auto* pView
= pViewShell
->GetView();
141 pView
->getSearchContext().resetSearchFunction();
145 // When the controller has not been detached from its view
146 // shell, i.e. mpViewShell is not NULL, then tell PaneManager
147 // and ViewShellManager to clear the shell stack.
148 if (mxSubController
.is() && mpBase
!=nullptr)
150 mpBase
->DisconnectAllClients();
151 mpBase
->GetViewShellManager()->Shutdown();
154 OPropertySetHelper::disposing();
156 DisposeFrameworkControllers();
158 SfxBaseController::dispose();
161 void SAL_CALL
DrawController::addEventListener(
162 const Reference
<lang::XEventListener
>& xListener
)
165 SfxBaseController::addEventListener( xListener
);
168 void SAL_CALL
DrawController::removeEventListener (
169 const Reference
<lang::XEventListener
>& aListener
)
171 if(!rBHelper
.bDisposed
&& !rBHelper
.bInDispose
&& !mbDisposing
)
172 SfxBaseController::removeEventListener( aListener
);
176 sal_Bool SAL_CALL
DrawController::suspend( sal_Bool Suspend
)
180 ViewShellBase
* pViewShellBase
= GetViewShellBase();
183 // do not allow suspend if a slideshow needs this controller!
184 rtl::Reference
< SlideShow
> xSlideShow( SlideShow::GetSlideShow( *pViewShellBase
) );
187 if (xSlideShow
->IsInteractiveSlideshow())
189 // IASS mode: If preview mode, end it
190 if (xSlideShow
->isInteractiveSetup())
191 xSlideShow
->endInteractivePreview();
196 // use SfxBaseController::suspend( Suspend ) below
197 // for normal processing and return value
201 // original reaction - prevent exit
202 if (xSlideShow
->dependsOn(pViewShellBase
))
209 return SfxBaseController::suspend( Suspend
);
213 OUString SAL_CALL
DrawController::getImplementationName( )
215 // Do not throw an exception at the moment. This leads to a crash
216 // under Solaris on reload. See issue i70929 for details.
217 // ThrowIfDisposed();
218 return u
"DrawController"_ustr
;
221 constexpr OUString ssServiceName
= u
"com.sun.star.drawing.DrawingDocumentDrawView"_ustr
;
223 sal_Bool SAL_CALL
DrawController::supportsService (const OUString
& rsServiceName
)
225 return cppu::supportsService(this, rsServiceName
);
228 Sequence
<OUString
> SAL_CALL
DrawController::getSupportedServiceNames()
231 Sequence
<OUString
> aSupportedServices
{ ssServiceName
};
232 return aSupportedServices
;
235 //------ XSelectionSupplier --------------------------------------------
236 sal_Bool SAL_CALL
DrawController::select (const Any
& aSelection
)
239 SolarMutexGuard aGuard
;
241 if (mxSubController
.is())
242 return mxSubController
->select(aSelection
);
247 Any SAL_CALL
DrawController::getSelection()
250 SolarMutexGuard aGuard
;
252 if (mxSubController
.is())
253 return mxSubController
->getSelection();
258 void SAL_CALL
DrawController::addSelectionChangeListener(
259 const Reference
< view::XSelectionChangeListener
>& xListener
)
262 throw lang::DisposedException();
264 BroadcastHelperOwner::maBroadcastHelper
.addListener (m_aSelectionTypeIdentifier
, xListener
);
267 void SAL_CALL
DrawController::removeSelectionChangeListener(
268 const Reference
< view::XSelectionChangeListener
>& xListener
)
270 if (rBHelper
.bDisposed
)
271 throw lang::DisposedException();
273 BroadcastHelperOwner::maBroadcastHelper
.removeListener (m_aSelectionTypeIdentifier
, xListener
);
276 //===== lang::XEventListener ================================================
279 DrawController::disposing (const lang::EventObject
& )
283 //===== view::XSelectionChangeListener ======================================
286 DrawController::selectionChanged (const lang::EventObject
& rEvent
)
289 // Have to forward the event to our selection change listeners.
290 OInterfaceContainerHelper
* pListeners
= BroadcastHelperOwner::maBroadcastHelper
.getContainer(
291 cppu::UnoType
<view::XSelectionChangeListener
>::get());
295 // Re-send the event to all of our listeners.
296 OInterfaceIteratorHelper
aIterator (*pListeners
);
297 while (aIterator
.hasMoreElements())
301 view::XSelectionChangeListener
* pListener
=
302 static_cast<view::XSelectionChangeListener
*>(
304 if (pListener
!= nullptr)
305 pListener
->selectionChanged (rEvent
);
307 catch (const RuntimeException
&)
315 void SAL_CALL
DrawController::setCurrentPage( const Reference
< drawing::XDrawPage
>& xPage
)
318 SolarMutexGuard aGuard
;
320 if (mxSubController
.is())
321 mxSubController
->setCurrentPage(xPage
);
324 Reference
< drawing::XDrawPage
> SAL_CALL
DrawController::getCurrentPage()
327 SolarMutexGuard aGuard
;
328 Reference
<drawing::XDrawPage
> xPage
;
330 // Get current page from sub controller.
331 if (mxSubController
.is())
332 xPage
= mxSubController
->getCurrentPage();
334 // When there is not yet a sub controller (during initialization) then fall back
335 // to the current page in mpCurrentPage.
337 if (rtl::Reference
<SdPage
> pPage
= mpCurrentPage
.get())
338 xPage
.set(pPage
->getUnoPage(), UNO_QUERY
);
343 void DrawController::FireVisAreaChanged (const ::tools::Rectangle
& rVisArea
) noexcept
345 if( maLastVisArea
== rVisArea
)
349 aNewValue
<<= awt::Rectangle(
353 rVisArea
.GetHeight() );
356 aOldValue
<<= awt::Rectangle(
357 maLastVisArea
.Left(),
359 maLastVisArea
.GetWidth(),
360 maLastVisArea
.GetHeight() );
362 FirePropertyChange (PROPERTY_WORKAREA
, aNewValue
, aOldValue
);
364 maLastVisArea
= rVisArea
;
367 void DrawController::FireSelectionChangeListener() noexcept
369 OInterfaceContainerHelper
* pLC
= BroadcastHelperOwner::maBroadcastHelper
.getContainer(
370 m_aSelectionTypeIdentifier
);
374 Reference
< XInterface
> xSource( static_cast<XWeak
*>(this) );
375 const lang::EventObject
aEvent( xSource
);
377 // iterate over all listeners and send events
378 OInterfaceIteratorHelper
aIt( *pLC
);
379 while( aIt
.hasMoreElements() )
383 view::XSelectionChangeListener
* pL
=
384 static_cast<view::XSelectionChangeListener
*>(aIt
.next());
386 pL
->selectionChanged( aEvent
);
388 catch (const RuntimeException
&)
394 void DrawController::FireChangeEditMode (bool bMasterPageMode
) noexcept
396 if (bMasterPageMode
!= mbMasterPageMode
)
399 PROPERTY_MASTERPAGEMODE
,
400 Any(bMasterPageMode
),
401 Any(mbMasterPageMode
));
403 mbMasterPageMode
= bMasterPageMode
;
407 void DrawController::FireChangeLayerMode (bool bLayerMode
) noexcept
409 if (bLayerMode
!= mbLayerMode
)
416 mbLayerMode
= bLayerMode
;
420 void DrawController::FireSwitchCurrentPage (SdPage
* pNewCurrentPage
) noexcept
422 rtl::Reference
<SdrPage
> pCurrentPage
= mpCurrentPage
.get();
423 if (pNewCurrentPage
== pCurrentPage
.get())
429 Any(Reference
<drawing::XDrawPage
>(pNewCurrentPage
->getUnoPage(), UNO_QUERY
)));
432 if (pCurrentPage
!= nullptr)
434 Reference
<drawing::XDrawPage
> xOldPage (pCurrentPage
->getUnoPage(), UNO_QUERY
);
435 aOldValue
<<= xOldPage
;
438 FirePropertyChange(PROPERTY_CURRENTPAGE
, aNewValue
, aOldValue
);
440 mpCurrentPage
= pNewCurrentPage
;
442 catch (const uno::Exception
&)
444 TOOLS_WARN_EXCEPTION("sd", "sd::SdUnoDrawView::FireSwitchCurrentPage()");
448 void DrawController::NotifyAccUpdate()
450 sal_Int32 nHandle
= PROPERTY_UPDATEACC
;
451 Any aNewValue
, aOldValue
;
452 fire (&nHandle
, &aNewValue
, &aOldValue
, 1, false);
455 void DrawController::fireChangeLayer( css::uno::Reference
< css::drawing::XLayer
>* pCurrentLayer
) noexcept
457 if( pCurrentLayer
!= mpCurrentLayer
)
459 sal_Int32 nHandle
= PROPERTY_ACTIVE_LAYER
;
461 Any
aNewValue ( *pCurrentLayer
);
465 fire (&nHandle
, &aNewValue
, &aOldValue
, 1, false);
467 mpCurrentLayer
= pCurrentLayer
;
471 // This method is only called in slide show and outline view
472 //void DrawController::fireSwitchCurrentPage(String pageName ) throw()
473 void DrawController::fireSwitchCurrentPage(sal_Int32 pageIndex
) noexcept
477 //OUString aPageName( pageName );
478 //aNewValue <<= aPageName ;
479 aNewValue
<<= pageIndex
;
481 // Use new property to handle page change event
482 sal_Int32 nHandles
= PROPERTY_PAGE_CHANGE
;
483 fire( &nHandles
, &aNewValue
, &aOldValue
, 1, false );
486 void DrawController::FirePropertyChange (
488 const Any
& rNewValue
,
489 const Any
& rOldValue
)
493 fire (&nHandle
, &rNewValue
, &rOldValue
, 1, false);
495 catch (const RuntimeException
&)
497 // Ignore this exception. Exceptions should be handled in the
498 // fire() function so that all listeners are called. This is
499 // not the case at the moment, so we simply ignore the
505 void DrawController::BroadcastContextChange() const
507 std::shared_ptr
<ViewShell
> pViewShell (mpBase
->GetMainViewShell());
511 EnumContext::Context
eContext (EnumContext::Context::Unknown
);
512 switch (pViewShell
->GetShellType())
514 case ViewShell::ST_IMPRESS
:
515 case ViewShell::ST_DRAW
:
516 if (mbMasterPageMode
)
517 eContext
= EnumContext::Context::MasterPage
;
519 eContext
= EnumContext::Context::DrawPage
;
522 case ViewShell::ST_NOTES
:
523 eContext
= EnumContext::Context::NotesPage
;
526 case ViewShell::ST_HANDOUT
:
527 eContext
= EnumContext::Context::HandoutPage
;
530 case ViewShell::ST_OUTLINE
:
531 eContext
= EnumContext::Context::OutlineText
;
534 case ViewShell::ST_SLIDE_SORTER
:
535 eContext
= EnumContext::Context::SlidesorterPage
;
538 case ViewShell::ST_PRESENTATION
:
539 case ViewShell::ST_NONE
:
541 eContext
= EnumContext::Context::Empty
;
545 ContextChangeEventMultiplexer::NotifyContextChange(mpBase
, eContext
);
548 void DrawController::ReleaseViewShellBase()
550 DisposeFrameworkControllers();
554 //===== XControllerManager ==============================================================
556 Reference
<XConfigurationController
> SAL_CALL
557 DrawController::getConfigurationController()
561 return mxConfigurationController
;
564 const rtl::Reference
<sd::framework::ConfigurationController
> &
565 DrawController::getConfigurationControllerImpl()
569 return mxConfigurationController
;
572 Reference
<XModuleController
> SAL_CALL
573 DrawController::getModuleController()
577 return mxModuleController
;
580 //===== Properties ============================================================
582 void DrawController::FillPropertyTable (
583 ::std::vector
<beans::Property
>& rProperties
)
585 rProperties
.emplace_back("VisibleArea",
587 ::cppu::UnoType
< css::awt::Rectangle
>::get(),
588 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
);
589 rProperties
.emplace_back(
591 PROPERTY_SUB_CONTROLLER
,
592 cppu::UnoType
<drawing::XDrawSubController
>::get(),
593 beans::PropertyAttribute::BOUND
);
594 rProperties
.emplace_back(
596 PROPERTY_CURRENTPAGE
,
597 cppu::UnoType
<drawing::XDrawPage
>::get(),
598 beans::PropertyAttribute::BOUND
);
599 rProperties
.emplace_back("IsLayerMode",
601 cppu::UnoType
<bool>::get(),
602 beans::PropertyAttribute::BOUND
);
603 rProperties
.emplace_back("IsMasterPageMode",
604 PROPERTY_MASTERPAGEMODE
,
605 cppu::UnoType
<bool>::get(),
606 beans::PropertyAttribute::BOUND
);
607 rProperties
.emplace_back("ActiveLayer",
608 PROPERTY_ACTIVE_LAYER
,
609 cppu::UnoType
<drawing::XLayer
>::get(),
610 beans::PropertyAttribute::BOUND
);
611 rProperties
.emplace_back("ZoomValue",
613 ::cppu::UnoType
<sal_Int16
>::get(),
614 beans::PropertyAttribute::BOUND
);
615 rProperties
.emplace_back("ZoomType",
617 ::cppu::UnoType
<sal_Int16
>::get(),
618 beans::PropertyAttribute::BOUND
);
619 rProperties
.emplace_back("ViewOffset",
621 ::cppu::UnoType
< css::awt::Point
>::get(),
622 beans::PropertyAttribute::BOUND
);
623 rProperties
.emplace_back("DrawViewMode",
624 PROPERTY_DRAWVIEWMODE
,
625 ::cppu::UnoType
< css::awt::Point
>::get(),
626 beans::PropertyAttribute::BOUND
|beans::PropertyAttribute::READONLY
|beans::PropertyAttribute::MAYBEVOID
);
627 // add new property to update current page's acc information
628 rProperties
.emplace_back( "UpdateAcc",
630 ::cppu::UnoType
<sal_Int16
>::get(),
631 beans::PropertyAttribute::BOUND
);
632 rProperties
.emplace_back( "PageChange",
633 PROPERTY_PAGE_CHANGE
,
634 ::cppu::UnoType
<sal_Int16
>::get(),
635 beans::PropertyAttribute::BOUND
);
638 IPropertyArrayHelper
& DrawController::getInfoHelper()
640 SolarMutexGuard aGuard
;
642 if (mpPropertyArrayHelper
== nullptr)
644 ::std::vector
<beans::Property
> aProperties
;
645 FillPropertyTable(aProperties
);
646 mpPropertyArrayHelper
.reset(new OPropertyArrayHelper(comphelper::containerToSequence(aProperties
), false));
649 return *mpPropertyArrayHelper
;
652 Reference
< beans::XPropertySetInfo
> DrawController::getPropertySetInfo()
654 SolarMutexGuard aGuard
;
656 static Reference
< beans::XPropertySetInfo
> xInfo( createPropertySetInfo( getInfoHelper() ) );
660 uno::Reference
< form::runtime::XFormController
> SAL_CALL
DrawController::getFormController( const uno::Reference
< form::XForm
>& Form
)
662 SolarMutexGuard aGuard
;
664 FmFormShell
* pFormShell
= mpBase
->GetFormShellManager()->GetFormShell();
665 SdrView
* pSdrView
= mpBase
->GetDrawView();
666 std::shared_ptr
<ViewShell
> pViewShell
= mpBase
->GetMainViewShell();
667 ::sd::Window
* pWindow
= pViewShell
? pViewShell
->GetActiveWindow() : nullptr;
669 uno::Reference
< form::runtime::XFormController
> xController
;
670 if ( pFormShell
&& pSdrView
&& pWindow
)
671 xController
= FmFormShell::GetFormController( Form
, *pSdrView
, *pWindow
->GetOutDev() );
675 sal_Bool SAL_CALL
DrawController::isFormDesignMode( )
677 SolarMutexGuard aGuard
;
679 bool bIsDesignMode
= true;
681 FmFormShell
* pFormShell
= mpBase
->GetFormShellManager()->GetFormShell();
683 bIsDesignMode
= pFormShell
->IsDesignMode();
685 return bIsDesignMode
;
688 void SAL_CALL
DrawController::setFormDesignMode( sal_Bool DesignMode
)
690 SolarMutexGuard aGuard
;
692 FmFormShell
* pFormShell
= mpBase
->GetFormShellManager()->GetFormShell();
694 pFormShell
->SetDesignMode( DesignMode
);
697 uno::Reference
< awt::XControl
> SAL_CALL
DrawController::getControl( const uno::Reference
< awt::XControlModel
>& xModel
)
699 SolarMutexGuard aGuard
;
701 FmFormShell
* pFormShell
= mpBase
->GetFormShellManager()->GetFormShell();
702 SdrView
* pSdrView
= mpBase
->GetDrawView();
703 std::shared_ptr
<ViewShell
> pViewShell
= mpBase
->GetMainViewShell();
704 ::sd::Window
* pWindow
= pViewShell
? pViewShell
->GetActiveWindow() : nullptr;
706 uno::Reference
< awt::XControl
> xControl
;
707 if ( pFormShell
&& pSdrView
&& pWindow
)
708 pFormShell
->GetFormControl( xModel
, *pSdrView
, *pWindow
->GetOutDev(), xControl
);
712 sal_Bool
DrawController::convertFastPropertyValue (
713 Any
& rConvertedValue
,
718 bool bResult
= false;
720 if (nHandle
== PROPERTY_SUB_CONTROLLER
)
722 rOldValue
<<= mxSubController
;
723 rConvertedValue
<<= Reference
<drawing::XDrawSubController
>(rValue
, UNO_QUERY
);
724 bResult
= (rOldValue
!= rConvertedValue
);
726 else if (mxSubController
.is())
728 rConvertedValue
= rValue
;
731 rOldValue
= mxSubController
->getFastPropertyValue(nHandle
);
732 bResult
= (rOldValue
!= rConvertedValue
);
734 catch (const beans::UnknownPropertyException
&)
736 // The property is unknown and thus an illegal argument to this method.
737 throw css::lang::IllegalArgumentException();
744 void DrawController::setFastPropertyValue_NoBroadcast (
748 SolarMutexGuard aGuard
;
749 if (nHandle
== PROPERTY_SUB_CONTROLLER
)
750 SetSubController(Reference
<drawing::XDrawSubController
>(rValue
, UNO_QUERY
));
751 else if (mxSubController
.is())
752 mxSubController
->setFastPropertyValue(nHandle
, rValue
);
755 void DrawController::getFastPropertyValue (
757 sal_Int32 nHandle
) const
759 SolarMutexGuard aGuard
;
763 case PROPERTY_WORKAREA
:
764 rRet
<<= awt::Rectangle(
765 maLastVisArea
.Left(),
767 maLastVisArea
.GetWidth(),
768 maLastVisArea
.GetHeight());
771 case PROPERTY_SUB_CONTROLLER
:
772 rRet
<<= mxSubController
;
776 if (mxSubController
.is())
777 rRet
= mxSubController
->getFastPropertyValue(nHandle
);
782 void DrawController::ProvideFrameworkControllers()
784 SolarMutexGuard aGuard
;
787 mxConfigurationController
= new sd::framework::ConfigurationController(this);
788 mxModuleController
= new sd::framework::ModuleController(this);
790 catch (const RuntimeException
&)
792 mxConfigurationController
= nullptr;
793 mxModuleController
= nullptr;
797 void DrawController::DisposeFrameworkControllers()
799 if (mxModuleController
.is())
800 mxModuleController
->dispose();
802 if (mxConfigurationController
.is())
803 mxConfigurationController
->dispose();
806 void DrawController::ThrowIfDisposed() const
808 if (rBHelper
.bDisposed
|| rBHelper
.bInDispose
|| mbDisposing
)
810 SAL_WARN("sd", "Calling disposed DrawController object. Throwing exception.");
811 throw lang::DisposedException (
812 u
"DrawController object has already been disposed"_ustr
,
813 const_cast<uno::XWeak
*>(static_cast<const uno::XWeak
*>(this)));
817 } // end of namespace sd
819 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */