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 <toolkit/controls/controlmodelcontainerbase.hxx>
22 #include <vcl/svapp.hxx>
23 #include <vcl/window.hxx>
24 #include <vcl/wall.hxx>
25 #include <osl/mutex.hxx>
26 #include <toolkit/helper/property.hxx>
27 #include <toolkit/controls/geometrycontrolmodel.hxx>
28 #include <toolkit/controls/unocontrols.hxx>
29 #include "toolkit/controls/formattedcontrol.hxx"
30 #include "toolkit/controls/roadmapcontrol.hxx"
31 #include "toolkit/controls/tkscrollbar.hxx"
32 #include "toolkit/controls/tabpagemodel.hxx"
33 #include <toolkit/controls/stdtabcontroller.hxx>
34 #include <com/sun/star/awt/PosSize.hpp>
35 #include <com/sun/star/awt/WindowAttribute.hpp>
36 #include <com/sun/star/resource/XStringResourceResolver.hpp>
37 #include <com/sun/star/graphic/XGraphicProvider.hpp>
38 #include <com/sun/star/lang/XInitialization.hpp>
39 #include <cppuhelper/typeprovider.hxx>
40 #include <cppuhelper/queryinterface.hxx>
41 #include <tools/debug.hxx>
42 #include <tools/diagnose_ex.h>
43 #include <comphelper/processfactory.hxx>
44 #include <vcl/outdev.hxx>
45 #include <comphelper/types.hxx>
47 #include <toolkit/helper/vclunohelper.hxx>
48 #include <unotools/ucbstreamhelper.hxx>
49 #include <vcl/graph.hxx>
50 #include <vcl/image.hxx>
52 #include "tree/treecontrol.hxx"
53 #include "grid/gridcontrol.hxx"
54 #include <toolkit/controls/tabpagecontainer.hxx>
59 #include "tools/urlobj.hxx"
60 #include "osl/file.hxx"
61 #include "toolkit/controls/dialogcontrol.hxx"
63 #include "helper/tkresmgr.hxx"
64 #include "helper/unopropertyarrayhelper.hxx"
65 #include "controlmodelcontainerbase_internal.hxx"
67 using namespace ::com::sun::star
;
68 using namespace ::com::sun::star::uno
;
69 using namespace ::com::sun::star::awt
;
70 using namespace ::com::sun::star::lang
;
71 using namespace ::com::sun::star::container
;
72 using namespace ::com::sun::star::beans
;
73 using namespace ::com::sun::star::util
;
74 using namespace toolkit
;
76 #define PROPERTY_RESOURCERESOLVER "ResourceResolver"
77 struct LanguageDependentProp
79 const char* pPropName
;
80 sal_Int32 nPropNameLength
;
86 const Sequence
< OUString
>& lcl_getLanguageDependentProperties()
88 static Sequence
< OUString
> s_aLanguageDependentProperties
;
89 if ( s_aLanguageDependentProperties
.getLength() == 0 )
91 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
92 if ( s_aLanguageDependentProperties
.getLength() == 0 )
94 s_aLanguageDependentProperties
.realloc( 2 );
95 s_aLanguageDependentProperties
[0] = "HelpText";
96 s_aLanguageDependentProperties
[1] = "Title";
97 // note: properties must be sorted
100 return s_aLanguageDependentProperties
;
105 // functor for disposing a control model
106 struct DisposeControlModel
: public ::std::unary_function
< Reference
< XControlModel
>, void >
108 void operator()( Reference
< XControlModel
>& _rxModel
)
112 ::comphelper::disposeComponent( _rxModel
);
114 catch (const Exception
&)
116 SAL_WARN("toolkit", "caught an exception while disposing a component!" );
122 // functor for searching control model by name
123 struct FindControlModel
: public ::std::unary_function
< ControlModelContainerBase::UnoControlModelHolder
, bool >
126 const OUString
& m_rName
;
129 explicit FindControlModel( const OUString
& _rName
) : m_rName( _rName
) { }
131 bool operator()( const ControlModelContainerBase::UnoControlModelHolder
& _rCompare
)
133 return _rCompare
.second
== m_rName
;
138 // functor for cloning a control model, and insertion into a target list
139 struct CloneControlModel
: public ::std::unary_function
< ControlModelContainerBase::UnoControlModelHolder
, void >
142 ControlModelContainerBase::UnoControlModelHolderList
& m_rTargetList
;
145 explicit CloneControlModel( ControlModelContainerBase::UnoControlModelHolderList
& _rTargetList
)
146 :m_rTargetList( _rTargetList
)
150 void operator()( const ControlModelContainerBase::UnoControlModelHolder
& _rSource
)
152 // clone the source object
153 Reference
< XCloneable
> xCloneSource( _rSource
.first
, UNO_QUERY
);
154 Reference
< XControlModel
> xClone( xCloneSource
->createClone(), UNO_QUERY
);
155 // add to target list
156 m_rTargetList
.push_back( ControlModelContainerBase::UnoControlModelHolder( xClone
, _rSource
.second
) );
161 // functor for comparing a XControlModel with a given reference
162 struct CompareControlModel
: public ::std::unary_function
< ControlModelContainerBase::UnoControlModelHolder
, bool >
165 Reference
< XControlModel
> m_xReference
;
167 explicit CompareControlModel( const Reference
< XControlModel
>& _rxReference
) : m_xReference( _rxReference
) { }
169 bool operator()( const ControlModelContainerBase::UnoControlModelHolder
& _rCompare
)
171 return _rCompare
.first
.get() == m_xReference
.get();
176 static void lcl_throwIllegalArgumentException( )
177 { // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this ....
178 throw IllegalArgumentException();
182 static void lcl_throwNoSuchElementException( )
183 { // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this ....
184 throw NoSuchElementException();
188 static void lcl_throwElementExistException( )
189 { // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this ....
190 throw ElementExistException();
194 static OUString
getTabIndexPropertyName( )
196 return OUString( "TabIndex" );
200 static OUString
getStepPropertyName( )
202 return OUString( "Step" );
206 // class ControlModelContainerBase
208 ControlModelContainerBase::ControlModelContainerBase( const Reference
< XComponentContext
>& rxContext
)
209 :ControlModelContainer_IBase( rxContext
)
210 ,maContainerListeners( *this )
211 ,maChangeListeners ( GetMutex() )
212 ,mbGroupsUpToDate( false )
218 ControlModelContainerBase::ControlModelContainerBase( const ControlModelContainerBase
& rModel
)
219 : ControlModelContainer_IBase( rModel
)
220 , maContainerListeners( *this )
221 , maChangeListeners ( GetMutex() )
222 , mbGroupsUpToDate( false )
223 , m_bEnabled( rModel
.m_bEnabled
)
224 , m_nTabPageId( rModel
.m_nTabPageId
)
228 ControlModelContainerBase::~ControlModelContainerBase()
231 mbGroupsUpToDate
= false;
234 Any
ControlModelContainerBase::ImplGetDefaultValue( sal_uInt16 nPropId
) const
240 case BASEPROPERTY_DEFAULTCONTROL
:
241 aAny
<<= OUString::createFromAscii( szServiceName_UnoControlDialog
);
244 aAny
= UnoControlModel::ImplGetDefaultValue( nPropId
);
250 ::cppu::IPropertyArrayHelper
& ControlModelContainerBase::getInfoHelper()
252 static UnoPropertyArrayHelper
* pHelper
= nullptr;
255 Sequence
<sal_Int32
> aIDs
= ImplGetPropertyIds();
256 pHelper
= new UnoPropertyArrayHelper( aIDs
);
261 void SAL_CALL
ControlModelContainerBase::dispose( )
264 // tell our listeners
266 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
268 EventObject aDisposeEvent
;
269 aDisposeEvent
.Source
= static_cast< XAggregation
* >( static_cast< ::cppu::OWeakAggObject
* >( this ) );
271 maContainerListeners
.disposeAndClear( aDisposeEvent
);
272 maChangeListeners
.disposeAndClear( aDisposeEvent
);
276 // call the base class
277 UnoControlModel::dispose();
280 // dispose our child models
281 // for this, collect the models (we collect them from maModels, and this is modified when disposing children)
282 ::std::vector
< Reference
< XControlModel
> > aChildModels( maModels
.size() );
285 maModels
.begin(), maModels
.end(), // source range
286 aChildModels
.begin(), // target location
287 []( const UnoControlModelHolder
& rUnoControlModelHolder
)
288 { return rUnoControlModelHolder
.first
; } // operation to apply -> select the XControlModel part
292 ::std::for_each( aChildModels
.begin(), aChildModels
.end(), DisposeControlModel() );
293 aChildModels
.clear();
295 mbGroupsUpToDate
= false;
299 Reference
< XPropertySetInfo
> ControlModelContainerBase::getPropertySetInfo( )
301 static Reference
< XPropertySetInfo
> xInfo( createPropertySetInfo( getInfoHelper() ) );
304 void ControlModelContainerBase::Clone_Impl(ControlModelContainerBase
& _rClone
) const
306 // clone all children
308 maModels
.begin(), maModels
.end(),
309 CloneControlModel( _rClone
.maModels
)
312 UnoControlModel
* ControlModelContainerBase::Clone() const
314 // clone the container itself
315 ControlModelContainerBase
* pClone
= new ControlModelContainerBase( *this );
321 ControlModelContainerBase::UnoControlModelHolderList::iterator
ControlModelContainerBase::ImplFindElement( const OUString
& rName
)
323 return ::std::find_if( maModels
.begin(), maModels
.end(), FindControlModel( rName
) );
326 // ::XMultiServiceFactory
327 Reference
< XInterface
> ControlModelContainerBase::createInstance( const OUString
& aServiceSpecifier
)
329 SolarMutexGuard aGuard
;
331 OGeometryControlModel_Base
* pNewModel
= nullptr;
333 if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlEditModel" )
334 pNewModel
= new OGeometryControlModel
< UnoControlEditModel
>( m_xContext
);
335 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlFormattedFieldModel" )
336 pNewModel
= new OGeometryControlModel
< UnoControlFormattedFieldModel
>( m_xContext
);
337 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlFileControlModel" )
338 pNewModel
= new OGeometryControlModel
< UnoControlFileControlModel
>( m_xContext
);
339 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlButtonModel" )
340 pNewModel
= new OGeometryControlModel
< UnoControlButtonModel
>( m_xContext
);
341 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlImageControlModel" )
342 pNewModel
= new OGeometryControlModel
< UnoControlImageControlModel
>( m_xContext
);
343 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlRadioButtonModel" )
344 pNewModel
= new OGeometryControlModel
< UnoControlRadioButtonModel
>( m_xContext
);
345 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlCheckBoxModel" )
346 pNewModel
= new OGeometryControlModel
< UnoControlCheckBoxModel
>( m_xContext
);
347 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlFixedHyperlinkModel" )
348 pNewModel
= new OGeometryControlModel
< UnoControlFixedHyperlinkModel
>( m_xContext
);
349 else if ( aServiceSpecifier
== "stardiv.vcl.controlmodel.FixedText" )
350 pNewModel
= new OGeometryControlModel
< UnoControlFixedTextModel
>( m_xContext
);
351 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlGroupBoxModel" )
352 pNewModel
= new OGeometryControlModel
< UnoControlGroupBoxModel
>( m_xContext
);
353 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlListBoxModel" )
354 pNewModel
= new OGeometryControlModel
< UnoControlListBoxModel
>( m_xContext
);
355 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlComboBoxModel" )
356 pNewModel
= new OGeometryControlModel
< UnoControlComboBoxModel
>( m_xContext
);
357 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlDateFieldModel" )
358 pNewModel
= new OGeometryControlModel
< UnoControlDateFieldModel
>( m_xContext
);
359 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlTimeFieldModel" )
360 pNewModel
= new OGeometryControlModel
< UnoControlTimeFieldModel
>( m_xContext
);
361 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlNumericFieldModel" )
362 pNewModel
= new OGeometryControlModel
< UnoControlNumericFieldModel
>( m_xContext
);
363 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlCurrencyFieldModel" )
364 pNewModel
= new OGeometryControlModel
< UnoControlCurrencyFieldModel
>( m_xContext
);
365 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlPatternFieldModel" )
366 pNewModel
= new OGeometryControlModel
< UnoControlPatternFieldModel
>( m_xContext
);
367 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlProgressBarModel" )
368 pNewModel
= new OGeometryControlModel
< UnoControlProgressBarModel
>( m_xContext
);
369 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlScrollBarModel" )
370 pNewModel
= new OGeometryControlModel
< UnoControlScrollBarModel
>( m_xContext
);
371 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlFixedLineModel" )
372 pNewModel
= new OGeometryControlModel
< UnoControlFixedLineModel
>( m_xContext
);
373 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoControlRoadmapModel" )
374 pNewModel
= new OGeometryControlModel
< UnoControlRoadmapModel
>( m_xContext
);
375 else if ( aServiceSpecifier
== "com.sun.star.awt.tree.TreeControlModel" )
376 pNewModel
= new OGeometryControlModel
< UnoTreeModel
>( m_xContext
);
377 else if ( aServiceSpecifier
== "com.sun.star.awt.grid.UnoControlGridModel" )
378 pNewModel
= new OGeometryControlModel
< UnoGridModel
>( m_xContext
);
379 else if ( aServiceSpecifier
== "com.sun.star.awt.tab.UnoControlTabPageContainerModel" )
380 pNewModel
= new OGeometryControlModel
< UnoControlTabPageContainerModel
>( m_xContext
);
381 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoMultiPageModel" )
382 pNewModel
= new OGeometryControlModel
< UnoMultiPageModel
>( m_xContext
);
383 else if ( aServiceSpecifier
== "com.sun.star.awt.tab.UnoControlTabPageModel" )
384 pNewModel
= new OGeometryControlModel
< UnoControlTabPageModel
>( m_xContext
);
385 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoPageModel" )
386 pNewModel
= new OGeometryControlModel
< UnoPageModel
>( m_xContext
);
387 else if ( aServiceSpecifier
== "com.sun.star.awt.UnoFrameModel" )
388 pNewModel
= new OGeometryControlModel
< UnoFrameModel
>( m_xContext
);
392 Reference
< XInterface
> xObject
= m_xContext
->getServiceManager()->createInstanceWithContext(aServiceSpecifier
, m_xContext
);
393 Reference
< XServiceInfo
> xSI( xObject
, UNO_QUERY
);
394 Reference
< XCloneable
> xCloneAccess( xSI
, UNO_QUERY
);
395 Reference
< XAggregation
> xAgg( xCloneAccess
, UNO_QUERY
);
398 if ( xSI
->supportsService("com.sun.star.awt.UnoControlModel") )
400 // release 3 of the 4 references we have to the object
405 pNewModel
= new OCommonGeometryControlModel( xCloneAccess
, aServiceSpecifier
);
410 Reference
< XInterface
> xNewModel
= static_cast<cppu::OWeakObject
*>(pNewModel
);
414 Reference
< XInterface
> ControlModelContainerBase::createInstanceWithArguments( const OUString
& ServiceSpecifier
, const Sequence
< Any
>& i_arguments
)
416 const Reference
< XInterface
> xInstance( createInstance( ServiceSpecifier
) );
417 const Reference
< XInitialization
> xInstanceInit( xInstance
, UNO_QUERY
);
418 ENSURE_OR_RETURN( xInstanceInit
.is(), "ControlModelContainerBase::createInstanceWithArguments: can't pass the arguments!", xInstance
);
419 xInstanceInit
->initialize( i_arguments
);
423 Sequence
< OUString
> ControlModelContainerBase::getAvailableServiceNames()
425 static Sequence
< OUString
>* pNamesSeq
= nullptr;
428 pNamesSeq
= new Sequence
< OUString
>( 26 );
429 OUString
* pNames
= pNamesSeq
->getArray();
430 pNames
[0] = "com.sun.star.awt.UnoControlEditModel";
431 pNames
[1] = "com.sun.star.awt.UnoControlFormattedFieldModel";
432 pNames
[2] = "com.sun.star.awt.UnoControlFileControlModel";
433 pNames
[3] = "com.sun.star.awt.UnoControlButtonModel";
434 pNames
[4] = "com.sun.star.awt.UnoControlImageControlModel";
435 pNames
[5] = "com.sun.star.awt.UnoControlRadioButtonModel";
436 pNames
[6] = "com.sun.star.awt.UnoControlCheckBoxModel";
437 pNames
[7] = "com.sun.star.awt.UnoControlFixedTextModel";
438 pNames
[8] = "com.sun.star.awt.UnoControlGroupBoxModel";
439 pNames
[9] = "com.sun.star.awt.UnoControlListBoxModel";
440 pNames
[10] = "com.sun.star.awt.UnoControlComboBoxModel";
441 pNames
[11] = "com.sun.star.awt.UnoControlDateFieldModel";
442 pNames
[12] = "com.sun.star.awt.UnoControlTimeFieldModel";
443 pNames
[13] = "com.sun.star.awt.UnoControlNumericFieldModel";
444 pNames
[14] = "com.sun.star.awt.UnoControlCurrencyFieldModel";
445 pNames
[15] = "com.sun.star.awt.UnoControlPatternFieldModel";
446 pNames
[16] = "com.sun.star.awt.tree.TreeControlModel";
447 pNames
[21] = "com.sun.star.awt.grid.UnoControlGridModel";
448 pNames
[22] = "com.sun.star.awt.tab.UnoControlTabPageContainerModel";
449 pNames
[23] = "com.sun.star.awt.tab.UnoControlTabPageModel";
450 pNames
[24] = "com.sun.star.awt.UnoMultiPageModel";
451 pNames
[25] = "com.sun.star.awt.UnoFrameModel";
457 void ControlModelContainerBase::addContainerListener( const Reference
< XContainerListener
>& l
)
459 maContainerListeners
.addInterface( l
);
462 void ControlModelContainerBase::removeContainerListener( const Reference
< XContainerListener
>& l
)
464 maContainerListeners
.removeInterface( l
);
468 Type
ControlModelContainerBase::getElementType()
470 Type aType
= cppu::UnoType
<XControlModel
>::get();
474 sal_Bool
ControlModelContainerBase::hasElements()
476 return !maModels
.empty();
479 // XNameContainer, XNameReplace, XNameAccess
480 void ControlModelContainerBase::replaceByName( const OUString
& aName
, const Any
& aElement
)
482 SolarMutexGuard aGuard
;
484 Reference
< XControlModel
> xNewModel
;
485 aElement
>>= xNewModel
;
486 if ( !xNewModel
.is() )
487 lcl_throwIllegalArgumentException();
489 UnoControlModelHolderList::iterator aElementPos
= ImplFindElement( aName
);
490 if ( maModels
.end() == aElementPos
)
491 lcl_throwNoSuchElementException();
492 // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
493 // With container controls you could have constructed an existing hierarchy and are now
494 // add this to an existing container, in this case a name nested in the containment
495 // hierarchy of the added control could contain a name clash, if we have access to the
496 // list of global names then recursively check for previously existing names (we need
497 // to do this obviously before the 'this' objects container is updated)
498 Reference
< XNameContainer
> xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES
) ), UNO_QUERY
);
499 if ( xAllChildren
.is() )
501 // remove old control (and children) from global list of containees
502 updateUserFormChildren( xAllChildren
, aName
, Remove
, uno::Reference
< XControlModel
>() );
503 // Add new control (and containees if they exist)
504 updateUserFormChildren( xAllChildren
, aName
, Insert
, xNewModel
);
506 // stop listening at the old model
507 stopControlListening( aElementPos
->first
);
508 Reference
< XControlModel
> xReplaced( aElementPos
->first
);
509 // remember the new model, and start listening
510 aElementPos
->first
= xNewModel
;
511 startControlListening( xNewModel
);
513 ContainerEvent aEvent
;
514 aEvent
.Source
= *this;
515 aEvent
.Element
= aElement
;
516 aEvent
.ReplacedElement
<<= xReplaced
;
517 aEvent
.Accessor
<<= aName
;
519 // notify the container listener
520 maContainerListeners
.elementReplaced( aEvent
);
522 // our "tab controller model" has potentially changed -> notify this
523 implNotifyTabModelChange( aName
);
526 Any
ControlModelContainerBase::getByName( const OUString
& aName
)
528 UnoControlModelHolderList::iterator aElementPos
= ImplFindElement( aName
);
529 if ( maModels
.end() == aElementPos
)
530 lcl_throwNoSuchElementException();
532 return makeAny( aElementPos
->first
);
535 Sequence
< OUString
> ControlModelContainerBase::getElementNames()
537 Sequence
< OUString
> aNames( maModels
.size() );
540 maModels
.begin(), maModels
.end(), // source range
541 aNames
.getArray(), // target range
542 []( const UnoControlModelHolder
& rUnoControlModelHolder
)
543 { return rUnoControlModelHolder
.second
; } // operator to apply: select the second element (the name)
549 sal_Bool
ControlModelContainerBase::hasByName( const OUString
& aName
)
551 return maModels
.end() != ImplFindElement( aName
);
554 void ControlModelContainerBase::insertByName( const OUString
& aName
, const Any
& aElement
)
556 SolarMutexGuard aGuard
;
558 Reference
< XControlModel
> xM
;
563 Reference
< beans::XPropertySet
> xProps( xM
, UNO_QUERY
);
567 Reference
< beans::XPropertySetInfo
> xPropInfo
= xProps
.get()->getPropertySetInfo();
569 const OUString
& sImageSourceProperty
= GetPropertyName( BASEPROPERTY_IMAGEURL
);
570 if ( xPropInfo
.get()->hasPropertyByName( sImageSourceProperty
) && ImplHasProperty(BASEPROPERTY_DIALOGSOURCEURL
) )
572 Any aUrl
= xProps
.get()->getPropertyValue( sImageSourceProperty
);
574 OUString absoluteUrl
=
575 getPhysicalLocation( getPropertyValue( GetPropertyName( BASEPROPERTY_DIALOGSOURCEURL
) ), aUrl
);
577 aUrl
<<= absoluteUrl
;
579 xProps
.get()->setPropertyValue( sImageSourceProperty
, aUrl
);
585 if ( aName
.isEmpty() || !xM
.is() )
586 lcl_throwIllegalArgumentException();
588 UnoControlModelHolderList::iterator aElementPos
= ImplFindElement( aName
);
589 if ( maModels
.end() != aElementPos
)
590 lcl_throwElementExistException();
592 // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
593 // With container controls you could have constructed an existing hierarchy and are now
594 // add this to an existing container, in this case a name nested in the containment
595 // hierarchy of the added control could contain a name clash, if we have access to the
596 // list of global names then we need to recursively check for previously existing
597 // names (we need to do this obviously before the 'this' objects container is updated)
598 // remove old control (and children) from global list of containees
599 Reference
< XNameContainer
> xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES
) ), UNO_QUERY
);
601 if ( xAllChildren
.is() )
602 updateUserFormChildren( xAllChildren
, aName
, Insert
, xM
);
603 maModels
.push_back( UnoControlModelHolder( xM
, aName
) );
604 mbGroupsUpToDate
= false;
605 startControlListening( xM
);
607 ContainerEvent aEvent
;
608 aEvent
.Source
= *this;
609 aEvent
.Element
= aElement
;
610 aEvent
.Accessor
<<= aName
;
611 maContainerListeners
.elementInserted( aEvent
);
613 // our "tab controller model" has potentially changed -> notify this
614 implNotifyTabModelChange( aName
);
617 void ControlModelContainerBase::removeByName( const OUString
& aName
)
619 SolarMutexGuard aGuard
;
621 UnoControlModelHolderList::iterator aElementPos
= ImplFindElement( aName
);
622 if ( maModels
.end() == aElementPos
)
623 lcl_throwNoSuchElementException();
625 // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
626 // With container controls you could have constructed an existing hierarchy and are now
627 // removing this control from an existing container, in this case all nested names in
628 // the containment hierarchy of the control to be removed need to be removed from the global
629 // names cache (we need to do this obviously before the 'this' objects container is updated)
630 Reference
< XNameContainer
> xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES
) ), UNO_QUERY
);
631 if ( xAllChildren
.is() )
632 updateUserFormChildren( xAllChildren
, aName
, Remove
, uno::Reference
< XControlModel
>() );
634 ContainerEvent aEvent
;
635 aEvent
.Source
= *this;
636 aEvent
.Element
<<= aElementPos
->first
;
637 aEvent
.Accessor
<<= aName
;
638 maContainerListeners
.elementRemoved( aEvent
);
640 stopControlListening( aElementPos
->first
);
641 Reference
< XPropertySet
> xPS( aElementPos
->first
, UNO_QUERY
);
642 maModels
.erase( aElementPos
);
643 mbGroupsUpToDate
= false;
649 xPS
->setPropertyValue( PROPERTY_RESOURCERESOLVER
, makeAny( Reference
< resource::XStringResourceResolver
>() ) );
651 catch (const Exception
&)
653 DBG_UNHANDLED_EXCEPTION();
657 // our "tab controller model" has potentially changed -> notify this
658 implNotifyTabModelChange( aName
);
662 sal_Bool SAL_CALL
ControlModelContainerBase::getGroupControl( )
668 void SAL_CALL
ControlModelContainerBase::setGroupControl( sal_Bool
)
670 SAL_WARN("toolkit", "explicit grouping not supported" );
674 void SAL_CALL
ControlModelContainerBase::setControlModels( const Sequence
< Reference
< XControlModel
> >& _rControls
)
676 SolarMutexGuard aGuard
;
678 // set the tab indexes according to the order of models in the sequence
679 const Reference
< XControlModel
>* pControls
= _rControls
.getConstArray( );
680 const Reference
< XControlModel
>* pControlsEnd
= _rControls
.getConstArray( ) + _rControls
.getLength();
682 sal_Int16 nTabIndex
= 1;
684 for ( ; pControls
!= pControlsEnd
; ++pControls
)
686 // look up the control in our own structure. This is to prevent invalid arguments
687 UnoControlModelHolderList::const_iterator aPos
=
689 maModels
.begin(), maModels
.end(),
690 CompareControlModel( *pControls
)
692 if ( maModels
.end() != aPos
)
694 // okay, this is an existent model
695 // now set the TabIndex property (if applicable)
696 Reference
< XPropertySet
> xProps( aPos
->first
, UNO_QUERY
);
697 Reference
< XPropertySetInfo
> xPSI
;
699 xPSI
= xProps
->getPropertySetInfo();
700 if ( xPSI
.is() && xPSI
->hasPropertyByName( getTabIndexPropertyName() ) )
701 xProps
->setPropertyValue( getTabIndexPropertyName(), makeAny( nTabIndex
++ ) );
703 mbGroupsUpToDate
= false;
708 typedef ::std::multimap
< sal_Int32
, Reference
< XControlModel
> > MapIndexToModel
;
711 Sequence
< Reference
< XControlModel
> > SAL_CALL
ControlModelContainerBase::getControlModels( )
713 SolarMutexGuard aGuard
;
715 MapIndexToModel aSortedModels
;
716 // will be the sorted container of all models which have a tab index property
717 ::std::vector
< Reference
< XControlModel
> > aUnindexedModels
;
718 // will be the container of all models which do not have a tab index property
720 UnoControlModelHolderList::const_iterator aLoop
= maModels
.begin();
721 for ( ; aLoop
!= maModels
.end(); ++aLoop
)
723 Reference
< XControlModel
> xModel( aLoop
->first
);
725 // see if the model has a TabIndex property
726 Reference
< XPropertySet
> xControlProps( xModel
, UNO_QUERY
);
727 Reference
< XPropertySetInfo
> xPSI
;
728 if ( xControlProps
.is() )
729 xPSI
= xControlProps
->getPropertySetInfo( );
730 DBG_ASSERT( xPSI
.is(), "ControlModelContainerBase::getControlModels: invalid child model!" );
733 if ( xPSI
.is() && xPSI
->hasPropertyByName( getTabIndexPropertyName() ) )
735 sal_Int32 nTabIndex
= -1;
736 xControlProps
->getPropertyValue( getTabIndexPropertyName() ) >>= nTabIndex
;
738 aSortedModels
.insert( MapIndexToModel::value_type( nTabIndex
, xModel
) );
740 else if ( xModel
.is() )
741 // no, it hasn't, but we have to include it, anyway
742 aUnindexedModels
.push_back( xModel
);
745 // okay, here we have a container of all our models, sorted by tab index,
746 // plus a container of "unindexed" models
748 Sequence
< Reference
< XControlModel
> > aReturn( aUnindexedModels
.size() + aSortedModels
.size() );
750 aSortedModels
.begin(), aSortedModels
.end(),
751 ::std::copy( aUnindexedModels
.begin(), aUnindexedModels
.end(), aReturn
.getArray() ),
752 [] ( const MapIndexToModel::value_type
& entryIndexToModel
)
753 { return entryIndexToModel
.second
; }
760 void SAL_CALL
ControlModelContainerBase::setGroup( const Sequence
< Reference
< XControlModel
> >&, const OUString
& )
762 // not supported. We have only implicit grouping:
763 // We only have a sequence of control models, and we _know_ (yes, that's a HACK relying on
764 // implementation details) that VCL does grouping according to the order of controls automatically
765 // At least VCL does this for all we're interested in: Radio buttons.
766 SAL_WARN("toolkit", "grouping not supported" );
769 ////----- XInitialization -------------------------------------------------------------------
770 void SAL_CALL
ControlModelContainerBase::initialize (const Sequence
<Any
>& rArguments
)
772 if ( rArguments
.getLength() == 1 )
774 sal_Int16 nPageId
= -1;
775 if ( !( rArguments
[ 0 ] >>= nPageId
))
776 throw lang::IllegalArgumentException();
777 m_nTabPageId
= nPageId
;
782 ::sal_Int16 SAL_CALL
ControlModelContainerBase::getTabPageID()
786 sal_Bool SAL_CALL
ControlModelContainerBase::getEnabled()
790 void SAL_CALL
ControlModelContainerBase::setEnabled( sal_Bool _enabled
)
792 m_bEnabled
= _enabled
;
794 OUString SAL_CALL
ControlModelContainerBase::getTitle()
796 SolarMutexGuard aGuard
;
797 Reference
<XPropertySet
> xThis(*this,UNO_QUERY
);
799 xThis
->getPropertyValue(GetPropertyName(BASEPROPERTY_TITLE
)) >>= sTitle
;
802 void SAL_CALL
ControlModelContainerBase::setTitle( const OUString
& _title
)
804 SolarMutexGuard aGuard
;
805 Reference
<XPropertySet
> xThis(*this,UNO_QUERY
);
806 xThis
->setPropertyValue(GetPropertyName(BASEPROPERTY_TITLE
),makeAny(_title
));
808 OUString SAL_CALL
ControlModelContainerBase::getImageURL()
812 void SAL_CALL
ControlModelContainerBase::setImageURL( const OUString
& _imageurl
)
814 m_sImageURL
= _imageurl
;
816 OUString SAL_CALL
ControlModelContainerBase::getToolTip()
820 void SAL_CALL
ControlModelContainerBase::setToolTip( const OUString
& _tooltip
)
822 m_sTooltip
= _tooltip
;
828 enum GroupingMachineState
835 sal_Int32
lcl_getDialogStep( const Reference
< XControlModel
>& _rxModel
)
840 Reference
< XPropertySet
> xModelProps( _rxModel
, UNO_QUERY
);
841 xModelProps
->getPropertyValue( getStepPropertyName() ) >>= nStep
;
843 catch (const Exception
&)
845 SAL_WARN("toolkit", "caught an exception while determining the dialog page!" );
852 sal_Int32 SAL_CALL
ControlModelContainerBase::getGroupCount( )
854 SolarMutexGuard aGuard
;
856 implUpdateGroupStructure();
858 return maGroups
.size();
862 void SAL_CALL
ControlModelContainerBase::getGroup( sal_Int32 _nGroup
, Sequence
< Reference
< XControlModel
> >& _rGroup
, OUString
& _rName
)
864 SolarMutexGuard aGuard
;
866 implUpdateGroupStructure();
868 if ( ( _nGroup
< 0 ) || ( _nGroup
>= (sal_Int32
)maGroups
.size() ) )
870 SAL_WARN("toolkit", "invalid argument and I am not allowed to throw an exception!" );
871 _rGroup
.realloc( 0 );
876 AllGroups::const_iterator aGroupPos
= maGroups
.begin() + _nGroup
;
877 _rGroup
.realloc( aGroupPos
->size() );
879 ::std::copy( aGroupPos
->begin(), aGroupPos
->end(), _rGroup
.getArray() );
880 // give the group a name
881 _rName
= OUString::number( _nGroup
);
886 void SAL_CALL
ControlModelContainerBase::getGroupByName( const OUString
& _rName
, Sequence
< Reference
< XControlModel
> >& _rGroup
)
888 SolarMutexGuard aGuard
;
891 getGroup( _rName
.toInt32( ), _rGroup
, sDummyName
);
895 void SAL_CALL
ControlModelContainerBase::addChangesListener( const Reference
< XChangesListener
>& _rxListener
)
897 maChangeListeners
.addInterface( _rxListener
);
901 void SAL_CALL
ControlModelContainerBase::removeChangesListener( const Reference
< XChangesListener
>& _rxListener
)
903 maChangeListeners
.removeInterface( _rxListener
);
907 void ControlModelContainerBase::implNotifyTabModelChange( const OUString
& _rAccessor
)
909 // multiplex to our change listeners:
912 aEvent
.Source
= *this;
913 aEvent
.Base
<<= aEvent
.Source
; // the "base of the changes root" is also ourself
914 aEvent
.Changes
.realloc( 1 ); // exactly one change
915 aEvent
.Changes
[ 0 ].Accessor
<<= _rAccessor
;
918 std::vector
< Reference
< XInterface
> > aChangeListeners( maChangeListeners
.getElements() );
919 for ( const auto& rListener
: aChangeListeners
)
921 if ( rListener
.is() )
922 static_cast< XChangesListener
* >( rListener
.get() )->changesOccurred( aEvent
);
927 void ControlModelContainerBase::implUpdateGroupStructure()
929 if ( mbGroupsUpToDate
)
933 // conditions for a group:
934 // * all elements of the group are radio buttons
935 // * all elements of the group are on the same dialog page
936 // * in the overall control order (determined by the tab index), all elements are subsequent
940 Sequence
< Reference
< XControlModel
> > aControlModels
= getControlModels();
941 const Reference
< XControlModel
>* pControlModels
= aControlModels
.getConstArray();
942 const Reference
< XControlModel
>* pControlModelsEnd
= pControlModels
+ aControlModels
.getLength();
944 // in extreme we have as much groups as controls
945 maGroups
.reserve( aControlModels
.getLength() );
947 GroupingMachineState eState
= eLookingForGroup
; // the current state of our machine
948 Reference
< XServiceInfo
> xModelSI
; // for checking for a radio button
949 AllGroups::iterator aCurrentGroup
= maGroups
.end(); // the group which we're currently building
950 sal_Int32 nCurrentGroupStep
= -1; // the step which all controls of the current group belong to
953 for ( ; pControlModels
!= pControlModelsEnd
; ++pControlModels
)
955 // we'll need this in every state
956 xModelSI
.set(*pControlModels
, css::uno::UNO_QUERY
);
957 // is it a radio button?
958 bool bIsRadioButton
= xModelSI
.is() && xModelSI
->supportsService( "com.sun.star.awt.UnoControlRadioButtonModel" );
962 case eLookingForGroup
:
964 if ( !bIsRadioButton
)
965 // this is no radio button -> still looking for the beginning of a group
967 // the current model is a radio button
968 // -> we found the beginning of a new group
969 // create the place for this group
970 size_t nGroups
= maGroups
.size();
971 maGroups
.resize( nGroups
+ 1 );
972 aCurrentGroup
= maGroups
.begin() + nGroups
;
973 // and add the (only, til now) member
974 aCurrentGroup
->push_back( *pControlModels
);
976 // get the step which all controls of this group now have to belong to
977 nCurrentGroupStep
= lcl_getDialogStep( *pControlModels
);
978 // new state: looking for further members
979 eState
= eExpandingGroup
;
984 case eExpandingGroup
:
986 if ( !bIsRadioButton
)
987 { // no radio button -> the group is done
988 aCurrentGroup
= maGroups
.end();
989 eState
= eLookingForGroup
;
993 // it is a radio button - is it on the proper page?
994 const sal_Int32 nThisModelStep
= lcl_getDialogStep( *pControlModels
);
995 if ( ( nThisModelStep
== nCurrentGroupStep
) // the current button is on the same dialog page
996 || ( 0 == nThisModelStep
) // the current button appears on all pages
999 // -> it belongs to the same group
1000 aCurrentGroup
->push_back( *pControlModels
);
1001 // state still is eExpandingGroup - we're looking for further elements
1002 eState
= eExpandingGroup
;
1007 // it's a radio button, but on a different page
1008 // -> we open a new group for it
1012 size_t nGroups
= maGroups
.size();
1013 maGroups
.resize( nGroups
+ 1 );
1014 aCurrentGroup
= maGroups
.begin() + nGroups
;
1015 // and add the (only, til now) member
1016 aCurrentGroup
->push_back( *pControlModels
);
1018 nCurrentGroupStep
= nThisModelStep
;
1020 // state is the same: we still are looking for further elements of the current group
1021 eState
= eExpandingGroup
;
1027 mbGroupsUpToDate
= true;
1031 void SAL_CALL
ControlModelContainerBase::propertyChange( const PropertyChangeEvent
& _rEvent
)
1033 SolarMutexGuard aGuard
;
1035 DBG_ASSERT( _rEvent
.PropertyName
== "TabIndex",
1036 "ControlModelContainerBase::propertyChange: not listening for this property!" );
1038 // the accessor for the changed element
1040 UnoControlModelHolderList::const_iterator aPos
=
1042 maModels
.begin(), maModels
.end(),
1043 CompareControlModel( Reference
< XControlModel
>( _rEvent
.Source
, UNO_QUERY
) )
1045 OSL_ENSURE( maModels
.end() != aPos
, "ControlModelContainerBase::propertyChange: don't know this model!" );
1046 if ( maModels
.end() != aPos
)
1047 sAccessor
= aPos
->second
;
1049 // our groups are not up-to-date
1050 mbGroupsUpToDate
= false;
1053 implNotifyTabModelChange( sAccessor
);
1057 void SAL_CALL
ControlModelContainerBase::disposing( const EventObject
& /*rEvent*/ )
1062 void ControlModelContainerBase::startControlListening( const Reference
< XControlModel
>& _rxChildModel
)
1064 SolarMutexGuard aGuard
;
1066 Reference
< XPropertySet
> xModelProps( _rxChildModel
, UNO_QUERY
);
1067 Reference
< XPropertySetInfo
> xPSI
;
1068 if ( xModelProps
.is() )
1069 xPSI
= xModelProps
->getPropertySetInfo();
1071 if ( xPSI
.is() && xPSI
->hasPropertyByName( getTabIndexPropertyName() ) )
1072 xModelProps
->addPropertyChangeListener( getTabIndexPropertyName(), this );
1076 void ControlModelContainerBase::stopControlListening( const Reference
< XControlModel
>& _rxChildModel
)
1078 SolarMutexGuard aGuard
;
1080 Reference
< XPropertySet
> xModelProps( _rxChildModel
, UNO_QUERY
);
1081 Reference
< XPropertySetInfo
> xPSI
;
1082 if ( xModelProps
.is() )
1083 xPSI
= xModelProps
->getPropertySetInfo();
1085 if ( xPSI
.is() && xPSI
->hasPropertyByName( getTabIndexPropertyName() ) )
1086 xModelProps
->removePropertyChangeListener( getTabIndexPropertyName(), this );
1090 // = class ResourceListener
1093 ResourceListener::ResourceListener(
1094 const Reference
< util::XModifyListener
>& rListener
) :
1096 m_xListener( rListener
),
1097 m_bListening( false )
1101 ResourceListener::~ResourceListener()
1106 Any SAL_CALL
ResourceListener::queryInterface( const Type
& rType
)
1108 Any a
= ::cppu::queryInterface(
1110 static_cast< XModifyListener
* >( this ),
1111 static_cast< XEventListener
* >( this ));
1116 return OWeakObject::queryInterface( rType
);
1119 void SAL_CALL
ResourceListener::acquire() throw ()
1121 OWeakObject::acquire();
1124 void SAL_CALL
ResourceListener::release() throw ()
1126 OWeakObject::release();
1129 void ResourceListener::startListening(
1130 const Reference
< resource::XStringResourceResolver
>& rResource
)
1132 Reference
< util::XModifyBroadcaster
> xModifyBroadcaster( rResource
, UNO_QUERY
);
1136 ::osl::ResettableGuard
< ::osl::Mutex
> aGuard( m_aMutex
);
1137 bool bListening( m_bListening
);
1138 bool bResourceSet( m_xResource
.is() );
1142 if ( bListening
&& bResourceSet
)
1147 m_xResource
= rResource
;
1152 Reference
< util::XModifyListener
> xThis( static_cast<OWeakObject
*>( this ), UNO_QUERY
);
1153 if ( xModifyBroadcaster
.is() )
1157 xModifyBroadcaster
->addModifyListener( xThis
);
1160 ::osl::ResettableGuard
< ::osl::Mutex
> aGuard( m_aMutex
);
1161 m_bListening
= true;
1164 catch (const RuntimeException
&)
1168 catch (const Exception
&)
1174 void ResourceListener::stopListening()
1176 Reference
< util::XModifyBroadcaster
> xModifyBroadcaster
;
1179 ::osl::ResettableGuard
< ::osl::Mutex
> aGuard( m_aMutex
);
1180 if ( m_bListening
&& m_xResource
.is() )
1181 xModifyBroadcaster
.set( m_xResource
, UNO_QUERY
);
1185 Reference
< util::XModifyListener
> xThis( static_cast< OWeakObject
* >( this ), UNO_QUERY
);
1186 if ( xModifyBroadcaster
.is() )
1192 m_bListening
= false;
1193 m_xResource
.clear();
1197 xModifyBroadcaster
->removeModifyListener( xThis
);
1199 catch (const RuntimeException
&)
1203 catch (const Exception
&)
1210 void SAL_CALL
ResourceListener::modified(
1211 const lang::EventObject
& aEvent
)
1213 Reference
< util::XModifyListener
> xListener
;
1216 ::osl::ResettableGuard
< ::osl::Mutex
> aGuard( m_aMutex
);
1217 xListener
= m_xListener
;
1221 if ( xListener
.is() )
1225 xListener
->modified( aEvent
);
1227 catch (const RuntimeException
&)
1231 catch (const Exception
&)
1238 void SAL_CALL
ResourceListener::disposing(
1239 const EventObject
& Source
)
1241 Reference
< lang::XEventListener
> xListener
;
1242 Reference
< resource::XStringResourceResolver
> xResource
;
1245 ::osl::ResettableGuard
< ::osl::Mutex
> aGuard( m_aMutex
);
1246 Reference
< XInterface
> xIfacRes( m_xResource
, UNO_QUERY
);
1247 Reference
< XInterface
> xIfacList( m_xListener
, UNO_QUERY
);
1251 if ( Source
.Source
== xIfacRes
)
1255 m_bListening
= false;
1256 xResource
= m_xResource
;
1257 xListener
.set( m_xListener
, UNO_QUERY
);
1258 m_xResource
.clear();
1262 if ( xListener
.is() )
1266 xListener
->disposing( Source
);
1268 catch (const RuntimeException
&)
1272 catch (const Exception
&)
1277 else if ( Source
.Source
== xIfacList
)
1281 m_bListening
= false;
1282 xListener
.set( m_xListener
, UNO_QUERY
);
1283 xResource
= m_xResource
;
1284 m_xResource
.clear();
1285 m_xListener
.clear();
1289 // Remove ourself as listener from resource resolver
1290 Reference
< util::XModifyBroadcaster
> xModifyBroadcaster( xResource
, UNO_QUERY
);
1291 Reference
< util::XModifyListener
> xThis( static_cast< OWeakObject
* >( this ), UNO_QUERY
);
1292 if ( xModifyBroadcaster
.is() )
1296 xModifyBroadcaster
->removeModifyListener( xThis
);
1298 catch (const RuntimeException
&)
1302 catch (const Exception
&)
1310 // class DialogContainerControl
1312 ControlContainerBase::ControlContainerBase( const Reference
< XComponentContext
>& rxContext
)
1313 :ContainerControl_IBase()
1314 ,m_xContext(rxContext
)
1315 ,mbSizeModified(false)
1316 ,mbPosModified(false)
1318 maComponentInfos
.nWidth
= 280;
1319 maComponentInfos
.nHeight
= 400;
1320 mxListener
= new ResourceListener( Reference
< util::XModifyListener
>(
1321 static_cast< OWeakObject
* >( this ), UNO_QUERY
));
1324 ControlContainerBase::~ControlContainerBase()
1328 void ControlContainerBase::createPeer( const Reference
< XToolkit
> & rxToolkit
, const Reference
< XWindowPeer
> & rParentPeer
)
1330 SolarMutexGuard aGuard
;
1331 UnoControlContainer::createPeer( rxToolkit
, rParentPeer
);
1334 void ControlContainerBase::ImplInsertControl( Reference
< XControlModel
>& rxModel
, const OUString
& rName
)
1336 Reference
< XPropertySet
> xP( rxModel
, UNO_QUERY
);
1339 xP
->getPropertyValue( GetPropertyName( BASEPROPERTY_DEFAULTCONTROL
) ) >>= aDefCtrl
;
1340 Reference
< XControl
> xCtrl( m_xContext
->getServiceManager()->createInstanceWithContext(aDefCtrl
, m_xContext
), UNO_QUERY
);
1342 DBG_ASSERT( xCtrl
.is(), "ControlContainerBase::ImplInsertControl: could not create the control!" );
1345 xCtrl
->setModel( rxModel
);
1346 addControl( rName
, xCtrl
);
1347 // will implicitly call addingControl, where we can add the PropertiesChangeListener to the model
1348 // (which we formerly did herein)
1349 // 08.01.2001 - 96008 - fs@openoffice.org
1351 ImplSetPosSize( xCtrl
);
1355 void ControlContainerBase::ImplRemoveControl( Reference
< XControlModel
>& rxModel
)
1357 Sequence
< Reference
< XControl
> > aControls
= getControls();
1358 Reference
< XControl
> xCtrl
= StdTabController::FindControl( aControls
, rxModel
);
1361 removeControl( xCtrl
);
1366 catch (const Exception
&)
1368 DBG_UNHANDLED_EXCEPTION();
1373 void ControlContainerBase::ImplSetPosSize( Reference
< XControl
>& rxCtrl
)
1375 Reference
< XPropertySet
> xP( rxCtrl
->getModel(), UNO_QUERY
);
1377 sal_Int32 nX
= 0, nY
= 0, nWidth
= 0, nHeight
= 0;
1378 xP
->getPropertyValue("PositionX") >>= nX
;
1379 xP
->getPropertyValue("PositionY") >>= nY
;
1380 xP
->getPropertyValue("Width") >>= nWidth
;
1381 xP
->getPropertyValue("Height") >>= nHeight
;
1382 MapMode
aMode( MapUnit::MapAppFont
);
1383 OutputDevice
*pOutDev
= Application::GetDefaultDevice();
1386 ::Size
aTmp( nX
, nY
);
1387 aTmp
= pOutDev
->LogicToPixel( aTmp
, aMode
);
1390 aTmp
= ::Size( nWidth
, nHeight
);
1391 aTmp
= pOutDev
->LogicToPixel( aTmp
, aMode
);
1392 nWidth
= aTmp
.Width();
1393 nHeight
= aTmp
.Height();
1397 Reference
< XWindowPeer
> xPeer
= ImplGetCompatiblePeer();
1398 Reference
< XDevice
> xD( xPeer
, UNO_QUERY
);
1400 SimpleFontMetric aFM
;
1402 Any aVal
= ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_FONTDESCRIPTOR
) );
1404 if ( !aFD
.StyleName
.isEmpty() )
1406 Reference
< XFont
> xFont
= xD
->getFont( aFD
);
1407 aFM
= xFont
->getFontMetric();
1411 Reference
< XGraphics
> xG
= xD
->createGraphics();
1412 aFM
= xG
->getFontMetric();
1415 sal_Int16 nH
= aFM
.Ascent
+ aFM
.Descent
;
1416 sal_Int16 nW
= nH
/2; // calculate average width?!
1427 Reference
< XWindow
> xW( rxCtrl
, UNO_QUERY
);
1428 xW
->setPosSize( nX
, nY
, nWidth
, nHeight
, PosSize::POSSIZE
);
1431 void ControlContainerBase::dispose()
1434 aEvt
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
1435 // Notify our listener helper about dispose
1438 SolarMutexClearableGuard aGuard
;
1439 Reference
< XEventListener
> xListener( mxListener
, UNO_QUERY
);
1444 if ( xListener
.is() )
1445 xListener
->disposing( aEvt
);
1446 UnoControlContainer::dispose();
1449 void SAL_CALL
ControlContainerBase::disposing(
1450 const EventObject
& Source
)
1452 UnoControlContainer::disposing( Source
);
1455 sal_Bool
ControlContainerBase::setModel( const Reference
< XControlModel
>& rxModel
)
1457 SolarMutexGuard aGuard
;
1459 // destroy the old tab controller, if existent
1460 if ( mxTabController
.is() )
1462 mxTabController
->setModel( nullptr ); // just to be sure, should not be necessary
1463 removeTabController( mxTabController
);
1464 ::comphelper::disposeComponent( mxTabController
); // just to be sure, should not be necessary
1465 mxTabController
.clear();
1468 if ( getModel().is() )
1470 Sequence
< Reference
< XControl
> > aControls
= getControls();
1471 const Reference
< XControl
>* pCtrls
= aControls
.getConstArray();
1472 const Reference
< XControl
>* pCtrlsEnd
= pCtrls
+ aControls
.getLength();
1474 for ( ; pCtrls
< pCtrlsEnd
; ++pCtrls
)
1475 removeControl( *pCtrls
);
1476 // will implicitly call removingControl, which will remove the PropertyChangeListener
1477 // (which we formerly did herein)
1478 // 08.01.2001 - 96008 - fs@openoffice.org
1480 Reference
< XContainer
> xC( getModel(), UNO_QUERY
);
1482 xC
->removeContainerListener( this );
1484 Reference
< XChangesNotifier
> xChangeNotifier( getModel(), UNO_QUERY
);
1485 if ( xChangeNotifier
.is() )
1486 xChangeNotifier
->removeChangesListener( this );
1489 bool bRet
= UnoControl::setModel( rxModel
);
1491 if ( getModel().is() )
1493 Reference
< XNameAccess
> xNA( getModel(), UNO_QUERY
);
1496 Sequence
< OUString
> aNames
= xNA
->getElementNames();
1497 const OUString
* pNames
= aNames
.getConstArray();
1498 sal_uInt32 nCtrls
= aNames
.getLength();
1500 Reference
< XControlModel
> xCtrlModel
;
1501 for( sal_uInt32 n
= 0; n
< nCtrls
; ++n
, ++pNames
)
1503 xNA
->getByName( *pNames
) >>= xCtrlModel
;
1504 ImplInsertControl( xCtrlModel
, *pNames
);
1508 Reference
< XContainer
> xC( getModel(), UNO_QUERY
);
1510 xC
->addContainerListener( this );
1512 Reference
< XChangesNotifier
> xChangeNotifier( getModel(), UNO_QUERY
);
1513 if ( xChangeNotifier
.is() )
1514 xChangeNotifier
->addChangesListener( this );
1517 Reference
< XTabControllerModel
> xTabbing( getModel(), UNO_QUERY
);
1518 if ( xTabbing
.is() )
1520 mxTabController
= new StdTabController
;
1521 mxTabController
->setModel( xTabbing
);
1522 addTabController( mxTabController
);
1524 ImplStartListingForResourceEvents();
1528 void ControlContainerBase::setDesignMode( sal_Bool bOn
)
1530 SolarMutexGuard aGuard
;
1532 UnoControl::setDesignMode( bOn
);
1534 Sequence
< Reference
< XControl
> > xCtrls
= getControls();
1535 sal_Int32 nControls
= xCtrls
.getLength();
1536 Reference
< XControl
>* pControls
= xCtrls
.getArray();
1537 for ( sal_Int32 n
= 0; n
< nControls
; n
++ )
1538 pControls
[n
]->setDesignMode( bOn
);
1540 // #109067# in design mode the tab controller is not notified about
1541 // tab index changes, therefore the tab order must be activated
1542 // when switching from design mode to live mode
1543 if ( mxTabController
.is() && !bOn
)
1544 mxTabController
->activateTabOrder();
1547 void ControlContainerBase::elementInserted( const ContainerEvent
& Event
)
1549 SolarMutexGuard aGuard
;
1551 Reference
< XControlModel
> xModel
;
1554 Event
.Accessor
>>= aName
;
1555 Event
.Element
>>= xModel
;
1556 ENSURE_OR_RETURN_VOID( xModel
.is(), "ControlContainerBase::elementInserted: illegal element!" );
1559 ImplInsertControl( xModel
, aName
);
1561 catch (const RuntimeException
&)
1565 catch (const Exception
&)
1567 DBG_UNHANDLED_EXCEPTION();
1571 void ControlContainerBase::elementRemoved( const ContainerEvent
& Event
)
1573 SolarMutexGuard aGuard
;
1575 Reference
< XControlModel
> xModel
;
1576 Event
.Element
>>= xModel
;
1577 ENSURE_OR_RETURN_VOID( xModel
.is(), "ControlContainerBase::elementRemoved: illegal element!" );
1580 ImplRemoveControl( xModel
);
1582 catch (const RuntimeException
&)
1586 catch (const Exception
&)
1588 DBG_UNHANDLED_EXCEPTION();
1592 void ControlContainerBase::elementReplaced( const ContainerEvent
& Event
)
1594 SolarMutexGuard aGuard
;
1596 Reference
< XControlModel
> xModel
;
1597 Event
.ReplacedElement
>>= xModel
;
1600 OSL_ENSURE( xModel
.is(), "ControlContainerBase::elementReplaced: invalid ReplacedElement!" );
1602 ImplRemoveControl( xModel
);
1604 catch (const RuntimeException
&)
1608 catch (const Exception
&)
1610 DBG_UNHANDLED_EXCEPTION();
1614 Event
.Accessor
>>= aName
;
1615 Event
.Element
>>= xModel
;
1616 ENSURE_OR_RETURN_VOID( xModel
.is(), "ControlContainerBase::elementReplaced: invalid new element!" );
1619 ImplInsertControl( xModel
, aName
);
1621 catch (const RuntimeException
&)
1625 catch (const Exception
&)
1627 DBG_UNHANDLED_EXCEPTION();
1631 // XPropertiesChangeListener
1632 void ControlContainerBase::ImplModelPropertiesChanged( const Sequence
< PropertyChangeEvent
>& rEvents
)
1634 if( !isDesignMode() && !mbCreatingCompatiblePeer
)
1636 OUString
s1( "PositionX" );
1637 OUString
s2( "PositionY" );
1638 OUString
s3( "Width" );
1639 OUString
s4( "Height" );
1641 sal_Int32 nLen
= rEvents
.getLength();
1642 for( sal_Int32 i
= 0; i
< nLen
; i
++ )
1644 const PropertyChangeEvent
& rEvt
= rEvents
.getConstArray()[i
];
1645 Reference
< XControlModel
> xModel( rEvt
.Source
, UNO_QUERY
);
1646 bool bOwnModel
= xModel
.get() == getModel().get();
1647 if ( ( rEvt
.PropertyName
== s1
) ||
1648 ( rEvt
.PropertyName
== s2
) ||
1649 ( rEvt
.PropertyName
== s3
) ||
1650 ( rEvt
.PropertyName
== s4
) )
1654 if ( !mbPosModified
&& !mbSizeModified
)
1656 // Don't set new pos/size if we get new values from window listener
1657 Reference
< XControl
> xThis( static_cast<XAggregation
*>(static_cast<cppu::OWeakAggObject
*>(this)), UNO_QUERY
);
1658 ImplSetPosSize( xThis
);
1663 Sequence
<Reference
<XControl
> > aControlSequence(getControls());
1664 Reference
<XControl
> aControlRef( StdTabController::FindControl( aControlSequence
, xModel
) );
1665 ImplSetPosSize( aControlRef
);
1672 UnoControlContainer::ImplModelPropertiesChanged( rEvents
);
1675 void ControlContainerBase::addingControl( const Reference
< XControl
>& _rxControl
)
1677 SolarMutexGuard aGuard
;
1678 UnoControlContainer::addingControl( _rxControl
);
1680 if ( _rxControl
.is() )
1682 Reference
< XMultiPropertySet
> xProps( _rxControl
->getModel(), UNO_QUERY
);
1685 Sequence
< OUString
> aNames( 4 );
1686 OUString
* pNames
= aNames
.getArray();
1687 *pNames
++ = "PositionX";
1688 *pNames
++ = "PositionY";
1689 *pNames
++ = "Width";
1690 *pNames
++ = "Height";
1692 xProps
->addPropertiesChangeListener( aNames
, this );
1697 void ControlContainerBase::removingControl( const Reference
< XControl
>& _rxControl
)
1699 SolarMutexGuard aGuard
;
1700 UnoControlContainer::removingControl( _rxControl
);
1702 if ( _rxControl
.is() )
1704 Reference
< XMultiPropertySet
> xProps( _rxControl
->getModel(), UNO_QUERY
);
1706 xProps
->removePropertiesChangeListener( this );
1711 void SAL_CALL
ControlContainerBase::changesOccurred( const ChangesEvent
& )
1713 SolarMutexGuard aGuard
;
1714 // a tab controller model may have changed
1716 // #109067# in design mode don't notify the tab controller
1717 // about tab index changes
1718 if ( mxTabController
.is() && !mbDesignMode
)
1719 mxTabController
->activateTabOrder();
1721 static void lcl_ApplyResolverToNestedContainees( const Reference
< resource::XStringResourceResolver
>& xStringResourceResolver
, const Reference
< XControlContainer
>& xContainer
)
1723 OUString
aPropName( PROPERTY_RESOURCERESOLVER
);
1725 Any aNewStringResourceResolver
;
1726 aNewStringResourceResolver
<<= xStringResourceResolver
;
1728 Sequence
< OUString
> aPropNames
{ aPropName
};
1730 const Sequence
< Reference
< awt::XControl
> > aSeq
= xContainer
->getControls();
1731 for ( sal_Int32 i
= 0; i
< aSeq
.getLength(); i
++ )
1733 Reference
< XControl
> xControl( aSeq
[i
] );
1734 Reference
< XPropertySet
> xPropertySet
;
1736 if ( xControl
.is() )
1737 xPropertySet
.set( xControl
->getModel(), UNO_QUERY
);
1739 if ( !xPropertySet
.is() )
1744 Reference
< resource::XStringResourceResolver
> xCurrStringResourceResolver
;
1745 Any aOldValue
= xPropertySet
->getPropertyValue( aPropName
);
1746 if ( ( aOldValue
>>= xCurrStringResourceResolver
)
1747 && ( xStringResourceResolver
== xCurrStringResourceResolver
)
1750 Reference
< XMultiPropertySet
> xMultiPropSet( xPropertySet
, UNO_QUERY
);
1751 Reference
< XPropertiesChangeListener
> xListener( xPropertySet
, UNO_QUERY
);
1752 xMultiPropSet
->firePropertiesChangeEvent( aPropNames
, xListener
);
1755 xPropertySet
->setPropertyValue( aPropName
, aNewStringResourceResolver
);
1757 catch (const Exception
&)
1761 uno::Reference
< XControlContainer
> xNestedContainer( xControl
, uno::UNO_QUERY
);
1762 if ( xNestedContainer
.is() )
1763 lcl_ApplyResolverToNestedContainees( xStringResourceResolver
, xNestedContainer
);
1768 void ControlContainerBase::ImplStartListingForResourceEvents()
1770 Reference
< resource::XStringResourceResolver
> xStringResourceResolver
;
1772 ImplGetPropertyValue( PROPERTY_RESOURCERESOLVER
) >>= xStringResourceResolver
;
1774 // Add our helper as listener to retrieve notifications about changes
1775 Reference
< util::XModifyListener
> rListener( mxListener
);
1776 ResourceListener
* pResourceListener
= static_cast< ResourceListener
* >( rListener
.get() );
1778 // resource listener will stop listening if resolver reference is empty
1779 if ( pResourceListener
)
1780 pResourceListener
->startListening( xStringResourceResolver
);
1781 ImplUpdateResourceResolver();
1784 void ControlContainerBase::ImplUpdateResourceResolver()
1786 OUString
aPropName( PROPERTY_RESOURCERESOLVER
);
1787 Reference
< resource::XStringResourceResolver
> xStringResourceResolver
;
1789 ImplGetPropertyValue( aPropName
) >>= xStringResourceResolver
;
1790 if ( !xStringResourceResolver
.is() )
1793 lcl_ApplyResolverToNestedContainees( xStringResourceResolver
, this );
1795 // propagate resource resolver changes to language dependent props of the dialog
1796 Reference
< XPropertySet
> xPropertySet( getModel(), UNO_QUERY
);
1797 if ( xPropertySet
.is() )
1799 Reference
< XMultiPropertySet
> xMultiPropSet( xPropertySet
, UNO_QUERY
);
1800 Reference
< XPropertiesChangeListener
> xListener( xPropertySet
, UNO_QUERY
);
1801 xMultiPropSet
->firePropertiesChangeEvent( lcl_getLanguageDependentProperties(), xListener
);
1805 //// ----------------------------------------------------
1806 //// Helper Method to convert relative url to physical location
1807 //// ----------------------------------------------------
1809 OUString
getPhysicalLocation( const css::uno::Any
& rbase
, const css::uno::Any
& rUrl
)
1812 OUString baseLocation
;
1815 rbase
>>= baseLocation
;
1818 OUString
absoluteURL( url
);
1819 if ( !url
.isEmpty() )
1821 INetURLObject
urlObj(baseLocation
);
1822 urlObj
.removeSegment();
1823 baseLocation
= urlObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1825 const INetURLObject
protocolCheck( url
);
1826 const INetProtocol protocol
= protocolCheck
.GetProtocol();
1827 if ( protocol
== INetProtocol::NotValid
)
1829 OUString testAbsoluteURL
;
1830 if ( ::osl::FileBase::E_None
== ::osl::FileBase::getAbsoluteFileURL( baseLocation
, url
, testAbsoluteURL
) )
1831 absoluteURL
= testAbsoluteURL
;
1839 ControlModelContainerBase::updateUserFormChildren( const Reference
< XNameContainer
>& xAllChildren
, const OUString
& aName
, ChildOperation Operation
, const css::uno::Reference
< css::awt::XControlModel
>& xTarget
)
1841 if ( Operation
< Insert
|| Operation
> Remove
)
1842 throw IllegalArgumentException();
1844 if ( xAllChildren
.is() )
1846 if ( Operation
== Remove
)
1848 Reference
< XControlModel
> xOldModel( xAllChildren
->getByName( aName
), UNO_QUERY
);
1849 xAllChildren
->removeByName( aName
);
1851 Reference
< XNameContainer
> xChildContainer( xOldModel
, UNO_QUERY
);
1852 if ( xChildContainer
.is() )
1854 Reference
< XPropertySet
> xProps( xChildContainer
, UNO_QUERY
);
1855 // container control is being removed from this container, reset the
1856 // global list of containees
1858 xProps
->setPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES
), uno::makeAny( uno::Reference
< XNameContainer
>() ) );
1859 Sequence
< OUString
> aChildNames
= xChildContainer
->getElementNames();
1860 for ( sal_Int32 index
=0; index
< aChildNames
.getLength(); ++index
)
1861 updateUserFormChildren( xAllChildren
, aChildNames
[ index
], Operation
, Reference
< XControlModel
> () );
1864 else if ( Operation
== Insert
)
1866 xAllChildren
->insertByName( aName
, uno::makeAny( xTarget
) );
1867 Reference
< XNameContainer
> xChildContainer( xTarget
, UNO_QUERY
);
1868 if ( xChildContainer
.is() )
1870 // container control is being added from this container, reset the
1871 // global list of containees to point to the correct global list
1872 Reference
< XPropertySet
> xProps( xChildContainer
, UNO_QUERY
);
1874 xProps
->setPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES
), uno::makeAny( xAllChildren
) );
1875 Sequence
< OUString
> aChildNames
= xChildContainer
->getElementNames();
1876 for ( sal_Int32 index
=0; index
< aChildNames
.getLength(); ++index
)
1878 Reference
< XControlModel
> xChildTarget( xChildContainer
->getByName( aChildNames
[ index
] ), UNO_QUERY
);
1879 updateUserFormChildren( xAllChildren
, aChildNames
[ index
], Operation
, xChildTarget
);
1885 throw IllegalArgumentException();
1888 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */