LibreOffice Module toolkit (master) 1
controlmodelcontainerbase.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
22#include <vcl/svapp.hxx>
23#include <o3tl/safeint.hxx>
24#include <osl/mutex.hxx>
25#include <helper/property.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>
38#include <cppuhelper/weak.hxx>
40#include <tools/debug.hxx>
42#include <vcl/outdev.hxx>
43#include <comphelper/types.hxx>
44
45#include "tree/treecontrol.hxx"
46#include "grid/gridcontrol.hxx"
48
49#include <map>
50#include <algorithm>
51#include <tools/urlobj.hxx>
52#include <osl/file.hxx>
53#include <sal/log.hxx>
55
58
59using namespace ::com::sun::star;
60using namespace ::com::sun::star::uno;
61using namespace ::com::sun::star::awt;
62using namespace ::com::sun::star::lang;
63using namespace ::com::sun::star::container;
64using namespace ::com::sun::star::beans;
65using namespace ::com::sun::star::util;
66using namespace toolkit;
67
68constexpr OUStringLiteral PROPERTY_RESOURCERESOLVER = u"ResourceResolver";
69
70
71namespace
72{
73 const Sequence< OUString >& lcl_getLanguageDependentProperties()
74 {
75 // note: properties must be sorted
76 static Sequence<OUString> s_aLanguageDependentProperties{ "HelpText", "Title" };
77 return s_aLanguageDependentProperties;
78 }
79
80// functor for disposing a control model
81struct DisposeControlModel
82{
83 void operator()( Reference< XControlModel >& _rxModel )
84 {
85 try
86 {
87 ::comphelper::disposeComponent( _rxModel );
88 }
89 catch (const Exception&)
90 {
91 TOOLS_WARN_EXCEPTION("toolkit", "caught an exception while disposing a component" );
92 }
93 }
94};
95
96}
97
98
99// functor for cloning a control model, and insertion into a target list
101{
102private:
104
105public:
107 :m_rTargetVector( _rTargetVector )
108 {
109 }
110
112 {
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 );
118 }
119};
120
121
122// functor for comparing a XControlModel with a given reference
124{
125private:
126 Reference< XControlModel > m_xReference;
127public:
128 explicit CompareControlModel( const Reference< XControlModel >& _rxReference ) : m_xReference( _rxReference ) { }
129
131 {
132 return _rCompare.first.get() == m_xReference.get();
133 }
134};
135
136
138{ // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this...
139 throw IllegalArgumentException();
140}
141
142
144{ // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this...
145 throw NoSuchElementException();
146}
147
148
150{ // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this...
151 throw ElementExistException();
152}
153
154
155static OUString getTabIndexPropertyName( )
156{
157 return "TabIndex";
158}
159
160
161static OUString getStepPropertyName( )
162{
163 return "Step";
164}
165
166
167
168ControlModelContainerBase::ControlModelContainerBase( const Reference< XComponentContext >& rxContext )
169 :ControlModelContainer_IBase( rxContext )
170 ,maContainerListeners( *this )
171 ,mbGroupsUpToDate( false )
172 ,m_nTabPageId(0)
173{
174 ImplRegisterProperty(BASEPROPERTY_ENABLED);
175}
176
179 , maContainerListeners( *this )
180 , mbGroupsUpToDate( false )
181 , m_nTabPageId( rModel.m_nTabPageId )
182{
183}
184
186{
187 maModels.clear();
188 mbGroupsUpToDate = false;
189}
190
192{
193 Any aAny;
194
195 switch ( nPropId )
196 {
198 aAny <<= OUString::createFromAscii( szServiceName_UnoControlDialog );
199 break;
200 default:
201 aAny = UnoControlModel::ImplGetDefaultValue( nPropId );
202 }
203
204 return aAny;
205}
206
208{
209 static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() );
210 return aHelper;
211}
212
214{
215
216 // tell our listeners
217 {
218 std::unique_lock aGuard( m_aMutex );
219
220 EventObject aDisposeEvent;
221 aDisposeEvent.Source = static_cast< XAggregation* >( static_cast< ::cppu::OWeakAggObject* >( this ) );
222
223 maContainerListeners.disposeAndClear( aGuard, aDisposeEvent );
224 maChangeListeners.disposeAndClear( aGuard, aDisposeEvent );
225 }
226
227
228 // call the base class
230
231
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() );
235
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
241 );
242
243 // now dispose
244 ::std::for_each( aChildModels.begin(), aChildModels.end(), DisposeControlModel() );
245 aChildModels.clear();
246
247 mbGroupsUpToDate = false;
248}
249
250// XMultiPropertySet
251Reference< XPropertySetInfo > ControlModelContainerBase::getPropertySetInfo( )
252{
253 static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
254 return xInfo;
255}
257{
258 // clone all children
259 ::std::for_each(
260 maModels.begin(), maModels.end(),
261 CloneControlModel( _rClone.maModels )
262 );
263}
265{
266 // clone the container itself
268 Clone_Impl(*pClone);
269
270 return pClone;
271}
272
273ControlModelContainerBase::UnoControlModelHolderVector::iterator ControlModelContainerBase::ImplFindElement( std::u16string_view rName )
274{
275 return ::std::find_if( maModels.begin(), maModels.end(), [&](const UnoControlModelHolder& elem) { return elem.second == rName; });
276}
277
278// ::XMultiServiceFactory
279Reference< XInterface > ControlModelContainerBase::createInstance( const OUString& aServiceSpecifier )
280{
281 SolarMutexGuard aGuard;
282
284
285 if ( aServiceSpecifier == "com.sun.star.awt.UnoControlEditModel" )
287 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFormattedFieldModel" )
289 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFileControlModel" )
291 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlButtonModel" )
293 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlImageControlModel" )
295 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlRadioButtonModel" )
297 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlCheckBoxModel" )
299 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFixedHyperlinkModel" )
301 else if ( aServiceSpecifier == "stardiv.vcl.controlmodel.FixedText" )
303 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlGroupBoxModel" )
305 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlListBoxModel" )
307 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlComboBoxModel" )
309 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlDateFieldModel" )
311 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlTimeFieldModel" )
313 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlNumericFieldModel" )
315 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlCurrencyFieldModel" )
317 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlPatternFieldModel" )
319 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlProgressBarModel" )
321 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlScrollBarModel" )
323 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFixedLineModel" )
325 else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlRoadmapModel" )
327 else if ( aServiceSpecifier == "com.sun.star.awt.tree.TreeControlModel" )
329 else if ( aServiceSpecifier == "com.sun.star.awt.grid.UnoControlGridModel" )
331 else if ( aServiceSpecifier == "com.sun.star.awt.tab.UnoControlTabPageContainerModel" )
333 else if ( aServiceSpecifier == "com.sun.star.awt.UnoMultiPageModel" )
335 else if ( aServiceSpecifier == "com.sun.star.awt.tab.UnoControlTabPageModel" )
337 else if ( aServiceSpecifier == "com.sun.star.awt.UnoPageModel" )
339 else if ( aServiceSpecifier == "com.sun.star.awt.UnoFrameModel" )
341
342 if ( !pNewModel )
343 {
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() )
349 {
350 if ( xSI->supportsService("com.sun.star.awt.UnoControlModel") )
351 {
352 // release 3 of the 4 references we have to the object
353 xAgg.clear();
354 xSI.clear();
355 xObject.clear();
356
357 pNewModel = new OCommonGeometryControlModel( xCloneAccess, aServiceSpecifier );
358 }
359 }
360 }
361
362 Reference< XInterface > xNewModel = static_cast<cppu::OWeakObject*>(pNewModel.get());
363 return xNewModel;
364}
365
366Reference< XInterface > ControlModelContainerBase::createInstanceWithArguments( const OUString& ServiceSpecifier, const Sequence< Any >& i_arguments )
367{
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;
373}
374
376{
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"
404 };
405}
406
407// XContainer
408void ControlModelContainerBase::addContainerListener( const Reference< XContainerListener >& l )
409{
410 maContainerListeners.addInterface( l );
411}
412
413void ControlModelContainerBase::removeContainerListener( const Reference< XContainerListener >& l )
414{
415 maContainerListeners.removeInterface( l );
416}
417
418// XElementAccess
420{
422 return aType;
423}
424
426{
427 return !maModels.empty();
428}
429
430// XNameContainer, XNameReplace, XNameAccess
431void ControlModelContainerBase::replaceByName( const OUString& aName, const Any& aElement )
432{
433 SolarMutexGuard aGuard;
434
435 Reference< XControlModel > xNewModel;
436 aElement >>= xNewModel;
437 if ( !xNewModel.is() )
439
440 UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName );
441 if ( maModels.end() == aElementPos )
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() )
451 {
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 );
456 }
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 );
463
464 ContainerEvent aEvent;
465 aEvent.Source = *this;
466 aEvent.Element = aElement;
467 aEvent.ReplacedElement <<= xReplaced;
468 aEvent.Accessor <<= aName;
469
470 // notify the container listener
471 maContainerListeners.elementReplaced( aEvent );
472
473 // our "tab controller model" has potentially changed -> notify this
475}
476
478{
479 UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName );
480 if ( maModels.end() == aElementPos )
482
483 return Any( aElementPos->first );
484}
485
487{
488 Sequence< OUString > aNames( maModels.size() );
489
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)
495 );
496
497 return aNames;
498}
499
501{
502 return maModels.end() != ImplFindElement( aName );
503}
504
505void ControlModelContainerBase::insertByName( const OUString& aName, const Any& aElement )
506{
507 SolarMutexGuard aGuard;
508
509 Reference< XControlModel > xM;
510 aElement >>= xM;
511
512 if ( xM.is() )
513 {
514 Reference< beans::XPropertySet > xProps( xM, UNO_QUERY );
515 if ( xProps.is() )
516 {
517
518 Reference< beans::XPropertySetInfo > xPropInfo = xProps->getPropertySetInfo();
519
520 const OUString& sImageSourceProperty = GetPropertyName( BASEPROPERTY_IMAGEURL );
521 if ( xPropInfo->hasPropertyByName( sImageSourceProperty ) && ImplHasProperty(BASEPROPERTY_DIALOGSOURCEURL) )
522 {
523 Any aUrl = xProps->getPropertyValue( sImageSourceProperty );
524
525 OUString absoluteUrl =
527
528 aUrl <<= absoluteUrl;
529
530 xProps->setPropertyValue( sImageSourceProperty , aUrl );
531 }
532 }
533 }
534
535
536 if ( aName.isEmpty() || !xM.is() )
538
539 UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName );
540 if ( maModels.end() != aElementPos )
542
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 );
551
552 if ( xAllChildren.is() )
553 updateUserFormChildren( xAllChildren, aName, Insert, xM );
554 maModels.emplace_back( xM, aName );
555 mbGroupsUpToDate = false;
557
558 ContainerEvent aEvent;
559 aEvent.Source = *this;
560 aEvent.Element = aElement;
561 aEvent.Accessor <<= aName;
562 maContainerListeners.elementInserted( aEvent );
563
564 // our "tab controller model" has potentially changed -> notify this
566}
567
568void ControlModelContainerBase::removeByName( const OUString& aName )
569{
570 SolarMutexGuard aGuard;
571
572 UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName );
573 if ( maModels.end() == aElementPos )
575
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 >() );
584
585 ContainerEvent aEvent;
586 aEvent.Source = *this;
587 aEvent.Element <<= aElementPos->first;
588 aEvent.Accessor <<= aName;
589 maContainerListeners.elementRemoved( aEvent );
590
591 stopControlListening( aElementPos->first );
592 Reference< XPropertySet > xPS( aElementPos->first, UNO_QUERY );
593 maModels.erase( aElementPos );
594 mbGroupsUpToDate = false;
595
596 if ( xPS.is() )
597 {
598 try
599 {
600 xPS->setPropertyValue( PROPERTY_RESOURCERESOLVER, Any( Reference< resource::XStringResourceResolver >() ) );
601 }
602 catch (const Exception&)
603 {
604 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
605 }
606 }
607
608 // our "tab controller model" has potentially changed -> notify this
610}
611
612
614{
615 return true;
616}
617
618
620{
621 SAL_WARN("toolkit", "explicit grouping not supported" );
622}
623
624
625void SAL_CALL ControlModelContainerBase::setControlModels( const Sequence< Reference< XControlModel > >& _rControls )
626{
627 SolarMutexGuard aGuard;
628
629 // set the tab indexes according to the order of models in the sequence
630
631 sal_Int16 nTabIndex = 1;
632
633 for ( auto const & control : _rControls )
634 {
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 )
640 );
641 if ( maModels.end() != aPos )
642 {
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++ ) );
651 }
652 mbGroupsUpToDate = false;
653 }
654}
655
656
657typedef ::std::multimap< sal_Int32, Reference< XControlModel > > MapIndexToModel;
658
659
660Sequence< Reference< XControlModel > > SAL_CALL ControlModelContainerBase::getControlModels( )
661{
662 SolarMutexGuard aGuard;
663
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
668
669 for ( const auto& rModel : maModels )
670 {
671 Reference< XControlModel > xModel( rModel.first );
672
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!" );
679
680 // has it?
681 if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) )
682 { // yes
683 sal_Int32 nTabIndex = -1;
684 xControlProps->getPropertyValue( getTabIndexPropertyName() ) >>= nTabIndex;
685
686 aSortedModels.emplace( nTabIndex, xModel );
687 }
688 else if ( xModel.is() )
689 // no, it hasn't, but we have to include it, anyway
690 aUnindexedModels.push_back( xModel );
691 }
692
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; }
702 );
703
704 return aReturn;
705}
706
707
708void SAL_CALL ControlModelContainerBase::setGroup( const Sequence< Reference< XControlModel > >&, const OUString& )
709{
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" );
715}
716
718void SAL_CALL ControlModelContainerBase::initialize (const Sequence<Any>& rArguments)
719{
720 if ( rArguments.getLength() == 1 )
721 {
722 sal_Int16 nPageId = -1;
723 if ( !( rArguments[ 0 ] >>= nPageId ))
724 throw lang::IllegalArgumentException();
726 }
727 else
728 m_nTabPageId = -1;
729}
731{
732 return m_nTabPageId;
733}
735{
736 SolarMutexGuard aGuard;
737 bool bEnabled = false;
739 return bEnabled;
740}
742{
743 SolarMutexGuard aGuard;
745}
747{
748 SolarMutexGuard aGuard;
749 OUString sTitle;
751 return sTitle;
752}
753void SAL_CALL ControlModelContainerBase::setTitle( const OUString& _title )
754{
755 SolarMutexGuard aGuard;
757}
759{
760 return m_sImageURL;
761}
762void SAL_CALL ControlModelContainerBase::setImageURL( const OUString& _imageurl )
763{
764 m_sImageURL = _imageurl;
765 SolarMutexGuard aGuard;
767}
769{
770 return m_sTooltip;
771}
772void SAL_CALL ControlModelContainerBase::setToolTip( const OUString& _tooltip )
773{
774 m_sTooltip = _tooltip;
775}
776
777
778namespace
779{
780 enum GroupingMachineState
781 {
782 eLookingForGroup,
783 eExpandingGroup
784 };
785
786
787 sal_Int32 lcl_getDialogStep( const Reference< XControlModel >& _rxModel )
788 {
789 sal_Int32 nStep = 0;
790 try
791 {
792 Reference< XPropertySet > xModelProps( _rxModel, UNO_QUERY );
793 xModelProps->getPropertyValue( getStepPropertyName() ) >>= nStep;
794 }
795 catch (const Exception&)
796 {
797 TOOLS_WARN_EXCEPTION("toolkit", "caught an exception while determining the dialog page" );
798 }
799 return nStep;
800 }
801}
802
803
805{
806 SolarMutexGuard aGuard;
807
809
810 return maGroups.size();
811}
812
813
814void SAL_CALL ControlModelContainerBase::getGroup( sal_Int32 _nGroup, Sequence< Reference< XControlModel > >& _rGroup, OUString& _rName )
815{
816 SolarMutexGuard aGuard;
817
819
820 if ( ( _nGroup < 0 ) || ( o3tl::make_unsigned(_nGroup) >= maGroups.size() ) )
821 {
822 SAL_WARN("toolkit", "invalid argument and I am not allowed to throw exception!" );
823 _rGroup.realloc( 0 );
824 _rName.clear();
825 }
826 else
827 {
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 );
834 }
835}
836
837
838void SAL_CALL ControlModelContainerBase::getGroupByName( const OUString& _rName, Sequence< Reference< XControlModel > >& _rGroup )
839{
840 SolarMutexGuard aGuard;
841
842 OUString sDummyName;
843 getGroup( _rName.toInt32( ), _rGroup, sDummyName );
844}
845
846
847void SAL_CALL ControlModelContainerBase::addChangesListener( const Reference< XChangesListener >& _rxListener )
848{
849 std::unique_lock g(m_aMutex);
850 maChangeListeners.addInterface( g, _rxListener );
851}
852
853
854void SAL_CALL ControlModelContainerBase::removeChangesListener( const Reference< XChangesListener >& _rxListener )
855{
856 std::unique_lock g(m_aMutex);
857 maChangeListeners.removeInterface( g, _rxListener );
858}
859
860
862{
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;
870
871
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 );
877}
878
879
881{
882 if ( mbGroupsUpToDate )
883 // nothing to do
884 return;
885
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
890
891 maGroups.clear();
892
893 const Sequence< Reference< XControlModel > > aControlModels = getControlModels();
894
895 // in extreme we have as much groups as controls
896 maGroups.reserve( aControlModels.getLength() );
897
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
902
903
904 for ( const Reference< XControlModel >& rControlModel : aControlModels )
905 {
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" );
910
911 switch ( eState )
912 {
913 case eLookingForGroup:
914 {
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 );
926
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;
931
932 }
933 break;
934
935 case eExpandingGroup:
936 {
937 if ( !bIsRadioButton )
938 { // no radio button -> the group is done
939 aCurrentGroup = maGroups.end();
940 eState = eLookingForGroup;
941 continue;
942 }
943
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
948 )
949 {
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;
954
955 continue;
956 }
957
958 // it's a radio button, but on a different page
959 // -> we open a new group for it
960
961
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 );
968
969 nCurrentGroupStep = nThisModelStep;
970
971 // state is the same: we still are looking for further elements of the current group
972 eState = eExpandingGroup;
973 }
974 break;
975 }
976 }
977
978 mbGroupsUpToDate = true;
979}
980
981
982void SAL_CALL ControlModelContainerBase::propertyChange( const PropertyChangeEvent& _rEvent )
983{
984 SolarMutexGuard aGuard;
985
986 DBG_ASSERT( _rEvent.PropertyName == "TabIndex",
987 "ControlModelContainerBase::propertyChange: not listening for this property!" );
988
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 ) )
995 );
996 OSL_ENSURE( maModels.end() != aPos, "ControlModelContainerBase::propertyChange: don't know this model!" );
997 if ( maModels.end() != aPos )
998 sAccessor = aPos->second;
999
1000 // our groups are not up-to-date
1001 mbGroupsUpToDate = false;
1002
1003 // notify
1004 implNotifyTabModelChange( sAccessor );
1005}
1006
1007
1008void SAL_CALL ControlModelContainerBase::disposing( const EventObject& /*rEvent*/ )
1009{
1010}
1011
1012
1013void ControlModelContainerBase::startControlListening( const Reference< XControlModel >& _rxChildModel )
1014{
1015 SolarMutexGuard aGuard;
1016
1017 Reference< XPropertySet > xModelProps( _rxChildModel, UNO_QUERY );
1018 Reference< XPropertySetInfo > xPSI;
1019 if ( xModelProps.is() )
1020 xPSI = xModelProps->getPropertySetInfo();
1021
1022 if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) )
1023 xModelProps->addPropertyChangeListener( getTabIndexPropertyName(), this );
1024}
1025
1026
1027void ControlModelContainerBase::stopControlListening( const Reference< XControlModel >& _rxChildModel )
1028{
1029 SolarMutexGuard aGuard;
1030
1031 Reference< XPropertySet > xModelProps( _rxChildModel, UNO_QUERY );
1032 Reference< XPropertySetInfo > xPSI;
1033 if ( xModelProps.is() )
1034 xPSI = xModelProps->getPropertySetInfo();
1035
1036 if ( xPSI.is() && xPSI->hasPropertyByName( getTabIndexPropertyName() ) )
1037 xModelProps->removePropertyChangeListener( getTabIndexPropertyName(), this );
1038}
1039
1040
1041// = class ResourceListener
1042
1043
1045 const Reference< util::XModifyListener >& rListener ) :
1046 m_xListener( rListener ),
1047 m_bListening( false )
1048{
1049}
1050
1052{
1053}
1054
1055// XInterface
1057{
1058 Any a = ::cppu::queryInterface(
1059 rType ,
1060 static_cast< XModifyListener* >( this ),
1061 static_cast< XEventListener* >( this ));
1062
1063 if ( a.hasValue() )
1064 return a;
1065
1066 return OWeakObject::queryInterface( rType );
1067}
1068
1069void SAL_CALL ResourceListener::acquire() noexcept
1070{
1071 OWeakObject::acquire();
1072}
1073
1074void SAL_CALL ResourceListener::release() noexcept
1075{
1076 OWeakObject::release();
1077}
1078
1080 const Reference< resource::XStringResourceResolver >& rResource )
1081{
1082 {
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 ---
1089
1090 if ( bListening && bResourceSet )
1091 stopListening();
1092
1093 // --- SAFE ---
1094 aGuard.lock();
1095 m_xResource = rResource;
1096 aGuard.unlock();
1097 // --- SAFE ---
1098 }
1099
1100 if ( !rResource.is() )
1101 return;
1102
1103 try
1104 {
1105 rResource->addModifyListener( this );
1106
1107 // --- SAFE ---
1108 std::scoped_lock aGuard( m_aMutex );
1109 m_bListening = true;
1110 // --- SAFE ---
1111 }
1112 catch (const RuntimeException&)
1113 {
1114 throw;
1115 }
1116 catch (const Exception&)
1117 {
1118 }
1119}
1120
1122{
1123 Reference< util::XModifyBroadcaster > xModifyBroadcaster;
1124
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 ---
1131
1132 if ( !xModifyBroadcaster.is() )
1133 return;
1134
1135 try
1136 {
1137 // --- SAFE ---
1138 aGuard.lock();
1139 m_bListening = false;
1140 m_xResource.clear();
1141 aGuard.unlock();
1142 // --- SAFE ---
1143
1144 xModifyBroadcaster->removeModifyListener( this );
1145 }
1146 catch (const RuntimeException&)
1147 {
1148 throw;
1149 }
1150 catch (const Exception&)
1151 {
1152 }
1153}
1154
1155// XModifyListener
1157 const lang::EventObject& aEvent )
1158{
1159 Reference< util::XModifyListener > xListener;
1160
1161 // --- SAFE ---
1162 std::unique_lock aGuard( m_aMutex );
1163 xListener = m_xListener;
1164 aGuard.unlock();
1165 // --- SAFE ---
1166
1167 if ( !xListener.is() )
1168 return;
1169
1170 try
1171 {
1172 xListener->modified( aEvent );
1173 }
1174 catch (const RuntimeException&)
1175 {
1176 throw;
1177 }
1178 catch (const Exception&)
1179 {
1180 }
1181}
1182
1183// XEventListener
1185 const EventObject& Source )
1186{
1187 Reference< lang::XEventListener > xListener;
1188 Reference< resource::XStringResourceResolver > xResource;
1189
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 ---
1196
1197 if ( Source.Source == xIfacRes )
1198 {
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 ---
1207
1208 if ( xListener.is() )
1209 {
1210 try
1211 {
1212 xListener->disposing( Source );
1213 }
1214 catch (const RuntimeException&)
1215 {
1216 throw;
1217 }
1218 catch (const Exception&)
1219 {
1220 }
1221 }
1222 }
1223 else if ( Source.Source == xIfacList )
1224 {
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 ---
1234
1235 // Remove ourself as listener from resource resolver
1236 if ( xResource.is() )
1237 {
1238 try
1239 {
1240 xResource->removeModifyListener( this );
1241 }
1242 catch (const RuntimeException&)
1243 {
1244 throw;
1245 }
1246 catch (const Exception&)
1247 {
1248 }
1249 }
1250 }
1251}
1252
1253
1254
1255ControlContainerBase::ControlContainerBase( const Reference< XComponentContext >& rxContext )
1256 :m_xContext(rxContext)
1257 ,mbSizeModified(false)
1258 ,mbPosModified(false)
1259{
1260 maComponentInfos.nWidth = 280;
1261 maComponentInfos.nHeight = 400;
1262 mxListener = new ResourceListener( Reference< util::XModifyListener >(this) );
1263}
1264
1266{
1267}
1268
1269void ControlContainerBase::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer )
1270{
1271 SolarMutexGuard aGuard;
1272 UnoControlContainer::createPeer( rxToolkit, rParentPeer );
1273}
1274
1275void ControlContainerBase::ImplInsertControl( Reference< XControlModel > const & rxModel, const OUString& rName )
1276{
1277 Reference< XPropertySet > xP( rxModel, UNO_QUERY );
1278
1279 OUString aDefCtrl;
1280 xP->getPropertyValue( GetPropertyName( BASEPROPERTY_DEFAULTCONTROL ) ) >>= aDefCtrl;
1281 Reference < XControl > xCtrl( m_xContext->getServiceManager()->createInstanceWithContext(aDefCtrl, m_xContext), UNO_QUERY );
1282
1283 DBG_ASSERT( xCtrl.is(), "ControlContainerBase::ImplInsertControl: could not create the control!" );
1284 if ( xCtrl.is() )
1285 {
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
1291
1292 ImplSetPosSize( xCtrl );
1293 }
1294}
1295
1296void ControlContainerBase::ImplRemoveControl( Reference< XControlModel > const & rxModel )
1297{
1298 Sequence< Reference< XControl > > aControls = getControls();
1299 Reference< XControl > xCtrl = StdTabController::FindControl( aControls, rxModel );
1300 if ( xCtrl.is() )
1301 {
1302 removeControl( xCtrl );
1303 try
1304 {
1305 xCtrl->dispose();
1306 }
1307 catch (const Exception&)
1308 {
1309 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1310 }
1311 }
1312}
1313
1314void ControlContainerBase::ImplSetPosSize( Reference< XControl >& rxCtrl )
1315{
1316 Reference< XPropertySet > xP( rxCtrl->getModel(), UNO_QUERY );
1317
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 );
1325 if ( pOutDev )
1326 {
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();
1335 }
1336 else
1337 {
1338 Reference< XWindowPeer > xPeer = ImplGetCompatiblePeer();
1339 Reference< XDevice > xD( xPeer, UNO_QUERY );
1340
1341 SimpleFontMetric aFM;
1342 FontDescriptor aFD;
1343 Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_FONTDESCRIPTOR ) );
1344 aVal >>= aFD;
1345 if ( !aFD.StyleName.isEmpty() )
1346 {
1347 Reference< XFont > xFont = xD->getFont( aFD );
1348 aFM = xFont->getFontMetric();
1349 }
1350 else
1351 {
1352 Reference< XGraphics > xG = xD->createGraphics();
1353 aFM = xG->getFontMetric();
1354 }
1355
1356 sal_Int16 nH = aFM.Ascent + aFM.Descent;
1357 sal_Int16 nW = nH/2; // calculate average width?!
1358
1359 nX *= nW;
1360 nX /= 4;
1361 nWidth *= nW;
1362 nWidth /= 4;
1363 nY *= nH;
1364 nY /= 8;
1365 nHeight *= nH;
1366 nHeight /= 8;
1367 }
1368 Reference < XWindow > xW( rxCtrl, UNO_QUERY );
1369 xW->setPosSize( nX, nY, nWidth, nHeight, PosSize::POSSIZE );
1370}
1371
1373{
1374 EventObject aEvt;
1375 aEvt.Source = static_cast< ::cppu::OWeakObject* >( this );
1376 // Notify our listener helper about dispose
1377 // --- SAFE ---
1378
1380 Reference< XEventListener > xListener = mxListener;
1381 mxListener.clear();
1382 aGuard.clear();
1383 // --- SAFE ---
1384
1385 if ( xListener.is() )
1386 xListener->disposing( aEvt );
1388}
1389
1391 const EventObject& Source )
1392{
1394}
1395
1396sal_Bool ControlContainerBase::setModel( const Reference< XControlModel >& rxModel )
1397{
1398 SolarMutexGuard aGuard;
1399
1400 // destroy the old tab controller, if existent
1401 if ( mxTabController.is() )
1402 {
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();
1407 }
1408
1409 if ( getModel().is() )
1410 {
1411 const Sequence< Reference< XControl > > aControls = getControls();
1412
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
1418
1419 Reference< XContainer > xC( getModel(), UNO_QUERY );
1420 if ( xC.is() )
1421 xC->removeContainerListener( this );
1422
1423 Reference< XChangesNotifier > xChangeNotifier( getModel(), UNO_QUERY );
1424 if ( xChangeNotifier.is() )
1425 xChangeNotifier->removeChangesListener( this );
1426 }
1427
1428 bool bRet = UnoControl::setModel( rxModel );
1429
1430 if ( getModel().is() )
1431 {
1432 Reference< XNameAccess > xNA( getModel(), UNO_QUERY );
1433 if ( xNA.is() )
1434 {
1435 const Sequence< OUString > aNames = xNA->getElementNames();
1436
1437 Reference< XControlModel > xCtrlModel;
1438 for( const OUString& rName : aNames )
1439 {
1440 xNA->getByName( rName ) >>= xCtrlModel;
1441 ImplInsertControl( xCtrlModel, rName );
1442 }
1443 }
1444
1445 Reference< XContainer > xC( getModel(), UNO_QUERY );
1446 if ( xC.is() )
1447 xC->addContainerListener( this );
1448
1449 Reference< XChangesNotifier > xChangeNotifier( getModel(), UNO_QUERY );
1450 if ( xChangeNotifier.is() )
1451 xChangeNotifier->addChangesListener( this );
1452 }
1453
1454 Reference< XTabControllerModel > xTabbing( getModel(), UNO_QUERY );
1455 if ( xTabbing.is() )
1456 {
1458 mxTabController->setModel( xTabbing );
1459 addTabController( mxTabController );
1460 }
1462
1463 return bRet;
1464}
1466{
1467 SolarMutexGuard aGuard;
1468
1470
1471 Sequence< Reference< XControl > > xCtrls = getControls();
1472 for ( Reference< XControl >& rControl : asNonConstRange(xCtrls) )
1473 rControl->setDesignMode( bOn );
1474
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();
1480}
1481
1482void ControlContainerBase::elementInserted( const ContainerEvent& Event )
1483{
1484 SolarMutexGuard aGuard;
1485
1486 Reference< XControlModel > xModel;
1487 OUString aName;
1488
1489 Event.Accessor >>= aName;
1490 Event.Element >>= xModel;
1491 ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementInserted: illegal element!" );
1492 try
1493 {
1495 }
1496 catch (const RuntimeException&)
1497 {
1498 throw;
1499 }
1500 catch (const Exception&)
1501 {
1502 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1503 }
1504}
1505
1506void ControlContainerBase::elementRemoved( const ContainerEvent& Event )
1507{
1508 SolarMutexGuard aGuard;
1509
1510 Reference< XControlModel > xModel;
1511 Event.Element >>= xModel;
1512 ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementRemoved: illegal element!" );
1513 try
1514 {
1516 }
1517 catch (const RuntimeException&)
1518 {
1519 throw;
1520 }
1521 catch (const Exception&)
1522 {
1523 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1524 }
1525}
1526
1527void ControlContainerBase::elementReplaced( const ContainerEvent& Event )
1528{
1529 SolarMutexGuard aGuard;
1530
1531 Reference< XControlModel > xModel;
1532 Event.ReplacedElement >>= xModel;
1533 try
1534 {
1535 OSL_ENSURE( xModel.is(), "ControlContainerBase::elementReplaced: invalid ReplacedElement!" );
1536 if ( xModel.is() )
1538 }
1539 catch (const RuntimeException&)
1540 {
1541 throw;
1542 }
1543 catch (const Exception&)
1544 {
1545 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1546 }
1547
1548 OUString aName;
1549 Event.Accessor >>= aName;
1550 Event.Element >>= xModel;
1551 ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementReplaced: invalid new element!" );
1552 try
1553 {
1555 }
1556 catch (const RuntimeException&)
1557 {
1558 throw;
1559 }
1560 catch (const Exception&)
1561 {
1562 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1563 }
1564}
1565
1566// XPropertiesChangeListener
1567void ControlContainerBase::ImplModelPropertiesChanged( const Sequence< PropertyChangeEvent >& rEvents )
1568{
1569 if( !isDesignMode() && !mbCreatingCompatiblePeer )
1570 {
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";
1577 });
1578 if (pEvt != rEvents.end())
1579 {
1580 Reference< XControlModel > xModel( pEvt->Source, UNO_QUERY );
1581 bool bOwnModel = xModel.get() == getModel().get();
1582 if ( bOwnModel )
1583 {
1584 if ( !mbPosModified && !mbSizeModified )
1585 {
1586 // Don't set new pos/size if we get new values from window listener
1587 Reference< XControl > xThis(this);
1588 ImplSetPosSize( xThis );
1589 }
1590 }
1591 else
1592 {
1593 Sequence<Reference<XControl> > aControlSequence(getControls());
1594 Reference<XControl> aControlRef( StdTabController::FindControl( aControlSequence, xModel ) );
1595 ImplSetPosSize( aControlRef );
1596 }
1597 }
1598 }
1599
1600 UnoControlContainer::ImplModelPropertiesChanged( rEvents );
1601}
1602
1603void ControlContainerBase::addingControl( const Reference< XControl >& _rxControl )
1604{
1605 SolarMutexGuard aGuard;
1607
1608 if ( !_rxControl.is() )
1609 return;
1610
1611 Reference< XMultiPropertySet > xProps( _rxControl->getModel(), UNO_QUERY );
1612 if ( xProps.is() )
1613 {
1614 const Sequence< OUString > aNames {
1615 "PositionX",
1616 "PositionY",
1617 "Width",
1618 "Height"
1619 };
1620
1621 xProps->addPropertiesChangeListener( aNames, this );
1622 }
1623}
1624
1625void ControlContainerBase::removingControl( const Reference< XControl >& _rxControl )
1626{
1627 SolarMutexGuard aGuard;
1629
1630 if ( _rxControl.is() )
1631 {
1632 Reference< XMultiPropertySet > xProps( _rxControl->getModel(), UNO_QUERY );
1633 if ( xProps.is() )
1634 xProps->removePropertiesChangeListener( this );
1635 }
1636
1637}
1638
1639void SAL_CALL ControlContainerBase::changesOccurred( const ChangesEvent& )
1640{
1641 SolarMutexGuard aGuard;
1642 // a tab controller model may have changed
1643
1644 // #109067# in design mode don't notify the tab controller
1645 // about tab index changes
1646 if ( mxTabController.is() && !mbDesignMode )
1647 mxTabController->activateTabOrder();
1648}
1649static void lcl_ApplyResolverToNestedContainees( const Reference< resource::XStringResourceResolver >& xStringResourceResolver, const Reference< XControlContainer >& xContainer )
1650{
1652
1653 Any aNewStringResourceResolver;
1654 aNewStringResourceResolver <<= xStringResourceResolver;
1655
1656 Sequence< OUString > aPropNames { aPropName };
1657
1658 const Sequence< Reference< awt::XControl > > aSeq = xContainer->getControls();
1659 for ( const Reference< XControl >& xControl : aSeq )
1660 {
1661 Reference< XPropertySet > xPropertySet;
1662
1663 if ( xControl.is() )
1664 xPropertySet.set( xControl->getModel(), UNO_QUERY );
1665
1666 if ( !xPropertySet.is() )
1667 continue;
1668
1669 try
1670 {
1671 Reference< resource::XStringResourceResolver > xCurrStringResourceResolver;
1672 Any aOldValue = xPropertySet->getPropertyValue( aPropName );
1673 if ( ( aOldValue >>= xCurrStringResourceResolver )
1674 && ( xStringResourceResolver == xCurrStringResourceResolver )
1675 )
1676 {
1677 Reference< XMultiPropertySet > xMultiPropSet( xPropertySet, UNO_QUERY );
1678 Reference< XPropertiesChangeListener > xListener( xPropertySet, UNO_QUERY );
1679 xMultiPropSet->firePropertiesChangeEvent( aPropNames, xListener );
1680 }
1681 else
1682 xPropertySet->setPropertyValue( aPropName, aNewStringResourceResolver );
1683 }
1684 catch (const Exception&)
1685 {
1686 }
1687
1688 uno::Reference< XControlContainer > xNestedContainer( xControl, uno::UNO_QUERY );
1689 if ( xNestedContainer.is() )
1690 lcl_ApplyResolverToNestedContainees( xStringResourceResolver, xNestedContainer );
1691
1692 }
1693
1694}
1696{
1697 Reference< resource::XStringResourceResolver > xStringResourceResolver;
1698
1699 if ( !ImplHasProperty(PROPERTY_RESOURCERESOLVER) )
1700 return;
1701
1702 ImplGetPropertyValue( PROPERTY_RESOURCERESOLVER ) >>= xStringResourceResolver;
1703
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() );
1707
1708 // resource listener will stop listening if resolver reference is empty
1709 if ( pResourceListener )
1710 pResourceListener->startListening( xStringResourceResolver );
1712}
1713
1715{
1716 Reference< resource::XStringResourceResolver > xStringResourceResolver;
1717
1718 if ( !ImplHasProperty(PROPERTY_RESOURCERESOLVER) )
1719 return;
1720
1721 ImplGetPropertyValue(PROPERTY_RESOURCERESOLVER) >>= xStringResourceResolver;
1722
1723 if ( !xStringResourceResolver.is() )
1724 return;
1725
1726 lcl_ApplyResolverToNestedContainees( xStringResourceResolver, this );
1727
1728 // propagate resource resolver changes to language dependent props of the dialog
1729 Reference< XPropertySet > xPropertySet( getModel(), UNO_QUERY );
1730 if ( xPropertySet.is() )
1731 {
1732 Reference< XMultiPropertySet > xMultiPropSet( xPropertySet, UNO_QUERY );
1733 Reference< XPropertiesChangeListener > xListener( xPropertySet, UNO_QUERY );
1734 xMultiPropSet->firePropertiesChangeEvent( lcl_getLanguageDependentProperties(), xListener );
1735 }
1736}
1737
1741
1742OUString getPhysicalLocation( const css::uno::Any& rbase, const css::uno::Any& rUrl )
1743{
1744
1745 OUString baseLocation;
1746 OUString url;
1747
1748 rbase >>= baseLocation;
1749 rUrl >>= url;
1750
1751 OUString absoluteURL( url );
1752 if ( !url.isEmpty() )
1753 {
1754 INetURLObject urlObj(baseLocation);
1755 urlObj.removeSegment();
1756 baseLocation = urlObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1757
1758 const INetURLObject protocolCheck( url );
1759 const INetProtocol protocol = protocolCheck.GetProtocol();
1760 if ( protocol == INetProtocol::NotValid )
1761 {
1762 OUString testAbsoluteURL;
1763 if ( ::osl::FileBase::E_None == ::osl::FileBase::getAbsoluteFileURL( baseLocation, url, testAbsoluteURL ) )
1764 absoluteURL = testAbsoluteURL;
1765 }
1766 }
1767
1768 return absoluteURL;
1769}
1770
1771void
1772ControlModelContainerBase::updateUserFormChildren( const Reference< XNameContainer >& xAllChildren, const OUString& aName, ChildOperation Operation, const css::uno::Reference< css::awt::XControlModel >& xTarget )
1773{
1775 throw IllegalArgumentException();
1776
1777 if ( !xAllChildren.is() )
1778 throw IllegalArgumentException();
1779
1780 if ( Operation == Remove )
1781 {
1782 Reference< XControlModel > xOldModel( xAllChildren->getByName( aName ), UNO_QUERY );
1783 xAllChildren->removeByName( aName );
1784
1785 Reference< XNameContainer > xChildContainer( xOldModel, UNO_QUERY );
1786 if ( xChildContainer.is() )
1787 {
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 > () );
1796 }
1797 }
1798 else if ( Operation == Insert )
1799 {
1800 xAllChildren->insertByName( aName, uno::Any( xTarget ) );
1801 Reference< XNameContainer > xChildContainer( xTarget, UNO_QUERY );
1802 if ( xChildContainer.is() )
1803 {
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 )
1811 {
1812 Reference< XControlModel > xChildTarget( xChildContainer->getByName( rName ), UNO_QUERY );
1813 updateUserFormChildren( xAllChildren, rName, Operation, xChildTarget );
1814 }
1815 }
1816 }
1817
1818}
1819
1820/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XComponentContext > m_xContext
AnyEventRef aEvent
sal_uInt16 nPageId
static OutputDevice * GetDefaultDevice()
void SAL_CALL elementInserted(const css::container::ContainerEvent &Event) override
void ImplInsertControl(css::uno::Reference< css::awt::XControlModel > const &rxModel, const OUString &rName)
void SAL_CALL createPeer(const css::uno::Reference< css::awt::XToolkit > &Toolkit, const css::uno::Reference< css::awt::XWindowPeer > &Parent) override
ControlContainerBase(const css::uno::Reference< css::uno::XComponentContext > &rxContext)
css::uno::Reference< css::awt::XTabController > mxTabController
void SAL_CALL elementRemoved(const css::container::ContainerEvent &Event) override
virtual void ImplSetPosSize(css::uno::Reference< css::awt::XControl > &rxCtrl)
void SAL_CALL elementReplaced(const css::container::ContainerEvent &Event) override
css::uno::Reference< css::util::XModifyListener > mxListener
virtual void addingControl(const css::uno::Reference< css::awt::XControl > &_rxControl) override
void ImplRemoveControl(css::uno::Reference< css::awt::XControlModel > const &rxModel)
css::uno::Reference< css::uno::XComponentContext > m_xContext
virtual ~ControlContainerBase() override
void SAL_CALL dispose() override
virtual void SAL_CALL changesOccurred(const css::util::ChangesEvent &Event) override
virtual void ImplModelPropertiesChanged(const css::uno::Sequence< css::beans::PropertyChangeEvent > &rEvents) override
sal_Bool SAL_CALL setModel(const css::uno::Reference< css::awt::XControlModel > &Model) override
void SAL_CALL disposing(const css::lang::EventObject &Source) override
virtual void removingControl(const css::uno::Reference< css::awt::XControl > &_rxControl) override
void SAL_CALL setDesignMode(sal_Bool bOn) override
virtual void SAL_CALL addChangesListener(const css::uno::Reference< css::util::XChangesListener > &aListener) override
UnoControlModelHolderVector maModels
sal_Bool SAL_CALL hasByName(const OUString &aName) override
virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > &rArguments) override
css::uno::Any SAL_CALL getByName(const OUString &aName) override
css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
virtual void SAL_CALL setToolTip(const OUString &_tooltip) override
virtual OUString SAL_CALL getTitle() override
ContainerListenerMultiplexer maContainerListeners
virtual void SAL_CALL setControlModels(const css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > &Controls) override
virtual void SAL_CALL setGroupControl(sal_Bool GroupControl) override
void updateUserFormChildren(const css::uno::Reference< css::container::XNameContainer > &xAllChildren, const OUString &aName, ChildOperation Operation, const css::uno::Reference< css::awt::XControlModel > &xTarget)
sal_Bool SAL_CALL hasElements() override
virtual sal_Bool SAL_CALL getEnabled() override
void SAL_CALL replaceByName(const OUString &aName, const css::uno::Any &aElement) override
void SAL_CALL insertByName(const OUString &aName, const css::uno::Any &aElement) override
void stopControlListening(const css::uno::Reference< css::awt::XControlModel > &_rxChildModel)
virtual void SAL_CALL getGroup(sal_Int32 nGroup, css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > &Group, OUString &Name) override
void Clone_Impl(ControlModelContainerBase &_rClone) const
void implNotifyTabModelChange(const OUString &_rAccessor)
void SAL_CALL addContainerListener(const css::uno::Reference< css::container::XContainerListener > &xListener) override
::cppu::IPropertyArrayHelper & getInfoHelper() override
void SAL_CALL removeByName(const OUString &Name) override
virtual sal_Int32 SAL_CALL getGroupCount() override
css::uno::Sequence< OUString > SAL_CALL getAvailableServiceNames() override
virtual OUString SAL_CALL getToolTip() override
virtual void SAL_CALL setEnabled(sal_Bool _enabled) override
virtual void SAL_CALL removeChangesListener(const css::uno::Reference< css::util::XChangesListener > &aListener) override
css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments(const OUString &ServiceSpecifier, const css::uno::Sequence< css::uno::Any > &Arguments) override
virtual void SAL_CALL setGroup(const css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > &Group, const OUString &GroupName) override
virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent &evt) override
::comphelper::OInterfaceContainerHelper4< css::util::XChangesListener > maChangeListeners
css::uno::Sequence< OUString > SAL_CALL getElementNames() override
virtual css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > SAL_CALL getControlModels() override
css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance(const OUString &aServiceSpecifier) override
virtual void SAL_CALL getGroupByName(const OUString &Name, css::uno::Sequence< css::uno::Reference< css::awt::XControlModel > > &Group) override
virtual void SAL_CALL disposing(const css::lang::EventObject &evt) override
virtual void SAL_CALL setTitle(const OUString &_title) override
css::uno::Type SAL_CALL getElementType() override
css::uno::Any ImplGetDefaultValue(sal_uInt16 nPropId) const override
virtual void SAL_CALL setImageURL(const OUString &_imageurl) override
void SAL_CALL removeContainerListener(const css::uno::Reference< css::container::XContainerListener > &xListener) override
::std::pair< css::uno::Reference< css::awt::XControlModel >, OUString > UnoControlModelHolder
virtual ::sal_Int16 SAL_CALL getTabPageID() override
rtl::Reference< UnoControlModel > Clone() const override
virtual OUString SAL_CALL getImageURL() override
::std::vector< UnoControlModelHolder > UnoControlModelHolderVector
void startControlListening(const css::uno::Reference< css::awt::XControlModel > &_rxChildModel)
ControlModelContainerBase(const css::uno::Reference< css::uno::XComponentContext > &rxContext)
virtual sal_Bool SAL_CALL getGroupControl() override
UnoControlModelHolderVector::iterator ImplFindElement(std::u16string_view rName)
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
bool removeSegment(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true)
INetProtocol GetProtocol() const
allows to extend an arbitrary com.sun.star.awt::UnoControlModel with geometry information.
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
ResourceListener(const css::uno::Reference< css::util::XModifyListener > &xListener)
virtual void SAL_CALL acquire() noexcept override
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &aType) override
virtual void SAL_CALL release() noexcept override
css::uno::Reference< css::util::XModifyListener > m_xListener
virtual ~ResourceListener() override
void startListening(const css::uno::Reference< css::resource::XStringResourceResolver > &rResource)
css::uno::Reference< css::resource::XStringResourceResolver > m_xResource
virtual void SAL_CALL modified(const css::lang::EventObject &aEvent) override
constexpr tools::Long Height() const
constexpr tools::Long Width() const
static css::uno::Reference< css::awt::XControl > FindControl(css::uno::Sequence< css::uno::Reference< css::awt::XControl > > &rCtrls, const css::uno::Reference< css::awt::XControlModel > &rxCtrlModel)
void SAL_CALL createPeer(const css::uno::Reference< css::awt::XToolkit > &Toolkit, const css::uno::Reference< css::awt::XWindowPeer > &Parent) override
virtual void addingControl(const css::uno::Reference< css::awt::XControl > &_rxControl)
void SAL_CALL disposing(const css::lang::EventObject &Source) override
virtual void removingControl(const css::uno::Reference< css::awt::XControl > &_rxControl)
void SAL_CALL dispose() override
void SAL_CALL dispose() override
virtual css::uno::Any ImplGetDefaultValue(sal_uInt16 nPropId) const
sal_Bool SAL_CALL setModel(const css::uno::Reference< css::awt::XControlModel > &Model) override
void SAL_CALL setDesignMode(sal_Bool bOn) override
std::vector< css::uno::Reference< ListenerT > > getElements(std::unique_lock< std::mutex > &rGuard) const
sal_Int32 addInterface(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< ListenerT > &rxIFace)
void disposeAndClear(::std::unique_lock<::std::mutex > &rGuard, const css::lang::EventObject &rEvt)
sal_Int32 removeInterface(std::unique_lock< std::mutex > &rGuard, const css::uno::Reference< ListenerT > &rxIFace)
css::uno::Type const & get()
static void lcl_throwElementExistException()
static void lcl_ApplyResolverToNestedContainees(const Reference< resource::XStringResourceResolver > &xStringResourceResolver, const Reference< XControlContainer > &xContainer)
constexpr OUStringLiteral PROPERTY_RESOURCERESOLVER
static void lcl_throwNoSuchElementException()
OUString getPhysicalLocation(const css::uno::Any &rbase, const css::uno::Any &rUrl)
static void lcl_throwIllegalArgumentException()
static OUString getStepPropertyName()
static OUString getTabIndexPropertyName()
::std::multimap< sal_Int32, Reference< XControlModel > > MapIndexToModel
#define DBG_ASSERT(sCon, aError)
#define TOOLS_WARN_EXCEPTION(area, stream)
#define ENSURE_OR_RETURN(c, m, r)
#define DBG_UNHANDLED_EXCEPTION(...)
#define ENSURE_OR_RETURN_VOID(c, m)
float u
Any aHelper
Reference< XInterface > xTarget
Reference< XTextListener > m_xListener
std::mutex m_aMutex
OUString aName
uno_Any a
Sequence< sal_Int8 > aSeq
#define SAL_WARN(area, stream)
@ Exception
Type
OUString aPropName
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
VBAHELPER_DLLPUBLIC bool setPropertyValue(css::uno::Sequence< css::beans::PropertyValue > &aProp, const OUString &aName, const css::uno::Any &aValue)
bool getPropertyValue(ValueType &rValue, css::uno::Reference< css::beans::XPropertySet > const &xPropSet, OUString const &propName)
const PropertyStruct aPropNames[]
const OUString & GetPropertyName(sal_uInt16 nPropertyId)
Definition: property.cxx:295
#define BASEPROPERTY_TITLE
Definition: property.hxx:102
#define BASEPROPERTY_IMAGEURL
Definition: property.hxx:75
#define BASEPROPERTY_ENABLED
Definition: property.hxx:77
#define BASEPROPERTY_DEFAULTCONTROL
Definition: property.hxx:52
#define BASEPROPERTY_FONTDESCRIPTOR
Definition: property.hxx:41
#define BASEPROPERTY_USERFORMCONTAINEES
Definition: property.hxx:192
#define BASEPROPERTY_DIALOGSOURCEURL
Definition: property.hxx:167
const char szServiceName_UnoControlDialog[]
CloneControlModel(ControlModelContainerBase::UnoControlModelHolderVector &_rTargetVector)
ControlModelContainerBase::UnoControlModelHolderVector & m_rTargetVector
void operator()(const ControlModelContainerBase::UnoControlModelHolder &_rSource)
Reference< XControlModel > m_xReference
CompareControlModel(const Reference< XControlModel > &_rxReference)
bool operator()(const ControlModelContainerBase::UnoControlModelHolder &_rCompare)
Reference< XModel > xModel
unsigned char sal_Bool
INetProtocol