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