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 <sdr/contact/viewcontactofunocontrol.hxx>
21 #include <sdr/contact/viewobjectcontactofunocontrol.hxx>
22 #include <com/sun/star/container/XChild.hpp>
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/util/XCloneable.hpp>
25 #include <com/sun/star/uno/XComponentContext.hpp>
26 #include <comphelper/processfactory.hxx>
27 #include <svx/svdouno.hxx>
28 #include <svx/svdpagv.hxx>
29 #include <svx/svdmodel.hxx>
30 #include <svx/dialmgr.hxx>
31 #include <svx/strings.hrc>
32 #include <svx/svdview.hxx>
33 #include <svx/svdorect.hxx>
34 #include <svx/svdviter.hxx>
35 #include <rtl/ref.hxx>
36 #include <svx/sdrpagewindow.hxx>
37 #include <comphelper/diagnose_ex.hxx>
38 #include <tools/debug.hxx>
39 #include <o3tl/sorted_vector.hxx>
41 using namespace ::com::sun::star
;
42 using namespace sdr::contact
;
48 // Helper class SdrControlEventListenerImpl
50 #include <com/sun/star/lang/XEventListener.hpp>
52 #include <cppuhelper/implbase.hxx>
55 class SdrControlEventListenerImpl
: public ::cppu::WeakImplHelper
< css::lang::XEventListener
>
61 explicit SdrControlEventListenerImpl(SdrUnoObj
* _pObj
)
66 virtual void SAL_CALL
disposing( const css::lang::EventObject
& Source
) override
;
68 void StopListening(const uno::Reference
< lang::XComponent
>& xComp
);
69 void StartListening(const uno::Reference
< lang::XComponent
>& xComp
);
73 void SAL_CALL
SdrControlEventListenerImpl::disposing( const css::lang::EventObject
& /*Source*/)
77 pObj
->xUnoControlModel
= nullptr;
81 void SdrControlEventListenerImpl::StopListening(const uno::Reference
< lang::XComponent
>& xComp
)
84 xComp
->removeEventListener(this);
87 void SdrControlEventListenerImpl::StartListening(const uno::Reference
< lang::XComponent
>& xComp
)
90 xComp
->addEventListener(this);
94 struct SdrUnoObjDataHolder
96 mutable ::rtl::Reference
< SdrControlEventListenerImpl
>
103 void lcl_ensureControlVisibility( SdrView
const * _pView
, const SdrUnoObj
* _pObject
, bool _bVisible
)
105 OSL_PRECOND( _pObject
, "lcl_ensureControlVisibility: no object -> no survival!" );
107 SdrPageView
* pPageView
= _pView
? _pView
->GetSdrPageView() : nullptr;
108 DBG_ASSERT( pPageView
, "lcl_ensureControlVisibility: no view found!" );
112 ViewContact
& rUnoControlContact( _pObject
->GetViewContact() );
114 for ( sal_uInt32 i
= 0; i
< pPageView
->PageWindowCount(); ++i
)
116 SdrPageWindow
* pPageWindow
= pPageView
->GetPageWindow( i
);
117 DBG_ASSERT( pPageWindow
, "lcl_ensureControlVisibility: invalid PageViewWindow!" );
121 if ( !pPageWindow
->HasObjectContact() )
124 ObjectContact
& rPageViewContact( pPageWindow
->GetObjectContact() );
125 const ViewObjectContact
& rViewObjectContact( rUnoControlContact
.GetViewObjectContact( rPageViewContact
) );
126 const ViewObjectContactOfUnoControl
* pUnoControlContact
= dynamic_cast< const ViewObjectContactOfUnoControl
* >( &rViewObjectContact
);
127 DBG_ASSERT( pUnoControlContact
, "lcl_ensureControlVisibility: wrong ViewObjectContact type!" );
128 if ( !pUnoControlContact
)
131 pUnoControlContact
->ensureControlVisibility( _bVisible
);
136 SdrUnoObj::SdrUnoObj(
138 const OUString
& rModelName
)
139 : SdrRectObj(rSdrModel
),
140 m_pImpl( new SdrUnoObjDataHolder
)
142 osl_atomic_increment(&m_refCount
); // prevent deletion during creation
145 m_pImpl
->pEventListener
= new SdrControlEventListenerImpl(this);
147 // only an owner may create independently
148 if (!rModelName
.isEmpty())
149 CreateUnoControlModel(rModelName
);
150 osl_atomic_decrement(&m_refCount
);
153 SdrUnoObj::SdrUnoObj( SdrModel
& rSdrModel
, SdrUnoObj
const & rSource
)
154 : SdrRectObj(rSdrModel
, rSource
),
155 m_pImpl( new SdrUnoObjDataHolder
)
159 m_pImpl
->pEventListener
= new SdrControlEventListenerImpl(this);
161 aUnoControlModelTypeName
= rSource
.aUnoControlModelTypeName
;
162 aUnoControlTypeName
= rSource
.aUnoControlTypeName
;
164 // copy the uno control model
165 const uno::Reference
< awt::XControlModel
> xSourceControlModel
= rSource
.GetUnoControlModel();
166 if ( xSourceControlModel
.is() )
170 uno::Reference
< util::XCloneable
> xClone( xSourceControlModel
, uno::UNO_QUERY_THROW
);
171 xUnoControlModel
.set( xClone
->createClone(), uno::UNO_QUERY_THROW
);
173 catch( const uno::Exception
& )
175 DBG_UNHANDLED_EXCEPTION("svx");
179 // get service name of the control from the control model
180 uno::Reference
< beans::XPropertySet
> xSet(xUnoControlModel
, uno::UNO_QUERY
);
183 uno::Any
aValue( xSet
->getPropertyValue("DefaultControl") );
186 if( aValue
>>= aStr
)
187 aUnoControlTypeName
= aStr
;
190 uno::Reference
< lang::XComponent
> xComp(xUnoControlModel
, uno::UNO_QUERY
);
192 m_pImpl
->pEventListener
->StartListening(xComp
);
195 SdrUnoObj::SdrUnoObj(
197 const OUString
& rModelName
,
198 const uno::Reference
< lang::XMultiServiceFactory
>& rxSFac
)
199 : SdrRectObj(rSdrModel
),
200 m_pImpl( new SdrUnoObjDataHolder
)
204 m_pImpl
->pEventListener
= new SdrControlEventListenerImpl(this);
206 // only an owner may create independently
207 if (!rModelName
.isEmpty())
208 CreateUnoControlModel(rModelName
,rxSFac
);
211 SdrUnoObj::~SdrUnoObj()
215 // clean up the control model
216 uno::Reference
< lang::XComponent
> xComp(xUnoControlModel
, uno::UNO_QUERY
);
219 // is the control model owned by its environment?
220 uno::Reference
< container::XChild
> xContent(xUnoControlModel
, uno::UNO_QUERY
);
221 if (xContent
.is() && !xContent
->getParent().is())
224 m_pImpl
->pEventListener
->StopListening(xComp
);
227 catch( const uno::Exception
& )
229 TOOLS_WARN_EXCEPTION( "svx", "SdrUnoObj::~SdrUnoObj" );
233 void SdrUnoObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
235 rInfo
.bRotateFreeAllowed
= false;
236 rInfo
.bRotate90Allowed
= false;
237 rInfo
.bMirrorFreeAllowed
= false;
238 rInfo
.bMirror45Allowed
= false;
239 rInfo
.bMirror90Allowed
= false;
240 rInfo
.bTransparenceAllowed
= false;
241 rInfo
.bShearAllowed
= false;
242 rInfo
.bEdgeRadiusAllowed
= false;
243 rInfo
.bNoOrthoDesired
= false;
244 rInfo
.bCanConvToPath
= false;
245 rInfo
.bCanConvToPoly
= false;
246 rInfo
.bCanConvToPathLineToArea
= false;
247 rInfo
.bCanConvToPolyLineToArea
= false;
248 rInfo
.bCanConvToContour
= false;
251 SdrObjKind
SdrUnoObj::GetObjIdentifier() const
253 return SdrObjKind::UNO
;
256 void SdrUnoObj::SetContextWritingMode( const sal_Int16 _nContextWritingMode
)
260 uno::Reference
< beans::XPropertySet
> xModelProperties( GetUnoControlModel(), uno::UNO_QUERY_THROW
);
261 xModelProperties
->setPropertyValue( "ContextWritingMode", uno::Any( _nContextWritingMode
) );
263 catch( const uno::Exception
& )
265 DBG_UNHANDLED_EXCEPTION("svx");
269 OUString
SdrUnoObj::TakeObjNameSingul() const
271 OUString
sName(SvxResId(STR_ObjNameSingulUno
));
273 OUString
aName(GetName());
274 if (!aName
.isEmpty())
275 sName
+= " '" + aName
+ "'";
280 OUString
SdrUnoObj::TakeObjNamePlural() const
282 return SvxResId(STR_ObjNamePluralUno
);
285 rtl::Reference
<SdrObject
> SdrUnoObj::CloneSdrObject(SdrModel
& rTargetModel
) const
287 return new SdrUnoObj(rTargetModel
, *this);
290 void SdrUnoObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
292 SdrRectObj::NbcResize(rRef
,xFact
,yFact
);
294 if (maGeo
.nShearAngle
==0_deg100
&& maGeo
.nRotationAngle
==0_deg100
)
298 if (maGeo
.nRotationAngle
>=9000_deg100
&& maGeo
.nRotationAngle
<27000_deg100
)
300 moveRectangle(getRectangle().Left() - getRectangle().Right(), getRectangle().Top() - getRectangle().Bottom());
303 maGeo
.nRotationAngle
= 0_deg100
;
304 maGeo
.nShearAngle
= 0_deg100
;
305 maGeo
.mfSinRotationAngle
= 0.0;
306 maGeo
.mfCosRotationAngle
= 1.0;
307 maGeo
.mfTanShearAngle
= 0.0;
308 SetBoundAndSnapRectsDirty();
312 bool SdrUnoObj::hasSpecialDrag() const
314 // no special drag; we have no rounding rect and
315 // do want frame handles
319 void SdrUnoObj::NbcSetLayer( SdrLayerID _nLayer
)
321 if ( GetLayer() == _nLayer
)
322 { // redundant call -> not interested in doing anything here
323 SdrRectObj::NbcSetLayer( _nLayer
);
327 // we need some special handling here in case we're moved from an invisible layer
328 // to a visible one, or vice versa
329 // (relative to a layer. Remember that the visibility of a layer is a view attribute
330 // - the same layer can be visible in one view, and invisible in another view, at the
333 // collect all views in which our old layer is visible
334 o3tl::sorted_vector
< SdrView
* > aPreviouslyVisible
;
337 SdrViewIter
aIter( this );
338 for ( SdrView
* pView
= aIter
.FirstView(); pView
; pView
= aIter
.NextView() )
339 aPreviouslyVisible
.insert( pView
);
342 SdrRectObj::NbcSetLayer( _nLayer
);
344 // collect all views in which our new layer is visible
345 o3tl::sorted_vector
< SdrView
* > aNewlyVisible
;
348 SdrViewIter
aIter( this );
349 for ( SdrView
* pView
= aIter
.FirstView(); pView
; pView
= aIter
.NextView() )
351 if ( aPreviouslyVisible
.erase(pView
) == 0 )
353 // in pView, we were visible _before_ the layer change, and are
354 // _not_ visible after the layer change
355 // => remember this view, as our visibility there changed
356 aNewlyVisible
.insert( pView
);
361 // now aPreviouslyVisible contains all views where we became invisible
362 for (const auto& rpView
: aPreviouslyVisible
)
364 lcl_ensureControlVisibility( rpView
, this, false );
367 // and aNewlyVisible all views where we became visible
368 for (const auto& rpView
: aNewlyVisible
)
370 lcl_ensureControlVisibility( rpView
, this, true );
374 void SdrUnoObj::CreateUnoControlModel(const OUString
& rModelName
)
376 DBG_ASSERT(!xUnoControlModel
.is(), "model already exists");
378 aUnoControlModelTypeName
= rModelName
;
380 uno::Reference
< awt::XControlModel
> xModel
;
381 uno::Reference
< uno::XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
382 if (!aUnoControlModelTypeName
.isEmpty() )
384 xModel
.set(xContext
->getServiceManager()->createInstanceWithContext(
385 aUnoControlModelTypeName
, xContext
), uno::UNO_QUERY
);
391 SetUnoControlModel(xModel
);
394 void SdrUnoObj::CreateUnoControlModel(const OUString
& rModelName
,
395 const uno::Reference
< lang::XMultiServiceFactory
>& rxSFac
)
397 DBG_ASSERT(!xUnoControlModel
.is(), "model already exists");
399 aUnoControlModelTypeName
= rModelName
;
401 uno::Reference
< awt::XControlModel
> xModel
;
402 if (!aUnoControlModelTypeName
.isEmpty() && rxSFac
.is() )
404 xModel
.set(rxSFac
->createInstance(aUnoControlModelTypeName
), uno::UNO_QUERY
);
410 SetUnoControlModel(xModel
);
413 void SdrUnoObj::SetUnoControlModel( const uno::Reference
< awt::XControlModel
>& xModel
)
415 if (xUnoControlModel
.is())
417 uno::Reference
< lang::XComponent
> xComp(xUnoControlModel
, uno::UNO_QUERY
);
419 m_pImpl
->pEventListener
->StopListening(xComp
);
422 xUnoControlModel
= xModel
;
424 // control model has to contain service name of the control
425 if (xUnoControlModel
.is())
427 uno::Reference
< beans::XPropertySet
> xSet(xUnoControlModel
, uno::UNO_QUERY
);
430 uno::Any
aValue( xSet
->getPropertyValue("DefaultControl") );
432 if( aValue
>>= aStr
)
433 aUnoControlTypeName
= aStr
;
436 uno::Reference
< lang::XComponent
> xComp(xUnoControlModel
, uno::UNO_QUERY
);
438 m_pImpl
->pEventListener
->StartListening(xComp
);
441 // invalidate all ViewObject contacts
442 ViewContactOfUnoControl
* pVC
= nullptr;
443 if ( impl_getViewContact( pVC
) )
445 // flushViewObjectContacts() removes all existing VOCs for the local DrawHierarchy. This
446 // is always allowed since they will be re-created on demand (and with the changed model)
447 GetViewContact().flushViewObjectContacts();
452 uno::Reference
< awt::XControl
> SdrUnoObj::GetUnoControl(const SdrView
& _rView
, const OutputDevice
& _rOut
) const
454 uno::Reference
< awt::XControl
> xControl
;
456 SdrPageView
* pPageView
= _rView
.GetSdrPageView();
457 OSL_ENSURE( pPageView
&& getSdrPageFromSdrObject() == pPageView
->GetPage(), "SdrUnoObj::GetUnoControl: This object is not displayed in that particular view!" );
458 if ( !pPageView
|| getSdrPageFromSdrObject() != pPageView
->GetPage() )
461 SdrPageWindow
* pPageWindow
= pPageView
->FindPageWindow( _rOut
);
462 OSL_ENSURE( pPageWindow
, "SdrUnoObj::GetUnoControl: did not find my SdrPageWindow!" );
466 ViewObjectContact
& rViewObjectContact( GetViewContact().GetViewObjectContact( pPageWindow
->GetObjectContact() ) );
467 ViewObjectContactOfUnoControl
* pUnoContact
= dynamic_cast< ViewObjectContactOfUnoControl
* >( &rViewObjectContact
);
468 OSL_ENSURE( pUnoContact
, "SdrUnoObj::GetUnoControl: wrong contact type!" );
470 xControl
= pUnoContact
->getControl();
476 uno::Reference
< awt::XControl
> SdrUnoObj::GetTemporaryControlForWindow(
477 const vcl::Window
& _rWindow
, uno::Reference
< awt::XControlContainer
>& _inout_ControlContainer
) const
479 uno::Reference
< awt::XControl
> xControl
;
481 ViewContactOfUnoControl
* pVC
= nullptr;
482 if ( impl_getViewContact( pVC
) )
483 xControl
= pVC
->getTemporaryControlForWindow( _rWindow
, _inout_ControlContainer
);
489 bool SdrUnoObj::impl_getViewContact( ViewContactOfUnoControl
*& _out_rpContact
) const
491 ViewContact
& rViewContact( GetViewContact() );
492 _out_rpContact
= dynamic_cast< ViewContactOfUnoControl
* >( &rViewContact
);
493 DBG_ASSERT( _out_rpContact
, "SdrUnoObj::impl_getViewContact: could not find my ViewContact!" );
494 return ( _out_rpContact
!= nullptr );
498 std::unique_ptr
<sdr::contact::ViewContact
> SdrUnoObj::CreateObjectSpecificViewContact()
500 return std::make_unique
<sdr::contact::ViewContactOfUnoControl
>( *this );
504 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */