Coverage Report

Created: 2026-10-14 09:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/form/fmshimp.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
#include <sal/config.h>
21
22
#include <o3tl/safeint.hxx>
23
#include <sal/macros.h>
24
#include <sal/log.hxx>
25
#include <fmobj.hxx>
26
#include <fmpgeimp.hxx>
27
#include <svx/fmtools.hxx>
28
#include <fmprop.hxx>
29
#include <fmservs.hxx>
30
#include <fmshimp.hxx>
31
#include <fmtextcontrolshell.hxx>
32
#include <fmundo.hxx>
33
#include <fmurl.hxx>
34
#include <fmvwimp.hxx>
35
#include <gridcols.hxx>
36
#include <svx/svditer.hxx>
37
#include <svx/dialmgr.hxx>
38
#include <svx/strings.hrc>
39
#include <svx/svdobjkind.hxx>
40
#include <svx/fmmodel.hxx>
41
#include <svx/fmpage.hxx>
42
#include <svx/fmshell.hxx>
43
#include <svx/fmview.hxx>
44
#include <svx/obj3d.hxx>
45
#include <svx/sdrpagewindow.hxx>
46
#include <svx/svdpagv.hxx>
47
#include <svx/svxdlg.hxx>
48
#include <svx/svxids.hrc>
49
#include <bitmaps.hlst>
50
#include <formnavi.hrc>
51
52
#include <com/sun/star/awt/XWindow2.hpp>
53
#include <com/sun/star/awt/XCheckBox.hpp>
54
#include <com/sun/star/awt/XListBox.hpp>
55
#include <com/sun/star/awt/XTextComponent.hpp>
56
#include <com/sun/star/beans/theIntrospection.hpp>
57
#include <com/sun/star/beans/PropertyAttribute.hpp>
58
#include <com/sun/star/beans/XPropertyState.hpp>
59
#include <com/sun/star/container/XContainer.hpp>
60
#include <com/sun/star/container/XIndexAccess.hpp>
61
#include <com/sun/star/container/XNamed.hpp>
62
#include <com/sun/star/form/ListSourceType.hpp>
63
#include <com/sun/star/form/TabOrderDialog.hpp>
64
#include <com/sun/star/form/XGrid.hpp>
65
#include <com/sun/star/form/XGridPeer.hpp>
66
#include <com/sun/star/form/XLoadable.hpp>
67
#include <com/sun/star/form/XReset.hpp>
68
#include <com/sun/star/form/binding/XBindableValue.hpp>
69
#include <com/sun/star/form/binding/XListEntrySink.hpp>
70
#include <com/sun/star/frame/FrameSearchFlag.hpp>
71
#include <com/sun/star/lang/XServiceInfo.hpp>
72
#include <com/sun/star/script/XEventAttacherManager.hpp>
73
#include <com/sun/star/sdbc/SQLException.hpp>
74
#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
75
#include <com/sun/star/util/XModeSelector.hpp>
76
#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
77
#include <com/sun/star/view/XSelectionSupplier.hpp>
78
79
#include <comphelper/evtmethodhelper.hxx>
80
#include <comphelper/processfactory.hxx>
81
#include <comphelper/property.hxx>
82
#include <comphelper/sequence.hxx>
83
#include <comphelper/solarmutex.hxx>
84
#include <comphelper/string.hxx>
85
#include <comphelper/types.hxx>
86
#include <connectivity/dbtools.hxx>
87
#include <sfx2/dispatch.hxx>
88
#include <sfx2/frame.hxx>
89
#include <sfx2/objsh.hxx>
90
#include <sfx2/viewfrm.hxx>
91
#include <sfx2/viewsh.hxx>
92
#include <toolkit/controls/unocontrolcontainer.hxx>
93
#include <toolkit/helper/vclunohelper.hxx>
94
#include <tools/debug.hxx>
95
#include <comphelper/diagnose_ex.hxx>
96
#include <comphelper/configuration.hxx>
97
#include <vcl/settings.hxx>
98
#include <vcl/svapp.hxx>
99
#include <vcl/weld/Menu.hxx>
100
#include <vcl/weld/MessageDialog.hxx>
101
#include <vcl/window.hxx>
102
103
#include <algorithm>
104
#include <map>
105
#include <memory>
106
#include <string_view>
107
#include <vector>
108
109
// is used for Invalidate -> maintain it as well
110
const sal_uInt16 DatabaseSlotMap[] =
111
{
112
    SID_FM_RECORD_FIRST,
113
    SID_FM_RECORD_NEXT,
114
    SID_FM_RECORD_PREV,
115
    SID_FM_RECORD_LAST,
116
    SID_FM_RECORD_NEW,
117
    SID_FM_RECORD_DELETE,
118
    SID_FM_RECORD_ABSOLUTE,
119
    SID_FM_RECORD_TOTAL,
120
    SID_FM_RECORD_SAVE,
121
    SID_FM_RECORD_UNDO,
122
    SID_FM_REMOVE_FILTER_SORT,
123
    SID_FM_SORTUP,
124
    SID_FM_SORTDOWN,
125
    SID_FM_ORDERCRIT,
126
    SID_FM_AUTOFILTER,
127
    SID_FM_FORM_FILTERED,
128
    SID_FM_REFRESH,
129
    SID_FM_REFRESH_FORM_CONTROL,
130
    SID_FM_SEARCH,
131
    SID_FM_FILTER_START,
132
    SID_FM_VIEW_AS_GRID,
133
    0
134
};
135
136
// is used for Invalidate -> maintain it as well
137
// sort ascending !!!!!!
138
const sal_uInt16 DlgSlotMap[] =    // slots of the controller
139
{
140
    SID_FM_CTL_PROPERTIES,
141
    SID_FM_PROPERTIES,
142
    SID_FM_TAB_DIALOG,
143
    SID_FM_ADD_FIELD,
144
    SID_FM_SHOW_FMEXPLORER,
145
    SID_FM_FIELDS_CONTROL,
146
    SID_FM_SHOW_PROPERTIES,
147
    SID_FM_PROPERTY_CONTROL,
148
    SID_FM_FMEXPLORER_CONTROL,
149
    SID_FM_SHOW_DATANAVIGATOR,
150
    SID_FM_DATANAVIGATOR_CONTROL,
151
    0
152
};
153
154
const sal_uInt16 SelObjectSlotMap[] =  // slots depending on the SelObject
155
{
156
    SID_FM_CONVERTTO_EDIT,
157
    SID_FM_CONVERTTO_BUTTON,
158
    SID_FM_CONVERTTO_FIXEDTEXT,
159
    SID_FM_CONVERTTO_LISTBOX,
160
    SID_FM_CONVERTTO_CHECKBOX,
161
    SID_FM_CONVERTTO_RADIOBUTTON,
162
    SID_FM_CONVERTTO_GROUPBOX,
163
    SID_FM_CONVERTTO_COMBOBOX,
164
    SID_FM_CONVERTTO_IMAGEBUTTON,
165
    SID_FM_CONVERTTO_FILECONTROL,
166
    SID_FM_CONVERTTO_DATE,
167
    SID_FM_CONVERTTO_TIME,
168
    SID_FM_CONVERTTO_NUMERIC,
169
    SID_FM_CONVERTTO_CURRENCY,
170
    SID_FM_CONVERTTO_PATTERN,
171
    SID_FM_CONVERTTO_IMAGECONTROL,
172
    SID_FM_CONVERTTO_FORMATTED,
173
    SID_FM_CONVERTTO_SCROLLBAR,
174
    SID_FM_CONVERTTO_SPINBUTTON,
175
    SID_FM_CONVERTTO_NAVIGATIONBAR,
176
177
    SID_FM_FMEXPLORER_CONTROL,
178
    SID_FM_DATANAVIGATOR_CONTROL,
179
180
    0
181
};
182
183
// the following arrays must be consistent, i.e., corresponding entries should
184
// be at the same relative position within their respective arrays
185
constexpr std::u16string_view aConvertSlots[] =
186
{
187
    u"ConvertToEdit",
188
    u"ConvertToButton",
189
    u"ConvertToFixed",
190
    u"ConvertToList",
191
    u"ConvertToCheckBox",
192
    u"ConvertToRadio",
193
    u"ConvertToGroup",
194
    u"ConvertToCombo",
195
    u"ConvertToImageBtn",
196
    u"ConvertToFileControl",
197
    u"ConvertToDate",
198
    u"ConvertToTime",
199
    u"ConvertToNumeric",
200
    u"ConvertToCurrency",
201
    u"ConvertToPattern",
202
    u"ConvertToImageControl",
203
    u"ConvertToFormatted",
204
    u"ConvertToScrollBar",
205
    u"ConvertToSpinButton",
206
    u"ConvertToNavigationBar"
207
};
208
209
constexpr OUString aImgIds[] =
210
{
211
    RID_SVXBMP_EDITBOX,
212
    RID_SVXBMP_BUTTON,
213
    RID_SVXBMP_FIXEDTEXT,
214
    RID_SVXBMP_LISTBOX,
215
    RID_SVXBMP_CHECKBOX,
216
    RID_SVXBMP_RADIOBUTTON,
217
    RID_SVXBMP_GROUPBOX,
218
    RID_SVXBMP_COMBOBOX,
219
    RID_SVXBMP_IMAGEBUTTON,
220
    RID_SVXBMP_FILECONTROL,
221
    RID_SVXBMP_DATEFIELD,
222
    RID_SVXBMP_TIMEFIELD,
223
    RID_SVXBMP_NUMERICFIELD,
224
    RID_SVXBMP_CURRENCYFIELD,
225
    RID_SVXBMP_PATTERNFIELD,
226
    RID_SVXBMP_IMAGECONTROL,
227
    RID_SVXBMP_FORMATTEDFIELD,
228
    RID_SVXBMP_SCROLLBAR,
229
    RID_SVXBMP_SPINBUTTON,
230
    RID_SVXBMP_NAVIGATIONBAR
231
};
232
233
const SdrObjKind nObjectTypes[] =
234
{
235
    SdrObjKind::FormEdit,
236
    SdrObjKind::FormButton,
237
    SdrObjKind::FormFixedText,
238
    SdrObjKind::FormListbox,
239
    SdrObjKind::FormCheckbox,
240
    SdrObjKind::FormRadioButton,
241
    SdrObjKind::FormGroupBox,
242
    SdrObjKind::FormCombobox,
243
    SdrObjKind::FormImageButton,
244
    SdrObjKind::FormFileControl,
245
    SdrObjKind::FormDateField,
246
    SdrObjKind::FormTimeField,
247
    SdrObjKind::FormNumericField,
248
    SdrObjKind::FormCurrencyField,
249
    SdrObjKind::FormPatternField,
250
    SdrObjKind::FormImageControl,
251
    SdrObjKind::FormFormattedField,
252
    SdrObjKind::FormScrollbar,
253
    SdrObjKind::FormSpinButton,
254
    SdrObjKind::FormNavigationBar
255
};
256
257
using namespace ::com::sun::star;
258
using namespace ::com::sun::star::ui;
259
using namespace ::com::sun::star::uno;
260
using namespace ::com::sun::star::sdb;
261
using namespace ::com::sun::star::sdbc;
262
using namespace ::com::sun::star::sdbcx;
263
using namespace ::com::sun::star::beans;
264
using namespace ::com::sun::star::container;
265
using namespace ::com::sun::star::form;
266
using namespace ::com::sun::star::form::binding;
267
using namespace ::com::sun::star::form::runtime;
268
using namespace ::com::sun::star::awt;
269
using namespace ::com::sun::star::view;
270
using namespace ::com::sun::star::util;
271
using namespace ::com::sun::star::script;
272
using namespace ::svxform;
273
using namespace ::svx;
274
using namespace ::dbtools;
275
276
277
//= helper
278
279
namespace
280
{
281
282
    void collectInterfacesFromMarkList( const SdrMarkList& _rMarkList, InterfaceBag& /* [out] */ _rInterfaces )
283
0
    {
284
0
        _rInterfaces.clear();
285
286
0
        const size_t nMarkCount = _rMarkList.GetMarkCount();
287
0
        for ( size_t i = 0; i < nMarkCount; ++i)
288
0
        {
289
0
            SdrObject* pCurrent = _rMarkList.GetMark( i )->GetMarkedSdrObj();
290
0
            assert(pCurrent && "marked object will exist");
291
292
0
            std::optional<SdrObjListIter> oGroupIterator;
293
0
            if ( pCurrent->IsGroupObject() )
294
0
            {
295
0
                oGroupIterator.emplace( pCurrent->GetSubList() );
296
0
                pCurrent = oGroupIterator->IsMore() ? oGroupIterator->Next() : nullptr;
297
0
            }
298
299
0
            while ( pCurrent )
300
0
            {
301
0
                FmFormObj* pAsFormObject = FmFormObj::GetFormObject( pCurrent );
302
                    // note this will de-reference virtual objects, if necessary/possible
303
0
                if ( pAsFormObject )
304
0
                {
305
0
                    Reference< XInterface > xControlModel( pAsFormObject->GetUnoControlModel(), UNO_QUERY );
306
                        // the UNO_QUERY is important for normalization
307
0
                    if ( xControlModel.is() )
308
0
                        _rInterfaces.insert( xControlModel );
309
0
                }
310
311
                // next element
312
0
                pCurrent = oGroupIterator && oGroupIterator->IsMore() ? oGroupIterator->Next() : nullptr;
313
0
            }
314
0
        }
315
0
    }
316
317
318
    sal_Int32 GridView2ModelPos(const Reference< XIndexAccess>& rColumns, sal_Int16 nViewPos)
319
0
    {
320
0
        try
321
0
        {
322
0
            if (rColumns.is())
323
0
            {
324
                // loop through all columns
325
0
                sal_Int32 i;
326
0
                Reference< XPropertySet> xCur;
327
0
                for (i=0; i<rColumns->getCount(); ++i)
328
0
                {
329
0
                    rColumns->getByIndex(i) >>= xCur;
330
0
                    if (!::comphelper::getBOOL(xCur->getPropertyValue(FM_PROP_HIDDEN)))
331
0
                    {
332
                        // for every visible col : if nViewPos is greater zero, decrement it, else we
333
                        // have found the model position
334
0
                        if (!nViewPos)
335
0
                            break;
336
0
                        else
337
0
                            --nViewPos;
338
0
                    }
339
0
                }
340
0
                if (i<rColumns->getCount())
341
0
                    return i;
342
0
            }
343
0
        }
344
0
        catch(const Exception&)
345
0
        {
346
0
            DBG_UNHANDLED_EXCEPTION("svx");
347
0
        }
348
0
        return -1;
349
0
    }
350
351
352
    void TransferEventScripts(const Reference< XControlModel>& xModel, const Reference< XControl>& xControl,
353
        const Sequence< ScriptEventDescriptor>& rTransferIfAvailable)
354
0
    {
355
        // first check if we have a XEventAttacherManager for the model
356
0
        Reference< XChild> xModelChild(xModel, UNO_QUERY);
357
0
        if (!xModelChild.is())
358
0
            return; // nothing to do
359
360
0
        Reference< XEventAttacherManager> xEventManager(xModelChild->getParent(), UNO_QUERY);
361
0
        if (!xEventManager.is())
362
0
            return; // nothing to do
363
364
0
        if (!rTransferIfAvailable.hasElements())
365
0
            return; // nothing to do
366
367
        // check for the index of the model within its parent
368
0
        Reference< XIndexAccess> xParentIndex(xModelChild->getParent(), UNO_QUERY);
369
0
        if (!xParentIndex.is())
370
0
            return; // nothing to do
371
0
        sal_Int32 nIndex = getElementPos(xParentIndex, xModel);
372
0
        if (nIndex<0 || nIndex>=xParentIndex->getCount())
373
0
            return; // nothing to do
374
375
        // then we need information about the listeners supported by the control and the model
376
0
        Sequence< Type> aModelListeners;
377
0
        Sequence< Type> aControlListeners;
378
379
0
        Reference< XIntrospection> xIntrospection = theIntrospection::get(::comphelper::getProcessComponentContext());
380
381
0
        if (xModel.is())
382
0
        {
383
0
            Any aModel(xModel);
384
0
            aModelListeners = xIntrospection->inspect(aModel)->getSupportedListeners();
385
0
        }
386
387
0
        if (xControl.is())
388
0
        {
389
0
            Any aControl(xControl);
390
0
            aControlListeners = xIntrospection->inspect(aControl)->getSupportedListeners();
391
0
        }
392
393
0
        sal_Int32 nMaxNewLen = aModelListeners.getLength() + aControlListeners.getLength();
394
0
        if (!nMaxNewLen)
395
0
            return; // the model and the listener don't support any listeners (or we were unable to retrieve these infos)
396
397
0
        Sequence< ScriptEventDescriptor>    aTransferable(nMaxNewLen);
398
0
        ScriptEventDescriptor* pTransferable = aTransferable.getArray();
399
400
0
        for (const ScriptEventDescriptor& rCurrent : rTransferIfAvailable)
401
0
        {
402
            // search the model/control idl classes for the event described by pCurrent
403
0
            for (const Sequence< Type>* pCurrentArray : { &aModelListeners, &aControlListeners })
404
0
            {
405
0
                for (const Type& rCurrentListener : *pCurrentArray)
406
0
                {
407
0
                    OUString aListener = rCurrentListener.getTypeName();
408
0
                    if (!aListener.isEmpty())
409
0
                        aListener = aListener.copy(aListener.lastIndexOf('.')+1);
410
411
0
                    if (aListener == rCurrent.ListenerType)
412
                        // the current ScriptEventDescriptor doesn't match the current listeners class
413
0
                        continue;
414
415
                    // now check the methods
416
0
                    Sequence< OUString> aMethodsNames = ::comphelper::getEventMethodsForType(rCurrentListener);
417
418
0
                    if (comphelper::findValue(aMethodsNames, rCurrent.EventMethod) != -1)
419
0
                    {
420
                        // we can transfer the script event : the model (control) supports it
421
0
                        *pTransferable = rCurrent;
422
0
                        ++pTransferable;
423
0
                        break;
424
0
                    }
425
0
                }
426
0
            }
427
0
        }
428
429
0
        sal_Int32 nRealNewLen = pTransferable - aTransferable.getArray();
430
0
        aTransferable.realloc(nRealNewLen);
431
432
0
        xEventManager->registerScriptEvents(nIndex, aTransferable);
433
0
    }
434
435
436
    const OUString & getServiceNameByControlType(SdrObjKind nType)
437
0
    {
438
0
        switch (nType)
439
0
        {
440
0
            case SdrObjKind::FormEdit            : return FM_COMPONENT_TEXTFIELD;
441
0
            case SdrObjKind::FormButton          : return FM_COMPONENT_COMMANDBUTTON;
442
0
            case SdrObjKind::FormFixedText       : return FM_COMPONENT_FIXEDTEXT;
443
0
            case SdrObjKind::FormListbox         : return FM_COMPONENT_LISTBOX;
444
0
            case SdrObjKind::FormCheckbox        : return FM_COMPONENT_CHECKBOX;
445
0
            case SdrObjKind::FormRadioButton     : return FM_COMPONENT_RADIOBUTTON;
446
0
            case SdrObjKind::FormGroupBox        : return FM_COMPONENT_GROUPBOX;
447
0
            case SdrObjKind::FormCombobox        : return FM_COMPONENT_COMBOBOX;
448
0
            case SdrObjKind::FormGrid            : return FM_COMPONENT_GRIDCONTROL;
449
0
            case SdrObjKind::FormImageButton     : return FM_COMPONENT_IMAGEBUTTON;
450
0
            case SdrObjKind::FormFileControl     : return FM_COMPONENT_FILECONTROL;
451
0
            case SdrObjKind::FormDateField       : return FM_COMPONENT_DATEFIELD;
452
0
            case SdrObjKind::FormTimeField       : return FM_COMPONENT_TIMEFIELD;
453
0
            case SdrObjKind::FormNumericField    : return FM_COMPONENT_NUMERICFIELD;
454
0
            case SdrObjKind::FormCurrencyField   : return FM_COMPONENT_CURRENCYFIELD;
455
0
            case SdrObjKind::FormPatternField    : return FM_COMPONENT_PATTERNFIELD;
456
0
            case SdrObjKind::FormHidden          : return FM_COMPONENT_HIDDENCONTROL;
457
0
            case SdrObjKind::FormImageControl    : return FM_COMPONENT_IMAGECONTROL;
458
0
            case SdrObjKind::FormFormattedField  : return FM_COMPONENT_FORMATTEDFIELD;
459
0
            case SdrObjKind::FormScrollbar       : return FM_SUN_COMPONENT_SCROLLBAR;
460
0
            case SdrObjKind::FormSpinButton      : return FM_SUN_COMPONENT_SPINBUTTON;
461
0
            case SdrObjKind::FormNavigationBar   : return FM_SUN_COMPONENT_NAVIGATIONBAR;
462
0
            default:;
463
0
        }
464
0
        return EMPTY_OUSTRING;
465
0
    }
466
467
}
468
469
470
// check if the control has one of the interfaces we can use for searching
471
// *_pCurrentText will be filled with the current text of the control (as used when searching this control)
472
bool IsSearchableControl( const css::uno::Reference< css::uno::XInterface>& _rxControl,
473
    OUString* _pCurrentText )
474
0
{
475
0
    if ( !_rxControl.is() )
476
0
        return false;
477
478
0
    Reference< XTextComponent > xAsText( _rxControl, UNO_QUERY );
479
0
    if ( xAsText.is() )
480
0
    {
481
0
        if ( _pCurrentText )
482
0
            *_pCurrentText = xAsText->getText();
483
0
        return true;
484
0
    }
485
486
0
    Reference< XListBox > xListBox( _rxControl, UNO_QUERY );
487
0
    if ( xListBox.is() )
488
0
    {
489
0
        if ( _pCurrentText )
490
0
            *_pCurrentText = xListBox->getSelectedItem();
491
0
        return true;
492
0
    }
493
494
0
    Reference< XCheckBox > xCheckBox( _rxControl, UNO_QUERY );
495
0
    if ( xCheckBox.is() )
496
0
    {
497
0
        if ( _pCurrentText )
498
0
        {
499
0
            switch ( static_cast<::TriState>(xCheckBox->getState()) )
500
0
            {
501
0
                case TRISTATE_FALSE: *_pCurrentText = "0"; break;
502
0
                case TRISTATE_TRUE: *_pCurrentText = "1"; break;
503
0
                default: _pCurrentText->clear(); break;
504
0
            }
505
0
        }
506
0
        return true;
507
0
    }
508
509
0
    return false;
510
0
}
511
512
513
bool FmXBoundFormFieldIterator::ShouldStepInto(const Reference< XInterface>& _rContainer) const
514
0
{
515
0
    if (_rContainer == m_xStartingPoint)
516
        // would be quite stupid to step over the root...
517
0
        return true;
518
519
0
    return Reference< XControlModel>(_rContainer, UNO_QUERY).is();
520
0
}
521
522
523
bool FmXBoundFormFieldIterator::ShouldHandleElement(const Reference< XInterface>& _rElement)
524
0
{
525
0
    if (!_rElement.is())
526
        // NULL element
527
0
        return false;
528
529
0
    if (Reference< XForm>(_rElement, UNO_QUERY).is() || Reference< XGrid>(_rElement, UNO_QUERY).is())
530
        // a forms or a grid
531
0
        return false;
532
533
0
    Reference< XPropertySet> xSet(_rElement, UNO_QUERY);
534
0
    if (!xSet.is() || !::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
535
        // no "BoundField" property
536
0
        return false;
537
538
0
    Any aVal( xSet->getPropertyValue(FM_PROP_BOUNDFIELD) );
539
0
    if (aVal.getValueTypeClass() != TypeClass_INTERFACE)
540
        // void or invalid property value
541
0
        return false;
542
543
0
    return aVal.hasValue();
544
0
}
545
546
547
static bool isControlList(const SdrMarkList& rMarkList)
548
0
{
549
    // the list contains only controls and at least one control
550
0
    const size_t nMarkCount = rMarkList.GetMarkCount();
551
0
    bool  bControlList = nMarkCount != 0;
552
553
0
    bool bHadAnyLeafs = false;
554
555
0
    for (size_t i = 0; i < nMarkCount && bControlList; ++i)
556
0
    {
557
0
        SdrObject *pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
558
0
        E3dObject* pAs3DObject = DynCastE3dObject( pObj);
559
        // E3dObject's do not contain any 2D-objects (by definition)
560
        // we need this extra check here : an E3dObject->IsGroupObject says "YES", but an SdrObjListIter working
561
        // with an E3dObject doesn't give me any Nodes (E3dObject has a sub list, but no members in that list,
562
        // cause their implementation differs from the one of "normal" SdrObject's. Unfortunately SdrObject::IsGroupObject
563
        // doesn't check the element count of the sub list, which is simply a bug in IsGroupObject we can't fix at the moment).
564
        // So at the end of this function bControlList would have the same value it was initialized with above : sal_True
565
        // And this would be wrong :)
566
        // 03.02.00 - 72529 - FS
567
0
        if (!pAs3DObject)
568
0
        {
569
0
            if (pObj->IsGroupObject())
570
0
            {
571
0
                SdrObjListIter aIter(pObj->GetSubList());
572
0
                while (aIter.IsMore() && bControlList)
573
0
                {
574
0
                    bControlList = SdrInventor::FmForm == aIter.Next()->GetObjInventor();
575
0
                    bHadAnyLeafs = true;
576
0
                }
577
0
            }
578
0
            else
579
0
            {
580
0
                bHadAnyLeafs = true;
581
0
                bControlList = SdrInventor::FmForm == pObj->GetObjInventor();
582
0
            }
583
0
        }
584
0
    }
585
586
0
    return bControlList && bHadAnyLeafs;
587
0
}
588
589
590
static Reference< XForm > GetForm(const Reference< XInterface>& _rxElement)
591
0
{
592
0
    Reference< XForm > xForm( _rxElement, UNO_QUERY );
593
0
    if ( xForm.is() )
594
0
        return xForm;
595
596
0
    Reference< XChild > xChild( _rxElement, UNO_QUERY );
597
0
    if ( xChild.is() )
598
0
        return GetForm( xChild->getParent() );
599
600
0
    return Reference< XForm >();
601
0
}
602
603
FmXFormShell_Base_Disambiguation::FmXFormShell_Base_Disambiguation( ::osl::Mutex& _rMutex )
604
8.87k
    :FmXFormShell_BD_BASE( _rMutex )
605
8.87k
{
606
8.87k
}
607
608
FmXFormShell::FmXFormShell( FmFormShell& _rShell, SfxViewFrame* _pViewFrame )
609
8.87k
        :FmXFormShell_BASE(m_aMutex)
610
8.87k
        ,FmXFormShell_CFGBASE(u"Office.Common/Misc"_ustr, ConfigItemMode::NONE)
611
8.87k
        ,m_aMarkTimer("svx::FmXFormShell m_aMarkTimer")
612
8.87k
        ,m_eNavigate( NavigationBarMode_NONE )
613
8.87k
        ,m_nInvalidationEvent( nullptr )
614
8.87k
        ,m_nActivationEvent( nullptr )
615
8.87k
        ,m_pShell( &_rShell )
616
8.87k
        ,m_pTextShell( new svx::FmTextControlShell( _pViewFrame ) )
617
8.87k
        ,m_aActiveControllerFeatures( this )
618
8.87k
        ,m_aNavControllerFeatures( this )
619
8.87k
        ,m_eDocumentType( eUnknownDocumentType )
620
8.87k
        ,m_nLockSlotInvalidation( 0 )
621
8.87k
        ,m_bHadPropertyBrowserInDesignMode( false )
622
8.87k
        ,m_bTrackProperties( true )
623
8.87k
        ,m_bUseWizards( true )
624
8.87k
        ,m_bDatabaseBar( false )
625
8.87k
        ,m_bInActivate( false )
626
8.87k
        ,m_bSetFocus( false )
627
8.87k
        ,m_bFilterMode( false )
628
8.87k
        ,m_bChangingDesignMode( false )
629
8.87k
        ,m_bPreparedClose( false )
630
8.87k
        ,m_bFirstActivation( true )
631
8.87k
{
632
8.87k
    m_aMarkTimer.SetTimeout(100);
633
8.87k
    m_aMarkTimer.SetInvokeHandler(LINK(this, FmXFormShell, OnTimeOut_Lock));
634
635
8.87k
    m_xAttachedFrame = _pViewFrame->GetFrame().GetFrameInterface();
636
637
    // to prevent deletion of this we acquire our refcounter once
638
8.87k
    osl_atomic_increment(&m_refCount);
639
640
    // correct the refcounter
641
8.87k
    osl_atomic_decrement(&m_refCount);
642
643
    // cache the current configuration settings we're interested in
644
8.87k
    implAdjustConfigCache_Lock();
645
    // and register for changes on this settings
646
8.87k
    Sequence< OUString > aNames { u"FormControlPilotsEnabled"_ustr };
647
8.87k
    EnableNotification(aNames);
648
8.87k
}
649
650
651
FmXFormShell::~FmXFormShell()
652
8.87k
{
653
8.87k
}
654
655
656
Reference< css::frame::XModel > FmXFormShell::getContextDocument_Lock() const
657
8.87k
{
658
8.87k
    Reference< css::frame::XModel > xModel;
659
660
    // determine the type of document we live in
661
8.87k
    try
662
8.87k
    {
663
8.87k
        Reference< css::frame::XController > xController;
664
8.87k
        if ( m_xAttachedFrame.is() )
665
8.87k
            xController = m_xAttachedFrame->getController();
666
8.87k
        if ( xController.is() )
667
8.87k
            xModel = xController->getModel();
668
8.87k
    }
669
8.87k
    catch( const Exception& )
670
8.87k
    {
671
0
        DBG_UNHANDLED_EXCEPTION("svx");
672
0
    }
673
8.87k
    return xModel;
674
8.87k
}
675
676
677
bool FmXFormShell::isEnhancedForm_Lock() const
678
8.87k
{
679
8.87k
    return getDocumentType_Lock() == eEnhancedForm;
680
8.87k
}
681
682
683
bool FmXFormShell::impl_checkDisposed_Lock() const
684
71.0k
{
685
71.0k
    DBG_TESTSOLARMUTEX();
686
71.0k
    if ( !m_pShell )
687
0
    {
688
0
        OSL_FAIL( "FmXFormShell::impl_checkDisposed: already disposed!" );
689
0
        return true;
690
0
    }
691
71.0k
    return false;
692
71.0k
}
693
694
695
::svxform::DocumentType FmXFormShell::getDocumentType_Lock() const
696
8.87k
{
697
8.87k
    if ( m_eDocumentType != eUnknownDocumentType )
698
0
        return m_eDocumentType;
699
700
    // determine the type of document we live in
701
8.87k
    Reference<css::frame::XModel> xModel = getContextDocument_Lock();
702
8.87k
    if ( xModel.is() )
703
8.87k
        m_eDocumentType = DocumentClassification::classifyDocument( xModel );
704
0
    else
705
0
    {
706
0
        OSL_FAIL( "FmXFormShell::getDocumentType: can't determine the document type!" );
707
0
        m_eDocumentType = eTextDocument;
708
            // fallback, just to have a defined state
709
0
    }
710
711
8.87k
    return m_eDocumentType;
712
8.87k
}
713
714
715
bool FmXFormShell::IsReadonlyDoc_Lock() const
716
8.87k
{
717
8.87k
    if (impl_checkDisposed_Lock())
718
0
        return true;
719
720
8.87k
    FmFormModel* pModel = m_pShell->GetFormModel();
721
8.87k
    if ( pModel && pModel->GetObjectShell() )
722
8.87k
        return pModel->GetObjectShell()->IsReadOnly() || pModel->GetObjectShell()->IsReadOnlyUI();
723
0
    return true;
724
8.87k
}
725
726
//  EventListener
727
728
void SAL_CALL FmXFormShell::disposing(const lang::EventObject& e)
729
0
{
730
0
    SolarMutexGuard g;
731
732
0
    if (m_xActiveController == e.Source)
733
0
    {
734
        // the controller will release, then release everything
735
0
        stopListening_Lock();
736
0
        m_xActiveForm = nullptr;
737
0
        m_xActiveController = nullptr;
738
0
        m_xNavigationController = nullptr;
739
740
0
        m_aActiveControllerFeatures.dispose();
741
0
        m_aNavControllerFeatures.dispose();
742
743
0
        if ( m_pShell )
744
0
            m_pShell->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell);
745
0
    }
746
747
0
    if (e.Source != m_xExternalViewController)
748
0
        return;
749
750
0
    Reference< runtime::XFormController > xFormController( m_xExternalViewController, UNO_QUERY );
751
0
    OSL_ENSURE( xFormController.is(), "FmXFormShell::disposing: invalid external view controller!" );
752
0
    if (xFormController.is())
753
0
        xFormController->removeActivateListener(static_cast<XFormControllerListener*>(this));
754
755
0
    if (m_xExternalViewController.is())
756
0
        m_xExternalViewController->removeEventListener(static_cast<XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
757
758
0
    m_xExternalViewController = nullptr;
759
0
    m_xExternalDisplayedForm = nullptr;
760
0
    m_xExtViewTriggerController = nullptr;
761
762
0
    InvalidateSlot_Lock( SID_FM_VIEW_AS_GRID, false );
763
0
}
764
765
766
void SAL_CALL FmXFormShell::propertyChange(const PropertyChangeEvent& evt)
767
0
{
768
0
    SolarMutexGuard g;
769
770
0
    if (impl_checkDisposed_Lock())
771
0
        return;
772
773
0
    if (evt.PropertyName == FM_PROP_ROWCOUNT)
774
0
    {
775
        // The update following this forces a re-painting of the corresponding
776
        // slots. But if I am not in the MainThread of the application (because,
777
        // for example, a cursor is counting data sets at the moment and always
778
        // gives me this PropertyChanges), this can clash with normal paints in
779
        // the MainThread of the application. (Such paints happen, for example,
780
        // if one simply places another application over the office and switches
781
        // back again).
782
        // Therefore the use of the SolarMutex, which safeguards that.
783
0
        comphelper::SolarMutex& rSolarSafety = Application::GetSolarMutex();
784
0
        if (rSolarSafety.tryToAcquire())
785
0
        {
786
0
            m_pShell->GetViewShell()->GetViewFrame().GetBindings().Invalidate(SID_FM_RECORD_TOTAL, true);
787
0
            m_pShell->GetViewShell()->GetViewFrame().GetBindings().Update(SID_FM_RECORD_TOTAL);
788
0
            rSolarSafety.release();
789
0
        }
790
0
        else
791
0
        {
792
            // with the following the slot is invalidated asynchronously
793
0
            LockSlotInvalidation_Lock(true);
794
0
            InvalidateSlot_Lock(SID_FM_RECORD_TOTAL, false);
795
0
            LockSlotInvalidation_Lock(false);
796
0
        }
797
0
    }
798
799
    // this may be called from a non-main-thread so invalidate the shell asynchronously
800
0
    LockSlotInvalidation_Lock(true);
801
0
    InvalidateSlot_Lock(0, false); // special meaning : invalidate m_pShell
802
0
    LockSlotInvalidation_Lock(false);
803
0
}
804
805
806
void FmXFormShell::invalidateFeatures( const ::std::vector< sal_Int32 >& _rFeatures )
807
0
{
808
0
    SolarMutexGuard g;
809
810
0
    if (impl_checkDisposed_Lock())
811
0
        return;
812
813
0
    OSL_ENSURE( !_rFeatures.empty(), "FmXFormShell::invalidateFeatures: invalid arguments!" );
814
815
0
    if (!m_pShell->GetViewShell())
816
0
        return;
817
818
    // unfortunately, SFX requires sal_uInt16
819
0
    ::std::vector< sal_uInt16 > aSlotIds( _rFeatures.begin(), _rFeatures.end() );
820
821
    // furthermore, SFX wants a terminating 0
822
0
    aSlotIds.push_back( 0 );
823
824
    // and, last but not least, SFX wants the ids to be sorted
825
0
    ::std::sort( aSlotIds.begin(), aSlotIds.end() - 1 );
826
827
0
    sal_uInt16 *pSlotIds = aSlotIds.data();
828
0
    m_pShell->GetViewShell()->GetViewFrame().GetBindings().Invalidate( pSlotIds );
829
0
}
830
831
832
void SAL_CALL FmXFormShell::formActivated(const lang::EventObject& rEvent)
833
0
{
834
0
    SolarMutexGuard g;
835
836
0
    if (impl_checkDisposed_Lock())
837
0
        return;
838
839
0
    Reference< runtime::XFormController > xController( rEvent.Source, UNO_QUERY_THROW );
840
0
    m_pTextShell->formActivated( xController );
841
0
    setActiveController_Lock(xController);
842
0
}
843
844
845
void SAL_CALL FmXFormShell::formDeactivated(const lang::EventObject& rEvent)
846
0
{
847
0
    SolarMutexGuard g;
848
849
0
    if (impl_checkDisposed_Lock())
850
0
        return;
851
852
0
    Reference< runtime::XFormController > xController( rEvent.Source, UNO_QUERY_THROW );
853
0
    m_pTextShell->formDeactivated( xController );
854
0
}
855
856
857
void FmXFormShell::disposing()
858
8.87k
{
859
8.87k
    SolarMutexGuard g;
860
861
8.87k
    FmXFormShell_BASE::disposing();
862
863
8.87k
    if ( m_pShell && !m_pShell->IsDesignMode() )
864
32
        setActiveController_Lock(nullptr, true);
865
        // do NOT save the content of the old form (the second parameter tells this)
866
        // if we're here, then we expect that PrepareClose has been called, and thus the user
867
        // got a chance to commit or reject any changes. So in case we're here and there
868
        // are still uncommitted changes, the user explicitly wanted this.
869
870
8.87k
    m_pTextShell->dispose();
871
872
8.87k
    m_xAttachedFrame = nullptr;
873
874
8.87k
    CloseExternalFormViewer_Lock();
875
876
8.87k
    while ( !m_aLoadingPages.empty() )
877
0
    {
878
0
        Application::RemoveUserEvent( m_aLoadingPages.front().nEventId );
879
0
        m_aLoadingPages.pop();
880
0
    }
881
882
8.87k
    {
883
8.87k
        if (m_nInvalidationEvent)
884
0
        {
885
0
            Application::RemoveUserEvent(m_nInvalidationEvent);
886
0
            m_nInvalidationEvent = nullptr;
887
0
        }
888
8.87k
        if ( m_nActivationEvent )
889
8.87k
        {
890
8.87k
            Application::RemoveUserEvent( m_nActivationEvent );
891
8.87k
            m_nActivationEvent = nullptr;
892
8.87k
        }
893
8.87k
    }
894
895
8.87k
    {
896
8.87k
        DBG_ASSERT(!m_nInvalidationEvent, "FmXFormShell::~FmXFormShell : still have an invalidation event !");
897
            // should have been deleted while being disposed
898
899
8.87k
        m_aMarkTimer.Stop();
900
8.87k
    }
901
902
8.87k
    DisableNotification();
903
904
8.87k
    RemoveElement_Lock(m_xForms);
905
8.87k
    m_xForms.clear();
906
907
8.87k
    impl_switchActiveControllerListening_Lock(false);
908
8.87k
    m_xActiveController         = nullptr;
909
8.87k
    m_xActiveForm               = nullptr;
910
911
8.87k
    m_pShell                    = nullptr;
912
8.87k
    m_xNavigationController     = nullptr;
913
8.87k
    m_xCurrentForm              = nullptr;
914
8.87k
    m_xLastGridFound            = nullptr;
915
8.87k
    m_xAttachedFrame            = nullptr;
916
8.87k
    m_xExternalViewController   = nullptr;
917
8.87k
    m_xExtViewTriggerController = nullptr;
918
8.87k
    m_xExternalDisplayedForm    = nullptr;
919
920
8.87k
    InterfaceBag().swap(m_aCurrentSelection);
921
922
8.87k
    m_aActiveControllerFeatures.dispose();
923
8.87k
    m_aNavControllerFeatures.dispose();
924
8.87k
}
925
926
927
void FmXFormShell::UpdateSlot_Lock(sal_Int16 _nId)
928
0
{
929
0
    if (impl_checkDisposed_Lock())
930
0
        return;
931
932
0
    if ( m_nLockSlotInvalidation )
933
0
    {
934
0
        OSL_FAIL( "FmXFormShell::UpdateSlot: cannot update if invalidation is currently locked!" );
935
0
        InvalidateSlot_Lock(_nId, false);
936
0
    }
937
0
    else
938
0
    {
939
0
        OSL_ENSURE( _nId, "FmXFormShell::UpdateSlot: can't update the complete shell!" );
940
0
        m_pShell->GetViewShell()->GetViewFrame().GetBindings().Invalidate( _nId, true, true );
941
0
        m_pShell->GetViewShell()->GetViewFrame().GetBindings().Update( _nId );
942
0
    }
943
0
}
944
945
void FmXFormShell::InvalidateSlot_Lock(sal_Int16 nId, bool bWithId)
946
0
{
947
0
    if (impl_checkDisposed_Lock())
948
0
        return;
949
950
0
    if (m_nLockSlotInvalidation)
951
0
    {
952
0
        sal_uInt8 nFlags = ( bWithId ? 0x01 : 0 );
953
0
        m_arrInvalidSlots.emplace_back(nId, nFlags );
954
0
    }
955
0
    else
956
0
        if (nId)
957
0
            m_pShell->GetViewShell()->GetViewFrame().GetBindings().Invalidate(nId, true, bWithId);
958
0
        else
959
0
            m_pShell->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell);
960
0
}
961
962
void FmXFormShell::LockSlotInvalidation_Lock(bool bLock)
963
0
{
964
0
    if (impl_checkDisposed_Lock())
965
0
        return;
966
967
0
    DBG_ASSERT(bLock || m_nLockSlotInvalidation>0, "FmXFormShell::LockSlotInvalidation : invalid call !");
968
969
0
    if (bLock)
970
0
        ++m_nLockSlotInvalidation;
971
0
    else if (!--m_nLockSlotInvalidation)
972
0
    {
973
        // (asynchronously) invalidate everything accumulated during the locked phase
974
0
        if (!m_nInvalidationEvent)
975
0
            m_nInvalidationEvent = Application::PostUserEvent(LINK(this, FmXFormShell, OnInvalidateSlots_Lock));
976
0
    }
977
0
}
978
979
IMPL_LINK_NOARG(FmXFormShell, OnInvalidateSlots_Lock, void*,void)
980
0
{
981
0
    if (impl_checkDisposed_Lock())
982
0
        return;
983
984
0
    m_nInvalidationEvent = nullptr;
985
986
0
    for (const auto& rInvalidSlot : m_arrInvalidSlots)
987
0
    {
988
0
        if (rInvalidSlot.id)
989
0
            m_pShell->GetViewShell()->GetViewFrame().GetBindings().Invalidate(rInvalidSlot.id, true, (rInvalidSlot.flags & 0x01));
990
0
        else
991
0
            m_pShell->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell);
992
0
    }
993
0
    m_arrInvalidSlots.clear();
994
0
}
995
996
void FmXFormShell::ForceUpdateSelection_Lock()
997
0
{
998
0
    if (impl_checkDisposed_Lock())
999
0
        return;
1000
1001
0
    if (IsSelectionUpdatePending_Lock())
1002
0
    {
1003
0
        m_aMarkTimer.Stop();
1004
1005
        // optionally turn off the invalidation of slots which is implicitly done by SetSelection
1006
0
        LockSlotInvalidation_Lock(true);
1007
1008
0
        SetSelection_Lock(m_pShell->GetFormView()->GetMarkedObjectList());
1009
1010
0
        LockSlotInvalidation_Lock(false);
1011
0
    }
1012
0
}
1013
1014
void FmXFormShell::GetConversionMenu_Lock(weld::Menu& rNewMenu)
1015
0
{
1016
0
    for (size_t i = 0; i < SAL_N_ELEMENTS(aConvertSlots); ++i)
1017
0
    {
1018
        // the corresponding image at it
1019
0
        rNewMenu.append(OUString(aConvertSlots[i]), SvxResId(RID_SVXSW_CONVERTMENU[i]), aImgIds[i]);
1020
0
    }
1021
0
}
1022
1023
OUString FmXFormShell::SlotToIdent(sal_uInt16 nSlot)
1024
0
{
1025
0
    static_assert(SAL_N_ELEMENTS(SelObjectSlotMap) >= SAL_N_ELEMENTS(aConvertSlots));
1026
1027
0
    for (size_t i = 0; i < SAL_N_ELEMENTS(aConvertSlots); ++i)
1028
0
    {
1029
0
        if (nSlot == SelObjectSlotMap[i])
1030
0
            return OUString(aConvertSlots[i]);
1031
0
    }
1032
1033
0
    return {};
1034
0
}
1035
1036
bool FmXFormShell::isControlConversionSlot(std::u16string_view rIdent)
1037
0
{
1038
0
    for (const auto& rConvertSlot : aConvertSlots)
1039
0
        if (rIdent == rConvertSlot)
1040
0
            return true;
1041
0
    return false;
1042
0
}
1043
1044
void FmXFormShell::executeControlConversionSlot_Lock(std::u16string_view rIdent)
1045
0
{
1046
0
    OSL_PRECOND( canConvertCurrentSelectionToControl_Lock(rIdent), "FmXFormShell::executeControlConversionSlot: illegal call!" );
1047
0
    InterfaceBag::const_iterator aSelectedElement = m_aCurrentSelection.begin();
1048
0
    if ( aSelectedElement == m_aCurrentSelection.end() )
1049
0
        return;
1050
1051
0
    executeControlConversionSlot_Lock(Reference<XFormComponent>(*aSelectedElement, UNO_QUERY), rIdent);
1052
0
}
1053
1054
bool FmXFormShell::executeControlConversionSlot_Lock(const Reference<XFormComponent>& _rxObject, std::u16string_view rIdent)
1055
0
{
1056
0
    if (impl_checkDisposed_Lock())
1057
0
        return false;
1058
1059
0
    OSL_ENSURE( _rxObject.is(), "FmXFormShell::executeControlConversionSlot: invalid object!" );
1060
0
    if ( !_rxObject.is() )
1061
0
        return false;
1062
1063
0
    SdrPage* pPage = m_pShell->GetCurPage();
1064
0
    FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( pPage );
1065
0
    OSL_ENSURE( pFormPage, "FmXFormShell::executeControlConversionSlot: no current (form) page!" );
1066
0
    if ( !pFormPage )
1067
0
        return false;
1068
1069
0
    OSL_ENSURE( isSolelySelected_Lock(_rxObject),
1070
0
        "FmXFormShell::executeControlConversionSlot: hmm ... shouldn't this parameter be redundant?" );
1071
1072
0
    for (size_t lookupSlot = 0; lookupSlot < SAL_N_ELEMENTS(aConvertSlots); ++lookupSlot)
1073
0
    {
1074
0
        if (rIdent == aConvertSlots[lookupSlot])
1075
0
        {
1076
0
            Reference< XInterface > xNormalizedObject( _rxObject, UNO_QUERY );
1077
1078
0
            FmFormObj* pFormObject = nullptr;
1079
0
            SdrObjListIter aPageIter( pFormPage );
1080
0
            while ( aPageIter.IsMore() )
1081
0
            {
1082
0
                SdrObject* pCurrent = aPageIter.Next();
1083
0
                pFormObject = FmFormObj::GetFormObject( pCurrent );
1084
0
                if ( !pFormObject )
1085
0
                    continue;
1086
1087
0
                Reference< XInterface > xCurrentNormalized( pFormObject->GetUnoControlModel(), UNO_QUERY );
1088
0
                if ( xCurrentNormalized.get() == xNormalizedObject.get() )
1089
0
                    break;
1090
1091
0
                pFormObject = nullptr;
1092
0
            }
1093
1094
0
            if ( !pFormObject )
1095
0
                return false;
1096
1097
0
            OUString sNewName( getServiceNameByControlType( nObjectTypes[ lookupSlot ] ) );
1098
0
            const Reference<XComponentContext>& xContext = comphelper::getProcessComponentContext();
1099
0
            Reference< XControlModel> xNewModel( xContext->getServiceManager()->createInstanceWithContext(sNewName, xContext), UNO_QUERY );
1100
0
            if (!xNewModel.is())
1101
0
                return false;
1102
1103
0
            Reference< XControlModel> xOldModel( pFormObject->GetUnoControlModel() );
1104
1105
            // transfer properties
1106
0
            Reference< XPropertySet> xOldSet(xOldModel, UNO_QUERY);
1107
0
            Reference< XPropertySet> xNewSet(xNewModel, UNO_QUERY);
1108
1109
1110
0
            lang::Locale aNewLanguage = Application::GetSettings().GetUILanguageTag().getLocale();
1111
0
            TransferFormComponentProperties(xOldSet, xNewSet, aNewLanguage);
1112
1113
0
            Sequence< css::script::ScriptEventDescriptor> aOldScripts;
1114
0
            Reference< XChild> xChild(xOldModel, UNO_QUERY);
1115
0
            if (xChild.is())
1116
0
            {
1117
0
                Reference< XIndexAccess> xParent(xChild->getParent(), UNO_QUERY);
1118
1119
                // remember old script events
1120
0
                Reference< css::script::XEventAttacherManager> xEvManager(xChild->getParent(), UNO_QUERY);
1121
0
                if (xParent.is() && xEvManager.is())
1122
0
                {
1123
0
                    sal_Int32 nIndex = getElementPos(xParent, xOldModel);
1124
0
                    if (nIndex>=0 && nIndex<xParent->getCount())
1125
0
                        aOldScripts = xEvManager->getScriptEvents(nIndex);
1126
0
                }
1127
1128
                // replace the model within the parent container
1129
0
                Reference< XIndexContainer> xIndexParent(xChild->getParent(), UNO_QUERY);
1130
0
                if (xIndexParent.is())
1131
0
                {
1132
                    // the form container works with FormComponents
1133
0
                    Reference< XFormComponent> xComponent(xNewModel, UNO_QUERY);
1134
0
                    DBG_ASSERT(xComponent.is(), "FmXFormShell::executeControlConversionSlot: the new model is no form component !");
1135
0
                    Any aNewModel(xComponent);
1136
0
                    try
1137
0
                    {
1138
1139
0
                        sal_Int32 nIndex = getElementPos(xParent, xOldModel);
1140
0
                        if (nIndex>=0 && nIndex<xParent->getCount())
1141
0
                            xIndexParent->replaceByIndex(nIndex, aNewModel);
1142
0
                        else
1143
0
                        {
1144
0
                            OSL_FAIL("FmXFormShell::executeControlConversionSlot: could not replace the model !");
1145
0
                            Reference< css::lang::XComponent> xNewComponent(xNewModel, UNO_QUERY);
1146
0
                            if (xNewComponent.is())
1147
0
                                xNewComponent->dispose();
1148
0
                            return false;
1149
0
                        }
1150
0
                    }
1151
0
                    catch(Exception&)
1152
0
                    {
1153
0
                        OSL_FAIL("FmXFormShell::executeControlConversionSlot: could not replace the model !");
1154
0
                        Reference< css::lang::XComponent> xNewComponent(xNewModel, UNO_QUERY);
1155
0
                        if (xNewComponent.is())
1156
0
                            xNewComponent->dispose();
1157
0
                        return false;
1158
0
                    }
1159
1160
0
                }
1161
0
            }
1162
1163
            // special handling for the LabelControl-property : can only be set when the model is placed
1164
            // within the forms hierarchy
1165
0
            if (::comphelper::hasProperty(FM_PROP_CONTROLLABEL, xOldSet) && ::comphelper::hasProperty(FM_PROP_CONTROLLABEL, xNewSet))
1166
0
            {
1167
0
                try
1168
0
                {
1169
0
                    xNewSet->setPropertyValue(FM_PROP_CONTROLLABEL, xOldSet->getPropertyValue(FM_PROP_CONTROLLABEL));
1170
0
                }
1171
0
                catch(Exception&)
1172
0
                {
1173
0
                }
1174
1175
0
            }
1176
1177
            // set new model
1178
0
            pFormObject->SetChanged();
1179
0
            pFormObject->SetUnoControlModel(xNewModel);
1180
1181
            // transfer script events
1182
            // (do this _after_ SetUnoControlModel as we need the new (implicitly created) control)
1183
0
            if (aOldScripts.hasElements())
1184
0
            {
1185
                // find the control for the model
1186
0
                Reference<XControlContainer> xControlContainer(getControlContainerForView_Lock());
1187
1188
0
                const Sequence< Reference< XControl> > aControls( xControlContainer->getControls() );
1189
1190
0
                Reference< XControl> xControl;
1191
0
                auto pControl = std::find_if(aControls.begin(), aControls.end(),
1192
0
                    [&xNewModel](const Reference< XControl>& rControl) { return rControl->getModel() == xNewModel; });
1193
0
                if (pControl != aControls.end())
1194
0
                    xControl = *pControl;
1195
0
                TransferEventScripts(xNewModel, xControl, aOldScripts);
1196
0
            }
1197
1198
            // transfer value bindings, if possible
1199
0
            {
1200
0
                Reference< XBindableValue > xOldBindable( xOldModel, UNO_QUERY );
1201
0
                Reference< XBindableValue > xNewBindable( xNewModel, UNO_QUERY );
1202
0
                if ( xOldBindable.is() )
1203
0
                {
1204
0
                    try
1205
0
                    {
1206
0
                        if ( xNewBindable.is() )
1207
0
                            xNewBindable->setValueBinding( xOldBindable->getValueBinding() );
1208
0
                        xOldBindable->setValueBinding( nullptr );
1209
0
                    }
1210
0
                    catch(const Exception&)
1211
0
                    {
1212
0
                        DBG_UNHANDLED_EXCEPTION("svx");
1213
0
                    }
1214
0
                }
1215
0
            }
1216
            // same for list entry sources
1217
0
            {
1218
0
                Reference< XListEntrySink > xOldSink( xOldModel, UNO_QUERY );
1219
0
                Reference< XListEntrySink > xNewSink( xNewModel, UNO_QUERY );
1220
0
                if ( xOldSink.is() )
1221
0
                {
1222
0
                    try
1223
0
                    {
1224
0
                        if ( xNewSink.is() )
1225
0
                            xNewSink->setListEntrySource( xOldSink->getListEntrySource() );
1226
0
                        xOldSink->setListEntrySource( nullptr );
1227
0
                    }
1228
0
                    catch(const Exception&)
1229
0
                    {
1230
0
                        DBG_UNHANDLED_EXCEPTION("svx");
1231
0
                    }
1232
0
                }
1233
0
            }
1234
1235
            // create an undo action
1236
0
            FmFormModel* pModel = m_pShell->GetFormModel();
1237
0
            DBG_ASSERT(pModel != nullptr, "FmXFormShell::executeControlConversionSlot: my shell has no model !");
1238
0
            if (pModel && pModel->IsUndoEnabled() )
1239
0
            {
1240
0
                pModel->AddUndo(std::make_unique<FmUndoModelReplaceAction>(*pModel, pFormObject, xOldModel));
1241
0
            }
1242
0
            else
1243
0
            {
1244
0
                FmUndoModelReplaceAction::DisposeElement( xOldModel );
1245
0
            }
1246
1247
0
            return true;
1248
0
        }
1249
0
    }
1250
0
    return false;
1251
0
}
1252
1253
bool FmXFormShell::canConvertCurrentSelectionToControl_Lock(std::u16string_view rIdent)
1254
0
{
1255
0
    if ( m_aCurrentSelection.empty() )
1256
0
        return false;
1257
1258
0
    InterfaceBag::const_iterator aCheck = m_aCurrentSelection.begin();
1259
0
    Reference< lang::XServiceInfo > xElementInfo( *aCheck, UNO_QUERY );
1260
0
    if ( !xElementInfo.is() )
1261
        // no service info -> cannot determine this
1262
0
        return false;
1263
1264
0
    if (  ++aCheck != m_aCurrentSelection.end() )
1265
        // more than one element
1266
0
        return false;
1267
1268
0
    if ( Reference< XForm >::query( xElementInfo ).is() )
1269
        // it's a form
1270
0
        return false;
1271
1272
0
    SdrObjKind nObjectType = getControlTypeByObject( xElementInfo );
1273
1274
0
    if (  ( SdrObjKind::FormHidden == nObjectType )
1275
0
       || ( SdrObjKind::FormControl == nObjectType )
1276
0
       || ( SdrObjKind::FormGrid == nObjectType )
1277
0
       )
1278
0
        return false;   // those types cannot be converted
1279
1280
0
    DBG_ASSERT(SAL_N_ELEMENTS(aConvertSlots) == SAL_N_ELEMENTS(nObjectTypes),
1281
0
        "FmXFormShell::canConvertCurrentSelectionToControl: aConvertSlots & nObjectTypes must have the same size !");
1282
1283
0
    for (size_t i = 0; i < SAL_N_ELEMENTS(aConvertSlots); ++i)
1284
0
        if (rIdent == aConvertSlots[i])
1285
0
            return nObjectTypes[i] != nObjectType;
1286
1287
0
    return true;    // all other slots: assume "yes"
1288
0
}
1289
1290
void FmXFormShell::checkControlConversionSlotsForCurrentSelection_Lock(weld::Menu& rMenu)
1291
0
{
1292
0
    for (int i = 0, nCount = rMenu.n_children(); i < nCount; ++i)
1293
0
    {
1294
        // the context is already of a type that corresponds to the entry -> disable
1295
0
        OUString sIdent(aConvertSlots[i]);
1296
0
        rMenu.set_sensitive(sIdent, canConvertCurrentSelectionToControl_Lock(sIdent));
1297
0
    }
1298
0
}
1299
1300
void FmXFormShell::LoopGrids_Lock(LoopGridsSync nSync, LoopGridsFlags nFlags)
1301
0
{
1302
0
    if (impl_checkDisposed_Lock())
1303
0
        return;
1304
1305
0
    Reference< XIndexContainer> xControlModels(m_xActiveForm, UNO_QUERY);
1306
0
    if (!xControlModels.is())
1307
0
        return;
1308
1309
0
    for (sal_Int32 i=0; i<xControlModels->getCount(); ++i)
1310
0
    {
1311
0
        Reference< XPropertySet> xModelSet;
1312
0
        xControlModels->getByIndex(i) >>= xModelSet;
1313
0
        if (!xModelSet.is())
1314
0
            continue;
1315
1316
0
        if (!::comphelper::hasProperty(FM_PROP_CLASSID, xModelSet))
1317
0
            continue;
1318
0
        sal_Int16 nClassId = ::comphelper::getINT16(xModelSet->getPropertyValue(FM_PROP_CLASSID));
1319
0
        if (FormComponentType::GRIDCONTROL != nClassId)
1320
0
            continue;
1321
1322
0
        if (!::comphelper::hasProperty(FM_PROP_CURSORCOLOR, xModelSet) || !::comphelper::hasProperty(FM_PROP_ALWAYSSHOWCURSOR, xModelSet) || !::comphelper::hasProperty(FM_PROP_DISPLAYSYNCHRON, xModelSet))
1323
0
            continue;
1324
1325
0
        switch (nSync)
1326
0
        {
1327
0
            case LoopGridsSync::DISABLE_SYNC:
1328
0
            {
1329
0
                xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(false));
1330
0
            }
1331
0
            break;
1332
0
            case LoopGridsSync::FORCE_SYNC:
1333
0
            {
1334
0
                Any aOldVal( xModelSet->getPropertyValue(FM_PROP_DISPLAYSYNCHRON) );
1335
0
                xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(true));
1336
0
                xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, aOldVal);
1337
0
            }
1338
0
            break;
1339
0
            case LoopGridsSync::ENABLE_SYNC:
1340
0
            {
1341
0
                xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(true));
1342
0
            }
1343
0
            break;
1344
0
        }
1345
1346
0
        if (nFlags & LoopGridsFlags::DISABLE_ROCTRLR)
1347
0
        {
1348
0
            xModelSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, Any(false));
1349
0
            Reference< XPropertyState> xModelPropState(xModelSet, UNO_QUERY);
1350
0
            if (xModelPropState.is())
1351
0
                xModelPropState->setPropertyToDefault(FM_PROP_CURSORCOLOR);
1352
0
            else
1353
0
                xModelSet->setPropertyValue(FM_PROP_CURSORCOLOR, Any());        // this should be the default
1354
0
        }
1355
0
    }
1356
0
}
1357
1358
1359
Reference< XControlContainer > FmXFormShell::getControlContainerForView_Lock() const
1360
0
{
1361
0
    if (impl_checkDisposed_Lock())
1362
0
        return nullptr;
1363
1364
0
    SdrPageView* pPageView = nullptr;
1365
0
    if ( m_pShell && m_pShell->GetFormView() )
1366
0
        pPageView = m_pShell->GetFormView()->GetSdrPageView();
1367
1368
0
    Reference< XControlContainer> xControlContainer;
1369
0
    if ( pPageView )
1370
0
        xControlContainer = pPageView->GetPageWindow(0)->GetControlContainer();
1371
1372
0
    return xControlContainer;
1373
0
}
1374
1375
1376
void FmXFormShell::ExecuteTabOrderDialog_Lock(const Reference<XTabControllerModel>& _rxForForm)
1377
0
{
1378
0
    if (impl_checkDisposed_Lock())
1379
0
        return;
1380
1381
0
    OSL_PRECOND( _rxForForm.is(), "FmXFormShell::ExecuteTabOrderDialog: invalid tabbing model!" );
1382
0
    if ( !_rxForForm.is() )
1383
0
        return;
1384
1385
0
    try
1386
0
    {
1387
0
        Reference< XWindow > xParentWindow;
1388
0
        if (m_pShell->GetViewShell())
1389
0
            xParentWindow = VCLUnoHelper::GetInterface ( &m_pShell->GetViewShell()->GetViewFrame().GetWindow() );
1390
1391
0
        Reference< dialogs::XExecutableDialog > xDialog = form::TabOrderDialog::createWithModel(
1392
0
                comphelper::getProcessComponentContext(),
1393
0
                _rxForForm, getControlContainerForView_Lock(), xParentWindow
1394
0
            );
1395
1396
0
        (void)xDialog->execute();
1397
0
    }
1398
0
    catch( const Exception& )
1399
0
    {
1400
0
        TOOLS_WARN_EXCEPTION( "svx", "FmXFormShell::ExecuteTabOrderDialog" );
1401
0
    }
1402
0
}
1403
1404
1405
void FmXFormShell::ExecuteSearch_Lock()
1406
0
{
1407
0
    if (impl_checkDisposed_Lock())
1408
0
        return;
1409
1410
    // a collection of all (logical) forms
1411
0
    FmFormArray().swap(m_aSearchForms);
1412
0
    ::std::vector< OUString > aContextNames;
1413
0
    impl_collectFormSearchContexts_nothrow_Lock(
1414
0
        m_pShell->GetCurPage()->GetForms(), u"",
1415
0
        m_aSearchForms, aContextNames);
1416
1417
0
    if ( m_aSearchForms.size() != aContextNames.size() )
1418
0
    {
1419
0
        SAL_WARN ( "svx.form", "FmXFormShell::ExecuteSearch: nonsense!" );
1420
0
        return;
1421
0
    }
1422
1423
    // filter out the forms which do not contain valid controls at all
1424
0
    {
1425
0
        FmFormArray aValidForms;
1426
0
        ::std::vector< OUString > aValidContexts;
1427
0
        FmFormArray::const_iterator form = m_aSearchForms.begin();
1428
0
        ::std::vector< OUString >::const_iterator contextName = aContextNames.begin();
1429
0
        for ( ; form != m_aSearchForms.end(); ++form, ++contextName )
1430
0
        {
1431
0
            FmSearchContext aTestContext;
1432
0
            aTestContext.nContext = static_cast< sal_Int16 >( form - m_aSearchForms.begin() );
1433
0
            sal_uInt32 nValidControls = OnSearchContextRequest_Lock(aTestContext);
1434
0
            if ( nValidControls > 0 )
1435
0
            {
1436
0
                aValidForms.push_back( *form );
1437
0
                aValidContexts.push_back( *contextName );
1438
0
            }
1439
0
        }
1440
1441
0
        m_aSearchForms.swap( aValidForms );
1442
0
        aContextNames.swap( aValidContexts );
1443
0
    }
1444
1445
0
    if (m_aSearchForms.empty() )
1446
0
    {
1447
        // there are no controls that meet all the conditions for a search
1448
0
        std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
1449
0
                                                                 VclMessageType::Warning, VclButtonsType::Ok,
1450
0
                                                                 SvxResId(RID_STR_NODATACONTROLS)));
1451
0
        xBox->run();
1452
0
        return;
1453
0
    }
1454
1455
    // now I need another 'initial context'
1456
0
    sal_Int16 nInitialContext = 0;
1457
0
    Reference<XForm> xActiveForm(getActiveForm_Lock());
1458
0
    for ( size_t i=0; i<m_aSearchForms.size(); ++i )
1459
0
    {
1460
0
        if (m_aSearchForms.at(i) == xActiveForm)
1461
0
        {
1462
0
            nInitialContext = static_cast<sal_Int16>(i);
1463
0
            break;
1464
0
        }
1465
0
    }
1466
1467
    // If the dialog should initially offer the text of the active control,
1468
    // this must have an XTextComponent interface. An addition, this makes
1469
    // sense only if the current field is also bound to a table (or whatever) field.
1470
0
    OUString strActiveField;
1471
0
    OUString strInitialText;
1472
    // ... this I get from my FormController
1473
0
    DBG_ASSERT(m_xActiveController.is(), "FmXFormShell::ExecuteSearch : no active controller !");
1474
0
    Reference< XControl> xActiveControl( m_xActiveController->getCurrentControl());
1475
0
    if (xActiveControl.is())
1476
0
    {
1477
        // the control can tell me its model ...
1478
0
        Reference< XControlModel> xActiveModel( xActiveControl->getModel());
1479
0
        DBG_ASSERT(xActiveModel.is(), "FmXFormShell::ExecuteSearch : active control has no model !");
1480
1481
        // I ask the model for the ControlSource property ...
1482
0
        Reference< XPropertySet> xProperties(xActiveControl->getModel(), UNO_QUERY);
1483
0
        if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xProperties) && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xProperties))
1484
0
        {
1485
0
            Reference< XPropertySet> xField;
1486
0
            xProperties->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
1487
0
            if (xField.is())    // (only when the thing is really bound)
1488
0
            {
1489
                // and the control itself for a TextComponent interface (so that I can pick up the text there)
1490
0
                Reference< XTextComponent> xText(xActiveControl, UNO_QUERY);
1491
0
                if (xText.is())
1492
0
                {
1493
0
                    strActiveField = getLabelName(xProperties);
1494
0
                    strInitialText = xText->getText();
1495
0
                }
1496
0
            }
1497
0
        }
1498
0
        else
1499
0
        {
1500
            // the control itself has no ControlSource, but maybe it is a GridControl
1501
0
            Reference< XGrid> xGrid(xActiveControl, UNO_QUERY);
1502
0
            if (xGrid.is())
1503
0
            {
1504
                // for strActiveField I need the ControlSource of the column,
1505
                // for that the columns container, for that the GridPeer
1506
0
                Reference< XGridPeer> xGridPeer(xActiveControl->getPeer(), UNO_QUERY);
1507
0
                Reference< XIndexAccess> xColumns;
1508
0
                if (xGridPeer.is())
1509
0
                    xColumns = xGridPeer->getColumns();
1510
1511
0
                sal_Int16 nViewCol = xGrid->getCurrentColumnPosition();
1512
0
                sal_Int32 nModelCol = GridView2ModelPos(xColumns, nViewCol);
1513
0
                Reference< XPropertySet> xCurrentCol;
1514
0
                if(xColumns.is())
1515
0
                    xColumns->getByIndex(nModelCol) >>= xCurrentCol;
1516
0
                if (xCurrentCol.is())
1517
0
                    strActiveField = ::comphelper::getString(xCurrentCol->getPropertyValue(FM_PROP_LABEL));
1518
1519
                // the text of the current column
1520
0
                Reference< XIndexAccess> xColControls(xGridPeer, UNO_QUERY);
1521
0
                Reference< XInterface> xCurControl;
1522
0
                xColControls->getByIndex(nViewCol) >>= xCurControl;
1523
0
                OUString sInitialText;
1524
0
                if (IsSearchableControl(xCurControl, &sInitialText))
1525
0
                    strInitialText = sInitialText;
1526
0
            }
1527
0
        }
1528
0
    }
1529
1530
    // taking care of possible GridControls that I know
1531
0
    LoopGrids_Lock(LoopGridsSync::DISABLE_SYNC);
1532
1533
    // Now I am ready for the dialogue.
1534
    // When the potential deadlocks caused by the use of the solar mutex in
1535
    // MTs VCLX... classes are eventually cleared, an SM_USETHREAD should be
1536
    // placed here, because the search in a separate thread is nevertheless
1537
    // somewhat more fluid. Should be, however, somehow made dependent of the
1538
    // underlying cursor. DAO for example is not thread-safe.
1539
0
    SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1540
0
    ScopedVclPtr<AbstractFmSearchDialog> pDialog(
1541
0
            pFact->CreateFmSearchDialog(
1542
0
                m_pShell->GetViewShell()->GetViewFrame().GetFrameWeld(),
1543
0
                strInitialText, aContextNames, nInitialContext,
1544
0
                LINK(this, FmXFormShell, OnSearchContextRequest_Lock) ));
1545
0
    pDialog->SetActiveField( strActiveField );
1546
0
    pDialog->SetFoundHandler(LINK(this, FmXFormShell, OnFoundData_Lock));
1547
0
    pDialog->SetCanceledNotFoundHdl(LINK(this, FmXFormShell, OnCanceledNotFound_Lock));
1548
0
    pDialog->Execute();
1549
0
    pDialog.disposeAndClear();
1550
1551
    // restore GridControls again
1552
0
    LoopGrids_Lock(LoopGridsSync::ENABLE_SYNC, LoopGridsFlags::DISABLE_ROCTRLR);
1553
1554
0
    m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView());
1555
        // because I marked controls in OnFoundData (if I was there)
1556
0
}
1557
1558
1559
bool FmXFormShell::GetY2KState_Lock(sal_uInt16& n)
1560
0
{
1561
0
    if (impl_checkDisposed_Lock())
1562
0
        return false;
1563
1564
0
    if (m_pShell->IsDesignMode())
1565
        // in the design mode (without active controls) the main document is to take care of it
1566
0
        return false;
1567
1568
0
    Reference<XForm> xForm(getActiveForm_Lock());
1569
0
    if (!xForm.is())
1570
        // no current form (in particular no current control) -> the main document is to take care
1571
0
        return false;
1572
1573
0
    Reference< XRowSet> xDB(xForm, UNO_QUERY);
1574
0
    DBG_ASSERT(xDB.is(), "FmXFormShell::GetY2KState : current form has no dbform-interface !");
1575
1576
0
    Reference< XNumberFormatsSupplier> xSupplier( getNumberFormats(getConnection(xDB)));
1577
0
    if (xSupplier.is())
1578
0
    {
1579
0
        Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings());
1580
0
        if (xSet.is())
1581
0
        {
1582
0
            try
1583
0
            {
1584
0
                Any aVal( xSet->getPropertyValue(u"TwoDigitDateStart"_ustr) );
1585
0
                aVal >>= n;
1586
0
                return true;
1587
0
            }
1588
0
            catch(Exception&)
1589
0
            {
1590
0
            }
1591
1592
0
        }
1593
0
    }
1594
0
    return false;
1595
0
}
1596
1597
1598
void FmXFormShell::SetY2KState_Lock(sal_uInt16 n)
1599
0
{
1600
0
    if (impl_checkDisposed_Lock())
1601
0
        return;
1602
1603
0
    Reference<XForm> xActiveForm(getActiveForm_Lock());
1604
0
    Reference< XRowSet > xActiveRowSet( xActiveForm, UNO_QUERY );
1605
0
    if ( xActiveRowSet.is() )
1606
0
    {
1607
0
        Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( getConnection( xActiveRowSet ) ) );
1608
0
        if (xSupplier.is())
1609
0
        {
1610
0
            Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings());
1611
0
            if (xSet.is())
1612
0
            {
1613
0
                try
1614
0
                {
1615
0
                    xSet->setPropertyValue(u"TwoDigitDateStart"_ustr, Any(sal_uInt16(n)));
1616
0
                }
1617
0
                catch(Exception&)
1618
0
                {
1619
0
                    TOOLS_WARN_EXCEPTION("svx.form", "");
1620
0
                }
1621
1622
0
            }
1623
0
            return;
1624
0
        }
1625
0
    }
1626
1627
    // no active form found -> iterate through all current forms
1628
0
    Reference< XIndexAccess> xCurrentForms( m_xForms);
1629
0
    if (!xCurrentForms.is())
1630
0
    {   // in the alive mode, my forms are not set, but the ones on the page are
1631
0
        if (m_pShell->GetCurPage())
1632
0
            xCurrentForms = m_pShell->GetCurPage()->GetForms( false );
1633
0
    }
1634
0
    if (!xCurrentForms.is())
1635
0
        return;
1636
1637
0
    ::comphelper::IndexAccessIterator aIter(xCurrentForms);
1638
0
    Reference< XInterface> xCurrentElement( aIter.Next());
1639
0
    while (xCurrentElement.is())
1640
0
    {
1641
        // is the current element a DatabaseForm?
1642
0
        Reference< XRowSet> xElementAsRowSet( xCurrentElement, UNO_QUERY );
1643
0
        if ( xElementAsRowSet.is() )
1644
0
        {
1645
0
            Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( getConnection( xElementAsRowSet ) ) );
1646
0
            if (!xSupplier.is())
1647
0
                continue;
1648
1649
0
            Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings());
1650
0
            if (xSet.is())
1651
0
            {
1652
0
                try
1653
0
                {
1654
0
                    xSet->setPropertyValue(u"TwoDigitDateStart"_ustr, Any(sal_uInt16(n)));
1655
0
                }
1656
0
                catch(Exception&)
1657
0
                {
1658
0
                    TOOLS_WARN_EXCEPTION("svx.form", "");
1659
0
                }
1660
1661
0
            }
1662
0
        }
1663
0
        xCurrentElement = aIter.Next();
1664
0
    }
1665
0
}
1666
1667
1668
void FmXFormShell::CloseExternalFormViewer_Lock()
1669
8.87k
{
1670
8.87k
    if (impl_checkDisposed_Lock())
1671
0
        return;
1672
1673
8.87k
    if (!m_xExternalViewController.is())
1674
8.87k
        return;
1675
1676
0
    Reference< css::frame::XFrame> xExternalViewFrame( m_xExternalViewController->getFrame());
1677
0
    Reference< css::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY);
1678
0
    if (!xCommLink.is())
1679
0
        return;
1680
1681
0
    xExternalViewFrame->setComponent(nullptr,nullptr);
1682
0
    ::comphelper::disposeComponent(xExternalViewFrame);
1683
0
    m_xExternalViewController   = nullptr;
1684
0
    m_xExtViewTriggerController = nullptr;
1685
0
    m_xExternalDisplayedForm    = nullptr;
1686
0
}
1687
1688
1689
Reference<XResultSet> FmXFormShell::getInternalForm_Lock(const Reference<XResultSet>& _xForm) const
1690
0
{
1691
0
    if (impl_checkDisposed_Lock())
1692
0
        return nullptr;
1693
1694
0
    Reference< runtime::XFormController> xExternalCtrlr(m_xExternalViewController, UNO_QUERY);
1695
0
    if (xExternalCtrlr.is() && (_xForm == xExternalCtrlr->getModel()))
1696
0
    {
1697
0
        DBG_ASSERT(m_xExternalDisplayedForm.is(), "FmXFormShell::getInternalForm : invalid external form !");
1698
0
        return m_xExternalDisplayedForm;
1699
0
    }
1700
0
    return _xForm;
1701
0
}
1702
1703
1704
Reference<XForm> FmXFormShell::getInternalForm_Lock(const Reference<XForm>& _xForm) const
1705
0
{
1706
0
    if (impl_checkDisposed_Lock())
1707
0
        return nullptr;
1708
1709
0
    Reference< runtime::XFormController > xExternalCtrlr(m_xExternalViewController, UNO_QUERY);
1710
0
    if (xExternalCtrlr.is() && (_xForm == xExternalCtrlr->getModel()))
1711
0
    {
1712
0
        DBG_ASSERT(m_xExternalDisplayedForm.is(), "FmXFormShell::getInternalForm : invalid external form !");
1713
0
        return Reference< XForm>(m_xExternalDisplayedForm, UNO_QUERY);
1714
0
    }
1715
0
    return _xForm;
1716
0
}
1717
1718
1719
namespace
1720
{
1721
    bool lcl_isNavigationRelevant( sal_Int32 _nWhich )
1722
0
    {
1723
0
        return  ( _nWhich == SID_FM_RECORD_FIRST )
1724
0
            ||  ( _nWhich == SID_FM_RECORD_PREV )
1725
0
            ||  ( _nWhich == SID_FM_RECORD_NEXT )
1726
0
            ||  ( _nWhich == SID_FM_RECORD_LAST )
1727
0
            ||  ( _nWhich == SID_FM_RECORD_NEW );
1728
0
    }
1729
}
1730
1731
1732
bool FmXFormShell::IsFormSlotEnabled( sal_Int32 _nSlot, FeatureState* _pCompleteState ) const
1733
0
{
1734
0
    const svx::ControllerFeatures& rController =
1735
0
            lcl_isNavigationRelevant( _nSlot )
1736
0
        ?   getNavControllerFeatures_Lock()
1737
0
        :   getActiveControllerFeatures_Lock();
1738
1739
0
    if ( !_pCompleteState )
1740
0
        return rController->isEnabled( _nSlot );
1741
1742
0
    rController->getState( _nSlot, *_pCompleteState );
1743
0
    return _pCompleteState->Enabled;
1744
0
}
1745
1746
1747
void FmXFormShell::ExecuteFormSlot_Lock( sal_Int32 _nSlot )
1748
0
{
1749
0
    const svx::ControllerFeatures& rController =
1750
0
            lcl_isNavigationRelevant( _nSlot )
1751
0
        ?   getNavControllerFeatures_Lock()
1752
0
        :   getActiveControllerFeatures_Lock();
1753
1754
0
    rController->execute( _nSlot );
1755
1756
0
    if ( _nSlot != SID_FM_RECORD_UNDO )
1757
0
        return;
1758
1759
    // if we're doing an UNDO, *and* if the affected form is the form which we also display
1760
    // as external view, then we need to reset the controls of the external form, too
1761
0
    if (getInternalForm_Lock(getActiveForm_Lock()) != m_xExternalDisplayedForm)
1762
0
        return;
1763
1764
0
    Reference< XIndexAccess > xContainer( m_xExternalDisplayedForm, UNO_QUERY );
1765
0
    if ( !xContainer.is() )
1766
0
        return;
1767
1768
0
    Reference< XReset > xReset;
1769
0
    for ( sal_Int32 i = 0; i < xContainer->getCount(); ++i )
1770
0
    {
1771
0
        if ( ( xContainer->getByIndex( i ) >>= xReset ) && xReset.is() )
1772
0
        {
1773
            // no resets on sub forms
1774
0
            Reference< XForm > xAsForm( xReset, UNO_QUERY );
1775
0
            if ( !xAsForm.is() )
1776
0
                xReset->reset();
1777
0
        }
1778
0
    }
1779
0
}
1780
1781
void FmXFormShell::impl_switchActiveControllerListening_Lock(const bool _bListen)
1782
8.87k
{
1783
8.87k
    if ( !m_xActiveController.is() )
1784
8.87k
        return;
1785
1786
0
    if ( _bListen )
1787
0
        m_xActiveController->addEventListener( static_cast<XFormControllerListener*>(this) );
1788
0
    else
1789
0
        m_xActiveController->removeEventListener( static_cast<XFormControllerListener*>(this) );
1790
0
}
1791
1792
void FmXFormShell::setActiveController_Lock(const Reference<runtime::XFormController>& xController, bool _bNoSaveOldContent)
1793
32
{
1794
32
    if (impl_checkDisposed_Lock())
1795
0
        return;
1796
1797
32
    if (m_bChangingDesignMode)
1798
0
        return;
1799
32
    DBG_ASSERT(!m_pShell->IsDesignMode(), "only to be used in alive mode");
1800
1801
    // if the routine has been called a second time,
1802
    // the focus should no longer be transferred
1803
32
    if (m_bInActivate)
1804
0
    {
1805
0
        m_bSetFocus = xController != m_xActiveController;
1806
0
        return;
1807
0
    }
1808
1809
32
    if (xController == m_xActiveController)
1810
32
        return;
1811
1812
    // switch all nav dispatchers belonging to the form of the current nav controller to 'non active'
1813
0
    Reference< XResultSet> xNavigationForm;
1814
0
    if (m_xNavigationController.is())
1815
0
        xNavigationForm.set(m_xNavigationController->getModel(), UNO_QUERY);
1816
1817
0
    m_bInActivate = true;
1818
1819
    // check if the 2 controllers serve different forms
1820
0
    Reference< XResultSet> xOldForm;
1821
0
    if (m_xActiveController.is())
1822
0
        xOldForm.set(m_xActiveController->getModel(), UNO_QUERY);
1823
0
    Reference< XResultSet> xNewForm;
1824
0
    if (xController.is())
1825
0
        xNewForm = Reference< XResultSet>(xController->getModel(), UNO_QUERY);
1826
0
    xOldForm = getInternalForm_Lock(xOldForm);
1827
0
    xNewForm = getInternalForm_Lock(xNewForm);
1828
1829
0
    bool bDifferentForm = ( xOldForm.get() != xNewForm.get() );
1830
0
    bool bNeedSave = bDifferentForm && !_bNoSaveOldContent;
1831
        // we save the content of the old form if we move to a new form, and saving old content is allowed
1832
1833
0
    if ( m_xActiveController.is() && bNeedSave )
1834
0
    {
1835
        // save content on change of the controller; a commit has already been executed
1836
0
        if ( m_aActiveControllerFeatures->commitCurrentControl() )
1837
0
        {
1838
0
            m_bSetFocus = true;
1839
0
            if ( m_aActiveControllerFeatures->isModifiedRow() )
1840
0
            {
1841
0
                bool bIsNew = m_aActiveControllerFeatures->isInsertionRow();
1842
0
                bool bResult = m_aActiveControllerFeatures->commitCurrentRecord();
1843
0
                if ( !bResult && m_bSetFocus )
1844
0
                {
1845
                    // if we couldn't save the current record, set the focus back to the
1846
                    // current control
1847
0
                    Reference< XWindow > xWindow( m_xActiveController->getCurrentControl(), UNO_QUERY );
1848
0
                    if ( xWindow.is() )
1849
0
                        xWindow->setFocus();
1850
0
                    m_bInActivate = false;
1851
0
                    return;
1852
0
                }
1853
0
                else if ( bResult && bIsNew )
1854
0
                {
1855
0
                    Reference< XResultSet > xCursor( m_aActiveControllerFeatures->getCursor() );
1856
0
                    if ( xCursor.is() )
1857
0
                    {
1858
0
                        DO_SAFE( xCursor->last(); );
1859
0
                    }
1860
0
                }
1861
0
            }
1862
0
        }
1863
0
    }
1864
1865
0
    stopListening_Lock();
1866
1867
0
    impl_switchActiveControllerListening_Lock(false);
1868
1869
0
    m_aActiveControllerFeatures.dispose();
1870
0
    m_xActiveController = xController;
1871
0
    if ( m_xActiveController.is() )
1872
0
        m_aActiveControllerFeatures.assign( m_xActiveController );
1873
1874
0
    impl_switchActiveControllerListening_Lock(true);
1875
1876
0
    if ( m_xActiveController.is() )
1877
0
        m_xActiveForm = getInternalForm_Lock(Reference<XForm>(m_xActiveController->getModel(), UNO_QUERY));
1878
0
    else
1879
0
        m_xActiveForm = nullptr;
1880
1881
0
    startListening_Lock();
1882
1883
    // activate all dispatchers belonging to form of the new navigation controller
1884
0
    xNavigationForm = nullptr;
1885
0
    if (m_xNavigationController.is())
1886
0
        xNavigationForm.set(m_xNavigationController->getModel(), UNO_QUERY);
1887
1888
0
    m_bInActivate = false;
1889
1890
0
    m_pShell->UIFeatureChanged();
1891
0
    m_pShell->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell);
1892
1893
0
    InvalidateSlot_Lock(SID_FM_FILTER_NAVIGATOR_CONTROL, true);
1894
0
}
1895
1896
InterfaceBag FmXFormShell::getCurrentSelection_Lock() const
1897
0
{
1898
0
    return m_aCurrentSelection;
1899
0
}
1900
1901
bool FmXFormShell::setCurrentSelectionFromMark_Lock(const SdrMarkList& _rMarkList)
1902
0
{
1903
0
    m_aLastKnownMarkedControls.clear();
1904
1905
0
    if ( ( _rMarkList.GetMarkCount() > 0 ) && isControlList( _rMarkList ) )
1906
0
        collectInterfacesFromMarkList( _rMarkList, m_aLastKnownMarkedControls );
1907
1908
0
    return setCurrentSelection_Lock(o3tl::sorted_vector(m_aLastKnownMarkedControls));
1909
0
}
1910
1911
1912
bool FmXFormShell::selectLastMarkedControls_Lock()
1913
0
{
1914
0
    return setCurrentSelection_Lock(o3tl::sorted_vector(m_aLastKnownMarkedControls));
1915
0
}
1916
1917
1918
bool FmXFormShell::setCurrentSelection_Lock( InterfaceBag&& _rSelection )
1919
0
{
1920
0
    if (impl_checkDisposed_Lock())
1921
0
        return false;
1922
1923
0
    DBG_ASSERT( m_pShell->IsDesignMode(), "FmXFormShell::setCurrentSelection: only to be used in design mode!" );
1924
1925
0
    if ( _rSelection.empty() && m_aCurrentSelection.empty() )
1926
        // nothing to do
1927
0
        return false;
1928
1929
0
    if ( _rSelection.size() == m_aCurrentSelection.size() )
1930
0
    {
1931
0
        InterfaceBag::const_iterator aNew = _rSelection.begin();
1932
0
        InterfaceBag::const_iterator aOld = m_aCurrentSelection.begin();
1933
0
        for ( ; aNew != _rSelection.end(); ++aNew, ++aOld )
1934
0
        {
1935
0
            OSL_ENSURE( Reference< XInterface >( *aNew, UNO_QUERY ).get() == aNew->get(), "FmXFormShell::setCurrentSelection: new interface not normalized!" );
1936
0
            OSL_ENSURE( Reference< XInterface >( *aOld, UNO_QUERY ).get() == aOld->get(), "FmXFormShell::setCurrentSelection: old interface not normalized!" );
1937
1938
0
            if ( aNew->get() != aOld->get() )
1939
0
                break;
1940
0
        }
1941
1942
0
        if ( aNew == _rSelection.end() )
1943
            // both bags equal
1944
0
            return false;
1945
0
    }
1946
1947
    // the following is some strange code to ensure that when you have two grid controls in a document,
1948
    // only one of them can have a selected column.
1949
    // TODO: this should happen elsewhere, but not here - shouldn't it?
1950
0
    if ( !m_aCurrentSelection.empty() )
1951
0
    {
1952
0
        Reference< XChild > xCur; if ( m_aCurrentSelection.size() == 1 ) xCur.set(*m_aCurrentSelection.begin(), css::uno::UNO_QUERY);
1953
0
        Reference< XChild > xNew; if ( _rSelection.size() == 1 ) xNew.set(*_rSelection.begin(), css::uno::UNO_QUERY);
1954
1955
        // is there nothing to be selected, or the parents differ, and the parent of the current object
1956
        // is a selection supplier, then deselect
1957
0
        if ( xCur.is() && ( !xNew.is() || ( xCur->getParent() != xNew->getParent() ) ) )
1958
0
        {
1959
0
            Reference< XSelectionSupplier > xSel( xCur->getParent(), UNO_QUERY );
1960
0
            if ( xSel.is() )
1961
0
                xSel->select( Any() );
1962
0
        }
1963
0
    }
1964
1965
0
    m_aCurrentSelection = std::move(_rSelection);
1966
1967
    // determine the form which all the selected objects belong to, if any
1968
0
    Reference< XForm > xNewCurrentForm;
1969
0
    for (const auto& rpSelection : m_aCurrentSelection)
1970
0
    {
1971
0
        Reference< XForm > xThisRoundsForm( GetForm( rpSelection ) );
1972
0
        OSL_ENSURE( xThisRoundsForm.is(), "FmXFormShell::setCurrentSelection: *everything* should belong to a form!" );
1973
1974
0
        if ( !xNewCurrentForm.is() )
1975
0
        {   // the first form we encountered
1976
0
            xNewCurrentForm = std::move(xThisRoundsForm);
1977
0
        }
1978
0
        else if ( xNewCurrentForm != xThisRoundsForm )
1979
0
        {   // different forms -> no "current form" at all
1980
0
            xNewCurrentForm.clear();
1981
0
            break;
1982
0
        }
1983
0
    }
1984
1985
0
    if ( !m_aCurrentSelection.empty() )
1986
0
        impl_updateCurrentForm_Lock(xNewCurrentForm);
1987
1988
    // ensure some slots are updated
1989
0
    for (sal_Int16 i : SelObjectSlotMap)
1990
0
        InvalidateSlot_Lock(i, false);
1991
1992
0
    return true;
1993
0
}
1994
1995
1996
bool FmXFormShell::isSolelySelected_Lock(const Reference<XInterface>& _rxObject)
1997
0
{
1998
0
    return ( m_aCurrentSelection.size() == 1 ) && ( *m_aCurrentSelection.begin() == _rxObject );
1999
0
}
2000
2001
2002
void FmXFormShell::forgetCurrentForm_Lock()
2003
0
{
2004
0
    if ( !m_xCurrentForm.is() )
2005
0
        return;
2006
2007
    // reset ...
2008
0
    impl_updateCurrentForm_Lock(nullptr);
2009
2010
    // ... and try finding a new current form
2011
    // #i88186# / 2008-04-12 / frank.schoenheit@sun.com
2012
0
    impl_defaultCurrentForm_nothrow_Lock();
2013
0
}
2014
2015
2016
void FmXFormShell::impl_updateCurrentForm_Lock(const Reference<XForm>& _rxNewCurForm)
2017
0
{
2018
0
    if (impl_checkDisposed_Lock())
2019
0
        return;
2020
2021
0
    m_xCurrentForm = _rxNewCurForm;
2022
2023
    // propagate to the FormPage(Impl)
2024
0
    FmFormPage* pPage = m_pShell->GetCurPage();
2025
0
    if ( pPage )
2026
0
        pPage->GetImpl().setCurForm( m_xCurrentForm );
2027
2028
    // ensure the UI which depends on the current form is up-to-date
2029
0
    for (sal_Int16 i : DlgSlotMap)
2030
0
        InvalidateSlot_Lock(i, false);
2031
0
}
2032
2033
2034
void FmXFormShell::startListening_Lock()
2035
0
{
2036
0
    if (impl_checkDisposed_Lock())
2037
0
        return;
2038
2039
0
    Reference< XRowSet> xDatabaseForm(m_xActiveForm, UNO_QUERY);
2040
0
    if (xDatabaseForm.is() && getConnection(xDatabaseForm).is())
2041
0
    {
2042
0
        Reference< XPropertySet> xActiveFormSet(m_xActiveForm, UNO_QUERY);
2043
0
        if (xActiveFormSet.is())
2044
0
        {
2045
            // if there is a data source, then build the listener
2046
            // TODO: this is strange - shouldn't this depend on a isLoaded instead of
2047
            // a "has command value"? Finally, the command value only means that it was
2048
            // intended to be loaded, not that it actually *is* loaded
2049
0
            OUString aSource = ::comphelper::getString(xActiveFormSet->getPropertyValue(FM_PROP_COMMAND));
2050
0
            if (!aSource.isEmpty())
2051
0
            {
2052
0
                m_bDatabaseBar = true;
2053
2054
0
                xActiveFormSet->getPropertyValue(FM_PROP_NAVIGATION) >>= m_eNavigate;
2055
2056
0
                switch (m_eNavigate)
2057
0
                {
2058
0
                    case NavigationBarMode_PARENT:
2059
0
                    {
2060
                        // search for the controller via which navigation is possible
2061
0
                        Reference< XChild> xChild = m_xActiveController;
2062
0
                        Reference< runtime::XFormController > xParent;
2063
0
                        while (xChild.is())
2064
0
                        {
2065
0
                            xChild.set(xChild->getParent(), UNO_QUERY);
2066
0
                            xParent.set(xChild, UNO_QUERY);
2067
0
                            Reference< XPropertySet> xParentSet;
2068
0
                            if (xParent.is())
2069
0
                                xParentSet.set(xParent->getModel(), UNO_QUERY);
2070
0
                            if (xParentSet.is())
2071
0
                            {
2072
0
                                xParentSet->getPropertyValue(FM_PROP_NAVIGATION) >>= m_eNavigate;
2073
0
                                if (m_eNavigate == NavigationBarMode_CURRENT)
2074
0
                                    break;
2075
0
                            }
2076
0
                        }
2077
0
                        m_xNavigationController = std::move(xParent);
2078
0
                    }
2079
0
                    break;
2080
2081
0
                    case NavigationBarMode_CURRENT:
2082
0
                        m_xNavigationController = m_xActiveController;
2083
0
                        break;
2084
2085
0
                    default:
2086
0
                        m_xNavigationController = nullptr;
2087
0
                        m_bDatabaseBar = false;
2088
0
                }
2089
2090
0
                m_aNavControllerFeatures.dispose();
2091
0
                if ( m_xNavigationController.is() && ( m_xNavigationController != m_xActiveController ) )
2092
0
                    m_aNavControllerFeatures.assign( m_xNavigationController );
2093
2094
                // because of RecordCount, listen at the controller which controls the navigation
2095
0
                Reference< XPropertySet> xNavigationSet;
2096
0
                if (m_xNavigationController.is())
2097
0
                {
2098
0
                    xNavigationSet.set(m_xNavigationController->getModel(), UNO_QUERY);
2099
0
                    if (xNavigationSet.is())
2100
0
                        xNavigationSet->addPropertyChangeListener(FM_PROP_ROWCOUNT,this);
2101
0
                }
2102
0
                return;
2103
0
            }
2104
0
        }
2105
0
    }
2106
2107
0
    m_eNavigate  = NavigationBarMode_NONE;
2108
0
    m_bDatabaseBar = false;
2109
0
    m_xNavigationController = nullptr;
2110
0
}
2111
2112
2113
void FmXFormShell::stopListening_Lock()
2114
0
{
2115
0
    if (impl_checkDisposed_Lock())
2116
0
        return;
2117
2118
0
    Reference< XRowSet> xDatabaseForm(m_xActiveForm, UNO_QUERY);
2119
0
    if ( xDatabaseForm.is() )
2120
0
    {
2121
0
        if (m_xNavigationController.is())
2122
0
        {
2123
0
            Reference< XPropertySet> xSet(m_xNavigationController->getModel(), UNO_QUERY);
2124
0
            if (xSet.is())
2125
0
                xSet->removePropertyChangeListener(FM_PROP_ROWCOUNT, this);
2126
2127
0
        }
2128
0
    }
2129
2130
0
    m_bDatabaseBar = false;
2131
0
    m_eNavigate  = NavigationBarMode_NONE;
2132
0
    m_xNavigationController = nullptr;
2133
0
}
2134
2135
void FmXFormShell::ShowSelectionProperties_Lock(bool bShow)
2136
0
{
2137
0
    if (impl_checkDisposed_Lock())
2138
0
        return;
2139
2140
    // if the window is already visible, only update the state
2141
0
    bool bHasChild = m_pShell->GetViewShell()->GetViewFrame().HasChildWindow( SID_FM_SHOW_PROPERTIES );
2142
0
    if ( bHasChild && bShow )
2143
0
        UpdateSlot_Lock(SID_FM_PROPERTY_CONTROL);
2144
2145
    // else toggle state
2146
0
    else
2147
0
        m_pShell->GetViewShell()->GetViewFrame().ToggleChildWindow(SID_FM_SHOW_PROPERTIES);
2148
2149
0
    InvalidateSlot_Lock(SID_FM_PROPERTIES, false);
2150
0
    InvalidateSlot_Lock(SID_FM_CTL_PROPERTIES, false);
2151
0
}
2152
2153
IMPL_LINK(FmXFormShell, OnFoundData_Lock, FmFoundRecordInformation&, rfriWhere, void)
2154
0
{
2155
0
    if (impl_checkDisposed_Lock())
2156
0
        return;
2157
2158
0
    DBG_ASSERT((rfriWhere.nContext >= 0) && (o3tl::make_unsigned(rfriWhere.nContext) < m_aSearchForms.size()),
2159
0
        "FmXFormShell::OnFoundData : invalid context!");
2160
0
    Reference< XForm> xForm( m_aSearchForms.at(rfriWhere.nContext));
2161
0
    DBG_ASSERT(xForm.is(), "FmXFormShell::OnFoundData : invalid form!");
2162
2163
0
    Reference< XRowLocate> xCursor(xForm, UNO_QUERY);
2164
0
    if (!xCursor.is())
2165
0
        return;       // what should I do there?
2166
2167
    // to the record
2168
0
    try
2169
0
    {
2170
0
        xCursor->moveToBookmark(rfriWhere.aPosition);
2171
0
    }
2172
0
    catch(const SQLException&)
2173
0
    {
2174
0
        OSL_FAIL("Can position on bookmark!");
2175
0
    }
2176
2177
0
    LoopGrids_Lock(LoopGridsSync::FORCE_SYNC);
2178
2179
    // and to the field (for that, I collected the XVclComponent interfaces before the start of the search)
2180
0
    SAL_WARN_IF(o3tl::make_unsigned(rfriWhere.nFieldPos) >=
2181
0
            m_arrSearchedControls.size(),
2182
0
        "svx.form", "FmXFormShell::OnFoundData : invalid index!");
2183
0
    SdrObject* pObject = m_arrSearchedControls.at(rfriWhere.nFieldPos);
2184
2185
0
    m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView());
2186
0
    m_pShell->GetFormView()->MarkObj(pObject, m_pShell->GetFormView()->GetSdrPageView());
2187
2188
0
    FmFormObj* pFormObject = FmFormObj::GetFormObject( pObject );
2189
0
    Reference< XControlModel > xControlModel( pFormObject ? pFormObject->GetUnoControlModel() : Reference< XControlModel >() );
2190
0
    DBG_ASSERT( xControlModel.is(), "FmXFormShell::OnFoundData: invalid control!" );
2191
0
    if ( !xControlModel.is() )
2192
0
        return;
2193
2194
    // disable the permanent cursor for the last grid we found a record
2195
0
    if (m_xLastGridFound.is() && (m_xLastGridFound != xControlModel))
2196
0
    {
2197
0
        Reference< XPropertySet> xOldSet(m_xLastGridFound, UNO_QUERY);
2198
0
        xOldSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, Any( false ) );
2199
0
        Reference< XPropertyState> xOldSetState(xOldSet, UNO_QUERY);
2200
0
        if (xOldSetState.is())
2201
0
            xOldSetState->setPropertyToDefault(FM_PROP_CURSORCOLOR);
2202
0
        else
2203
0
            xOldSet->setPropertyValue(FM_PROP_CURSORCOLOR, Any());
2204
0
    }
2205
2206
    // if the field is in a GridControl, I have to additionally go into the corresponding column there
2207
0
    sal_Int32 nGridColumn = m_arrRelativeGridColumn[rfriWhere.nFieldPos];
2208
0
    if (nGridColumn != -1)
2209
0
    {   // unfortunately, I have to first get the control again
2210
0
        Reference<XControl> xControl(pFormObject ? impl_getControl_Lock(xControlModel, *pFormObject) : Reference<XControl>());
2211
0
        Reference< XGrid> xGrid(xControl, UNO_QUERY);
2212
0
        DBG_ASSERT(xGrid.is(), "FmXFormShell::OnFoundData : invalid control!");
2213
        // if one of the asserts fires, I probably did something wrong on building of m_arrSearchedControls
2214
2215
        // enable a permanent cursor for the grid so we can see the found text
2216
0
        Reference< XPropertySet> xModelSet(xControlModel, UNO_QUERY);
2217
0
        DBG_ASSERT(xModelSet.is(), "FmXFormShell::OnFoundData : invalid control model (no property set) !");
2218
0
        xModelSet->setPropertyValue( FM_PROP_ALWAYSSHOWCURSOR, Any( true ) );
2219
0
        xModelSet->setPropertyValue( FM_PROP_CURSORCOLOR, Any( COL_LIGHTRED ) );
2220
0
        m_xLastGridFound = std::move(xControlModel);
2221
2222
0
        if ( xGrid.is() )
2223
0
            xGrid->setCurrentColumnPosition(static_cast<sal_Int16>(nGridColumn));
2224
0
    }
2225
2226
    // As the cursor has been repositioned, I have (in positioned) invalidated
2227
    // my form bar slots. But that does not take effect here unfortunately, as
2228
    // generally the (modal) search dialog is of course at the top ... So, force ...
2229
0
    sal_uInt16 nPos = 0;
2230
0
    while (DatabaseSlotMap[nPos])
2231
0
        m_pShell->GetViewShell()->GetViewFrame().GetBindings().Update(DatabaseSlotMap[nPos++]);
2232
        // unfortunately the update goes against the invalidate with only individual slots
2233
0
}
2234
2235
IMPL_LINK(FmXFormShell, OnCanceledNotFound_Lock, FmFoundRecordInformation&, rfriWhere, void)
2236
0
{
2237
0
    if (impl_checkDisposed_Lock())
2238
0
        return;
2239
2240
0
    DBG_ASSERT((rfriWhere.nContext >= 0) && (o3tl::make_unsigned(rfriWhere.nContext) < m_aSearchForms.size()),
2241
0
        "FmXFormShell::OnCanceledNotFound : invalid context!");
2242
0
    Reference< XForm> xForm( m_aSearchForms.at(rfriWhere.nContext));
2243
0
    DBG_ASSERT(xForm.is(), "FmXFormShell::OnCanceledNotFound : invalid form!");
2244
2245
0
    Reference< XRowLocate> xCursor(xForm, UNO_QUERY);
2246
0
    if (!xCursor.is())
2247
0
        return;       // what should I do there?
2248
2249
    // to the record
2250
0
    try
2251
0
    {
2252
0
        xCursor->moveToBookmark(rfriWhere.aPosition);
2253
0
    }
2254
0
    catch(const SQLException&)
2255
0
    {
2256
0
        OSL_FAIL("Can position on bookmark!");
2257
0
    }
2258
2259
2260
0
    m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView());
2261
0
}
2262
2263
2264
IMPL_LINK(FmXFormShell, OnSearchContextRequest_Lock, FmSearchContext&, rfmscContextInfo, sal_uInt32)
2265
0
{
2266
0
    if (impl_checkDisposed_Lock())
2267
0
        return 0;
2268
2269
0
    DBG_ASSERT(rfmscContextInfo.nContext < static_cast<sal_Int16>(m_aSearchForms.size()), "FmXFormShell::OnSearchContextRequest : invalid parameter !");
2270
0
    Reference< XForm> xForm( m_aSearchForms.at(rfmscContextInfo.nContext));
2271
0
    DBG_ASSERT(xForm.is(), "FmXFormShell::OnSearchContextRequest : unexpected : invalid context !");
2272
2273
0
    Reference< XResultSet> xIter(xForm, UNO_QUERY);
2274
0
    DBG_ASSERT(xIter.is(), "FmXFormShell::OnSearchContextRequest : unexpected : context has no iterator !");
2275
2276
2277
    // assemble the list of fields to involve (that is, the ControlSources of all fields that have such a property)
2278
0
    OUString strFieldList, sFieldDisplayNames;
2279
0
    m_arrSearchedControls.clear();
2280
0
    m_arrRelativeGridColumn.clear();
2281
2282
    // small problem: To mark found fields, I need SdrObjects. To determine which controls
2283
    // to include in the search, I need Controls (that is, XControl interfaces). So I have
2284
    // to iterate over one of them and get the other in some way. Unfortunately, there is
2285
    // no direct connection between the two worlds (except from a GetUnoControl to a
2286
    // SdrUnoObject, but this requires an OutputDevice I can not do anything with.
2287
    // However I can get to the Model from the Control and also from the SdrObject, and in
2288
    // this way the assignment SdrObject<->Control is possible with a double loop.
2289
    // The alternative to this (ugly but certainly not entirely fixable) solution would be
2290
    // to renounce the caching of the SdrObjects, which would lead to significant extra
2291
    // work in OnFoundData (since there I'd have to get the SdrObject first thing every
2292
    // time). But since OnFoundData is usually called more often than ExecuteSearch, I'll
2293
    // do that here.
2294
2295
0
    Reference< XNameAccess> xValidFormFields;
2296
0
    Reference< XColumnsSupplier> xSupplyCols(xIter, UNO_QUERY);
2297
0
    DBG_ASSERT(xSupplyCols.is(), "FmXFormShell::OnSearchContextRequest : invalid cursor : no columns supplier !");
2298
0
    if (xSupplyCols.is())
2299
0
        xValidFormFields = xSupplyCols->getColumns();
2300
0
    DBG_ASSERT(xValidFormFields.is(), "FmXFormShell::OnSearchContextRequest : form has no fields !");
2301
2302
    // current Page/Controller
2303
0
    FmFormPage* pCurrentPage = m_pShell->GetCurPage();
2304
0
    assert(pCurrentPage && "FmXFormShell::OnSearchContextRequest : no page !");
2305
    // Search all SdrControls of this page...
2306
0
    OUString sControlSource, aName;
2307
2308
0
    SdrObjListIter aPageIter( pCurrentPage );
2309
0
    while ( aPageIter.IsMore() )
2310
0
    {
2311
0
        SdrObject* pCurrent = aPageIter.Next();
2312
0
        FmFormObj* pFormObject = FmFormObj::GetFormObject( pCurrent );
2313
        // note that in case pCurrent is a virtual object, pFormObject points to the referenced object
2314
2315
0
        if ( !pFormObject )
2316
0
            continue;
2317
2318
        // the current object's model, in different tastes
2319
0
        Reference< XControlModel> xControlModel( pFormObject->GetUnoControlModel() );
2320
0
        Reference< XFormComponent > xCurrentFormComponent( xControlModel, UNO_QUERY );
2321
0
        DBG_ASSERT( xCurrentFormComponent.is(), "FmXFormShell::OnSearchContextRequest: invalid objects!" );
2322
0
        if ( !xCurrentFormComponent.is() )
2323
0
            continue;
2324
2325
        // does the component belong to the form which we're interested in?
2326
0
        if ( xCurrentFormComponent->getParent() != xForm )
2327
0
            continue;
2328
2329
        // ... ask for the ControlSource property
2330
0
        SearchableControlIterator iter( xCurrentFormComponent );
2331
0
        Reference< XControl> xControl;
2332
        // the control that has model xControlModel
2333
        // (the following while can be passed through several times, without the Control
2334
        // being modified, so I don't have to search every time from scratch)
2335
2336
0
        Reference< XInterface > xSearchable( iter.Next() );
2337
0
        while ( xSearchable.is() )
2338
0
        {
2339
0
            sControlSource = iter.getCurrentValue();
2340
0
            if ( sControlSource.isEmpty() )
2341
0
            {
2342
                // the current element has no ControlSource, so it is a GridControl (that
2343
                // is the only thing that still permits the SearchableControlIterator)
2344
0
                xControl = impl_getControl_Lock(xControlModel, *pFormObject);
2345
0
                DBG_ASSERT(xControl.is(), "FmXFormShell::OnSearchContextRequest : didn't ::std::find a control with requested model !");
2346
2347
0
                Reference< XGridPeer> xGridPeer;
2348
0
                if ( xControl.is() )
2349
0
                    xGridPeer.set( xControl->getPeer(), UNO_QUERY );
2350
0
                do
2351
0
                {
2352
0
                    if (!xGridPeer.is())
2353
0
                        break;
2354
2355
0
                    Reference< XIndexAccess> xPeerContainer(xGridPeer, UNO_QUERY);
2356
0
                    if (!xPeerContainer.is())
2357
0
                        break;
2358
2359
0
                    Reference< XIndexAccess> xModelColumns = xGridPeer->getColumns();
2360
0
                    DBG_ASSERT(xModelColumns.is(), "FmXFormShell::OnSearchContextRequest : there is a grid control without columns !");
2361
                    // the case 'no columns' should be indicated with an empty container, I think ...
2362
0
                    DBG_ASSERT(xModelColumns->getCount() >= xPeerContainer->getCount(), "FmXFormShell::OnSearchContextRequest : impossible : have more view than model columns !");
2363
2364
0
                    Reference< XInterface> xCurrentColumn;
2365
0
                    for (sal_Int32 nViewPos=0; nViewPos<xPeerContainer->getCount(); ++nViewPos)
2366
0
                    {
2367
0
                        xPeerContainer->getByIndex(nViewPos) >>= xCurrentColumn;
2368
0
                        if (!xCurrentColumn.is())
2369
0
                            continue;
2370
2371
                        // can we use this column control for searching ?
2372
0
                        if (!IsSearchableControl(xCurrentColumn))
2373
0
                            continue;
2374
2375
0
                        sal_Int32 nModelPos = GridView2ModelPos(xModelColumns, nViewPos);
2376
0
                        Reference< XPropertySet> xCurrentColModel;
2377
0
                        xModelColumns->getByIndex(nModelPos) >>= xCurrentColModel;
2378
0
                        aName = ::comphelper::getString(xCurrentColModel->getPropertyValue(FM_PROP_CONTROLSOURCE));
2379
                        // the cursor has a field matching the control source ?
2380
0
                        if (xValidFormFields->hasByName(aName))
2381
0
                        {
2382
0
                            strFieldList += aName + ";";
2383
2384
0
                            sFieldDisplayNames +=
2385
0
                                    ::comphelper::getString(xCurrentColModel->getPropertyValue(FM_PROP_LABEL)) +
2386
0
                                    ";";
2387
2388
0
                            rfmscContextInfo.arrFields.push_back(xCurrentColumn);
2389
2390
                            // and the SdrOject to the Field
2391
0
                            m_arrSearchedControls.push_back(pCurrent);
2392
                            // the number of the column
2393
0
                            m_arrRelativeGridColumn.push_back(nViewPos);
2394
0
                        }
2395
0
                    }
2396
0
                } while (false);
2397
0
            }
2398
0
            else
2399
0
            {
2400
0
                if (!sControlSource.isEmpty() && xValidFormFields->hasByName(sControlSource))
2401
0
                {
2402
                    // now I need the Control to SdrObject
2403
0
                    if (!xControl.is())
2404
0
                    {
2405
0
                        xControl = impl_getControl_Lock(xControlModel, *pFormObject);
2406
0
                        DBG_ASSERT(xControl.is(), "FmXFormShell::OnSearchContextRequest : didn't ::std::find a control with requested model !");
2407
0
                    }
2408
2409
0
                    if (IsSearchableControl(xControl))
2410
0
                    {
2411
                        // all tests passed -> take along in the list
2412
0
                        strFieldList += sControlSource + ";";
2413
2414
                        // the label which should appear for the control :
2415
0
                        sFieldDisplayNames +=
2416
0
                                getLabelName(Reference< XPropertySet>(xControlModel, UNO_QUERY)) +
2417
0
                                ";";
2418
2419
                        // mark the SdrObject (accelerates the treatment in OnFoundData)
2420
0
                        m_arrSearchedControls.push_back(pCurrent);
2421
2422
                        // the number of the column (here a dummy, since it is only interesting for GridControls)
2423
0
                        m_arrRelativeGridColumn.push_back(-1);
2424
2425
                        // and for the formatted search...
2426
0
                        rfmscContextInfo.arrFields.emplace_back( xControl, UNO_QUERY );
2427
0
                    }
2428
0
                }
2429
0
            }
2430
2431
0
            xSearchable = iter.Next();
2432
0
        }
2433
0
    }
2434
2435
0
    strFieldList = comphelper::string::stripEnd(strFieldList, ';');
2436
0
    sFieldDisplayNames = comphelper::string::stripEnd(sFieldDisplayNames, ';');
2437
2438
0
    if (rfmscContextInfo.arrFields.empty())
2439
0
    {
2440
0
        rfmscContextInfo.arrFields.clear();
2441
0
        rfmscContextInfo.xCursor = nullptr;
2442
0
        rfmscContextInfo.strUsedFields.clear();
2443
0
        return 0;
2444
0
    }
2445
2446
0
    rfmscContextInfo.xCursor = std::move(xIter);
2447
0
    rfmscContextInfo.strUsedFields = strFieldList;
2448
0
    rfmscContextInfo.sFieldDisplayNames = sFieldDisplayNames;
2449
2450
    // 66463 - 31.05.99 - FS
2451
    // when the cursor is a non-STANDARD RecordMode, set it back
2452
0
    Reference< XPropertySet> xCursorSet(rfmscContextInfo.xCursor, UNO_QUERY);
2453
0
    Reference< XResultSetUpdate> xUpdateCursor(rfmscContextInfo.xCursor, UNO_QUERY);
2454
0
    if (xUpdateCursor.is() && xCursorSet.is())
2455
0
    {
2456
0
        if (::comphelper::getBOOL(xCursorSet->getPropertyValue(FM_PROP_ISNEW)))
2457
0
            xUpdateCursor->moveToCurrentRow();
2458
0
        else if (::comphelper::getBOOL(xCursorSet->getPropertyValue(FM_PROP_ISMODIFIED)))
2459
0
            xUpdateCursor->cancelRowUpdates();
2460
0
    }
2461
2462
0
    return rfmscContextInfo.arrFields.size();
2463
0
}
2464
2465
  // XContainerListener
2466
2467
void SAL_CALL FmXFormShell::elementInserted(const ContainerEvent& evt)
2468
0
{
2469
0
    SolarMutexGuard g;
2470
2471
0
    if (impl_checkDisposed_Lock())
2472
0
        return;
2473
2474
    // new object to listen to
2475
0
    Reference< XInterface> xTemp;
2476
0
    evt.Element >>= xTemp;
2477
0
    AddElement_Lock(xTemp);
2478
2479
0
    m_pShell->DetermineForms(true);
2480
0
}
2481
2482
2483
void SAL_CALL FmXFormShell::elementReplaced(const ContainerEvent& evt)
2484
0
{
2485
0
    SolarMutexGuard g;
2486
2487
0
    if (impl_checkDisposed_Lock() )
2488
0
        return;
2489
2490
0
    Reference< XInterface> xTemp;
2491
0
    evt.ReplacedElement >>= xTemp;
2492
0
    RemoveElement_Lock(xTemp);
2493
0
    evt.Element >>= xTemp;
2494
0
    AddElement_Lock(xTemp);
2495
0
}
2496
2497
2498
void SAL_CALL FmXFormShell::elementRemoved(const ContainerEvent& evt)
2499
0
{
2500
0
    SolarMutexGuard g;
2501
2502
0
    if (impl_checkDisposed_Lock())
2503
0
        return;
2504
2505
0
    Reference< XInterface> xTemp;
2506
0
    evt.Element >>= xTemp;
2507
0
    RemoveElement_Lock(xTemp);
2508
2509
0
    m_pShell->DetermineForms(true);
2510
0
}
2511
2512
2513
void FmXFormShell::UpdateForms_Lock(bool _bInvalidate)
2514
26.6k
{
2515
26.6k
    if (impl_checkDisposed_Lock())
2516
0
        return;
2517
2518
26.6k
    Reference< XIndexAccess > xForms;
2519
2520
26.6k
    FmFormPage* pPage = m_pShell->GetCurPage();
2521
26.6k
    if ( pPage && m_pShell->m_bDesignMode )
2522
26.5k
        xForms = pPage->GetForms( false );
2523
2524
26.6k
    if ( m_xForms != xForms )
2525
0
    {
2526
0
        RemoveElement_Lock( m_xForms );
2527
0
        m_xForms = std::move(xForms);
2528
0
        AddElement_Lock(m_xForms);
2529
0
    }
2530
2531
26.6k
    SolarMutexGuard g;
2532
26.6k
    m_pShell->DetermineForms( _bInvalidate );
2533
26.6k
}
2534
2535
2536
void FmXFormShell::AddElement_Lock(const Reference<XInterface>& _xElement)
2537
0
{
2538
0
    if (impl_checkDisposed_Lock())
2539
0
        return;
2540
0
    impl_AddElement_nothrow(_xElement);
2541
0
}
2542
2543
void FmXFormShell::impl_AddElement_nothrow(const Reference< XInterface>& Element)
2544
0
{
2545
    // listen at the container
2546
0
    const Reference< XIndexContainer> xContainer(Element, UNO_QUERY);
2547
0
    if (xContainer.is())
2548
0
    {
2549
0
        const sal_uInt32 nCount = xContainer->getCount();
2550
0
        Reference< XInterface> xElement;
2551
0
        for (sal_uInt32 i = 0; i < nCount; ++i)
2552
0
        {
2553
0
            xElement.set(xContainer->getByIndex(i),UNO_QUERY);
2554
0
            impl_AddElement_nothrow(xElement);
2555
0
        }
2556
2557
0
        const Reference< XContainer> xCont(Element, UNO_QUERY);
2558
0
        if (xCont.is())
2559
0
            xCont->addContainerListener(this);
2560
0
    }
2561
2562
0
    const Reference< css::view::XSelectionSupplier> xSelSupplier(Element, UNO_QUERY);
2563
0
    if (xSelSupplier.is())
2564
0
        xSelSupplier->addSelectionChangeListener(this);
2565
0
}
2566
2567
2568
void FmXFormShell::RemoveElement_Lock(const Reference<XInterface>& Element)
2569
8.87k
{
2570
8.87k
    if (impl_checkDisposed_Lock())
2571
0
        return;
2572
8.87k
    impl_RemoveElement_nothrow_Lock(Element);
2573
8.87k
}
2574
2575
void FmXFormShell::impl_RemoveElement_nothrow_Lock(const Reference<XInterface>& Element)
2576
8.87k
{
2577
8.87k
    const Reference< css::view::XSelectionSupplier> xSelSupplier(Element, UNO_QUERY);
2578
8.87k
    if (xSelSupplier.is())
2579
0
        xSelSupplier->removeSelectionChangeListener(this);
2580
2581
    // remove connection to children
2582
8.87k
    const Reference< XIndexContainer> xContainer(Element, UNO_QUERY);
2583
8.87k
    if (xContainer.is())
2584
0
    {
2585
0
        const Reference< XContainer> xCont(Element, UNO_QUERY);
2586
0
        if (xCont.is())
2587
0
            xCont->removeContainerListener(this);
2588
2589
0
        const sal_uInt32 nCount = xContainer->getCount();
2590
0
        Reference< XInterface> xElement;
2591
0
        for (sal_uInt32 i = 0; i < nCount; i++)
2592
0
        {
2593
0
            xElement.set(xContainer->getByIndex(i),UNO_QUERY);
2594
0
            impl_RemoveElement_nothrow_Lock(xElement);
2595
0
        }
2596
0
    }
2597
2598
8.87k
    auto wasSelectedPos = m_aCurrentSelection.find( Element );
2599
8.87k
    if ( wasSelectedPos != m_aCurrentSelection.end() )
2600
0
        m_aCurrentSelection.erase( wasSelectedPos );
2601
8.87k
}
2602
2603
2604
void SAL_CALL FmXFormShell::selectionChanged(const lang::EventObject& rEvent)
2605
0
{
2606
0
    SolarMutexGuard g;
2607
2608
0
    if (impl_checkDisposed_Lock())
2609
0
        return;
2610
2611
0
    Reference< XSelectionSupplier > xSupplier( rEvent.Source, UNO_QUERY );
2612
0
    Reference< XInterface > xSelObj( xSupplier->getSelection(), UNO_QUERY );
2613
    // a selection was removed, this can only be done by the shell
2614
0
    if ( !xSelObj.is() )
2615
0
        return;
2616
2617
0
    EnableTrackProperties_Lock(false);
2618
2619
0
    bool bMarkChanged = m_pShell->GetFormView()->checkUnMarkAll(rEvent.Source);
2620
2621
0
    InterfaceBag aNewSelection;
2622
0
    aNewSelection.insert( Reference<XInterface>( xSelObj, UNO_QUERY ) );
2623
2624
0
    if (setCurrentSelection_Lock(std::move(aNewSelection)) && IsPropBrwOpen_Lock())
2625
0
        ShowSelectionProperties_Lock(true);
2626
2627
0
    EnableTrackProperties_Lock(true);
2628
2629
0
    if ( bMarkChanged )
2630
0
        m_pShell->NotifyMarkListChanged( m_pShell->GetFormView() );
2631
0
}
2632
2633
2634
IMPL_LINK_NOARG(FmXFormShell, OnTimeOut_Lock, Timer*, void)
2635
0
{
2636
0
    if (impl_checkDisposed_Lock())
2637
0
        return;
2638
2639
0
    if (m_pShell->IsDesignMode() && m_pShell->GetFormView())
2640
0
        SetSelection_Lock(m_pShell->GetFormView()->GetMarkedObjectList());
2641
0
}
2642
2643
2644
void FmXFormShell::SetSelectionDelayed_Lock()
2645
36
{
2646
36
    if (impl_checkDisposed_Lock())
2647
0
        return;
2648
2649
36
    if (m_pShell->IsDesignMode() && IsTrackPropertiesEnabled_Lock() && !m_aMarkTimer.IsActive())
2650
18
        m_aMarkTimer.Start();
2651
36
}
2652
2653
2654
void FmXFormShell::SetSelection_Lock(const SdrMarkList& rMarkList)
2655
0
{
2656
0
    if (impl_checkDisposed_Lock())
2657
0
        return;
2658
2659
0
    DetermineSelection_Lock(rMarkList);
2660
0
    m_pShell->NotifyMarkListChanged(m_pShell->GetFormView());
2661
0
}
2662
2663
void FmXFormShell::DetermineSelection_Lock(const SdrMarkList& rMarkList)
2664
0
{
2665
0
    if (setCurrentSelectionFromMark_Lock(rMarkList) && IsPropBrwOpen_Lock())
2666
0
        ShowSelectionProperties_Lock(true);
2667
0
}
2668
2669
bool FmXFormShell::IsPropBrwOpen_Lock() const
2670
0
{
2671
0
    if (impl_checkDisposed_Lock())
2672
0
        return false;
2673
2674
0
    return m_pShell->GetViewShell() &&
2675
0
           m_pShell->GetViewShell()->GetViewFrame().HasChildWindow(SID_FM_SHOW_PROPERTIES);
2676
0
}
2677
2678
class FmXFormShell::SuspendPropertyTracking
2679
{
2680
private:
2681
    FmXFormShell&   m_rShell;
2682
    bool            m_bEnabled;
2683
2684
public:
2685
    explicit SuspendPropertyTracking( FmXFormShell& _rShell )
2686
8.87k
        :m_rShell( _rShell )
2687
8.87k
        ,m_bEnabled( false )
2688
8.87k
    {
2689
8.87k
        if (m_rShell.IsTrackPropertiesEnabled_Lock())
2690
8.87k
        {
2691
8.87k
            m_rShell.EnableTrackProperties_Lock(false);
2692
8.87k
            m_bEnabled = true;
2693
8.87k
        }
2694
8.87k
    }
2695
2696
    ~SuspendPropertyTracking( )
2697
8.87k
    {
2698
8.87k
        if ( m_bEnabled )   // note that ( false != m_bEnabled ) implies ( NULL != m_pShell )
2699
8.87k
            m_rShell.EnableTrackProperties_Lock(true);
2700
8.87k
    }
2701
};
2702
2703
void FmXFormShell::SetDesignMode_Lock(bool bDesign)
2704
8.87k
{
2705
8.87k
    if (impl_checkDisposed_Lock())
2706
0
        return;
2707
2708
8.87k
    DBG_ASSERT(m_pShell->GetFormView(), "FmXFormShell::SetDesignMode : invalid call (have no shell or no view) !");
2709
8.87k
    m_bChangingDesignMode = true;
2710
2711
    // 67506 - 15.07.99 - FS
2712
    // if we're switching off the design mode we have to force the property browser to be closed
2713
    // so it can commit its changes _before_ we load the forms
2714
8.87k
    if (!bDesign)
2715
32
    {
2716
32
        m_bHadPropertyBrowserInDesignMode = m_pShell->GetViewShell()->GetViewFrame().HasChildWindow(SID_FM_SHOW_PROPERTIES);
2717
32
        if (m_bHadPropertyBrowserInDesignMode)
2718
0
            m_pShell->GetViewShell()->GetViewFrame().ToggleChildWindow(SID_FM_SHOW_PROPERTIES);
2719
32
    }
2720
2721
8.87k
    FmFormView* pFormView = m_pShell->GetFormView();
2722
8.87k
    if (bDesign)
2723
8.84k
    {
2724
        // we are currently filtering, so stop filtering
2725
8.84k
        if (m_bFilterMode)
2726
0
            stopFiltering_Lock(false);
2727
2728
        // unsubscribe from the objects of my MarkList
2729
8.84k
        pFormView->GetImpl()->stopMarkListWatching();
2730
8.84k
    }
2731
32
    else
2732
32
    {
2733
32
        m_aMarkTimer.Stop();
2734
2735
32
        SuspendPropertyTracking aSuspend( *this );
2736
32
        pFormView->GetImpl()->saveMarkList();
2737
32
    }
2738
2739
8.87k
    if (bDesign && m_xExternalViewController.is())
2740
0
        CloseExternalFormViewer_Lock();
2741
2742
8.87k
    pFormView->ChangeDesignMode(bDesign);
2743
2744
    // notify listeners
2745
8.87k
    FmDesignModeChangedHint aChangedHint( bDesign );
2746
8.87k
    m_pShell->Broadcast(aChangedHint);
2747
2748
8.87k
    m_pShell->m_bDesignMode = bDesign;
2749
8.87k
    UpdateForms_Lock(false);
2750
2751
8.87k
    m_pTextShell->designModeChanged();
2752
2753
8.87k
    if (bDesign)
2754
8.84k
    {
2755
8.84k
        SdrMarkList aList;
2756
8.84k
        {
2757
            // during changing the mark list, don't track the selected objects in the property browser
2758
8.84k
            SuspendPropertyTracking aSuspend( *this );
2759
            // restore the marks
2760
8.84k
            pFormView->GetImpl()->restoreMarkList( aList );
2761
8.84k
        }
2762
2763
        // synchronize with the restored mark list
2764
8.84k
        if ( aList.GetMarkCount() )
2765
0
            SetSelection_Lock(aList);
2766
8.84k
    }
2767
32
    else
2768
32
    {
2769
        // subscribe to the model of the view (so that I'm informed when someone deletes
2770
        // during the alive mode controls that I had saved in the saveMarklist (60343)
2771
32
        pFormView->GetImpl()->startMarkListWatching();
2772
32
    }
2773
2774
8.87k
    m_pShell->UIFeatureChanged();
2775
2776
    // 67506 - 15.07.99 - FS
2777
8.87k
    if (bDesign && m_bHadPropertyBrowserInDesignMode)
2778
0
    {
2779
        // The UIFeatureChanged performs an update (a check of the available features) asynchronously.
2780
        // So we can't call ShowSelectionProperties directly as the according feature isn't enabled yet.
2781
        // That's why we use an asynchronous execution on the dispatcher.
2782
        // (And that's why this has to be done AFTER the UIFeatureChanged.)
2783
0
        m_pShell->GetViewShell()->GetViewFrame().GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER, SfxCallMode::ASYNCHRON );
2784
0
    }
2785
8.87k
    m_bChangingDesignMode = false;
2786
8.87k
}
2787
2788
Reference< XControl> FmXFormShell::impl_getControl_Lock(const Reference<XControlModel>& i_rxModel, const FmFormObj& i_rKnownFormObj)
2789
0
{
2790
0
    if (impl_checkDisposed_Lock())
2791
0
        return nullptr;
2792
2793
0
    Reference< XControl > xControl;
2794
0
    try
2795
0
    {
2796
0
        Reference< XControlContainer> xControlContainer(getControlContainerForView_Lock(), UNO_SET_THROW);
2797
2798
0
        const Sequence< Reference< XControl > > seqControls( xControlContainer->getControls() );
2799
        // ... that I can then search
2800
0
        for (Reference< XControl > const & control : seqControls)
2801
0
        {
2802
0
            xControl.set( control, UNO_SET_THROW );
2803
0
            Reference< XControlModel > xCurrentModel( xControl->getModel() );
2804
0
            if ( xCurrentModel == i_rxModel )
2805
0
                break;
2806
0
            xControl.clear();
2807
0
        }
2808
2809
0
        if ( !xControl.is() )
2810
0
        {
2811
            // fallback (some controls might not have been created, yet, since they were never visible so far)
2812
0
            Reference< XControl > xContainerControl( xControlContainer, UNO_QUERY_THROW );
2813
0
            const vcl::Window* pContainerWindow = VCLUnoHelper::GetWindow( xContainerControl->getPeer() );
2814
0
            ENSURE_OR_THROW( pContainerWindow, "unexpected control container implementation" );
2815
2816
0
            const SdrView* pSdrView = m_pShell ? m_pShell->GetFormView() : nullptr;
2817
0
            ENSURE_OR_THROW( pSdrView, "no current view" );
2818
2819
0
            xControl.set( i_rKnownFormObj.GetUnoControl( *pSdrView, *pContainerWindow->GetOutDev() ), UNO_SET_THROW );
2820
0
        }
2821
0
    }
2822
0
    catch( const Exception& )
2823
0
    {
2824
0
        DBG_UNHANDLED_EXCEPTION("svx");
2825
0
    }
2826
2827
0
    OSL_ENSURE( xControl.is(), "FmXFormShell::impl_getControl: no control found!" );
2828
0
    return xControl;
2829
0
}
2830
2831
// note: _out_rForms is a member so needs lock
2832
void FmXFormShell::impl_collectFormSearchContexts_nothrow_Lock( const Reference<XInterface>& _rxStartingPoint,
2833
    std::u16string_view _rCurrentLevelPrefix, FmFormArray& _out_rForms, ::std::vector< OUString >& _out_rNames )
2834
0
{
2835
0
    try
2836
0
    {
2837
0
        Reference< XIndexAccess> xContainer( _rxStartingPoint, UNO_QUERY );
2838
0
        if ( !xContainer.is() )
2839
0
            return;
2840
2841
0
        sal_Int32 nCount( xContainer->getCount() );
2842
0
        if ( nCount == 0 )
2843
0
            return;
2844
2845
0
        OUString sCurrentFormName;
2846
0
        OUStringBuffer aNextLevelPrefix;
2847
0
        for ( sal_Int32 i=0; i<nCount; ++i )
2848
0
        {
2849
            // is the current child a form?
2850
0
            Reference< XForm > xCurrentAsForm( xContainer->getByIndex(i), UNO_QUERY );
2851
0
            if ( !xCurrentAsForm.is() )
2852
0
                continue;
2853
2854
0
            Reference< XNamed > xNamed( xCurrentAsForm, UNO_QUERY_THROW );
2855
0
            sCurrentFormName = xNamed->getName();
2856
2857
            // the name of the current form
2858
0
            OUString sCompleteCurrentName( sCurrentFormName );
2859
0
            if ( !_rCurrentLevelPrefix.empty() )
2860
0
            {
2861
0
                sCompleteCurrentName += OUString::Concat(" (") + _rCurrentLevelPrefix + ")";
2862
0
            }
2863
2864
            // the prefix for the next level
2865
0
            aNextLevelPrefix = _rCurrentLevelPrefix;
2866
0
            if ( !_rCurrentLevelPrefix.empty() )
2867
0
                aNextLevelPrefix.append( '/' );
2868
0
            aNextLevelPrefix.append( sCurrentFormName );
2869
2870
            // remember both the form and its "display name"
2871
0
            _out_rForms.push_back( xCurrentAsForm );
2872
0
            _out_rNames.push_back( sCompleteCurrentName );
2873
2874
            // and descend
2875
0
            impl_collectFormSearchContexts_nothrow_Lock(
2876
0
                xCurrentAsForm, aNextLevelPrefix,
2877
0
                _out_rForms, _out_rNames);
2878
0
            aNextLevelPrefix.setLength(0);
2879
0
        }
2880
0
    }
2881
0
    catch( const Exception& )
2882
0
    {
2883
0
        DBG_UNHANDLED_EXCEPTION("svx");
2884
0
    }
2885
0
}
2886
2887
void FmXFormShell::startFiltering_Lock()
2888
0
{
2889
0
    if (impl_checkDisposed_Lock())
2890
0
        return;
2891
2892
    // setting all forms in filter mode
2893
0
    FmXFormView* pXView = m_pShell->GetFormView()->GetImpl();
2894
2895
    // if the active controller is our external one we have to use the trigger controller
2896
0
    Reference< XControlContainer> xContainer;
2897
0
    if (getActiveController_Lock() == m_xExternalViewController)
2898
0
    {
2899
0
        DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::startFiltering : inconsistent : active external controller, but no one triggered this !");
2900
0
        xContainer = m_xExtViewTriggerController->getContainer();
2901
0
    }
2902
0
    else
2903
0
        xContainer = getActiveController_Lock()->getContainer();
2904
2905
0
    rtl::Reference< FormViewPageWindowAdapter > pAdapter = pXView->findWindow( xContainer );
2906
0
    if ( pAdapter.is() )
2907
0
    {
2908
0
        const ::std::vector< Reference< runtime::XFormController> >& rControllerList = pAdapter->GetList();
2909
0
        for (const auto& rpController : rControllerList)
2910
0
        {
2911
0
            Reference< XModeSelector> xModeSelector(rpController, UNO_QUERY);
2912
0
            if (xModeSelector.is())
2913
0
                xModeSelector->setMode( u"FilterMode"_ustr );
2914
0
        }
2915
0
    }
2916
2917
0
    m_bFilterMode = true;
2918
2919
0
    m_pShell->UIFeatureChanged();
2920
0
    SfxViewFrame& rViewFrame = m_pShell->GetViewShell()->GetViewFrame();
2921
0
    rViewFrame.GetBindings().InvalidateShell( *m_pShell );
2922
2923
0
    if  (   rViewFrame.KnowsChildWindow( SID_FM_FILTER_NAVIGATOR )
2924
0
        &&  !rViewFrame.HasChildWindow( SID_FM_FILTER_NAVIGATOR )
2925
0
        )
2926
0
    {
2927
0
        rViewFrame.ToggleChildWindow( SID_FM_FILTER_NAVIGATOR );
2928
0
    }
2929
0
}
2930
2931
static void saveFilter(const Reference< runtime::XFormController >& _rxController)
2932
0
{
2933
0
    Reference< XPropertySet> xFormAsSet(_rxController->getModel(), UNO_QUERY);
2934
0
    Reference< XPropertySet> xControllerAsSet(_rxController, UNO_QUERY);
2935
2936
    // call the subcontroller
2937
0
    Reference< runtime::XFormController > xController;
2938
0
    for (sal_Int32 i = 0, nCount = _rxController->getCount(); i < nCount; ++i)
2939
0
    {
2940
0
        _rxController->getByIndex(i) >>= xController;
2941
0
        saveFilter(xController);
2942
0
    }
2943
2944
0
    try
2945
0
    {
2946
2947
0
        xFormAsSet->setPropertyValue(FM_PROP_FILTER, xControllerAsSet->getPropertyValue(FM_PROP_FILTER));
2948
0
        xFormAsSet->setPropertyValue(FM_PROP_APPLYFILTER, Any( true ) );
2949
0
    }
2950
0
    catch (const Exception& )
2951
0
    {
2952
0
        DBG_UNHANDLED_EXCEPTION("svx");
2953
0
    }
2954
2955
0
}
2956
2957
2958
void FmXFormShell::stopFiltering_Lock(bool bSave)
2959
0
{
2960
0
    if (impl_checkDisposed_Lock())
2961
0
        return;
2962
2963
0
    m_bFilterMode = false;
2964
2965
0
    FmXFormView* pXView = m_pShell->GetFormView()->GetImpl();
2966
2967
    // if the active controller is our external one we have to use the trigger controller
2968
0
    Reference< XControlContainer> xContainer;
2969
0
    if (getActiveController_Lock() == m_xExternalViewController)
2970
0
    {
2971
0
        DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::stopFiltering : inconsistent : active external controller, but no one triggered this !");
2972
0
        xContainer = m_xExtViewTriggerController->getContainer();
2973
0
    }
2974
0
    else
2975
0
        xContainer = getActiveController_Lock()->getContainer();
2976
2977
0
    rtl::Reference< FormViewPageWindowAdapter > pAdapter = pXView->findWindow(xContainer);
2978
0
    if ( pAdapter.is() )
2979
0
    {
2980
0
        const ::std::vector< Reference< runtime::XFormController > >& rControllerList = pAdapter->GetList();
2981
0
        ::std::vector < OUString >   aOriginalFilters;
2982
0
        ::std::vector < bool >       aOriginalApplyFlags;
2983
2984
0
        if (bSave)
2985
0
        {
2986
0
            for (const auto& rpController : rControllerList)
2987
0
            {
2988
                // remember the current filter settings in case we're going to reload the forms below (which may fail)
2989
0
                try
2990
0
                {
2991
0
                    Reference< XPropertySet > xFormAsSet(rpController->getModel(), UNO_QUERY);
2992
0
                    aOriginalFilters.push_back(::comphelper::getString(xFormAsSet->getPropertyValue(FM_PROP_FILTER)));
2993
0
                    aOriginalApplyFlags.push_back(::comphelper::getBOOL(xFormAsSet->getPropertyValue(FM_PROP_APPLYFILTER)));
2994
0
                }
2995
0
                catch(Exception&)
2996
0
                {
2997
0
                    OSL_FAIL("FmXFormShell::stopFiltering : could not get the original filter !");
2998
                    // put dummies into the arrays so the they have the right size
2999
3000
0
                    if (aOriginalFilters.size() == aOriginalApplyFlags.size())
3001
                        // the first getPropertyValue failed -> use two dummies
3002
0
                        aOriginalFilters.emplace_back( );
3003
0
                    aOriginalApplyFlags.push_back( false );
3004
0
                }
3005
0
                saveFilter(rpController);
3006
0
            }
3007
0
        }
3008
0
        for (const auto& rController : rControllerList)
3009
0
        {
3010
3011
0
            Reference< XModeSelector> xModeSelector(rController, UNO_QUERY);
3012
0
            if (xModeSelector.is())
3013
0
                xModeSelector->setMode( u"DataMode"_ustr );
3014
0
        }
3015
0
        if (bSave)  // execute the filter
3016
0
        {
3017
0
            const ::std::vector< Reference< runtime::XFormController > > & rControllers = pAdapter->GetList();
3018
0
            for (::std::vector< Reference< runtime::XFormController > > ::const_iterator j = rControllers.begin();
3019
0
                 j != rControllers.end(); ++j)
3020
0
            {
3021
0
                Reference< XLoadable> xReload((*j)->getModel(), UNO_QUERY);
3022
0
                if (!xReload.is())
3023
0
                    continue;
3024
0
                Reference< XPropertySet > xFormSet(xReload, UNO_QUERY);
3025
3026
0
                try
3027
0
                {
3028
0
                    xReload->reload();
3029
0
                }
3030
0
                catch(Exception&)
3031
0
                {
3032
0
                    TOOLS_WARN_EXCEPTION("svx.form", "");
3033
0
                }
3034
3035
0
                if (!isRowSetAlive(xFormSet))
3036
0
                {   // something went wrong -> restore the original state
3037
0
                    OUString sOriginalFilter = aOriginalFilters[ j - rControllers.begin() ];
3038
0
                    bool bOriginalApplyFlag = aOriginalApplyFlags[ j - rControllers.begin() ];
3039
0
                    try
3040
0
                    {
3041
0
                        xFormSet->setPropertyValue(FM_PROP_FILTER, Any(sOriginalFilter));
3042
0
                        xFormSet->setPropertyValue(FM_PROP_APPLYFILTER, Any(bOriginalApplyFlag));
3043
0
                        xReload->reload();
3044
0
                    }
3045
0
                    catch(const Exception&)
3046
0
                    {
3047
0
                        DBG_UNHANDLED_EXCEPTION("svx");
3048
0
                    }
3049
0
                }
3050
0
            }
3051
0
        }
3052
0
    }
3053
3054
0
    m_pShell->UIFeatureChanged();
3055
0
    m_pShell->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell);
3056
0
}
3057
3058
3059
void FmXFormShell::CreateExternalView_Lock()
3060
0
{
3061
0
    if (impl_checkDisposed_Lock())
3062
0
        return;
3063
3064
0
    DBG_ASSERT(m_xAttachedFrame.is(), "FmXFormShell::CreateExternalView : no frame !");
3065
3066
    // the frame the external view is displayed in
3067
0
    bool bAlreadyExistent = m_xExternalViewController.is();
3068
0
    Reference< css::frame::XFrame> xExternalViewFrame;
3069
3070
0
    Reference<runtime::XFormController> xCurrentNavController(getNavController_Lock());
3071
        // the creation of the "partwindow" may cause a deactivate of the document which will result in our nav controller to be set to NULL
3072
3073
    // _first_ check if we have any valid fields we can use for the grid view
3074
    // FS - 21.10.99 - 69219
3075
0
    {
3076
0
        FmXBoundFormFieldIterator aModelIterator(xCurrentNavController->getModel());
3077
0
        bool bHaveUsableControls = false;
3078
0
        for (;;)
3079
0
        {
3080
0
            Reference< XPropertySet> xCurrentModelSet(aModelIterator.Next(), UNO_QUERY);
3081
0
            if (!xCurrentModelSet.is())
3082
0
                break;
3083
            // the FmXBoundFormFieldIterator only supplies controls with a valid control source
3084
            // so we just have to check the field type
3085
0
            sal_Int16 nClassId = ::comphelper::getINT16(xCurrentModelSet->getPropertyValue(FM_PROP_CLASSID));
3086
0
            switch (nClassId)
3087
0
            {
3088
0
                case FormComponentType::IMAGECONTROL:
3089
0
                case FormComponentType::CONTROL:
3090
0
                    continue;
3091
0
            }
3092
0
            bHaveUsableControls = true;
3093
0
            break;
3094
0
        }
3095
3096
0
        if (!bHaveUsableControls)
3097
0
        {
3098
0
            std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
3099
0
                                                                     VclMessageType::Warning, VclButtonsType::Ok,
3100
0
                                                                     SvxResId(RID_STR_NOCONTROLS_FOR_EXTERNALDISPLAY)));
3101
0
            xBox->run();
3102
0
            return;
3103
0
        }
3104
0
    }
3105
3106
    // load the component for external form views
3107
0
    if (!bAlreadyExistent)
3108
0
    {
3109
0
        OUString sFrameName(u"_beamer"_ustr);
3110
0
        URL aWantToDispatch;
3111
0
        aWantToDispatch.Complete = FMURL_COMPONENT_FORMGRIDVIEW;
3112
3113
0
        Reference< css::frame::XDispatchProvider> xProv(m_xAttachedFrame, UNO_QUERY);
3114
0
        Reference< css::frame::XDispatch> xDisp;
3115
0
        if (xProv.is())
3116
0
            xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName,
3117
0
                                         css::frame::FrameSearchFlag::CHILDREN | css::frame::FrameSearchFlag::CREATE);
3118
0
        if (xDisp.is())
3119
0
        {
3120
0
            xDisp->dispatch(aWantToDispatch, Sequence< PropertyValue>());
3121
0
        }
3122
3123
        // with this the component should be loaded, now search the frame where it resides in
3124
0
        xExternalViewFrame = m_xAttachedFrame->findFrame(sFrameName, css::frame::FrameSearchFlag::CHILDREN);
3125
0
        if (xExternalViewFrame.is())
3126
0
        {
3127
0
            m_xExternalViewController = xExternalViewFrame->getController();
3128
0
            if (m_xExternalViewController.is())
3129
0
                m_xExternalViewController->addEventListener(static_cast<XEventListener*>(static_cast<XPropertyChangeListener*>(this)));
3130
0
        }
3131
0
    }
3132
0
    else
3133
0
    {
3134
0
        xExternalViewFrame = m_xExternalViewController->getFrame();
3135
0
        Reference< css::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY);
3136
3137
        // if we display the active form we interpret the slot as "remove it"
3138
0
        Reference< XForm> xCurrentModel(xCurrentNavController->getModel(), UNO_QUERY);
3139
0
        if ((xCurrentModel == m_xExternalDisplayedForm) || (getInternalForm_Lock(xCurrentModel) == m_xExternalDisplayedForm))
3140
0
        {
3141
0
            if (m_xExternalViewController == getActiveController_Lock())
3142
0
            {
3143
0
                Reference< runtime::XFormController > xAsFormController( m_xExternalViewController, UNO_QUERY );
3144
0
                ControllerFeatures aHelper( xAsFormController );
3145
0
                (void)aHelper->commitCurrentControl();
3146
0
            }
3147
3148
0
            Reference< runtime::XFormController > xNewController(m_xExtViewTriggerController);
3149
0
            CloseExternalFormViewer_Lock();
3150
0
            setActiveController_Lock(xNewController);
3151
0
            return;
3152
0
        }
3153
3154
0
        URL aClearURL;
3155
0
        aClearURL.Complete = FMURL_GRIDVIEW_CLEARVIEW;
3156
3157
0
        Reference< css::frame::XDispatch> xClear( xCommLink->queryDispatch(aClearURL, OUString(), 0));
3158
0
        if (xClear.is())
3159
0
            xClear->dispatch(aClearURL, Sequence< PropertyValue>());
3160
0
    }
3161
3162
    // TODO: We need an interceptor at the xSupplier, which forwards all queryDispatch requests to the FormController
3163
    // instance for which this "external view" was triggered
3164
3165
    // get the dispatch interface of the frame so we can communicate (interceptable) with the controller
3166
0
    Reference< css::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY);
3167
3168
0
    if (m_xExternalViewController.is())
3169
0
    {
3170
0
        DBG_ASSERT(xCommLink.is(), "FmXFormShell::CreateExternalView : the component doesn't have the necessary interfaces !");
3171
        // collect the dispatchers we will need
3172
0
        URL aAddColumnURL;
3173
0
        aAddColumnURL.Complete = FMURL_GRIDVIEW_ADDCOLUMN;
3174
0
        Reference< css::frame::XDispatch> xAddColumnDispatch( xCommLink->queryDispatch(aAddColumnURL, OUString(), 0));
3175
0
        URL aAttachURL;
3176
0
        aAttachURL.Complete = FMURL_GRIDVIEW_ATTACHTOFORM;
3177
0
        Reference< css::frame::XDispatch> xAttachDispatch( xCommLink->queryDispatch(aAttachURL, OUString(), 0));
3178
3179
0
        if (xAddColumnDispatch.is() && xAttachDispatch.is())
3180
0
        {
3181
0
            DBG_ASSERT(xCurrentNavController.is(), "FmXFormShell::CreateExternalView : invalid call : have no nav controller !");
3182
            // first : dispatch the descriptions for the columns to add
3183
0
            sal_Int16 nAddedColumns = 0;
3184
3185
            // for radio buttons we need some special structures
3186
0
            typedef std::map< OUString, Sequence< OUString> > MapUString2UstringSeq;
3187
0
            typedef std::map< OUString, OUString > FmMapUString2UString;
3188
0
            typedef std::map< OUString, sal_Int16 > FmMapUString2Int16;
3189
3190
0
            MapUString2UstringSeq   aRadioValueLists;
3191
0
            MapUString2UstringSeq   aRadioListSources;
3192
0
            FmMapUString2UString    aRadioControlSources;
3193
0
            FmMapUString2Int16      aRadioPositions;
3194
3195
0
            FmXBoundFormFieldIterator aModelIterator(xCurrentNavController->getModel());
3196
0
            OUString sColumnType,aGroupName,sControlSource;
3197
0
            Sequence< Property> aProps;
3198
0
            for (;;)
3199
0
            {
3200
0
                Reference< XPropertySet> xCurrentModelSet(aModelIterator.Next(), UNO_QUERY);
3201
0
                if (!xCurrentModelSet.is())
3202
0
                    break;
3203
0
                OSL_ENSURE(xCurrentModelSet.is(),"xCurrentModelSet is null!");
3204
                // create a description of the column to be created
3205
                // first : determine its type
3206
3207
0
                sal_Int16 nClassId = ::comphelper::getINT16(xCurrentModelSet->getPropertyValue(FM_PROP_CLASSID));
3208
0
                switch (nClassId)
3209
0
                {
3210
0
                    case FormComponentType::RADIOBUTTON:
3211
0
                    {
3212
                        // get the label of the button (this is the access key for our structures)
3213
0
                        aGroupName = getLabelName(xCurrentModelSet);
3214
3215
                        // add the reference value of the radio button to the list source sequence
3216
0
                        Sequence< OUString>& aThisGroupLabels = aRadioListSources[aGroupName];
3217
0
                        sal_Int32 nNewSizeL = aThisGroupLabels.getLength() + 1;
3218
0
                        aThisGroupLabels.realloc(nNewSizeL);
3219
0
                        aThisGroupLabels.getArray()[nNewSizeL - 1] = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_REFVALUE));
3220
3221
                        // add the label to the value list sequence
3222
0
                        Sequence< OUString>& aThisGroupControlSources = aRadioValueLists[aGroupName];
3223
0
                        sal_Int32 nNewSizeC = aThisGroupControlSources.getLength() + 1;
3224
0
                        aThisGroupControlSources.realloc(nNewSizeC);
3225
0
                        aThisGroupControlSources.getArray()[nNewSizeC - 1] = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_LABEL));
3226
3227
                        // remember the controls source of the radio group
3228
0
                        sControlSource = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_CONTROLSOURCE));
3229
0
                        if (aRadioControlSources.find(aGroupName) == aRadioControlSources.end())
3230
0
                            aRadioControlSources[aGroupName] = sControlSource;
3231
#ifdef DBG_UTIL
3232
                        else
3233
                            DBG_ASSERT(aRadioControlSources[aGroupName] == sControlSource,
3234
                            "FmXFormShell::CreateExternalView : inconsistent radio buttons detected !");
3235
                            // (radio buttons with the same name should have the same control source)
3236
#endif
3237
                        // remember the position within the columns
3238
0
                        if (aRadioPositions.find(aGroupName) == aRadioPositions.end())
3239
0
                            aRadioPositions[aGroupName] = nAddedColumns;
3240
3241
                        // any further handling is done below
3242
0
                    }
3243
0
                    continue;
3244
3245
0
                    case FormComponentType::IMAGECONTROL:
3246
0
                    case FormComponentType::CONTROL:
3247
                        // no grid columns for these types (though they have a control source)
3248
0
                        continue;
3249
0
                    case FormComponentType::CHECKBOX:
3250
0
                        sColumnType = FM_COL_CHECKBOX; break;
3251
0
                    case FormComponentType::LISTBOX:
3252
0
                        sColumnType = FM_COL_LISTBOX; break;
3253
0
                    case FormComponentType::COMBOBOX:
3254
0
                        sColumnType = FM_COL_COMBOBOX; break;
3255
0
                    case FormComponentType::DATEFIELD:
3256
0
                        sColumnType = FM_COL_DATEFIELD; break;
3257
0
                    case FormComponentType::TIMEFIELD:
3258
0
                        sColumnType = FM_COL_TIMEFIELD; break;
3259
0
                    case FormComponentType::NUMERICFIELD:
3260
0
                        sColumnType = FM_COL_NUMERICFIELD; break;
3261
0
                    case FormComponentType::CURRENCYFIELD:
3262
0
                        sColumnType = FM_COL_CURRENCYFIELD; break;
3263
0
                    case FormComponentType::PATTERNFIELD:
3264
0
                        sColumnType = FM_COL_PATTERNFIELD; break;
3265
3266
0
                    case FormComponentType::TEXTFIELD:
3267
0
                        {
3268
0
                            sColumnType = FM_COL_TEXTFIELD;
3269
                            // we know at least two different controls which are TextFields : the basic edit field and the formatted
3270
                            // field. we distinguish them by their service name
3271
0
                            Reference< lang::XServiceInfo> xInfo(xCurrentModelSet, UNO_QUERY);
3272
0
                            if (xInfo.is())
3273
0
                            {
3274
0
                                SdrObjKind nObjectType = getControlTypeByObject(xInfo);
3275
0
                                if (SdrObjKind::FormFormattedField == nObjectType)
3276
0
                                    sColumnType = FM_COL_FORMATTEDFIELD;
3277
0
                            }
3278
0
                        }
3279
0
                        break;
3280
0
                    default:
3281
0
                        sColumnType = FM_COL_TEXTFIELD; break;
3282
0
                }
3283
3284
0
                const sal_Int16 nDispatchArgs = 3;
3285
0
                Sequence< PropertyValue> aDispatchArgs(nDispatchArgs);
3286
0
                PropertyValue* pDispatchArgs = aDispatchArgs.getArray();
3287
3288
                // properties describing "meta data" about the column
3289
                // the type
3290
0
                pDispatchArgs->Name = FMARG_ADDCOL_COLUMNTYPE;
3291
0
                pDispatchArgs->Value <<= sColumnType;
3292
0
                ++pDispatchArgs;
3293
3294
                // the pos : append the col
3295
0
                pDispatchArgs->Name = FMARG_ADDCOL_COLUMNPOS;
3296
0
                pDispatchArgs->Value <<= nAddedColumns;
3297
0
                ++pDispatchArgs;
3298
3299
                // the properties to forward to the new column
3300
0
                Sequence< PropertyValue> aColumnProps(1);
3301
0
                PropertyValue* pColumnProps = aColumnProps.getArray();
3302
3303
                // the label
3304
0
                pColumnProps->Name = FM_PROP_LABEL;
3305
0
                pColumnProps->Value <<= getLabelName(xCurrentModelSet);
3306
0
                ++pColumnProps;
3307
3308
                // for all other props : transfer them
3309
0
                Reference< XPropertySetInfo> xControlModelInfo( xCurrentModelSet->getPropertySetInfo());
3310
0
                DBG_ASSERT(xControlModelInfo.is(), "FmXFormShell::CreateExternalView : the control model has no property info ! This will crash !");
3311
0
                aProps = xControlModelInfo->getProperties();
3312
3313
                // realloc the control description sequence
3314
0
                sal_Int32 nExistentDescs = pColumnProps - aColumnProps.getArray();
3315
0
                aColumnProps.realloc(nExistentDescs + aProps.getLength());
3316
0
                pColumnProps = aColumnProps.getArray() + nExistentDescs;
3317
3318
0
                for (const Property& rProp : aProps)
3319
0
                {
3320
0
                    if (rProp.Name == FM_PROP_LABEL)
3321
                        // already set
3322
0
                        continue;
3323
0
                    if (rProp.Name == FM_PROP_DEFAULTCONTROL)
3324
                        // allow the column's own "default control"
3325
0
                        continue;
3326
0
                    if (rProp.Attributes & PropertyAttribute::READONLY)
3327
                        // assume that properties which are readonly for the control are ro for the column to be created, too
3328
0
                        continue;
3329
3330
0
                    pColumnProps->Name = rProp.Name;
3331
0
                    pColumnProps->Value = xCurrentModelSet->getPropertyValue(rProp.Name);
3332
0
                    ++pColumnProps;
3333
0
                }
3334
0
                aColumnProps.realloc(pColumnProps - aColumnProps.getArray());
3335
3336
                // columns props are a dispatch argument
3337
0
                pDispatchArgs->Name = "ColumnProperties"; // TODO : fmurl.*
3338
0
                pDispatchArgs->Value <<= aColumnProps;
3339
0
                ++pDispatchArgs;
3340
0
                DBG_ASSERT(nDispatchArgs == (pDispatchArgs - aDispatchArgs.getConstArray()),
3341
0
                    "FmXFormShell::CreateExternalView : forgot to adjust nDispatchArgs ?");
3342
3343
                // dispatch the "add column"
3344
0
                xAddColumnDispatch->dispatch(aAddColumnURL, aDispatchArgs);
3345
0
                ++nAddedColumns;
3346
0
            }
3347
3348
            // now for the radio button handling
3349
0
            sal_Int16 nOffset(0);
3350
            // properties describing the "direct" column properties
3351
0
            const sal_Int16 nListBoxDescription = 6;
3352
0
            Sequence< PropertyValue> aListBoxDescription(nListBoxDescription);
3353
0
            for (const auto& rCtrlSource : aRadioControlSources)
3354
0
            {
3355
0
                PropertyValue* pListBoxDescription = aListBoxDescription.getArray();
3356
                // label
3357
0
                pListBoxDescription->Name = FM_PROP_LABEL;
3358
0
                pListBoxDescription->Value <<= rCtrlSource.first;
3359
0
                ++pListBoxDescription;
3360
3361
                // control source
3362
0
                pListBoxDescription->Name = FM_PROP_CONTROLSOURCE;
3363
0
                pListBoxDescription->Value <<= rCtrlSource.second;
3364
0
                ++pListBoxDescription;
3365
3366
                // bound column
3367
0
                pListBoxDescription->Name = FM_PROP_BOUNDCOLUMN;
3368
0
                pListBoxDescription->Value <<= sal_Int16(1);
3369
0
                ++pListBoxDescription;
3370
3371
                // content type
3372
0
                pListBoxDescription->Name = FM_PROP_LISTSOURCETYPE;
3373
0
                pListBoxDescription->Value <<= ListSourceType_VALUELIST;
3374
0
                ++pListBoxDescription;
3375
3376
                // list source
3377
0
                MapUString2UstringSeq::const_iterator aCurrentListSource = aRadioListSources.find(rCtrlSource.first);
3378
0
                assert(aCurrentListSource != aRadioListSources.end() &&
3379
0
                    "FmXFormShell::CreateExternalView : inconsistent radio descriptions !");
3380
0
                pListBoxDescription->Name = FM_PROP_LISTSOURCE;
3381
0
                pListBoxDescription->Value <<= (*aCurrentListSource).second;
3382
0
                ++pListBoxDescription;
3383
3384
                // value list
3385
0
                MapUString2UstringSeq::const_iterator aCurrentValueList = aRadioValueLists.find(rCtrlSource.first);
3386
0
                assert(aCurrentValueList != aRadioValueLists.end() && "FmXFormShell::CreateExternalView : inconsistent radio descriptions !");
3387
0
                pListBoxDescription->Name = FM_PROP_STRINGITEMLIST;
3388
0
                pListBoxDescription->Value <<= (*aCurrentValueList).second;
3389
0
                ++pListBoxDescription;
3390
3391
0
                DBG_ASSERT(nListBoxDescription == (pListBoxDescription - aListBoxDescription.getConstArray()),
3392
0
                    "FmXFormShell::CreateExternalView : forgot to adjust nListBoxDescription ?");
3393
3394
                // properties describing the column "meta data"
3395
0
                const sal_Int16 nDispatchArgs = 3;
3396
0
                Sequence< PropertyValue> aDispatchArgs(nDispatchArgs);
3397
0
                PropertyValue* pDispatchArgs = aDispatchArgs.getArray();
3398
3399
                // column type : listbox
3400
0
                pDispatchArgs->Name = FMARG_ADDCOL_COLUMNTYPE;
3401
0
                pDispatchArgs->Value <<= u"" FM_COL_LISTBOX ""_ustr;
3402
//              pDispatchArgs->Value <<= (OUString)FM_COL_LISTBOX;
3403
0
                ++pDispatchArgs;
3404
3405
                // column position
3406
0
                pDispatchArgs->Name = FMARG_ADDCOL_COLUMNPOS;
3407
0
                FmMapUString2Int16::const_iterator aOffset = aRadioPositions.find(rCtrlSource.first);
3408
0
                assert(aOffset != aRadioPositions.end() && "FmXFormShell::CreateExternalView : inconsistent radio descriptions !");
3409
0
                sal_Int16 nPosition = (*aOffset).second;
3410
0
                nPosition = nPosition + nOffset;
3411
                    // we already inserted nOffset additional columns...
3412
0
                pDispatchArgs->Value <<= nPosition;
3413
0
                ++pDispatchArgs;
3414
3415
                // the
3416
0
                pDispatchArgs->Name = "ColumnProperties"; // TODO : fmurl.*
3417
0
                pDispatchArgs->Value <<= aListBoxDescription;
3418
0
                ++pDispatchArgs;
3419
0
                DBG_ASSERT(nDispatchArgs == (pDispatchArgs - aDispatchArgs.getConstArray()),
3420
0
                    "FmXFormShell::CreateExternalView : forgot to adjust nDispatchArgs ?");
3421
3422
                // dispatch the "add column"
3423
0
                xAddColumnDispatch->dispatch(aAddColumnURL, aDispatchArgs);
3424
0
                ++nAddedColumns;
3425
0
                ++nOffset;
3426
0
            }
3427
3428
3429
0
            DBG_ASSERT(nAddedColumns > 0, "FmXFormShell::CreateExternalView : no controls (inconsistent) !");
3430
                // we should have checked if we have any usable controls (see above).
3431
3432
            // "load" the "form" of the external view
3433
0
            PropertyValue aArg;
3434
0
            aArg.Name = FMARG_ATTACHTO_MASTERFORM;
3435
0
            Reference< XResultSet> xForm(xCurrentNavController->getModel(), UNO_QUERY);
3436
0
            aArg.Value <<= xForm;
3437
3438
0
            m_xExternalDisplayedForm = std::move(xForm);
3439
                // do this before dispatching the "attach" command, as the attach may result in a call to our queryDispatch (for the FormSlots)
3440
                // which needs the m_xExternalDisplayedForm
3441
3442
0
            xAttachDispatch->dispatch(aAttachURL, Sequence< PropertyValue>(&aArg, 1));
3443
3444
0
            m_xExtViewTriggerController = std::move(xCurrentNavController);
3445
3446
            // we want to know modifications done in the external view
3447
            // if the external controller is a XFormController we can use all our default handlings for it
3448
0
            Reference< runtime::XFormController > xFormController( m_xExternalViewController, UNO_QUERY );
3449
0
            OSL_ENSURE( xFormController.is(), "FmXFormShell::CreateExternalView:: invalid external view controller!" );
3450
0
            if (xFormController.is())
3451
0
                xFormController->addActivateListener(static_cast<XFormControllerListener*>(this));
3452
0
        }
3453
0
    }
3454
#ifdef DBG_UTIL
3455
    else
3456
    {
3457
        OSL_FAIL("FmXFormShell::CreateExternalView : could not create the external form view !");
3458
    }
3459
#endif
3460
0
    InvalidateSlot_Lock(SID_FM_VIEW_AS_GRID, false);
3461
0
}
3462
3463
3464
void FmXFormShell::implAdjustConfigCache_Lock()
3465
8.87k
{
3466
8.87k
    const bool bFuzzing(comphelper::IsFuzzing());
3467
8.87k
    if (bFuzzing)
3468
8.87k
        return;
3469
3470
    // get (cache) the wizard usage flag
3471
0
    Sequence< OUString > aNames { u"FormControlPilotsEnabled"_ustr };
3472
0
    Sequence< Any > aFlags = GetProperties(aNames);
3473
0
    if (1 == aFlags.getLength())
3474
0
        m_bUseWizards = ::cppu::any2bool(aFlags[0]);
3475
0
}
3476
3477
3478
void FmXFormShell::Notify( const css::uno::Sequence< OUString >& _rPropertyNames)
3479
0
{
3480
0
    DBG_TESTSOLARMUTEX();
3481
0
    if (impl_checkDisposed_Lock())
3482
0
        return;
3483
3484
0
    for (const OUString& rName : _rPropertyNames)
3485
0
        if (rName == "FormControlPilotsEnabled")
3486
0
        {
3487
0
            implAdjustConfigCache_Lock();
3488
0
            InvalidateSlot_Lock(SID_FM_USE_WIZARDS, true);
3489
0
        }
3490
0
}
3491
3492
void FmXFormShell::ImplCommit()
3493
0
{
3494
0
}
3495
3496
3497
void FmXFormShell::SetWizardUsing_Lock(bool _bUseThem)
3498
0
{
3499
0
    m_bUseWizards = _bUseThem;
3500
3501
0
    Sequence< OUString > aNames { u"FormControlPilotsEnabled"_ustr };
3502
0
    Sequence< Any > aValues{ Any(m_bUseWizards) };
3503
0
    PutProperties(aNames, aValues);
3504
0
}
3505
3506
3507
void FmXFormShell::viewDeactivated_Lock(FmFormView& _rCurrentView, bool _bDeactivateController)
3508
8.87k
{
3509
3510
8.87k
    if ( _rCurrentView.GetImpl() && !_rCurrentView.IsDesignMode() )
3511
32
    {
3512
32
        _rCurrentView.GetImpl()->Deactivate( _bDeactivateController );
3513
32
    }
3514
3515
    // if we have an async load operation pending for the 0-th page for this view,
3516
    // we need to cancel this
3517
8.87k
    if (FmFormPage* pPage = _rCurrentView.GetCurPage())
3518
8.87k
    {
3519
        // move all events from our queue to a new one, omit the events for the deactivated
3520
        // page
3521
8.87k
        ::std::queue< FmLoadAction > aNewEvents;
3522
8.91k
        while ( !m_aLoadingPages.empty() )
3523
32
        {
3524
32
            FmLoadAction aAction = m_aLoadingPages.front();
3525
32
            m_aLoadingPages.pop();
3526
32
            if ( pPage != aAction.pPage )
3527
0
            {
3528
0
                aNewEvents.push( aAction );
3529
0
            }
3530
32
            else
3531
32
            {
3532
32
                Application::RemoveUserEvent( aAction.nEventId );
3533
32
            }
3534
32
        }
3535
8.87k
        m_aLoadingPages = std::move(aNewEvents);
3536
3537
        // remove callbacks at the page
3538
8.87k
        pPage->GetImpl().SetFormsCreationHdl( Link<FmFormPageImpl&,void>() );
3539
8.87k
    }
3540
8.87k
    UpdateForms_Lock(true);
3541
8.87k
}
3542
3543
3544
IMPL_LINK_NOARG( FmXFormShell, OnFirstTimeActivation_Lock, void*, void )
3545
0
{
3546
0
    if (impl_checkDisposed_Lock())
3547
0
        return;
3548
3549
0
    m_nActivationEvent = nullptr;
3550
0
    SfxObjectShell* pDocument = m_pShell->GetObjectShell();
3551
3552
0
    if  ( pDocument && !pDocument->HasName() )
3553
0
    {
3554
0
        if (isEnhancedForm_Lock())
3555
0
        {
3556
            // show the data navigator
3557
0
            if ( !m_pShell->GetViewShell()->GetViewFrame().HasChildWindow( SID_FM_SHOW_DATANAVIGATOR ) )
3558
0
                m_pShell->GetViewShell()->GetViewFrame().ToggleChildWindow( SID_FM_SHOW_DATANAVIGATOR );
3559
0
        }
3560
0
    }
3561
0
}
3562
3563
3564
IMPL_LINK_NOARG( FmXFormShell, OnFormsCreated_Lock, FmFormPageImpl&, void )
3565
0
{
3566
0
    UpdateForms_Lock(true);
3567
0
}
3568
3569
3570
void FmXFormShell::viewActivated_Lock(FmFormView& _rCurrentView, bool _bSyncAction)
3571
8.87k
{
3572
8.87k
    FmFormPage* pPage = _rCurrentView.GetCurPage();
3573
3574
    // activate our view if we are activated ourself
3575
    // FS - 30.06.99 - 67308
3576
8.87k
    if ( _rCurrentView.GetImpl() && !_rCurrentView.IsDesignMode() )
3577
32
    {
3578
        // load forms for the page the current view belongs to
3579
32
        if ( pPage )
3580
32
        {
3581
32
            if ( !pPage->GetImpl().hasEverBeenActivated() )
3582
32
                loadForms_Lock(pPage, LoadFormsFlags::Load
3583
32
                                      | (_bSyncAction ? LoadFormsFlags::Sync
3584
32
                                                      : LoadFormsFlags::Async));
3585
32
            pPage->GetImpl().setHasBeenActivated( );
3586
32
        }
3587
3588
        // first-time initializations for the views
3589
32
        if ( !_rCurrentView.GetImpl()->hasEverBeenActivated( ) )
3590
32
        {
3591
32
            auto* pFormModel = dynamic_cast<FmFormModel*>(&_rCurrentView.GetModel());
3592
32
            _rCurrentView.GetImpl()->onFirstViewActivation(pFormModel);
3593
32
            _rCurrentView.GetImpl()->setHasBeenActivated();
3594
32
        }
3595
3596
        // activate the current view
3597
32
        _rCurrentView.GetImpl()->Activate( _bSyncAction );
3598
32
    }
3599
3600
    // set callbacks at the page
3601
8.87k
    if ( pPage )
3602
8.87k
    {
3603
8.87k
        pPage->GetImpl().SetFormsCreationHdl(LINK(this, FmXFormShell, OnFormsCreated_Lock));
3604
8.87k
    }
3605
3606
8.87k
    UpdateForms_Lock(true);
3607
3608
8.87k
    if ( m_bFirstActivation )
3609
8.87k
    {
3610
8.87k
        m_nActivationEvent = Application::PostUserEvent(LINK(this, FmXFormShell, OnFirstTimeActivation_Lock));
3611
8.87k
        m_bFirstActivation = false;
3612
8.87k
    }
3613
3614
    // find a default "current form", if there is none, yet
3615
    // #i88186# / 2008-04-12 / frank.schoenheit@sun.com
3616
8.87k
    impl_defaultCurrentForm_nothrow_Lock();
3617
8.87k
}
3618
3619
3620
void FmXFormShell::impl_defaultCurrentForm_nothrow_Lock()
3621
8.87k
{
3622
8.87k
    if (impl_checkDisposed_Lock())
3623
0
        return;
3624
3625
8.87k
    if ( m_xCurrentForm.is() )
3626
        // no action required
3627
0
        return;
3628
3629
8.87k
    FmFormView* pFormView = m_pShell->GetFormView();
3630
8.87k
    FmFormPage* pPage = pFormView ? pFormView->GetCurPage() : nullptr;
3631
8.87k
    if ( !pPage )
3632
0
        return;
3633
3634
8.87k
    try
3635
8.87k
    {
3636
8.87k
        Reference< XIndexAccess > xForms = pPage->GetForms( false );
3637
8.87k
        if ( !xForms.is() || !xForms->hasElements() )
3638
8.87k
            return;
3639
3640
0
        Reference< XForm > xNewCurrentForm( xForms->getByIndex(0), UNO_QUERY_THROW );
3641
0
        impl_updateCurrentForm_Lock(xNewCurrentForm);
3642
0
    }
3643
8.87k
    catch( const Exception& )
3644
8.87k
    {
3645
0
        DBG_UNHANDLED_EXCEPTION("svx");
3646
0
    }
3647
8.87k
}
3648
3649
3650
void FmXFormShell::smartControlReset( const Reference< XIndexAccess >& _rxModels )
3651
0
{
3652
0
    if (!_rxModels.is())
3653
0
    {
3654
0
        OSL_FAIL("FmXFormShell::smartControlReset: invalid container!");
3655
0
        return;
3656
0
    }
3657
3658
0
    sal_Int32 nCount = _rxModels->getCount();
3659
0
    Reference< XPropertySet > xCurrent;
3660
0
    Reference< XPropertySetInfo > xCurrentInfo;
3661
0
    Reference< XPropertySet > xBoundField;
3662
3663
0
    for (sal_Int32 i=0; i<nCount; ++i)
3664
0
    {
3665
0
        _rxModels->getByIndex(i) >>= xCurrent;
3666
0
        if (xCurrent.is())
3667
0
            xCurrentInfo = xCurrent->getPropertySetInfo();
3668
0
        else
3669
0
            xCurrentInfo.clear();
3670
0
        if (!xCurrentInfo.is())
3671
0
            continue;
3672
3673
0
        if (xCurrentInfo->hasPropertyByName(FM_PROP_CLASSID))
3674
0
        {   // it's a control model
3675
3676
            // check if this control is bound to a living database field
3677
0
            if (xCurrentInfo->hasPropertyByName(FM_PROP_BOUNDFIELD))
3678
0
                xCurrent->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xBoundField;
3679
0
            else
3680
0
                xBoundField.clear();
3681
3682
            // reset only if it's *not* bound
3683
0
            bool bReset = !xBoundField.is();
3684
3685
            // and additionally, check if it has an external value binding
3686
0
            Reference< XBindableValue > xBindable( xCurrent, UNO_QUERY );
3687
0
            if ( xBindable.is() && xBindable->getValueBinding().is() )
3688
0
                bReset = false;
3689
3690
0
            if ( bReset )
3691
0
            {
3692
0
                Reference< XReset > xControlReset( xCurrent, UNO_QUERY );
3693
0
                if ( xControlReset.is() )
3694
0
                    xControlReset->reset();
3695
0
            }
3696
0
        }
3697
0
        else
3698
0
        {
3699
0
            Reference< XIndexAccess > xContainer(xCurrent, UNO_QUERY);
3700
0
            if (xContainer.is())
3701
0
                smartControlReset(xContainer);
3702
0
        }
3703
0
    }
3704
0
}
3705
3706
3707
IMPL_LINK_NOARG( FmXFormShell, OnLoadForms_Lock, void*, void )
3708
0
{
3709
0
    FmLoadAction aAction = m_aLoadingPages.front();
3710
0
    m_aLoadingPages.pop();
3711
3712
0
    loadForms_Lock(aAction.pPage, aAction.nFlags & ~LoadFormsFlags::Async);
3713
0
}
3714
3715
3716
namespace
3717
{
3718
    bool lcl_isLoadable( const Reference< XInterface >& _rxLoadable )
3719
0
    {
3720
        // determines whether a form should be loaded or not
3721
        // if there is no datasource or connection there is no reason to load a form
3722
0
        Reference< XPropertySet > xSet( _rxLoadable, UNO_QUERY );
3723
0
        if ( !xSet.is() )
3724
0
            return false;
3725
0
        try
3726
0
        {
3727
0
            Reference< XConnection > xConn;
3728
0
            if ( isEmbeddedInDatabase( _rxLoadable, xConn ) )
3729
0
                return true;
3730
3731
            // is there already an active connection
3732
0
            xSet->getPropertyValue(FM_PROP_ACTIVE_CONNECTION) >>= xConn;
3733
0
            if ( xConn.is() )
3734
0
                return true;
3735
3736
0
            OUString sPropertyValue;
3737
0
            OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DATASOURCE ) >>= sPropertyValue );
3738
0
            if ( !sPropertyValue.isEmpty() )
3739
0
                return true;
3740
3741
0
            OSL_VERIFY( xSet->getPropertyValue( FM_PROP_URL ) >>= sPropertyValue );
3742
0
            if ( !sPropertyValue.isEmpty() )
3743
0
                return true;
3744
0
        }
3745
0
        catch(const Exception&)
3746
0
        {
3747
0
            DBG_UNHANDLED_EXCEPTION("svx");
3748
0
        }
3749
0
        return false;
3750
0
    }
3751
}
3752
3753
3754
void FmXFormShell::loadForms_Lock(FmFormPage* _pPage, const LoadFormsFlags _nBehaviour /* LoadFormsFlags::Load | LoadFormsFlags::Sync */)
3755
32
{
3756
32
    DBG_ASSERT( ( _nBehaviour & ( LoadFormsFlags::Async | LoadFormsFlags::Unload ) )  != ( LoadFormsFlags::Async | LoadFormsFlags::Unload ),
3757
32
        "FmXFormShell::loadForms: async loading not supported - this will heavily fail!" );
3758
3759
32
    if ( _nBehaviour & LoadFormsFlags::Async )
3760
32
    {
3761
32
        m_aLoadingPages.push( FmLoadAction(
3762
32
            _pPage,
3763
32
            _nBehaviour,
3764
32
            Application::PostUserEvent(LINK(this, FmXFormShell, OnLoadForms_Lock), _pPage)
3765
32
        ) );
3766
32
        return;
3767
32
    }
3768
3769
0
    DBG_ASSERT( _pPage, "FmXFormShell::loadForms: invalid page!" );
3770
0
    if ( !_pPage )
3771
0
        return;
3772
3773
    // lock the undo env so the forms can change non-transient properties while loading
3774
    // (without this my doc's modified flag would be set)
3775
0
    FmFormModel& rFmFormModel(dynamic_cast< FmFormModel& >(_pPage->getSdrModelFromSdrPage()));
3776
0
    rFmFormModel.GetUndoEnv().Lock();
3777
3778
    // load all forms
3779
0
    Reference< XIndexAccess >  xForms = _pPage->GetForms( false );
3780
3781
0
    if ( xForms.is() )
3782
0
    {
3783
0
        Reference< XLoadable >  xForm;
3784
0
        for ( sal_Int32 j = 0, nCount = xForms->getCount(); j < nCount; ++j )
3785
0
        {
3786
0
            xForms->getByIndex( j ) >>= xForm;
3787
0
            bool bFormWasLoaded = false;
3788
            // a database form must be loaded for
3789
0
            try
3790
0
            {
3791
0
                if ( !( _nBehaviour & LoadFormsFlags::Unload ) )
3792
0
                {
3793
0
                    if ( lcl_isLoadable( xForm ) && !xForm->isLoaded() )
3794
0
                        xForm->load();
3795
0
                }
3796
0
                else
3797
0
                {
3798
0
                    if ( xForm->isLoaded() )
3799
0
                    {
3800
0
                        bFormWasLoaded = true;
3801
0
                        xForm->unload();
3802
0
                    }
3803
0
                }
3804
0
            }
3805
0
            catch( const Exception& )
3806
0
            {
3807
0
                DBG_UNHANDLED_EXCEPTION("svx");
3808
0
            }
3809
3810
            // reset the form if it was loaded
3811
0
            if ( bFormWasLoaded )
3812
0
            {
3813
0
                Reference< XIndexAccess > xContainer( xForm, UNO_QUERY );
3814
0
                DBG_ASSERT( xContainer.is(), "FmXFormShell::loadForms: the form is no container!" );
3815
0
                if ( xContainer.is() )
3816
0
                    smartControlReset( xContainer );
3817
0
            }
3818
0
        }
3819
0
    }
3820
3821
    // unlock the environment
3822
0
    rFmFormModel.GetUndoEnv().UnLock();
3823
0
}
3824
3825
3826
void FmXFormShell::ExecuteTextAttribute_Lock(SfxRequest& _rReq)
3827
0
{
3828
0
    DBG_TESTSOLARMUTEX();
3829
0
    m_pTextShell->ExecuteTextAttribute( _rReq );
3830
0
}
3831
3832
3833
void FmXFormShell::GetTextAttributeState_Lock(SfxItemSet& _rSet)
3834
0
{
3835
0
    DBG_TESTSOLARMUTEX();
3836
0
    m_pTextShell->GetTextAttributeState( _rSet );
3837
0
}
3838
3839
3840
bool FmXFormShell::IsActiveControl_Lock(bool _bCountRichTextOnly ) const
3841
34.2k
{
3842
34.2k
    DBG_TESTSOLARMUTEX();
3843
34.2k
    return m_pTextShell->IsActiveControl( _bCountRichTextOnly );
3844
34.2k
}
3845
3846
3847
void FmXFormShell::ForgetActiveControl_Lock()
3848
0
{
3849
0
    DBG_TESTSOLARMUTEX();
3850
0
    m_pTextShell->ForgetActiveControl();
3851
0
}
3852
3853
3854
void FmXFormShell::SetControlActivationHandler_Lock(const Link<LinkParamNone*,void>& _rHdl)
3855
8.87k
{
3856
8.87k
    DBG_TESTSOLARMUTEX();
3857
8.87k
    m_pTextShell->SetControlActivationHandler( _rHdl );
3858
8.87k
}
3859
3860
void FmXFormShell::handleShowPropertiesRequest_Lock()
3861
0
{
3862
0
    if (onlyControlsAreMarked_Lock())
3863
0
        ShowSelectionProperties_Lock( true );
3864
0
}
3865
3866
3867
void FmXFormShell::handleMouseButtonDown_Lock(const SdrViewEvent& _rViewEvent)
3868
0
{
3869
    // catch simple double clicks
3870
0
    if (_rViewEvent.mnMouseClicks == 2 && _rViewEvent.mnMouseCode == MOUSE_LEFT)
3871
0
    {
3872
0
        if ( _rViewEvent.meHit == SdrHitKind::MarkedObject )
3873
0
        {
3874
0
            if (onlyControlsAreMarked_Lock())
3875
0
                ShowSelectionProperties_Lock( true );
3876
0
        }
3877
0
    }
3878
0
}
3879
3880
3881
bool FmXFormShell::HasControlFocus_Lock() const
3882
0
{
3883
0
    bool bHasControlFocus = false;
3884
3885
0
    try
3886
0
    {
3887
0
        Reference<runtime::XFormController> xController(getActiveController_Lock());
3888
0
        Reference< XControl > xCurrentControl;
3889
0
        if ( xController.is() )
3890
0
            xCurrentControl.set( xController->getCurrentControl() );
3891
0
        if ( xCurrentControl.is() )
3892
0
        {
3893
0
            Reference< XWindow2 > xPeerWindow( xCurrentControl->getPeer(), UNO_QUERY_THROW );
3894
0
            bHasControlFocus = xPeerWindow->hasFocus();
3895
0
        }
3896
0
    }
3897
0
    catch( const Exception& )
3898
0
    {
3899
0
        DBG_UNHANDLED_EXCEPTION("svx");
3900
0
    }
3901
3902
0
    return bHasControlFocus;
3903
0
}
3904
3905
3906
SearchableControlIterator::SearchableControlIterator(Reference< XInterface> const & xStartingPoint)
3907
0
    :IndexAccessIterator(xStartingPoint)
3908
0
{
3909
0
}
3910
3911
3912
bool SearchableControlIterator::ShouldHandleElement(const Reference< XInterface>& xElement)
3913
0
{
3914
    // if the thing has a ControlSource and a BoundField property
3915
0
    Reference< XPropertySet> xProperties(xElement, UNO_QUERY);
3916
0
    if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xProperties) && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xProperties))
3917
0
    {
3918
        // and the BoundField is valid
3919
0
        Reference< XPropertySet> xField;
3920
0
        xProperties->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
3921
0
        if (xField.is())
3922
0
        {
3923
            // we take it
3924
0
            m_sCurrentValue = ::comphelper::getString(xProperties->getPropertyValue(FM_PROP_CONTROLSOURCE));
3925
0
            return true;
3926
0
        }
3927
0
    }
3928
3929
    // if it is a grid control
3930
0
    if (::comphelper::hasProperty(FM_PROP_CLASSID, xProperties))
3931
0
    {
3932
0
        Any aClassId( xProperties->getPropertyValue(FM_PROP_CLASSID) );
3933
0
        if (::comphelper::getINT16(aClassId) == FormComponentType::GRIDCONTROL)
3934
0
        {
3935
0
            m_sCurrentValue.clear();
3936
0
            return true;
3937
0
        }
3938
0
    }
3939
3940
0
    return false;
3941
0
}
3942
3943
3944
bool SearchableControlIterator::ShouldStepInto(const Reference< XInterface>& /*xContainer*/) const
3945
0
{
3946
0
    return true;
3947
0
}
3948
3949
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */