Branch libreoffice-5-0-4
[LibreOffice.git] / toolkit / source / controls / controlmodelcontainerbase.cxx
blob7e70d43324c661c8b88b5dcd819cf5e25643b254
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 <boost/bind.hpp>
58 #include <map>
59 #include <algorithm>
60 #include <functional>
61 #include "tools/urlobj.hxx"
62 #include "osl/file.hxx"
63 #include "toolkit/controls/dialogcontrol.hxx"
65 #include "helper/tkresmgr.hxx"
66 #include "helper/unopropertyarrayhelper.hxx"
67 #include "controlmodelcontainerbase_internal.hxx"
69 using namespace ::com::sun::star;
70 using namespace ::com::sun::star::uno;
71 using namespace ::com::sun::star::awt;
72 using namespace ::com::sun::star::lang;
73 using namespace ::com::sun::star::container;
74 using namespace ::com::sun::star::beans;
75 using namespace ::com::sun::star::util;
76 using namespace toolkit;
78 #define PROPERTY_RESOURCERESOLVER OUString( "ResourceResolver" )
80 struct LanguageDependentProp
82 const char* pPropName;
83 sal_Int32 nPropNameLength;
87 namespace
89 static const Sequence< OUString >& lcl_getLanguageDependentProperties()
91 static Sequence< OUString > s_aLanguageDependentProperties;
92 if ( s_aLanguageDependentProperties.getLength() == 0 )
94 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
95 if ( s_aLanguageDependentProperties.getLength() == 0 )
97 s_aLanguageDependentProperties.realloc( 2 );
98 s_aLanguageDependentProperties[0] = "HelpText";
99 s_aLanguageDependentProperties[1] = "Title";
100 // note: properties must be sorted
103 return s_aLanguageDependentProperties;
108 // functor for disposing a control model
109 struct DisposeControlModel : public ::std::unary_function< Reference< XControlModel >, void >
111 void operator()( Reference< XControlModel >& _rxModel )
115 ::comphelper::disposeComponent( _rxModel );
117 catch (const Exception&)
119 OSL_TRACE( "DisposeControlModel::(): caught an exception while disposing a component!" );
125 // functor for searching control model by name
126 struct FindControlModel : public ::std::unary_function< ControlModelContainerBase::UnoControlModelHolder, bool >
128 private:
129 const OUString& m_rName;
131 public:
132 FindControlModel( const OUString& _rName ) : m_rName( _rName ) { }
134 bool operator()( const ControlModelContainerBase::UnoControlModelHolder& _rCompare )
136 return _rCompare.second == m_rName;
141 // functor for cloning a control model, and insertion into a target list
142 struct CloneControlModel : public ::std::unary_function< ControlModelContainerBase::UnoControlModelHolder, void >
144 private:
145 ControlModelContainerBase::UnoControlModelHolderList& m_rTargetList;
147 public:
148 CloneControlModel( ControlModelContainerBase::UnoControlModelHolderList& _rTargetList )
149 :m_rTargetList( _rTargetList )
153 void operator()( const ControlModelContainerBase::UnoControlModelHolder& _rSource )
155 // clone the source object
156 Reference< XCloneable > xCloneSource( _rSource.first, UNO_QUERY );
157 Reference< XControlModel > xClone( xCloneSource->createClone(), UNO_QUERY );
158 // add to target list
159 m_rTargetList.push_back( ControlModelContainerBase::UnoControlModelHolder( xClone, _rSource.second ) );
164 // functor for comparing a XControlModel with a given reference
165 struct CompareControlModel : public ::std::unary_function< ControlModelContainerBase::UnoControlModelHolder, bool >
167 private:
168 Reference< XControlModel > m_xReference;
169 public:
170 CompareControlModel( const Reference< XControlModel >& _rxReference ) : m_xReference( _rxReference ) { }
172 bool operator()( const ControlModelContainerBase::UnoControlModelHolder& _rCompare )
174 return _rCompare.first.get() == m_xReference.get();
179 static void lcl_throwIllegalArgumentException( )
180 { // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this ....
181 throw IllegalArgumentException();
185 static void lcl_throwNoSuchElementException( )
186 { // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this ....
187 throw NoSuchElementException();
191 static void lcl_throwElementExistException( )
192 { // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this ....
193 throw ElementExistException();
197 static OUString getTabIndexPropertyName( )
199 return OUString( "TabIndex" );
203 static OUString getStepPropertyName( )
205 return OUString( "Step" );
209 // class ControlModelContainerBase
211 ControlModelContainerBase::ControlModelContainerBase( const Reference< XComponentContext >& rxContext )
212 :ControlModelContainer_IBase( rxContext )
213 ,maContainerListeners( *this )
214 ,maChangeListeners ( GetMutex() )
215 ,mbGroupsUpToDate( false )
216 ,m_bEnabled( true )
217 ,m_nTabPageId(0)
221 ControlModelContainerBase::ControlModelContainerBase( const ControlModelContainerBase& rModel )
222 : ControlModelContainer_IBase( rModel )
223 , maContainerListeners( *this )
224 , maChangeListeners ( GetMutex() )
225 , mbGroupsUpToDate( false )
226 , m_bEnabled( rModel.m_bEnabled )
227 , m_nTabPageId( rModel.m_nTabPageId )
231 ControlModelContainerBase::~ControlModelContainerBase()
233 maModels.clear();
234 mbGroupsUpToDate = false;
237 Any ControlModelContainerBase::ImplGetDefaultValue( sal_uInt16 nPropId ) const
239 Any aAny;
241 switch ( nPropId )
243 case BASEPROPERTY_DEFAULTCONTROL:
244 aAny <<= OUString::createFromAscii( szServiceName_UnoControlDialog );
245 break;
246 default:
247 aAny = UnoControlModel::ImplGetDefaultValue( nPropId );
250 return aAny;
253 ::cppu::IPropertyArrayHelper& ControlModelContainerBase::getInfoHelper()
255 static UnoPropertyArrayHelper* pHelper = NULL;
256 if ( !pHelper )
258 Sequence<sal_Int32> aIDs = ImplGetPropertyIds();
259 pHelper = new UnoPropertyArrayHelper( aIDs );
261 return *pHelper;
264 void SAL_CALL ControlModelContainerBase::dispose( ) throw(RuntimeException, std::exception)
267 // tell our listeners
269 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
271 EventObject aDisposeEvent;
272 aDisposeEvent.Source = static_cast< XAggregation* >( static_cast< ::cppu::OWeakAggObject* >( this ) );
274 maContainerListeners.disposeAndClear( aDisposeEvent );
275 maChangeListeners.disposeAndClear( aDisposeEvent );
279 // call the base class
280 UnoControlModel::dispose();
283 // dispose our child models
284 // for this, collect the models (we collect them from maModels, and this is modified when disposing children)
285 ::std::vector< Reference< XControlModel > > aChildModels( maModels.size() );
287 ::std::transform(
288 maModels.begin(), maModels.end(), // source range
289 aChildModels.begin(), // target location
290 ::boost::bind( &UnoControlModelHolder::first, _1 ) // operation to apply -> select the XControlModel part
293 // now dispose
294 ::std::for_each( aChildModels.begin(), aChildModels.end(), DisposeControlModel() );
295 aChildModels.clear();
297 mbGroupsUpToDate = false;
300 // XMultiPropertySet
301 Reference< XPropertySetInfo > ControlModelContainerBase::getPropertySetInfo( ) throw(RuntimeException, std::exception)
303 static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
304 return xInfo;
306 void ControlModelContainerBase::Clone_Impl(ControlModelContainerBase& _rClone) const
308 // clone all children
309 ::std::for_each(
310 maModels.begin(), maModels.end(),
311 CloneControlModel( _rClone.maModels )
314 UnoControlModel* ControlModelContainerBase::Clone() const
316 // clone the container itself
317 ControlModelContainerBase* pClone = new ControlModelContainerBase( *this );
318 Clone_Impl(*pClone);
320 return pClone;
323 ControlModelContainerBase::UnoControlModelHolderList::iterator ControlModelContainerBase::ImplFindElement( const OUString& rName )
325 return ::std::find_if( maModels.begin(), maModels.end(), FindControlModel( rName ) );
328 // ::XMultiServiceFactory
329 Reference< XInterface > ControlModelContainerBase::createInstance( const OUString& aServiceSpecifier ) throw(Exception, RuntimeException, std::exception)
331 SolarMutexGuard aGuard;
333 OGeometryControlModel_Base* pNewModel = NULL;
335 if ( aServiceSpecifier == "com.sun.star.awt.UnoControlEditModel" )
336 pNewModel = new OGeometryControlModel< UnoControlEditModel >( m_xContext );
337 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFormattedFieldModel" )
338 pNewModel = new OGeometryControlModel< UnoControlFormattedFieldModel >( m_xContext);
339 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFileControlModel" )
340 pNewModel = new OGeometryControlModel< UnoControlFileControlModel >( m_xContext );
341 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlButtonModel" )
342 pNewModel = new OGeometryControlModel< UnoControlButtonModel >( m_xContext );
343 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlImageControlModel" )
344 pNewModel = new OGeometryControlModel< UnoControlImageControlModel >( m_xContext );
345 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlRadioButtonModel" )
346 pNewModel = new OGeometryControlModel< UnoControlRadioButtonModel >( m_xContext );
347 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlCheckBoxModel" )
348 pNewModel = new OGeometryControlModel< UnoControlCheckBoxModel >( m_xContext );
349 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFixedHyperlinkModel" )
350 pNewModel = new OGeometryControlModel< UnoControlFixedHyperlinkModel >( m_xContext );
351 else if ( aServiceSpecifier == "stardiv.vcl.controlmodel.FixedText" )
352 pNewModel = new OGeometryControlModel< UnoControlFixedTextModel >( m_xContext );
353 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlGroupBoxModel" )
354 pNewModel = new OGeometryControlModel< UnoControlGroupBoxModel >( m_xContext );
355 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlListBoxModel" )
356 pNewModel = new OGeometryControlModel< UnoControlListBoxModel >( m_xContext );
357 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlComboBoxModel" )
358 pNewModel = new OGeometryControlModel< UnoControlComboBoxModel >( m_xContext );
359 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlDateFieldModel" )
360 pNewModel = new OGeometryControlModel< UnoControlDateFieldModel >( m_xContext );
361 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlTimeFieldModel" )
362 pNewModel = new OGeometryControlModel< UnoControlTimeFieldModel >( m_xContext );
363 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlNumericFieldModel" )
364 pNewModel = new OGeometryControlModel< UnoControlNumericFieldModel >( m_xContext );
365 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlCurrencyFieldModel" )
366 pNewModel = new OGeometryControlModel< UnoControlCurrencyFieldModel >( m_xContext );
367 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlPatternFieldModel" )
368 pNewModel = new OGeometryControlModel< UnoControlPatternFieldModel >( m_xContext );
369 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlProgressBarModel" )
370 pNewModel = new OGeometryControlModel< UnoControlProgressBarModel >( m_xContext );
371 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlScrollBarModel" )
372 pNewModel = new OGeometryControlModel< UnoControlScrollBarModel >( m_xContext );
373 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFixedLineModel" )
374 pNewModel = new OGeometryControlModel< UnoControlFixedLineModel >( m_xContext );
375 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlRoadmapModel" )
376 pNewModel = new OGeometryControlModel< UnoControlRoadmapModel >( m_xContext );
377 else if ( aServiceSpecifier == "com.sun.star.awt.tree.TreeControlModel" )
378 pNewModel = new OGeometryControlModel< UnoTreeModel >( m_xContext );
379 else if ( aServiceSpecifier == "com.sun.star.awt.grid.UnoControlGridModel" )
380 pNewModel = new OGeometryControlModel< UnoGridModel >( m_xContext );
381 else if ( aServiceSpecifier == "com.sun.star.awt.tab.UnoControlTabPageContainerModel" )
382 pNewModel = new OGeometryControlModel< UnoControlTabPageContainerModel >( m_xContext );
383 else if ( aServiceSpecifier == "com.sun.star.awt.UnoMultiPageModel" )
384 pNewModel = new OGeometryControlModel< UnoMultiPageModel >( m_xContext );
385 else if ( aServiceSpecifier == "com.sun.star.awt.tab.UnoControlTabPageModel" )
386 pNewModel = new OGeometryControlModel< UnoControlTabPageModel >( m_xContext );
387 else if ( aServiceSpecifier == "com.sun.star.awt.UnoPageModel" )
388 pNewModel = new OGeometryControlModel< UnoPageModel >( m_xContext );
389 else if ( aServiceSpecifier == "com.sun.star.awt.UnoFrameModel" )
390 pNewModel = new OGeometryControlModel< UnoFrameModel >( m_xContext );
392 if ( !pNewModel )
394 Reference< XInterface > xObject = m_xContext->getServiceManager()->createInstanceWithContext(aServiceSpecifier, m_xContext);
395 Reference< XServiceInfo > xSI( xObject, UNO_QUERY );
396 Reference< XCloneable > xCloneAccess( xSI, UNO_QUERY );
397 Reference< XAggregation > xAgg( xCloneAccess, UNO_QUERY );
398 if ( xAgg.is() )
400 if ( xSI->supportsService("com.sun.star.awt.UnoControlModel") )
402 // release 3 of the 4 references we have to the object
403 xAgg.clear();
404 xSI.clear();
405 xObject.clear();
407 pNewModel = new OCommonGeometryControlModel( xCloneAccess, aServiceSpecifier );
412 Reference< XInterface > xNewModel = (::cppu::OWeakObject*)pNewModel;
413 return xNewModel;
416 Reference< XInterface > ControlModelContainerBase::createInstanceWithArguments( const OUString& ServiceSpecifier, const Sequence< Any >& i_arguments ) throw(Exception, RuntimeException, std::exception)
418 const Reference< XInterface > xInstance( createInstance( ServiceSpecifier ) );
419 const Reference< XInitialization > xInstanceInit( xInstance, UNO_QUERY );
420 ENSURE_OR_RETURN( xInstanceInit.is(), "ControlModelContainerBase::createInstanceWithArguments: can't pass the arguments!", xInstance );
421 xInstanceInit->initialize( i_arguments );
422 return xInstance;
425 Sequence< OUString > ControlModelContainerBase::getAvailableServiceNames() throw(RuntimeException, std::exception)
427 static Sequence< OUString >* pNamesSeq = NULL;
428 if ( !pNamesSeq )
430 pNamesSeq = new Sequence< OUString >( 26 );
431 OUString* pNames = pNamesSeq->getArray();
432 pNames[0] = "com.sun.star.awt.UnoControlEditModel";
433 pNames[1] = "com.sun.star.awt.UnoControlFormattedFieldModel";
434 pNames[2] = "com.sun.star.awt.UnoControlFileControlModel";
435 pNames[3] = "com.sun.star.awt.UnoControlButtonModel";
436 pNames[4] = "com.sun.star.awt.UnoControlImageControlModel";
437 pNames[5] = "com.sun.star.awt.UnoControlRadioButtonModel";
438 pNames[6] = "com.sun.star.awt.UnoControlCheckBoxModel";
439 pNames[7] = "com.sun.star.awt.UnoControlFixedTextModel";
440 pNames[8] = "com.sun.star.awt.UnoControlGroupBoxModel";
441 pNames[9] = "com.sun.star.awt.UnoControlListBoxModel";
442 pNames[10] = "com.sun.star.awt.UnoControlComboBoxModel";
443 pNames[11] = "com.sun.star.awt.UnoControlDateFieldModel";
444 pNames[12] = "com.sun.star.awt.UnoControlTimeFieldModel";
445 pNames[13] = "com.sun.star.awt.UnoControlNumericFieldModel";
446 pNames[14] = "com.sun.star.awt.UnoControlCurrencyFieldModel";
447 pNames[15] = "com.sun.star.awt.UnoControlPatternFieldModel";
448 pNames[16] = "com.sun.star.awt.tree.TreeControlModel";
449 pNames[21] = "com.sun.star.awt.grid.UnoControlGridModel";
450 pNames[22] = "com.sun.star.awt.tab.UnoControlTabPageContainerModel";
451 pNames[23] = "com.sun.star.awt.tab.UnoControlTabPageModel";
452 pNames[24] = "com.sun.star.awt.UnoMultiPageModel";
453 pNames[25] = "com.sun.star.awt.UnoFrameModel";
455 return *pNamesSeq;
458 // XContainer
459 void ControlModelContainerBase::addContainerListener( const Reference< XContainerListener >& l ) throw(RuntimeException, std::exception)
461 maContainerListeners.addInterface( l );
464 void ControlModelContainerBase::removeContainerListener( const Reference< XContainerListener >& l ) throw(RuntimeException, std::exception)
466 maContainerListeners.removeInterface( l );
469 // XElementAcces
470 Type ControlModelContainerBase::getElementType() throw(RuntimeException, std::exception)
472 Type aType = cppu::UnoType<XControlModel>::get();
473 return aType;
476 sal_Bool ControlModelContainerBase::hasElements() throw(RuntimeException, std::exception)
478 return !maModels.empty();
481 // XNameContainer, XNameReplace, XNameAccess
482 void ControlModelContainerBase::replaceByName( const OUString& aName, const Any& aElement ) throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException, std::exception)
484 SolarMutexGuard aGuard;
486 Reference< XControlModel > xNewModel;
487 aElement >>= xNewModel;
488 if ( !xNewModel.is() )
489 lcl_throwIllegalArgumentException();
491 UnoControlModelHolderList::iterator aElementPos = ImplFindElement( aName );
492 if ( maModels.end() == aElementPos )
493 lcl_throwNoSuchElementException();
494 // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
495 // With container controls you could have constructed an existing hierarchy and are now
496 // add this to an existing container, in this case a name nested in the containment
497 // hierarchy of the added control could contain a name clash, if we have access to the
498 // list of global names then recursively check for previously existing names (we need
499 // to do this obviously before the 'this' objects container is updated)
500 Reference< XNameContainer > xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ) ), UNO_QUERY );
501 if ( xAllChildren.is() )
503 // remove old control (and children) from global list of containees
504 updateUserFormChildren( xAllChildren, aName, Remove, uno::Reference< XControlModel >() );
505 // Add new control (and containees if they exist)
506 updateUserFormChildren( xAllChildren, aName, Insert, xNewModel );
508 // stop listening at the old model
509 stopControlListening( aElementPos->first );
510 Reference< XControlModel > xReplaced( aElementPos->first );
511 // remember the new model, and start listening
512 aElementPos->first = xNewModel;
513 startControlListening( xNewModel );
515 ContainerEvent aEvent;
516 aEvent.Source = *this;
517 aEvent.Element = aElement;
518 aEvent.ReplacedElement <<= xReplaced;
519 aEvent.Accessor <<= aName;
521 // notify the container listener
522 maContainerListeners.elementReplaced( aEvent );
524 // our "tab controller model" has potentially changed -> notify this
525 implNotifyTabModelChange( aName );
528 Any ControlModelContainerBase::getByName( const OUString& aName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException, std::exception)
530 UnoControlModelHolderList::iterator aElementPos = ImplFindElement( aName );
531 if ( maModels.end() == aElementPos )
532 lcl_throwNoSuchElementException();
534 return makeAny( aElementPos->first );
537 Sequence< OUString > ControlModelContainerBase::getElementNames() throw(RuntimeException, std::exception)
539 Sequence< OUString > aNames( maModels.size() );
541 ::std::transform(
542 maModels.begin(), maModels.end(), // source range
543 aNames.getArray(), // target range
544 ::boost::bind( &UnoControlModelHolder::second, _1 ) // operator to apply: select the second element (the name)
547 return aNames;
550 sal_Bool ControlModelContainerBase::hasByName( const OUString& aName ) throw(RuntimeException, std::exception)
552 return maModels.end() != ImplFindElement( aName );
555 void ControlModelContainerBase::insertByName( const OUString& aName, const Any& aElement ) throw(IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException, std::exception)
557 SolarMutexGuard aGuard;
559 Reference< XControlModel > xM;
560 aElement >>= xM;
562 if ( xM.is() )
564 Reference< beans::XPropertySet > xProps( xM, UNO_QUERY );
565 if ( xProps.is() )
568 Reference< beans::XPropertySetInfo > xPropInfo = xProps.get()->getPropertySetInfo();
570 OUString sImageSourceProperty = GetPropertyName( BASEPROPERTY_IMAGEURL );
571 if ( xPropInfo.get()->hasPropertyByName( sImageSourceProperty ) && ImplHasProperty(BASEPROPERTY_DIALOGSOURCEURL) )
573 Any aUrl = xProps.get()->getPropertyValue( sImageSourceProperty );
575 OUString absoluteUrl =
576 getPhysicalLocation( getPropertyValue( GetPropertyName( BASEPROPERTY_DIALOGSOURCEURL ) ), aUrl );
578 aUrl <<= absoluteUrl;
580 xProps.get()->setPropertyValue( sImageSourceProperty , aUrl );
587 if ( aName.isEmpty() || !xM.is() )
588 lcl_throwIllegalArgumentException();
590 UnoControlModelHolderList::iterator aElementPos = ImplFindElement( aName );
591 if ( maModels.end() != aElementPos )
592 lcl_throwElementExistException();
594 // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
595 // With container controls you could have constructed an existing hierarchy and are now
596 // add this to an existing container, in this case a name nested in the containment
597 // hierarchy of the added control could contain a name clash, if we have access to the
598 // list of global names then we need to recursively check for previously existing
599 // names (we need to do this obviously before the 'this' objects container is updated)
600 // remove old control (and children) from global list of containees
601 Reference< XNameContainer > xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ) ), UNO_QUERY );
603 if ( xAllChildren.is() )
604 updateUserFormChildren( xAllChildren, aName, Insert, xM );
605 maModels.push_back( UnoControlModelHolder( xM, aName ) );
606 mbGroupsUpToDate = false;
607 startControlListening( xM );
609 ContainerEvent aEvent;
610 aEvent.Source = *this;
611 aEvent.Element <<= aElement;
612 aEvent.Accessor <<= aName;
613 maContainerListeners.elementInserted( aEvent );
615 // our "tab controller model" has potentially changed -> notify this
616 implNotifyTabModelChange( aName );
619 void ControlModelContainerBase::removeByName( const OUString& aName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException, std::exception)
621 SolarMutexGuard aGuard;
623 UnoControlModelHolderList::iterator aElementPos = ImplFindElement( aName );
624 if ( maModels.end() == aElementPos )
625 lcl_throwNoSuchElementException();
627 // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
628 // With container controls you could have constructed an existing hierarchy and are now
629 // removing this control from an existing container, in this case all nested names in
630 // the containment hierarchy of the control to be removed need to be removed from the global
631 // names cache (we need to do this obviously before the 'this' objects container is updated)
632 Reference< XNameContainer > xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ) ), UNO_QUERY );
633 if ( xAllChildren.is() )
634 updateUserFormChildren( xAllChildren, aName, Remove, uno::Reference< XControlModel >() );
636 ContainerEvent aEvent;
637 aEvent.Source = *this;
638 aEvent.Element <<= aElementPos->first;
639 aEvent.Accessor <<= aName;
640 maContainerListeners.elementRemoved( aEvent );
642 stopControlListening( aElementPos->first );
643 Reference< XPropertySet > xPS( aElementPos->first, UNO_QUERY );
644 maModels.erase( aElementPos );
645 mbGroupsUpToDate = false;
647 if ( xPS.is() )
651 xPS->setPropertyValue( PROPERTY_RESOURCERESOLVER, makeAny( Reference< resource::XStringResourceResolver >() ) );
653 catch (const Exception&)
655 DBG_UNHANDLED_EXCEPTION();
659 // our "tab controller model" has potentially changed -> notify this
660 implNotifyTabModelChange( aName );
664 sal_Bool SAL_CALL ControlModelContainerBase::getGroupControl( ) throw (RuntimeException, std::exception)
666 return sal_True;
670 void SAL_CALL ControlModelContainerBase::setGroupControl( sal_Bool ) throw (RuntimeException, std::exception)
672 OSL_TRACE( "ControlModelContainerBase::setGroupControl: explicit grouping not supported" );
676 void SAL_CALL ControlModelContainerBase::setControlModels( const Sequence< Reference< XControlModel > >& _rControls ) throw (RuntimeException, std::exception)
678 SolarMutexGuard aGuard;
680 // set the tab indexes according to the order of models in the sequence
681 const Reference< XControlModel >* pControls = _rControls.getConstArray( );
682 const Reference< XControlModel >* pControlsEnd = _rControls.getConstArray( ) + _rControls.getLength();
684 sal_Int16 nTabIndex = 1;
686 for ( ; pControls != pControlsEnd; ++pControls )
688 // look up the control in our own structure. This is to prevent invalid arguments
689 UnoControlModelHolderList::const_iterator aPos =
690 ::std::find_if(
691 maModels.begin(), maModels.end(),
692 CompareControlModel( *pControls )
694 if ( maModels.end() != aPos )
696 // okay, this is an existent model
697 // now set the TabIndex property (if applicable)
698 Reference< XPropertySet > xProps( aPos->first, UNO_QUERY );
699 Reference< XPropertySetInfo > xPSI;
700 if ( xProps.is() )
701 xPSI = xProps->getPropertySetInfo();
702 if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) )
703 xProps->setPropertyValue( getTabIndexPropertyName(), makeAny( nTabIndex++ ) );
705 mbGroupsUpToDate = false;
710 typedef ::std::multimap< sal_Int32, Reference< XControlModel >, ::std::less< sal_Int32 > > MapIndexToModel;
713 Sequence< Reference< XControlModel > > SAL_CALL ControlModelContainerBase::getControlModels( ) throw (RuntimeException, std::exception)
715 SolarMutexGuard aGuard;
717 MapIndexToModel aSortedModels;
718 // will be the sorted container of all models which have a tab index property
719 ::std::vector< Reference< XControlModel > > aUnindexedModels;
720 // will be the container of all models which do not have a tab index property
722 UnoControlModelHolderList::const_iterator aLoop = maModels.begin();
723 for ( ; aLoop != maModels.end(); ++aLoop )
725 Reference< XControlModel > xModel( aLoop->first );
727 // see if the model has a TabIndex property
728 Reference< XPropertySet > xControlProps( xModel, UNO_QUERY );
729 Reference< XPropertySetInfo > xPSI;
730 if ( xControlProps.is() )
731 xPSI = xControlProps->getPropertySetInfo( );
732 DBG_ASSERT( xPSI.is(), "ControlModelContainerBase::getControlModels: invalid child model!" );
734 // has it?
735 if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) )
736 { // yes
737 sal_Int32 nTabIndex = -1;
738 xControlProps->getPropertyValue( getTabIndexPropertyName() ) >>= nTabIndex;
740 aSortedModels.insert( MapIndexToModel::value_type( nTabIndex, xModel ) );
742 else if ( xModel.is() )
743 // no, it hasn't, but we have to include it, anyway
744 aUnindexedModels.push_back( xModel );
747 // okay, here we have a container of all our models, sorted by tab index,
748 // plus a container of "unindexed" models
749 // -> merge them
750 Sequence< Reference< XControlModel > > aReturn( aUnindexedModels.size() + aSortedModels.size() );
751 ::std::transform(
752 aSortedModels.begin(), aSortedModels.end(),
753 ::std::copy( aUnindexedModels.begin(), aUnindexedModels.end(), aReturn.getArray() ),
754 ::boost::bind( &MapIndexToModel::value_type::second, _1 )
757 return aReturn;
761 void SAL_CALL ControlModelContainerBase::setGroup( const Sequence< Reference< XControlModel > >&, const OUString& ) throw (RuntimeException, std::exception)
763 // not supported. We have only implicit grouping:
764 // We only have a sequence of control models, and we _know_ (yes, that's a HACK relying on
765 // implementation details) that VCL does grouping according to the order of controls automatically
766 // At least VCL does this for all we're interested in: Radio buttons.
767 OSL_TRACE( "ControlModelContainerBase::setGroup: grouping not supported" );
770 ////----- XInitialization -------------------------------------------------------------------
771 void SAL_CALL ControlModelContainerBase::initialize (const Sequence<Any>& rArguments) throw (com::sun::star::uno::Exception, com::sun::star::uno::RuntimeException, std::exception)
773 if ( rArguments.getLength() == 1 )
775 sal_Int16 nPageId = -1;
776 if ( !( rArguments[ 0 ] >>= nPageId ))
777 throw lang::IllegalArgumentException();
778 m_nTabPageId = nPageId;
780 else
781 m_nTabPageId = -1;
783 ::sal_Int16 SAL_CALL ControlModelContainerBase::getTabPageID() throw (::com::sun::star::uno::RuntimeException, std::exception)
785 return m_nTabPageId;
787 sal_Bool SAL_CALL ControlModelContainerBase::getEnabled() throw (::com::sun::star::uno::RuntimeException, std::exception)
789 return m_bEnabled;
791 void SAL_CALL ControlModelContainerBase::setEnabled( sal_Bool _enabled ) throw (::com::sun::star::uno::RuntimeException, std::exception)
793 m_bEnabled = _enabled;
795 OUString SAL_CALL ControlModelContainerBase::getTitle() throw (::com::sun::star::uno::RuntimeException, std::exception)
797 SolarMutexGuard aGuard;
798 Reference<XPropertySet> xThis(*this,UNO_QUERY);
799 OUString sTitle;
800 xThis->getPropertyValue(GetPropertyName(BASEPROPERTY_TITLE)) >>= sTitle;
801 return sTitle;
803 void SAL_CALL ControlModelContainerBase::setTitle( const OUString& _title ) throw (::com::sun::star::uno::RuntimeException, std::exception)
805 SolarMutexGuard aGuard;
806 Reference<XPropertySet> xThis(*this,UNO_QUERY);
807 xThis->setPropertyValue(GetPropertyName(BASEPROPERTY_TITLE),makeAny(_title));
809 OUString SAL_CALL ControlModelContainerBase::getImageURL() throw (::com::sun::star::uno::RuntimeException, std::exception)
811 return m_sImageURL;
813 void SAL_CALL ControlModelContainerBase::setImageURL( const OUString& _imageurl ) throw (::com::sun::star::uno::RuntimeException, std::exception)
815 m_sImageURL = _imageurl;
817 OUString SAL_CALL ControlModelContainerBase::getToolTip() throw (::com::sun::star::uno::RuntimeException, std::exception)
819 return m_sTooltip;
821 void SAL_CALL ControlModelContainerBase::setToolTip( const OUString& _tooltip ) throw (::com::sun::star::uno::RuntimeException, std::exception)
823 m_sTooltip = _tooltip;
827 namespace
829 enum GroupingMachineState
831 eLookingForGroup,
832 eExpandingGroup
836 static sal_Int32 lcl_getDialogStep( const Reference< XControlModel >& _rxModel )
838 sal_Int32 nStep = 0;
841 Reference< XPropertySet > xModelProps( _rxModel, UNO_QUERY );
842 xModelProps->getPropertyValue( getStepPropertyName() ) >>= nStep;
844 catch (const Exception&)
846 OSL_TRACE( "lcl_getDialogStep: caught an exception while determining the dialog page!" );
848 return nStep;
853 sal_Int32 SAL_CALL ControlModelContainerBase::getGroupCount( ) throw (RuntimeException, std::exception)
855 SolarMutexGuard aGuard;
857 implUpdateGroupStructure();
859 return maGroups.size();
863 void SAL_CALL ControlModelContainerBase::getGroup( sal_Int32 _nGroup, Sequence< Reference< XControlModel > >& _rGroup, OUString& _rName ) throw (RuntimeException, std::exception)
865 SolarMutexGuard aGuard;
867 implUpdateGroupStructure();
869 if ( ( _nGroup < 0 ) || ( _nGroup >= (sal_Int32)maGroups.size() ) )
871 OSL_TRACE( "ControlModelContainerBase::getGroup: invalid argument and I am not allowed to throw an exception!" );
872 _rGroup.realloc( 0 );
873 _rName.clear();
875 else
877 AllGroups::const_iterator aGroupPos = maGroups.begin() + _nGroup;
878 _rGroup.realloc( aGroupPos->size() );
879 // copy the models
880 ::std::copy( aGroupPos->begin(), aGroupPos->end(), _rGroup.getArray() );
881 // give the group a name
882 _rName = OUString::number( _nGroup );
887 void SAL_CALL ControlModelContainerBase::getGroupByName( const OUString& _rName, Sequence< Reference< XControlModel > >& _rGroup ) throw (RuntimeException, std::exception)
889 SolarMutexGuard aGuard;
891 OUString sDummyName;
892 getGroup( _rName.toInt32( ), _rGroup, sDummyName );
896 void SAL_CALL ControlModelContainerBase::addChangesListener( const Reference< XChangesListener >& _rxListener ) throw (RuntimeException, std::exception)
898 maChangeListeners.addInterface( _rxListener );
902 void SAL_CALL ControlModelContainerBase::removeChangesListener( const Reference< XChangesListener >& _rxListener ) throw (RuntimeException, std::exception)
904 maChangeListeners.removeInterface( _rxListener );
908 void ControlModelContainerBase::implNotifyTabModelChange( const OUString& _rAccessor )
910 // multiplex to our change listeners:
911 // the changes event
912 ChangesEvent aEvent;
913 aEvent.Source = *this;
914 aEvent.Base <<= aEvent.Source; // the "base of the changes root" is also ourself
915 aEvent.Changes.realloc( 1 ); // exactly one change
916 aEvent.Changes[ 0 ].Accessor <<= _rAccessor;
919 Sequence< Reference< XInterface > > aChangeListeners( maChangeListeners.getElements() );
920 const Reference< XInterface >* pListener = aChangeListeners.getConstArray();
921 const Reference< XInterface >* pListenerEnd = aChangeListeners.getConstArray() + aChangeListeners.getLength();
922 for ( ; pListener != pListenerEnd; ++pListener )
924 if ( pListener->is() )
925 static_cast< XChangesListener* >( pListener->get() )->changesOccurred( aEvent );
931 void ControlModelContainerBase::implUpdateGroupStructure()
933 if ( mbGroupsUpToDate )
934 // nothing to do
935 return;
937 // conditions for a group:
938 // * all elements of the group are radio buttons
939 // * all elements of the group are on the same dialog page
940 // * in the overall control order (determined by the tab index), all elements are subsequent
942 maGroups.clear();
944 Sequence< Reference< XControlModel > > aControlModels = getControlModels();
945 const Reference< XControlModel >* pControlModels = aControlModels.getConstArray();
946 const Reference< XControlModel >* pControlModelsEnd = pControlModels + aControlModels.getLength();
948 // in extreme we have as much groups as controls
949 maGroups.reserve( aControlModels.getLength() );
951 GroupingMachineState eState = eLookingForGroup; // the current state of our machine
952 Reference< XServiceInfo > xModelSI; // for checking for a radion button
953 AllGroups::iterator aCurrentGroup = maGroups.end(); // the group which we're currently building
954 sal_Int32 nCurrentGroupStep = -1; // the step which all controls of the current group belong to
955 bool bIsRadioButton; // is it a radio button?
957 #if OSL_DEBUG_LEVEL > 1
958 ::std::vector< OUString > aCurrentGroupLabels;
959 #endif
961 for ( ; pControlModels != pControlModelsEnd; ++pControlModels )
963 // we'll need this in every state
964 xModelSI.set(*pControlModels, css::uno::UNO_QUERY);
965 bIsRadioButton = xModelSI.is() && xModelSI->supportsService( "com.sun.star.awt.UnoControlRadioButtonModel" );
967 switch ( eState )
969 case eLookingForGroup:
971 if ( !bIsRadioButton )
972 // this is no radio button -> still looking for the beginning of a group
973 continue;
974 // the current model is a radio button
975 // -> we found the beginning of a new group
976 // create the place for this group
977 size_t nGroups = maGroups.size();
978 maGroups.resize( nGroups + 1 );
979 aCurrentGroup = maGroups.begin() + nGroups;
980 // and add the (only, til now) member
981 aCurrentGroup->push_back( *pControlModels );
983 // get the step which all controls of this group now have to belong to
984 nCurrentGroupStep = lcl_getDialogStep( *pControlModels );
985 // new state: looking for further members
986 eState = eExpandingGroup;
988 #if OSL_DEBUG_LEVEL > 1
989 Reference< XPropertySet > xModelProps( *pControlModels, UNO_QUERY );
990 OUString sLabel;
991 if ( xModelProps.is() && xModelProps->getPropertySetInfo().is() && xModelProps->getPropertySetInfo()->hasPropertyByName("Label") )
992 xModelProps->getPropertyValue("Label") >>= sLabel;
993 aCurrentGroupLabels.push_back( sLabel );
994 #endif
996 break;
998 case eExpandingGroup:
1000 if ( !bIsRadioButton )
1001 { // no radio button -> the group is done
1002 aCurrentGroup = maGroups.end();
1003 eState = eLookingForGroup;
1004 #if OSL_DEBUG_LEVEL > 1
1005 aCurrentGroupLabels.clear();
1006 #endif
1007 continue;
1010 // it is a radio button - is it on the proper page?
1011 const sal_Int32 nThisModelStep = lcl_getDialogStep( *pControlModels );
1012 if ( ( nThisModelStep == nCurrentGroupStep ) // the current button is on the same dialog page
1013 || ( 0 == nThisModelStep ) // the current button appears on all pages
1016 // -> it belongs to the same group
1017 aCurrentGroup->push_back( *pControlModels );
1018 // state still is eExpandingGroup - we're looking for further elements
1019 eState = eExpandingGroup;
1021 #if OSL_DEBUG_LEVEL > 1
1022 Reference< XPropertySet > xModelProps( *pControlModels, UNO_QUERY );
1023 OUString sLabel;
1024 if ( xModelProps.is() && xModelProps->getPropertySetInfo().is() && xModelProps->getPropertySetInfo()->hasPropertyByName("Label") )
1025 xModelProps->getPropertyValue("Label") >>= sLabel;
1026 aCurrentGroupLabels.push_back( sLabel );
1027 #endif
1028 continue;
1031 // it's a radio button, but on a different page
1032 // -> we open a new group for it
1034 // close the old group
1035 aCurrentGroup = maGroups.end();
1036 #if OSL_DEBUG_LEVEL > 1
1037 aCurrentGroupLabels.clear();
1038 #endif
1040 // open a new group
1041 size_t nGroups = maGroups.size();
1042 maGroups.resize( nGroups + 1 );
1043 aCurrentGroup = maGroups.begin() + nGroups;
1044 // and add the (only, til now) member
1045 aCurrentGroup->push_back( *pControlModels );
1047 nCurrentGroupStep = nThisModelStep;
1049 // state is the same: we still are looking for further elements of the current group
1050 eState = eExpandingGroup;
1051 #if OSL_DEBUG_LEVEL > 1
1052 Reference< XPropertySet > xModelProps( *pControlModels, UNO_QUERY );
1053 OUString sLabel;
1054 if ( xModelProps.is() && xModelProps->getPropertySetInfo().is() && xModelProps->getPropertySetInfo()->hasPropertyByName("Label") )
1055 xModelProps->getPropertyValue("Label") >>= sLabel;
1056 aCurrentGroupLabels.push_back( sLabel );
1057 #endif
1059 break;
1063 mbGroupsUpToDate = true;
1067 void SAL_CALL ControlModelContainerBase::propertyChange( const PropertyChangeEvent& _rEvent ) throw (RuntimeException, std::exception)
1069 SolarMutexGuard aGuard;
1071 DBG_ASSERT( _rEvent.PropertyName == "TabIndex",
1072 "ControlModelContainerBase::propertyChange: not listening for this property!" );
1074 // the accessor for the changed element
1075 OUString sAccessor;
1076 UnoControlModelHolderList::const_iterator aPos =
1077 ::std::find_if(
1078 maModels.begin(), maModels.end(),
1079 CompareControlModel( Reference< XControlModel >( _rEvent.Source, UNO_QUERY ) )
1081 OSL_ENSURE( maModels.end() != aPos, "ControlModelContainerBase::propertyChange: don't know this model!" );
1082 if ( maModels.end() != aPos )
1083 sAccessor = aPos->second;
1085 // our groups are not up-to-date
1086 mbGroupsUpToDate = false;
1088 // notify
1089 implNotifyTabModelChange( sAccessor );
1093 void SAL_CALL ControlModelContainerBase::disposing( const EventObject& /*rEvent*/ ) throw (RuntimeException, std::exception)
1098 void ControlModelContainerBase::startControlListening( const Reference< XControlModel >& _rxChildModel )
1100 SolarMutexGuard aGuard;
1102 Reference< XPropertySet > xModelProps( _rxChildModel, UNO_QUERY );
1103 Reference< XPropertySetInfo > xPSI;
1104 if ( xModelProps.is() )
1105 xPSI = xModelProps->getPropertySetInfo();
1107 if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) )
1108 xModelProps->addPropertyChangeListener( getTabIndexPropertyName(), this );
1112 void ControlModelContainerBase::stopControlListening( const Reference< XControlModel >& _rxChildModel )
1114 SolarMutexGuard aGuard;
1116 Reference< XPropertySet > xModelProps( _rxChildModel, UNO_QUERY );
1117 Reference< XPropertySetInfo > xPSI;
1118 if ( xModelProps.is() )
1119 xPSI = xModelProps->getPropertySetInfo();
1121 if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) )
1122 xModelProps->removePropertyChangeListener( getTabIndexPropertyName(), this );
1126 // = class ResourceListener
1129 ResourceListener::ResourceListener(
1130 const Reference< util::XModifyListener >& rListener ) :
1131 OWeakObject(),
1132 m_xListener( rListener ),
1133 m_bListening( false )
1137 ResourceListener::~ResourceListener()
1141 // XInterface
1142 Any SAL_CALL ResourceListener::queryInterface( const Type& rType )
1143 throw ( RuntimeException, std::exception )
1145 Any a = ::cppu::queryInterface(
1146 rType ,
1147 static_cast< XModifyListener* >( this ),
1148 static_cast< XEventListener* >( this ));
1150 if ( a.hasValue() )
1151 return a;
1153 return OWeakObject::queryInterface( rType );
1156 void SAL_CALL ResourceListener::acquire() throw ()
1158 OWeakObject::acquire();
1161 void SAL_CALL ResourceListener::release() throw ()
1163 OWeakObject::release();
1166 void ResourceListener::startListening(
1167 const Reference< resource::XStringResourceResolver >& rResource )
1169 Reference< util::XModifyBroadcaster > xModifyBroadcaster( rResource, UNO_QUERY );
1172 // --- SAFE ---
1173 ::osl::ResettableGuard < ::osl::Mutex > aGuard( m_aMutex );
1174 bool bListening( m_bListening );
1175 bool bResourceSet( m_xResource.is() );
1176 aGuard.clear();
1177 // --- SAFE ---
1179 if ( bListening && bResourceSet )
1180 stopListening();
1182 // --- SAFE ---
1183 aGuard.reset();
1184 m_xResource = rResource;
1185 aGuard.clear();
1186 // --- SAFE ---
1189 Reference< util::XModifyListener > xThis( static_cast<OWeakObject*>( this ), UNO_QUERY );
1190 if ( xModifyBroadcaster.is() )
1194 xModifyBroadcaster->addModifyListener( xThis );
1196 // --- SAFE ---
1197 ::osl::ResettableGuard < ::osl::Mutex > aGuard( m_aMutex );
1198 m_bListening = true;
1199 // --- SAFE ---
1201 catch (const RuntimeException&)
1203 throw;
1205 catch (const Exception&)
1211 void ResourceListener::stopListening()
1213 Reference< util::XModifyBroadcaster > xModifyBroadcaster;
1215 // --- SAFE ---
1216 ::osl::ResettableGuard < ::osl::Mutex > aGuard( m_aMutex );
1217 if ( m_bListening && m_xResource.is() )
1218 xModifyBroadcaster = Reference< util::XModifyBroadcaster >( m_xResource, UNO_QUERY );
1219 aGuard.clear();
1220 // --- SAFE ---
1222 Reference< util::XModifyListener > xThis( static_cast< OWeakObject* >( this ), UNO_QUERY );
1223 if ( xModifyBroadcaster.is() )
1227 // --- SAFE ---
1228 aGuard.reset();
1229 m_bListening = false;
1230 m_xResource.clear();
1231 aGuard.clear();
1232 // --- SAFE ---
1234 xModifyBroadcaster->removeModifyListener( xThis );
1236 catch (const RuntimeException&)
1238 throw;
1240 catch (const Exception&)
1246 // XModifyListener
1247 void SAL_CALL ResourceListener::modified(
1248 const lang::EventObject& aEvent )
1249 throw ( RuntimeException, std::exception )
1251 Reference< util::XModifyListener > xListener;
1253 // --- SAFE ---
1254 ::osl::ResettableGuard < ::osl::Mutex > aGuard( m_aMutex );
1255 xListener = m_xListener;
1256 aGuard.clear();
1257 // --- SAFE ---
1259 if ( xListener.is() )
1263 xListener->modified( aEvent );
1265 catch (const RuntimeException&)
1267 throw;
1269 catch (const Exception&)
1275 // XEventListener
1276 void SAL_CALL ResourceListener::disposing(
1277 const EventObject& Source )
1278 throw ( RuntimeException, std::exception )
1280 Reference< lang::XEventListener > xListener;
1281 Reference< resource::XStringResourceResolver > xResource;
1283 // --- SAFE ---
1284 ::osl::ResettableGuard < ::osl::Mutex > aGuard( m_aMutex );
1285 Reference< XInterface > xIfacRes( m_xResource, UNO_QUERY );
1286 Reference< XInterface > xIfacList( m_xListener, UNO_QUERY );
1287 aGuard.clear();
1288 // --- SAFE ---
1290 if ( Source.Source == xIfacRes )
1292 // --- SAFE ---
1293 aGuard.reset();
1294 m_bListening = false;
1295 xResource = m_xResource;
1296 xListener = Reference< lang::XEventListener >( m_xListener, UNO_QUERY );
1297 m_xResource.clear();
1298 aGuard.clear();
1299 // --- SAFE ---
1301 if ( xListener.is() )
1305 xListener->disposing( Source );
1307 catch (const RuntimeException&)
1309 throw;
1311 catch (const Exception&)
1316 else if ( Source.Source == xIfacList )
1318 // --- SAFE ---
1319 aGuard.reset();
1320 m_bListening = false;
1321 xListener = Reference< lang::XEventListener >( m_xListener, UNO_QUERY );
1322 xResource = m_xResource;
1323 m_xResource.clear();
1324 m_xListener.clear();
1325 aGuard.clear();
1326 // --- SAFE ---
1328 // Remove ourself as listener from resource resolver
1329 Reference< util::XModifyBroadcaster > xModifyBroadcaster( xResource, UNO_QUERY );
1330 Reference< util::XModifyListener > xThis( static_cast< OWeakObject* >( this ), UNO_QUERY );
1331 if ( xModifyBroadcaster.is() )
1335 xModifyBroadcaster->removeModifyListener( xThis );
1337 catch (const RuntimeException&)
1339 throw;
1341 catch (const Exception&)
1350 // class DialogContainerControl
1352 ControlContainerBase::ControlContainerBase( const Reference< XComponentContext >& rxContext )
1353 :ContainerControl_IBase()
1354 ,m_xContext(rxContext)
1355 ,mbSizeModified(false)
1356 ,mbPosModified(false)
1358 maComponentInfos.nWidth = 280;
1359 maComponentInfos.nHeight = 400;
1360 mxListener = new ResourceListener( Reference< util::XModifyListener >(
1361 static_cast< OWeakObject* >( this ), UNO_QUERY ));
1364 ControlContainerBase::~ControlContainerBase()
1368 void ControlContainerBase::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer ) throw(RuntimeException, std::exception)
1370 SolarMutexGuard aGuard;
1371 UnoControlContainer::createPeer( rxToolkit, rParentPeer );
1374 void ControlContainerBase::ImplInsertControl( Reference< XControlModel >& rxModel, const OUString& rName )
1376 Reference< XPropertySet > xP( rxModel, UNO_QUERY );
1378 OUString aDefCtrl;
1379 xP->getPropertyValue( GetPropertyName( BASEPROPERTY_DEFAULTCONTROL ) ) >>= aDefCtrl;
1380 Reference < XControl > xCtrl( m_xContext->getServiceManager()->createInstanceWithContext(aDefCtrl, m_xContext), UNO_QUERY );
1382 DBG_ASSERT( xCtrl.is(), "ControlContainerBase::ImplInsertControl: could not create the control!" );
1383 if ( xCtrl.is() )
1385 xCtrl->setModel( rxModel );
1386 addControl( rName, xCtrl );
1387 // will implicitly call addingControl, where we can add the PropertiesChangeListener to the model
1388 // (which we formerly did herein)
1389 // 08.01.2001 - 96008 - fs@openoffice.org
1391 ImplSetPosSize( xCtrl );
1395 void ControlContainerBase::ImplRemoveControl( Reference< XControlModel >& rxModel )
1397 Sequence< Reference< XControl > > aControls = getControls();
1398 Reference< XControl > xCtrl = StdTabController::FindControl( aControls, rxModel );
1399 if ( xCtrl.is() )
1401 removeControl( xCtrl );
1404 xCtrl->dispose();
1406 catch (const Exception&)
1408 DBG_UNHANDLED_EXCEPTION();
1413 void ControlContainerBase::ImplSetPosSize( Reference< XControl >& rxCtrl )
1415 Reference< XPropertySet > xP( rxCtrl->getModel(), UNO_QUERY );
1417 sal_Int32 nX = 0, nY = 0, nWidth = 0, nHeight = 0;
1418 xP->getPropertyValue("PositionX") >>= nX;
1419 xP->getPropertyValue("PositionY") >>= nY;
1420 xP->getPropertyValue("Width") >>= nWidth;
1421 xP->getPropertyValue("Height") >>= nHeight;
1422 MapMode aMode( MAP_APPFONT );
1423 OutputDevice*pOutDev = Application::GetDefaultDevice();
1424 if ( pOutDev )
1426 ::Size aTmp( nX, nY );
1427 aTmp = pOutDev->LogicToPixel( aTmp, aMode );
1428 nX = aTmp.Width();
1429 nY = aTmp.Height();
1430 aTmp = ::Size( nWidth, nHeight );
1431 aTmp = pOutDev->LogicToPixel( aTmp, aMode );
1432 nWidth = aTmp.Width();
1433 nHeight = aTmp.Height();
1435 else
1437 Reference< XWindowPeer > xPeer = ImplGetCompatiblePeer( true );
1438 Reference< XDevice > xD( xPeer, UNO_QUERY );
1440 SimpleFontMetric aFM;
1441 FontDescriptor aFD;
1442 Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_FONTDESCRIPTOR ) );
1443 aVal >>= aFD;
1444 if ( !aFD.StyleName.isEmpty() )
1446 Reference< XFont > xFont = xD->getFont( aFD );
1447 aFM = xFont->getFontMetric();
1449 else
1451 Reference< XGraphics > xG = xD->createGraphics();
1452 aFM = xG->getFontMetric();
1455 sal_Int16 nH = aFM.Ascent + aFM.Descent;
1456 sal_Int16 nW = nH/2; // calculate avarage width?!
1458 nX *= nW;
1459 nX /= 4;
1460 nWidth *= nW;
1461 nWidth /= 4;
1462 nY *= nH;
1463 nY /= 8;
1464 nHeight *= nH;
1465 nHeight /= 8;
1467 Reference < XWindow > xW( rxCtrl, UNO_QUERY );
1468 xW->setPosSize( nX, nY, nWidth, nHeight, PosSize::POSSIZE );
1471 void ControlContainerBase::dispose() throw(RuntimeException, std::exception)
1473 EventObject aEvt;
1474 aEvt.Source = static_cast< ::cppu::OWeakObject* >( this );
1475 // Notify our listener helper about dispose
1476 // --- SAFE ---
1478 SolarMutexClearableGuard aGuard;
1479 Reference< XEventListener > xListener( mxListener, UNO_QUERY );
1480 mxListener.clear();
1481 aGuard.clear();
1482 // --- SAFE ---
1484 if ( xListener.is() )
1485 xListener->disposing( aEvt );
1486 UnoControlContainer::dispose();
1489 void SAL_CALL ControlContainerBase::disposing(
1490 const EventObject& Source )
1491 throw(RuntimeException, std::exception)
1493 UnoControlContainer::disposing( Source );
1496 sal_Bool ControlContainerBase::setModel( const Reference< XControlModel >& rxModel ) throw(RuntimeException, std::exception)
1498 SolarMutexGuard aGuard;
1500 // destroy the old tab controller, if existent
1501 if ( mxTabController.is() )
1503 mxTabController->setModel( NULL ); // just to be sure, should not be necessary
1504 removeTabController( mxTabController );
1505 ::comphelper::disposeComponent( mxTabController ); // just to be sure, should not be necessary
1506 mxTabController.clear();
1509 if ( getModel().is() )
1511 Sequence< Reference< XControl > > aControls = getControls();
1512 const Reference< XControl >* pCtrls = aControls.getConstArray();
1513 const Reference< XControl >* pCtrlsEnd = pCtrls + aControls.getLength();
1515 for ( ; pCtrls < pCtrlsEnd; ++pCtrls )
1516 removeControl( *pCtrls );
1517 // will implicitly call removingControl, which will remove the PropertyChangeListener
1518 // (which we formerly did herein)
1519 // 08.01.2001 - 96008 - fs@openoffice.org
1521 Reference< XContainer > xC( getModel(), UNO_QUERY );
1522 if ( xC.is() )
1523 xC->removeContainerListener( this );
1525 Reference< XChangesNotifier > xChangeNotifier( getModel(), UNO_QUERY );
1526 if ( xChangeNotifier.is() )
1527 xChangeNotifier->removeChangesListener( this );
1530 bool bRet = UnoControl::setModel( rxModel );
1532 if ( getModel().is() )
1534 Reference< XNameAccess > xNA( getModel(), UNO_QUERY );
1535 if ( xNA.is() )
1537 Sequence< OUString > aNames = xNA->getElementNames();
1538 const OUString* pNames = aNames.getConstArray();
1539 sal_uInt32 nCtrls = aNames.getLength();
1541 Reference< XControlModel > xCtrlModel;
1542 for( sal_uInt32 n = 0; n < nCtrls; ++n, ++pNames )
1544 xNA->getByName( *pNames ) >>= xCtrlModel;
1545 ImplInsertControl( xCtrlModel, *pNames );
1549 Reference< XContainer > xC( getModel(), UNO_QUERY );
1550 if ( xC.is() )
1551 xC->addContainerListener( this );
1553 Reference< XChangesNotifier > xChangeNotifier( getModel(), UNO_QUERY );
1554 if ( xChangeNotifier.is() )
1555 xChangeNotifier->addChangesListener( this );
1558 Reference< XTabControllerModel > xTabbing( getModel(), UNO_QUERY );
1559 if ( xTabbing.is() )
1561 mxTabController = new StdTabController;
1562 mxTabController->setModel( xTabbing );
1563 addTabController( mxTabController );
1565 ImplStartListingForResourceEvents();
1567 return bRet;
1569 void ControlContainerBase::setDesignMode( sal_Bool bOn ) throw(RuntimeException, std::exception)
1571 SolarMutexGuard aGuard;
1573 UnoControl::setDesignMode( bOn );
1575 Sequence< Reference< XControl > > xCtrls = getControls();
1576 sal_Int32 nControls = xCtrls.getLength();
1577 Reference< XControl >* pControls = xCtrls.getArray();
1578 for ( sal_Int32 n = 0; n < nControls; n++ )
1579 pControls[n]->setDesignMode( bOn );
1581 // #109067# in design mode the tab controller is not notified about
1582 // tab index changes, therefore the tab order must be activated
1583 // when switching from design mode to live mode
1584 if ( mxTabController.is() && !bOn )
1585 mxTabController->activateTabOrder();
1588 void ControlContainerBase::elementInserted( const ContainerEvent& Event ) throw(RuntimeException, std::exception)
1590 SolarMutexGuard aGuard;
1592 Reference< XControlModel > xModel;
1593 OUString aName;
1595 Event.Accessor >>= aName;
1596 Event.Element >>= xModel;
1597 ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementInserted: illegal element!" );
1600 ImplInsertControl( xModel, aName );
1602 catch (const RuntimeException&)
1604 throw;
1606 catch (const Exception&)
1608 DBG_UNHANDLED_EXCEPTION();
1612 void ControlContainerBase::elementRemoved( const ContainerEvent& Event ) throw(RuntimeException, std::exception)
1614 SolarMutexGuard aGuard;
1616 Reference< XControlModel > xModel;
1617 Event.Element >>= xModel;
1618 ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementRemoved: illegal element!" );
1621 ImplRemoveControl( xModel );
1623 catch (const RuntimeException&)
1625 throw;
1627 catch (const Exception&)
1629 DBG_UNHANDLED_EXCEPTION();
1633 void ControlContainerBase::elementReplaced( const ContainerEvent& Event ) throw(RuntimeException, std::exception)
1635 SolarMutexGuard aGuard;
1637 Reference< XControlModel > xModel;
1638 Event.ReplacedElement >>= xModel;
1641 OSL_ENSURE( xModel.is(), "ControlContainerBase::elementReplaced: invalid ReplacedElement!" );
1642 if ( xModel.is() )
1643 ImplRemoveControl( xModel );
1645 catch (const RuntimeException&)
1647 throw;
1649 catch (const Exception&)
1651 DBG_UNHANDLED_EXCEPTION();
1654 OUString aName;
1655 Event.Accessor >>= aName;
1656 Event.Element >>= xModel;
1657 ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementReplaced: invalid new element!" );
1660 ImplInsertControl( xModel, aName );
1662 catch (const RuntimeException&)
1664 throw;
1666 catch (const Exception&)
1668 DBG_UNHANDLED_EXCEPTION();
1672 // XPropertiesChangeListener
1673 void ControlContainerBase::ImplModelPropertiesChanged( const Sequence< PropertyChangeEvent >& rEvents ) throw(RuntimeException)
1675 if( !isDesignMode() && !mbCreatingCompatiblePeer )
1677 OUString s1( "PositionX" );
1678 OUString s2( "PositionY" );
1679 OUString s3( "Width" );
1680 OUString s4( "Height" );
1682 sal_Int32 nLen = rEvents.getLength();
1683 for( sal_Int32 i = 0; i < nLen; i++ )
1685 const PropertyChangeEvent& rEvt = rEvents.getConstArray()[i];
1686 Reference< XControlModel > xModel( rEvt.Source, UNO_QUERY );
1687 bool bOwnModel = (XControlModel*)xModel.get() == (XControlModel*)getModel().get();
1688 if ( ( rEvt.PropertyName == s1 ) ||
1689 ( rEvt.PropertyName == s2 ) ||
1690 ( rEvt.PropertyName == s3 ) ||
1691 ( rEvt.PropertyName == s4 ) )
1693 if ( bOwnModel )
1695 if ( !mbPosModified && !mbSizeModified )
1697 // Don't set new pos/size if we get new values from window listener
1698 Reference< XControl > xThis( (XAggregation*)(::cppu::OWeakAggObject*)this, UNO_QUERY );
1699 ImplSetPosSize( xThis );
1702 else
1704 Sequence<Reference<XControl> > aControlSequence(getControls());
1705 Reference<XControl> aControlRef( StdTabController::FindControl( aControlSequence, xModel ) );
1706 ImplSetPosSize( aControlRef );
1708 break;
1713 UnoControlContainer::ImplModelPropertiesChanged( rEvents );
1716 void ControlContainerBase::addingControl( const Reference< XControl >& _rxControl )
1718 SolarMutexGuard aGuard;
1719 UnoControlContainer::addingControl( _rxControl );
1721 if ( _rxControl.is() )
1723 Reference< XMultiPropertySet > xProps( _rxControl->getModel(), UNO_QUERY );
1724 if ( xProps.is() )
1726 Sequence< OUString > aNames( 4 );
1727 OUString* pNames = aNames.getArray();
1728 *pNames++ = "PositionX";
1729 *pNames++ = "PositionY";
1730 *pNames++ = "Width";
1731 *pNames++ = "Height";
1733 xProps->addPropertiesChangeListener( aNames, this );
1738 void ControlContainerBase::removingControl( const Reference< XControl >& _rxControl )
1740 SolarMutexGuard aGuard;
1741 UnoControlContainer::removingControl( _rxControl );
1743 if ( _rxControl.is() )
1745 Reference< XMultiPropertySet > xProps( _rxControl->getModel(), UNO_QUERY );
1746 if ( xProps.is() )
1747 xProps->removePropertiesChangeListener( this );
1752 void SAL_CALL ControlContainerBase::changesOccurred( const ChangesEvent& ) throw (RuntimeException, std::exception)
1754 SolarMutexGuard aGuard;
1755 // a tab controller model may have changed
1757 // #109067# in design mode don't notify the tab controller
1758 // about tab index changes
1759 if ( mxTabController.is() && !mbDesignMode )
1760 mxTabController->activateTabOrder();
1762 static void lcl_ApplyResolverToNestedContainees( const Reference< resource::XStringResourceResolver >& xStringResourceResolver, const Reference< XControlContainer >& xContainer )
1764 OUString aPropName( PROPERTY_RESOURCERESOLVER );
1766 Any xNewStringResourceResolver; xNewStringResourceResolver <<= xStringResourceResolver;
1768 Sequence< OUString > aPropNames(1);
1769 aPropNames[0] = aPropName;
1771 const Sequence< Reference< awt::XControl > > aSeq = xContainer->getControls();
1772 for ( sal_Int32 i = 0; i < aSeq.getLength(); i++ )
1774 Reference< XControl > xControl( aSeq[i] );
1775 Reference< XPropertySet > xPropertySet;
1777 if ( xControl.is() )
1778 xPropertySet = Reference< XPropertySet >( xControl->getModel(), UNO_QUERY );
1780 if ( !xPropertySet.is() )
1781 continue;
1785 Reference< resource::XStringResourceResolver > xCurrStringResourceResolver;
1786 Any aOldValue = xPropertySet->getPropertyValue( aPropName );
1787 if ( ( aOldValue >>= xCurrStringResourceResolver )
1788 && ( xStringResourceResolver == xCurrStringResourceResolver )
1791 Reference< XMultiPropertySet > xMultiPropSet( xPropertySet, UNO_QUERY );
1792 Reference< XPropertiesChangeListener > xListener( xPropertySet, UNO_QUERY );
1793 xMultiPropSet->firePropertiesChangeEvent( aPropNames, xListener );
1795 else
1796 xPropertySet->setPropertyValue( aPropName, xNewStringResourceResolver );
1798 catch (const Exception&)
1802 uno::Reference< XControlContainer > xNestedContainer( xControl, uno::UNO_QUERY );
1803 if ( xNestedContainer.is() )
1804 lcl_ApplyResolverToNestedContainees( xStringResourceResolver, xNestedContainer );
1809 void ControlContainerBase::ImplStartListingForResourceEvents()
1811 Reference< resource::XStringResourceResolver > xStringResourceResolver;
1813 ImplGetPropertyValue( PROPERTY_RESOURCERESOLVER ) >>= xStringResourceResolver;
1815 // Add our helper as listener to retrieve notifications about changes
1816 Reference< util::XModifyListener > rListener( mxListener );
1817 ResourceListener* pResourceListener = static_cast< ResourceListener* >( rListener.get() );
1819 // resource listener will stop listening if resolver reference is empty
1820 if ( pResourceListener )
1821 pResourceListener->startListening( xStringResourceResolver );
1822 ImplUpdateResourceResolver();
1825 void ControlContainerBase::ImplUpdateResourceResolver()
1827 OUString aPropName( PROPERTY_RESOURCERESOLVER );
1828 Reference< resource::XStringResourceResolver > xStringResourceResolver;
1830 ImplGetPropertyValue( aPropName ) >>= xStringResourceResolver;
1831 if ( !xStringResourceResolver.is() )
1832 return;
1834 lcl_ApplyResolverToNestedContainees( xStringResourceResolver, this );
1836 // propagate resource resolver changes to language dependent props of the dialog
1837 Reference< XPropertySet > xPropertySet( getModel(), UNO_QUERY );
1838 if ( xPropertySet.is() )
1840 Reference< XMultiPropertySet > xMultiPropSet( xPropertySet, UNO_QUERY );
1841 Reference< XPropertiesChangeListener > xListener( xPropertySet, UNO_QUERY );
1842 xMultiPropSet->firePropertiesChangeEvent( lcl_getLanguageDependentProperties(), xListener );
1846 //// ----------------------------------------------------
1847 //// Helper Method to convert relative url to physical location
1848 //// ----------------------------------------------------
1850 OUString getPhysicalLocation( const ::com::sun::star::uno::Any& rbase, const ::com::sun::star::uno::Any& rUrl )
1853 OUString baseLocation;
1854 OUString url;
1856 rbase >>= baseLocation;
1857 rUrl >>= url;
1859 OUString absoluteURL( url );
1860 if ( !url.isEmpty() )
1862 INetURLObject urlObj(baseLocation);
1863 urlObj.removeSegment();
1864 baseLocation = urlObj.GetMainURL( INetURLObject::NO_DECODE );
1866 const INetURLObject protocolCheck( url );
1867 const INetProtocol protocol = protocolCheck.GetProtocol();
1868 if ( protocol == INetProtocol::NotValid )
1870 OUString testAbsoluteURL;
1871 if ( ::osl::FileBase::E_None == ::osl::FileBase::getAbsoluteFileURL( baseLocation, url, testAbsoluteURL ) )
1872 absoluteURL = testAbsoluteURL;
1876 return absoluteURL;
1879 void
1880 ControlModelContainerBase::updateUserFormChildren( const Reference< XNameContainer >& xAllChildren, const OUString& aName, ChildOperation Operation, const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlModel >& xTarget ) throw(IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException)
1882 if ( Operation < Insert || Operation > Remove )
1883 throw IllegalArgumentException();
1885 if ( xAllChildren.is() )
1887 if ( Operation == Remove )
1889 Reference< XControlModel > xOldModel( xAllChildren->getByName( aName ), UNO_QUERY );
1890 xAllChildren->removeByName( aName );
1892 Reference< XNameContainer > xChildContainer( xOldModel, UNO_QUERY );
1893 if ( xChildContainer.is() )
1895 Reference< XPropertySet > xProps( xChildContainer, UNO_QUERY );
1896 // container control is being removed from this container, reset the
1897 // global list of containees
1898 if ( xProps.is() )
1899 xProps->setPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ), uno::makeAny( uno::Reference< XNameContainer >() ) );
1900 Sequence< OUString > aChildNames = xChildContainer->getElementNames();
1901 for ( sal_Int32 index=0; index< aChildNames.getLength(); ++index )
1902 updateUserFormChildren( xAllChildren, aChildNames[ index ], Operation, Reference< XControlModel > () );
1905 else if ( Operation == Insert )
1907 xAllChildren->insertByName( aName, uno::makeAny( xTarget ) );
1908 Reference< XNameContainer > xChildContainer( xTarget, UNO_QUERY );
1909 if ( xChildContainer.is() )
1911 // container control is being added from this container, reset the
1912 // global list of containees to point to the correct global list
1913 Reference< XPropertySet > xProps( xChildContainer, UNO_QUERY );
1914 if ( xProps.is() )
1915 xProps->setPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ), uno::makeAny( xAllChildren ) );
1916 Sequence< OUString > aChildNames = xChildContainer->getElementNames();
1917 for ( sal_Int32 index=0; index< aChildNames.getLength(); ++index )
1919 Reference< XControlModel > xChildTarget( xChildContainer->getByName( aChildNames[ index ] ), UNO_QUERY );
1920 updateUserFormChildren( xAllChildren, aChildNames[ index ], Operation, xChildTarget );
1925 else
1926 throw IllegalArgumentException();
1929 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */