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 #ifndef INCLUDED_SVX_SOURCE_INC_FMEXPL_HXX
20 #define INCLUDED_SVX_SOURCE_INC_FMEXPL_HXX
21 
22 #include <config_options.h>
23 #include <svl/lstner.hxx>
24 #include <svl/SfxBroadcaster.hxx>
25 #include <vcl/window.hxx>
26 #include <sfx2/childwin.hxx>
27 #include <svl/poolitem.hxx>
28 #include <sfx2/bindings.hxx>
29 #include <sfx2/dockwin.hxx>
30 #include <sfx2/ctrlitem.hxx>
31 
32 #include <com/sun/star/form/XForm.hpp>
33 #include <com/sun/star/form/XFormComponent.hpp>
34 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
35 #include <com/sun/star/container/XContainerListener.hpp>
36 #include <com/sun/star/beans/XPropertyChangeListener.hpp>
37 #include <com/sun/star/container/XIndexContainer.hpp>
38 
39 #include <svx/fmview.hxx>
40 
41 #include "fmexch.hxx"
42 #include <vector>
43 #include <set>
44 #include <cppuhelper/implbase.hxx>
45 
46 class SdrObjListIter;
47 class FmFormShell;
48 class SdrObject;
49 class FmFormModel;
50 class FmFormView;
51 class SdrMarkList;
52 
53 
54 class FmEntryData;
55 class FmNavInsertedHint : public SfxHint
56 {
57     FmEntryData* pEntryData;
58     sal_uInt32 nPos;
59 
60 public:
61     FmNavInsertedHint( FmEntryData* pInsertedEntryData, sal_uInt32 nRelPos );
62     virtual ~FmNavInsertedHint() override;
63 
GetEntryData() const64     FmEntryData* GetEntryData() const { return pEntryData; }
GetRelPos() const65     sal_uInt32 GetRelPos() const { return nPos; }
66 };
67 
68 
69 class FmNavModelReplacedHint : public SfxHint
70 {
71     FmEntryData* pEntryData;    // the data of the entry that has got a new model
72 
73 public:
74     FmNavModelReplacedHint( FmEntryData* pAffectedEntryData );
75     virtual ~FmNavModelReplacedHint() override;
76 
GetEntryData() const77     FmEntryData* GetEntryData() const { return pEntryData; }
78 };
79 
80 
81 class FmNavRemovedHint : public SfxHint
82 {
83     FmEntryData* pEntryData;
84 
85 public:
86     FmNavRemovedHint( FmEntryData* pInsertedEntryData );
87     virtual ~FmNavRemovedHint() override;
88 
GetEntryData() const89     FmEntryData* GetEntryData() const { return pEntryData; }
90 };
91 
92 
93 class FmNavNameChangedHint : public SfxHint
94 {
95     FmEntryData*    pEntryData;
96     OUString          aNewName;
97 
98 public:
99     FmNavNameChangedHint( FmEntryData* pData, const OUString& rNewName );
100     virtual ~FmNavNameChangedHint() override;
101 
GetEntryData() const102     FmEntryData*    GetEntryData() const { return pEntryData; }
GetNewName() const103     const OUString& GetNewName() const { return aNewName; }
104 };
105 
106 
107 class FmNavClearedHint : public SfxHint
108 {
109 public:
110     FmNavClearedHint();
111     virtual ~FmNavClearedHint() override;
112 };
113 
114 
115 class FmNavViewMarksChanged : public SfxHint
116 {
117     FmFormView* pView;
118 public:
FmNavViewMarksChanged(FmFormView * pWhichView)119     FmNavViewMarksChanged(FmFormView* pWhichView) { pView = pWhichView; }
120 
GetAffectedView() const121     const FmFormView* GetAffectedView() const { return pView; }
122 };
123 
124 
125 class FmEntryDataList;
126 class FmEntryData
127 {
128 private:
129     css::uno::Reference< css::uno::XInterface >       m_xNormalizedIFace;
130     css::uno::Reference< css::beans::XPropertySet >   m_xProperties;
131     css::uno::Reference< css::container::XChild >     m_xChild;
132 
133 protected:
134     OUString            m_aNormalImage;
135     OUString            aText;
136 
137     std::unique_ptr<FmEntryDataList>
138                         pChildList;
139     FmEntryData*        pParent;
140 
141 protected:
142     void    newObject( const css::uno::Reference< css::uno::XInterface >& _rxIFace );
143 
144 public:
145 
146     FmEntryData( FmEntryData* pParentData, const css::uno::Reference< css::uno::XInterface >& _rIFace );
147     FmEntryData( const FmEntryData& rEntryData );
148     virtual ~FmEntryData();
149 
SetText(const OUString & rText)150     void    SetText( const OUString& rText ){ aText = rText; }
SetParent(FmEntryData * pParentData)151     void    SetParent( FmEntryData* pParentData ){ pParent = pParentData; }
152 
GetNormalImage() const153     const OUString& GetNormalImage() const { return m_aNormalImage; }
154 
GetText() const155     const OUString& GetText() const { return aText; }
GetParent() const156     FmEntryData*    GetParent() const { return pParent; }
GetChildList() const157     FmEntryDataList* GetChildList() const { return pChildList.get(); }
158 
159     virtual bool IsEqualWithoutChildren( FmEntryData* pEntryData );
160     virtual std::unique_ptr<FmEntryData> Clone() = 0;
161 
162     // note that the interface returned is normalized, i.e. querying the given XInterface of the object
163     // for XInterface must return the interface itself.
GetElement() const164     const css::uno::Reference< css::uno::XInterface >& GetElement() const
165     {
166         return m_xNormalizedIFace;
167     }
168 
GetPropertySet() const169     const css::uno::Reference< css::beans::XPropertySet >& GetPropertySet() const
170     {
171         return m_xProperties;
172     }
173 
GetChildIFace() const174     const css::uno::Reference< css::container::XChild >& GetChildIFace() const
175     {
176         return m_xChild;
177     }
178 };
179 
180 
181 class FmEntryDataList final
182 {
183 private:
184     std::vector< std::unique_ptr<FmEntryData> > maEntryDataList;
185 
186 public:
187     FmEntryDataList();
188     ~FmEntryDataList();
189 
at(size_t Index)190     FmEntryData*    at( size_t Index )
191         { return maEntryDataList.at(Index).get(); }
192 
size() const193     size_t          size() const { return maEntryDataList.size(); }
194     void            removeNoDelete( FmEntryData* pItem );
195     void            insert( std::unique_ptr<FmEntryData> pItem, size_t Index );
196     void            clear();
197 };
198 
199 
200 // FmNavRequestSelectHint - someone tells the NavigatorTree to select certain entries
201 
202 typedef std::set<FmEntryData*> FmEntryDataArray;
203 
204 class FmNavRequestSelectHint : public SfxHint
205 {
206     FmEntryDataArray    m_arredToSelect;
207     bool                m_bMixedSelection;
208 public:
FmNavRequestSelectHint()209     FmNavRequestSelectHint()
210         : m_bMixedSelection(false)
211     {
212     }
213 
SetMixedSelection(bool bMixedSelection)214     void SetMixedSelection(bool bMixedSelection) { m_bMixedSelection = bMixedSelection; }
IsMixedSelection() const215     bool IsMixedSelection() const { return m_bMixedSelection; }
AddItem(FmEntryData * pEntry)216     void AddItem(FmEntryData* pEntry) { m_arredToSelect.insert(pEntry); }
ClearItems()217     void ClearItems() { m_arredToSelect.clear(); }
GetItems()218     FmEntryDataArray& GetItems() { return m_arredToSelect; }
219 };
220 
221 
222 class FmFormData : public FmEntryData
223 {
224     css::uno::Reference< css::form::XForm >           m_xForm;
225 
226 public:
227     FmFormData(const css::uno::Reference< css::form::XForm >& _rxForm, FmFormData* _pParent);
228     FmFormData( const FmFormData& rFormData );
229     virtual ~FmFormData() override;
230 
GetFormIface() const231     const css::uno::Reference< css::form::XForm >& GetFormIface() const { return m_xForm; }
232 
233     virtual bool IsEqualWithoutChildren( FmEntryData* pEntryData ) override;
234     virtual std::unique_ptr<FmEntryData> Clone() override;
235 };
236 
237 
238 class FmControlData : public FmEntryData
239 {
240     css::uno::Reference< css::form::XFormComponent >  m_xFormComponent;
241 
242     OUString GetImage() const;
243 
244 public:
245 
246     FmControlData(
247         const css::uno::Reference< css::form::XFormComponent >& _rxComponent,
248         FmFormData* _pParent
249     );
250     FmControlData( const FmControlData& rControlData );
251     virtual ~FmControlData() override;
252 
GetFormComponent() const253     const css::uno::Reference< css::form::XFormComponent >& GetFormComponent() const { return m_xFormComponent; }
254     virtual bool IsEqualWithoutChildren( FmEntryData* pEntryData ) override;
255     virtual std::unique_ptr<FmEntryData> Clone() override;
256 
257     void ModelReplaced(const css::uno::Reference< css::form::XFormComponent >& _rxNew);
258 };
259 
260 
261 namespace svxform
262 {
263 
264 
265     class NavigatorTreeModel;
266 
267     class OFormComponentObserver final
268         :public ::cppu::WeakImplHelper <   css::beans::XPropertyChangeListener
269                                         ,   css::container::XContainerListener
270                                         >
271     {
272         ::svxform::NavigatorTreeModel*  m_pNavModel;
273         sal_uInt32 m_nLocks;
274         bool   m_bCanUndo;
275 
276     public:
277         OFormComponentObserver( ::svxform::NavigatorTreeModel* pModel );
278 
279     // XEventListenerListener
280         virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
281 
282     // css::beans::XPropertyChangeListener
283         virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& evt) override;
284 
285     // css::container::XContainerListener
286 
287         virtual void SAL_CALL elementInserted(const  css::container::ContainerEvent& rEvent) override;
288         virtual void SAL_CALL elementReplaced(const  css::container::ContainerEvent& rEvent) override;
289         virtual void SAL_CALL elementRemoved(const  css::container::ContainerEvent& rEvent) override;
290 
Lock()291         void Lock() { m_nLocks++; }
UnLock()292         void UnLock() { m_nLocks--; }
IsLocked() const293         bool IsLocked() const { return m_nLocks != 0; }
CanUndo() const294         bool CanUndo() const { return m_bCanUndo; }
ReleaseModel()295         void ReleaseModel() { m_pNavModel = nullptr; }
296     private:
297         void Insert(const css::uno::Reference< css::uno::XInterface >& xIface, sal_Int32 nIndex);
298         void Remove( const css::uno::Reference< css::uno::XInterface >& _rxElement );
299     };
300 
301     class NavigatorTreeModel : public SfxBroadcaster
302                            ,public SfxListener
303     {
304         friend class NavigatorTree;
305         friend class OFormComponentObserver;
306 
307         std::unique_ptr<FmEntryDataList>
308                                     m_pRootList;
309         FmFormShell*                m_pFormShell;
310         FmFormPage*                 m_pFormPage;
311         FmFormModel*                m_pFormModel;
312         rtl::Reference<OFormComponentObserver> m_pPropChangeList;
313 
314         void UpdateContent( const css::uno::Reference< css::form::XForms >& xForms );
315 
316         void InsertForm(const css::uno::Reference< css::form::XForm >& xForm, sal_uInt32 nRelPos);
317         void RemoveForm(FmFormData const * pFormData);
318 
319         void InsertFormComponent(const css::uno::Reference< css::form::XFormComponent >& xComp, sal_uInt32 nRelPos);
320         void RemoveFormComponent(FmControlData const * pControlData);
321         void InsertSdrObj(const SdrObject* pSdrObj);
322         void RemoveSdrObj(const SdrObject* pSdrObj);
323 
324         void ReplaceFormComponent(const css::uno::Reference< css::form::XFormComponent >& xOld, const css::uno::Reference< css::form::XFormComponent >& xNew);
325 
326         void BroadcastMarkedObjects(const SdrMarkList& mlMarked);
327             // send a RequestSelectHint with the currently selected objects
328         bool InsertFormComponent(FmNavRequestSelectHint& rHint, SdrObject* pObject);
329             // is a helper for previous, manages the ... in SdrObjGroups;
330             // returns sal_True if the object is a FormComponent (or recursively consists only of such)
331 
332     public:
333         NavigatorTreeModel();
334         virtual ~NavigatorTreeModel() override;
335 
336         void FillBranch( FmFormData* pParentData );
337         void UpdateContent( FmFormShell* pNewShell );
338 
339         void Insert(FmEntryData* pEntryData, sal_uInt32 nRelPos = SAL_MAX_UINT32,
340                                              bool bAlterModel = false);
341         void Remove(FmEntryData* pEntryData, bool bAlterModel = false);
342 
343         static bool Rename( FmEntryData* pEntryData, const OUString& rNewText );
344 
345         void Clear();
346         void SetModified();
347 
348         css::uno::Reference< css::form::XForms >    GetForms() const;
GetFormShell() const349         FmFormShell*        GetFormShell() const { return m_pFormShell; }
GetFormPage() const350         FmFormPage*         GetFormPage() const { return m_pFormPage; }
351         FmEntryData*        FindData( const css::uno::Reference< css::uno::XInterface >& xElement, FmEntryDataList* pDataList, bool bRecurs=true );
352         FmEntryData*        FindData( const OUString& rText, FmFormData const * pParentData, bool bRecurs );
GetRootList() const353         FmEntryDataList*    GetRootList() const { return m_pRootList.get(); }
354         static css::uno::Reference< css::container::XIndexContainer >   GetFormComponents( FmFormData const * pParentFormData );
355 
356         virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
357     };
358 
359     class NavigatorTree;
360 
361     class NavigatorTreeDropTarget : public DropTargetHelper
362     {
363     private:
364         NavigatorTree& m_rTreeView;
365 
366         virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
367         virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
368 
369     public:
370         NavigatorTreeDropTarget(NavigatorTree& rTreeView);
371     };
372 
373     typedef std::set<std::unique_ptr<weld::TreeIter>> SvLBoxEntrySortedArray;
374 
375     class NavigatorTree final : public SfxListener
376     {
377         std::unique_ptr<weld::TreeView> m_xTreeView;
378         NavigatorTreeDropTarget m_aDropTargetHelper;
379 
380         enum SELDATA_ITEMS      { SDI_DIRTY, SDI_ALL, SDI_NORMALIZED, SDI_NORMALIZED_FORMARK };
381 
382         Timer               m_aSynchronizeTimer;
383         // the meta-data about my current selection
384         SvLBoxEntrySortedArray  m_arrCurrentSelection;
385         // the entries which, in the view, are currently marked as "cut" (painted semi-transparent)
386         ListBoxEntrySet         m_aCutEntries;
387 
388         ::svxform::OControlExchangeHelper m_aControlExchange;
389 
390         std::unique_ptr<NavigatorTreeModel> m_pNavModel;
391         std::unique_ptr<weld::TreeIter> m_xRootEntry;
392         std::unique_ptr<weld::TreeIter> m_xEditEntry;
393 
394         ImplSVEvent *       nEditEvent;
395 
396         SELDATA_ITEMS       m_sdiState;
397 
398         sal_uInt16          m_nSelectLock;
399         sal_uInt16          m_nFormsSelected;
400         sal_uInt16          m_nControlsSelected;
401         sal_uInt16          m_nHiddenControls;      // (the number is included in m_nControlsSelected)
402 
403         bool            m_bDragDataDirty        : 1;    // ditto
404         bool            m_bPrevSelectionMixed   : 1;
405         bool            m_bRootSelected         : 1;
406         bool            m_bInitialUpdate        : 1;    // am I the first time in the UpdateContent?
407         bool            m_bKeyboardCut          : 1;
408         bool            m_bEditing              : 1;
409 
410         FmControlData*  NewControl(const OUString& rServiceName, const weld::TreeIter& rParentEntry, bool bEditName);
411         void            NewForm(const weld::TreeIter& rParentEntry);
412         std::unique_ptr<weld::TreeIter> Insert(FmEntryData* pEntryData, int nRelPos);
413         void            Remove( FmEntryData* pEntryData );
414 
415 
416         void CollectSelectionData(SELDATA_ITEMS sdiHow);
417             // Collects the currently selected entries in m_arrCurrentSelection, normalizes the list if requested.
418             // - SDI_NORMALIZED simply means that all entries that already have a selected ancestor are not collected.
419             // - SDI_NORMALIZED_FORMARK means that the procedure is the same as for SDI_NORMALIZED,
420             //   but entries whose direct parent is not selected are collected (independent of the
421             //   status of further ancestors). The same applies for forms that are selected,
422             //   regardless of the status of any ancestors.
423             // For both normalized modes, the m_nFormsSelected, ... contain the correct number,
424             // even if not all of these entries end up in m_arrCurrentSelection.
425             // SDI_DIRTY is of course not allowed as a parameter.
426 
427         // a single interface for all selected entries
428         void    ShowSelectionProperties(bool bForce = false);
429         // delete all selected elements
430         void    DeleteSelection();
431 
432         void SynchronizeSelection(FmEntryDataArray& arredToSelect);
433             // after calling this method, exactly the entries marked in the array are selected
434         void SynchronizeSelection();
435             // makes the same, takes the MarkList of the View
436         void SynchronizeMarkList();
437             // reverse direction of SynchronizeMarkList: selects in the view all controls corresponding to the current selection
438 
439         void CollectObjects(FmFormData const * pFormData, bool bDeep, ::std::set< css::uno::Reference< css::form::XFormComponent > >& _rObjects);
440 
441         // in the Select I usually update the Marklist of the corresponding view,
442         // with the following functions I can control the locking of this behavior
LockSelectionHandling()443         void LockSelectionHandling() { ++m_nSelectLock; }
UnlockSelectionHandling()444         void UnlockSelectionHandling() { --m_nSelectLock; }
IsSelectionHandlingLocked() const445         bool IsSelectionHandlingLocked() const { return m_nSelectLock>0; }
446 
IsEditingActive() const447         bool IsEditingActive() const { return m_bEditing; }
448 
449         static bool IsHiddenControl(FmEntryData const * pEntryData);
450 
451         DECL_LINK( KeyInputHdl, const KeyEvent&, bool );
452         DECL_LINK( PopupMenuHdl, const CommandEvent&, bool );
453 
454         DECL_LINK(EditingEntryHdl, const weld::TreeIter&, bool);
455         typedef std::pair<const weld::TreeIter&, OUString> IterString;
456         DECL_LINK(EditedEntryHdl, const IterString&, bool);
457 
458         DECL_LINK( OnEdit, void*, void );
459 
460         DECL_LINK( OnEntrySelDesel, weld::TreeView&, void );
461         DECL_LINK( OnSynchronizeTimer, Timer*, void );
462 
463         DECL_LINK( OnClipboardAction, OLocalExchange&, void );
464 
465         DECL_LINK( DragBeginHdl, bool&, bool );
466 
467     public:
468         NavigatorTree(std::unique_ptr<weld::TreeView> xTreeView);
469         virtual ~NavigatorTree() override;
470 
471         void Clear();
472         void UpdateContent( FmFormShell* pFormShell );
473         void MarkViewObj( FmFormData const * pFormData, bool bDeep );
474         void MarkViewObj( FmControlData const * pControlData );
475         void UnmarkAllViewObj();
476 
GrabFocus()477         void GrabFocus() { m_xTreeView->grab_focus(); }
478 
479         bool IsFormEntry(const weld::TreeIter& rEntry);
480         bool IsFormComponentEntry(const weld::TreeIter& rEntry);
481 
482         OUString GenerateName( FmEntryData const * pEntryData );
483 
GetNavModel() const484         NavigatorTreeModel*    GetNavModel() const { return m_pNavModel.get(); }
485         std::unique_ptr<weld::TreeIter> FindEntry(FmEntryData* pEntryData);
486 
487         virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
488 
get_widget()489         weld::TreeView& get_widget() { return *m_xTreeView; }
490 
491         sal_Int8    AcceptDrop(const AcceptDropEvent& rEvt);
492         sal_Int8    ExecuteDrop(const ExecuteDropEvent& rEvt);
493 
494     private:
495         sal_Int8    implAcceptDataTransfer( const DataFlavorExVector& _rFlavors, sal_Int8 _nAction, const weld::TreeIter* _pTargetEntry, bool _bDnD );
496 
497         sal_Int8    implExecuteDataTransfer( const OControlTransferData& _rData, sal_Int8 _nAction, const Point& _rDropPos, bool _bDnD );
498         sal_Int8    implExecuteDataTransfer( const OControlTransferData& _rData, sal_Int8 _nAction, const weld::TreeIter* _pTargetEntry, bool _bDnD );
499 
500         // check if a cut, copy, or drag operation can be started in the current situation
501         bool        implAllowExchange( sal_Int8 _nAction, bool* _pHasNonHidden = nullptr );
502         // check if a paste with the current clipboard content can be accepted
503         bool        implAcceptPaste( );
504 
505         // fills m_aControlExchange in preparation of a DnD or clipboard operation
506         bool        implPrepareExchange( sal_Int8 _nAction );
507 
508         void        ModelHasRemoved(const weld::TreeIter* _pEntry);
509 
510         void        doPaste();
511         void        doCopy();
512         void        doCut();
513 
doingKeyboardCut() const514         bool    doingKeyboardCut( ) const { return m_bKeyboardCut; }
515     };
516 
517     class NavigatorFrame : public SfxDockingWindow, public SfxControllerItem
518     {
519     private:
520         std::unique_ptr<NavigatorTree> m_xNavigatorTree;
521 
522     protected:
523         virtual bool Close() override;
524         virtual void GetFocus() override;
525         virtual Size CalcDockingSize( SfxChildAlignment ) override;
526         virtual SfxChildAlignment CheckAlignment( SfxChildAlignment, SfxChildAlignment ) override;
527 
528         using SfxDockingWindow::StateChanged;
529 
530     public:
531         NavigatorFrame( SfxBindings *pBindings, SfxChildWindow *pMgr,
532                        vcl::Window* pParent );
533         virtual ~NavigatorFrame() override;
534         virtual void dispose() override;
535 
536         void UpdateContent( FmFormShell* pFormShell );
537         void StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState ) override;
538         void FillInfo( SfxChildWinInfo& rInfo ) const override;
539     };
540 
541     class UNLESS_MERGELIBS(SVXCORE_DLLPUBLIC) NavigatorFrameManager : public SfxChildWindow
542     {
543     public:
544         SVX_DLLPRIVATE NavigatorFrameManager( vcl::Window *pParent, sal_uInt16 nId, SfxBindings *pBindings,
545                           SfxChildWinInfo *pInfo );
546         SFX_DECL_CHILDWINDOW( NavigatorFrameManager );
547     };
548 }
549 
550 #endif // INCLUDED_SVX_SOURCE_INC_FMEXPL_HXX
551 
552 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
553