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 .
21 #include <controls/controlmodelcontainerbase.hxx>
22 #include <vcl/svapp.hxx>
23 #include <o3tl/safeint.hxx>
24 #include <osl/mutex.hxx>
25 #include <helper/property.hxx>
26 #include <helper/servicenames.hxx>
27 #include <controls/geometrycontrolmodel.hxx>
28 #include <toolkit/controls/unocontrols.hxx>
29 #include <controls/formattedcontrol.hxx>
30 #include <controls/roadmapcontrol.hxx>
31 #include <controls/tkscrollbar.hxx>
32 #include <controls/tabpagemodel.hxx>
33 #include <controls/stdtabcontroller.hxx>
34 #include <com/sun/star/awt/PosSize.hpp>
35 #include <com/sun/star/resource/XStringResourceResolver.hpp>
36 #include <com/sun/star/lang/XInitialization.hpp>
37 #include <cppuhelper/queryinterface.hxx>
38 #include <cppuhelper/weak.hxx>
39 #include <cppuhelper/weakagg.hxx>
40 #include <tools/debug.hxx>
41 #include <comphelper/diagnose_ex.hxx>
42 #include <vcl/outdev.hxx>
43 #include <comphelper/types.hxx>
45 #include "tree/treecontrol.hxx"
46 #include "grid/gridcontrol.hxx"
47 #include <controls/tabpagecontainer.hxx>
51 #include <tools/urlobj.hxx>
52 #include <osl/file.hxx>
53 #include <sal/log.hxx>
54 #include <controls/dialogcontrol.hxx>
56 #include <helper/unopropertyarrayhelper.hxx>
57 #include "controlmodelcontainerbase_internal.hxx"
59 using namespace ::com::sun::star
;
60 using namespace ::com::sun::star::uno
;
61 using namespace ::com::sun::star::awt
;
62 using namespace ::com::sun::star::lang
;
63 using namespace ::com::sun::star::container
;
64 using namespace ::com::sun::star::beans
;
65 using namespace ::com::sun::star::util
;
66 using namespace toolkit
;
68 constexpr OUString PROPERTY_RESOURCERESOLVER
= u
"ResourceResolver"_ustr
;
73 const Sequence
< OUString
>& lcl_getLanguageDependentProperties()
75 // note: properties must be sorted
76 static Sequence
<OUString
> s_aLanguageDependentProperties
{ u
"HelpText"_ustr
, u
"Title"_ustr
};
77 return s_aLanguageDependentProperties
;
80 // functor for disposing a control model
81 struct DisposeControlModel
83 void operator()( Reference
< XControlModel
>& _rxModel
)
87 ::comphelper::disposeComponent( _rxModel
);
89 catch (const Exception
&)
91 TOOLS_WARN_EXCEPTION("toolkit", "caught an exception while disposing a component" );
99 // functor for cloning a control model, and insertion into a target list
100 struct CloneControlModel
103 ControlModelContainerBase::UnoControlModelHolderVector
& m_rTargetVector
;
106 explicit CloneControlModel( ControlModelContainerBase::UnoControlModelHolderVector
& _rTargetVector
)
107 :m_rTargetVector( _rTargetVector
)
111 void operator()( const ControlModelContainerBase::UnoControlModelHolder
& _rSource
)
113 // clone the source object
114 Reference
< XCloneable
> xCloneSource( _rSource
.first
, UNO_QUERY
);
115 Reference
< XControlModel
> xClone( xCloneSource
->createClone(), UNO_QUERY
);
116 // add to target list
117 m_rTargetVector
.emplace_back( xClone
, _rSource
.second
);
122 // functor for comparing a XControlModel with a given reference
123 struct CompareControlModel
126 Reference
< XControlModel
> m_xReference
;
128 explicit CompareControlModel( const Reference
< XControlModel
>& _rxReference
) : m_xReference( _rxReference
) { }
130 bool operator()( const ControlModelContainerBase::UnoControlModelHolder
& _rCompare
)
132 return _rCompare
.first
.get() == m_xReference
.get();
136 constexpr OUString
aTabIndexPropertyNameStr( u
"TabIndex"_ustr
);
138 ControlModelContainerBase::ControlModelContainerBase( const Reference
< XComponentContext
>& rxContext
)
139 :ControlModelContainer_IBase( rxContext
)
140 ,maContainerListeners( *this )
141 ,mbGroupsUpToDate( false )
144 ImplRegisterProperty(BASEPROPERTY_ENABLED
);
147 ControlModelContainerBase::ControlModelContainerBase( const ControlModelContainerBase
& rModel
)
148 : ControlModelContainer_IBase( rModel
)
149 , maContainerListeners( *this )
150 , mbGroupsUpToDate( false )
151 , m_nTabPageId( rModel
.m_nTabPageId
)
155 ControlModelContainerBase::~ControlModelContainerBase()
158 mbGroupsUpToDate
= false;
161 Any
ControlModelContainerBase::ImplGetDefaultValue( sal_uInt16 nPropId
) const
167 case BASEPROPERTY_DEFAULTCONTROL
:
168 aAny
<<= sServiceName_UnoControlDialog
;
171 aAny
= UnoControlModel::ImplGetDefaultValue( nPropId
);
177 ::cppu::IPropertyArrayHelper
& ControlModelContainerBase::getInfoHelper()
179 static UnoPropertyArrayHelper
aHelper( ImplGetPropertyIds() );
183 void SAL_CALL
ControlModelContainerBase::dispose( )
186 // tell our listeners
188 std::unique_lock
aGuard( m_aMutex
);
190 EventObject aDisposeEvent
;
191 aDisposeEvent
.Source
= static_cast< XAggregation
* >( static_cast< ::cppu::OWeakAggObject
* >( this ) );
193 maContainerListeners
.disposeAndClear( aGuard
, aDisposeEvent
);
194 maChangeListeners
.disposeAndClear( aGuard
, aDisposeEvent
);
198 // call the base class
199 UnoControlModel::dispose();
202 // dispose our child models
203 // for this, collect the models (we collect them from maModels, and this is modified when disposing children)
204 ::std::vector
< Reference
< XControlModel
> > aChildModels( maModels
.size() );
207 maModels
.begin(), maModels
.end(), // source range
208 aChildModels
.begin(), // target location
209 []( const UnoControlModelHolder
& rUnoControlModelHolder
)
210 { return rUnoControlModelHolder
.first
; } // operation to apply -> select the XControlModel part
214 ::std::for_each( aChildModels
.begin(), aChildModels
.end(), DisposeControlModel() );
215 aChildModels
.clear();
217 mbGroupsUpToDate
= false;
221 Reference
< XPropertySetInfo
> ControlModelContainerBase::getPropertySetInfo( )
223 static Reference
< XPropertySetInfo
> xInfo( createPropertySetInfo( getInfoHelper() ) );
226 void ControlModelContainerBase::Clone_Impl(ControlModelContainerBase
& _rClone
) const
228 // clone all children
230 maModels
.begin(), maModels
.end(),
231 CloneControlModel( _rClone
.maModels
)
234 rtl::Reference
<UnoControlModel
> ControlModelContainerBase::Clone() const
236 // clone the container itself
237 rtl::Reference
<ControlModelContainerBase
> pClone
= new ControlModelContainerBase( *this );
243 ControlModelContainerBase::UnoControlModelHolderVector::iterator
ControlModelContainerBase::ImplFindElement( std::u16string_view rName
)
245 return ::std::find_if( maModels
.begin(), maModels
.end(), [&](const UnoControlModelHolder
& elem
) { return elem
.second
== rName
; });
248 // ::XMultiServiceFactory
249 Reference
< XInterface
> ControlModelContainerBase::createInstance( const OUString
& aServiceSpecifier
)
251 SolarMutexGuard aGuard
;
253 rtl::Reference
<OGeometryControlModel_Base
> pNewModel
;
255 if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlEditModel" )
256 pNewModel
= new OGeometryControlModel
< UnoControlEditModel
>( m_xContext
);
257 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlFormattedFieldModel" )
258 pNewModel
= new OGeometryControlModel
< UnoControlFormattedFieldModel
>( m_xContext
);
259 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlFileControlModel" )
260 pNewModel
= new OGeometryControlModel
< UnoControlFileControlModel
>( m_xContext
);
261 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlButtonModel" )
262 pNewModel
= new OGeometryControlModel
< UnoControlButtonModel
>( m_xContext
);
263 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlImageControlModel" )
264 pNewModel
= new OGeometryControlModel
< UnoControlImageControlModel
>( m_xContext
);
265 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlRadioButtonModel" )
266 pNewModel
= new OGeometryControlModel
< UnoControlRadioButtonModel
>( m_xContext
);
267 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlCheckBoxModel" )
268 pNewModel
= new OGeometryControlModel
< UnoControlCheckBoxModel
>( m_xContext
);
269 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlFixedHyperlinkModel" )
270 pNewModel
= new OGeometryControlModel
< UnoControlFixedHyperlinkModel
>( m_xContext
);
271 else if ( aServiceSpecifier
== "stardiv.vcl.controlmodel.FixedText" )
272 pNewModel
= new OGeometryControlModel
< UnoControlFixedTextModel
>( m_xContext
);
273 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlGroupBoxModel" )
274 pNewModel
= new OGeometryControlModel
< UnoControlGroupBoxModel
>( m_xContext
);
275 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlListBoxModel" )
276 pNewModel
= new OGeometryControlModel
< UnoControlListBoxModel
>( m_xContext
);
277 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlComboBoxModel" )
278 pNewModel
= new OGeometryControlModel
< UnoControlComboBoxModel
>( m_xContext
);
279 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlDateFieldModel" )
280 pNewModel
= new OGeometryControlModel
< UnoControlDateFieldModel
>( m_xContext
);
281 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlTimeFieldModel" )
282 pNewModel
= new OGeometryControlModel
< UnoControlTimeFieldModel
>( m_xContext
);
283 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlNumericFieldModel" )
284 pNewModel
= new OGeometryControlModel
< UnoControlNumericFieldModel
>( m_xContext
);
285 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlCurrencyFieldModel" )
286 pNewModel
= new OGeometryControlModel
< UnoControlCurrencyFieldModel
>( m_xContext
);
287 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlPatternFieldModel" )
288 pNewModel
= new OGeometryControlModel
< UnoControlPatternFieldModel
>( m_xContext
);
289 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlProgressBarModel" )
290 pNewModel
= new OGeometryControlModel
< UnoControlProgressBarModel
>( m_xContext
);
291 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlScrollBarModel" )
292 pNewModel
= new OGeometryControlModel
< UnoControlScrollBarModel
>( m_xContext
);
293 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlFixedLineModel" )
294 pNewModel
= new OGeometryControlModel
< UnoControlFixedLineModel
>( m_xContext
);
295 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlRoadmapModel" )
296 pNewModel
= new OGeometryControlModel
< UnoControlRoadmapModel
>( m_xContext
);
297 else if ( aServiceSpecifier
== "com.sun.star.awt.tree.TreeControlModel" )
298 pNewModel
= new OGeometryControlModel
< UnoTreeModel
>( m_xContext
);
299 else if ( aServiceSpecifier
== "com.sun.star.awt.grid.UnoControlGridModel" )
300 pNewModel
= new OGeometryControlModel
< UnoGridModel
>( m_xContext
);
301 else if ( aServiceSpecifier
== "com.sun.star.awt.tab.UnoControlTabPageContainerModel" )
302 pNewModel
= new OGeometryControlModel
< UnoControlTabPageContainerModel
>( m_xContext
);
303 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoMultiPageModel" )
304 pNewModel
= new OGeometryControlModel
< UnoMultiPageModel
>( m_xContext
);
305 else if ( aServiceSpecifier
== "com.sun.star.awt.tab.UnoControlTabPageModel" )
306 pNewModel
= new OGeometryControlModel
< UnoControlTabPageModel
>( m_xContext
);
307 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoPageModel" )
308 pNewModel
= new OGeometryControlModel
< UnoPageModel
>( m_xContext
);
309 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoFrameModel" )
310 pNewModel
= new OGeometryControlModel
< UnoFrameModel
>( m_xContext
);
314 Reference
< XInterface
> xObject
= m_xContext
->getServiceManager()->createInstanceWithContext(aServiceSpecifier
, m_xContext
);
315 Reference
< XServiceInfo
> xSI( xObject
, UNO_QUERY
);
316 Reference
< XCloneable
> xCloneAccess( xSI
, UNO_QUERY
);
317 Reference
< XAggregation
> xAgg( xCloneAccess
, UNO_QUERY
);
320 if ( xSI
->supportsService(u
"com.sun.star.awt.UnoControlModel"_ustr
) )
322 // release 3 of the 4 references we have to the object
327 pNewModel
= new OCommonGeometryControlModel( xCloneAccess
, aServiceSpecifier
);
332 return cppu::getXWeak(pNewModel
.get());
335 Reference
< XInterface
> ControlModelContainerBase::createInstanceWithArguments( const OUString
& ServiceSpecifier
, const Sequence
< Any
>& i_arguments
)
337 const Reference
< XInterface
> xInstance( createInstance( ServiceSpecifier
) );
338 const Reference
< XInitialization
> xInstanceInit( xInstance
, UNO_QUERY
);
339 ENSURE_OR_RETURN( xInstanceInit
.is(), "ControlModelContainerBase::createInstanceWithArguments: can't pass the arguments!", xInstance
);
340 xInstanceInit
->initialize( i_arguments
);
344 Sequence
< OUString
> ControlModelContainerBase::getAvailableServiceNames()
346 return { u
"com.sun.star.awt.UnoControlEditModel"_ustr
,
347 u
"com.sun.star.awt.UnoControlFormattedFieldModel"_ustr
,
348 u
"com.sun.star.awt.UnoControlFileControlModel"_ustr
,
349 u
"com.sun.star.awt.UnoControlButtonModel"_ustr
,
350 u
"com.sun.star.awt.UnoControlImageControlModel"_ustr
,
351 u
"com.sun.star.awt.UnoControlRadioButtonModel"_ustr
,
352 u
"com.sun.star.awt.UnoControlCheckBoxModel"_ustr
,
353 u
"com.sun.star.awt.UnoControlFixedTextModel"_ustr
,
354 u
"com.sun.star.awt.UnoControlGroupBoxModel"_ustr
,
355 u
"com.sun.star.awt.UnoControlListBoxModel"_ustr
,
356 u
"com.sun.star.awt.UnoControlComboBoxModel"_ustr
,
357 u
"com.sun.star.awt.UnoControlDateFieldModel"_ustr
,
358 u
"com.sun.star.awt.UnoControlTimeFieldModel"_ustr
,
359 u
"com.sun.star.awt.UnoControlNumericFieldModel"_ustr
,
360 u
"com.sun.star.awt.UnoControlCurrencyFieldModel"_ustr
,
361 u
"com.sun.star.awt.UnoControlPatternFieldModel"_ustr
,
362 u
"com.sun.star.awt.UnoControlProgressBarModel"_ustr
,
363 u
"com.sun.star.awt.UnoControlScrollBarModel"_ustr
,
364 u
"com.sun.star.awt.UnoControlFixedLineModel"_ustr
,
365 u
"com.sun.star.awt.UnoControlRoadmapModel"_ustr
,
366 u
"com.sun.star.awt.tree.TreeControlModel"_ustr
,
367 u
"com.sun.star.awt.grid.UnoControlGridModel"_ustr
,
368 u
"com.sun.star.awt.UnoControlFixedHyperlinkModel"_ustr
,
369 u
"com.sun.star.awt.tab.UnoControlTabPageContainerModel"_ustr
,
370 u
"com.sun.star.awt.tab.UnoControlTabPageModel"_ustr
,
371 u
"com.sun.star.awt.UnoMultiPageModel"_ustr
,
372 u
"com.sun.star.awt.UnoFrameModel"_ustr
377 void ControlModelContainerBase::addContainerListener( const Reference
< XContainerListener
>& l
)
379 maContainerListeners
.addInterface( l
);
382 void ControlModelContainerBase::removeContainerListener( const Reference
< XContainerListener
>& l
)
384 maContainerListeners
.removeInterface( l
);
388 Type
ControlModelContainerBase::getElementType()
390 Type aType
= cppu::UnoType
<XControlModel
>::get();
394 sal_Bool
ControlModelContainerBase::hasElements()
396 return !maModels
.empty();
399 // XNameContainer, XNameReplace, XNameAccess
400 void ControlModelContainerBase::replaceByName( const OUString
& aName
, const Any
& aElement
)
402 SolarMutexGuard aGuard
;
404 Reference
< XControlModel
> xNewModel
;
405 aElement
>>= xNewModel
;
406 if ( !xNewModel
.is() )
407 throw IllegalArgumentException();
409 UnoControlModelHolderVector::iterator aElementPos
= ImplFindElement( aName
);
410 if ( maModels
.end() == aElementPos
)
411 throw NoSuchElementException();
412 // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
413 // With container controls you could have constructed an existing hierarchy and are now
414 // add this to an existing container, in this case a name nested in the containment
415 // hierarchy of the added control could contain a name clash, if we have access to the
416 // list of global names then recursively check for previously existing names (we need
417 // to do this obviously before the 'this' objects container is updated)
418 Reference
< XNameContainer
> xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES
) ), UNO_QUERY
);
419 if ( xAllChildren
.is() )
421 // remove old control (and children) from global list of containers
422 updateUserFormChildren( xAllChildren
, aName
, Remove
, uno::Reference
< XControlModel
>() );
423 // Add new control (and containers if they exist)
424 updateUserFormChildren( xAllChildren
, aName
, Insert
, xNewModel
);
426 // stop listening at the old model
427 stopControlListening( aElementPos
->first
);
428 Reference
< XControlModel
> xReplaced( aElementPos
->first
);
429 // remember the new model, and start listening
430 aElementPos
->first
= xNewModel
;
431 startControlListening( xNewModel
);
433 ContainerEvent aEvent
;
434 aEvent
.Source
= *this;
435 aEvent
.Element
= aElement
;
436 aEvent
.ReplacedElement
<<= xReplaced
;
437 aEvent
.Accessor
<<= aName
;
439 // notify the container listener
440 maContainerListeners
.elementReplaced( aEvent
);
442 // our "tab controller model" has potentially changed -> notify this
443 implNotifyTabModelChange( aName
);
446 Any
ControlModelContainerBase::getByName( const OUString
& aName
)
448 UnoControlModelHolderVector::iterator aElementPos
= ImplFindElement( aName
);
449 if ( maModels
.end() == aElementPos
)
450 throw NoSuchElementException();
452 return Any( aElementPos
->first
);
455 Sequence
< OUString
> ControlModelContainerBase::getElementNames()
457 Sequence
< OUString
> aNames( maModels
.size() );
460 maModels
.begin(), maModels
.end(), // source range
461 aNames
.getArray(), // target range
462 []( const UnoControlModelHolder
& rUnoControlModelHolder
)
463 { return rUnoControlModelHolder
.second
; } // operator to apply: select the second element (the name)
469 sal_Bool
ControlModelContainerBase::hasByName( const OUString
& aName
)
471 return maModels
.end() != ImplFindElement( aName
);
474 void ControlModelContainerBase::insertByName( const OUString
& aName
, const Any
& aElement
)
476 SolarMutexGuard aGuard
;
478 Reference
< XControlModel
> xM
;
483 Reference
< beans::XPropertySet
> xProps( xM
, UNO_QUERY
);
487 Reference
< beans::XPropertySetInfo
> xPropInfo
= xProps
->getPropertySetInfo();
489 const OUString
& sImageSourceProperty
= GetPropertyName( BASEPROPERTY_IMAGEURL
);
490 if ( xPropInfo
->hasPropertyByName( sImageSourceProperty
) && ImplHasProperty(BASEPROPERTY_DIALOGSOURCEURL
) )
492 Any aUrl
= xProps
->getPropertyValue( sImageSourceProperty
);
494 OUString absoluteUrl
=
495 getPhysicalLocation( getPropertyValue( GetPropertyName( BASEPROPERTY_DIALOGSOURCEURL
) ), aUrl
);
497 aUrl
<<= absoluteUrl
;
499 xProps
->setPropertyValue( sImageSourceProperty
, aUrl
);
505 if ( aName
.isEmpty() || !xM
.is() )
506 throw IllegalArgumentException();
508 UnoControlModelHolderVector::iterator aElementPos
= ImplFindElement( aName
);
509 if ( maModels
.end() != aElementPos
)
510 throw ElementExistException();
512 // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
513 // With container controls you could have constructed an existing hierarchy and are now
514 // add this to an existing container, in this case a name nested in the containment
515 // hierarchy of the added control could contain a name clash, if we have access to the
516 // list of global names then we need to recursively check for previously existing
517 // names (we need to do this obviously before the 'this' objects container is updated)
518 // remove old control (and children) from global list of containers
519 Reference
< XNameContainer
> xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES
) ), UNO_QUERY
);
521 if ( xAllChildren
.is() )
522 updateUserFormChildren( xAllChildren
, aName
, Insert
, xM
);
523 maModels
.emplace_back( xM
, aName
);
524 mbGroupsUpToDate
= false;
525 startControlListening( xM
);
527 ContainerEvent aEvent
;
528 aEvent
.Source
= *this;
529 aEvent
.Element
= aElement
;
530 aEvent
.Accessor
<<= aName
;
531 maContainerListeners
.elementInserted( aEvent
);
533 // our "tab controller model" has potentially changed -> notify this
534 implNotifyTabModelChange( aName
);
537 void ControlModelContainerBase::removeByName( const OUString
& aName
)
539 SolarMutexGuard aGuard
;
541 UnoControlModelHolderVector::iterator aElementPos
= ImplFindElement( aName
);
542 if ( maModels
.end() == aElementPos
)
543 throw NoSuchElementException();
545 // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
546 // With container controls you could have constructed an existing hierarchy and are now
547 // removing this control from an existing container, in this case all nested names in
548 // the containment hierarchy of the control to be removed need to be removed from the global
549 // names cache (we need to do this obviously before the 'this' objects container is updated)
550 Reference
< XNameContainer
> xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES
) ), UNO_QUERY
);
551 if ( xAllChildren
.is() )
552 updateUserFormChildren( xAllChildren
, aName
, Remove
, uno::Reference
< XControlModel
>() );
554 ContainerEvent aEvent
;
555 aEvent
.Source
= *this;
556 aEvent
.Element
<<= aElementPos
->first
;
557 aEvent
.Accessor
<<= aName
;
558 maContainerListeners
.elementRemoved( aEvent
);
560 stopControlListening( aElementPos
->first
);
561 Reference
< XPropertySet
> xPS( aElementPos
->first
, UNO_QUERY
);
562 maModels
.erase( aElementPos
);
563 mbGroupsUpToDate
= false;
569 xPS
->setPropertyValue( PROPERTY_RESOURCERESOLVER
, Any( Reference
< resource::XStringResourceResolver
>() ) );
571 catch (const Exception
&)
573 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
577 // our "tab controller model" has potentially changed -> notify this
578 implNotifyTabModelChange( aName
);
582 sal_Bool SAL_CALL
ControlModelContainerBase::getGroupControl( )
588 void SAL_CALL
ControlModelContainerBase::setGroupControl( sal_Bool
)
590 SAL_WARN("toolkit", "explicit grouping not supported" );
594 void SAL_CALL
ControlModelContainerBase::setControlModels( const Sequence
< Reference
< XControlModel
> >& _rControls
)
596 SolarMutexGuard aGuard
;
598 // set the tab indexes according to the order of models in the sequence
600 sal_Int16 nTabIndex
= 1;
602 for ( auto const & control
: _rControls
)
604 // look up the control in our own structure. This is to prevent invalid arguments
605 UnoControlModelHolderVector::const_iterator aPos
=
607 maModels
.begin(), maModels
.end(),
608 CompareControlModel( control
)
610 if ( maModels
.end() != aPos
)
612 // okay, this is an existent model
613 // now set the TabIndex property (if applicable)
614 Reference
< XPropertySet
> xProps( aPos
->first
, UNO_QUERY
);
615 Reference
< XPropertySetInfo
> xPSI
;
617 xPSI
= xProps
->getPropertySetInfo();
618 if ( xPSI
.is() && xPSI
->hasPropertyByName( aTabIndexPropertyNameStr
) )
619 xProps
->setPropertyValue( aTabIndexPropertyNameStr
, Any( nTabIndex
++ ) );
621 mbGroupsUpToDate
= false;
626 typedef ::std::multimap
< sal_Int32
, Reference
< XControlModel
> > MapIndexToModel
;
629 Sequence
< Reference
< XControlModel
> > SAL_CALL
ControlModelContainerBase::getControlModels( )
631 SolarMutexGuard aGuard
;
633 MapIndexToModel aSortedModels
;
634 // will be the sorted container of all models which have a tab index property
635 ::std::vector
< Reference
< XControlModel
> > aUnindexedModels
;
636 // will be the container of all models which do not have a tab index property
638 for ( const auto& rModel
: maModels
)
640 Reference
< XControlModel
> xModel( rModel
.first
);
642 // see if the model has a TabIndex property
643 Reference
< XPropertySet
> xControlProps( xModel
, UNO_QUERY
);
644 Reference
< XPropertySetInfo
> xPSI
;
645 if ( xControlProps
.is() )
646 xPSI
= xControlProps
->getPropertySetInfo( );
647 DBG_ASSERT( xPSI
.is(), "ControlModelContainerBase::getControlModels: invalid child model!" );
650 if ( xPSI
.is() && xPSI
->hasPropertyByName( aTabIndexPropertyNameStr
) )
652 sal_Int32 nTabIndex
= -1;
653 xControlProps
->getPropertyValue( aTabIndexPropertyNameStr
) >>= nTabIndex
;
655 aSortedModels
.emplace( nTabIndex
, xModel
);
657 else if ( xModel
.is() )
658 // no, it hasn't, but we have to include it, anyway
659 aUnindexedModels
.push_back( xModel
);
662 // okay, here we have a container of all our models, sorted by tab index,
663 // plus a container of "unindexed" models
665 Sequence
< Reference
< XControlModel
> > aReturn( aUnindexedModels
.size() + aSortedModels
.size() );
667 aSortedModels
.begin(), aSortedModels
.end(),
668 ::std::copy( aUnindexedModels
.begin(), aUnindexedModels
.end(), aReturn
.getArray() ),
669 [] ( const MapIndexToModel::value_type
& entryIndexToModel
)
670 { return entryIndexToModel
.second
; }
677 void SAL_CALL
ControlModelContainerBase::setGroup( const Sequence
< Reference
< XControlModel
> >&, const OUString
& )
679 // not supported. We have only implicit grouping:
680 // We only have a sequence of control models, and we _know_ (yes, that's a HACK relying on
681 // implementation details) that VCL does grouping according to the order of controls automatically
682 // At least VCL does this for all we're interested in: Radio buttons.
683 SAL_WARN("toolkit", "grouping not supported" );
686 ////----- XInitialization -------------------------------------------------------------------
687 void SAL_CALL
ControlModelContainerBase::initialize (const Sequence
<Any
>& rArguments
)
689 if ( rArguments
.getLength() == 1 )
691 sal_Int16 nPageId
= -1;
692 if ( !( rArguments
[ 0 ] >>= nPageId
))
693 throw lang::IllegalArgumentException();
694 m_nTabPageId
= nPageId
;
699 ::sal_Int16 SAL_CALL
ControlModelContainerBase::getTabPageID()
703 sal_Bool SAL_CALL
ControlModelContainerBase::getEnabled()
705 SolarMutexGuard aGuard
;
706 bool bEnabled
= false;
707 getPropertyValue(GetPropertyName(BASEPROPERTY_ENABLED
)) >>= bEnabled
;
710 void SAL_CALL
ControlModelContainerBase::setEnabled( sal_Bool _enabled
)
712 SolarMutexGuard aGuard
;
713 setPropertyValue(GetPropertyName(BASEPROPERTY_ENABLED
), Any(_enabled
));
715 OUString SAL_CALL
ControlModelContainerBase::getTitle()
717 SolarMutexGuard aGuard
;
719 getPropertyValue(GetPropertyName(BASEPROPERTY_TITLE
)) >>= sTitle
;
722 void SAL_CALL
ControlModelContainerBase::setTitle( const OUString
& _title
)
724 SolarMutexGuard aGuard
;
725 setPropertyValue(GetPropertyName(BASEPROPERTY_TITLE
),Any(_title
));
727 OUString SAL_CALL
ControlModelContainerBase::getImageURL()
731 void SAL_CALL
ControlModelContainerBase::setImageURL( const OUString
& _imageurl
)
733 m_sImageURL
= _imageurl
;
734 SolarMutexGuard aGuard
;
735 setPropertyValue(GetPropertyName(BASEPROPERTY_IMAGEURL
), Any(_imageurl
));
737 OUString SAL_CALL
ControlModelContainerBase::getToolTip()
741 void SAL_CALL
ControlModelContainerBase::setToolTip( const OUString
& _tooltip
)
743 m_sTooltip
= _tooltip
;
749 enum GroupingMachineState
756 sal_Int32
lcl_getDialogStep( const Reference
< XControlModel
>& _rxModel
)
761 Reference
< XPropertySet
> xModelProps( _rxModel
, UNO_QUERY
);
762 xModelProps
->getPropertyValue( u
"Step"_ustr
) >>= nStep
;
764 catch (const Exception
&)
766 TOOLS_WARN_EXCEPTION("toolkit", "caught an exception while determining the dialog page" );
773 sal_Int32 SAL_CALL
ControlModelContainerBase::getGroupCount( )
775 SolarMutexGuard aGuard
;
777 implUpdateGroupStructure();
779 return maGroups
.size();
783 void SAL_CALL
ControlModelContainerBase::getGroup( sal_Int32 _nGroup
, Sequence
< Reference
< XControlModel
> >& _rGroup
, OUString
& _rName
)
785 SolarMutexGuard aGuard
;
787 implUpdateGroupStructure();
789 if ( ( _nGroup
< 0 ) || ( o3tl::make_unsigned(_nGroup
) >= maGroups
.size() ) )
791 SAL_WARN("toolkit", "invalid argument and I am not allowed to throw exception!" );
792 _rGroup
.realloc( 0 );
797 AllGroups::const_iterator aGroupPos
= maGroups
.begin() + _nGroup
;
798 _rGroup
.realloc( aGroupPos
->size() );
800 ::std::copy( aGroupPos
->begin(), aGroupPos
->end(), _rGroup
.getArray() );
801 // give the group a name
802 _rName
= OUString::number( _nGroup
);
807 void SAL_CALL
ControlModelContainerBase::getGroupByName( const OUString
& _rName
, Sequence
< Reference
< XControlModel
> >& _rGroup
)
809 SolarMutexGuard aGuard
;
812 getGroup( _rName
.toInt32( ), _rGroup
, sDummyName
);
816 void SAL_CALL
ControlModelContainerBase::addChangesListener( const Reference
< XChangesListener
>& _rxListener
)
818 std::unique_lock
g(m_aMutex
);
819 maChangeListeners
.addInterface( g
, _rxListener
);
823 void SAL_CALL
ControlModelContainerBase::removeChangesListener( const Reference
< XChangesListener
>& _rxListener
)
825 std::unique_lock
g(m_aMutex
);
826 maChangeListeners
.removeInterface( g
, _rxListener
);
830 void ControlModelContainerBase::implNotifyTabModelChange( const OUString
& _rAccessor
)
832 // multiplex to our change listeners:
835 aEvent
.Source
= *this;
836 aEvent
.Base
<<= aEvent
.Source
; // the "base of the changes root" is also ourself
837 aEvent
.Changes
.realloc( 1 ); // exactly one change
838 aEvent
.Changes
.getArray()[ 0 ].Accessor
<<= _rAccessor
;
841 std::unique_lock
g(m_aMutex
);
842 std::vector
< Reference
< css::util::XChangesListener
> > aChangeListeners( maChangeListeners
.getElements(g
) );
844 for ( const auto& rListener
: aChangeListeners
)
845 rListener
->changesOccurred( aEvent
);
849 void ControlModelContainerBase::implUpdateGroupStructure()
851 if ( mbGroupsUpToDate
)
855 // conditions for a group:
856 // * all elements of the group are radio buttons
857 // * all elements of the group are on the same dialog page
858 // * in the overall control order (determined by the tab index), all elements are subsequent
862 const Sequence
< Reference
< XControlModel
> > aControlModels
= getControlModels();
864 // in extreme we have as much groups as controls
865 maGroups
.reserve( aControlModels
.getLength() );
867 GroupingMachineState eState
= eLookingForGroup
; // the current state of our machine
868 Reference
< XServiceInfo
> xModelSI
; // for checking for a radio button
869 AllGroups::iterator aCurrentGroup
= maGroups
.end(); // the group which we're currently building
870 sal_Int32 nCurrentGroupStep
= -1; // the step which all controls of the current group belong to
873 for ( const Reference
< XControlModel
>& rControlModel
: aControlModels
)
875 // we'll need this in every state
876 xModelSI
.set(rControlModel
, css::uno::UNO_QUERY
);
877 // is it a radio button?
878 bool bIsRadioButton
= xModelSI
.is() && xModelSI
->supportsService( u
"com.sun.star.awt.UnoControlRadioButtonModel"_ustr
);
882 case eLookingForGroup
:
884 if ( !bIsRadioButton
)
885 // this is no radio button -> still looking for the beginning of a group
887 // the current model is a radio button
888 // -> we found the beginning of a new group
889 // create the place for this group
890 size_t nGroups
= maGroups
.size();
891 maGroups
.resize( nGroups
+ 1 );
892 aCurrentGroup
= maGroups
.begin() + nGroups
;
893 // and add the (only, til now) member
894 aCurrentGroup
->push_back( rControlModel
);
896 // get the step which all controls of this group now have to belong to
897 nCurrentGroupStep
= lcl_getDialogStep( rControlModel
);
898 // new state: looking for further members
899 eState
= eExpandingGroup
;
904 case eExpandingGroup
:
906 if ( !bIsRadioButton
)
907 { // no radio button -> the group is done
908 aCurrentGroup
= maGroups
.end();
909 eState
= eLookingForGroup
;
913 // it is a radio button - is it on the proper page?
914 const sal_Int32 nThisModelStep
= lcl_getDialogStep( rControlModel
);
915 if ( ( nThisModelStep
== nCurrentGroupStep
) // the current button is on the same dialog page
916 || ( 0 == nThisModelStep
) // the current button appears on all pages
919 // -> it belongs to the same group
920 aCurrentGroup
->push_back( rControlModel
);
921 // state still is eExpandingGroup - we're looking for further elements
922 eState
= eExpandingGroup
;
927 // it's a radio button, but on a different page
928 // -> we open a new group for it
932 size_t nGroups
= maGroups
.size();
933 maGroups
.resize( nGroups
+ 1 );
934 aCurrentGroup
= maGroups
.begin() + nGroups
;
935 // and add the (only, til now) member
936 aCurrentGroup
->push_back( rControlModel
);
938 nCurrentGroupStep
= nThisModelStep
;
940 // state is the same: we still are looking for further elements of the current group
941 eState
= eExpandingGroup
;
947 mbGroupsUpToDate
= true;
951 void SAL_CALL
ControlModelContainerBase::propertyChange( const PropertyChangeEvent
& _rEvent
)
953 SolarMutexGuard aGuard
;
955 DBG_ASSERT( _rEvent
.PropertyName
== "TabIndex",
956 "ControlModelContainerBase::propertyChange: not listening for this property!" );
958 // the accessor for the changed element
960 UnoControlModelHolderVector::const_iterator aPos
=
962 maModels
.begin(), maModels
.end(),
963 CompareControlModel( Reference
< XControlModel
>( _rEvent
.Source
, UNO_QUERY
) )
965 OSL_ENSURE( maModels
.end() != aPos
, "ControlModelContainerBase::propertyChange: don't know this model!" );
966 if ( maModels
.end() != aPos
)
967 sAccessor
= aPos
->second
;
969 // our groups are not up-to-date
970 mbGroupsUpToDate
= false;
973 implNotifyTabModelChange( sAccessor
);
977 void SAL_CALL
ControlModelContainerBase::disposing( const EventObject
& /*rEvent*/ )
982 void ControlModelContainerBase::startControlListening( const Reference
< XControlModel
>& _rxChildModel
)
984 SolarMutexGuard aGuard
;
986 Reference
< XPropertySet
> xModelProps( _rxChildModel
, UNO_QUERY
);
987 Reference
< XPropertySetInfo
> xPSI
;
988 if ( xModelProps
.is() )
989 xPSI
= xModelProps
->getPropertySetInfo();
991 if ( xPSI
.is() && xPSI
->hasPropertyByName( aTabIndexPropertyNameStr
) )
992 xModelProps
->addPropertyChangeListener( aTabIndexPropertyNameStr
, this );
996 void ControlModelContainerBase::stopControlListening( const Reference
< XControlModel
>& _rxChildModel
)
998 SolarMutexGuard aGuard
;
1000 Reference
< XPropertySet
> xModelProps( _rxChildModel
, UNO_QUERY
);
1001 Reference
< XPropertySetInfo
> xPSI
;
1002 if ( xModelProps
.is() )
1003 xPSI
= xModelProps
->getPropertySetInfo();
1005 if ( xPSI
.is() && xPSI
->hasPropertyByName( aTabIndexPropertyNameStr
) )
1006 xModelProps
->removePropertyChangeListener( aTabIndexPropertyNameStr
, this );
1010 // = class ResourceListener
1013 ResourceListener::ResourceListener(
1014 const Reference
< util::XModifyListener
>& rListener
) :
1015 m_xListener( rListener
),
1016 m_bListening( false )
1020 ResourceListener::~ResourceListener()
1025 Any SAL_CALL
ResourceListener::queryInterface( const Type
& rType
)
1027 Any a
= ::cppu::queryInterface(
1029 static_cast< XModifyListener
* >( this ),
1030 static_cast< XEventListener
* >( this ));
1035 return OWeakObject::queryInterface( rType
);
1038 void SAL_CALL
ResourceListener::acquire() noexcept
1040 OWeakObject::acquire();
1043 void SAL_CALL
ResourceListener::release() noexcept
1045 OWeakObject::release();
1048 void ResourceListener::startListening(
1049 const Reference
< resource::XStringResourceResolver
>& rResource
)
1053 std::unique_lock
aGuard( m_aMutex
);
1054 bool bListening( m_bListening
);
1055 bool bResourceSet( m_xResource
.is() );
1059 if ( bListening
&& bResourceSet
)
1064 m_xResource
= rResource
;
1069 if ( !rResource
.is() )
1074 rResource
->addModifyListener( this );
1077 std::scoped_lock
aGuard( m_aMutex
);
1078 m_bListening
= true;
1081 catch (const RuntimeException
&)
1085 catch (const Exception
&)
1090 void ResourceListener::stopListening()
1092 Reference
< util::XModifyBroadcaster
> xModifyBroadcaster
;
1095 std::unique_lock
aGuard( m_aMutex
);
1096 if ( m_bListening
&& m_xResource
.is() )
1097 xModifyBroadcaster
= m_xResource
;
1101 if ( !xModifyBroadcaster
.is() )
1108 m_bListening
= false;
1109 m_xResource
.clear();
1113 xModifyBroadcaster
->removeModifyListener( this );
1115 catch (const RuntimeException
&)
1119 catch (const Exception
&)
1125 void SAL_CALL
ResourceListener::modified(
1126 const lang::EventObject
& aEvent
)
1128 Reference
< util::XModifyListener
> xListener
;
1131 std::unique_lock
aGuard( m_aMutex
);
1132 xListener
= m_xListener
;
1136 if ( !xListener
.is() )
1141 xListener
->modified( aEvent
);
1143 catch (const RuntimeException
&)
1147 catch (const Exception
&)
1153 void SAL_CALL
ResourceListener::disposing(
1154 const EventObject
& Source
)
1156 Reference
< lang::XEventListener
> xListener
;
1157 Reference
< resource::XStringResourceResolver
> xResource
;
1160 std::unique_lock
aGuard( m_aMutex
);
1161 Reference
< XInterface
> xIfacRes( m_xResource
, UNO_QUERY
);
1162 Reference
< XInterface
> xIfacList( m_xListener
, UNO_QUERY
);
1166 if ( Source
.Source
== xIfacRes
)
1170 m_bListening
= false;
1171 xResource
= m_xResource
;
1172 xListener
= m_xListener
;
1173 m_xResource
.clear();
1177 if ( xListener
.is() )
1181 xListener
->disposing( Source
);
1183 catch (const RuntimeException
&)
1187 catch (const Exception
&)
1192 else if ( Source
.Source
== xIfacList
)
1196 m_bListening
= false;
1197 xListener
= m_xListener
;
1198 xResource
= m_xResource
;
1199 m_xResource
.clear();
1200 m_xListener
.clear();
1204 // Remove ourself as listener from resource resolver
1205 if ( xResource
.is() )
1209 xResource
->removeModifyListener( this );
1211 catch (const RuntimeException
&)
1215 catch (const Exception
&)
1224 ControlContainerBase::ControlContainerBase( const Reference
< XComponentContext
>& rxContext
)
1225 :m_xContext(rxContext
)
1226 ,mbSizeModified(false)
1227 ,mbPosModified(false)
1229 maComponentInfos
.nWidth
= 280;
1230 maComponentInfos
.nHeight
= 400;
1231 mxListener
= new ResourceListener( Reference
< util::XModifyListener
>(this) );
1234 ControlContainerBase::~ControlContainerBase()
1238 void ControlContainerBase::createPeer( const Reference
< XToolkit
> & rxToolkit
, const Reference
< XWindowPeer
> & rParentPeer
)
1240 SolarMutexGuard aGuard
;
1241 UnoControlContainer::createPeer( rxToolkit
, rParentPeer
);
1244 void ControlContainerBase::ImplInsertControl( Reference
< XControlModel
> const & rxModel
, const OUString
& rName
)
1246 Reference
< XPropertySet
> xP( rxModel
, UNO_QUERY
);
1249 xP
->getPropertyValue( GetPropertyName( BASEPROPERTY_DEFAULTCONTROL
) ) >>= aDefCtrl
;
1250 Reference
< XControl
> xCtrl( m_xContext
->getServiceManager()->createInstanceWithContext(aDefCtrl
, m_xContext
), UNO_QUERY
);
1252 DBG_ASSERT( xCtrl
.is(), "ControlContainerBase::ImplInsertControl: could not create the control!" );
1255 xCtrl
->setModel( rxModel
);
1256 addControl( rName
, xCtrl
);
1257 // will implicitly call addingControl, where we can add the PropertiesChangeListener to the model
1258 // (which we formerly did herein)
1259 // 08.01.2001 - 96008 - fs@openoffice.org
1261 ImplSetPosSize( xCtrl
);
1265 void ControlContainerBase::ImplRemoveControl( Reference
< XControlModel
> const & rxModel
)
1267 Sequence
< Reference
< XControl
> > aControls
= getControls();
1268 Reference
< XControl
> xCtrl
= StdTabController::FindControl( aControls
, rxModel
);
1271 removeControl( xCtrl
);
1276 catch (const Exception
&)
1278 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1283 void ControlContainerBase::ImplSetPosSize( Reference
< XControl
>& rxCtrl
)
1285 Reference
< XPropertySet
> xP( rxCtrl
->getModel(), UNO_QUERY
);
1287 sal_Int32 nX
= 0, nY
= 0, nWidth
= 0, nHeight
= 0;
1288 xP
->getPropertyValue(u
"PositionX"_ustr
) >>= nX
;
1289 xP
->getPropertyValue(u
"PositionY"_ustr
) >>= nY
;
1290 xP
->getPropertyValue(u
"Width"_ustr
) >>= nWidth
;
1291 xP
->getPropertyValue(u
"Height"_ustr
) >>= nHeight
;
1292 MapMode
aMode( MapUnit::MapAppFont
);
1293 OutputDevice
*pOutDev
= Application::GetDefaultDevice();
1296 ::Size
aTmp( nX
, nY
);
1297 aTmp
= pOutDev
->LogicToPixel( aTmp
, aMode
);
1300 aTmp
= ::Size( nWidth
, nHeight
);
1301 aTmp
= pOutDev
->LogicToPixel( aTmp
, aMode
);
1302 nWidth
= aTmp
.Width();
1303 nHeight
= aTmp
.Height();
1307 Reference
< XWindowPeer
> xPeer
= ImplGetCompatiblePeer();
1308 Reference
< XDevice
> xD( xPeer
, UNO_QUERY
);
1310 SimpleFontMetric aFM
;
1312 Any aVal
= ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_FONTDESCRIPTOR
) );
1314 if ( !aFD
.StyleName
.isEmpty() )
1316 Reference
< XFont
> xFont
= xD
->getFont( aFD
);
1317 aFM
= xFont
->getFontMetric();
1321 Reference
< XGraphics
> xG
= xD
->createGraphics();
1322 aFM
= xG
->getFontMetric();
1325 sal_Int16 nH
= aFM
.Ascent
+ aFM
.Descent
;
1326 sal_Int16 nW
= nH
/2; // calculate average width?!
1337 Reference
< XWindow
> xW( rxCtrl
, UNO_QUERY
);
1338 xW
->setPosSize( nX
, nY
, nWidth
, nHeight
, PosSize::POSSIZE
);
1341 void ControlContainerBase::dispose()
1344 aEvt
.Source
= getXWeak();
1345 // Notify our listener helper about dispose
1348 SolarMutexClearableGuard aGuard
;
1349 Reference
< XEventListener
> xListener
= mxListener
;
1354 if ( xListener
.is() )
1355 xListener
->disposing( aEvt
);
1356 UnoControlContainer::dispose();
1359 void SAL_CALL
ControlContainerBase::disposing(
1360 const EventObject
& Source
)
1362 UnoControlContainer::disposing( Source
);
1365 sal_Bool
ControlContainerBase::setModel( const Reference
< XControlModel
>& rxModel
)
1367 SolarMutexGuard aGuard
;
1369 // destroy the old tab controller, if existent
1370 if ( mxTabController
.is() )
1372 mxTabController
->setModel( nullptr ); // just to be sure, should not be necessary
1373 removeTabController( mxTabController
);
1374 mxTabController
.clear();
1377 if ( getModel().is() )
1379 const Sequence
< Reference
< XControl
> > aControls
= getControls();
1381 for ( const Reference
< XControl
>& rCtrl
: aControls
)
1382 removeControl( rCtrl
);
1383 // will implicitly call removingControl, which will remove the PropertyChangeListener
1384 // (which we formerly did herein)
1385 // 08.01.2001 - 96008 - fs@openoffice.org
1387 Reference
< XContainer
> xC( getModel(), UNO_QUERY
);
1389 xC
->removeContainerListener( this );
1391 Reference
< XChangesNotifier
> xChangeNotifier( getModel(), UNO_QUERY
);
1392 if ( xChangeNotifier
.is() )
1393 xChangeNotifier
->removeChangesListener( this );
1396 bool bRet
= UnoControl::setModel( rxModel
);
1398 if ( getModel().is() )
1400 Reference
< XNameAccess
> xNA( getModel(), UNO_QUERY
);
1403 const Sequence
< OUString
> aNames
= xNA
->getElementNames();
1405 Reference
< XControlModel
> xCtrlModel
;
1406 for( const OUString
& rName
: aNames
)
1408 xNA
->getByName( rName
) >>= xCtrlModel
;
1409 ImplInsertControl( xCtrlModel
, rName
);
1413 Reference
< XContainer
> xC( getModel(), UNO_QUERY
);
1415 xC
->addContainerListener( this );
1417 Reference
< XChangesNotifier
> xChangeNotifier( getModel(), UNO_QUERY
);
1418 if ( xChangeNotifier
.is() )
1419 xChangeNotifier
->addChangesListener( this );
1422 Reference
< XTabControllerModel
> xTabbing( getModel(), UNO_QUERY
);
1423 if ( xTabbing
.is() )
1425 mxTabController
= new StdTabController
;
1426 mxTabController
->setModel( xTabbing
);
1427 addTabController( mxTabController
);
1429 ImplStartListingForResourceEvents();
1433 void ControlContainerBase::setDesignMode( sal_Bool bOn
)
1435 SolarMutexGuard aGuard
;
1437 UnoControl::setDesignMode( bOn
);
1439 Sequence
< Reference
< XControl
> > xCtrls
= getControls();
1440 for ( Reference
< XControl
>& rControl
: asNonConstRange(xCtrls
) )
1441 rControl
->setDesignMode( bOn
);
1443 // #109067# in design mode the tab controller is not notified about
1444 // tab index changes, therefore the tab order must be activated
1445 // when switching from design mode to live mode
1446 if ( mxTabController
.is() && !bOn
)
1447 mxTabController
->activateTabOrder();
1450 void ControlContainerBase::elementInserted( const ContainerEvent
& Event
)
1452 SolarMutexGuard aGuard
;
1454 Reference
< XControlModel
> xModel
;
1457 Event
.Accessor
>>= aName
;
1458 Event
.Element
>>= xModel
;
1459 ENSURE_OR_RETURN_VOID( xModel
.is(), "ControlContainerBase::elementInserted: illegal element!" );
1462 ImplInsertControl( xModel
, aName
);
1464 catch (const RuntimeException
&)
1468 catch (const Exception
&)
1470 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1474 void ControlContainerBase::elementRemoved( const ContainerEvent
& Event
)
1476 SolarMutexGuard aGuard
;
1478 Reference
< XControlModel
> xModel
;
1479 Event
.Element
>>= xModel
;
1480 ENSURE_OR_RETURN_VOID( xModel
.is(), "ControlContainerBase::elementRemoved: illegal element!" );
1483 ImplRemoveControl( xModel
);
1485 catch (const RuntimeException
&)
1489 catch (const Exception
&)
1491 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1495 void ControlContainerBase::elementReplaced( const ContainerEvent
& Event
)
1497 SolarMutexGuard aGuard
;
1499 Reference
< XControlModel
> xModel
;
1500 Event
.ReplacedElement
>>= xModel
;
1503 OSL_ENSURE( xModel
.is(), "ControlContainerBase::elementReplaced: invalid ReplacedElement!" );
1505 ImplRemoveControl( xModel
);
1507 catch (const RuntimeException
&)
1511 catch (const Exception
&)
1513 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1517 Event
.Accessor
>>= aName
;
1518 Event
.Element
>>= xModel
;
1519 ENSURE_OR_RETURN_VOID( xModel
.is(), "ControlContainerBase::elementReplaced: invalid new element!" );
1522 ImplInsertControl( xModel
, aName
);
1524 catch (const RuntimeException
&)
1528 catch (const Exception
&)
1530 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1534 // XPropertiesChangeListener
1535 void ControlContainerBase::ImplModelPropertiesChanged( const Sequence
< PropertyChangeEvent
>& rEvents
)
1537 if( !isDesignMode() && !mbCreatingCompatiblePeer
)
1539 auto pEvt
= std::find_if(rEvents
.begin(), rEvents
.end(),
1540 [](const PropertyChangeEvent
& rEvt
) {
1541 return rEvt
.PropertyName
== "PositionX"
1542 || rEvt
.PropertyName
== "PositionY"
1543 || rEvt
.PropertyName
== "Width"
1544 || rEvt
.PropertyName
== "Height";
1546 if (pEvt
!= rEvents
.end())
1548 Reference
< XControlModel
> xModel( pEvt
->Source
, UNO_QUERY
);
1549 bool bOwnModel
= xModel
.get() == getModel().get();
1552 if ( !mbPosModified
&& !mbSizeModified
)
1554 // Don't set new pos/size if we get new values from window listener
1555 Reference
< XControl
> xThis(this);
1556 ImplSetPosSize( xThis
);
1561 Sequence
<Reference
<XControl
> > aControlSequence(getControls());
1562 Reference
<XControl
> aControlRef( StdTabController::FindControl( aControlSequence
, xModel
) );
1563 ImplSetPosSize( aControlRef
);
1568 UnoControlContainer::ImplModelPropertiesChanged( rEvents
);
1571 void ControlContainerBase::addingControl( const Reference
< XControl
>& _rxControl
)
1573 SolarMutexGuard aGuard
;
1574 UnoControlContainer::addingControl( _rxControl
);
1576 if ( !_rxControl
.is() )
1579 Reference
< XMultiPropertySet
> xProps( _rxControl
->getModel(), UNO_QUERY
);
1582 const Sequence
< OUString
> aNames
{
1589 xProps
->addPropertiesChangeListener( aNames
, this );
1593 void ControlContainerBase::removingControl( const Reference
< XControl
>& _rxControl
)
1595 SolarMutexGuard aGuard
;
1596 UnoControlContainer::removingControl( _rxControl
);
1598 if ( _rxControl
.is() )
1600 Reference
< XMultiPropertySet
> xProps( _rxControl
->getModel(), UNO_QUERY
);
1602 xProps
->removePropertiesChangeListener( this );
1607 void SAL_CALL
ControlContainerBase::changesOccurred( const ChangesEvent
& )
1609 SolarMutexGuard aGuard
;
1610 // a tab controller model may have changed
1612 // #109067# in design mode don't notify the tab controller
1613 // about tab index changes
1614 if ( mxTabController
.is() && !mbDesignMode
)
1615 mxTabController
->activateTabOrder();
1617 static void lcl_ApplyResolverToNestedContainees( const Reference
< resource::XStringResourceResolver
>& xStringResourceResolver
, const Reference
< XControlContainer
>& xContainer
)
1619 OUString
aPropName( PROPERTY_RESOURCERESOLVER
);
1621 Any aNewStringResourceResolver
;
1622 aNewStringResourceResolver
<<= xStringResourceResolver
;
1624 Sequence
< OUString
> aPropNames
{ aPropName
};
1626 const Sequence
< Reference
< awt::XControl
> > aSeq
= xContainer
->getControls();
1627 for ( const Reference
< XControl
>& xControl
: aSeq
)
1629 Reference
< XPropertySet
> xPropertySet
;
1631 if ( xControl
.is() )
1632 xPropertySet
.set( xControl
->getModel(), UNO_QUERY
);
1634 if ( !xPropertySet
.is() )
1639 Reference
< resource::XStringResourceResolver
> xCurrStringResourceResolver
;
1640 Any aOldValue
= xPropertySet
->getPropertyValue( aPropName
);
1641 if ( ( aOldValue
>>= xCurrStringResourceResolver
)
1642 && ( xStringResourceResolver
== xCurrStringResourceResolver
)
1645 Reference
< XMultiPropertySet
> xMultiPropSet( xPropertySet
, UNO_QUERY
);
1646 Reference
< XPropertiesChangeListener
> xListener( xPropertySet
, UNO_QUERY
);
1647 xMultiPropSet
->firePropertiesChangeEvent( aPropNames
, xListener
);
1650 xPropertySet
->setPropertyValue( aPropName
, aNewStringResourceResolver
);
1652 catch (const Exception
&)
1656 uno::Reference
< XControlContainer
> xNestedContainer( xControl
, uno::UNO_QUERY
);
1657 if ( xNestedContainer
.is() )
1658 lcl_ApplyResolverToNestedContainees( xStringResourceResolver
, xNestedContainer
);
1663 void ControlContainerBase::ImplStartListingForResourceEvents()
1665 Reference
< resource::XStringResourceResolver
> xStringResourceResolver
;
1667 if ( !ImplHasProperty(PROPERTY_RESOURCERESOLVER
) )
1670 ImplGetPropertyValue( PROPERTY_RESOURCERESOLVER
) >>= xStringResourceResolver
;
1672 // Add our helper as listener to retrieve notifications about changes
1673 Reference
< util::XModifyListener
> rListener( mxListener
);
1674 ResourceListener
* pResourceListener
= static_cast< ResourceListener
* >( rListener
.get() );
1676 // resource listener will stop listening if resolver reference is empty
1677 if ( pResourceListener
)
1678 pResourceListener
->startListening( xStringResourceResolver
);
1679 ImplUpdateResourceResolver();
1682 void ControlContainerBase::ImplUpdateResourceResolver()
1684 Reference
< resource::XStringResourceResolver
> xStringResourceResolver
;
1686 if ( !ImplHasProperty(PROPERTY_RESOURCERESOLVER
) )
1689 ImplGetPropertyValue(PROPERTY_RESOURCERESOLVER
) >>= xStringResourceResolver
;
1691 if ( !xStringResourceResolver
.is() )
1694 lcl_ApplyResolverToNestedContainees( xStringResourceResolver
, this );
1696 // propagate resource resolver changes to language dependent props of the dialog
1697 Reference
< XPropertySet
> xPropertySet( getModel(), UNO_QUERY
);
1698 if ( xPropertySet
.is() )
1700 Reference
< XMultiPropertySet
> xMultiPropSet( xPropertySet
, UNO_QUERY
);
1701 Reference
< XPropertiesChangeListener
> xListener( xPropertySet
, UNO_QUERY
);
1702 xMultiPropSet
->firePropertiesChangeEvent( lcl_getLanguageDependentProperties(), xListener
);
1706 //// ----------------------------------------------------
1707 //// Helper Method to convert relative url to physical location
1708 //// ----------------------------------------------------
1710 OUString
getPhysicalLocation( const css::uno::Any
& rbase
, const css::uno::Any
& rUrl
)
1713 OUString baseLocation
;
1716 rbase
>>= baseLocation
;
1719 OUString
absoluteURL( url
);
1720 if ( !url
.isEmpty() )
1722 INetURLObject
urlObj(baseLocation
);
1723 urlObj
.removeSegment();
1724 baseLocation
= urlObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1726 const INetURLObject
protocolCheck( url
);
1727 const INetProtocol protocol
= protocolCheck
.GetProtocol();
1728 if ( protocol
== INetProtocol::NotValid
)
1730 OUString testAbsoluteURL
;
1731 if ( ::osl::FileBase::E_None
== ::osl::FileBase::getAbsoluteFileURL( baseLocation
, url
, testAbsoluteURL
) )
1732 absoluteURL
= testAbsoluteURL
;
1740 ControlModelContainerBase::updateUserFormChildren( const Reference
< XNameContainer
>& xAllChildren
, const OUString
& aName
, ChildOperation Operation
, const css::uno::Reference
< css::awt::XControlModel
>& xTarget
)
1742 if ( Operation
< Insert
|| Operation
> Remove
)
1743 throw IllegalArgumentException();
1745 if ( !xAllChildren
.is() )
1746 throw IllegalArgumentException();
1748 if ( Operation
== Remove
)
1750 Reference
< XControlModel
> xOldModel( xAllChildren
->getByName( aName
), UNO_QUERY
);
1751 xAllChildren
->removeByName( aName
);
1753 Reference
< XNameContainer
> xChildContainer( xOldModel
, UNO_QUERY
);
1754 if ( xChildContainer
.is() )
1756 Reference
< XPropertySet
> xProps( xChildContainer
, UNO_QUERY
);
1757 // container control is being removed from this container, reset the
1758 // global list of containers
1760 xProps
->setPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES
), uno::Any( uno::Reference
< XNameContainer
>() ) );
1761 const Sequence
< OUString
> aChildNames
= xChildContainer
->getElementNames();
1762 for ( const auto& rName
: aChildNames
)
1763 updateUserFormChildren( xAllChildren
, rName
, Operation
, Reference
< XControlModel
> () );
1766 else if ( Operation
== Insert
)
1768 xAllChildren
->insertByName( aName
, uno::Any( xTarget
) );
1769 Reference
< XNameContainer
> xChildContainer( xTarget
, UNO_QUERY
);
1770 if ( xChildContainer
.is() )
1772 // container control is being added from this container, reset the
1773 // global list of containers to point to the correct global list
1774 Reference
< XPropertySet
> xProps( xChildContainer
, UNO_QUERY
);
1776 xProps
->setPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES
), uno::Any( xAllChildren
) );
1777 const Sequence
< OUString
> aChildNames
= xChildContainer
->getElementNames();
1778 for ( const auto& rName
: aChildNames
)
1780 Reference
< XControlModel
> xChildTarget( xChildContainer
->getByName( rName
), UNO_QUERY
);
1781 updateUserFormChildren( xAllChildren
, rName
, Operation
, xChildTarget
);
1788 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */