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