Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / toolkit / source / controls / controlmodelcontainerbase.cxx
blob14933e96affca61ccc15edd732691b473e2a0891
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 <controls/controlmodelcontainerbase.hxx>
22 #include <vcl/svapp.hxx>
23 #include <o3tl/safeint.hxx>
24 #include <osl/mutex.hxx>
25 #include <helper/property.hxx>
26 #include <helper/servicenames.hxx>
27 #include <controls/geometrycontrolmodel.hxx>
28 #include <toolkit/controls/unocontrols.hxx>
29 #include <controls/formattedcontrol.hxx>
30 #include <controls/roadmapcontrol.hxx>
31 #include <controls/tkscrollbar.hxx>
32 #include <controls/tabpagemodel.hxx>
33 #include <controls/stdtabcontroller.hxx>
34 #include <com/sun/star/awt/PosSize.hpp>
35 #include <com/sun/star/resource/XStringResourceResolver.hpp>
36 #include <com/sun/star/lang/XInitialization.hpp>
37 #include <cppuhelper/queryinterface.hxx>
38 #include <cppuhelper/weak.hxx>
39 #include <cppuhelper/weakagg.hxx>
40 #include <tools/debug.hxx>
41 #include <comphelper/diagnose_ex.hxx>
42 #include <vcl/outdev.hxx>
43 #include <comphelper/types.hxx>
45 #include "tree/treecontrol.hxx"
46 #include "grid/gridcontrol.hxx"
47 #include <controls/tabpagecontainer.hxx>
49 #include <map>
50 #include <algorithm>
51 #include <tools/urlobj.hxx>
52 #include <osl/file.hxx>
53 #include <sal/log.hxx>
54 #include <controls/dialogcontrol.hxx>
56 #include <helper/unopropertyarrayhelper.hxx>
57 #include "controlmodelcontainerbase_internal.hxx"
59 using namespace ::com::sun::star;
60 using namespace ::com::sun::star::uno;
61 using namespace ::com::sun::star::awt;
62 using namespace ::com::sun::star::lang;
63 using namespace ::com::sun::star::container;
64 using namespace ::com::sun::star::beans;
65 using namespace ::com::sun::star::util;
66 using namespace toolkit;
68 constexpr OUStringLiteral PROPERTY_RESOURCERESOLVER = u"ResourceResolver";
71 namespace
73 const Sequence< OUString >& lcl_getLanguageDependentProperties()
75 // note: properties must be sorted
76 static Sequence<OUString> s_aLanguageDependentProperties{ "HelpText", "Title" };
77 return s_aLanguageDependentProperties;
80 // functor for disposing a control model
81 struct DisposeControlModel
83 void operator()( Reference< XControlModel >& _rxModel )
85 try
87 ::comphelper::disposeComponent( _rxModel );
89 catch (const Exception&)
91 TOOLS_WARN_EXCEPTION("toolkit", "caught an exception while disposing a component" );
99 // functor for cloning a control model, and insertion into a target list
100 struct CloneControlModel
102 private:
103 ControlModelContainerBase::UnoControlModelHolderVector& m_rTargetVector;
105 public:
106 explicit CloneControlModel( ControlModelContainerBase::UnoControlModelHolderVector& _rTargetVector )
107 :m_rTargetVector( _rTargetVector )
111 void operator()( const ControlModelContainerBase::UnoControlModelHolder& _rSource )
113 // clone the source object
114 Reference< XCloneable > xCloneSource( _rSource.first, UNO_QUERY );
115 Reference< XControlModel > xClone( xCloneSource->createClone(), UNO_QUERY );
116 // add to target list
117 m_rTargetVector.emplace_back( xClone, _rSource.second );
122 // functor for comparing a XControlModel with a given reference
123 struct CompareControlModel
125 private:
126 Reference< XControlModel > m_xReference;
127 public:
128 explicit CompareControlModel( const Reference< XControlModel >& _rxReference ) : m_xReference( _rxReference ) { }
130 bool operator()( const ControlModelContainerBase::UnoControlModelHolder& _rCompare )
132 return _rCompare.first.get() == m_xReference.get();
137 static void lcl_throwIllegalArgumentException( )
138 { // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this...
139 throw IllegalArgumentException();
143 static void lcl_throwNoSuchElementException( )
144 { // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this...
145 throw NoSuchElementException();
149 static void lcl_throwElementExistException( )
150 { // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this...
151 throw ElementExistException();
155 static OUString getTabIndexPropertyName( )
157 return "TabIndex";
161 static OUString getStepPropertyName( )
163 return "Step";
168 ControlModelContainerBase::ControlModelContainerBase( const Reference< XComponentContext >& rxContext )
169 :ControlModelContainer_IBase( rxContext )
170 ,maContainerListeners( *this )
171 ,mbGroupsUpToDate( false )
172 ,m_nTabPageId(0)
174 ImplRegisterProperty(BASEPROPERTY_ENABLED);
177 ControlModelContainerBase::ControlModelContainerBase( const ControlModelContainerBase& rModel )
178 : ControlModelContainer_IBase( rModel )
179 , maContainerListeners( *this )
180 , mbGroupsUpToDate( false )
181 , m_nTabPageId( rModel.m_nTabPageId )
185 ControlModelContainerBase::~ControlModelContainerBase()
187 maModels.clear();
188 mbGroupsUpToDate = false;
191 Any ControlModelContainerBase::ImplGetDefaultValue( sal_uInt16 nPropId ) const
193 Any aAny;
195 switch ( nPropId )
197 case BASEPROPERTY_DEFAULTCONTROL:
198 aAny <<= OUString::createFromAscii( szServiceName_UnoControlDialog );
199 break;
200 default:
201 aAny = UnoControlModel::ImplGetDefaultValue( nPropId );
204 return aAny;
207 ::cppu::IPropertyArrayHelper& ControlModelContainerBase::getInfoHelper()
209 static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() );
210 return aHelper;
213 void SAL_CALL ControlModelContainerBase::dispose( )
216 // tell our listeners
218 std::unique_lock aGuard( m_aMutex );
220 EventObject aDisposeEvent;
221 aDisposeEvent.Source = static_cast< XAggregation* >( static_cast< ::cppu::OWeakAggObject* >( this ) );
223 maContainerListeners.disposeAndClear( aGuard, aDisposeEvent );
224 maChangeListeners.disposeAndClear( aGuard, aDisposeEvent );
228 // call the base class
229 UnoControlModel::dispose();
232 // dispose our child models
233 // for this, collect the models (we collect them from maModels, and this is modified when disposing children)
234 ::std::vector< Reference< XControlModel > > aChildModels( maModels.size() );
236 ::std::transform(
237 maModels.begin(), maModels.end(), // source range
238 aChildModels.begin(), // target location
239 []( const UnoControlModelHolder& rUnoControlModelHolder )
240 { return rUnoControlModelHolder.first; } // operation to apply -> select the XControlModel part
243 // now dispose
244 ::std::for_each( aChildModels.begin(), aChildModels.end(), DisposeControlModel() );
245 aChildModels.clear();
247 mbGroupsUpToDate = false;
250 // XMultiPropertySet
251 Reference< XPropertySetInfo > ControlModelContainerBase::getPropertySetInfo( )
253 static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
254 return xInfo;
256 void ControlModelContainerBase::Clone_Impl(ControlModelContainerBase& _rClone) const
258 // clone all children
259 ::std::for_each(
260 maModels.begin(), maModels.end(),
261 CloneControlModel( _rClone.maModels )
264 rtl::Reference<UnoControlModel> ControlModelContainerBase::Clone() const
266 // clone the container itself
267 rtl::Reference<ControlModelContainerBase> pClone = new ControlModelContainerBase( *this );
268 Clone_Impl(*pClone);
270 return pClone;
273 ControlModelContainerBase::UnoControlModelHolderVector::iterator ControlModelContainerBase::ImplFindElement( std::u16string_view rName )
275 return ::std::find_if( maModels.begin(), maModels.end(), [&](const UnoControlModelHolder& elem) { return elem.second == rName; });
278 // ::XMultiServiceFactory
279 Reference< XInterface > ControlModelContainerBase::createInstance( const OUString& aServiceSpecifier )
281 SolarMutexGuard aGuard;
283 rtl::Reference<OGeometryControlModel_Base> pNewModel;
285 if ( aServiceSpecifier == "com.sun.star.awt.UnoControlEditModel" )
286 pNewModel = new OGeometryControlModel< UnoControlEditModel >( m_xContext );
287 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFormattedFieldModel" )
288 pNewModel = new OGeometryControlModel< UnoControlFormattedFieldModel >( m_xContext);
289 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFileControlModel" )
290 pNewModel = new OGeometryControlModel< UnoControlFileControlModel >( m_xContext );
291 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlButtonModel" )
292 pNewModel = new OGeometryControlModel< UnoControlButtonModel >( m_xContext );
293 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlImageControlModel" )
294 pNewModel = new OGeometryControlModel< UnoControlImageControlModel >( m_xContext );
295 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlRadioButtonModel" )
296 pNewModel = new OGeometryControlModel< UnoControlRadioButtonModel >( m_xContext );
297 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlCheckBoxModel" )
298 pNewModel = new OGeometryControlModel< UnoControlCheckBoxModel >( m_xContext );
299 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFixedHyperlinkModel" )
300 pNewModel = new OGeometryControlModel< UnoControlFixedHyperlinkModel >( m_xContext );
301 else if ( aServiceSpecifier == "stardiv.vcl.controlmodel.FixedText" )
302 pNewModel = new OGeometryControlModel< UnoControlFixedTextModel >( m_xContext );
303 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlGroupBoxModel" )
304 pNewModel = new OGeometryControlModel< UnoControlGroupBoxModel >( m_xContext );
305 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlListBoxModel" )
306 pNewModel = new OGeometryControlModel< UnoControlListBoxModel >( m_xContext );
307 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlComboBoxModel" )
308 pNewModel = new OGeometryControlModel< UnoControlComboBoxModel >( m_xContext );
309 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlDateFieldModel" )
310 pNewModel = new OGeometryControlModel< UnoControlDateFieldModel >( m_xContext );
311 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlTimeFieldModel" )
312 pNewModel = new OGeometryControlModel< UnoControlTimeFieldModel >( m_xContext );
313 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlNumericFieldModel" )
314 pNewModel = new OGeometryControlModel< UnoControlNumericFieldModel >( m_xContext );
315 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlCurrencyFieldModel" )
316 pNewModel = new OGeometryControlModel< UnoControlCurrencyFieldModel >( m_xContext );
317 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlPatternFieldModel" )
318 pNewModel = new OGeometryControlModel< UnoControlPatternFieldModel >( m_xContext );
319 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlProgressBarModel" )
320 pNewModel = new OGeometryControlModel< UnoControlProgressBarModel >( m_xContext );
321 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlScrollBarModel" )
322 pNewModel = new OGeometryControlModel< UnoControlScrollBarModel >( m_xContext );
323 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFixedLineModel" )
324 pNewModel = new OGeometryControlModel< UnoControlFixedLineModel >( m_xContext );
325 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlRoadmapModel" )
326 pNewModel = new OGeometryControlModel< UnoControlRoadmapModel >( m_xContext );
327 else if ( aServiceSpecifier == "com.sun.star.awt.tree.TreeControlModel" )
328 pNewModel = new OGeometryControlModel< UnoTreeModel >( m_xContext );
329 else if ( aServiceSpecifier == "com.sun.star.awt.grid.UnoControlGridModel" )
330 pNewModel = new OGeometryControlModel< UnoGridModel >( m_xContext );
331 else if ( aServiceSpecifier == "com.sun.star.awt.tab.UnoControlTabPageContainerModel" )
332 pNewModel = new OGeometryControlModel< UnoControlTabPageContainerModel >( m_xContext );
333 else if ( aServiceSpecifier == "com.sun.star.awt.UnoMultiPageModel" )
334 pNewModel = new OGeometryControlModel< UnoMultiPageModel >( m_xContext );
335 else if ( aServiceSpecifier == "com.sun.star.awt.tab.UnoControlTabPageModel" )
336 pNewModel = new OGeometryControlModel< UnoControlTabPageModel >( m_xContext );
337 else if ( aServiceSpecifier == "com.sun.star.awt.UnoPageModel" )
338 pNewModel = new OGeometryControlModel< UnoPageModel >( m_xContext );
339 else if ( aServiceSpecifier == "com.sun.star.awt.UnoFrameModel" )
340 pNewModel = new OGeometryControlModel< UnoFrameModel >( m_xContext );
342 if ( !pNewModel )
344 Reference< XInterface > xObject = m_xContext->getServiceManager()->createInstanceWithContext(aServiceSpecifier, m_xContext);
345 Reference< XServiceInfo > xSI( xObject, UNO_QUERY );
346 Reference< XCloneable > xCloneAccess( xSI, UNO_QUERY );
347 Reference< XAggregation > xAgg( xCloneAccess, UNO_QUERY );
348 if ( xAgg.is() )
350 if ( xSI->supportsService("com.sun.star.awt.UnoControlModel") )
352 // release 3 of the 4 references we have to the object
353 xAgg.clear();
354 xSI.clear();
355 xObject.clear();
357 pNewModel = new OCommonGeometryControlModel( xCloneAccess, aServiceSpecifier );
362 Reference< XInterface > xNewModel = static_cast<cppu::OWeakObject*>(pNewModel.get());
363 return xNewModel;
366 Reference< XInterface > ControlModelContainerBase::createInstanceWithArguments( const OUString& ServiceSpecifier, const Sequence< Any >& i_arguments )
368 const Reference< XInterface > xInstance( createInstance( ServiceSpecifier ) );
369 const Reference< XInitialization > xInstanceInit( xInstance, UNO_QUERY );
370 ENSURE_OR_RETURN( xInstanceInit.is(), "ControlModelContainerBase::createInstanceWithArguments: can't pass the arguments!", xInstance );
371 xInstanceInit->initialize( i_arguments );
372 return xInstance;
375 Sequence< OUString > ControlModelContainerBase::getAvailableServiceNames()
377 return { "com.sun.star.awt.UnoControlEditModel",
378 "com.sun.star.awt.UnoControlFormattedFieldModel",
379 "com.sun.star.awt.UnoControlFileControlModel",
380 "com.sun.star.awt.UnoControlButtonModel",
381 "com.sun.star.awt.UnoControlImageControlModel",
382 "com.sun.star.awt.UnoControlRadioButtonModel",
383 "com.sun.star.awt.UnoControlCheckBoxModel",
384 "com.sun.star.awt.UnoControlFixedTextModel",
385 "com.sun.star.awt.UnoControlGroupBoxModel",
386 "com.sun.star.awt.UnoControlListBoxModel",
387 "com.sun.star.awt.UnoControlComboBoxModel",
388 "com.sun.star.awt.UnoControlDateFieldModel",
389 "com.sun.star.awt.UnoControlTimeFieldModel",
390 "com.sun.star.awt.UnoControlNumericFieldModel",
391 "com.sun.star.awt.UnoControlCurrencyFieldModel",
392 "com.sun.star.awt.UnoControlPatternFieldModel",
393 "com.sun.star.awt.UnoControlProgressBarModel",
394 "com.sun.star.awt.UnoControlScrollBarModel",
395 "com.sun.star.awt.UnoControlFixedLineModel",
396 "com.sun.star.awt.UnoControlRoadmapModel",
397 "com.sun.star.awt.tree.TreeControlModel",
398 "com.sun.star.awt.grid.UnoControlGridModel",
399 "com.sun.star.awt.UnoControlFixedHyperlinkModel",
400 "com.sun.star.awt.tab.UnoControlTabPageContainerModel",
401 "com.sun.star.awt.tab.UnoControlTabPageModel",
402 "com.sun.star.awt.UnoMultiPageModel",
403 "com.sun.star.awt.UnoFrameModel"
407 // XContainer
408 void ControlModelContainerBase::addContainerListener( const Reference< XContainerListener >& l )
410 maContainerListeners.addInterface( l );
413 void ControlModelContainerBase::removeContainerListener( const Reference< XContainerListener >& l )
415 maContainerListeners.removeInterface( l );
418 // XElementAccess
419 Type ControlModelContainerBase::getElementType()
421 Type aType = cppu::UnoType<XControlModel>::get();
422 return aType;
425 sal_Bool ControlModelContainerBase::hasElements()
427 return !maModels.empty();
430 // XNameContainer, XNameReplace, XNameAccess
431 void ControlModelContainerBase::replaceByName( const OUString& aName, const Any& aElement )
433 SolarMutexGuard aGuard;
435 Reference< XControlModel > xNewModel;
436 aElement >>= xNewModel;
437 if ( !xNewModel.is() )
438 lcl_throwIllegalArgumentException();
440 UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName );
441 if ( maModels.end() == aElementPos )
442 lcl_throwNoSuchElementException();
443 // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
444 // With container controls you could have constructed an existing hierarchy and are now
445 // add this to an existing container, in this case a name nested in the containment
446 // hierarchy of the added control could contain a name clash, if we have access to the
447 // list of global names then recursively check for previously existing names (we need
448 // to do this obviously before the 'this' objects container is updated)
449 Reference< XNameContainer > xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ) ), UNO_QUERY );
450 if ( xAllChildren.is() )
452 // remove old control (and children) from global list of containers
453 updateUserFormChildren( xAllChildren, aName, Remove, uno::Reference< XControlModel >() );
454 // Add new control (and containers if they exist)
455 updateUserFormChildren( xAllChildren, aName, Insert, xNewModel );
457 // stop listening at the old model
458 stopControlListening( aElementPos->first );
459 Reference< XControlModel > xReplaced( aElementPos->first );
460 // remember the new model, and start listening
461 aElementPos->first = xNewModel;
462 startControlListening( xNewModel );
464 ContainerEvent aEvent;
465 aEvent.Source = *this;
466 aEvent.Element = aElement;
467 aEvent.ReplacedElement <<= xReplaced;
468 aEvent.Accessor <<= aName;
470 // notify the container listener
471 maContainerListeners.elementReplaced( aEvent );
473 // our "tab controller model" has potentially changed -> notify this
474 implNotifyTabModelChange( aName );
477 Any ControlModelContainerBase::getByName( const OUString& aName )
479 UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName );
480 if ( maModels.end() == aElementPos )
481 lcl_throwNoSuchElementException();
483 return Any( aElementPos->first );
486 Sequence< OUString > ControlModelContainerBase::getElementNames()
488 Sequence< OUString > aNames( maModels.size() );
490 ::std::transform(
491 maModels.begin(), maModels.end(), // source range
492 aNames.getArray(), // target range
493 []( const UnoControlModelHolder& rUnoControlModelHolder )
494 { return rUnoControlModelHolder.second; } // operator to apply: select the second element (the name)
497 return aNames;
500 sal_Bool ControlModelContainerBase::hasByName( const OUString& aName )
502 return maModels.end() != ImplFindElement( aName );
505 void ControlModelContainerBase::insertByName( const OUString& aName, const Any& aElement )
507 SolarMutexGuard aGuard;
509 Reference< XControlModel > xM;
510 aElement >>= xM;
512 if ( xM.is() )
514 Reference< beans::XPropertySet > xProps( xM, UNO_QUERY );
515 if ( xProps.is() )
518 Reference< beans::XPropertySetInfo > xPropInfo = xProps->getPropertySetInfo();
520 const OUString& sImageSourceProperty = GetPropertyName( BASEPROPERTY_IMAGEURL );
521 if ( xPropInfo->hasPropertyByName( sImageSourceProperty ) && ImplHasProperty(BASEPROPERTY_DIALOGSOURCEURL) )
523 Any aUrl = xProps->getPropertyValue( sImageSourceProperty );
525 OUString absoluteUrl =
526 getPhysicalLocation( getPropertyValue( GetPropertyName( BASEPROPERTY_DIALOGSOURCEURL ) ), aUrl );
528 aUrl <<= absoluteUrl;
530 xProps->setPropertyValue( sImageSourceProperty , aUrl );
536 if ( aName.isEmpty() || !xM.is() )
537 lcl_throwIllegalArgumentException();
539 UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName );
540 if ( maModels.end() != aElementPos )
541 lcl_throwElementExistException();
543 // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
544 // With container controls you could have constructed an existing hierarchy and are now
545 // add this to an existing container, in this case a name nested in the containment
546 // hierarchy of the added control could contain a name clash, if we have access to the
547 // list of global names then we need to recursively check for previously existing
548 // names (we need to do this obviously before the 'this' objects container is updated)
549 // remove old control (and children) from global list of containers
550 Reference< XNameContainer > xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ) ), UNO_QUERY );
552 if ( xAllChildren.is() )
553 updateUserFormChildren( xAllChildren, aName, Insert, xM );
554 maModels.emplace_back( xM, aName );
555 mbGroupsUpToDate = false;
556 startControlListening( xM );
558 ContainerEvent aEvent;
559 aEvent.Source = *this;
560 aEvent.Element = aElement;
561 aEvent.Accessor <<= aName;
562 maContainerListeners.elementInserted( aEvent );
564 // our "tab controller model" has potentially changed -> notify this
565 implNotifyTabModelChange( aName );
568 void ControlModelContainerBase::removeByName( const OUString& aName )
570 SolarMutexGuard aGuard;
572 UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName );
573 if ( maModels.end() == aElementPos )
574 lcl_throwNoSuchElementException();
576 // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
577 // With container controls you could have constructed an existing hierarchy and are now
578 // removing this control from an existing container, in this case all nested names in
579 // the containment hierarchy of the control to be removed need to be removed from the global
580 // names cache (we need to do this obviously before the 'this' objects container is updated)
581 Reference< XNameContainer > xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ) ), UNO_QUERY );
582 if ( xAllChildren.is() )
583 updateUserFormChildren( xAllChildren, aName, Remove, uno::Reference< XControlModel >() );
585 ContainerEvent aEvent;
586 aEvent.Source = *this;
587 aEvent.Element <<= aElementPos->first;
588 aEvent.Accessor <<= aName;
589 maContainerListeners.elementRemoved( aEvent );
591 stopControlListening( aElementPos->first );
592 Reference< XPropertySet > xPS( aElementPos->first, UNO_QUERY );
593 maModels.erase( aElementPos );
594 mbGroupsUpToDate = false;
596 if ( xPS.is() )
600 xPS->setPropertyValue( PROPERTY_RESOURCERESOLVER, Any( Reference< resource::XStringResourceResolver >() ) );
602 catch (const Exception&)
604 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
608 // our "tab controller model" has potentially changed -> notify this
609 implNotifyTabModelChange( aName );
613 sal_Bool SAL_CALL ControlModelContainerBase::getGroupControl( )
615 return true;
619 void SAL_CALL ControlModelContainerBase::setGroupControl( sal_Bool )
621 SAL_WARN("toolkit", "explicit grouping not supported" );
625 void SAL_CALL ControlModelContainerBase::setControlModels( const Sequence< Reference< XControlModel > >& _rControls )
627 SolarMutexGuard aGuard;
629 // set the tab indexes according to the order of models in the sequence
631 sal_Int16 nTabIndex = 1;
633 for ( auto const & control : _rControls )
635 // look up the control in our own structure. This is to prevent invalid arguments
636 UnoControlModelHolderVector::const_iterator aPos =
637 ::std::find_if(
638 maModels.begin(), maModels.end(),
639 CompareControlModel( control )
641 if ( maModels.end() != aPos )
643 // okay, this is an existent model
644 // now set the TabIndex property (if applicable)
645 Reference< XPropertySet > xProps( aPos->first, UNO_QUERY );
646 Reference< XPropertySetInfo > xPSI;
647 if ( xProps.is() )
648 xPSI = xProps->getPropertySetInfo();
649 if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) )
650 xProps->setPropertyValue( getTabIndexPropertyName(), Any( nTabIndex++ ) );
652 mbGroupsUpToDate = false;
657 typedef ::std::multimap< sal_Int32, Reference< XControlModel > > MapIndexToModel;
660 Sequence< Reference< XControlModel > > SAL_CALL ControlModelContainerBase::getControlModels( )
662 SolarMutexGuard aGuard;
664 MapIndexToModel aSortedModels;
665 // will be the sorted container of all models which have a tab index property
666 ::std::vector< Reference< XControlModel > > aUnindexedModels;
667 // will be the container of all models which do not have a tab index property
669 for ( const auto& rModel : maModels )
671 Reference< XControlModel > xModel( rModel.first );
673 // see if the model has a TabIndex property
674 Reference< XPropertySet > xControlProps( xModel, UNO_QUERY );
675 Reference< XPropertySetInfo > xPSI;
676 if ( xControlProps.is() )
677 xPSI = xControlProps->getPropertySetInfo( );
678 DBG_ASSERT( xPSI.is(), "ControlModelContainerBase::getControlModels: invalid child model!" );
680 // has it?
681 if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) )
682 { // yes
683 sal_Int32 nTabIndex = -1;
684 xControlProps->getPropertyValue( getTabIndexPropertyName() ) >>= nTabIndex;
686 aSortedModels.emplace( nTabIndex, xModel );
688 else if ( xModel.is() )
689 // no, it hasn't, but we have to include it, anyway
690 aUnindexedModels.push_back( xModel );
693 // okay, here we have a container of all our models, sorted by tab index,
694 // plus a container of "unindexed" models
695 // -> merge them
696 Sequence< Reference< XControlModel > > aReturn( aUnindexedModels.size() + aSortedModels.size() );
697 ::std::transform(
698 aSortedModels.begin(), aSortedModels.end(),
699 ::std::copy( aUnindexedModels.begin(), aUnindexedModels.end(), aReturn.getArray() ),
700 [] ( const MapIndexToModel::value_type& entryIndexToModel )
701 { return entryIndexToModel.second; }
704 return aReturn;
708 void SAL_CALL ControlModelContainerBase::setGroup( const Sequence< Reference< XControlModel > >&, const OUString& )
710 // not supported. We have only implicit grouping:
711 // We only have a sequence of control models, and we _know_ (yes, that's a HACK relying on
712 // implementation details) that VCL does grouping according to the order of controls automatically
713 // At least VCL does this for all we're interested in: Radio buttons.
714 SAL_WARN("toolkit", "grouping not supported" );
717 ////----- XInitialization -------------------------------------------------------------------
718 void SAL_CALL ControlModelContainerBase::initialize (const Sequence<Any>& rArguments)
720 if ( rArguments.getLength() == 1 )
722 sal_Int16 nPageId = -1;
723 if ( !( rArguments[ 0 ] >>= nPageId ))
724 throw lang::IllegalArgumentException();
725 m_nTabPageId = nPageId;
727 else
728 m_nTabPageId = -1;
730 ::sal_Int16 SAL_CALL ControlModelContainerBase::getTabPageID()
732 return m_nTabPageId;
734 sal_Bool SAL_CALL ControlModelContainerBase::getEnabled()
736 SolarMutexGuard aGuard;
737 bool bEnabled = false;
738 getPropertyValue(GetPropertyName(BASEPROPERTY_ENABLED)) >>= bEnabled;
739 return bEnabled;
741 void SAL_CALL ControlModelContainerBase::setEnabled( sal_Bool _enabled )
743 SolarMutexGuard aGuard;
744 setPropertyValue(GetPropertyName(BASEPROPERTY_ENABLED), Any(_enabled));
746 OUString SAL_CALL ControlModelContainerBase::getTitle()
748 SolarMutexGuard aGuard;
749 OUString sTitle;
750 getPropertyValue(GetPropertyName(BASEPROPERTY_TITLE)) >>= sTitle;
751 return sTitle;
753 void SAL_CALL ControlModelContainerBase::setTitle( const OUString& _title )
755 SolarMutexGuard aGuard;
756 setPropertyValue(GetPropertyName(BASEPROPERTY_TITLE),Any(_title));
758 OUString SAL_CALL ControlModelContainerBase::getImageURL()
760 return m_sImageURL;
762 void SAL_CALL ControlModelContainerBase::setImageURL( const OUString& _imageurl )
764 m_sImageURL = _imageurl;
765 SolarMutexGuard aGuard;
766 setPropertyValue(GetPropertyName(BASEPROPERTY_IMAGEURL), Any(_imageurl));
768 OUString SAL_CALL ControlModelContainerBase::getToolTip()
770 return m_sTooltip;
772 void SAL_CALL ControlModelContainerBase::setToolTip( const OUString& _tooltip )
774 m_sTooltip = _tooltip;
778 namespace
780 enum GroupingMachineState
782 eLookingForGroup,
783 eExpandingGroup
787 sal_Int32 lcl_getDialogStep( const Reference< XControlModel >& _rxModel )
789 sal_Int32 nStep = 0;
792 Reference< XPropertySet > xModelProps( _rxModel, UNO_QUERY );
793 xModelProps->getPropertyValue( getStepPropertyName() ) >>= nStep;
795 catch (const Exception&)
797 TOOLS_WARN_EXCEPTION("toolkit", "caught an exception while determining the dialog page" );
799 return nStep;
804 sal_Int32 SAL_CALL ControlModelContainerBase::getGroupCount( )
806 SolarMutexGuard aGuard;
808 implUpdateGroupStructure();
810 return maGroups.size();
814 void SAL_CALL ControlModelContainerBase::getGroup( sal_Int32 _nGroup, Sequence< Reference< XControlModel > >& _rGroup, OUString& _rName )
816 SolarMutexGuard aGuard;
818 implUpdateGroupStructure();
820 if ( ( _nGroup < 0 ) || ( o3tl::make_unsigned(_nGroup) >= maGroups.size() ) )
822 SAL_WARN("toolkit", "invalid argument and I am not allowed to throw exception!" );
823 _rGroup.realloc( 0 );
824 _rName.clear();
826 else
828 AllGroups::const_iterator aGroupPos = maGroups.begin() + _nGroup;
829 _rGroup.realloc( aGroupPos->size() );
830 // copy the models
831 ::std::copy( aGroupPos->begin(), aGroupPos->end(), _rGroup.getArray() );
832 // give the group a name
833 _rName = OUString::number( _nGroup );
838 void SAL_CALL ControlModelContainerBase::getGroupByName( const OUString& _rName, Sequence< Reference< XControlModel > >& _rGroup )
840 SolarMutexGuard aGuard;
842 OUString sDummyName;
843 getGroup( _rName.toInt32( ), _rGroup, sDummyName );
847 void SAL_CALL ControlModelContainerBase::addChangesListener( const Reference< XChangesListener >& _rxListener )
849 std::unique_lock g(m_aMutex);
850 maChangeListeners.addInterface( g, _rxListener );
854 void SAL_CALL ControlModelContainerBase::removeChangesListener( const Reference< XChangesListener >& _rxListener )
856 std::unique_lock g(m_aMutex);
857 maChangeListeners.removeInterface( g, _rxListener );
861 void ControlModelContainerBase::implNotifyTabModelChange( const OUString& _rAccessor )
863 // multiplex to our change listeners:
864 // the changes event
865 ChangesEvent aEvent;
866 aEvent.Source = *this;
867 aEvent.Base <<= aEvent.Source; // the "base of the changes root" is also ourself
868 aEvent.Changes.realloc( 1 ); // exactly one change
869 aEvent.Changes.getArray()[ 0 ].Accessor <<= _rAccessor;
872 std::unique_lock g(m_aMutex);
873 std::vector< Reference< css::util::XChangesListener > > aChangeListeners( maChangeListeners.getElements(g) );
874 g.unlock();
875 for ( const auto& rListener : aChangeListeners )
876 rListener->changesOccurred( aEvent );
880 void ControlModelContainerBase::implUpdateGroupStructure()
882 if ( mbGroupsUpToDate )
883 // nothing to do
884 return;
886 // conditions for a group:
887 // * all elements of the group are radio buttons
888 // * all elements of the group are on the same dialog page
889 // * in the overall control order (determined by the tab index), all elements are subsequent
891 maGroups.clear();
893 const Sequence< Reference< XControlModel > > aControlModels = getControlModels();
895 // in extreme we have as much groups as controls
896 maGroups.reserve( aControlModels.getLength() );
898 GroupingMachineState eState = eLookingForGroup; // the current state of our machine
899 Reference< XServiceInfo > xModelSI; // for checking for a radio button
900 AllGroups::iterator aCurrentGroup = maGroups.end(); // the group which we're currently building
901 sal_Int32 nCurrentGroupStep = -1; // the step which all controls of the current group belong to
904 for ( const Reference< XControlModel >& rControlModel : aControlModels )
906 // we'll need this in every state
907 xModelSI.set(rControlModel, css::uno::UNO_QUERY);
908 // is it a radio button?
909 bool bIsRadioButton = xModelSI.is() && xModelSI->supportsService( "com.sun.star.awt.UnoControlRadioButtonModel" );
911 switch ( eState )
913 case eLookingForGroup:
915 if ( !bIsRadioButton )
916 // this is no radio button -> still looking for the beginning of a group
917 continue;
918 // the current model is a radio button
919 // -> we found the beginning of a new group
920 // create the place for this group
921 size_t nGroups = maGroups.size();
922 maGroups.resize( nGroups + 1 );
923 aCurrentGroup = maGroups.begin() + nGroups;
924 // and add the (only, til now) member
925 aCurrentGroup->push_back( rControlModel );
927 // get the step which all controls of this group now have to belong to
928 nCurrentGroupStep = lcl_getDialogStep( rControlModel );
929 // new state: looking for further members
930 eState = eExpandingGroup;
933 break;
935 case eExpandingGroup:
937 if ( !bIsRadioButton )
938 { // no radio button -> the group is done
939 aCurrentGroup = maGroups.end();
940 eState = eLookingForGroup;
941 continue;
944 // it is a radio button - is it on the proper page?
945 const sal_Int32 nThisModelStep = lcl_getDialogStep( rControlModel );
946 if ( ( nThisModelStep == nCurrentGroupStep ) // the current button is on the same dialog page
947 || ( 0 == nThisModelStep ) // the current button appears on all pages
950 // -> it belongs to the same group
951 aCurrentGroup->push_back( rControlModel );
952 // state still is eExpandingGroup - we're looking for further elements
953 eState = eExpandingGroup;
955 continue;
958 // it's a radio button, but on a different page
959 // -> we open a new group for it
962 // open a new group
963 size_t nGroups = maGroups.size();
964 maGroups.resize( nGroups + 1 );
965 aCurrentGroup = maGroups.begin() + nGroups;
966 // and add the (only, til now) member
967 aCurrentGroup->push_back( rControlModel );
969 nCurrentGroupStep = nThisModelStep;
971 // state is the same: we still are looking for further elements of the current group
972 eState = eExpandingGroup;
974 break;
978 mbGroupsUpToDate = true;
982 void SAL_CALL ControlModelContainerBase::propertyChange( const PropertyChangeEvent& _rEvent )
984 SolarMutexGuard aGuard;
986 DBG_ASSERT( _rEvent.PropertyName == "TabIndex",
987 "ControlModelContainerBase::propertyChange: not listening for this property!" );
989 // the accessor for the changed element
990 OUString sAccessor;
991 UnoControlModelHolderVector::const_iterator aPos =
992 ::std::find_if(
993 maModels.begin(), maModels.end(),
994 CompareControlModel( Reference< XControlModel >( _rEvent.Source, UNO_QUERY ) )
996 OSL_ENSURE( maModels.end() != aPos, "ControlModelContainerBase::propertyChange: don't know this model!" );
997 if ( maModels.end() != aPos )
998 sAccessor = aPos->second;
1000 // our groups are not up-to-date
1001 mbGroupsUpToDate = false;
1003 // notify
1004 implNotifyTabModelChange( sAccessor );
1008 void SAL_CALL ControlModelContainerBase::disposing( const EventObject& /*rEvent*/ )
1013 void ControlModelContainerBase::startControlListening( const Reference< XControlModel >& _rxChildModel )
1015 SolarMutexGuard aGuard;
1017 Reference< XPropertySet > xModelProps( _rxChildModel, UNO_QUERY );
1018 Reference< XPropertySetInfo > xPSI;
1019 if ( xModelProps.is() )
1020 xPSI = xModelProps->getPropertySetInfo();
1022 if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) )
1023 xModelProps->addPropertyChangeListener( getTabIndexPropertyName(), this );
1027 void ControlModelContainerBase::stopControlListening( const Reference< XControlModel >& _rxChildModel )
1029 SolarMutexGuard aGuard;
1031 Reference< XPropertySet > xModelProps( _rxChildModel, UNO_QUERY );
1032 Reference< XPropertySetInfo > xPSI;
1033 if ( xModelProps.is() )
1034 xPSI = xModelProps->getPropertySetInfo();
1036 if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) )
1037 xModelProps->removePropertyChangeListener( getTabIndexPropertyName(), this );
1041 // = class ResourceListener
1044 ResourceListener::ResourceListener(
1045 const Reference< util::XModifyListener >& rListener ) :
1046 m_xListener( rListener ),
1047 m_bListening( false )
1051 ResourceListener::~ResourceListener()
1055 // XInterface
1056 Any SAL_CALL ResourceListener::queryInterface( const Type& rType )
1058 Any a = ::cppu::queryInterface(
1059 rType ,
1060 static_cast< XModifyListener* >( this ),
1061 static_cast< XEventListener* >( this ));
1063 if ( a.hasValue() )
1064 return a;
1066 return OWeakObject::queryInterface( rType );
1069 void SAL_CALL ResourceListener::acquire() noexcept
1071 OWeakObject::acquire();
1074 void SAL_CALL ResourceListener::release() noexcept
1076 OWeakObject::release();
1079 void ResourceListener::startListening(
1080 const Reference< resource::XStringResourceResolver >& rResource )
1083 // --- SAFE ---
1084 std::unique_lock aGuard( m_aMutex );
1085 bool bListening( m_bListening );
1086 bool bResourceSet( m_xResource.is() );
1087 aGuard.unlock();
1088 // --- SAFE ---
1090 if ( bListening && bResourceSet )
1091 stopListening();
1093 // --- SAFE ---
1094 aGuard.lock();
1095 m_xResource = rResource;
1096 aGuard.unlock();
1097 // --- SAFE ---
1100 if ( !rResource.is() )
1101 return;
1105 rResource->addModifyListener( this );
1107 // --- SAFE ---
1108 std::scoped_lock aGuard( m_aMutex );
1109 m_bListening = true;
1110 // --- SAFE ---
1112 catch (const RuntimeException&)
1114 throw;
1116 catch (const Exception&)
1121 void ResourceListener::stopListening()
1123 Reference< util::XModifyBroadcaster > xModifyBroadcaster;
1125 // --- SAFE ---
1126 std::unique_lock aGuard( m_aMutex );
1127 if ( m_bListening && m_xResource.is() )
1128 xModifyBroadcaster = m_xResource;
1129 aGuard.unlock();
1130 // --- SAFE ---
1132 if ( !xModifyBroadcaster.is() )
1133 return;
1137 // --- SAFE ---
1138 aGuard.lock();
1139 m_bListening = false;
1140 m_xResource.clear();
1141 aGuard.unlock();
1142 // --- SAFE ---
1144 xModifyBroadcaster->removeModifyListener( this );
1146 catch (const RuntimeException&)
1148 throw;
1150 catch (const Exception&)
1155 // XModifyListener
1156 void SAL_CALL ResourceListener::modified(
1157 const lang::EventObject& aEvent )
1159 Reference< util::XModifyListener > xListener;
1161 // --- SAFE ---
1162 std::unique_lock aGuard( m_aMutex );
1163 xListener = m_xListener;
1164 aGuard.unlock();
1165 // --- SAFE ---
1167 if ( !xListener.is() )
1168 return;
1172 xListener->modified( aEvent );
1174 catch (const RuntimeException&)
1176 throw;
1178 catch (const Exception&)
1183 // XEventListener
1184 void SAL_CALL ResourceListener::disposing(
1185 const EventObject& Source )
1187 Reference< lang::XEventListener > xListener;
1188 Reference< resource::XStringResourceResolver > xResource;
1190 // --- SAFE ---
1191 std::unique_lock aGuard( m_aMutex );
1192 Reference< XInterface > xIfacRes( m_xResource, UNO_QUERY );
1193 Reference< XInterface > xIfacList( m_xListener, UNO_QUERY );
1194 aGuard.unlock();
1195 // --- SAFE ---
1197 if ( Source.Source == xIfacRes )
1199 // --- SAFE ---
1200 aGuard.lock();
1201 m_bListening = false;
1202 xResource = m_xResource;
1203 xListener = m_xListener;
1204 m_xResource.clear();
1205 aGuard.unlock();
1206 // --- SAFE ---
1208 if ( xListener.is() )
1212 xListener->disposing( Source );
1214 catch (const RuntimeException&)
1216 throw;
1218 catch (const Exception&)
1223 else if ( Source.Source == xIfacList )
1225 // --- SAFE ---
1226 aGuard.lock();
1227 m_bListening = false;
1228 xListener = m_xListener;
1229 xResource = m_xResource;
1230 m_xResource.clear();
1231 m_xListener.clear();
1232 aGuard.unlock();
1233 // --- SAFE ---
1235 // Remove ourself as listener from resource resolver
1236 if ( xResource.is() )
1240 xResource->removeModifyListener( this );
1242 catch (const RuntimeException&)
1244 throw;
1246 catch (const Exception&)
1255 ControlContainerBase::ControlContainerBase( const Reference< XComponentContext >& rxContext )
1256 :m_xContext(rxContext)
1257 ,mbSizeModified(false)
1258 ,mbPosModified(false)
1260 maComponentInfos.nWidth = 280;
1261 maComponentInfos.nHeight = 400;
1262 mxListener = new ResourceListener( Reference< util::XModifyListener >(this) );
1265 ControlContainerBase::~ControlContainerBase()
1269 void ControlContainerBase::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer )
1271 SolarMutexGuard aGuard;
1272 UnoControlContainer::createPeer( rxToolkit, rParentPeer );
1275 void ControlContainerBase::ImplInsertControl( Reference< XControlModel > const & rxModel, const OUString& rName )
1277 Reference< XPropertySet > xP( rxModel, UNO_QUERY );
1279 OUString aDefCtrl;
1280 xP->getPropertyValue( GetPropertyName( BASEPROPERTY_DEFAULTCONTROL ) ) >>= aDefCtrl;
1281 Reference < XControl > xCtrl( m_xContext->getServiceManager()->createInstanceWithContext(aDefCtrl, m_xContext), UNO_QUERY );
1283 DBG_ASSERT( xCtrl.is(), "ControlContainerBase::ImplInsertControl: could not create the control!" );
1284 if ( xCtrl.is() )
1286 xCtrl->setModel( rxModel );
1287 addControl( rName, xCtrl );
1288 // will implicitly call addingControl, where we can add the PropertiesChangeListener to the model
1289 // (which we formerly did herein)
1290 // 08.01.2001 - 96008 - fs@openoffice.org
1292 ImplSetPosSize( xCtrl );
1296 void ControlContainerBase::ImplRemoveControl( Reference< XControlModel > const & rxModel )
1298 Sequence< Reference< XControl > > aControls = getControls();
1299 Reference< XControl > xCtrl = StdTabController::FindControl( aControls, rxModel );
1300 if ( xCtrl.is() )
1302 removeControl( xCtrl );
1305 xCtrl->dispose();
1307 catch (const Exception&)
1309 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1314 void ControlContainerBase::ImplSetPosSize( Reference< XControl >& rxCtrl )
1316 Reference< XPropertySet > xP( rxCtrl->getModel(), UNO_QUERY );
1318 sal_Int32 nX = 0, nY = 0, nWidth = 0, nHeight = 0;
1319 xP->getPropertyValue("PositionX") >>= nX;
1320 xP->getPropertyValue("PositionY") >>= nY;
1321 xP->getPropertyValue("Width") >>= nWidth;
1322 xP->getPropertyValue("Height") >>= nHeight;
1323 MapMode aMode( MapUnit::MapAppFont );
1324 OutputDevice*pOutDev = Application::GetDefaultDevice();
1325 if ( pOutDev )
1327 ::Size aTmp( nX, nY );
1328 aTmp = pOutDev->LogicToPixel( aTmp, aMode );
1329 nX = aTmp.Width();
1330 nY = aTmp.Height();
1331 aTmp = ::Size( nWidth, nHeight );
1332 aTmp = pOutDev->LogicToPixel( aTmp, aMode );
1333 nWidth = aTmp.Width();
1334 nHeight = aTmp.Height();
1336 else
1338 Reference< XWindowPeer > xPeer = ImplGetCompatiblePeer();
1339 Reference< XDevice > xD( xPeer, UNO_QUERY );
1341 SimpleFontMetric aFM;
1342 FontDescriptor aFD;
1343 Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_FONTDESCRIPTOR ) );
1344 aVal >>= aFD;
1345 if ( !aFD.StyleName.isEmpty() )
1347 Reference< XFont > xFont = xD->getFont( aFD );
1348 aFM = xFont->getFontMetric();
1350 else
1352 Reference< XGraphics > xG = xD->createGraphics();
1353 aFM = xG->getFontMetric();
1356 sal_Int16 nH = aFM.Ascent + aFM.Descent;
1357 sal_Int16 nW = nH/2; // calculate average width?!
1359 nX *= nW;
1360 nX /= 4;
1361 nWidth *= nW;
1362 nWidth /= 4;
1363 nY *= nH;
1364 nY /= 8;
1365 nHeight *= nH;
1366 nHeight /= 8;
1368 Reference < XWindow > xW( rxCtrl, UNO_QUERY );
1369 xW->setPosSize( nX, nY, nWidth, nHeight, PosSize::POSSIZE );
1372 void ControlContainerBase::dispose()
1374 EventObject aEvt;
1375 aEvt.Source = static_cast< ::cppu::OWeakObject* >( this );
1376 // Notify our listener helper about dispose
1377 // --- SAFE ---
1379 SolarMutexClearableGuard aGuard;
1380 Reference< XEventListener > xListener = mxListener;
1381 mxListener.clear();
1382 aGuard.clear();
1383 // --- SAFE ---
1385 if ( xListener.is() )
1386 xListener->disposing( aEvt );
1387 UnoControlContainer::dispose();
1390 void SAL_CALL ControlContainerBase::disposing(
1391 const EventObject& Source )
1393 UnoControlContainer::disposing( Source );
1396 sal_Bool ControlContainerBase::setModel( const Reference< XControlModel >& rxModel )
1398 SolarMutexGuard aGuard;
1400 // destroy the old tab controller, if existent
1401 if ( mxTabController.is() )
1403 mxTabController->setModel( nullptr ); // just to be sure, should not be necessary
1404 removeTabController( mxTabController );
1405 ::comphelper::disposeComponent( mxTabController ); // just to be sure, should not be necessary
1406 mxTabController.clear();
1409 if ( getModel().is() )
1411 const Sequence< Reference< XControl > > aControls = getControls();
1413 for ( const Reference< XControl >& rCtrl : aControls )
1414 removeControl( rCtrl );
1415 // will implicitly call removingControl, which will remove the PropertyChangeListener
1416 // (which we formerly did herein)
1417 // 08.01.2001 - 96008 - fs@openoffice.org
1419 Reference< XContainer > xC( getModel(), UNO_QUERY );
1420 if ( xC.is() )
1421 xC->removeContainerListener( this );
1423 Reference< XChangesNotifier > xChangeNotifier( getModel(), UNO_QUERY );
1424 if ( xChangeNotifier.is() )
1425 xChangeNotifier->removeChangesListener( this );
1428 bool bRet = UnoControl::setModel( rxModel );
1430 if ( getModel().is() )
1432 Reference< XNameAccess > xNA( getModel(), UNO_QUERY );
1433 if ( xNA.is() )
1435 const Sequence< OUString > aNames = xNA->getElementNames();
1437 Reference< XControlModel > xCtrlModel;
1438 for( const OUString& rName : aNames )
1440 xNA->getByName( rName ) >>= xCtrlModel;
1441 ImplInsertControl( xCtrlModel, rName );
1445 Reference< XContainer > xC( getModel(), UNO_QUERY );
1446 if ( xC.is() )
1447 xC->addContainerListener( this );
1449 Reference< XChangesNotifier > xChangeNotifier( getModel(), UNO_QUERY );
1450 if ( xChangeNotifier.is() )
1451 xChangeNotifier->addChangesListener( this );
1454 Reference< XTabControllerModel > xTabbing( getModel(), UNO_QUERY );
1455 if ( xTabbing.is() )
1457 mxTabController = new StdTabController;
1458 mxTabController->setModel( xTabbing );
1459 addTabController( mxTabController );
1461 ImplStartListingForResourceEvents();
1463 return bRet;
1465 void ControlContainerBase::setDesignMode( sal_Bool bOn )
1467 SolarMutexGuard aGuard;
1469 UnoControl::setDesignMode( bOn );
1471 Sequence< Reference< XControl > > xCtrls = getControls();
1472 for ( Reference< XControl >& rControl : asNonConstRange(xCtrls) )
1473 rControl->setDesignMode( bOn );
1475 // #109067# in design mode the tab controller is not notified about
1476 // tab index changes, therefore the tab order must be activated
1477 // when switching from design mode to live mode
1478 if ( mxTabController.is() && !bOn )
1479 mxTabController->activateTabOrder();
1482 void ControlContainerBase::elementInserted( const ContainerEvent& Event )
1484 SolarMutexGuard aGuard;
1486 Reference< XControlModel > xModel;
1487 OUString aName;
1489 Event.Accessor >>= aName;
1490 Event.Element >>= xModel;
1491 ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementInserted: illegal element!" );
1494 ImplInsertControl( xModel, aName );
1496 catch (const RuntimeException&)
1498 throw;
1500 catch (const Exception&)
1502 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1506 void ControlContainerBase::elementRemoved( const ContainerEvent& Event )
1508 SolarMutexGuard aGuard;
1510 Reference< XControlModel > xModel;
1511 Event.Element >>= xModel;
1512 ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementRemoved: illegal element!" );
1515 ImplRemoveControl( xModel );
1517 catch (const RuntimeException&)
1519 throw;
1521 catch (const Exception&)
1523 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1527 void ControlContainerBase::elementReplaced( const ContainerEvent& Event )
1529 SolarMutexGuard aGuard;
1531 Reference< XControlModel > xModel;
1532 Event.ReplacedElement >>= xModel;
1535 OSL_ENSURE( xModel.is(), "ControlContainerBase::elementReplaced: invalid ReplacedElement!" );
1536 if ( xModel.is() )
1537 ImplRemoveControl( xModel );
1539 catch (const RuntimeException&)
1541 throw;
1543 catch (const Exception&)
1545 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1548 OUString aName;
1549 Event.Accessor >>= aName;
1550 Event.Element >>= xModel;
1551 ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementReplaced: invalid new element!" );
1554 ImplInsertControl( xModel, aName );
1556 catch (const RuntimeException&)
1558 throw;
1560 catch (const Exception&)
1562 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1566 // XPropertiesChangeListener
1567 void ControlContainerBase::ImplModelPropertiesChanged( const Sequence< PropertyChangeEvent >& rEvents )
1569 if( !isDesignMode() && !mbCreatingCompatiblePeer )
1571 auto pEvt = std::find_if(rEvents.begin(), rEvents.end(),
1572 [](const PropertyChangeEvent& rEvt) {
1573 return rEvt.PropertyName == "PositionX"
1574 || rEvt.PropertyName == "PositionY"
1575 || rEvt.PropertyName == "Width"
1576 || rEvt.PropertyName == "Height";
1578 if (pEvt != rEvents.end())
1580 Reference< XControlModel > xModel( pEvt->Source, UNO_QUERY );
1581 bool bOwnModel = xModel.get() == getModel().get();
1582 if ( bOwnModel )
1584 if ( !mbPosModified && !mbSizeModified )
1586 // Don't set new pos/size if we get new values from window listener
1587 Reference< XControl > xThis(this);
1588 ImplSetPosSize( xThis );
1591 else
1593 Sequence<Reference<XControl> > aControlSequence(getControls());
1594 Reference<XControl> aControlRef( StdTabController::FindControl( aControlSequence, xModel ) );
1595 ImplSetPosSize( aControlRef );
1600 UnoControlContainer::ImplModelPropertiesChanged( rEvents );
1603 void ControlContainerBase::addingControl( const Reference< XControl >& _rxControl )
1605 SolarMutexGuard aGuard;
1606 UnoControlContainer::addingControl( _rxControl );
1608 if ( !_rxControl.is() )
1609 return;
1611 Reference< XMultiPropertySet > xProps( _rxControl->getModel(), UNO_QUERY );
1612 if ( xProps.is() )
1614 const Sequence< OUString > aNames {
1615 "PositionX",
1616 "PositionY",
1617 "Width",
1618 "Height"
1621 xProps->addPropertiesChangeListener( aNames, this );
1625 void ControlContainerBase::removingControl( const Reference< XControl >& _rxControl )
1627 SolarMutexGuard aGuard;
1628 UnoControlContainer::removingControl( _rxControl );
1630 if ( _rxControl.is() )
1632 Reference< XMultiPropertySet > xProps( _rxControl->getModel(), UNO_QUERY );
1633 if ( xProps.is() )
1634 xProps->removePropertiesChangeListener( this );
1639 void SAL_CALL ControlContainerBase::changesOccurred( const ChangesEvent& )
1641 SolarMutexGuard aGuard;
1642 // a tab controller model may have changed
1644 // #109067# in design mode don't notify the tab controller
1645 // about tab index changes
1646 if ( mxTabController.is() && !mbDesignMode )
1647 mxTabController->activateTabOrder();
1649 static void lcl_ApplyResolverToNestedContainees( const Reference< resource::XStringResourceResolver >& xStringResourceResolver, const Reference< XControlContainer >& xContainer )
1651 OUString aPropName( PROPERTY_RESOURCERESOLVER );
1653 Any aNewStringResourceResolver;
1654 aNewStringResourceResolver <<= xStringResourceResolver;
1656 Sequence< OUString > aPropNames { aPropName };
1658 const Sequence< Reference< awt::XControl > > aSeq = xContainer->getControls();
1659 for ( const Reference< XControl >& xControl : aSeq )
1661 Reference< XPropertySet > xPropertySet;
1663 if ( xControl.is() )
1664 xPropertySet.set( xControl->getModel(), UNO_QUERY );
1666 if ( !xPropertySet.is() )
1667 continue;
1671 Reference< resource::XStringResourceResolver > xCurrStringResourceResolver;
1672 Any aOldValue = xPropertySet->getPropertyValue( aPropName );
1673 if ( ( aOldValue >>= xCurrStringResourceResolver )
1674 && ( xStringResourceResolver == xCurrStringResourceResolver )
1677 Reference< XMultiPropertySet > xMultiPropSet( xPropertySet, UNO_QUERY );
1678 Reference< XPropertiesChangeListener > xListener( xPropertySet, UNO_QUERY );
1679 xMultiPropSet->firePropertiesChangeEvent( aPropNames, xListener );
1681 else
1682 xPropertySet->setPropertyValue( aPropName, aNewStringResourceResolver );
1684 catch (const Exception&)
1688 uno::Reference< XControlContainer > xNestedContainer( xControl, uno::UNO_QUERY );
1689 if ( xNestedContainer.is() )
1690 lcl_ApplyResolverToNestedContainees( xStringResourceResolver, xNestedContainer );
1695 void ControlContainerBase::ImplStartListingForResourceEvents()
1697 Reference< resource::XStringResourceResolver > xStringResourceResolver;
1699 if ( !ImplHasProperty(PROPERTY_RESOURCERESOLVER) )
1700 return;
1702 ImplGetPropertyValue( PROPERTY_RESOURCERESOLVER ) >>= xStringResourceResolver;
1704 // Add our helper as listener to retrieve notifications about changes
1705 Reference< util::XModifyListener > rListener( mxListener );
1706 ResourceListener* pResourceListener = static_cast< ResourceListener* >( rListener.get() );
1708 // resource listener will stop listening if resolver reference is empty
1709 if ( pResourceListener )
1710 pResourceListener->startListening( xStringResourceResolver );
1711 ImplUpdateResourceResolver();
1714 void ControlContainerBase::ImplUpdateResourceResolver()
1716 Reference< resource::XStringResourceResolver > xStringResourceResolver;
1718 if ( !ImplHasProperty(PROPERTY_RESOURCERESOLVER) )
1719 return;
1721 ImplGetPropertyValue(PROPERTY_RESOURCERESOLVER) >>= xStringResourceResolver;
1723 if ( !xStringResourceResolver.is() )
1724 return;
1726 lcl_ApplyResolverToNestedContainees( xStringResourceResolver, this );
1728 // propagate resource resolver changes to language dependent props of the dialog
1729 Reference< XPropertySet > xPropertySet( getModel(), UNO_QUERY );
1730 if ( xPropertySet.is() )
1732 Reference< XMultiPropertySet > xMultiPropSet( xPropertySet, UNO_QUERY );
1733 Reference< XPropertiesChangeListener > xListener( xPropertySet, UNO_QUERY );
1734 xMultiPropSet->firePropertiesChangeEvent( lcl_getLanguageDependentProperties(), xListener );
1738 //// ----------------------------------------------------
1739 //// Helper Method to convert relative url to physical location
1740 //// ----------------------------------------------------
1742 OUString getPhysicalLocation( const css::uno::Any& rbase, const css::uno::Any& rUrl )
1745 OUString baseLocation;
1746 OUString url;
1748 rbase >>= baseLocation;
1749 rUrl >>= url;
1751 OUString absoluteURL( url );
1752 if ( !url.isEmpty() )
1754 INetURLObject urlObj(baseLocation);
1755 urlObj.removeSegment();
1756 baseLocation = urlObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1758 const INetURLObject protocolCheck( url );
1759 const INetProtocol protocol = protocolCheck.GetProtocol();
1760 if ( protocol == INetProtocol::NotValid )
1762 OUString testAbsoluteURL;
1763 if ( ::osl::FileBase::E_None == ::osl::FileBase::getAbsoluteFileURL( baseLocation, url, testAbsoluteURL ) )
1764 absoluteURL = testAbsoluteURL;
1768 return absoluteURL;
1771 void
1772 ControlModelContainerBase::updateUserFormChildren( const Reference< XNameContainer >& xAllChildren, const OUString& aName, ChildOperation Operation, const css::uno::Reference< css::awt::XControlModel >& xTarget )
1774 if ( Operation < Insert || Operation > Remove )
1775 throw IllegalArgumentException();
1777 if ( !xAllChildren.is() )
1778 throw IllegalArgumentException();
1780 if ( Operation == Remove )
1782 Reference< XControlModel > xOldModel( xAllChildren->getByName( aName ), UNO_QUERY );
1783 xAllChildren->removeByName( aName );
1785 Reference< XNameContainer > xChildContainer( xOldModel, UNO_QUERY );
1786 if ( xChildContainer.is() )
1788 Reference< XPropertySet > xProps( xChildContainer, UNO_QUERY );
1789 // container control is being removed from this container, reset the
1790 // global list of containers
1791 if ( xProps.is() )
1792 xProps->setPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ), uno::Any( uno::Reference< XNameContainer >() ) );
1793 const Sequence< OUString > aChildNames = xChildContainer->getElementNames();
1794 for ( const auto& rName : aChildNames )
1795 updateUserFormChildren( xAllChildren, rName, Operation, Reference< XControlModel > () );
1798 else if ( Operation == Insert )
1800 xAllChildren->insertByName( aName, uno::Any( xTarget ) );
1801 Reference< XNameContainer > xChildContainer( xTarget, UNO_QUERY );
1802 if ( xChildContainer.is() )
1804 // container control is being added from this container, reset the
1805 // global list of containers to point to the correct global list
1806 Reference< XPropertySet > xProps( xChildContainer, UNO_QUERY );
1807 if ( xProps.is() )
1808 xProps->setPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ), uno::Any( xAllChildren ) );
1809 const Sequence< OUString > aChildNames = xChildContainer->getElementNames();
1810 for ( const auto& rName : aChildNames )
1812 Reference< XControlModel > xChildTarget( xChildContainer->getByName( rName ), UNO_QUERY );
1813 updateUserFormChildren( xAllChildren, rName, Operation, xChildTarget );
1820 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */