Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / toolkit / source / controls / controlmodelcontainerbase.cxx
blob5f88ae38faae729b211503bf2ad9826e97081dfa
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
56 #include <map>
57 #include <algorithm>
58 #include <functional>
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;
84 namespace
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 >
125 private:
126 const OUString& m_rName;
128 public:
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 >
141 private:
142 ControlModelContainerBase::UnoControlModelHolderList& m_rTargetList;
144 public:
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 >
164 private:
165 Reference< XControlModel > m_xReference;
166 public:
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 )
213 ,m_bEnabled( true )
214 ,m_nTabPageId(0)
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()
230 maModels.clear();
231 mbGroupsUpToDate = false;
234 Any ControlModelContainerBase::ImplGetDefaultValue( sal_uInt16 nPropId ) const
236 Any aAny;
238 switch ( nPropId )
240 case BASEPROPERTY_DEFAULTCONTROL:
241 aAny <<= OUString::createFromAscii( szServiceName_UnoControlDialog );
242 break;
243 default:
244 aAny = UnoControlModel::ImplGetDefaultValue( nPropId );
247 return aAny;
250 ::cppu::IPropertyArrayHelper& ControlModelContainerBase::getInfoHelper()
252 static UnoPropertyArrayHelper* pHelper = nullptr;
253 if ( !pHelper )
255 Sequence<sal_Int32> aIDs = ImplGetPropertyIds();
256 pHelper = new UnoPropertyArrayHelper( aIDs );
258 return *pHelper;
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() );
284 ::std::transform(
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
291 // now dispose
292 ::std::for_each( aChildModels.begin(), aChildModels.end(), DisposeControlModel() );
293 aChildModels.clear();
295 mbGroupsUpToDate = false;
298 // XMultiPropertySet
299 Reference< XPropertySetInfo > ControlModelContainerBase::getPropertySetInfo( )
301 static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
302 return xInfo;
304 void ControlModelContainerBase::Clone_Impl(ControlModelContainerBase& _rClone) const
306 // clone all children
307 ::std::for_each(
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 );
316 Clone_Impl(*pClone);
318 return pClone;
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 );
390 if ( !pNewModel )
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 );
396 if ( xAgg.is() )
398 if ( xSI->supportsService("com.sun.star.awt.UnoControlModel") )
400 // release 3 of the 4 references we have to the object
401 xAgg.clear();
402 xSI.clear();
403 xObject.clear();
405 pNewModel = new OCommonGeometryControlModel( xCloneAccess, aServiceSpecifier );
410 Reference< XInterface > xNewModel = static_cast<cppu::OWeakObject*>(pNewModel);
411 return xNewModel;
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 );
420 return xInstance;
423 Sequence< OUString > ControlModelContainerBase::getAvailableServiceNames()
425 static Sequence< OUString >* pNamesSeq = nullptr;
426 if ( !pNamesSeq )
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";
453 return *pNamesSeq;
456 // XContainer
457 void ControlModelContainerBase::addContainerListener( const Reference< XContainerListener >& l )
459 maContainerListeners.addInterface( l );
462 void ControlModelContainerBase::removeContainerListener( const Reference< XContainerListener >& l )
464 maContainerListeners.removeInterface( l );
467 // XElementAcces
468 Type ControlModelContainerBase::getElementType()
470 Type aType = cppu::UnoType<XControlModel>::get();
471 return aType;
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() );
539 ::std::transform(
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)
546 return aNames;
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;
559 aElement >>= xM;
561 if ( xM.is() )
563 Reference< beans::XPropertySet > xProps( xM, UNO_QUERY );
564 if ( xProps.is() )
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;
645 if ( xPS.is() )
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( )
664 return true;
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 =
688 ::std::find_if(
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;
698 if ( xProps.is() )
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!" );
732 // has it?
733 if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) )
734 { // yes
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
747 // -> merge them
748 Sequence< Reference< XControlModel > > aReturn( aUnindexedModels.size() + aSortedModels.size() );
749 ::std::transform(
750 aSortedModels.begin(), aSortedModels.end(),
751 ::std::copy( aUnindexedModels.begin(), aUnindexedModels.end(), aReturn.getArray() ),
752 [] ( const MapIndexToModel::value_type& entryIndexToModel )
753 { return entryIndexToModel.second; }
756 return aReturn;
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;
779 else
780 m_nTabPageId = -1;
782 ::sal_Int16 SAL_CALL ControlModelContainerBase::getTabPageID()
784 return m_nTabPageId;
786 sal_Bool SAL_CALL ControlModelContainerBase::getEnabled()
788 return m_bEnabled;
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);
798 OUString sTitle;
799 xThis->getPropertyValue(GetPropertyName(BASEPROPERTY_TITLE)) >>= sTitle;
800 return 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()
810 return m_sImageURL;
812 void SAL_CALL ControlModelContainerBase::setImageURL( const OUString& _imageurl )
814 m_sImageURL = _imageurl;
816 OUString SAL_CALL ControlModelContainerBase::getToolTip()
818 return m_sTooltip;
820 void SAL_CALL ControlModelContainerBase::setToolTip( const OUString& _tooltip )
822 m_sTooltip = _tooltip;
826 namespace
828 enum GroupingMachineState
830 eLookingForGroup,
831 eExpandingGroup
835 sal_Int32 lcl_getDialogStep( const Reference< XControlModel >& _rxModel )
837 sal_Int32 nStep = 0;
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!" );
847 return nStep;
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 );
872 _rName.clear();
874 else
876 AllGroups::const_iterator aGroupPos = maGroups.begin() + _nGroup;
877 _rGroup.realloc( aGroupPos->size() );
878 // copy the models
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;
890 OUString sDummyName;
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:
910 // the changes event
911 ChangesEvent aEvent;
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 )
930 // nothing to do
931 return;
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
938 maGroups.clear();
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" );
960 switch ( eState )
962 case eLookingForGroup:
964 if ( !bIsRadioButton )
965 // this is no radio button -> still looking for the beginning of a group
966 continue;
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;
982 break;
984 case eExpandingGroup:
986 if ( !bIsRadioButton )
987 { // no radio button -> the group is done
988 aCurrentGroup = maGroups.end();
989 eState = eLookingForGroup;
990 continue;
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;
1004 continue;
1007 // it's a radio button, but on a different page
1008 // -> we open a new group for it
1011 // open a new group
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;
1023 break;
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
1039 OUString sAccessor;
1040 UnoControlModelHolderList::const_iterator aPos =
1041 ::std::find_if(
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;
1052 // notify
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 ) :
1095 OWeakObject(),
1096 m_xListener( rListener ),
1097 m_bListening( false )
1101 ResourceListener::~ResourceListener()
1105 // XInterface
1106 Any SAL_CALL ResourceListener::queryInterface( const Type& rType )
1108 Any a = ::cppu::queryInterface(
1109 rType ,
1110 static_cast< XModifyListener* >( this ),
1111 static_cast< XEventListener* >( this ));
1113 if ( a.hasValue() )
1114 return a;
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 );
1135 // --- SAFE ---
1136 ::osl::ResettableGuard < ::osl::Mutex > aGuard( m_aMutex );
1137 bool bListening( m_bListening );
1138 bool bResourceSet( m_xResource.is() );
1139 aGuard.clear();
1140 // --- SAFE ---
1142 if ( bListening && bResourceSet )
1143 stopListening();
1145 // --- SAFE ---
1146 aGuard.reset();
1147 m_xResource = rResource;
1148 aGuard.clear();
1149 // --- SAFE ---
1152 Reference< util::XModifyListener > xThis( static_cast<OWeakObject*>( this ), UNO_QUERY );
1153 if ( xModifyBroadcaster.is() )
1157 xModifyBroadcaster->addModifyListener( xThis );
1159 // --- SAFE ---
1160 ::osl::ResettableGuard < ::osl::Mutex > aGuard( m_aMutex );
1161 m_bListening = true;
1162 // --- SAFE ---
1164 catch (const RuntimeException&)
1166 throw;
1168 catch (const Exception&)
1174 void ResourceListener::stopListening()
1176 Reference< util::XModifyBroadcaster > xModifyBroadcaster;
1178 // --- SAFE ---
1179 ::osl::ResettableGuard < ::osl::Mutex > aGuard( m_aMutex );
1180 if ( m_bListening && m_xResource.is() )
1181 xModifyBroadcaster.set( m_xResource, UNO_QUERY );
1182 aGuard.clear();
1183 // --- SAFE ---
1185 Reference< util::XModifyListener > xThis( static_cast< OWeakObject* >( this ), UNO_QUERY );
1186 if ( xModifyBroadcaster.is() )
1190 // --- SAFE ---
1191 aGuard.reset();
1192 m_bListening = false;
1193 m_xResource.clear();
1194 aGuard.clear();
1195 // --- SAFE ---
1197 xModifyBroadcaster->removeModifyListener( xThis );
1199 catch (const RuntimeException&)
1201 throw;
1203 catch (const Exception&)
1209 // XModifyListener
1210 void SAL_CALL ResourceListener::modified(
1211 const lang::EventObject& aEvent )
1213 Reference< util::XModifyListener > xListener;
1215 // --- SAFE ---
1216 ::osl::ResettableGuard < ::osl::Mutex > aGuard( m_aMutex );
1217 xListener = m_xListener;
1218 aGuard.clear();
1219 // --- SAFE ---
1221 if ( xListener.is() )
1225 xListener->modified( aEvent );
1227 catch (const RuntimeException&)
1229 throw;
1231 catch (const Exception&)
1237 // XEventListener
1238 void SAL_CALL ResourceListener::disposing(
1239 const EventObject& Source )
1241 Reference< lang::XEventListener > xListener;
1242 Reference< resource::XStringResourceResolver > xResource;
1244 // --- SAFE ---
1245 ::osl::ResettableGuard < ::osl::Mutex > aGuard( m_aMutex );
1246 Reference< XInterface > xIfacRes( m_xResource, UNO_QUERY );
1247 Reference< XInterface > xIfacList( m_xListener, UNO_QUERY );
1248 aGuard.clear();
1249 // --- SAFE ---
1251 if ( Source.Source == xIfacRes )
1253 // --- SAFE ---
1254 aGuard.reset();
1255 m_bListening = false;
1256 xResource = m_xResource;
1257 xListener.set( m_xListener, UNO_QUERY );
1258 m_xResource.clear();
1259 aGuard.clear();
1260 // --- SAFE ---
1262 if ( xListener.is() )
1266 xListener->disposing( Source );
1268 catch (const RuntimeException&)
1270 throw;
1272 catch (const Exception&)
1277 else if ( Source.Source == xIfacList )
1279 // --- SAFE ---
1280 aGuard.reset();
1281 m_bListening = false;
1282 xListener.set( m_xListener, UNO_QUERY );
1283 xResource = m_xResource;
1284 m_xResource.clear();
1285 m_xListener.clear();
1286 aGuard.clear();
1287 // --- SAFE ---
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&)
1300 throw;
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 );
1338 OUString aDefCtrl;
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!" );
1343 if ( xCtrl.is() )
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 );
1359 if ( xCtrl.is() )
1361 removeControl( xCtrl );
1364 xCtrl->dispose();
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();
1384 if ( pOutDev )
1386 ::Size aTmp( nX, nY );
1387 aTmp = pOutDev->LogicToPixel( aTmp, aMode );
1388 nX = aTmp.Width();
1389 nY = aTmp.Height();
1390 aTmp = ::Size( nWidth, nHeight );
1391 aTmp = pOutDev->LogicToPixel( aTmp, aMode );
1392 nWidth = aTmp.Width();
1393 nHeight = aTmp.Height();
1395 else
1397 Reference< XWindowPeer > xPeer = ImplGetCompatiblePeer();
1398 Reference< XDevice > xD( xPeer, UNO_QUERY );
1400 SimpleFontMetric aFM;
1401 FontDescriptor aFD;
1402 Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_FONTDESCRIPTOR ) );
1403 aVal >>= aFD;
1404 if ( !aFD.StyleName.isEmpty() )
1406 Reference< XFont > xFont = xD->getFont( aFD );
1407 aFM = xFont->getFontMetric();
1409 else
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?!
1418 nX *= nW;
1419 nX /= 4;
1420 nWidth *= nW;
1421 nWidth /= 4;
1422 nY *= nH;
1423 nY /= 8;
1424 nHeight *= nH;
1425 nHeight /= 8;
1427 Reference < XWindow > xW( rxCtrl, UNO_QUERY );
1428 xW->setPosSize( nX, nY, nWidth, nHeight, PosSize::POSSIZE );
1431 void ControlContainerBase::dispose()
1433 EventObject aEvt;
1434 aEvt.Source = static_cast< ::cppu::OWeakObject* >( this );
1435 // Notify our listener helper about dispose
1436 // --- SAFE ---
1438 SolarMutexClearableGuard aGuard;
1439 Reference< XEventListener > xListener( mxListener, UNO_QUERY );
1440 mxListener.clear();
1441 aGuard.clear();
1442 // --- SAFE ---
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 );
1481 if ( xC.is() )
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 );
1494 if ( xNA.is() )
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 );
1509 if ( xC.is() )
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();
1526 return bRet;
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;
1552 OUString aName;
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&)
1563 throw;
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&)
1584 throw;
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!" );
1601 if ( xModel.is() )
1602 ImplRemoveControl( xModel );
1604 catch (const RuntimeException&)
1606 throw;
1608 catch (const Exception&)
1610 DBG_UNHANDLED_EXCEPTION();
1613 OUString aName;
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&)
1623 throw;
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 ) )
1652 if ( bOwnModel )
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 );
1661 else
1663 Sequence<Reference<XControl> > aControlSequence(getControls());
1664 Reference<XControl> aControlRef( StdTabController::FindControl( aControlSequence, xModel ) );
1665 ImplSetPosSize( aControlRef );
1667 break;
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 );
1683 if ( xProps.is() )
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 );
1705 if ( xProps.is() )
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() )
1740 continue;
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 );
1754 else
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() )
1791 return;
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;
1813 OUString url;
1815 rbase >>= baseLocation;
1816 rUrl >>= url;
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;
1835 return absoluteURL;
1838 void
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
1857 if ( xProps.is() )
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 );
1873 if ( xProps.is() )
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 );
1884 else
1885 throw IllegalArgumentException();
1888 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */