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 <Navigator.hxx>
21 
22 #include <strings.hxx>
23 #include <bitmaps.hlst>
24 #include <ReportController.hxx>
25 #include <UITools.hxx>
26 #include <RptUndo.hxx>
27 #include <reportformula.hxx>
28 #include <com/sun/star/container/XContainerListener.hpp>
29 #include <com/sun/star/report/XReportDefinition.hpp>
30 #include <com/sun/star/report/XFixedText.hpp>
31 #include <com/sun/star/report/XFixedLine.hpp>
32 #include <com/sun/star/report/XFormattedField.hpp>
33 #include <com/sun/star/report/XImageControl.hpp>
34 #include <com/sun/star/report/XShape.hpp>
35 #include <helpids.h>
36 #include <strings.hrc>
37 #include <rptui_slotid.hrc>
38 #include <comphelper/propmultiplex.hxx>
39 #include <comphelper/containermultiplexer.hxx>
40 #include <cppuhelper/basemutex.hxx>
41 #include <comphelper/SelectionMultiplex.hxx>
42 #include <vcl/treelistbox.hxx>
43 #include <vcl/treelistentry.hxx>
44 #include <vcl/commandevent.hxx>
45 #include <svl/solar.hrc>
46 #include <ReportVisitor.hxx>
47 #include <core_resource.hxx>
48 #include <rtl/ref.hxx>
49 
50 #include <memory>
51 #include <algorithm>
52 
53 #define DROP_ACTION_TIMER_INITIAL_TICKS     10
54 #define DROP_ACTION_TIMER_SCROLL_TICKS      3
55 #define DROP_ACTION_TIMER_TICK_BASE         10
56 
57 namespace rptui
58 {
59 using namespace ::com::sun::star;
60 using namespace utl;
61 using namespace ::comphelper;
62 
lcl_getImageId(const uno::Reference<report::XReportComponent> & _xElement)63 static OUString lcl_getImageId(const uno::Reference< report::XReportComponent>& _xElement)
64 {
65     OUString sId;
66     uno::Reference< report::XFixedLine> xFixedLine(_xElement,uno::UNO_QUERY);
67     if ( uno::Reference< report::XFixedText>(_xElement,uno::UNO_QUERY).is() )
68         sId = RID_SVXBMP_FM_FIXEDTEXT;
69     else if ( xFixedLine.is() )
70         sId = xFixedLine->getOrientation() ? OUStringLiteral(RID_SVXBMP_INSERT_VFIXEDLINE) : OUStringLiteral(RID_SVXBMP_INSERT_HFIXEDLINE);
71     else if ( uno::Reference< report::XFormattedField>(_xElement,uno::UNO_QUERY).is() )
72         sId = RID_SVXBMP_FM_EDIT;
73     else if ( uno::Reference< report::XImageControl>(_xElement,uno::UNO_QUERY).is() )
74         sId = RID_SVXBMP_FM_IMAGECONTROL;
75     else if ( uno::Reference< report::XShape>(_xElement,uno::UNO_QUERY).is() )
76         sId = RID_SVXBMP_DRAWTBX_CS_BASIC;
77     return sId;
78 }
79 
lcl_getName(const uno::Reference<beans::XPropertySet> & _xElement)80 static OUString lcl_getName(const uno::Reference< beans::XPropertySet>& _xElement)
81 {
82     OSL_ENSURE(_xElement.is(),"Found report element which is NULL!");
83     OUString sTempName;
84     _xElement->getPropertyValue(PROPERTY_NAME) >>= sTempName;
85     OUStringBuffer sName = sTempName;
86     uno::Reference< report::XFixedText> xFixedText(_xElement,uno::UNO_QUERY);
87     uno::Reference< report::XReportControlModel> xReportModel(_xElement,uno::UNO_QUERY);
88     if ( xFixedText.is() )
89     {
90         sName.append(" : ");
91         sName.append(xFixedText->getLabel());
92     }
93     else if ( xReportModel.is() && _xElement->getPropertySetInfo()->hasPropertyByName(PROPERTY_DATAFIELD) )
94     {
95         ReportFormula aFormula( xReportModel->getDataField() );
96         if ( aFormula.isValid() )
97         {
98             sName.append(" : ");
99             sName.append( aFormula.getUndecoratedContent() );
100         }
101     }
102     return sName.makeStringAndClear();
103 }
104 
105 
106 class NavigatorTree :   public ::cppu::BaseMutex
107                     ,   public SvTreeListBox
108                     ,   public reportdesign::ITraverseReport
109                     ,   public comphelper::OSelectionChangeListener
110                     ,   public ::comphelper::OPropertyChangeListener
111 {
112     class UserData;
113     friend class UserData;
114     class UserData : public ::cppu::BaseMutex
115                     ,public ::comphelper::OPropertyChangeListener
116                     ,public ::comphelper::OContainerListener
117     {
118         uno::Reference< uno::XInterface >                           m_xContent;
119         ::rtl::Reference< comphelper::OPropertyChangeMultiplexer>   m_pListener;
120         ::rtl::Reference< comphelper::OContainerListenerAdapter>    m_pContainerListener;
121         VclPtr<NavigatorTree>                                       m_pTree;
122     public:
123         UserData(NavigatorTree* _pTree,const uno::Reference<uno::XInterface>& _xContent);
124         virtual ~UserData() override;
125 
getContent() const126         const uno::Reference< uno::XInterface >& getContent() const { return m_xContent; }
setContent(const uno::Reference<uno::XInterface> & _xContent)127         void setContent(const uno::Reference< uno::XInterface >& _xContent) { m_xContent = _xContent; }
128 
129     protected:
130         // OPropertyChangeListener
131         virtual void _propertyChanged(const beans::PropertyChangeEvent& _rEvent) override;
132 
133         // OContainerListener
134         virtual void _elementInserted( const container::ContainerEvent& _rEvent ) override;
135         virtual void _elementRemoved( const container::ContainerEvent& Event ) override;
136         virtual void _elementReplaced( const container::ContainerEvent& _rEvent ) override;
137         virtual void _disposing(const lang::EventObject& _rSource) override;
138     };
139 
140     enum DROP_ACTION        { DA_SCROLLUP, DA_SCROLLDOWN, DA_EXPANDNODE };
141     AutoTimer                                                                   m_aDropActionTimer;
142     Point                                                                       m_aTimerTriggered;      // position at which the DropTimer started
143     DROP_ACTION                                                                 m_aDropActionType;
144     OReportController&                                                          m_rController;
145     SvTreeListEntry*                                                                m_pMasterReport;
146     SvTreeListEntry*                                                                m_pDragedEntry;
147     ::rtl::Reference< comphelper::OPropertyChangeMultiplexer>                   m_pReportListener;
148     ::rtl::Reference< comphelper::OSelectionChangeMultiplexer>                  m_pSelectionListener;
149     unsigned short                                                              m_nTimerCounter;
150 
151     SvTreeListEntry* insertEntry(const OUString& _sName,SvTreeListEntry* _pParent, const OUString& rImageId, sal_uLong _nPosition,UserData* _pData);
152     void traverseSection(const uno::Reference< report::XSection>& _xSection,SvTreeListEntry* _pParent, const OUString& rImageId, sal_uLong _nPosition = TREELIST_APPEND);
153     void traverseFunctions(const uno::Reference< report::XFunctions>& _xFunctions,SvTreeListEntry* _pParent);
154 
155 protected:
156     virtual void        Command( const CommandEvent& rEvt ) override;
157     // DragSourceHelper overridables
158     virtual void        StartDrag( sal_Int8 nAction, const Point& rPosPixel ) override;
159     // DropTargetHelper overridables
160     virtual sal_Int8    AcceptDrop( const AcceptDropEvent& _rEvt ) override;
161     virtual sal_Int8    ExecuteDrop( const ExecuteDropEvent& _rEvt ) override;
162 
163     // OSelectionChangeListener
164     virtual void _disposing(const lang::EventObject& _rSource) override;
165 
166     // OPropertyChangeListener
167     virtual void _propertyChanged(const beans::PropertyChangeEvent& _rEvent) override;
168 
169     // OContainerListener Helper
170     void _elementInserted( const container::ContainerEvent& _rEvent );
171     void _elementRemoved( const container::ContainerEvent& Event );
172     void _elementReplaced( const container::ContainerEvent& _rEvent );
173 
174 public:
175     NavigatorTree(vcl::Window* pParent,OReportController& _rController );
176     virtual ~NavigatorTree() override;
177     virtual void dispose() override;
178 
179     DECL_LINK(OnEntrySelDesel, SvTreeListBox*, void);
180     DECL_LINK( OnDropActionTimer, Timer*, void );
181 
182     virtual void _selectionChanged( const lang::EventObject& aEvent ) override;
183 
184     // ITraverseReport
185     virtual void traverseReport(const uno::Reference< report::XReportDefinition>& _xReport) override;
186     virtual void traverseReportFunctions(const uno::Reference< report::XFunctions>& _xFunctions) override;
187     virtual void traverseReportHeader(const uno::Reference< report::XSection>& _xSection) override;
188     virtual void traverseReportFooter(const uno::Reference< report::XSection>& _xSection) override;
189     virtual void traversePageHeader(const uno::Reference< report::XSection>& _xSection) override;
190     virtual void traversePageFooter(const uno::Reference< report::XSection>& _xSection) override;
191 
192     virtual void traverseGroups(const uno::Reference< report::XGroups>& _xGroups) override;
193     virtual void traverseGroup(const uno::Reference< report::XGroup>& _xGroup) override;
194     virtual void traverseGroupFunctions(const uno::Reference< report::XFunctions>& _xFunctions) override;
195     virtual void traverseGroupHeader(const uno::Reference< report::XSection>& _xSection) override;
196     virtual void traverseGroupFooter(const uno::Reference< report::XSection>& _xSection) override;
197 
198     virtual void traverseDetail(const uno::Reference< report::XSection>& _xSection) override;
199 
200     SvTreeListEntry* find(const uno::Reference< uno::XInterface >& _xContent);
201     void removeEntry(SvTreeListEntry* _pEntry,bool _bRemove = true);
202 
203     virtual Size GetOptimalSize() const override;
204 private:
205     using SvTreeListBox::ExecuteDrop;
206 };
207 
NavigatorTree(vcl::Window * pParent,OReportController & _rController)208 NavigatorTree::NavigatorTree( vcl::Window* pParent,OReportController& _rController )
209         :SvTreeListBox( pParent, WB_TABSTOP| WB_HASBUTTONS|WB_HASLINES|WB_BORDER|WB_HSCROLL|WB_HASBUTTONSATROOT )
210         ,comphelper::OSelectionChangeListener()
211         ,OPropertyChangeListener(m_aMutex)
212         ,m_aTimerTriggered(-1,-1)
213         ,m_aDropActionType( DA_SCROLLUP )
214         ,m_rController(_rController)
215         ,m_pMasterReport(nullptr)
216         ,m_pDragedEntry(nullptr)
217         ,m_nTimerCounter( DROP_ACTION_TIMER_INITIAL_TICKS )
218 {
219     set_hexpand(true);
220     set_vexpand(true);
221 
222     m_pReportListener = new OPropertyChangeMultiplexer(this,m_rController.getReportDefinition().get());
223     m_pReportListener->addProperty(PROPERTY_PAGEHEADERON);
224     m_pReportListener->addProperty(PROPERTY_PAGEFOOTERON);
225     m_pReportListener->addProperty(PROPERTY_REPORTHEADERON);
226     m_pReportListener->addProperty(PROPERTY_REPORTFOOTERON);
227 
228     m_pSelectionListener = new OSelectionChangeMultiplexer(this,&m_rController);
229 
230     SetHelpId( HID_REPORT_NAVIGATOR_TREE );
231 
232     SetNodeBitmaps(
233         Image(StockImage::Yes, RID_SVXBMP_COLLAPSEDNODE),
234         Image(StockImage::Yes, RID_SVXBMP_EXPANDEDNODE)
235     );
236 
237     SetDragDropMode(DragDropMode::ALL);
238     EnableInplaceEditing( false );
239     SetSelectionMode(SelectionMode::Multiple);
240     Clear();
241 
242     m_aDropActionTimer.SetInvokeHandler(LINK(this, NavigatorTree, OnDropActionTimer));
243     SetSelectHdl(LINK(this, NavigatorTree, OnEntrySelDesel));
244     SetDeselectHdl(LINK(this, NavigatorTree, OnEntrySelDesel));
245 }
246 
~NavigatorTree()247 NavigatorTree::~NavigatorTree()
248 {
249     disposeOnce();
250 }
251 
dispose()252 void NavigatorTree::dispose()
253 {
254     SvTreeListEntry* pCurrent = First();
255     while ( pCurrent )
256     {
257         delete static_cast<UserData*>(pCurrent->GetUserData());
258         pCurrent = Next(pCurrent);
259     }
260     m_pReportListener->dispose();
261     SvTreeListBox::dispose();
262 }
263 
264 namespace
265 {
mapIdent(const OString & rIdent)266     sal_uInt16 mapIdent(const OString& rIdent)
267     {
268         if (rIdent == "sorting")
269             return SID_SORTINGANDGROUPING;
270         else if (rIdent == "page")
271             return SID_PAGEHEADERFOOTER;
272         else if (rIdent == "report")
273             return SID_REPORTHEADERFOOTER;
274         else if (rIdent == "function")
275             return SID_RPT_NEW_FUNCTION;
276         else if (rIdent == "properties")
277             return SID_SHOW_PROPERTYBROWSER;
278         else if (rIdent == "delete")
279             return SID_DELETE;
280         return 0;
281     }
282 }
283 
Command(const CommandEvent & rEvt)284 void NavigatorTree::Command( const CommandEvent& rEvt )
285 {
286     bool bHandled = false;
287     switch( rEvt.GetCommand())
288     {
289     case CommandEventId::ContextMenu:
290         {
291             // the point that was clicked on
292             SvTreeListEntry* ptClickedOn = nullptr;
293             ::Point aWhere;
294             if (rEvt.IsMouseEvent())
295             {
296                 aWhere = rEvt.GetMousePosPixel();
297                 ptClickedOn = GetEntry(aWhere);
298                 if (ptClickedOn == nullptr)
299                     break;
300                 if ( !IsSelected(ptClickedOn) )
301                 {
302                     SelectAll(false);
303                     Select(ptClickedOn);
304                     SetCurEntry(ptClickedOn);
305                 }
306             }
307             else
308             {
309                 ptClickedOn = GetCurEntry();
310                 if ( !ptClickedOn )
311                     break;
312                 aWhere = GetEntryPosition(ptClickedOn);
313             }
314             UserData* pData = static_cast<UserData*>(ptClickedOn->GetUserData());
315             uno::Reference< report::XFunctionsSupplier> xSupplier(pData->getContent(),uno::UNO_QUERY);
316             uno::Reference< report::XFunctions> xFunctions(pData->getContent(),uno::UNO_QUERY);
317             uno::Reference< report::XGroup> xGroup(pData->getContent(),uno::UNO_QUERY);
318             bool bDeleteAllowed = m_rController.isEditable() && (xGroup.is() ||
319                                       uno::Reference< report::XFunction>(pData->getContent(),uno::UNO_QUERY).is());
320 
321             VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "modules/dbreport/ui/navigatormenu.ui", "");
322             VclPtr<PopupMenu> aContextMenu(aBuilder.get_menu("menu"));
323 
324             sal_uInt16 nCount = aContextMenu->GetItemCount();
325             for (sal_uInt16 i = 0; i < nCount; ++i)
326             {
327                 if ( MenuItemType::SEPARATOR != aContextMenu->GetItemType(i))
328                 {
329                     sal_uInt16 nMId = aContextMenu->GetItemId(i);
330                     sal_uInt16 nSId = mapIdent(aContextMenu->GetItemIdent(nMId));
331 
332                     aContextMenu->CheckItem(nMId, m_rController.isCommandChecked(nSId));
333                     bool bEnabled = m_rController.isCommandEnabled(nSId);
334                     if (nSId == SID_RPT_NEW_FUNCTION)
335                         aContextMenu->EnableItem(nMId, m_rController.isEditable() && (xSupplier.is() || xFunctions.is()));
336                     // special condition, check for function and group
337                     else if (nSId == SID_DELETE)
338                         aContextMenu->EnableItem(nMId, bDeleteAllowed);
339                     else
340                         aContextMenu->EnableItem(nMId, bEnabled);
341                 }
342             }
343 
344             if (aContextMenu->Execute(this, aWhere))
345             {
346                 sal_uInt16 nId = mapIdent(aContextMenu->GetCurItemIdent());
347                 uno::Sequence< beans::PropertyValue> aArgs;
348                 if ( nId == SID_RPT_NEW_FUNCTION )
349                 {
350                     aArgs.realloc(1);
351                     aArgs[0].Value <<= (xFunctions.is() ? xFunctions : xSupplier->getFunctions());
352                 }
353                 else if ( nId == SID_DELETE )
354                 {
355                     if ( xGroup.is() )
356                         nId = SID_GROUP_REMOVE;
357                     aArgs.realloc(1);
358                     aArgs[0].Name = PROPERTY_GROUP;
359                     aArgs[0].Value <<= pData->getContent();
360                 }
361                 m_rController.executeUnChecked(nId,aArgs);
362             }
363 
364             bHandled = true;
365         }
366         break;
367         default: break;
368     }
369 
370     if (!bHandled)
371         SvTreeListBox::Command( rEvt );
372 }
373 
AcceptDrop(const AcceptDropEvent & _rEvt)374 sal_Int8 NavigatorTree::AcceptDrop( const AcceptDropEvent& _rEvt )
375 {
376     ::Point aDropPos = _rEvt.maPosPixel;
377     if (_rEvt.mbLeaving)
378     {
379         if (m_aDropActionTimer.IsActive())
380             m_aDropActionTimer.Stop();
381     }
382     else
383     {
384         bool bNeedTrigger = false;
385         // At the first record?
386         if ((aDropPos.Y() >= 0) && (aDropPos.Y() < GetEntryHeight()))
387         {
388             m_aDropActionType = DA_SCROLLUP;
389             bNeedTrigger = true;
390         }
391         else if ((aDropPos.Y() < GetSizePixel().Height()) && (aDropPos.Y() >= GetSizePixel().Height() - GetEntryHeight()))
392         {
393             m_aDropActionType = DA_SCROLLDOWN;
394             bNeedTrigger = true;
395         }
396         else
397         {
398             SvTreeListEntry* pDroppedOn = GetEntry(aDropPos);
399             if (pDroppedOn && (GetChildCount(pDroppedOn) > 0) && !IsExpanded(pDroppedOn))
400             {
401                 m_aDropActionType = DA_EXPANDNODE;
402                 bNeedTrigger = true;
403             }
404         }
405 
406         if (bNeedTrigger && (m_aTimerTriggered != aDropPos))
407         {
408             // again start counting
409             m_nTimerCounter = DROP_ACTION_TIMER_INITIAL_TICKS;
410             // remember the position, because I also get AcceptDrops, if the mouse does not move
411             m_aTimerTriggered = aDropPos;
412             // start Timer
413             if (!m_aDropActionTimer.IsActive()) // Does the Timer already exists?
414             {
415                 m_aDropActionTimer.SetTimeout(DROP_ACTION_TIMER_TICK_BASE);
416                 m_aDropActionTimer.Start();
417             }
418         }
419         else if (!bNeedTrigger)
420             m_aDropActionTimer.Stop();
421     }
422 
423     return DND_ACTION_NONE;
424 }
425 
ExecuteDrop(const ExecuteDropEvent &)426 sal_Int8 NavigatorTree::ExecuteDrop( const ExecuteDropEvent& /*_rEvt*/ )
427 {
428     return DND_ACTION_NONE;
429 }
430 
StartDrag(sal_Int8,const Point & _rPosPixel)431 void NavigatorTree::StartDrag( sal_Int8 /*_nAction*/, const Point& _rPosPixel )
432 {
433     m_pDragedEntry = GetEntry(_rPosPixel);
434     if ( m_pDragedEntry )
435     {
436         EndSelection();
437     }
438 }
439 
IMPL_LINK_NOARG(NavigatorTree,OnDropActionTimer,Timer *,void)440 IMPL_LINK_NOARG(NavigatorTree, OnDropActionTimer, Timer *, void)
441 {
442     if (--m_nTimerCounter > 0)
443         return;
444 
445     switch ( m_aDropActionType )
446     {
447         case DA_EXPANDNODE:
448         {
449             SvTreeListEntry* pToExpand = GetEntry(m_aTimerTriggered);
450             if (pToExpand && (GetChildCount(pToExpand) > 0) &&  !IsExpanded(pToExpand))
451                 Expand(pToExpand);
452             m_aDropActionTimer.Stop();
453         }
454         break;
455 
456         case DA_SCROLLUP :
457             ScrollOutputArea( 1 );
458             m_nTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS;
459             break;
460 
461         case DA_SCROLLDOWN :
462             ScrollOutputArea( -1 );
463             m_nTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS;
464             break;
465 
466     }
467 }
468 
469 
IMPL_LINK_NOARG(NavigatorTree,OnEntrySelDesel,SvTreeListBox *,void)470 IMPL_LINK_NOARG(NavigatorTree, OnEntrySelDesel, SvTreeListBox*, void)
471 {
472     if ( !m_pSelectionListener->locked() )
473     {
474         m_pSelectionListener->lock();
475         SvTreeListEntry* pEntry = GetCurEntry();
476         uno::Any aSelection;
477         if ( IsSelected(pEntry) )
478             aSelection <<= static_cast<UserData*>(pEntry->GetUserData())->getContent();
479         m_rController.select(aSelection);
480         m_pSelectionListener->unlock();
481     }
482 }
483 
_selectionChanged(const lang::EventObject & aEvent)484 void NavigatorTree::_selectionChanged( const lang::EventObject& aEvent )
485 {
486     m_pSelectionListener->lock();
487     uno::Reference< view::XSelectionSupplier> xSelectionSupplier(aEvent.Source,uno::UNO_QUERY);
488     uno::Any aSec = xSelectionSupplier->getSelection();
489     uno::Sequence< uno::Reference< report::XReportComponent > > aSelection;
490     aSec >>= aSelection;
491     if ( !aSelection.hasElements() )
492     {
493         uno::Reference< uno::XInterface> xSelection(aSec,uno::UNO_QUERY);
494         SvTreeListEntry* pEntry = find(xSelection);
495         if ( pEntry && !IsSelected(pEntry) )
496         {
497             Select(pEntry);
498             SetCurEntry(pEntry);
499         }
500         else if ( !pEntry )
501             SelectAll(false,false);
502     }
503     else
504     {
505         for (const uno::Reference<report::XReportComponent>& rElem : std::as_const(aSelection))
506         {
507             SvTreeListEntry* pEntry = find(rElem);
508             if ( pEntry && !IsSelected(pEntry) )
509             {
510                 Select(pEntry);
511                 SetCurEntry(pEntry);
512             }
513         }
514     }
515     m_pSelectionListener->unlock();
516 }
517 
insertEntry(const OUString & _sName,SvTreeListEntry * _pParent,const OUString & rImageId,sal_uLong _nPosition,UserData * _pData)518 SvTreeListEntry* NavigatorTree::insertEntry(const OUString& _sName,SvTreeListEntry* _pParent, const OUString& rImageId, sal_uLong _nPosition,UserData* _pData)
519 {
520     SvTreeListEntry* pEntry = nullptr;
521     if (!rImageId.isEmpty())
522     {
523         const Image aImage(StockImage::Yes, rImageId);
524         pEntry = InsertEntry(_sName,aImage,aImage,_pParent,false,_nPosition,_pData);
525     }
526     else
527         pEntry = InsertEntry(_sName,_pParent,false,_nPosition,_pData);
528     return pEntry;
529 }
530 
traverseSection(const uno::Reference<report::XSection> & _xSection,SvTreeListEntry * _pParent,const OUString & rImageId,sal_uLong _nPosition)531 void NavigatorTree::traverseSection(const uno::Reference< report::XSection>& _xSection,SvTreeListEntry* _pParent, const OUString& rImageId, sal_uLong _nPosition)
532 {
533     SvTreeListEntry* pSection = insertEntry(_xSection->getName(),_pParent, rImageId, _nPosition,new UserData(this,_xSection));
534     const sal_Int32 nCount = _xSection->getCount();
535     for (sal_Int32 i = 0; i < nCount; ++i)
536     {
537         uno::Reference< report::XReportComponent> xElement(_xSection->getByIndex(i),uno::UNO_QUERY_THROW);
538         insertEntry(lcl_getName(xElement.get()),pSection,lcl_getImageId(xElement),TREELIST_APPEND,new UserData(this,xElement));
539         uno::Reference< report::XReportDefinition> xSubReport(xElement,uno::UNO_QUERY);
540         if ( xSubReport.is() )
541         {
542             m_pMasterReport = find(_xSection->getReportDefinition());
543             reportdesign::OReportVisitor aSubVisitor(this);
544             aSubVisitor.start(xSubReport);
545         }
546     }
547 }
548 
traverseFunctions(const uno::Reference<report::XFunctions> & _xFunctions,SvTreeListEntry * _pParent)549 void NavigatorTree::traverseFunctions(const uno::Reference< report::XFunctions>& _xFunctions,SvTreeListEntry* _pParent)
550 {
551     SvTreeListEntry* pFunctions = insertEntry(RptResId(RID_STR_FUNCTIONS), _pParent, RID_SVXBMP_RPT_NEW_FUNCTION, TREELIST_APPEND, new UserData(this,_xFunctions));
552     const sal_Int32 nCount = _xFunctions->getCount();
553     for (sal_Int32 i = 0; i< nCount; ++i)
554     {
555         uno::Reference< report::XFunction> xElement(_xFunctions->getByIndex(i),uno::UNO_QUERY);
556         insertEntry(xElement->getName(),pFunctions,RID_SVXBMP_RPT_NEW_FUNCTION,TREELIST_APPEND,new UserData(this,xElement));
557     }
558 }
559 
find(const uno::Reference<uno::XInterface> & _xContent)560 SvTreeListEntry* NavigatorTree::find(const uno::Reference< uno::XInterface >& _xContent)
561 {
562     SvTreeListEntry* pRet = nullptr;
563     if ( _xContent.is() )
564     {
565         SvTreeListEntry* pCurrent = First();
566         while ( pCurrent )
567         {
568             UserData* pData = static_cast<UserData*>(pCurrent->GetUserData());
569             OSL_ENSURE(pData,"No UserData set an entry!");
570             if ( pData->getContent() == _xContent )
571             {
572                 pRet = pCurrent;
573                 break;
574             }
575             pCurrent = Next(pCurrent);
576         }
577     }
578     return pRet;
579 }
580 
581 // ITraverseReport
582 
traverseReport(const uno::Reference<report::XReportDefinition> & _xReport)583 void NavigatorTree::traverseReport(const uno::Reference< report::XReportDefinition>& _xReport)
584 {
585     insertEntry(_xReport->getName(),m_pMasterReport,RID_SVXBMP_SELECT_REPORT,TREELIST_APPEND,new UserData(this,_xReport));
586 }
587 
traverseReportFunctions(const uno::Reference<report::XFunctions> & _xFunctions)588 void NavigatorTree::traverseReportFunctions(const uno::Reference< report::XFunctions>& _xFunctions)
589 {
590     SvTreeListEntry* pReport = find(_xFunctions->getParent());
591     traverseFunctions(_xFunctions,pReport);
592 }
593 
traverseReportHeader(const uno::Reference<report::XSection> & _xSection)594 void NavigatorTree::traverseReportHeader(const uno::Reference< report::XSection>& _xSection)
595 {
596     SvTreeListEntry* pReport = find(_xSection->getReportDefinition());
597     traverseSection(_xSection,pReport,RID_SVXBMP_REPORTHEADERFOOTER);
598 }
599 
traverseReportFooter(const uno::Reference<report::XSection> & _xSection)600 void NavigatorTree::traverseReportFooter(const uno::Reference< report::XSection>& _xSection)
601 {
602     SvTreeListEntry* pReport = find(_xSection->getReportDefinition());
603     traverseSection(_xSection,pReport,RID_SVXBMP_REPORTHEADERFOOTER);
604 }
605 
traversePageHeader(const uno::Reference<report::XSection> & _xSection)606 void NavigatorTree::traversePageHeader(const uno::Reference< report::XSection>& _xSection)
607 {
608     SvTreeListEntry* pReport = find(_xSection->getReportDefinition());
609     traverseSection(_xSection,pReport,RID_SVXBMP_PAGEHEADERFOOTER);
610 }
611 
traversePageFooter(const uno::Reference<report::XSection> & _xSection)612 void NavigatorTree::traversePageFooter(const uno::Reference< report::XSection>& _xSection)
613 {
614     SvTreeListEntry* pReport = find(_xSection->getReportDefinition());
615     traverseSection(_xSection,pReport,RID_SVXBMP_PAGEHEADERFOOTER);
616 }
617 
traverseGroups(const uno::Reference<report::XGroups> & _xGroups)618 void NavigatorTree::traverseGroups(const uno::Reference< report::XGroups>& _xGroups)
619 {
620     SvTreeListEntry* pReport = find(_xGroups->getReportDefinition());
621     insertEntry(RptResId(RID_STR_GROUPS), pReport, RID_SVXBMP_SORTINGANDGROUPING, TREELIST_APPEND, new UserData(this,_xGroups));
622 }
623 
traverseGroup(const uno::Reference<report::XGroup> & _xGroup)624 void NavigatorTree::traverseGroup(const uno::Reference< report::XGroup>& _xGroup)
625 {
626     uno::Reference< report::XGroups> xGroups(_xGroup->getParent(),uno::UNO_QUERY);
627     SvTreeListEntry* pGroups = find(xGroups);
628     OSL_ENSURE(pGroups,"No Groups inserted so far. Why!");
629     insertEntry(_xGroup->getExpression(),pGroups,RID_SVXBMP_GROUP,rptui::getPositionInIndexAccess(xGroups.get(),_xGroup),new UserData(this,_xGroup));
630 }
631 
traverseGroupFunctions(const uno::Reference<report::XFunctions> & _xFunctions)632 void NavigatorTree::traverseGroupFunctions(const uno::Reference< report::XFunctions>& _xFunctions)
633 {
634     SvTreeListEntry* pGroup = find(_xFunctions->getParent());
635     traverseFunctions(_xFunctions,pGroup);
636 }
637 
traverseGroupHeader(const uno::Reference<report::XSection> & _xSection)638 void NavigatorTree::traverseGroupHeader(const uno::Reference< report::XSection>& _xSection)
639 {
640     SvTreeListEntry* pGroup = find(_xSection->getGroup());
641     OSL_ENSURE(pGroup,"No group found");
642     traverseSection(_xSection,pGroup,RID_SVXBMP_GROUPHEADER,1);
643 }
644 
traverseGroupFooter(const uno::Reference<report::XSection> & _xSection)645 void NavigatorTree::traverseGroupFooter(const uno::Reference< report::XSection>& _xSection)
646 {
647     SvTreeListEntry* pGroup = find(_xSection->getGroup());
648     OSL_ENSURE(pGroup,"No group found");
649     traverseSection(_xSection,pGroup,RID_SVXBMP_GROUPFOOTER);
650 }
651 
traverseDetail(const uno::Reference<report::XSection> & _xSection)652 void NavigatorTree::traverseDetail(const uno::Reference< report::XSection>& _xSection)
653 {
654     uno::Reference< report::XReportDefinition> xReport = _xSection->getReportDefinition();
655     SvTreeListEntry* pParent = find(xReport);
656     traverseSection(_xSection,pParent,RID_SVXBMP_ICON_DETAIL);
657 }
658 
_propertyChanged(const beans::PropertyChangeEvent & _rEvent)659 void NavigatorTree::_propertyChanged(const beans::PropertyChangeEvent& _rEvent)
660 {
661     uno::Reference< report::XReportDefinition> xReport(_rEvent.Source,uno::UNO_QUERY);
662     if ( xReport.is() )
663     {
664         bool bEnabled = false;
665         _rEvent.NewValue >>= bEnabled;
666         if ( bEnabled )
667         {
668             SvTreeListEntry* pParent = find(xReport);
669             if ( _rEvent.PropertyName == PROPERTY_REPORTHEADERON )
670             {
671                 sal_uLong nPos = xReport->getReportHeaderOn() ? 2 : 1;
672                 traverseSection(xReport->getReportHeader(),pParent,RID_SVXBMP_REPORTHEADERFOOTER,nPos);
673             }
674             else if ( _rEvent.PropertyName == PROPERTY_PAGEHEADERON )
675             {
676                 traverseSection(xReport->getPageHeader(),pParent, RID_SVXBMP_PAGEHEADERFOOTER,1);
677             }
678             else if ( _rEvent.PropertyName == PROPERTY_PAGEFOOTERON )
679                 traverseSection(xReport->getPageFooter(),pParent, RID_SVXBMP_PAGEHEADERFOOTER);
680             else if ( _rEvent.PropertyName == PROPERTY_REPORTFOOTERON )
681             {
682                 sal_uLong nPos = xReport->getPageFooterOn() ? (GetLevelChildCount(pParent) - 1) : TREELIST_APPEND;
683                 traverseSection(xReport->getReportFooter(),pParent,RID_SVXBMP_REPORTHEADERFOOTER,nPos);
684             }
685         }
686     }
687 }
688 
_elementInserted(const container::ContainerEvent & _rEvent)689 void NavigatorTree::_elementInserted( const container::ContainerEvent& _rEvent )
690 {
691     SvTreeListEntry* pEntry = find(_rEvent.Source);
692     uno::Reference<beans::XPropertySet> xProp(_rEvent.Element,uno::UNO_QUERY_THROW);
693     OUString sName;
694     uno::Reference< beans::XPropertySetInfo> xInfo = xProp->getPropertySetInfo();
695     if ( xInfo.is() )
696     {
697         if ( xInfo->hasPropertyByName(PROPERTY_NAME) )
698             xProp->getPropertyValue(PROPERTY_NAME) >>= sName;
699         else if ( xInfo->hasPropertyByName(PROPERTY_EXPRESSION) )
700             xProp->getPropertyValue(PROPERTY_EXPRESSION) >>= sName;
701     }
702     uno::Reference< report::XGroup> xGroup(xProp,uno::UNO_QUERY);
703     if ( xGroup.is() )
704     {
705         reportdesign::OReportVisitor aSubVisitor(this);
706         aSubVisitor.start(xGroup);
707     }
708     else
709     {
710         uno::Reference< report::XReportComponent> xElement(xProp,uno::UNO_QUERY);
711         if ( xProp.is() )
712             sName = lcl_getName(xProp);
713         insertEntry(sName,pEntry,(!xElement.is() ? OUString(RID_SVXBMP_RPT_NEW_FUNCTION) : lcl_getImageId(xElement)),TREELIST_APPEND,new UserData(this,xProp));
714     }
715     if ( !IsExpanded(pEntry) )
716         Expand(pEntry);
717 }
718 
_elementRemoved(const container::ContainerEvent & _rEvent)719 void NavigatorTree::_elementRemoved( const container::ContainerEvent& _rEvent )
720 {
721     uno::Reference<beans::XPropertySet> xProp(_rEvent.Element,uno::UNO_QUERY);
722     SvTreeListEntry* pEntry = find(xProp);
723     OSL_ENSURE(pEntry,"NavigatorTree::_elementRemoved: No Entry found!");
724 
725     if (pEntry)
726     {
727         removeEntry(pEntry);
728         Invalidate();
729     }
730 }
731 
_elementReplaced(const container::ContainerEvent & _rEvent)732 void NavigatorTree::_elementReplaced( const container::ContainerEvent& _rEvent )
733 {
734     uno::Reference<beans::XPropertySet> xProp(_rEvent.ReplacedElement,uno::UNO_QUERY);
735     SvTreeListEntry* pEntry = find(xProp);
736     if ( pEntry )
737     {
738         UserData* pData = static_cast<UserData*>(pEntry->GetUserData());
739         xProp.set(_rEvent.Element,uno::UNO_QUERY);
740         pData->setContent(xProp);
741         OUString sName;
742         xProp->getPropertyValue(PROPERTY_NAME) >>= sName;
743         SetEntryText(pEntry,sName);
744     }
745 }
746 
_disposing(const lang::EventObject & _rSource)747 void NavigatorTree::_disposing(const lang::EventObject& _rSource)
748 {
749     removeEntry(find(_rSource.Source));
750 }
751 
removeEntry(SvTreeListEntry * _pEntry,bool _bRemove)752 void NavigatorTree::removeEntry(SvTreeListEntry* _pEntry,bool _bRemove)
753 {
754     if ( _pEntry )
755     {
756         SvTreeListEntry* pChild = FirstChild(_pEntry);
757         while( pChild )
758         {
759             removeEntry(pChild,false);
760             pChild = pChild->NextSibling();
761         }
762         delete static_cast<UserData*>(_pEntry->GetUserData());
763         if ( _bRemove )
764             GetModel()->Remove(_pEntry);
765     }
766 }
767 
UserData(NavigatorTree * _pTree,const uno::Reference<uno::XInterface> & _xContent)768 NavigatorTree::UserData::UserData(NavigatorTree* _pTree,const uno::Reference<uno::XInterface>& _xContent)
769     : OPropertyChangeListener(m_aMutex)
770     , OContainerListener(m_aMutex)
771     , m_xContent(_xContent)
772     , m_pTree(_pTree)
773 {
774     uno::Reference<beans::XPropertySet> xProp(m_xContent,uno::UNO_QUERY);
775     if ( xProp.is() )
776     {
777         uno::Reference< beans::XPropertySetInfo> xInfo = xProp->getPropertySetInfo();
778         if ( xInfo.is() )
779         {
780             m_pListener = new ::comphelper::OPropertyChangeMultiplexer(this,xProp);
781             if ( xInfo->hasPropertyByName(PROPERTY_NAME) )
782                 m_pListener->addProperty(PROPERTY_NAME);
783             else if ( xInfo->hasPropertyByName(PROPERTY_EXPRESSION) )
784                 m_pListener->addProperty(PROPERTY_EXPRESSION);
785             if ( xInfo->hasPropertyByName(PROPERTY_DATAFIELD) )
786                 m_pListener->addProperty(PROPERTY_DATAFIELD);
787             if ( xInfo->hasPropertyByName(PROPERTY_LABEL) )
788                 m_pListener->addProperty(PROPERTY_LABEL);
789             if ( xInfo->hasPropertyByName(PROPERTY_HEADERON) )
790                 m_pListener->addProperty(PROPERTY_HEADERON);
791             if ( xInfo->hasPropertyByName(PROPERTY_FOOTERON) )
792                 m_pListener->addProperty(PROPERTY_FOOTERON);
793         }
794     }
795     uno::Reference< container::XContainer> xContainer(m_xContent,uno::UNO_QUERY);
796     if ( xContainer.is() )
797     {
798         m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer);
799     }
800 }
801 
~UserData()802 NavigatorTree::UserData::~UserData()
803 {
804     if ( m_pContainerListener.is() )
805         m_pContainerListener->dispose();
806     if ( m_pListener.is() )
807         m_pListener->dispose();
808 }
809 
810 // OPropertyChangeListener
_propertyChanged(const beans::PropertyChangeEvent & _rEvent)811 void NavigatorTree::UserData::_propertyChanged(const beans::PropertyChangeEvent& _rEvent)
812 {
813     SvTreeListEntry* pEntry = m_pTree->find(_rEvent.Source);
814     OSL_ENSURE(pEntry,"No entry could be found! Why not!");
815     const bool bFooterOn = (PROPERTY_FOOTERON == _rEvent.PropertyName);
816     try
817     {
818         if ( bFooterOn || PROPERTY_HEADERON == _rEvent.PropertyName )
819         {
820             sal_Int32 nPos = 1;
821             uno::Reference< report::XGroup> xGroup(_rEvent.Source,uno::UNO_QUERY);
822             ::std::function<bool(OGroupHelper *)> pIsOn = ::std::mem_fn(&OGroupHelper::getHeaderOn);
823             ::std::function<uno::Reference<report::XSection>(OGroupHelper *)> pMemFunSection = ::std::mem_fn(&OGroupHelper::getHeader);
824             if ( bFooterOn )
825             {
826                 pIsOn = ::std::mem_fn(&OGroupHelper::getFooterOn);
827                 pMemFunSection = ::std::mem_fn(&OGroupHelper::getFooter);
828                 nPos = m_pTree->GetChildCount(pEntry) - 1;
829             }
830 
831             OGroupHelper aGroupHelper(xGroup);
832             if ( pIsOn(&aGroupHelper) )
833             {
834                 if ( bFooterOn )
835                     ++nPos;
836                 m_pTree->traverseSection(pMemFunSection(&aGroupHelper),pEntry,bFooterOn ? OUString(RID_SVXBMP_GROUPFOOTER) : OUString(RID_SVXBMP_GROUPHEADER),nPos);
837             }
838         }
839         else if ( PROPERTY_EXPRESSION == _rEvent.PropertyName)
840         {
841             OUString sNewName;
842             _rEvent.NewValue >>= sNewName;
843             m_pTree->SetEntryText(pEntry,sNewName);
844         }
845         else if ( PROPERTY_DATAFIELD == _rEvent.PropertyName || PROPERTY_LABEL == _rEvent.PropertyName || PROPERTY_NAME == _rEvent.PropertyName )
846         {
847             uno::Reference<beans::XPropertySet> xProp(_rEvent.Source,uno::UNO_QUERY);
848             m_pTree->SetEntryText(pEntry,lcl_getName(xProp));
849         }
850     }
851     catch(const uno::Exception &)
852     {}
853 }
854 
_elementInserted(const container::ContainerEvent & _rEvent)855 void NavigatorTree::UserData::_elementInserted( const container::ContainerEvent& _rEvent )
856 {
857     m_pTree->_elementInserted( _rEvent );
858 }
859 
_elementRemoved(const container::ContainerEvent & _rEvent)860 void NavigatorTree::UserData::_elementRemoved( const container::ContainerEvent& _rEvent )
861 {
862     m_pTree->_elementRemoved( _rEvent );
863 }
864 
_elementReplaced(const container::ContainerEvent & _rEvent)865 void NavigatorTree::UserData::_elementReplaced( const container::ContainerEvent& _rEvent )
866 {
867     m_pTree->_elementReplaced( _rEvent );
868 }
869 
_disposing(const lang::EventObject & _rSource)870 void NavigatorTree::UserData::_disposing(const lang::EventObject& _rSource)
871 {
872     m_pTree->_disposing( _rSource );
873 }
874 
GetOptimalSize() const875 Size NavigatorTree::GetOptimalSize() const
876 {
877     return LogicToPixel(Size(100, 70), MapMode(MapUnit::MapAppFont));
878 }
879 
880 // class ONavigatorImpl
881 class ONavigatorImpl
882 {
883 public:
884     ONavigatorImpl(OReportController& _rController,ONavigator* _pParent);
885     ONavigatorImpl(const ONavigatorImpl&) = delete;
886     ONavigatorImpl& operator=(const ONavigatorImpl&) = delete;
887 
888     uno::Reference< report::XReportDefinition>  m_xReport;
889     ::rptui::OReportController&                 m_rController;
890     VclPtr<NavigatorTree>                       m_pNavigatorTree;
891 };
892 
ONavigatorImpl(OReportController & _rController,ONavigator * _pParent)893 ONavigatorImpl::ONavigatorImpl(OReportController& _rController,ONavigator* _pParent)
894     :m_xReport(_rController.getReportDefinition())
895     ,m_rController(_rController)
896     ,m_pNavigatorTree(VclPtr<NavigatorTree>::Create(_pParent->get<vcl::Window>("box"),_rController))
897 {
898     reportdesign::OReportVisitor aVisitor(m_pNavigatorTree.get());
899     aVisitor.start(m_xReport);
900     m_pNavigatorTree->Expand(m_pNavigatorTree->find(m_xReport));
901     lang::EventObject aEvent(m_rController);
902     m_pNavigatorTree->_selectionChanged(aEvent);
903 }
904 
905 // class ONavigator
ONavigator(vcl::Window * _pParent,OReportController & _rController)906 ONavigator::ONavigator(vcl::Window* _pParent ,OReportController& _rController)
907     : FloatingWindow( _pParent, "FloatingNavigator", "modules/dbreport/ui/floatingnavigator.ui")
908 {
909     m_pImpl.reset(new ONavigatorImpl(_rController,this));
910 
911     m_pImpl->m_pNavigatorTree->Show();
912     m_pImpl->m_pNavigatorTree->GrabFocus();
913     Show();
914 }
915 
GetFocus()916 void ONavigator::GetFocus()
917 {
918     Window::GetFocus();
919     if ( m_pImpl->m_pNavigatorTree.get() )
920         m_pImpl->m_pNavigatorTree->GrabFocus();
921 }
922 
dispose()923 void ONavigator::dispose()
924 {
925     m_pImpl->m_pNavigatorTree.disposeAndClear();
926     FloatingWindow::dispose();
927 }
928 
929 } // rptui
930 
931 
932 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
933