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
{ "HelpText", "Title" };
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
<<= OUString::createFromAscii( szServiceName_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("com.sun.star.awt.UnoControlModel") )
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 { "com.sun.star.awt.UnoControlEditModel",
347 "com.sun.star.awt.UnoControlFormattedFieldModel",
348 "com.sun.star.awt.UnoControlFileControlModel",
349 "com.sun.star.awt.UnoControlButtonModel",
350 "com.sun.star.awt.UnoControlImageControlModel",
351 "com.sun.star.awt.UnoControlRadioButtonModel",
352 "com.sun.star.awt.UnoControlCheckBoxModel",
353 "com.sun.star.awt.UnoControlFixedTextModel",
354 "com.sun.star.awt.UnoControlGroupBoxModel",
355 "com.sun.star.awt.UnoControlListBoxModel",
356 "com.sun.star.awt.UnoControlComboBoxModel",
357 "com.sun.star.awt.UnoControlDateFieldModel",
358 "com.sun.star.awt.UnoControlTimeFieldModel",
359 "com.sun.star.awt.UnoControlNumericFieldModel",
360 "com.sun.star.awt.UnoControlCurrencyFieldModel",
361 "com.sun.star.awt.UnoControlPatternFieldModel",
362 "com.sun.star.awt.UnoControlProgressBarModel",
363 "com.sun.star.awt.UnoControlScrollBarModel",
364 "com.sun.star.awt.UnoControlFixedLineModel",
365 "com.sun.star.awt.UnoControlRoadmapModel",
366 "com.sun.star.awt.tree.TreeControlModel",
367 "com.sun.star.awt.grid.UnoControlGridModel",
368 "com.sun.star.awt.UnoControlFixedHyperlinkModel",
369 "com.sun.star.awt.tab.UnoControlTabPageContainerModel",
370 "com.sun.star.awt.tab.UnoControlTabPageModel",
371 "com.sun.star.awt.UnoMultiPageModel",
372 "com.sun.star.awt.UnoFrameModel"
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( "com.sun.star.awt.UnoControlRadioButtonModel" );
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("PositionX") >>= nX
;
1289 xP
->getPropertyValue("PositionY") >>= nY
;
1290 xP
->getPropertyValue("Width") >>= nWidth
;
1291 xP
->getPropertyValue("Height") >>= 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 ::comphelper::disposeComponent( mxTabController
); // just to be sure, should not be necessary
1375 mxTabController
.clear();
1378 if ( getModel().is() )
1380 const Sequence
< Reference
< XControl
> > aControls
= getControls();
1382 for ( const Reference
< XControl
>& rCtrl
: aControls
)
1383 removeControl( rCtrl
);
1384 // will implicitly call removingControl, which will remove the PropertyChangeListener
1385 // (which we formerly did herein)
1386 // 08.01.2001 - 96008 - fs@openoffice.org
1388 Reference
< XContainer
> xC( getModel(), UNO_QUERY
);
1390 xC
->removeContainerListener( this );
1392 Reference
< XChangesNotifier
> xChangeNotifier( getModel(), UNO_QUERY
);
1393 if ( xChangeNotifier
.is() )
1394 xChangeNotifier
->removeChangesListener( this );
1397 bool bRet
= UnoControl::setModel( rxModel
);
1399 if ( getModel().is() )
1401 Reference
< XNameAccess
> xNA( getModel(), UNO_QUERY
);
1404 const Sequence
< OUString
> aNames
= xNA
->getElementNames();
1406 Reference
< XControlModel
> xCtrlModel
;
1407 for( const OUString
& rName
: aNames
)
1409 xNA
->getByName( rName
) >>= xCtrlModel
;
1410 ImplInsertControl( xCtrlModel
, rName
);
1414 Reference
< XContainer
> xC( getModel(), UNO_QUERY
);
1416 xC
->addContainerListener( this );
1418 Reference
< XChangesNotifier
> xChangeNotifier( getModel(), UNO_QUERY
);
1419 if ( xChangeNotifier
.is() )
1420 xChangeNotifier
->addChangesListener( this );
1423 Reference
< XTabControllerModel
> xTabbing( getModel(), UNO_QUERY
);
1424 if ( xTabbing
.is() )
1426 mxTabController
= new StdTabController
;
1427 mxTabController
->setModel( xTabbing
);
1428 addTabController( mxTabController
);
1430 ImplStartListingForResourceEvents();
1434 void ControlContainerBase::setDesignMode( sal_Bool bOn
)
1436 SolarMutexGuard aGuard
;
1438 UnoControl::setDesignMode( bOn
);
1440 Sequence
< Reference
< XControl
> > xCtrls
= getControls();
1441 for ( Reference
< XControl
>& rControl
: asNonConstRange(xCtrls
) )
1442 rControl
->setDesignMode( bOn
);
1444 // #109067# in design mode the tab controller is not notified about
1445 // tab index changes, therefore the tab order must be activated
1446 // when switching from design mode to live mode
1447 if ( mxTabController
.is() && !bOn
)
1448 mxTabController
->activateTabOrder();
1451 void ControlContainerBase::elementInserted( const ContainerEvent
& Event
)
1453 SolarMutexGuard aGuard
;
1455 Reference
< XControlModel
> xModel
;
1458 Event
.Accessor
>>= aName
;
1459 Event
.Element
>>= xModel
;
1460 ENSURE_OR_RETURN_VOID( xModel
.is(), "ControlContainerBase::elementInserted: illegal element!" );
1463 ImplInsertControl( xModel
, aName
);
1465 catch (const RuntimeException
&)
1469 catch (const Exception
&)
1471 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1475 void ControlContainerBase::elementRemoved( const ContainerEvent
& Event
)
1477 SolarMutexGuard aGuard
;
1479 Reference
< XControlModel
> xModel
;
1480 Event
.Element
>>= xModel
;
1481 ENSURE_OR_RETURN_VOID( xModel
.is(), "ControlContainerBase::elementRemoved: illegal element!" );
1484 ImplRemoveControl( xModel
);
1486 catch (const RuntimeException
&)
1490 catch (const Exception
&)
1492 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1496 void ControlContainerBase::elementReplaced( const ContainerEvent
& Event
)
1498 SolarMutexGuard aGuard
;
1500 Reference
< XControlModel
> xModel
;
1501 Event
.ReplacedElement
>>= xModel
;
1504 OSL_ENSURE( xModel
.is(), "ControlContainerBase::elementReplaced: invalid ReplacedElement!" );
1506 ImplRemoveControl( xModel
);
1508 catch (const RuntimeException
&)
1512 catch (const Exception
&)
1514 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1518 Event
.Accessor
>>= aName
;
1519 Event
.Element
>>= xModel
;
1520 ENSURE_OR_RETURN_VOID( xModel
.is(), "ControlContainerBase::elementReplaced: invalid new element!" );
1523 ImplInsertControl( xModel
, aName
);
1525 catch (const RuntimeException
&)
1529 catch (const Exception
&)
1531 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1535 // XPropertiesChangeListener
1536 void ControlContainerBase::ImplModelPropertiesChanged( const Sequence
< PropertyChangeEvent
>& rEvents
)
1538 if( !isDesignMode() && !mbCreatingCompatiblePeer
)
1540 auto pEvt
= std::find_if(rEvents
.begin(), rEvents
.end(),
1541 [](const PropertyChangeEvent
& rEvt
) {
1542 return rEvt
.PropertyName
== "PositionX"
1543 || rEvt
.PropertyName
== "PositionY"
1544 || rEvt
.PropertyName
== "Width"
1545 || rEvt
.PropertyName
== "Height";
1547 if (pEvt
!= rEvents
.end())
1549 Reference
< XControlModel
> xModel( pEvt
->Source
, UNO_QUERY
);
1550 bool bOwnModel
= xModel
.get() == getModel().get();
1553 if ( !mbPosModified
&& !mbSizeModified
)
1555 // Don't set new pos/size if we get new values from window listener
1556 Reference
< XControl
> xThis(this);
1557 ImplSetPosSize( xThis
);
1562 Sequence
<Reference
<XControl
> > aControlSequence(getControls());
1563 Reference
<XControl
> aControlRef( StdTabController::FindControl( aControlSequence
, xModel
) );
1564 ImplSetPosSize( aControlRef
);
1569 UnoControlContainer::ImplModelPropertiesChanged( rEvents
);
1572 void ControlContainerBase::addingControl( const Reference
< XControl
>& _rxControl
)
1574 SolarMutexGuard aGuard
;
1575 UnoControlContainer::addingControl( _rxControl
);
1577 if ( !_rxControl
.is() )
1580 Reference
< XMultiPropertySet
> xProps( _rxControl
->getModel(), UNO_QUERY
);
1583 const Sequence
< OUString
> aNames
{
1590 xProps
->addPropertiesChangeListener( aNames
, this );
1594 void ControlContainerBase::removingControl( const Reference
< XControl
>& _rxControl
)
1596 SolarMutexGuard aGuard
;
1597 UnoControlContainer::removingControl( _rxControl
);
1599 if ( _rxControl
.is() )
1601 Reference
< XMultiPropertySet
> xProps( _rxControl
->getModel(), UNO_QUERY
);
1603 xProps
->removePropertiesChangeListener( this );
1608 void SAL_CALL
ControlContainerBase::changesOccurred( const ChangesEvent
& )
1610 SolarMutexGuard aGuard
;
1611 // a tab controller model may have changed
1613 // #109067# in design mode don't notify the tab controller
1614 // about tab index changes
1615 if ( mxTabController
.is() && !mbDesignMode
)
1616 mxTabController
->activateTabOrder();
1618 static void lcl_ApplyResolverToNestedContainees( const Reference
< resource::XStringResourceResolver
>& xStringResourceResolver
, const Reference
< XControlContainer
>& xContainer
)
1620 OUString
aPropName( PROPERTY_RESOURCERESOLVER
);
1622 Any aNewStringResourceResolver
;
1623 aNewStringResourceResolver
<<= xStringResourceResolver
;
1625 Sequence
< OUString
> aPropNames
{ aPropName
};
1627 const Sequence
< Reference
< awt::XControl
> > aSeq
= xContainer
->getControls();
1628 for ( const Reference
< XControl
>& xControl
: aSeq
)
1630 Reference
< XPropertySet
> xPropertySet
;
1632 if ( xControl
.is() )
1633 xPropertySet
.set( xControl
->getModel(), UNO_QUERY
);
1635 if ( !xPropertySet
.is() )
1640 Reference
< resource::XStringResourceResolver
> xCurrStringResourceResolver
;
1641 Any aOldValue
= xPropertySet
->getPropertyValue( aPropName
);
1642 if ( ( aOldValue
>>= xCurrStringResourceResolver
)
1643 && ( xStringResourceResolver
== xCurrStringResourceResolver
)
1646 Reference
< XMultiPropertySet
> xMultiPropSet( xPropertySet
, UNO_QUERY
);
1647 Reference
< XPropertiesChangeListener
> xListener( xPropertySet
, UNO_QUERY
);
1648 xMultiPropSet
->firePropertiesChangeEvent( aPropNames
, xListener
);
1651 xPropertySet
->setPropertyValue( aPropName
, aNewStringResourceResolver
);
1653 catch (const Exception
&)
1657 uno::Reference
< XControlContainer
> xNestedContainer( xControl
, uno::UNO_QUERY
);
1658 if ( xNestedContainer
.is() )
1659 lcl_ApplyResolverToNestedContainees( xStringResourceResolver
, xNestedContainer
);
1664 void ControlContainerBase::ImplStartListingForResourceEvents()
1666 Reference
< resource::XStringResourceResolver
> xStringResourceResolver
;
1668 if ( !ImplHasProperty(PROPERTY_RESOURCERESOLVER
) )
1671 ImplGetPropertyValue( PROPERTY_RESOURCERESOLVER
) >>= xStringResourceResolver
;
1673 // Add our helper as listener to retrieve notifications about changes
1674 Reference
< util::XModifyListener
> rListener( mxListener
);
1675 ResourceListener
* pResourceListener
= static_cast< ResourceListener
* >( rListener
.get() );
1677 // resource listener will stop listening if resolver reference is empty
1678 if ( pResourceListener
)
1679 pResourceListener
->startListening( xStringResourceResolver
);
1680 ImplUpdateResourceResolver();
1683 void ControlContainerBase::ImplUpdateResourceResolver()
1685 Reference
< resource::XStringResourceResolver
> xStringResourceResolver
;
1687 if ( !ImplHasProperty(PROPERTY_RESOURCERESOLVER
) )
1690 ImplGetPropertyValue(PROPERTY_RESOURCERESOLVER
) >>= xStringResourceResolver
;
1692 if ( !xStringResourceResolver
.is() )
1695 lcl_ApplyResolverToNestedContainees( xStringResourceResolver
, this );
1697 // propagate resource resolver changes to language dependent props of the dialog
1698 Reference
< XPropertySet
> xPropertySet( getModel(), UNO_QUERY
);
1699 if ( xPropertySet
.is() )
1701 Reference
< XMultiPropertySet
> xMultiPropSet( xPropertySet
, UNO_QUERY
);
1702 Reference
< XPropertiesChangeListener
> xListener( xPropertySet
, UNO_QUERY
);
1703 xMultiPropSet
->firePropertiesChangeEvent( lcl_getLanguageDependentProperties(), xListener
);
1707 //// ----------------------------------------------------
1708 //// Helper Method to convert relative url to physical location
1709 //// ----------------------------------------------------
1711 OUString
getPhysicalLocation( const css::uno::Any
& rbase
, const css::uno::Any
& rUrl
)
1714 OUString baseLocation
;
1717 rbase
>>= baseLocation
;
1720 OUString
absoluteURL( url
);
1721 if ( !url
.isEmpty() )
1723 INetURLObject
urlObj(baseLocation
);
1724 urlObj
.removeSegment();
1725 baseLocation
= urlObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1727 const INetURLObject
protocolCheck( url
);
1728 const INetProtocol protocol
= protocolCheck
.GetProtocol();
1729 if ( protocol
== INetProtocol::NotValid
)
1731 OUString testAbsoluteURL
;
1732 if ( ::osl::FileBase::E_None
== ::osl::FileBase::getAbsoluteFileURL( baseLocation
, url
, testAbsoluteURL
) )
1733 absoluteURL
= testAbsoluteURL
;
1741 ControlModelContainerBase::updateUserFormChildren( const Reference
< XNameContainer
>& xAllChildren
, const OUString
& aName
, ChildOperation Operation
, const css::uno::Reference
< css::awt::XControlModel
>& xTarget
)
1743 if ( Operation
< Insert
|| Operation
> Remove
)
1744 throw IllegalArgumentException();
1746 if ( !xAllChildren
.is() )
1747 throw IllegalArgumentException();
1749 if ( Operation
== Remove
)
1751 Reference
< XControlModel
> xOldModel( xAllChildren
->getByName( aName
), UNO_QUERY
);
1752 xAllChildren
->removeByName( aName
);
1754 Reference
< XNameContainer
> xChildContainer( xOldModel
, UNO_QUERY
);
1755 if ( xChildContainer
.is() )
1757 Reference
< XPropertySet
> xProps( xChildContainer
, UNO_QUERY
);
1758 // container control is being removed from this container, reset the
1759 // global list of containers
1761 xProps
->setPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES
), uno::Any( uno::Reference
< XNameContainer
>() ) );
1762 const Sequence
< OUString
> aChildNames
= xChildContainer
->getElementNames();
1763 for ( const auto& rName
: aChildNames
)
1764 updateUserFormChildren( xAllChildren
, rName
, Operation
, Reference
< XControlModel
> () );
1767 else if ( Operation
== Insert
)
1769 xAllChildren
->insertByName( aName
, uno::Any( xTarget
) );
1770 Reference
< XNameContainer
> xChildContainer( xTarget
, UNO_QUERY
);
1771 if ( xChildContainer
.is() )
1773 // container control is being added from this container, reset the
1774 // global list of containers to point to the correct global list
1775 Reference
< XPropertySet
> xProps( xChildContainer
, UNO_QUERY
);
1777 xProps
->setPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES
), uno::Any( xAllChildren
) );
1778 const Sequence
< OUString
> aChildNames
= xChildContainer
->getElementNames();
1779 for ( const auto& rName
: aChildNames
)
1781 Reference
< XControlModel
> xChildTarget( xChildContainer
->getByName( rName
), UNO_QUERY
);
1782 updateUserFormChildren( xAllChildren
, rName
, Operation
, xChildTarget
);
1789 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */