Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/toolkit/source/controls/controlmodelcontainerbase.cxx
Line
Count
Source
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
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/awt/XVclWindowPeer.hpp>
36
#include <com/sun/star/resource/XStringResourceResolver.hpp>
37
#include <com/sun/star/lang/XInitialization.hpp>
38
#include <cppuhelper/queryinterface.hxx>
39
#include <cppuhelper/weak.hxx>
40
#include <cppuhelper/weakagg.hxx>
41
#include <tools/debug.hxx>
42
#include <tools/mapunit.hxx>
43
#include <comphelper/diagnose_ex.hxx>
44
#include <vcl/outdev.hxx>
45
#include <comphelper/types.hxx>
46
47
#include "tree/treecontrol.hxx"
48
#include "grid/gridcontrol.hxx"
49
#include <controls/tabpagecontainer.hxx>
50
51
#include <map>
52
#include <algorithm>
53
#include <tools/urlobj.hxx>
54
#include <osl/file.hxx>
55
#include <sal/log.hxx>
56
#include <controls/dialogcontrol.hxx>
57
58
#include <helper/unopropertyarrayhelper.hxx>
59
#include "controlmodelcontainerbase_internal.hxx"
60
61
using namespace ::com::sun::star;
62
using namespace ::com::sun::star::uno;
63
using namespace ::com::sun::star::awt;
64
using namespace ::com::sun::star::lang;
65
using namespace ::com::sun::star::container;
66
using namespace ::com::sun::star::beans;
67
using namespace ::com::sun::star::util;
68
using namespace toolkit;
69
70
constexpr OUString PROPERTY_RESOURCERESOLVER = u"ResourceResolver"_ustr;
71
72
73
namespace
74
{
75
    const Sequence< OUString >& lcl_getLanguageDependentProperties()
76
0
    {
77
        // note: properties must be sorted
78
0
        static Sequence<OUString> s_aLanguageDependentProperties{ u"HelpText"_ustr, u"Title"_ustr };
79
0
        return s_aLanguageDependentProperties;
80
0
    }
81
82
// functor for disposing a control model
83
struct DisposeControlModel
84
{
85
    void operator()( Reference< XControlModel >& _rxModel )
86
0
    {
87
0
        try
88
0
        {
89
0
            ::comphelper::disposeComponent( _rxModel );
90
0
        }
91
0
        catch (const Exception&)
92
0
        {
93
0
            TOOLS_WARN_EXCEPTION("toolkit", "caught an exception while disposing a component" );
94
0
        }
95
0
    }
96
};
97
98
}
99
100
101
// functor for cloning a control model, and insertion into a target list
102
struct CloneControlModel
103
{
104
private:
105
    ControlModelContainerBase::UnoControlModelHolderVector&   m_rTargetVector;
106
107
public:
108
    explicit CloneControlModel( ControlModelContainerBase::UnoControlModelHolderVector& _rTargetVector )
109
0
        :m_rTargetVector( _rTargetVector )
110
0
    {
111
0
    }
112
113
    void operator()( const ControlModelContainerBase::UnoControlModelHolder& _rSource )
114
0
    {
115
        // clone the source object
116
0
        Reference< XCloneable > xCloneSource( _rSource.first, UNO_QUERY );
117
0
        Reference< XControlModel > xClone( xCloneSource->createClone(), UNO_QUERY );
118
        // add to target list
119
0
        m_rTargetVector.emplace_back( xClone, _rSource.second );
120
0
    }
121
};
122
123
124
// functor for comparing a XControlModel with a given reference
125
struct CompareControlModel
126
{
127
private:
128
    Reference< XControlModel > m_xReference;
129
public:
130
0
    explicit CompareControlModel( const Reference< XControlModel >& _rxReference ) : m_xReference( _rxReference ) { }
131
132
    bool operator()( const ControlModelContainerBase::UnoControlModelHolder& _rCompare )
133
0
    {
134
0
        return _rCompare.first.get() == m_xReference.get();
135
0
    }
136
};
137
138
constexpr OUString aTabIndexPropertyNameStr( u"TabIndex"_ustr );
139
140
ControlModelContainerBase::ControlModelContainerBase( const Reference< XComponentContext >& rxContext )
141
0
    :ControlModelContainer_IBase( rxContext )
142
0
    ,maContainerListeners( *this )
143
0
    ,mbGroupsUpToDate( false )
144
0
    ,m_nTabPageId(0)
145
0
{
146
0
    ImplRegisterProperty(BASEPROPERTY_ENABLED);
147
0
}
Unexecuted instantiation: ControlModelContainerBase::ControlModelContainerBase(com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const&)
Unexecuted instantiation: ControlModelContainerBase::ControlModelContainerBase(com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const&)
148
149
ControlModelContainerBase::ControlModelContainerBase( const ControlModelContainerBase& rModel )
150
0
    : ControlModelContainer_IBase( rModel )
151
0
    , maContainerListeners( *this )
152
0
    , mbGroupsUpToDate( false )
153
0
    , m_nTabPageId( rModel.m_nTabPageId )
154
0
{
155
0
}
Unexecuted instantiation: ControlModelContainerBase::ControlModelContainerBase(ControlModelContainerBase const&)
Unexecuted instantiation: ControlModelContainerBase::ControlModelContainerBase(ControlModelContainerBase const&)
156
157
ControlModelContainerBase::~ControlModelContainerBase()
158
0
{
159
0
    maModels.clear();
160
0
    mbGroupsUpToDate = false;
161
0
}
162
163
Any ControlModelContainerBase::ImplGetDefaultValue( sal_uInt16 nPropId ) const
164
0
{
165
0
    Any aAny;
166
167
0
    switch ( nPropId )
168
0
    {
169
0
        case BASEPROPERTY_DEFAULTCONTROL:
170
0
            aAny <<= sServiceName_UnoControlDialog;
171
0
            break;
172
0
        default:
173
0
            aAny = UnoControlModel::ImplGetDefaultValue( nPropId );
174
0
    }
175
176
0
    return aAny;
177
0
}
178
179
::cppu::IPropertyArrayHelper& ControlModelContainerBase::getInfoHelper()
180
0
{
181
0
    static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() );
182
0
    return aHelper;
183
0
}
184
185
void SAL_CALL ControlModelContainerBase::dispose(  )
186
0
{
187
188
    // tell our listeners
189
0
    {
190
0
        std::unique_lock aGuard( m_aMutex );
191
192
0
        EventObject aDisposeEvent;
193
0
        aDisposeEvent.Source = static_cast< XAggregation* >( static_cast< ::cppu::OWeakAggObject* >( this ) );
194
195
0
        maContainerListeners.disposeAndClear( aGuard, aDisposeEvent );
196
0
        maChangeListeners.disposeAndClear( aGuard, aDisposeEvent );
197
0
    }
198
199
200
    // call the base class
201
0
    UnoControlModel::dispose();
202
203
204
    // dispose our child models
205
    // for this, collect the models (we collect them from maModels, and this is modified when disposing children)
206
0
    ::std::vector< Reference< XControlModel > > aChildModels( maModels.size() );
207
208
0
    ::std::transform(
209
0
        maModels.begin(), maModels.end(),               // source range
210
0
        aChildModels.begin(),                           // target location
211
0
        []( const UnoControlModelHolder& rUnoControlModelHolder )
212
0
        { return rUnoControlModelHolder.first; }        // operation to apply -> select the XControlModel part
213
0
    );
214
215
    // now dispose
216
0
    ::std::for_each( aChildModels.begin(), aChildModels.end(), DisposeControlModel() );
217
0
    aChildModels.clear();
218
219
0
    mbGroupsUpToDate = false;
220
0
}
221
222
// XMultiPropertySet
223
Reference< XPropertySetInfo > ControlModelContainerBase::getPropertySetInfo(  )
224
0
{
225
0
    static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
226
0
    return xInfo;
227
0
}
228
void ControlModelContainerBase::Clone_Impl(ControlModelContainerBase& _rClone) const
229
0
{
230
    // clone all children
231
0
    ::std::for_each(
232
0
        maModels.begin(), maModels.end(),
233
0
        CloneControlModel( _rClone.maModels )
234
0
    );
235
0
}
236
rtl::Reference<UnoControlModel> ControlModelContainerBase::Clone() const
237
0
{
238
    // clone the container itself
239
0
    rtl::Reference<ControlModelContainerBase> pClone = new ControlModelContainerBase( *this );
240
0
    Clone_Impl(*pClone);
241
242
0
    return pClone;
243
0
}
244
245
ControlModelContainerBase::UnoControlModelHolderVector::iterator ControlModelContainerBase::ImplFindElement( std::u16string_view rName )
246
0
{
247
0
    return ::std::find_if( maModels.begin(), maModels.end(), [&](const UnoControlModelHolder& elem) { return elem.second == rName; });
248
0
}
249
250
// ::XMultiServiceFactory
251
Reference< XInterface > ControlModelContainerBase::createInstance( const OUString& aServiceSpecifier )
252
0
{
253
0
    SolarMutexGuard aGuard;
254
255
0
    rtl::Reference<OGeometryControlModel_Base> pNewModel;
256
257
0
    if ( aServiceSpecifier == "com.sun.star.awt.UnoControlEditModel" )
258
0
        pNewModel = new OGeometryControlModel< UnoControlEditModel >( m_xContext );
259
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFormattedFieldModel" )
260
0
        pNewModel = new OGeometryControlModel< UnoControlFormattedFieldModel >( m_xContext);
261
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFileControlModel" )
262
0
        pNewModel = new OGeometryControlModel< UnoControlFileControlModel >( m_xContext );
263
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlButtonModel" )
264
0
        pNewModel = new OGeometryControlModel< UnoControlButtonModel >( m_xContext );
265
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlImageControlModel" )
266
0
        pNewModel = new OGeometryControlModel< UnoControlImageControlModel >( m_xContext );
267
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlRadioButtonModel" )
268
0
        pNewModel = new OGeometryControlModel< UnoControlRadioButtonModel >( m_xContext );
269
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlCheckBoxModel" )
270
0
        pNewModel = new OGeometryControlModel< UnoControlCheckBoxModel >( m_xContext );
271
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFixedHyperlinkModel" )
272
0
        pNewModel = new OGeometryControlModel< UnoControlFixedHyperlinkModel >( m_xContext );
273
0
    else if ( aServiceSpecifier == "stardiv.vcl.controlmodel.FixedText" )
274
0
        pNewModel = new OGeometryControlModel< UnoControlFixedTextModel >( m_xContext );
275
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlGroupBoxModel" )
276
0
        pNewModel = new OGeometryControlModel< UnoControlGroupBoxModel >( m_xContext );
277
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlListBoxModel" )
278
0
        pNewModel = new OGeometryControlModel< UnoControlListBoxModel >( m_xContext );
279
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlComboBoxModel" )
280
0
        pNewModel = new OGeometryControlModel< UnoControlComboBoxModel >( m_xContext );
281
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlDateFieldModel" )
282
0
        pNewModel = new OGeometryControlModel< UnoControlDateFieldModel >( m_xContext );
283
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlTimeFieldModel" )
284
0
        pNewModel = new OGeometryControlModel< UnoControlTimeFieldModel >( m_xContext );
285
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlNumericFieldModel" )
286
0
        pNewModel = new OGeometryControlModel< UnoControlNumericFieldModel >( m_xContext );
287
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlCurrencyFieldModel" )
288
0
        pNewModel = new OGeometryControlModel< UnoControlCurrencyFieldModel >( m_xContext );
289
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlPatternFieldModel" )
290
0
        pNewModel = new OGeometryControlModel< UnoControlPatternFieldModel >( m_xContext );
291
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlProgressBarModel" )
292
0
        pNewModel = new OGeometryControlModel< UnoControlProgressBarModel >( m_xContext );
293
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlScrollBarModel" )
294
0
        pNewModel = new OGeometryControlModel< UnoControlScrollBarModel >( m_xContext );
295
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlFixedLineModel" )
296
0
        pNewModel = new OGeometryControlModel< UnoControlFixedLineModel >( m_xContext );
297
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoControlRoadmapModel" )
298
0
        pNewModel = new OGeometryControlModel< UnoControlRoadmapModel >( m_xContext );
299
0
    else if ( aServiceSpecifier == "com.sun.star.awt.tree.TreeControlModel" )
300
0
        pNewModel = new OGeometryControlModel< UnoTreeModel >( m_xContext );
301
0
    else if ( aServiceSpecifier == "com.sun.star.awt.grid.UnoControlGridModel" )
302
0
        pNewModel = new OGeometryControlModel< UnoGridModel >( m_xContext );
303
0
    else if ( aServiceSpecifier == "com.sun.star.awt.tab.UnoControlTabPageContainerModel" )
304
0
        pNewModel = new OGeometryControlModel< UnoControlTabPageContainerModel >( m_xContext );
305
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoMultiPageModel" )
306
0
        pNewModel = new OGeometryControlModel< UnoMultiPageModel >( m_xContext );
307
0
    else if ( aServiceSpecifier == "com.sun.star.awt.tab.UnoControlTabPageModel" )
308
0
        pNewModel = new OGeometryControlModel< UnoControlTabPageModel >( m_xContext );
309
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoPageModel" )
310
0
        pNewModel = new OGeometryControlModel< UnoPageModel >( m_xContext );
311
0
    else if ( aServiceSpecifier == "com.sun.star.awt.UnoFrameModel" )
312
0
        pNewModel = new OGeometryControlModel< UnoFrameModel >( m_xContext );
313
314
0
    if ( !pNewModel )
315
0
    {
316
0
        Reference< XInterface > xObject = m_xContext->getServiceManager()->createInstanceWithContext(aServiceSpecifier, m_xContext);
317
0
        Reference< XServiceInfo > xSI( xObject, UNO_QUERY );
318
0
        Reference< XCloneable > xCloneAccess( xSI, UNO_QUERY );
319
0
        Reference< XAggregation > xAgg( xCloneAccess, UNO_QUERY );
320
0
        if ( xAgg.is() )
321
0
        {
322
0
            if ( xSI->supportsService(u"com.sun.star.awt.UnoControlModel"_ustr) )
323
0
            {
324
                // release 3 of the 4 references we have to the object
325
0
                xAgg.clear();
326
0
                xSI.clear();
327
0
                xObject.clear();
328
329
0
                pNewModel = new OCommonGeometryControlModel( xCloneAccess, aServiceSpecifier );
330
0
            }
331
0
        }
332
0
    }
333
334
0
    return cppu::getXWeak(pNewModel.get());
335
0
}
336
337
Reference< XInterface > ControlModelContainerBase::createInstanceWithArguments( const OUString& ServiceSpecifier, const Sequence< Any >& i_arguments )
338
0
{
339
0
    const Reference< XInterface > xInstance( createInstance( ServiceSpecifier ) );
340
0
    const Reference< XInitialization > xInstanceInit( xInstance, UNO_QUERY );
341
0
    ENSURE_OR_RETURN( xInstanceInit.is(), "ControlModelContainerBase::createInstanceWithArguments: can't pass the arguments!", xInstance );
342
0
    xInstanceInit->initialize( i_arguments );
343
0
    return xInstance;
344
0
}
345
346
Sequence< OUString > ControlModelContainerBase::getAvailableServiceNames()
347
0
{
348
0
    return { u"com.sun.star.awt.UnoControlEditModel"_ustr,
349
0
            u"com.sun.star.awt.UnoControlFormattedFieldModel"_ustr,
350
0
            u"com.sun.star.awt.UnoControlFileControlModel"_ustr,
351
0
            u"com.sun.star.awt.UnoControlButtonModel"_ustr,
352
0
            u"com.sun.star.awt.UnoControlImageControlModel"_ustr,
353
0
            u"com.sun.star.awt.UnoControlRadioButtonModel"_ustr,
354
0
            u"com.sun.star.awt.UnoControlCheckBoxModel"_ustr,
355
0
            u"com.sun.star.awt.UnoControlFixedTextModel"_ustr,
356
0
            u"com.sun.star.awt.UnoControlGroupBoxModel"_ustr,
357
0
            u"com.sun.star.awt.UnoControlListBoxModel"_ustr,
358
0
            u"com.sun.star.awt.UnoControlComboBoxModel"_ustr,
359
0
            u"com.sun.star.awt.UnoControlDateFieldModel"_ustr,
360
0
            u"com.sun.star.awt.UnoControlTimeFieldModel"_ustr,
361
0
            u"com.sun.star.awt.UnoControlNumericFieldModel"_ustr,
362
0
            u"com.sun.star.awt.UnoControlCurrencyFieldModel"_ustr,
363
0
            u"com.sun.star.awt.UnoControlPatternFieldModel"_ustr,
364
0
            u"com.sun.star.awt.UnoControlProgressBarModel"_ustr,
365
0
            u"com.sun.star.awt.UnoControlScrollBarModel"_ustr,
366
0
            u"com.sun.star.awt.UnoControlFixedLineModel"_ustr,
367
0
            u"com.sun.star.awt.UnoControlRoadmapModel"_ustr,
368
0
            u"com.sun.star.awt.tree.TreeControlModel"_ustr,
369
0
            u"com.sun.star.awt.grid.UnoControlGridModel"_ustr,
370
0
            u"com.sun.star.awt.UnoControlFixedHyperlinkModel"_ustr,
371
0
            u"com.sun.star.awt.tab.UnoControlTabPageContainerModel"_ustr,
372
0
            u"com.sun.star.awt.tab.UnoControlTabPageModel"_ustr,
373
0
            u"com.sun.star.awt.UnoMultiPageModel"_ustr,
374
0
            u"com.sun.star.awt.UnoFrameModel"_ustr
375
0
    };
376
0
}
377
378
// XContainer
379
void ControlModelContainerBase::addContainerListener( const Reference< XContainerListener >& l )
380
0
{
381
0
    maContainerListeners.addInterface( l );
382
0
}
383
384
void ControlModelContainerBase::removeContainerListener( const Reference< XContainerListener >& l )
385
0
{
386
0
    maContainerListeners.removeInterface( l );
387
0
}
388
389
// XElementAccess
390
Type ControlModelContainerBase::getElementType()
391
0
{
392
0
    Type aType = cppu::UnoType<XControlModel>::get();
393
0
    return aType;
394
0
}
395
396
sal_Bool ControlModelContainerBase::hasElements()
397
0
{
398
0
    return !maModels.empty();
399
0
}
400
401
// XNameContainer, XNameReplace, XNameAccess
402
void ControlModelContainerBase::replaceByName( const OUString& aName, const Any& aElement )
403
0
{
404
0
    SolarMutexGuard aGuard;
405
406
0
    Reference< XControlModel > xNewModel;
407
0
    aElement >>= xNewModel;
408
0
    if ( !xNewModel.is() )
409
0
        throw IllegalArgumentException();
410
411
0
    UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName );
412
0
    if ( maModels.end() == aElementPos )
413
0
        throw NoSuchElementException();
414
    // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
415
    // With container controls you could have constructed an existing hierarchy and are now
416
    // add this to an existing container, in this case a name nested in the containment
417
    // hierarchy of the added control could contain a name clash, if we have access to the
418
    // list of global names then recursively check for previously existing names (we need
419
    // to do this obviously before the 'this' objects container is updated)
420
0
    Reference< XNameContainer > xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ) ), UNO_QUERY );
421
0
    if ( xAllChildren.is() )
422
0
    {
423
        // remove old control (and children) from global list of containers
424
0
        updateUserFormChildren( xAllChildren, aName, Remove, uno::Reference< XControlModel >() );
425
        // Add new control (and containers if they exist)
426
0
        updateUserFormChildren( xAllChildren, aName, Insert, xNewModel );
427
0
    }
428
    // stop listening at the old model
429
0
    stopControlListening( aElementPos->first );
430
0
    Reference< XControlModel > xReplaced( aElementPos->first );
431
    // remember the new model, and start listening
432
0
    aElementPos->first = xNewModel;
433
0
    startControlListening( xNewModel );
434
435
0
    ContainerEvent aEvent;
436
0
    aEvent.Source = *this;
437
0
    aEvent.Element = aElement;
438
0
    aEvent.ReplacedElement <<= xReplaced;
439
0
    aEvent.Accessor <<= aName;
440
441
    // notify the container listener
442
0
    maContainerListeners.elementReplaced( aEvent );
443
444
    // our "tab controller model" has potentially changed -> notify this
445
0
    implNotifyTabModelChange( aName );
446
0
}
447
448
Any ControlModelContainerBase::getByName( const OUString& aName )
449
0
{
450
0
    UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName );
451
0
    if ( maModels.end() == aElementPos )
452
0
        throw NoSuchElementException();
453
454
0
    return Any( aElementPos->first );
455
0
}
456
457
Sequence< OUString > ControlModelContainerBase::getElementNames()
458
0
{
459
0
    Sequence< OUString > aNames( maModels.size() );
460
461
0
    ::std::transform(
462
0
        maModels.begin(), maModels.end(),               // source range
463
0
        aNames.getArray(),                              // target range
464
0
        []( const UnoControlModelHolder& rUnoControlModelHolder )
465
0
        { return rUnoControlModelHolder.second; }        // operator to apply: select the second element (the name)
466
0
    );
467
468
0
    return aNames;
469
0
}
470
471
sal_Bool ControlModelContainerBase::hasByName( const OUString& aName )
472
0
{
473
0
    return maModels.end() != ImplFindElement( aName );
474
0
}
475
476
void ControlModelContainerBase::insertByName( const OUString& aName, const Any& aElement )
477
0
{
478
0
    SolarMutexGuard aGuard;
479
480
0
    Reference< XControlModel > xM;
481
0
    aElement >>= xM;
482
483
0
    if ( xM.is() )
484
0
    {
485
0
        Reference< beans::XPropertySet > xProps( xM, UNO_QUERY );
486
0
        if ( xProps.is() )
487
0
        {
488
489
0
                Reference< beans::XPropertySetInfo > xPropInfo = xProps->getPropertySetInfo();
490
491
0
                const OUString& sImageSourceProperty = GetPropertyName( BASEPROPERTY_IMAGEURL );
492
0
                if ( xPropInfo->hasPropertyByName(  sImageSourceProperty ) && ImplHasProperty(BASEPROPERTY_DIALOGSOURCEURL) )
493
0
                {
494
0
                    Any aUrl = xProps->getPropertyValue(  sImageSourceProperty );
495
496
0
                    OUString absoluteUrl =
497
0
                        getPhysicalLocation( getPropertyValue( GetPropertyName( BASEPROPERTY_DIALOGSOURCEURL ) ), aUrl );
498
499
0
                    aUrl <<= absoluteUrl;
500
501
0
                    xProps->setPropertyValue(  sImageSourceProperty , aUrl );
502
0
                }
503
0
        }
504
0
    }
505
506
507
0
    if ( aName.isEmpty() || !xM.is() )
508
0
        throw IllegalArgumentException();
509
510
0
    UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName );
511
0
    if ( maModels.end() != aElementPos )
512
0
        throw ElementExistException();
513
514
    // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
515
    // With container controls you could have constructed an existing hierarchy and are now
516
    // add this to an existing container, in this case a name nested in the containment
517
    // hierarchy of the added control could contain a name clash, if we have access to the
518
    // list of global names then we need to recursively check for previously existing
519
    // names (we need to do this obviously before the 'this' objects container is updated)
520
    // remove old control (and children) from global list of containers
521
0
    Reference< XNameContainer > xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ) ), UNO_QUERY );
522
523
0
    if ( xAllChildren.is() )
524
0
        updateUserFormChildren( xAllChildren, aName, Insert, xM );
525
0
    maModels.emplace_back( xM, aName );
526
0
    mbGroupsUpToDate = false;
527
0
    startControlListening( xM );
528
529
0
    ContainerEvent aEvent;
530
0
    aEvent.Source = *this;
531
0
    aEvent.Element = aElement;
532
0
    aEvent.Accessor <<= aName;
533
0
    maContainerListeners.elementInserted( aEvent );
534
535
    // our "tab controller model" has potentially changed -> notify this
536
0
    implNotifyTabModelChange( aName );
537
0
}
538
539
void ControlModelContainerBase::removeByName( const OUString& aName )
540
0
{
541
0
    SolarMutexGuard aGuard;
542
543
0
    UnoControlModelHolderVector::iterator aElementPos = ImplFindElement( aName );
544
0
    if ( maModels.end() == aElementPos )
545
0
        throw NoSuchElementException();
546
547
    // Dialog behaviour is to have all containee names unique (MSO Userform is the same)
548
    // With container controls you could have constructed an existing hierarchy and are now
549
    // removing this control from an existing container, in this case all nested names in
550
    // the containment hierarchy of the control to be removed need to be removed from the global
551
    // names cache (we need to do this obviously before the 'this' objects container is updated)
552
0
    Reference< XNameContainer > xAllChildren( getPropertyValue( GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ) ), UNO_QUERY );
553
0
    if ( xAllChildren.is() )
554
0
        updateUserFormChildren( xAllChildren, aName, Remove, uno::Reference< XControlModel >() );
555
556
0
    ContainerEvent aEvent;
557
0
    aEvent.Source = *this;
558
0
    aEvent.Element <<= aElementPos->first;
559
0
    aEvent.Accessor <<= aName;
560
0
    maContainerListeners.elementRemoved( aEvent );
561
562
0
    stopControlListening( aElementPos->first );
563
0
    Reference< XPropertySet > xPS( aElementPos->first, UNO_QUERY );
564
0
    maModels.erase( aElementPos );
565
0
    mbGroupsUpToDate = false;
566
567
0
    if ( xPS.is() )
568
0
    {
569
0
        try
570
0
        {
571
0
            xPS->setPropertyValue( PROPERTY_RESOURCERESOLVER, Any( Reference< resource::XStringResourceResolver >() ) );
572
0
        }
573
0
        catch (const Exception&)
574
0
        {
575
0
            DBG_UNHANDLED_EXCEPTION("toolkit.controls");
576
0
        }
577
0
    }
578
579
    // our "tab controller model" has potentially changed -> notify this
580
0
    implNotifyTabModelChange( aName );
581
0
}
582
583
584
sal_Bool SAL_CALL ControlModelContainerBase::getGroupControl(  )
585
0
{
586
0
    return true;
587
0
}
588
589
590
void SAL_CALL ControlModelContainerBase::setGroupControl( sal_Bool )
591
0
{
592
0
    SAL_WARN("toolkit", "explicit grouping not supported" );
593
0
}
594
595
596
void SAL_CALL ControlModelContainerBase::setControlModels( const Sequence< Reference< XControlModel > >& _rControls )
597
0
{
598
0
    SolarMutexGuard aGuard;
599
600
    // set the tab indexes according to the order of models in the sequence
601
602
0
    sal_Int16 nTabIndex = 1;
603
604
0
    for ( auto const & control : _rControls )
605
0
    {
606
        // look up the control in our own structure. This is to prevent invalid arguments
607
0
        UnoControlModelHolderVector::const_iterator aPos =
608
0
            ::std::find_if(
609
0
                maModels.begin(), maModels.end(),
610
0
                CompareControlModel( control )
611
0
            );
612
0
        if ( maModels.end() != aPos )
613
0
        {
614
            // okay, this is an existent model
615
            // now set the TabIndex property (if applicable)
616
0
            Reference< XPropertySet > xProps( aPos->first, UNO_QUERY );
617
0
            Reference< XPropertySetInfo > xPSI;
618
0
            if ( xProps.is() )
619
0
                xPSI = xProps->getPropertySetInfo();
620
0
            if ( xPSI.is() && xPSI->hasPropertyByName( aTabIndexPropertyNameStr ) )
621
0
                xProps->setPropertyValue( aTabIndexPropertyNameStr, Any( nTabIndex++ ) );
622
0
        }
623
0
        mbGroupsUpToDate = false;
624
0
    }
625
0
}
626
627
628
typedef ::std::multimap< sal_Int32, Reference< XControlModel > > MapIndexToModel;
629
630
631
Sequence< Reference< XControlModel > > SAL_CALL ControlModelContainerBase::getControlModels(  )
632
0
{
633
0
    SolarMutexGuard aGuard;
634
635
0
    MapIndexToModel aSortedModels;
636
        // will be the sorted container of all models which have a tab index property
637
0
    ::std::vector< Reference< XControlModel > > aUnindexedModels;
638
        // will be the container of all models which do not have a tab index property
639
640
0
    for ( const auto& rModel : maModels )
641
0
    {
642
0
        Reference< XControlModel > xModel( rModel.first );
643
644
        // see if the model has a TabIndex property
645
0
        Reference< XPropertySet > xControlProps( xModel, UNO_QUERY );
646
0
        Reference< XPropertySetInfo > xPSI;
647
0
        if ( xControlProps.is() )
648
0
            xPSI = xControlProps->getPropertySetInfo( );
649
0
        DBG_ASSERT( xPSI.is(), "ControlModelContainerBase::getControlModels: invalid child model!" );
650
651
        // has it?
652
0
        if ( xPSI.is() && xPSI->hasPropertyByName( aTabIndexPropertyNameStr ) )
653
0
        {   // yes
654
0
            sal_Int32 nTabIndex = -1;
655
0
            xControlProps->getPropertyValue( aTabIndexPropertyNameStr ) >>= nTabIndex;
656
657
0
            aSortedModels.emplace( nTabIndex, xModel );
658
0
        }
659
0
        else if ( xModel.is() )
660
            // no, it hasn't, but we have to include it, anyway
661
0
            aUnindexedModels.push_back( xModel );
662
0
    }
663
664
    // okay, here we have a container of all our models, sorted by tab index,
665
    // plus a container of "unindexed" models
666
    // -> merge them
667
0
    Sequence< Reference< XControlModel > > aReturn( aUnindexedModels.size() + aSortedModels.size() );
668
0
    ::std::transform(
669
0
            aSortedModels.begin(), aSortedModels.end(),
670
0
            ::std::copy( aUnindexedModels.begin(), aUnindexedModels.end(), aReturn.getArray() ),
671
0
            [] ( const MapIndexToModel::value_type& entryIndexToModel )
672
0
            { return entryIndexToModel.second; }
673
0
        );
674
675
0
    return aReturn;
676
0
}
677
678
679
void SAL_CALL ControlModelContainerBase::setGroup( const Sequence< Reference< XControlModel > >&, const OUString& )
680
0
{
681
    // not supported. We have only implicit grouping:
682
    // We only have a sequence of control models, and we _know_ (yes, that's a HACK relying on
683
    // implementation details) that VCL does grouping according to the order of controls automatically
684
    // At least VCL does this for all we're interested in: Radio buttons.
685
0
    SAL_WARN("toolkit", "grouping not supported" );
686
0
}
687
688
////----- XInitialization -------------------------------------------------------------------
689
void SAL_CALL ControlModelContainerBase::initialize (const Sequence<Any>& rArguments)
690
0
{
691
0
    if ( rArguments.getLength() == 1 )
692
0
    {
693
0
        sal_Int16 nPageId = -1;
694
0
        if ( !( rArguments[ 0 ] >>= nPageId ))
695
0
            throw lang::IllegalArgumentException();
696
0
        m_nTabPageId = nPageId;
697
0
    }
698
0
    else
699
0
        m_nTabPageId = -1;
700
0
}
701
::sal_Int16 SAL_CALL ControlModelContainerBase::getTabPageID()
702
0
{
703
0
    return m_nTabPageId;
704
0
}
705
sal_Bool SAL_CALL ControlModelContainerBase::getEnabled()
706
0
{
707
0
    SolarMutexGuard aGuard;
708
0
    bool bEnabled = false;
709
0
    getPropertyValue(GetPropertyName(BASEPROPERTY_ENABLED)) >>= bEnabled;
710
0
    return bEnabled;
711
0
}
712
void SAL_CALL ControlModelContainerBase::setEnabled( sal_Bool _enabled )
713
0
{
714
0
    SolarMutexGuard aGuard;
715
0
    setPropertyValue(GetPropertyName(BASEPROPERTY_ENABLED), Any(_enabled));
716
0
}
717
OUString SAL_CALL ControlModelContainerBase::getTitle()
718
0
{
719
0
    SolarMutexGuard aGuard;
720
0
    OUString sTitle;
721
0
    getPropertyValue(GetPropertyName(BASEPROPERTY_TITLE)) >>= sTitle;
722
0
    return sTitle;
723
0
}
724
void SAL_CALL ControlModelContainerBase::setTitle( const OUString& _title )
725
0
{
726
0
    SolarMutexGuard aGuard;
727
0
    setPropertyValue(GetPropertyName(BASEPROPERTY_TITLE),Any(_title));
728
0
}
729
OUString SAL_CALL ControlModelContainerBase::getImageURL()
730
0
{
731
0
    return m_sImageURL;
732
0
}
733
void SAL_CALL ControlModelContainerBase::setImageURL( const OUString& _imageurl )
734
0
{
735
0
    m_sImageURL = _imageurl;
736
0
    SolarMutexGuard aGuard;
737
0
    setPropertyValue(GetPropertyName(BASEPROPERTY_IMAGEURL), Any(_imageurl));
738
0
}
739
OUString SAL_CALL ControlModelContainerBase::getToolTip()
740
0
{
741
0
    return m_sTooltip;
742
0
}
743
void SAL_CALL ControlModelContainerBase::setToolTip( const OUString& _tooltip )
744
0
{
745
0
    m_sTooltip = _tooltip;
746
0
}
747
748
749
namespace
750
{
751
    enum GroupingMachineState
752
    {
753
        eLookingForGroup,
754
        eExpandingGroup
755
    };
756
757
758
    sal_Int32 lcl_getDialogStep( const Reference< XControlModel >& _rxModel )
759
0
    {
760
0
        sal_Int32 nStep = 0;
761
0
        try
762
0
        {
763
0
            Reference< XPropertySet > xModelProps( _rxModel, UNO_QUERY );
764
0
            xModelProps->getPropertyValue( u"Step"_ustr ) >>= nStep;
765
0
        }
766
0
        catch (const Exception&)
767
0
        {
768
0
            TOOLS_WARN_EXCEPTION("toolkit", "caught an exception while determining the dialog page" );
769
0
        }
770
0
        return nStep;
771
0
    }
772
}
773
774
775
sal_Int32 SAL_CALL ControlModelContainerBase::getGroupCount(  )
776
0
{
777
0
    SolarMutexGuard aGuard;
778
779
0
    implUpdateGroupStructure();
780
781
0
    return maGroups.size();
782
0
}
783
784
785
void SAL_CALL ControlModelContainerBase::getGroup( sal_Int32 _nGroup, Sequence< Reference< XControlModel > >& _rGroup, OUString& _rName )
786
0
{
787
0
    SolarMutexGuard aGuard;
788
789
0
    implUpdateGroupStructure();
790
791
0
    if ( ( _nGroup < 0 ) || ( o3tl::make_unsigned(_nGroup) >= maGroups.size() ) )
792
0
    {
793
0
        SAL_WARN("toolkit", "invalid argument and I am not allowed to throw exception!" );
794
0
        _rGroup.realloc( 0 );
795
0
        _rName.clear();
796
0
    }
797
0
    else
798
0
    {
799
0
        AllGroups::const_iterator aGroupPos = maGroups.begin() + _nGroup;
800
0
        _rGroup.realloc( aGroupPos->size() );
801
        // copy the models
802
0
        ::std::copy( aGroupPos->begin(), aGroupPos->end(), _rGroup.getArray() );
803
        // give the group a name
804
0
        _rName = OUString::number( _nGroup );
805
0
    }
806
0
}
807
808
809
void SAL_CALL ControlModelContainerBase::getGroupByName( const OUString& _rName, Sequence< Reference< XControlModel > >& _rGroup )
810
0
{
811
0
    SolarMutexGuard aGuard;
812
813
0
    OUString sDummyName;
814
0
    getGroup( _rName.toInt32( ), _rGroup, sDummyName );
815
0
}
816
817
818
void SAL_CALL ControlModelContainerBase::addChangesListener( const Reference< XChangesListener >& _rxListener )
819
0
{
820
0
    std::unique_lock g(m_aMutex);
821
0
    maChangeListeners.addInterface( g, _rxListener );
822
0
}
823
824
825
void SAL_CALL ControlModelContainerBase::removeChangesListener( const Reference< XChangesListener >& _rxListener )
826
0
{
827
0
    std::unique_lock g(m_aMutex);
828
0
    maChangeListeners.removeInterface( g, _rxListener );
829
0
}
830
831
832
void ControlModelContainerBase::implNotifyTabModelChange( const OUString& _rAccessor )
833
0
{
834
    // multiplex to our change listeners:
835
    // the changes event
836
0
    ChangesEvent aEvent;
837
0
    aEvent.Source = *this;
838
0
    aEvent.Base <<= aEvent.Source;  // the "base of the changes root" is also ourself
839
0
    aEvent.Changes.realloc( 1 );    // exactly one change
840
0
    aEvent.Changes.getArray()[ 0 ].Accessor <<= _rAccessor;
841
842
843
0
    std::unique_lock g(m_aMutex);
844
0
    std::vector< Reference< css::util::XChangesListener > > aChangeListeners( maChangeListeners.getElements(g) );
845
0
    g.unlock();
846
0
    for ( const auto& rListener : aChangeListeners )
847
0
        rListener->changesOccurred( aEvent );
848
0
}
849
850
851
void ControlModelContainerBase::implUpdateGroupStructure()
852
0
{
853
0
    if ( mbGroupsUpToDate )
854
        // nothing to do
855
0
        return;
856
857
    // conditions for a group:
858
    // * all elements of the group are radio buttons
859
    // * all elements of the group are on the same dialog page
860
    // * in the overall control order (determined by the tab index), all elements are subsequent
861
862
0
    maGroups.clear();
863
864
0
    const Sequence< Reference< XControlModel > > aControlModels = getControlModels();
865
866
    // in extreme we have as much groups as controls
867
0
    maGroups.reserve( aControlModels.getLength() );
868
869
0
    GroupingMachineState eState = eLookingForGroup;     // the current state of our machine
870
0
    Reference< XServiceInfo > xModelSI;                 // for checking for a radio button
871
0
    AllGroups::iterator aCurrentGroup = maGroups.end(); // the group which we're currently building
872
0
    sal_Int32   nCurrentGroupStep = -1;                 // the step which all controls of the current group belong to
873
874
875
0
    for ( const Reference< XControlModel >& rControlModel : aControlModels )
876
0
    {
877
        // we'll need this in every state
878
0
        xModelSI.set(rControlModel, css::uno::UNO_QUERY);
879
        // is it a radio button?
880
0
        bool bIsRadioButton = xModelSI.is() && xModelSI->supportsService( u"com.sun.star.awt.UnoControlRadioButtonModel"_ustr );
881
882
0
        switch ( eState )
883
0
        {
884
0
            case eLookingForGroup:
885
0
            {
886
0
                if ( !bIsRadioButton )
887
                    // this is no radio button -> still looking for the beginning of a group
888
0
                    continue;
889
                // the current model is a radio button
890
                // -> we found the beginning of a new group
891
                // create the place for this group
892
0
                size_t nGroups = maGroups.size();
893
0
                maGroups.resize( nGroups + 1 );
894
0
                aCurrentGroup = maGroups.begin() + nGroups;
895
                // and add the (only, til now) member
896
0
                aCurrentGroup->push_back( rControlModel );
897
898
                // get the step which all controls of this group now have to belong to
899
0
                nCurrentGroupStep = lcl_getDialogStep( rControlModel );
900
                // new state: looking for further members
901
0
                eState = eExpandingGroup;
902
903
0
            }
904
0
            break;
905
906
0
            case eExpandingGroup:
907
0
            {
908
0
                if ( !bIsRadioButton )
909
0
                {   // no radio button -> the group is done
910
0
                    aCurrentGroup = maGroups.end();
911
0
                    eState = eLookingForGroup;
912
0
                    continue;
913
0
                }
914
915
                // it is a radio button - is it on the proper page?
916
0
                const sal_Int32 nThisModelStep = lcl_getDialogStep( rControlModel );
917
0
                if  (   ( nThisModelStep == nCurrentGroupStep ) // the current button is on the same dialog page
918
0
                    ||  ( 0 == nThisModelStep )                 // the current button appears on all pages
919
0
                    )
920
0
                {
921
                    // -> it belongs to the same group
922
0
                    aCurrentGroup->push_back( rControlModel );
923
                    // state still is eExpandingGroup - we're looking for further elements
924
0
                    eState = eExpandingGroup;
925
926
0
                    continue;
927
0
                }
928
929
                // it's a radio button, but on a different page
930
                // -> we open a new group for it
931
932
933
                // open a new group
934
0
                size_t nGroups = maGroups.size();
935
0
                maGroups.resize( nGroups + 1 );
936
0
                aCurrentGroup = maGroups.begin() + nGroups;
937
                // and add the (only, til now) member
938
0
                aCurrentGroup->push_back( rControlModel );
939
940
0
                nCurrentGroupStep = nThisModelStep;
941
942
                // state is the same: we still are looking for further elements of the current group
943
0
                eState = eExpandingGroup;
944
0
            }
945
0
            break;
946
0
        }
947
0
    }
948
949
0
    mbGroupsUpToDate = true;
950
0
}
951
952
953
void SAL_CALL ControlModelContainerBase::propertyChange( const PropertyChangeEvent& _rEvent )
954
0
{
955
0
    SolarMutexGuard aGuard;
956
957
0
    DBG_ASSERT( _rEvent.PropertyName == "TabIndex",
958
0
        "ControlModelContainerBase::propertyChange: not listening for this property!" );
959
960
    // the accessor for the changed element
961
0
    OUString sAccessor;
962
0
    UnoControlModelHolderVector::const_iterator aPos =
963
0
        ::std::find_if(
964
0
            maModels.begin(), maModels.end(),
965
0
            CompareControlModel( Reference< XControlModel >( _rEvent.Source, UNO_QUERY ) )
966
0
        );
967
0
    OSL_ENSURE( maModels.end() != aPos, "ControlModelContainerBase::propertyChange: don't know this model!" );
968
0
    if ( maModels.end() != aPos )
969
0
        sAccessor = aPos->second;
970
971
    // our groups are not up-to-date
972
0
    mbGroupsUpToDate = false;
973
974
    // notify
975
0
    implNotifyTabModelChange( sAccessor );
976
0
}
977
978
979
void SAL_CALL ControlModelContainerBase::disposing( const EventObject& /*rEvent*/ )
980
0
{
981
0
}
982
983
984
void ControlModelContainerBase::startControlListening( const Reference< XControlModel >& _rxChildModel )
985
0
{
986
0
    SolarMutexGuard aGuard;
987
988
0
    Reference< XPropertySet > xModelProps( _rxChildModel, UNO_QUERY );
989
0
    Reference< XPropertySetInfo > xPSI;
990
0
    if ( xModelProps.is() )
991
0
        xPSI = xModelProps->getPropertySetInfo();
992
993
0
    if ( xPSI.is() && xPSI->hasPropertyByName( aTabIndexPropertyNameStr ) )
994
0
        xModelProps->addPropertyChangeListener( aTabIndexPropertyNameStr, this );
995
0
}
996
997
998
void ControlModelContainerBase::stopControlListening( const Reference< XControlModel >& _rxChildModel )
999
0
{
1000
0
    SolarMutexGuard aGuard;
1001
1002
0
    Reference< XPropertySet > xModelProps( _rxChildModel, UNO_QUERY );
1003
0
    Reference< XPropertySetInfo > xPSI;
1004
0
    if ( xModelProps.is() )
1005
0
        xPSI = xModelProps->getPropertySetInfo();
1006
1007
0
    if ( xPSI.is() && xPSI->hasPropertyByName( aTabIndexPropertyNameStr ) )
1008
0
        xModelProps->removePropertyChangeListener( aTabIndexPropertyNameStr, this );
1009
0
}
1010
1011
1012
// = class ResourceListener
1013
1014
1015
ResourceListener::ResourceListener(
1016
    const Reference< util::XModifyListener >& rListener ) :
1017
0
    m_xListener( rListener ),
1018
0
    m_bListening( false )
1019
0
{
1020
0
}
1021
1022
ResourceListener::~ResourceListener()
1023
0
{
1024
0
}
1025
1026
// XInterface
1027
Any SAL_CALL ResourceListener::queryInterface( const Type& rType )
1028
0
{
1029
0
    Any a = ::cppu::queryInterface(
1030
0
                rType ,
1031
0
                static_cast< XModifyListener* >( this ),
1032
0
                static_cast< XEventListener* >( this ));
1033
1034
0
    if ( a.hasValue() )
1035
0
        return a;
1036
1037
0
    return OWeakObject::queryInterface( rType );
1038
0
}
1039
1040
void SAL_CALL ResourceListener::acquire() noexcept
1041
0
{
1042
0
    OWeakObject::acquire();
1043
0
}
1044
1045
void SAL_CALL ResourceListener::release() noexcept
1046
0
{
1047
0
    OWeakObject::release();
1048
0
}
1049
1050
void ResourceListener::startListening(
1051
    const Reference< resource::XStringResourceResolver  >& rResource )
1052
0
{
1053
0
    {
1054
        // --- SAFE ---
1055
0
        std::unique_lock aGuard( m_aMutex );
1056
0
        bool bListening( m_bListening );
1057
0
        bool bResourceSet( m_xResource.is() );
1058
0
        aGuard.unlock();
1059
        // --- SAFE ---
1060
1061
0
        if ( bListening && bResourceSet )
1062
0
            stopListening();
1063
1064
        // --- SAFE ---
1065
0
        aGuard.lock();
1066
0
        m_xResource = rResource;
1067
0
        aGuard.unlock();
1068
        // --- SAFE ---
1069
0
    }
1070
1071
0
    if ( !rResource.is() )
1072
0
        return;
1073
1074
0
    try
1075
0
    {
1076
0
        rResource->addModifyListener( this );
1077
1078
        // --- SAFE ---
1079
0
        std::scoped_lock aGuard( m_aMutex );
1080
0
        m_bListening = true;
1081
        // --- SAFE ---
1082
0
    }
1083
0
    catch (const RuntimeException&)
1084
0
    {
1085
0
        throw;
1086
0
    }
1087
0
    catch (const Exception&)
1088
0
    {
1089
0
    }
1090
0
}
1091
1092
void ResourceListener::stopListening()
1093
0
{
1094
0
    Reference< util::XModifyBroadcaster > xModifyBroadcaster;
1095
1096
    // --- SAFE ---
1097
0
    std::unique_lock aGuard( m_aMutex );
1098
0
    if ( m_bListening && m_xResource.is() )
1099
0
        xModifyBroadcaster = m_xResource;
1100
0
    aGuard.unlock();
1101
    // --- SAFE ---
1102
1103
0
    if ( !xModifyBroadcaster.is() )
1104
0
        return;
1105
1106
0
    try
1107
0
    {
1108
        // --- SAFE ---
1109
0
        aGuard.lock();
1110
0
        m_bListening = false;
1111
0
        m_xResource.clear();
1112
0
        aGuard.unlock();
1113
        // --- SAFE ---
1114
1115
0
        xModifyBroadcaster->removeModifyListener( this );
1116
0
    }
1117
0
    catch (const RuntimeException&)
1118
0
    {
1119
0
        throw;
1120
0
    }
1121
0
    catch (const Exception&)
1122
0
    {
1123
0
    }
1124
0
}
1125
1126
// XModifyListener
1127
void SAL_CALL ResourceListener::modified(
1128
    const lang::EventObject& aEvent )
1129
0
{
1130
0
    Reference< util::XModifyListener > xListener;
1131
1132
    // --- SAFE ---
1133
0
    std::unique_lock aGuard( m_aMutex );
1134
0
    xListener = m_xListener;
1135
0
    aGuard.unlock();
1136
    // --- SAFE ---
1137
1138
0
    if ( !xListener.is() )
1139
0
        return;
1140
1141
0
    try
1142
0
    {
1143
0
        xListener->modified( aEvent );
1144
0
    }
1145
0
    catch (const RuntimeException&)
1146
0
    {
1147
0
        throw;
1148
0
    }
1149
0
    catch (const Exception&)
1150
0
    {
1151
0
    }
1152
0
}
1153
1154
// XEventListener
1155
void SAL_CALL ResourceListener::disposing(
1156
    const EventObject& Source )
1157
0
{
1158
0
    Reference< lang::XEventListener > xListener;
1159
0
    Reference< resource::XStringResourceResolver > xResource;
1160
1161
    // --- SAFE ---
1162
0
    std::unique_lock aGuard( m_aMutex );
1163
0
    Reference< XInterface > xIfacRes( m_xResource, UNO_QUERY );
1164
0
    Reference< XInterface > xIfacList( m_xListener, UNO_QUERY );
1165
0
    aGuard.unlock();
1166
    // --- SAFE ---
1167
1168
0
    if ( Source.Source == xIfacRes )
1169
0
    {
1170
        // --- SAFE ---
1171
0
        aGuard.lock();
1172
0
        m_bListening = false;
1173
0
        xResource = m_xResource;
1174
0
        xListener = m_xListener;
1175
0
        m_xResource.clear();
1176
0
        aGuard.unlock();
1177
        // --- SAFE ---
1178
1179
0
        if ( xListener.is() )
1180
0
        {
1181
0
            try
1182
0
            {
1183
0
                xListener->disposing( Source );
1184
0
            }
1185
0
            catch (const RuntimeException&)
1186
0
            {
1187
0
                throw;
1188
0
            }
1189
0
            catch (const Exception&)
1190
0
            {
1191
0
            }
1192
0
        }
1193
0
    }
1194
0
    else if ( Source.Source == xIfacList )
1195
0
    {
1196
        // --- SAFE ---
1197
0
        aGuard.lock();
1198
0
        m_bListening = false;
1199
0
        xListener = m_xListener;
1200
0
        xResource = m_xResource;
1201
0
        m_xResource.clear();
1202
0
        m_xListener.clear();
1203
0
        aGuard.unlock();
1204
        // --- SAFE ---
1205
1206
        // Remove ourself as listener from resource resolver
1207
0
        if ( xResource.is() )
1208
0
        {
1209
0
            try
1210
0
            {
1211
0
                xResource->removeModifyListener( this );
1212
0
            }
1213
0
            catch (const RuntimeException&)
1214
0
            {
1215
0
                throw;
1216
0
            }
1217
0
            catch (const Exception&)
1218
0
            {
1219
0
            }
1220
0
        }
1221
0
    }
1222
0
}
1223
1224
1225
1226
ControlContainerBase::ControlContainerBase( const Reference< XComponentContext >& rxContext )
1227
0
    :m_xContext(rxContext)
1228
0
    ,mbSizeModified(false)
1229
0
    ,mbPosModified(false)
1230
0
{
1231
0
    maComponentInfos.nWidth = 280;
1232
0
    maComponentInfos.nHeight = 400;
1233
0
    mxListener = new ResourceListener( Reference< util::XModifyListener >(this) );
1234
0
}
1235
1236
ControlContainerBase::~ControlContainerBase()
1237
0
{
1238
0
}
1239
1240
void ControlContainerBase::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer >  & rParentPeer )
1241
0
{
1242
0
    SolarMutexGuard aGuard;
1243
0
    UnoControlContainer::createPeer( rxToolkit, rParentPeer );
1244
0
}
1245
1246
void ControlContainerBase::ImplInsertControl( Reference< XControlModel > const & rxModel, const OUString& rName )
1247
0
{
1248
0
    Reference< XPropertySet > xP( rxModel, UNO_QUERY );
1249
1250
0
    OUString aDefCtrl;
1251
0
    xP->getPropertyValue( GetPropertyName( BASEPROPERTY_DEFAULTCONTROL ) ) >>= aDefCtrl;
1252
0
    Reference < XControl > xCtrl( m_xContext->getServiceManager()->createInstanceWithContext(aDefCtrl, m_xContext), UNO_QUERY );
1253
1254
0
    DBG_ASSERT( xCtrl.is(), "ControlContainerBase::ImplInsertControl: could not create the control!" );
1255
0
    if ( xCtrl.is() )
1256
0
    {
1257
0
        xCtrl->setModel( rxModel );
1258
0
        addControl( rName, xCtrl );
1259
            // will implicitly call addingControl, where we can add the PropertiesChangeListener to the model
1260
            // (which we formerly did herein)
1261
            // 08.01.2001 - 96008 - fs@openoffice.org
1262
1263
0
        ImplSetPosSize( xCtrl );
1264
0
    }
1265
0
}
1266
1267
void ControlContainerBase::ImplRemoveControl( Reference< XControlModel > const & rxModel )
1268
0
{
1269
0
    Sequence< Reference< XControl > > aControls = getControls();
1270
0
    Reference< XControl > xCtrl = StdTabController::FindControl( aControls, rxModel );
1271
0
    if ( xCtrl.is() )
1272
0
    {
1273
0
        removeControl( xCtrl );
1274
0
        try
1275
0
        {
1276
0
            xCtrl->dispose();
1277
0
        }
1278
0
        catch (const Exception&)
1279
0
        {
1280
0
            DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1281
0
        }
1282
0
    }
1283
0
}
1284
1285
void ControlContainerBase::ImplSetPosSize( Reference< XControl >& rxCtrl )
1286
0
{
1287
0
    Reference< XPropertySet > xP( rxCtrl->getModel(), UNO_QUERY );
1288
1289
0
    sal_Int32 nX = 0, nY = 0, nWidth = 0, nHeight = 0;
1290
0
    xP->getPropertyValue(u"PositionX"_ustr) >>= nX;
1291
0
    xP->getPropertyValue(u"PositionY"_ustr) >>= nY;
1292
0
    xP->getPropertyValue(u"Width"_ustr) >>= nWidth;
1293
0
    xP->getPropertyValue(u"Height"_ustr) >>= nHeight;
1294
0
    MapMode aMode( MapUnit::MapAppFont );
1295
0
    OutputDevice*pOutDev = Application::GetDefaultDevice();
1296
0
    if ( pOutDev )
1297
0
    {
1298
0
        ::Size aTmp( nX, nY );
1299
0
        aTmp = pOutDev->LogicToPixel( aTmp, aMode );
1300
0
        nX = aTmp.Width();
1301
0
        nY = aTmp.Height();
1302
0
        aTmp = ::Size( nWidth, nHeight );
1303
0
        aTmp = pOutDev->LogicToPixel( aTmp, aMode );
1304
0
        nWidth = aTmp.Width();
1305
0
        nHeight = aTmp.Height();
1306
0
    }
1307
0
    else
1308
0
    {
1309
0
        Reference< XWindowPeer > xPeer = ImplGetCompatiblePeer();
1310
0
        Reference< XDevice > xD( xPeer, UNO_QUERY );
1311
1312
0
        SimpleFontMetric aFM;
1313
0
        FontDescriptor aFD;
1314
0
        Any aVal = ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_FONTDESCRIPTOR ) );
1315
0
        aVal >>= aFD;
1316
0
        if ( !aFD.StyleName.isEmpty() )
1317
0
        {
1318
0
            Reference< XFont > xFont = xD->getFont( aFD );
1319
0
            aFM = xFont->getFontMetric();
1320
0
        }
1321
0
        else
1322
0
        {
1323
0
            Reference< XGraphics > xG = xD->createGraphics();
1324
0
            aFM = xG->getFontMetric();
1325
0
        }
1326
1327
0
        sal_Int16 nH = aFM.Ascent + aFM.Descent;
1328
0
        sal_Int16 nW = nH/2;    // calculate average width?!
1329
1330
0
        nX *= nW;
1331
0
        nX /= 4;
1332
0
        nWidth *= nW;
1333
0
        nWidth /= 4;
1334
0
        nY *= nH;
1335
0
        nY /= 8;
1336
0
        nHeight *= nH;
1337
0
        nHeight /= 8;
1338
0
    }
1339
0
    Reference < XWindow > xW( rxCtrl, UNO_QUERY );
1340
0
    xW->setPosSize( nX, nY, nWidth, nHeight, PosSize::POSSIZE );
1341
0
}
1342
1343
void ControlContainerBase::dispose()
1344
0
{
1345
0
    EventObject aEvt;
1346
0
    aEvt.Source = getXWeak();
1347
    // Notify our listener helper about dispose
1348
    // --- SAFE ---
1349
1350
0
    SolarMutexClearableGuard aGuard;
1351
0
    rtl::Reference< ResourceListener > xListener = std::move(mxListener);
1352
0
    aGuard.clear();
1353
    // --- SAFE ---
1354
1355
0
    if ( xListener.is() )
1356
0
        xListener->disposing( aEvt );
1357
0
    UnoControlContainer::dispose();
1358
0
}
1359
1360
void SAL_CALL ControlContainerBase::disposing(
1361
    const EventObject& Source )
1362
0
{
1363
0
    UnoControlContainer::disposing( Source );
1364
0
}
1365
1366
sal_Bool ControlContainerBase::setModel( const Reference< XControlModel >& rxModel )
1367
0
{
1368
0
    SolarMutexGuard aGuard;
1369
1370
    // destroy the old tab controller, if existent
1371
0
    if ( mxTabController.is() )
1372
0
    {
1373
0
        mxTabController->setModel( nullptr );                  // just to be sure, should not be necessary
1374
0
        removeTabController( mxTabController );
1375
0
        mxTabController.clear();
1376
0
    }
1377
1378
0
    if ( getModel().is() )
1379
0
    {
1380
0
        const Sequence< Reference< XControl > > aControls = getControls();
1381
1382
0
        for ( const Reference< XControl >& rCtrl : aControls )
1383
0
            removeControl( rCtrl );
1384
                // will implicitly call removingControl, which will remove the PropertyChangeListener
1385
                // (which we formerly did herein)
1386
                // 08.01.2001 - 96008 - fs@openoffice.org
1387
1388
0
        Reference< XContainer > xC( getModel(), UNO_QUERY );
1389
0
        if ( xC.is() )
1390
0
            xC->removeContainerListener( this );
1391
1392
0
        Reference< XChangesNotifier > xChangeNotifier( getModel(), UNO_QUERY );
1393
0
        if ( xChangeNotifier.is() )
1394
0
            xChangeNotifier->removeChangesListener( this );
1395
0
    }
1396
1397
0
    bool bRet = UnoControl::setModel( rxModel );
1398
1399
0
    if ( getModel().is() )
1400
0
    {
1401
0
        Reference< XNameAccess > xNA( getModel(), UNO_QUERY );
1402
0
        if ( xNA.is() )
1403
0
        {
1404
0
            const Sequence< OUString > aNames = xNA->getElementNames();
1405
1406
0
            Reference< XControlModel > xCtrlModel;
1407
0
            for( const OUString& rName : aNames )
1408
0
            {
1409
0
                xNA->getByName( rName ) >>= xCtrlModel;
1410
0
                ImplInsertControl( xCtrlModel, rName );
1411
0
            }
1412
0
        }
1413
1414
0
        Reference< XContainer > xC( getModel(), UNO_QUERY );
1415
0
        if ( xC.is() )
1416
0
            xC->addContainerListener( this );
1417
1418
0
        Reference< XChangesNotifier > xChangeNotifier( getModel(), UNO_QUERY );
1419
0
        if ( xChangeNotifier.is() )
1420
0
            xChangeNotifier->addChangesListener( this );
1421
0
    }
1422
1423
0
    Reference< XTabControllerModel > xTabbing( getModel(), UNO_QUERY );
1424
0
    if ( xTabbing.is() )
1425
0
    {
1426
0
        mxTabController = new StdTabController;
1427
0
        mxTabController->setModel( xTabbing );
1428
0
        addTabController( mxTabController );
1429
0
    }
1430
0
    ImplStartListingForResourceEvents();
1431
1432
0
    return bRet;
1433
0
}
1434
void ControlContainerBase::setDesignMode( sal_Bool bOn )
1435
0
{
1436
0
    SolarMutexGuard aGuard;
1437
1438
0
    UnoControl::setDesignMode( bOn );
1439
1440
0
    Sequence< Reference< XControl > > xCtrls = getControls();
1441
0
    for ( Reference< XControl >& rControl : asNonConstRange(xCtrls) )
1442
0
        rControl->setDesignMode( bOn );
1443
1444
    // #109067# in design mode the tab controller is not notified about
1445
    // tab index changes, therefore the tab order must be activated
1446
    // when switching from design mode to live mode
1447
0
    if ( mxTabController.is() && !bOn )
1448
0
        mxTabController->activateTabOrder();
1449
0
}
1450
1451
void ControlContainerBase::elementInserted( const ContainerEvent& Event )
1452
0
{
1453
0
    SolarMutexGuard aGuard;
1454
1455
0
    Reference< XControlModel > xModel;
1456
0
    OUString aName;
1457
1458
0
    Event.Accessor >>= aName;
1459
0
    Event.Element >>= xModel;
1460
0
    ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementInserted: illegal element!" );
1461
0
    try
1462
0
    {
1463
0
        ImplInsertControl( xModel, aName );
1464
0
    }
1465
0
    catch (const RuntimeException&)
1466
0
    {
1467
0
        throw;
1468
0
    }
1469
0
    catch (const Exception&)
1470
0
    {
1471
0
        DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1472
0
    }
1473
0
}
1474
1475
void ControlContainerBase::elementRemoved( const ContainerEvent& Event )
1476
0
{
1477
0
    SolarMutexGuard aGuard;
1478
1479
0
    Reference< XControlModel > xModel;
1480
0
    Event.Element >>= xModel;
1481
0
    ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementRemoved: illegal element!" );
1482
0
    try
1483
0
    {
1484
0
        ImplRemoveControl( xModel );
1485
0
    }
1486
0
    catch (const RuntimeException&)
1487
0
    {
1488
0
        throw;
1489
0
    }
1490
0
    catch (const Exception&)
1491
0
    {
1492
0
        DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1493
0
    }
1494
0
}
1495
1496
void ControlContainerBase::elementReplaced( const ContainerEvent& Event )
1497
0
{
1498
0
    SolarMutexGuard aGuard;
1499
1500
0
    Reference< XControlModel > xModel;
1501
0
    Event.ReplacedElement >>= xModel;
1502
0
    try
1503
0
    {
1504
0
        OSL_ENSURE( xModel.is(), "ControlContainerBase::elementReplaced: invalid ReplacedElement!" );
1505
0
        if ( xModel.is() )
1506
0
            ImplRemoveControl( xModel );
1507
0
    }
1508
0
    catch (const RuntimeException&)
1509
0
    {
1510
0
        throw;
1511
0
    }
1512
0
    catch (const Exception&)
1513
0
    {
1514
0
        DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1515
0
    }
1516
1517
0
    OUString aName;
1518
0
    Event.Accessor >>= aName;
1519
0
    Event.Element >>= xModel;
1520
0
    ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementReplaced: invalid new element!" );
1521
0
    try
1522
0
    {
1523
0
        ImplInsertControl( xModel, aName );
1524
0
    }
1525
0
    catch (const RuntimeException&)
1526
0
    {
1527
0
        throw;
1528
0
    }
1529
0
    catch (const Exception&)
1530
0
    {
1531
0
        DBG_UNHANDLED_EXCEPTION("toolkit.controls");
1532
0
    }
1533
0
}
1534
1535
// XPropertiesChangeListener
1536
void ControlContainerBase::ImplModelPropertiesChanged( const Sequence< PropertyChangeEvent >& rEvents )
1537
0
{
1538
0
    if( !isDesignMode() && !mbCreatingCompatiblePeer )
1539
0
    {
1540
0
        auto pEvt = std::find_if(rEvents.begin(), rEvents.end(),
1541
0
            [](const PropertyChangeEvent& rEvt) {
1542
0
                return rEvt.PropertyName == "PositionX"
1543
0
                    || rEvt.PropertyName == "PositionY"
1544
0
                    || rEvt.PropertyName == "Width"
1545
0
                    || rEvt.PropertyName == "Height";
1546
0
            });
1547
0
        if (pEvt != rEvents.end())
1548
0
        {
1549
0
            Reference< XControlModel > xModel( pEvt->Source, UNO_QUERY );
1550
0
            bool bOwnModel = xModel.get() == getModel().get();
1551
0
            if ( bOwnModel )
1552
0
            {
1553
0
                if ( !mbPosModified && !mbSizeModified )
1554
0
                {
1555
                    // Don't set new pos/size if we get new values from window listener
1556
0
                    Reference< XControl > xThis(this);
1557
0
                    ImplSetPosSize( xThis );
1558
0
                }
1559
0
            }
1560
0
            else
1561
0
            {
1562
0
                Sequence<Reference<XControl> > aControlSequence(getControls());
1563
0
                Reference<XControl> aControlRef( StdTabController::FindControl( aControlSequence, xModel ) );
1564
0
                ImplSetPosSize( aControlRef );
1565
0
            }
1566
0
        }
1567
0
    }
1568
1569
0
    UnoControlContainer::ImplModelPropertiesChanged( rEvents );
1570
0
}
1571
1572
void ControlContainerBase::addingControl( const Reference< XControl >& _rxControl )
1573
0
{
1574
0
    SolarMutexGuard aGuard;
1575
0
    UnoControlContainer::addingControl( _rxControl );
1576
1577
0
    if ( !_rxControl.is() )
1578
0
        return;
1579
1580
0
    Reference< XMultiPropertySet > xProps( _rxControl->getModel(), UNO_QUERY );
1581
0
    if ( xProps.is() )
1582
0
    {
1583
0
        const Sequence< OUString > aNames {
1584
0
          u"PositionX"_ustr,
1585
0
          u"PositionY"_ustr,
1586
0
          u"Width"_ustr,
1587
0
          u"Height"_ustr
1588
0
        };
1589
1590
0
        xProps->addPropertiesChangeListener( aNames, this );
1591
0
    }
1592
0
}
1593
1594
void ControlContainerBase::removingControl( const Reference< XControl >& _rxControl )
1595
0
{
1596
0
    SolarMutexGuard aGuard;
1597
0
    UnoControlContainer::removingControl( _rxControl );
1598
1599
0
    if ( _rxControl.is() )
1600
0
    {
1601
0
        Reference< XMultiPropertySet > xProps( _rxControl->getModel(), UNO_QUERY );
1602
0
        if ( xProps.is() )
1603
0
            xProps->removePropertiesChangeListener( this );
1604
0
    }
1605
1606
0
}
1607
1608
void SAL_CALL ControlContainerBase::changesOccurred( const ChangesEvent& )
1609
0
{
1610
0
    SolarMutexGuard aGuard;
1611
    // a tab controller model may have changed
1612
1613
    // #109067# in design mode don't notify the tab controller
1614
    // about tab index changes
1615
0
    if ( mxTabController.is() && !mbDesignMode )
1616
0
        mxTabController->activateTabOrder();
1617
0
}
1618
static void lcl_ApplyResolverToNestedContainees(  const Reference< resource::XStringResourceResolver >& xStringResourceResolver, const Reference< XControlContainer >& xContainer )
1619
0
{
1620
0
    OUString aPropName( PROPERTY_RESOURCERESOLVER );
1621
1622
0
    Any aNewStringResourceResolver;
1623
0
    aNewStringResourceResolver <<= xStringResourceResolver;
1624
1625
0
    Sequence< OUString > aPropNames { aPropName };
1626
1627
0
    const Sequence< Reference< awt::XControl > > aSeq = xContainer->getControls();
1628
0
    for ( const Reference< XControl >& xControl : aSeq )
1629
0
    {
1630
0
        Reference< XPropertySet > xPropertySet;
1631
1632
0
        if ( xControl.is() )
1633
0
            xPropertySet.set( xControl->getModel(), UNO_QUERY );
1634
1635
0
        if ( !xPropertySet.is() )
1636
0
            continue;
1637
1638
0
        try
1639
0
        {
1640
0
            Reference< resource::XStringResourceResolver > xCurrStringResourceResolver;
1641
0
            Any aOldValue = xPropertySet->getPropertyValue( aPropName );
1642
0
            if  (   ( aOldValue >>= xCurrStringResourceResolver )
1643
0
                &&  ( xStringResourceResolver == xCurrStringResourceResolver )
1644
0
                )
1645
0
            {
1646
0
                Reference< XMultiPropertySet >  xMultiPropSet( xPropertySet, UNO_QUERY );
1647
0
                Reference< XPropertiesChangeListener > xListener( xPropertySet, UNO_QUERY );
1648
0
                xMultiPropSet->firePropertiesChangeEvent( aPropNames, xListener );
1649
0
            }
1650
0
            else
1651
0
                xPropertySet->setPropertyValue( aPropName, aNewStringResourceResolver );
1652
0
        }
1653
0
        catch (const Exception&)
1654
0
        {
1655
0
        }
1656
1657
0
        uno::Reference< XControlContainer > xNestedContainer( xControl, uno::UNO_QUERY );
1658
0
        if ( xNestedContainer.is() )
1659
0
            lcl_ApplyResolverToNestedContainees(  xStringResourceResolver, xNestedContainer );
1660
1661
0
    }
1662
1663
0
}
1664
void ControlContainerBase::ImplStartListingForResourceEvents()
1665
0
{
1666
0
    Reference< resource::XStringResourceResolver > xStringResourceResolver;
1667
1668
0
    if ( !ImplHasProperty(PROPERTY_RESOURCERESOLVER) )
1669
0
        return;
1670
1671
0
    ImplGetPropertyValue( PROPERTY_RESOURCERESOLVER ) >>= xStringResourceResolver;
1672
1673
    // Add our helper as listener to retrieve notifications about changes.
1674
    // Resource listener will stop listening if resolver reference is empty.
1675
0
    if ( mxListener )
1676
0
        mxListener->startListening( xStringResourceResolver );
1677
0
    ImplUpdateResourceResolver();
1678
0
}
1679
1680
void ControlContainerBase::ImplUpdateResourceResolver()
1681
0
{
1682
0
    Reference< resource::XStringResourceResolver > xStringResourceResolver;
1683
1684
0
    if ( !ImplHasProperty(PROPERTY_RESOURCERESOLVER) )
1685
0
        return;
1686
1687
0
    ImplGetPropertyValue(PROPERTY_RESOURCERESOLVER) >>= xStringResourceResolver;
1688
1689
0
    if ( !xStringResourceResolver.is() )
1690
0
        return;
1691
1692
0
    lcl_ApplyResolverToNestedContainees(  xStringResourceResolver, this );
1693
1694
    // propagate resource resolver changes to language dependent props of the dialog
1695
0
    Reference< XPropertySet > xPropertySet( getModel(), UNO_QUERY );
1696
0
    if ( xPropertySet.is() )
1697
0
    {
1698
0
        Reference< XMultiPropertySet >  xMultiPropSet( xPropertySet, UNO_QUERY );
1699
0
        Reference< XPropertiesChangeListener > xListener( xPropertySet, UNO_QUERY );
1700
0
        xMultiPropSet->firePropertiesChangeEvent( lcl_getLanguageDependentProperties(), xListener );
1701
0
    }
1702
0
}
1703
1704
////    ----------------------------------------------------
1705
////    Helper Method to convert relative url to physical location
1706
////    ----------------------------------------------------
1707
1708
OUString getPhysicalLocation( const css::uno::Any& rbase, const css::uno::Any& rUrl )
1709
0
{
1710
1711
0
    OUString baseLocation;
1712
0
    OUString url;
1713
1714
0
    rbase  >>= baseLocation;
1715
0
    rUrl  >>= url;
1716
1717
0
    OUString absoluteURL( url );
1718
0
    if ( !url.isEmpty() )
1719
0
    {
1720
0
        INetURLObject urlObj(baseLocation);
1721
0
        urlObj.removeSegment();
1722
0
        baseLocation = urlObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1723
1724
0
        const INetURLObject protocolCheck( url );
1725
0
        const INetProtocol protocol = protocolCheck.GetProtocol();
1726
0
        if ( protocol == INetProtocol::NotValid )
1727
0
        {
1728
0
            OUString testAbsoluteURL;
1729
0
            if ( ::osl::FileBase::E_None == ::osl::FileBase::getAbsoluteFileURL( baseLocation, url, testAbsoluteURL ) )
1730
0
                absoluteURL = testAbsoluteURL;
1731
0
        }
1732
0
    }
1733
1734
0
    return absoluteURL;
1735
0
}
1736
1737
void
1738
ControlModelContainerBase::updateUserFormChildren( const Reference< XNameContainer >& xAllChildren, const OUString& aName, ChildOperation Operation, const css::uno::Reference< css::awt::XControlModel >& xTarget )
1739
0
{
1740
0
    if ( Operation < Insert || Operation > Remove )
1741
0
        throw IllegalArgumentException();
1742
1743
0
    if ( !xAllChildren.is() )
1744
0
        throw IllegalArgumentException();
1745
1746
0
    if ( Operation == Remove )
1747
0
    {
1748
0
        Reference< XControlModel > xOldModel( xAllChildren->getByName( aName ), UNO_QUERY );
1749
0
        xAllChildren->removeByName( aName );
1750
1751
0
        Reference< XNameContainer > xChildContainer( xOldModel, UNO_QUERY );
1752
0
        if ( xChildContainer.is() )
1753
0
        {
1754
0
            Reference< XPropertySet > xProps( xChildContainer, UNO_QUERY );
1755
            // container control is being removed from this container, reset the
1756
            // global list of containers
1757
0
            if ( xProps.is() )
1758
0
                xProps->setPropertyValue(  GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ), uno::Any( uno::Reference< XNameContainer >() ) );
1759
0
            const Sequence< OUString > aChildNames = xChildContainer->getElementNames();
1760
0
            for ( const auto& rName : aChildNames )
1761
0
                updateUserFormChildren( xAllChildren, rName, Operation,  Reference< XControlModel > () );
1762
0
        }
1763
0
    }
1764
0
    else if ( Operation == Insert )
1765
0
    {
1766
0
        xAllChildren->insertByName( aName, uno::Any( xTarget ) );
1767
0
        Reference< XNameContainer > xChildContainer( xTarget, UNO_QUERY );
1768
0
        if ( xChildContainer.is() )
1769
0
        {
1770
            // container control is being added from this container, reset the
1771
            // global list of containers to point to the correct global list
1772
0
            Reference< XPropertySet > xProps( xChildContainer, UNO_QUERY );
1773
0
            if ( xProps.is() )
1774
0
                xProps->setPropertyValue(  GetPropertyName( BASEPROPERTY_USERFORMCONTAINEES ), uno::Any( xAllChildren ) );
1775
0
            const Sequence< OUString > aChildNames = xChildContainer->getElementNames();
1776
0
            for ( const auto& rName : aChildNames )
1777
0
            {
1778
0
                Reference< XControlModel > xChildTarget( xChildContainer->getByName( rName ), UNO_QUERY );
1779
0
                updateUserFormChildren( xAllChildren, rName, Operation, xChildTarget );
1780
0
            }
1781
0
        }
1782
0
    }
1783
1784
0
}
1785
1786
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */