Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/form/navigatortreemodel.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 <svx/dialmgr.hxx>
21
#include <svx/fmshell.hxx>
22
#include <svx/fmmodel.hxx>
23
#include <svx/fmpage.hxx>
24
#include <svx/svditer.hxx>
25
#include <svx/svdogrp.hxx>
26
27
#include <fmprop.hxx>
28
29
#include <fmundo.hxx>
30
#include <fmexpl.hxx>
31
#include <svx/strings.hrc>
32
#include <fmshimp.hxx>
33
#include <fmobj.hxx>
34
#include <o3tl/safeint.hxx>
35
#include <sfx2/objsh.hxx>
36
#include <comphelper/diagnose_ex.hxx>
37
#include <com/sun/star/container/XContainer.hpp>
38
#include <comphelper/types.hxx>
39
40
41
namespace svxform
42
{
43
44
45
    using namespace ::com::sun::star::uno;
46
    using namespace ::com::sun::star::lang;
47
    using namespace ::com::sun::star::beans;
48
    using namespace ::com::sun::star::form;
49
    using namespace ::com::sun::star::container;
50
51
    OFormComponentObserver::OFormComponentObserver(NavigatorTreeModel* _pModel)
52
0
        :m_pNavModel(_pModel)
53
0
        ,m_nLocks(0)
54
0
        ,m_bCanUndo(true)
55
0
    {
56
0
    }
57
58
    // XPropertyChangeListener
59
60
    void SAL_CALL OFormComponentObserver::disposing(const EventObject& Source)
61
0
    {
62
0
        Remove( Source.Source );
63
0
    }
64
65
66
    void SAL_CALL OFormComponentObserver::propertyChange(const PropertyChangeEvent& evt)
67
0
    {
68
0
        if( !m_pNavModel ) return;
69
0
        if( evt.PropertyName != FM_PROP_NAME ) return;
70
71
0
        Reference< XFormComponent >  xFormComponent(evt.Source, UNO_QUERY);
72
0
        Reference< XForm >  xForm(evt.Source, UNO_QUERY);
73
74
0
        FmEntryData* pEntryData( nullptr );
75
0
        if( xForm.is() )
76
0
            pEntryData = m_pNavModel->FindData( xForm, m_pNavModel->GetRootList() );
77
0
        else if( xFormComponent.is() )
78
0
            pEntryData = m_pNavModel->FindData( xFormComponent, m_pNavModel->GetRootList() );
79
80
0
        if( pEntryData )
81
0
        {
82
0
            OUString aNewName =  ::comphelper::getString(evt.NewValue);
83
0
            pEntryData->SetText( aNewName );
84
0
            FmNavNameChangedHint aNameChangedHint( pEntryData, aNewName );
85
0
            m_pNavModel->Broadcast( aNameChangedHint );
86
0
        }
87
0
    }
88
89
    // XContainerListener
90
91
    void SAL_CALL OFormComponentObserver::elementInserted(const ContainerEvent& evt)
92
0
    {
93
0
        if (IsLocked() || !m_pNavModel)
94
0
            return;
95
96
        // insert no Undoaction
97
0
        m_bCanUndo = false;
98
99
0
        Reference< XInterface > xTemp;
100
0
        evt.Element >>= xTemp;
101
0
        Insert(xTemp, ::comphelper::getINT32(evt.Accessor));
102
103
0
        m_bCanUndo = true;
104
0
    }
105
106
107
    void OFormComponentObserver::Insert(const Reference< XInterface > & xIface, sal_Int32 nIndex)
108
0
    {
109
0
        Reference< XForm >  xForm(xIface, UNO_QUERY);
110
0
        if (xForm.is())
111
0
        {
112
0
            m_pNavModel->InsertForm(xForm, sal_uInt32(nIndex));
113
0
            Reference< XIndexContainer >  xContainer(xForm, UNO_QUERY);
114
0
            Reference< XInterface > xTemp;
115
0
            for (sal_Int32 i = 0; i < xContainer->getCount(); i++)
116
0
            {
117
0
                xContainer->getByIndex(i) >>= xTemp;
118
0
                Insert(xTemp, i);
119
0
            }
120
0
        }
121
0
        else
122
0
        {
123
0
            Reference< XFormComponent >  xFormComp(xIface, UNO_QUERY);
124
0
            if (xFormComp.is())
125
0
                m_pNavModel->InsertFormComponent(xFormComp, sal_uInt32(nIndex));
126
0
        }
127
0
    }
128
129
130
    void SAL_CALL OFormComponentObserver::elementReplaced(const ContainerEvent& evt)
131
0
    {
132
0
        if (IsLocked() || !m_pNavModel)
133
0
            return;
134
135
0
        m_bCanUndo = false;
136
137
        // delete EntryData
138
0
        Reference< XFormComponent >  xReplaced;
139
0
        evt.ReplacedElement >>= xReplaced;
140
0
        FmEntryData* pEntryData = m_pNavModel->FindData(xReplaced, m_pNavModel->GetRootList());
141
0
        if (pEntryData)
142
0
        {
143
0
            if (dynamic_cast<const FmControlData*>( pEntryData) !=  nullptr)
144
0
            {
145
0
                Reference< XFormComponent >  xComp;
146
0
                evt.Element >>= xComp;
147
0
                DBG_ASSERT(xComp.is(), "OFormComponentObserver::elementReplaced : invalid argument !");
148
                    // FmControlData should be coupled with XFormComponent
149
0
                m_pNavModel->ReplaceFormComponent(xReplaced, xComp);
150
0
            }
151
0
            else if (dynamic_cast<const FmFormData*>( pEntryData) !=  nullptr)
152
0
            {
153
0
                OSL_FAIL("replacing forms not implemented yet !");
154
0
            }
155
0
        }
156
157
0
        m_bCanUndo = true;
158
0
    }
159
160
161
    void OFormComponentObserver::Remove( const css::uno::Reference< css::uno::XInterface >& _rxElement )
162
0
    {
163
0
        if (IsLocked() || !m_pNavModel)
164
0
            return;
165
166
0
        m_bCanUndo = false;
167
168
169
        // delete EntryData
170
0
        FmEntryData* pEntryData = m_pNavModel->FindData( _rxElement, m_pNavModel->GetRootList() );
171
0
        if (pEntryData)
172
0
            m_pNavModel->Remove(pEntryData);
173
174
0
        m_bCanUndo = true;
175
0
    }
176
177
178
    void SAL_CALL OFormComponentObserver::elementRemoved(const ContainerEvent& evt)
179
0
    {
180
0
        Reference< XInterface > xElement;
181
0
        evt.Element >>= xElement;
182
0
        Remove( xElement );
183
0
    }
184
185
    NavigatorTreeModel::NavigatorTreeModel()
186
0
                    :m_pFormShell(nullptr)
187
0
                    ,m_pFormPage(nullptr)
188
0
                    ,m_pFormModel(nullptr)
189
0
    {
190
0
        m_pPropChangeList = new OFormComponentObserver(this);
191
0
        m_pRootList.reset( new FmEntryDataList() );
192
0
    }
193
194
    NavigatorTreeModel::~NavigatorTreeModel()
195
0
    {
196
197
        // unregister Listener
198
0
        if( m_pFormShell)
199
0
        {
200
0
            FmFormModel* pFormModel = m_pFormShell->GetFormModel();
201
0
            if( pFormModel && IsListening(*pFormModel))
202
0
                EndListening( *pFormModel );
203
204
0
            if (IsListening(*m_pFormShell))
205
0
                EndListening(*m_pFormShell);
206
0
        }
207
208
0
        Clear();
209
0
        m_pRootList.reset();
210
0
        m_pPropChangeList->ReleaseModel();
211
0
    }
212
213
214
    void NavigatorTreeModel::SetModified()
215
0
    {
216
0
        if( !m_pFormShell ) return;
217
0
        SfxObjectShell* pObjShell = m_pFormShell->GetFormModel()->GetObjectShell();
218
0
        if( !pObjShell ) return;
219
0
        pObjShell->SetModified();
220
0
    }
221
222
223
    void NavigatorTreeModel::Clear()
224
0
    {
225
0
        Reference< css::form::XForms >  xForms( GetForms());
226
0
        if(xForms.is())
227
0
            xForms->removeContainerListener(m_pPropChangeList);
228
229
230
        // delete RootList
231
0
        GetRootList()->clear();
232
233
234
        // notify UI
235
0
        FmNavClearedHint aClearedHint;
236
0
        Broadcast( aClearedHint );
237
0
    }
238
239
240
    Reference< css::form::XForms >  NavigatorTreeModel::GetForms() const
241
0
    {
242
0
        if( !m_pFormShell || !m_pFormShell->GetCurPage())
243
0
            return nullptr;
244
0
        else
245
0
            return m_pFormShell->GetCurPage()->GetForms();
246
0
    }
247
248
249
    void NavigatorTreeModel::Insert(FmEntryData* pEntry, sal_uInt32 nRelPos, bool bAlterModel)
250
0
    {
251
0
        if (IsListening(*m_pFormModel))
252
0
            EndListening(*m_pFormModel);
253
254
0
        m_pPropChangeList->Lock();
255
0
        FmFormData* pFolder     = static_cast<FmFormData*>( pEntry->GetParent() );
256
0
        Reference< XChild > xElement( pEntry->GetChildIFace() );
257
0
        if (bAlterModel)
258
0
        {
259
0
            OUString aStr;
260
0
            if (dynamic_cast<const FmFormData*>( pEntry) !=  nullptr)
261
0
                aStr = SvxResId(RID_STR_FORM);
262
0
            else
263
0
                aStr = SvxResId(RID_STR_CONTROL);
264
265
0
            Reference< XIndexContainer >  xContainer;
266
0
            if (pFolder)
267
0
                xContainer.set(pFolder->GetFormIface(), UNO_QUERY);
268
0
            else
269
0
                xContainer = GetForms();
270
271
0
            bool bUndo = m_pFormModel->IsUndoEnabled();
272
273
0
            if( bUndo )
274
0
            {
275
0
                OUString aUndoStr(SvxResId(RID_STR_UNDO_CONTAINER_INSERT));
276
0
                aUndoStr = aUndoStr.replaceFirst("#", aStr);
277
0
                m_pFormModel->BegUndo(aUndoStr);
278
0
            }
279
280
0
            if (nRelPos >= o3tl::make_unsigned(xContainer->getCount()))
281
0
                nRelPos = static_cast<sal_uInt32>(xContainer->getCount());
282
283
            // UndoAction
284
0
            if ( bUndo && m_pPropChangeList->CanUndo())
285
0
            {
286
0
                m_pFormModel->AddUndo(std::make_unique<FmUndoContainerAction>(*m_pFormModel,
287
0
                                                         FmUndoContainerAction::Inserted,
288
0
                                                         xContainer,
289
0
                                                         xElement,
290
0
                                                         nRelPos));
291
0
            }
292
293
            // Element has to be of the expected type by the container
294
0
            if (xContainer->getElementType() ==
295
0
                cppu::UnoType<XForm>::get())
296
297
0
            {
298
0
                Reference< XForm >  xElementAsForm(xElement, UNO_QUERY);
299
0
                xContainer->insertByIndex(nRelPos, Any(xElementAsForm));
300
0
            }
301
0
            else if (xContainer->getElementType() ==
302
0
                cppu::UnoType<XFormComponent>::get())
303
304
0
            {
305
0
                Reference< XFormComponent >  xElementAsComponent(xElement, UNO_QUERY);
306
0
                xContainer->insertByIndex(nRelPos, Any(xElementAsComponent));
307
0
            }
308
0
            else
309
0
            {
310
0
                OSL_FAIL("NavigatorTreeModel::Insert : the parent container needs an elementtype I don't know !");
311
0
            }
312
313
0
            if( bUndo )
314
0
                m_pFormModel->EndUndo();
315
0
        }
316
317
        // register as PropertyChangeListener
318
0
        Reference< XPropertySet >  xSet(xElement, UNO_QUERY);
319
0
        if( xSet.is() )
320
0
            xSet->addPropertyChangeListener( FM_PROP_NAME, m_pPropChangeList );
321
322
323
        // Remove data from model
324
0
        if (dynamic_cast<const FmFormData*>( pEntry) !=  nullptr)
325
0
        {
326
0
            Reference< XContainer >  xContainer(xElement, UNO_QUERY);
327
0
            if (xContainer.is())
328
0
                xContainer->addContainerListener(m_pPropChangeList);
329
0
        }
330
331
0
        if (pFolder)
332
0
            pFolder->GetChildList()->insert( std::unique_ptr<FmEntryData>(pEntry), nRelPos );
333
0
        else
334
0
            GetRootList()->insert( std::unique_ptr<FmEntryData>(pEntry), nRelPos );
335
336
337
        // notify UI
338
0
        FmNavInsertedHint aInsertedHint( pEntry, nRelPos );
339
0
        Broadcast( aInsertedHint );
340
341
0
        m_pPropChangeList->UnLock();
342
0
        if (IsListening(*m_pFormModel))
343
0
            StartListening(*m_pFormModel);
344
0
    }
345
346
347
    void NavigatorTreeModel::Remove(FmEntryData* pEntry, bool bAlterModel)
348
0
    {
349
350
        // get form and parent
351
0
        if (!pEntry || !m_pFormModel)
352
0
            return;
353
354
0
        if (IsListening(*m_pFormModel))
355
0
            EndListening(*m_pFormModel);
356
357
0
        const bool bUndo = m_pFormModel->IsUndoEnabled();
358
359
0
        m_pPropChangeList->Lock();
360
0
        FmFormData*     pFolder     = static_cast<FmFormData*>( pEntry->GetParent() );
361
0
        Reference< XChild > xElement ( pEntry->GetChildIFace() );
362
0
        if (bAlterModel)
363
0
        {
364
0
            OUString        aStr;
365
0
            if (dynamic_cast<const FmFormData*>( pEntry) !=  nullptr)
366
0
                aStr = SvxResId(RID_STR_FORM);
367
0
            else
368
0
                aStr = SvxResId(RID_STR_CONTROL);
369
370
0
            if( bUndo )
371
0
            {
372
0
                OUString aUndoStr(SvxResId(RID_STR_UNDO_CONTAINER_REMOVE));
373
0
                aUndoStr = aUndoStr.replaceFirst("#", aStr);
374
0
                m_pFormModel->BegUndo(aUndoStr);
375
0
            }
376
0
        }
377
378
        // now real deletion of data form model
379
0
        if (auto pFormData = dynamic_cast<FmFormData*>( pEntry))
380
0
            RemoveForm(pFormData);
381
0
        else
382
0
            RemoveFormComponent(static_cast<FmControlData*>(pEntry));
383
384
385
0
        if (bAlterModel)
386
0
        {
387
0
            Reference< XIndexContainer >  xContainer(xElement->getParent(), UNO_QUERY);
388
            // remove from Container
389
0
            sal_Int32 nContainerIndex = getElementPos(xContainer, xElement);
390
            // UndoAction
391
0
            if (nContainerIndex >= 0)
392
0
            {
393
0
                if ( bUndo && m_pPropChangeList->CanUndo())
394
0
                {
395
0
                    m_pFormModel->AddUndo(std::make_unique<FmUndoContainerAction>(*m_pFormModel,
396
0
                                                          FmUndoContainerAction::Removed,
397
0
                                                          xContainer,
398
0
                                                          xElement, nContainerIndex ));
399
0
                }
400
0
                else if( !m_pPropChangeList->CanUndo() )
401
0
                {
402
0
                    FmUndoContainerAction::DisposeElement( xElement );
403
0
                }
404
405
0
                xContainer->removeByIndex(nContainerIndex );
406
0
            }
407
408
0
            if( bUndo )
409
0
                m_pFormModel->EndUndo();
410
0
        }
411
412
        // remove from parent
413
0
        if (pFolder)
414
0
            pFolder->GetChildList()->removeNoDelete( pEntry );
415
0
        else
416
0
        {
417
0
            GetRootList()->removeNoDelete( pEntry );
418
419
            // If root has no more form, reset CurForm at shell
420
0
            if ( !GetRootList()->size() )
421
0
                m_pFormShell->GetImpl()->forgetCurrentForm_Lock();
422
0
        }
423
424
425
        // notify UI
426
0
        FmNavRemovedHint aRemovedHint( pEntry );
427
0
        Broadcast( aRemovedHint );
428
429
        // delete entry
430
0
        delete pEntry;
431
432
0
        m_pPropChangeList->UnLock();
433
0
        StartListening(*m_pFormModel);
434
0
    }
435
436
437
    void NavigatorTreeModel::RemoveForm(FmFormData const * pFormData)
438
0
    {
439
440
        // get form and parent
441
0
        if (!pFormData || !m_pFormModel)
442
0
            return;
443
444
0
        FmEntryDataList*    pChildList = pFormData->GetChildList();
445
0
        for ( size_t i = pChildList->size(); i > 0; )
446
0
        {
447
0
            FmEntryData* pEntryData = pChildList->at( --i );
448
449
450
            // Child is form -> recursive call
451
0
            if( auto pChildFormData = dynamic_cast<FmFormData*>( pEntryData) )
452
0
                RemoveForm(pChildFormData);
453
0
            else if( auto pChildControlData = dynamic_cast<FmControlData*>( pEntryData) )
454
0
                RemoveFormComponent(pChildControlData);
455
0
        }
456
457
458
        // unregister as PropertyChangeListener
459
0
        const Reference< XPropertySet >& xSet( pFormData->GetPropertySet() );
460
0
        if ( xSet.is() )
461
0
            xSet->removePropertyChangeListener( FM_PROP_NAME, m_pPropChangeList );
462
0
    }
463
464
465
    void NavigatorTreeModel::RemoveFormComponent(FmControlData const * pControlData)
466
0
    {
467
468
        // get control and parent
469
0
        if (!pControlData)
470
0
            return;
471
472
473
        // unregister as PropertyChangeListener
474
0
        const Reference< XPropertySet >&  xSet( pControlData->GetPropertySet() );
475
0
        if (xSet.is())
476
0
            xSet->removePropertyChangeListener( FM_PROP_NAME, m_pPropChangeList);
477
0
    }
478
479
480
    void NavigatorTreeModel::FillBranch( FmFormData* pFormData )
481
0
    {
482
483
        // insert forms from root
484
0
        if( pFormData == nullptr )
485
0
        {
486
0
            Reference< XIndexContainer >   xForms = GetForms();
487
0
            if (!xForms.is())
488
0
                return;
489
490
0
            Reference< XForm >     xSubForm;
491
0
            for (sal_Int32 i=0; i<xForms->getCount(); ++i)
492
0
            {
493
0
                DBG_ASSERT( xForms->getByIndex(i).getValueType() == cppu::UnoType<XForm>::get(),
494
0
                    "NavigatorTreeModel::FillBranch : the root container should supply only elements of type XForm");
495
496
0
                xForms->getByIndex(i) >>= xSubForm;
497
0
                FmFormData* pSubFormData = new FmFormData(xSubForm, pFormData);
498
0
                Insert( pSubFormData );
499
500
                // new branch, if SubForm contains Subforms itself
501
0
                FillBranch( pSubFormData );
502
0
            }
503
0
        }
504
505
506
        // insert components
507
0
        else
508
0
        {
509
0
            Reference< XIndexContainer >  xComponents( GetFormComponents(pFormData));
510
0
            if( !xComponents.is() ) return;
511
512
0
            FmControlData* pNewControlData;
513
0
            FmFormData* pSubFormData;
514
515
0
            Reference< XFormComponent >  xCurrentComponent;
516
0
            for (sal_Int32 j=0; j<xComponents->getCount(); ++j)
517
0
            {
518
0
                xComponents->getByIndex(j) >>= xCurrentComponent;
519
0
                Reference< XForm >  xSubForm(xCurrentComponent, UNO_QUERY);
520
521
0
                if (xSubForm.is())
522
0
                {   // actual component is a form
523
0
                    pSubFormData = new FmFormData(xSubForm, pFormData);
524
0
                    Insert(pSubFormData);
525
526
527
                    // new branch, if SubForm contains Subforms itself
528
0
                    FillBranch(pSubFormData);
529
0
                }
530
0
                else
531
0
                {
532
0
                    pNewControlData = new FmControlData(xCurrentComponent, pFormData);
533
0
                    Insert(pNewControlData);
534
0
                }
535
0
            }
536
0
        }
537
0
    }
538
539
540
    void NavigatorTreeModel::InsertForm(const Reference< XForm > & xForm, sal_uInt32 nRelPos)
541
0
    {
542
0
        FmFormData* pFormData = static_cast<FmFormData*>(FindData( xForm, GetRootList() ));
543
0
        if (pFormData)
544
0
            return;
545
546
547
        // set ParentData
548
0
        Reference< XInterface >  xIFace( xForm->getParent());
549
0
        Reference< XForm >  xParentForm(xIFace, UNO_QUERY);
550
0
        FmFormData* pParentData = nullptr;
551
0
        if (xParentForm.is())
552
0
            pParentData = static_cast<FmFormData*>(FindData( xParentForm, GetRootList() ));
553
554
0
        pFormData = new FmFormData(xForm, pParentData);
555
0
        Insert( pFormData, nRelPos );
556
0
    }
557
558
559
    void NavigatorTreeModel::InsertFormComponent(const Reference< XFormComponent > & xComp, sal_uInt32 nRelPos)
560
0
    {
561
562
        // set ParentData
563
0
        Reference< XInterface >  xIFace( xComp->getParent());
564
0
        Reference< XForm >  xForm(xIFace, UNO_QUERY);
565
0
        if (!xForm.is())
566
0
            return;
567
568
0
        FmFormData* pParentData = static_cast<FmFormData*>(FindData( xForm, GetRootList() ));
569
0
        if( !pParentData )
570
0
        {
571
0
            pParentData = new FmFormData(xForm, nullptr);
572
0
            Insert( pParentData );
573
0
        }
574
575
0
        if (!FindData(xComp, pParentData->GetChildList(),false))
576
0
        {
577
578
            // set new EntryData
579
0
            FmEntryData* pNewEntryData = new FmControlData(xComp, pParentData);
580
581
582
            // insert new EntryData
583
0
            Insert( pNewEntryData, nRelPos );
584
0
        }
585
0
    }
586
587
    void NavigatorTreeModel::ReplaceFormComponent(
588
        const Reference< XFormComponent > & xOld,
589
        const Reference< XFormComponent > & xNew
590
    )
591
0
    {
592
0
        FmEntryData* pData = FindData(xOld, GetRootList());
593
0
        assert(dynamic_cast<const FmControlData*>( pData)); //NavigatorTreeModel::ReplaceFormComponent : invalid argument
594
0
        auto pControlData = dynamic_cast<FmControlData*>( pData);
595
0
        if (!pControlData)
596
0
            return;
597
0
        pControlData->ModelReplaced(xNew);
598
599
0
        FmNavModelReplacedHint aReplacedHint( pData );
600
0
        Broadcast( aReplacedHint );
601
0
    }
602
603
    FmEntryData* NavigatorTreeModel::FindData(const Reference< XInterface > & xElement, FmEntryDataList* pDataList, bool bRecurs)
604
0
    {
605
        // normalize
606
0
        Reference< XInterface > xIFace( xElement, UNO_QUERY );
607
608
0
        for ( size_t i = 0; i < pDataList->size(); i++ )
609
0
        {
610
0
            FmEntryData* pEntryData = pDataList->at( i );
611
0
            if ( pEntryData->GetElement().get() == xIFace.get() )
612
0
                return pEntryData;
613
0
            else if (bRecurs)
614
0
            {
615
0
                pEntryData = FindData( xElement, pEntryData->GetChildList() );
616
0
                if (pEntryData)
617
0
                    return pEntryData;
618
0
            }
619
0
        }
620
0
        return nullptr;
621
0
    }
622
623
624
    FmEntryData* NavigatorTreeModel::FindData( const OUString& rText, FmFormData const * pParentData, bool bRecurs )
625
0
    {
626
0
        FmEntryDataList* pDataList;
627
0
        if( !pParentData )
628
0
            pDataList = GetRootList();
629
0
        else
630
0
            pDataList = pParentData->GetChildList();
631
632
0
        OUString aEntryText;
633
0
        FmEntryData* pEntryData;
634
0
        FmEntryData* pChildData;
635
636
0
        for( size_t i = 0; i < pDataList->size(); i++ )
637
0
        {
638
0
            pEntryData = pDataList->at( i );
639
0
            aEntryText = pEntryData->GetText();
640
641
0
            if (rText == aEntryText)
642
0
                return pEntryData;
643
644
0
            if (FmFormData* pFormData = bRecurs ? dynamic_cast<FmFormData*>(pEntryData) : nullptr)
645
0
            {
646
0
                pChildData = FindData(rText, pFormData, true);
647
0
                if( pChildData )
648
0
                    return pChildData;
649
0
            }
650
0
        }
651
652
0
        return nullptr;
653
0
    }
654
655
    void NavigatorTreeModel::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
656
0
    {
657
0
        if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
658
0
        {
659
0
            const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
660
0
            switch( pSdrHint->GetKind() )
661
0
            {
662
0
                case SdrHintKind::ObjectInserted:
663
0
                    InsertSdrObj(pSdrHint->GetObject());
664
0
                    break;
665
0
                case SdrHintKind::ObjectRemoved:
666
0
                    RemoveSdrObj(pSdrHint->GetObject());
667
0
                    break;
668
0
                default:
669
0
                    break;
670
0
            }
671
0
        }
672
        // is shell gone?
673
0
        else if (rHint.GetId() == SfxHintId::Dying)
674
0
        {
675
0
            UpdateContent(nullptr);
676
0
        }
677
        // changed mark of controls?
678
0
        else if (rHint.GetId() == SfxHintId::FmNavViewMarksChanged)
679
0
        {
680
0
            const FmNavViewMarksChanged* pvmcHint = static_cast<const FmNavViewMarksChanged*>(&rHint);
681
0
            BroadcastMarkedObjects(pvmcHint->GetAffectedView()->GetMarkedObjectList());
682
0
        }
683
0
    }
684
685
    void NavigatorTreeModel::InsertSdrObj( const SdrObject* pObj )
686
0
    {
687
0
        const FmFormObj* pFormObject = FmFormObj::GetFormObject( pObj );
688
0
        if ( pFormObject )
689
0
        {
690
0
            try
691
0
            {
692
0
                Reference< XFormComponent > xFormComponent( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW );
693
0
                Reference< XIndexAccess > xContainer( xFormComponent->getParent(), UNO_QUERY_THROW );
694
695
0
                sal_Int32 nPos = getElementPos( xContainer, xFormComponent );
696
0
                InsertFormComponent( xFormComponent, nPos );
697
0
            }
698
0
            catch( const Exception& )
699
0
            {
700
0
                DBG_UNHANDLED_EXCEPTION("svx");
701
0
            }
702
0
        }
703
0
        else if ( pObj->IsGroupObject() )
704
0
        {
705
0
            SdrObjListIter aIter( pObj->GetSubList() );
706
0
            while ( aIter.IsMore() )
707
0
                InsertSdrObj( aIter.Next() );
708
0
        }
709
0
    }
710
711
712
    void NavigatorTreeModel::RemoveSdrObj( const SdrObject* pObj )
713
0
    {
714
0
        const FmFormObj* pFormObject = FmFormObj::GetFormObject( pObj );
715
0
        if ( pFormObject )
716
0
        {
717
0
            try
718
0
            {
719
0
                Reference< XFormComponent > xFormComponent( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW );
720
0
                FmEntryData* pEntryData = FindData( xFormComponent, GetRootList() );
721
0
                if ( pEntryData )
722
0
                    Remove( pEntryData );
723
0
            }
724
0
            catch( const Exception& )
725
0
            {
726
0
                DBG_UNHANDLED_EXCEPTION("svx");
727
0
            }
728
0
        }
729
0
        else if ( pObj->IsGroupObject() )
730
0
        {
731
0
            SdrObjListIter aIter( pObj->GetSubList() );
732
0
            while ( aIter.IsMore() )
733
0
                RemoveSdrObj( aIter.Next() );
734
0
        }
735
0
    }
736
737
    bool NavigatorTreeModel::InsertFormComponent(FmNavRequestSelectHint& rHint, SdrObject* pObject)
738
0
    {
739
0
        if ( auto pObjGroup = dynamic_cast<const SdrObjGroup*>( pObject) )
740
0
        {   // descend recursively
741
0
            const SdrObjList *pChildren = pObjGroup->GetSubList();
742
0
            for (const rtl::Reference<SdrObject>& pCurrent : *pChildren)
743
0
            {
744
0
                if (!InsertFormComponent(rHint, pCurrent.get()))
745
0
                    return false;
746
0
            }
747
0
        }
748
0
        else
749
0
        {
750
0
            FmFormObj* pFormObject = FmFormObj::GetFormObject( pObject );
751
0
            if ( !pFormObject )
752
0
                return false;
753
754
0
            try
755
0
            {
756
0
                Reference< XFormComponent > xFormViewControl( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW );
757
0
                FmEntryData* pControlData = FindData( xFormViewControl, GetRootList() );
758
0
                if ( !pControlData )
759
0
                    return false;
760
761
0
                rHint.AddItem( pControlData );
762
0
                return true;
763
0
            }
764
0
            catch( const Exception& )
765
0
            {
766
0
                DBG_UNHANDLED_EXCEPTION("svx");
767
0
                return false;
768
0
            }
769
0
        }
770
771
0
        return true;
772
0
    }
773
774
    void NavigatorTreeModel::BroadcastMarkedObjects(const SdrMarkList& mlMarked)
775
0
    {
776
        // search all objects, which can be handled, out of marked objects
777
0
        FmNavRequestSelectHint rshRequestSelection;
778
0
        bool bIsMixedSelection = false;
779
780
0
        for (size_t i=0; (i<mlMarked.GetMarkCount()) && !bIsMixedSelection; ++i)
781
0
        {
782
0
            SdrObject* pobjCurrent = mlMarked.GetMark(i)->GetMarkedSdrObj();
783
0
            bIsMixedSelection |= !InsertFormComponent(rshRequestSelection, pobjCurrent);
784
                // if Not-Form-Control, InsertFormComponent returns sal_False !
785
0
        }
786
787
0
        rshRequestSelection.SetMixedSelection(bIsMixedSelection);
788
0
        if (bIsMixedSelection)
789
0
            rshRequestSelection.ClearItems();
790
791
0
        Broadcast(rshRequestSelection);
792
            // an empty list causes NavigatorTree to remove his selection
793
0
    }
794
795
    void NavigatorTreeModel::UpdateContent( const Reference< css::form::XForms > & xForms )
796
0
    {
797
798
        // refill model form root upward
799
0
        Clear();
800
0
        if (!xForms.is())
801
0
            return;
802
803
0
        xForms->addContainerListener(m_pPropChangeList);
804
805
0
        FillBranch(nullptr);
806
807
        // select same control in tree as in view
808
        // (or all of them), if there is one ...
809
0
        if(!m_pFormShell) return;       // no shell
810
811
0
        FmFormView* pFormView = m_pFormShell->GetFormView();
812
0
        assert(pFormView != nullptr && "NavigatorTreeModel::UpdateContent : no FormView");
813
0
        BroadcastMarkedObjects(pFormView->GetMarkedObjectList());
814
0
    }
815
816
    void NavigatorTreeModel::UpdateContent( FmFormShell* pShell )
817
0
    {
818
819
        // If shell is unchanged, do nothing
820
0
        FmFormPage* pNewPage = pShell ? pShell->GetCurPage() : nullptr;
821
0
        if ((pShell == m_pFormShell) && (m_pFormPage == pNewPage))
822
0
            return;
823
824
825
        // unregister as Listener
826
0
        if( m_pFormShell )
827
0
        {
828
0
            if (m_pFormModel)
829
0
                EndListening( *m_pFormModel );
830
0
            m_pFormModel = nullptr;
831
0
            EndListening( *m_pFormShell );
832
0
            Clear();
833
0
        }
834
835
836
        // entire update
837
0
        m_pFormShell = pShell;
838
0
        if (m_pFormShell)
839
0
        {
840
0
            m_pFormPage = pNewPage;
841
0
            UpdateContent(m_pFormPage->GetForms());
842
0
        } else
843
0
            m_pFormPage = nullptr;
844
845
846
        // register as Listener again
847
0
        if( m_pFormShell )
848
0
        {
849
0
            StartListening( *m_pFormShell );
850
0
            m_pFormModel = m_pFormShell->GetFormModel();
851
0
            if( m_pFormModel )
852
0
                StartListening( *m_pFormModel );
853
0
        }
854
0
    }
855
856
    Reference< XIndexContainer >  NavigatorTreeModel::GetFormComponents( FmFormData const * pFormData )
857
0
    {
858
859
        // get components from form
860
0
        if (pFormData)
861
0
            return Reference< XIndexContainer > (pFormData->GetFormIface(), UNO_QUERY);
862
863
0
        return Reference< XIndexContainer > ();
864
0
    }
865
866
    bool NavigatorTreeModel::Rename( FmEntryData* pEntryData, const OUString& rNewText )
867
0
    {
868
869
        // If name already exist, error message
870
0
        pEntryData->SetText( rNewText );
871
872
873
        // get PropertySet
874
0
        Reference< XFormComponent >  xFormComponent;
875
876
0
        if( auto pFormData = dynamic_cast<FmFormData*>( pEntryData))
877
0
        {
878
0
            xFormComponent = pFormData->GetFormIface();
879
0
        }
880
881
0
        if( auto pControlData = dynamic_cast<FmControlData*>( pEntryData) )
882
0
        {
883
0
            xFormComponent = pControlData->GetFormComponent();
884
0
        }
885
886
0
        if( !xFormComponent.is() ) return false;
887
0
        Reference< XPropertySet >  xSet(xFormComponent, UNO_QUERY);
888
0
        if( !xSet.is() ) return false;
889
890
891
        // set name
892
0
        xSet->setPropertyValue( FM_PROP_NAME, Any(rNewText) );
893
894
0
        return true;
895
0
    }
896
897
}
898
899
900
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */