/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DROP_ACTION_TIMER_INITIAL_TICKS 10 #define DROP_ACTION_TIMER_SCROLL_TICKS 3 #define DROP_ACTION_TIMER_TICK_BASE 10 namespace rptui { using namespace ::com::sun::star; using namespace utl; using namespace ::comphelper; static OUString lcl_getImageId(const uno::Reference< report::XReportComponent>& _xElement) { OUString sId; uno::Reference< report::XFixedLine> xFixedLine(_xElement,uno::UNO_QUERY); if ( uno::Reference< report::XFixedText>(_xElement,uno::UNO_QUERY).is() ) sId = RID_SVXBMP_FM_FIXEDTEXT; else if ( xFixedLine.is() ) sId = xFixedLine->getOrientation() ? OUStringLiteral(RID_SVXBMP_INSERT_VFIXEDLINE) : OUStringLiteral(RID_SVXBMP_INSERT_HFIXEDLINE); else if ( uno::Reference< report::XFormattedField>(_xElement,uno::UNO_QUERY).is() ) sId = RID_SVXBMP_FM_EDIT; else if ( uno::Reference< report::XImageControl>(_xElement,uno::UNO_QUERY).is() ) sId = RID_SVXBMP_FM_IMAGECONTROL; else if ( uno::Reference< report::XShape>(_xElement,uno::UNO_QUERY).is() ) sId = RID_SVXBMP_DRAWTBX_CS_BASIC; return sId; } static OUString lcl_getName(const uno::Reference< beans::XPropertySet>& _xElement) { OSL_ENSURE(_xElement.is(),"Found report element which is NULL!"); OUString sTempName; _xElement->getPropertyValue(PROPERTY_NAME) >>= sTempName; OUStringBuffer sName = sTempName; uno::Reference< report::XFixedText> xFixedText(_xElement,uno::UNO_QUERY); uno::Reference< report::XReportControlModel> xReportModel(_xElement,uno::UNO_QUERY); if ( xFixedText.is() ) { sName.append(" : "); sName.append(xFixedText->getLabel()); } else if ( xReportModel.is() && _xElement->getPropertySetInfo()->hasPropertyByName(PROPERTY_DATAFIELD) ) { ReportFormula aFormula( xReportModel->getDataField() ); if ( aFormula.isValid() ) { sName.append(" : "); sName.append( aFormula.getUndecoratedContent() ); } } return sName.makeStringAndClear(); } namespace { class NavigatorTree : public ::cppu::BaseMutex , public SvTreeListBox , public reportdesign::ITraverseReport , public comphelper::OSelectionChangeListener , public ::comphelper::OPropertyChangeListener { class UserData; friend class UserData; class UserData : public ::cppu::BaseMutex ,public ::comphelper::OPropertyChangeListener ,public ::comphelper::OContainerListener { uno::Reference< uno::XInterface > m_xContent; ::rtl::Reference< comphelper::OPropertyChangeMultiplexer> m_pListener; ::rtl::Reference< comphelper::OContainerListenerAdapter> m_pContainerListener; VclPtr m_pTree; public: UserData(NavigatorTree* _pTree,const uno::Reference& _xContent); virtual ~UserData() override; const uno::Reference< uno::XInterface >& getContent() const { return m_xContent; } void setContent(const uno::Reference< uno::XInterface >& _xContent) { m_xContent = _xContent; } protected: // OPropertyChangeListener virtual void _propertyChanged(const beans::PropertyChangeEvent& _rEvent) override; // OContainerListener virtual void _elementInserted( const container::ContainerEvent& _rEvent ) override; virtual void _elementRemoved( const container::ContainerEvent& Event ) override; virtual void _elementReplaced( const container::ContainerEvent& _rEvent ) override; virtual void _disposing(const lang::EventObject& _rSource) override; }; enum DROP_ACTION { DA_SCROLLUP, DA_SCROLLDOWN, DA_EXPANDNODE }; AutoTimer m_aDropActionTimer; Point m_aTimerTriggered; // position at which the DropTimer started DROP_ACTION m_aDropActionType; OReportController& m_rController; SvTreeListEntry* m_pMasterReport; SvTreeListEntry* m_pDragedEntry; ::rtl::Reference< comphelper::OPropertyChangeMultiplexer> m_pReportListener; ::rtl::Reference< comphelper::OSelectionChangeMultiplexer> m_pSelectionListener; unsigned short m_nTimerCounter; SvTreeListEntry* insertEntry(const OUString& _sName,SvTreeListEntry* _pParent, const OUString& rImageId, sal_uLong _nPosition,UserData* _pData); void traverseSection(const uno::Reference< report::XSection>& _xSection,SvTreeListEntry* _pParent, const OUString& rImageId, sal_uLong _nPosition = TREELIST_APPEND); void traverseFunctions(const uno::Reference< report::XFunctions>& _xFunctions,SvTreeListEntry* _pParent); protected: virtual void Command( const CommandEvent& rEvt ) override; // DragSourceHelper overridables virtual void StartDrag( sal_Int8 nAction, const Point& rPosPixel ) override; // DropTargetHelper overridables virtual sal_Int8 AcceptDrop( const AcceptDropEvent& _rEvt ) override; virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& _rEvt ) override; // OSelectionChangeListener virtual void _disposing(const lang::EventObject& _rSource) override; // OPropertyChangeListener virtual void _propertyChanged(const beans::PropertyChangeEvent& _rEvent) override; // OContainerListener Helper void _elementInserted( const container::ContainerEvent& _rEvent ); void _elementRemoved( const container::ContainerEvent& Event ); void _elementReplaced( const container::ContainerEvent& _rEvent ); public: NavigatorTree(vcl::Window* pParent,OReportController& _rController ); virtual ~NavigatorTree() override; virtual void dispose() override; DECL_LINK(OnEntrySelDesel, SvTreeListBox*, void); DECL_LINK( OnDropActionTimer, Timer*, void ); virtual void _selectionChanged( const lang::EventObject& aEvent ) override; // ITraverseReport virtual void traverseReport(const uno::Reference< report::XReportDefinition>& _xReport) override; virtual void traverseReportFunctions(const uno::Reference< report::XFunctions>& _xFunctions) override; virtual void traverseReportHeader(const uno::Reference< report::XSection>& _xSection) override; virtual void traverseReportFooter(const uno::Reference< report::XSection>& _xSection) override; virtual void traversePageHeader(const uno::Reference< report::XSection>& _xSection) override; virtual void traversePageFooter(const uno::Reference< report::XSection>& _xSection) override; virtual void traverseGroups(const uno::Reference< report::XGroups>& _xGroups) override; virtual void traverseGroup(const uno::Reference< report::XGroup>& _xGroup) override; virtual void traverseGroupFunctions(const uno::Reference< report::XFunctions>& _xFunctions) override; virtual void traverseGroupHeader(const uno::Reference< report::XSection>& _xSection) override; virtual void traverseGroupFooter(const uno::Reference< report::XSection>& _xSection) override; virtual void traverseDetail(const uno::Reference< report::XSection>& _xSection) override; SvTreeListEntry* find(const uno::Reference< uno::XInterface >& _xContent); void removeEntry(SvTreeListEntry* _pEntry,bool _bRemove = true); virtual Size GetOptimalSize() const override; private: using SvTreeListBox::ExecuteDrop; }; } NavigatorTree::NavigatorTree( vcl::Window* pParent,OReportController& _rController ) :SvTreeListBox( pParent, WB_TABSTOP| WB_HASBUTTONS|WB_HASLINES|WB_BORDER|WB_HSCROLL|WB_HASBUTTONSATROOT ) ,comphelper::OSelectionChangeListener() ,OPropertyChangeListener(m_aMutex) ,m_aTimerTriggered(-1,-1) ,m_aDropActionType( DA_SCROLLUP ) ,m_rController(_rController) ,m_pMasterReport(nullptr) ,m_pDragedEntry(nullptr) ,m_nTimerCounter( DROP_ACTION_TIMER_INITIAL_TICKS ) { set_hexpand(true); set_vexpand(true); m_pReportListener = new OPropertyChangeMultiplexer(this,m_rController.getReportDefinition().get()); m_pReportListener->addProperty(PROPERTY_PAGEHEADERON); m_pReportListener->addProperty(PROPERTY_PAGEFOOTERON); m_pReportListener->addProperty(PROPERTY_REPORTHEADERON); m_pReportListener->addProperty(PROPERTY_REPORTFOOTERON); m_pSelectionListener = new OSelectionChangeMultiplexer(this,&m_rController); SetHelpId( HID_REPORT_NAVIGATOR_TREE ); SetNodeBitmaps( Image(StockImage::Yes, RID_SVXBMP_COLLAPSEDNODE), Image(StockImage::Yes, RID_SVXBMP_EXPANDEDNODE) ); SetDragDropMode(DragDropMode::ALL); EnableInplaceEditing( false ); SetSelectionMode(SelectionMode::Multiple); Clear(); m_aDropActionTimer.SetInvokeHandler(LINK(this, NavigatorTree, OnDropActionTimer)); SetSelectHdl(LINK(this, NavigatorTree, OnEntrySelDesel)); SetDeselectHdl(LINK(this, NavigatorTree, OnEntrySelDesel)); } NavigatorTree::~NavigatorTree() { disposeOnce(); } void NavigatorTree::dispose() { SvTreeListEntry* pCurrent = First(); while ( pCurrent ) { delete static_cast(pCurrent->GetUserData()); pCurrent = Next(pCurrent); } m_pReportListener->dispose(); SvTreeListBox::dispose(); } namespace { sal_uInt16 mapIdent(const OString& rIdent) { if (rIdent == "sorting") return SID_SORTINGANDGROUPING; else if (rIdent == "page") return SID_PAGEHEADERFOOTER; else if (rIdent == "report") return SID_REPORTHEADERFOOTER; else if (rIdent == "function") return SID_RPT_NEW_FUNCTION; else if (rIdent == "properties") return SID_SHOW_PROPERTYBROWSER; else if (rIdent == "delete") return SID_DELETE; return 0; } } void NavigatorTree::Command( const CommandEvent& rEvt ) { bool bHandled = false; switch( rEvt.GetCommand()) { case CommandEventId::ContextMenu: { // the point that was clicked on SvTreeListEntry* ptClickedOn = nullptr; ::Point aWhere; if (rEvt.IsMouseEvent()) { aWhere = rEvt.GetMousePosPixel(); ptClickedOn = GetEntry(aWhere); if (ptClickedOn == nullptr) break; if ( !IsSelected(ptClickedOn) ) { SelectAll(false); Select(ptClickedOn); SetCurEntry(ptClickedOn); } } else { ptClickedOn = GetCurEntry(); if ( !ptClickedOn ) break; aWhere = GetEntryPosition(ptClickedOn); } UserData* pData = static_cast(ptClickedOn->GetUserData()); uno::Reference< report::XFunctionsSupplier> xSupplier(pData->getContent(),uno::UNO_QUERY); uno::Reference< report::XFunctions> xFunctions(pData->getContent(),uno::UNO_QUERY); uno::Reference< report::XGroup> xGroup(pData->getContent(),uno::UNO_QUERY); bool bDeleteAllowed = m_rController.isEditable() && (xGroup.is() || uno::Reference< report::XFunction>(pData->getContent(),uno::UNO_QUERY).is()); VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "modules/dbreport/ui/navigatormenu.ui", ""); VclPtr aContextMenu(aBuilder.get_menu("menu")); sal_uInt16 nCount = aContextMenu->GetItemCount(); for (sal_uInt16 i = 0; i < nCount; ++i) { if ( MenuItemType::SEPARATOR != aContextMenu->GetItemType(i)) { sal_uInt16 nMId = aContextMenu->GetItemId(i); sal_uInt16 nSId = mapIdent(aContextMenu->GetItemIdent(nMId)); aContextMenu->CheckItem(nMId, m_rController.isCommandChecked(nSId)); bool bEnabled = m_rController.isCommandEnabled(nSId); if (nSId == SID_RPT_NEW_FUNCTION) aContextMenu->EnableItem(nMId, m_rController.isEditable() && (xSupplier.is() || xFunctions.is())); // special condition, check for function and group else if (nSId == SID_DELETE) aContextMenu->EnableItem(nMId, bDeleteAllowed); else aContextMenu->EnableItem(nMId, bEnabled); } } if (aContextMenu->Execute(this, aWhere)) { sal_uInt16 nId = mapIdent(aContextMenu->GetCurItemIdent()); uno::Sequence< beans::PropertyValue> aArgs; if ( nId == SID_RPT_NEW_FUNCTION ) { aArgs.realloc(1); aArgs[0].Value <<= (xFunctions.is() ? xFunctions : xSupplier->getFunctions()); } else if ( nId == SID_DELETE ) { if ( xGroup.is() ) nId = SID_GROUP_REMOVE; aArgs.realloc(1); aArgs[0].Name = PROPERTY_GROUP; aArgs[0].Value <<= pData->getContent(); } m_rController.executeUnChecked(nId,aArgs); } bHandled = true; } break; default: break; } if (!bHandled) SvTreeListBox::Command( rEvt ); } sal_Int8 NavigatorTree::AcceptDrop( const AcceptDropEvent& _rEvt ) { ::Point aDropPos = _rEvt.maPosPixel; if (_rEvt.mbLeaving) { if (m_aDropActionTimer.IsActive()) m_aDropActionTimer.Stop(); } else { bool bNeedTrigger = false; // At the first record? if ((aDropPos.Y() >= 0) && (aDropPos.Y() < GetEntryHeight())) { m_aDropActionType = DA_SCROLLUP; bNeedTrigger = true; } else if ((aDropPos.Y() < GetSizePixel().Height()) && (aDropPos.Y() >= GetSizePixel().Height() - GetEntryHeight())) { m_aDropActionType = DA_SCROLLDOWN; bNeedTrigger = true; } else { SvTreeListEntry* pDroppedOn = GetEntry(aDropPos); if (pDroppedOn && (GetChildCount(pDroppedOn) > 0) && !IsExpanded(pDroppedOn)) { m_aDropActionType = DA_EXPANDNODE; bNeedTrigger = true; } } if (bNeedTrigger && (m_aTimerTriggered != aDropPos)) { // again start counting m_nTimerCounter = DROP_ACTION_TIMER_INITIAL_TICKS; // remember the position, because I also get AcceptDrops, if the mouse does not move m_aTimerTriggered = aDropPos; // start Timer if (!m_aDropActionTimer.IsActive()) // Does the Timer already exists? { m_aDropActionTimer.SetTimeout(DROP_ACTION_TIMER_TICK_BASE); m_aDropActionTimer.Start(); } } else if (!bNeedTrigger) m_aDropActionTimer.Stop(); } return DND_ACTION_NONE; } sal_Int8 NavigatorTree::ExecuteDrop( const ExecuteDropEvent& /*_rEvt*/ ) { return DND_ACTION_NONE; } void NavigatorTree::StartDrag( sal_Int8 /*_nAction*/, const Point& _rPosPixel ) { m_pDragedEntry = GetEntry(_rPosPixel); if ( m_pDragedEntry ) { EndSelection(); } } IMPL_LINK_NOARG(NavigatorTree, OnDropActionTimer, Timer *, void) { if (--m_nTimerCounter > 0) return; switch ( m_aDropActionType ) { case DA_EXPANDNODE: { SvTreeListEntry* pToExpand = GetEntry(m_aTimerTriggered); if (pToExpand && (GetChildCount(pToExpand) > 0) && !IsExpanded(pToExpand)) Expand(pToExpand); m_aDropActionTimer.Stop(); } break; case DA_SCROLLUP : ScrollOutputArea( 1 ); m_nTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS; break; case DA_SCROLLDOWN : ScrollOutputArea( -1 ); m_nTimerCounter = DROP_ACTION_TIMER_SCROLL_TICKS; break; } } IMPL_LINK_NOARG(NavigatorTree, OnEntrySelDesel, SvTreeListBox*, void) { if ( !m_pSelectionListener->locked() ) { m_pSelectionListener->lock(); SvTreeListEntry* pEntry = GetCurEntry(); uno::Any aSelection; if ( IsSelected(pEntry) ) aSelection <<= static_cast(pEntry->GetUserData())->getContent(); m_rController.select(aSelection); m_pSelectionListener->unlock(); } } void NavigatorTree::_selectionChanged( const lang::EventObject& aEvent ) { m_pSelectionListener->lock(); uno::Reference< view::XSelectionSupplier> xSelectionSupplier(aEvent.Source,uno::UNO_QUERY); uno::Any aSec = xSelectionSupplier->getSelection(); uno::Sequence< uno::Reference< report::XReportComponent > > aSelection; aSec >>= aSelection; if ( !aSelection.hasElements() ) { uno::Reference< uno::XInterface> xSelection(aSec,uno::UNO_QUERY); SvTreeListEntry* pEntry = find(xSelection); if ( pEntry && !IsSelected(pEntry) ) { Select(pEntry); SetCurEntry(pEntry); } else if ( !pEntry ) SelectAll(false,false); } else { for (const uno::Reference& rElem : std::as_const(aSelection)) { SvTreeListEntry* pEntry = find(rElem); if ( pEntry && !IsSelected(pEntry) ) { Select(pEntry); SetCurEntry(pEntry); } } } m_pSelectionListener->unlock(); } SvTreeListEntry* NavigatorTree::insertEntry(const OUString& _sName,SvTreeListEntry* _pParent, const OUString& rImageId, sal_uLong _nPosition,UserData* _pData) { SvTreeListEntry* pEntry = nullptr; if (!rImageId.isEmpty()) { const Image aImage(StockImage::Yes, rImageId); pEntry = InsertEntry(_sName,aImage,aImage,_pParent,false,_nPosition,_pData); } else pEntry = InsertEntry(_sName,_pParent,false,_nPosition,_pData); return pEntry; } void NavigatorTree::traverseSection(const uno::Reference< report::XSection>& _xSection,SvTreeListEntry* _pParent, const OUString& rImageId, sal_uLong _nPosition) { SvTreeListEntry* pSection = insertEntry(_xSection->getName(),_pParent, rImageId, _nPosition,new UserData(this,_xSection)); const sal_Int32 nCount = _xSection->getCount(); for (sal_Int32 i = 0; i < nCount; ++i) { uno::Reference< report::XReportComponent> xElement(_xSection->getByIndex(i),uno::UNO_QUERY_THROW); insertEntry(lcl_getName(xElement.get()),pSection,lcl_getImageId(xElement),TREELIST_APPEND,new UserData(this,xElement)); uno::Reference< report::XReportDefinition> xSubReport(xElement,uno::UNO_QUERY); if ( xSubReport.is() ) { m_pMasterReport = find(_xSection->getReportDefinition()); reportdesign::OReportVisitor aSubVisitor(this); aSubVisitor.start(xSubReport); } } } void NavigatorTree::traverseFunctions(const uno::Reference< report::XFunctions>& _xFunctions,SvTreeListEntry* _pParent) { SvTreeListEntry* pFunctions = insertEntry(RptResId(RID_STR_FUNCTIONS), _pParent, RID_SVXBMP_RPT_NEW_FUNCTION, TREELIST_APPEND, new UserData(this,_xFunctions)); const sal_Int32 nCount = _xFunctions->getCount(); for (sal_Int32 i = 0; i< nCount; ++i) { uno::Reference< report::XFunction> xElement(_xFunctions->getByIndex(i),uno::UNO_QUERY); insertEntry(xElement->getName(),pFunctions,RID_SVXBMP_RPT_NEW_FUNCTION,TREELIST_APPEND,new UserData(this,xElement)); } } SvTreeListEntry* NavigatorTree::find(const uno::Reference< uno::XInterface >& _xContent) { SvTreeListEntry* pRet = nullptr; if ( _xContent.is() ) { SvTreeListEntry* pCurrent = First(); while ( pCurrent ) { UserData* pData = static_cast(pCurrent->GetUserData()); OSL_ENSURE(pData,"No UserData set an entry!"); if ( pData->getContent() == _xContent ) { pRet = pCurrent; break; } pCurrent = Next(pCurrent); } } return pRet; } // ITraverseReport void NavigatorTree::traverseReport(const uno::Reference< report::XReportDefinition>& _xReport) { insertEntry(_xReport->getName(),m_pMasterReport,RID_SVXBMP_SELECT_REPORT,TREELIST_APPEND,new UserData(this,_xReport)); } void NavigatorTree::traverseReportFunctions(const uno::Reference< report::XFunctions>& _xFunctions) { SvTreeListEntry* pReport = find(_xFunctions->getParent()); traverseFunctions(_xFunctions,pReport); } void NavigatorTree::traverseReportHeader(const uno::Reference< report::XSection>& _xSection) { SvTreeListEntry* pReport = find(_xSection->getReportDefinition()); traverseSection(_xSection,pReport,RID_SVXBMP_REPORTHEADERFOOTER); } void NavigatorTree::traverseReportFooter(const uno::Reference< report::XSection>& _xSection) { SvTreeListEntry* pReport = find(_xSection->getReportDefinition()); traverseSection(_xSection,pReport,RID_SVXBMP_REPORTHEADERFOOTER); } void NavigatorTree::traversePageHeader(const uno::Reference< report::XSection>& _xSection) { SvTreeListEntry* pReport = find(_xSection->getReportDefinition()); traverseSection(_xSection,pReport,RID_SVXBMP_PAGEHEADERFOOTER); } void NavigatorTree::traversePageFooter(const uno::Reference< report::XSection>& _xSection) { SvTreeListEntry* pReport = find(_xSection->getReportDefinition()); traverseSection(_xSection,pReport,RID_SVXBMP_PAGEHEADERFOOTER); } void NavigatorTree::traverseGroups(const uno::Reference< report::XGroups>& _xGroups) { SvTreeListEntry* pReport = find(_xGroups->getReportDefinition()); insertEntry(RptResId(RID_STR_GROUPS), pReport, RID_SVXBMP_SORTINGANDGROUPING, TREELIST_APPEND, new UserData(this,_xGroups)); } void NavigatorTree::traverseGroup(const uno::Reference< report::XGroup>& _xGroup) { uno::Reference< report::XGroups> xGroups(_xGroup->getParent(),uno::UNO_QUERY); SvTreeListEntry* pGroups = find(xGroups); OSL_ENSURE(pGroups,"No Groups inserted so far. Why!"); insertEntry(_xGroup->getExpression(),pGroups,RID_SVXBMP_GROUP,rptui::getPositionInIndexAccess(xGroups.get(),_xGroup),new UserData(this,_xGroup)); } void NavigatorTree::traverseGroupFunctions(const uno::Reference< report::XFunctions>& _xFunctions) { SvTreeListEntry* pGroup = find(_xFunctions->getParent()); traverseFunctions(_xFunctions,pGroup); } void NavigatorTree::traverseGroupHeader(const uno::Reference< report::XSection>& _xSection) { SvTreeListEntry* pGroup = find(_xSection->getGroup()); OSL_ENSURE(pGroup,"No group found"); traverseSection(_xSection,pGroup,RID_SVXBMP_GROUPHEADER,1); } void NavigatorTree::traverseGroupFooter(const uno::Reference< report::XSection>& _xSection) { SvTreeListEntry* pGroup = find(_xSection->getGroup()); OSL_ENSURE(pGroup,"No group found"); traverseSection(_xSection,pGroup,RID_SVXBMP_GROUPFOOTER); } void NavigatorTree::traverseDetail(const uno::Reference< report::XSection>& _xSection) { uno::Reference< report::XReportDefinition> xReport = _xSection->getReportDefinition(); SvTreeListEntry* pParent = find(xReport); traverseSection(_xSection,pParent,RID_SVXBMP_ICON_DETAIL); } void NavigatorTree::_propertyChanged(const beans::PropertyChangeEvent& _rEvent) { uno::Reference< report::XReportDefinition> xReport(_rEvent.Source,uno::UNO_QUERY); if ( xReport.is() ) { bool bEnabled = false; _rEvent.NewValue >>= bEnabled; if ( bEnabled ) { SvTreeListEntry* pParent = find(xReport); if ( _rEvent.PropertyName == PROPERTY_REPORTHEADERON ) { sal_uLong nPos = xReport->getReportHeaderOn() ? 2 : 1; traverseSection(xReport->getReportHeader(),pParent,RID_SVXBMP_REPORTHEADERFOOTER,nPos); } else if ( _rEvent.PropertyName == PROPERTY_PAGEHEADERON ) { traverseSection(xReport->getPageHeader(),pParent, RID_SVXBMP_PAGEHEADERFOOTER,1); } else if ( _rEvent.PropertyName == PROPERTY_PAGEFOOTERON ) traverseSection(xReport->getPageFooter(),pParent, RID_SVXBMP_PAGEHEADERFOOTER); else if ( _rEvent.PropertyName == PROPERTY_REPORTFOOTERON ) { sal_uLong nPos = xReport->getPageFooterOn() ? (GetLevelChildCount(pParent) - 1) : TREELIST_APPEND; traverseSection(xReport->getReportFooter(),pParent,RID_SVXBMP_REPORTHEADERFOOTER,nPos); } } } } void NavigatorTree::_elementInserted( const container::ContainerEvent& _rEvent ) { SvTreeListEntry* pEntry = find(_rEvent.Source); uno::Reference xProp(_rEvent.Element,uno::UNO_QUERY_THROW); OUString sName; uno::Reference< beans::XPropertySetInfo> xInfo = xProp->getPropertySetInfo(); if ( xInfo.is() ) { if ( xInfo->hasPropertyByName(PROPERTY_NAME) ) xProp->getPropertyValue(PROPERTY_NAME) >>= sName; else if ( xInfo->hasPropertyByName(PROPERTY_EXPRESSION) ) xProp->getPropertyValue(PROPERTY_EXPRESSION) >>= sName; } uno::Reference< report::XGroup> xGroup(xProp,uno::UNO_QUERY); if ( xGroup.is() ) { reportdesign::OReportVisitor aSubVisitor(this); aSubVisitor.start(xGroup); } else { uno::Reference< report::XReportComponent> xElement(xProp,uno::UNO_QUERY); if ( xProp.is() ) sName = lcl_getName(xProp); insertEntry(sName,pEntry,(!xElement.is() ? OUString(RID_SVXBMP_RPT_NEW_FUNCTION) : lcl_getImageId(xElement)),TREELIST_APPEND,new UserData(this,xProp)); } if ( !IsExpanded(pEntry) ) Expand(pEntry); } void NavigatorTree::_elementRemoved( const container::ContainerEvent& _rEvent ) { uno::Reference xProp(_rEvent.Element,uno::UNO_QUERY); SvTreeListEntry* pEntry = find(xProp); OSL_ENSURE(pEntry,"NavigatorTree::_elementRemoved: No Entry found!"); if (pEntry) { removeEntry(pEntry); Invalidate(); } } void NavigatorTree::_elementReplaced( const container::ContainerEvent& _rEvent ) { uno::Reference xProp(_rEvent.ReplacedElement,uno::UNO_QUERY); SvTreeListEntry* pEntry = find(xProp); if ( pEntry ) { UserData* pData = static_cast(pEntry->GetUserData()); xProp.set(_rEvent.Element,uno::UNO_QUERY); pData->setContent(xProp); OUString sName; xProp->getPropertyValue(PROPERTY_NAME) >>= sName; SetEntryText(pEntry,sName); } } void NavigatorTree::_disposing(const lang::EventObject& _rSource) { removeEntry(find(_rSource.Source)); } void NavigatorTree::removeEntry(SvTreeListEntry* _pEntry,bool _bRemove) { if ( _pEntry ) { SvTreeListEntry* pChild = FirstChild(_pEntry); while( pChild ) { removeEntry(pChild,false); pChild = pChild->NextSibling(); } delete static_cast(_pEntry->GetUserData()); if ( _bRemove ) GetModel()->Remove(_pEntry); } } NavigatorTree::UserData::UserData(NavigatorTree* _pTree,const uno::Reference& _xContent) : OPropertyChangeListener(m_aMutex) , OContainerListener(m_aMutex) , m_xContent(_xContent) , m_pTree(_pTree) { uno::Reference xProp(m_xContent,uno::UNO_QUERY); if ( xProp.is() ) { uno::Reference< beans::XPropertySetInfo> xInfo = xProp->getPropertySetInfo(); if ( xInfo.is() ) { m_pListener = new ::comphelper::OPropertyChangeMultiplexer(this,xProp); if ( xInfo->hasPropertyByName(PROPERTY_NAME) ) m_pListener->addProperty(PROPERTY_NAME); else if ( xInfo->hasPropertyByName(PROPERTY_EXPRESSION) ) m_pListener->addProperty(PROPERTY_EXPRESSION); if ( xInfo->hasPropertyByName(PROPERTY_DATAFIELD) ) m_pListener->addProperty(PROPERTY_DATAFIELD); if ( xInfo->hasPropertyByName(PROPERTY_LABEL) ) m_pListener->addProperty(PROPERTY_LABEL); if ( xInfo->hasPropertyByName(PROPERTY_HEADERON) ) m_pListener->addProperty(PROPERTY_HEADERON); if ( xInfo->hasPropertyByName(PROPERTY_FOOTERON) ) m_pListener->addProperty(PROPERTY_FOOTERON); } } uno::Reference< container::XContainer> xContainer(m_xContent,uno::UNO_QUERY); if ( xContainer.is() ) { m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer); } } NavigatorTree::UserData::~UserData() { if ( m_pContainerListener.is() ) m_pContainerListener->dispose(); if ( m_pListener.is() ) m_pListener->dispose(); } // OPropertyChangeListener void NavigatorTree::UserData::_propertyChanged(const beans::PropertyChangeEvent& _rEvent) { SvTreeListEntry* pEntry = m_pTree->find(_rEvent.Source); OSL_ENSURE(pEntry,"No entry could be found! Why not!"); const bool bFooterOn = (PROPERTY_FOOTERON == _rEvent.PropertyName); try { if ( bFooterOn || PROPERTY_HEADERON == _rEvent.PropertyName ) { sal_Int32 nPos = 1; uno::Reference< report::XGroup> xGroup(_rEvent.Source,uno::UNO_QUERY); ::std::function pIsOn = ::std::mem_fn(&OGroupHelper::getHeaderOn); ::std::function(OGroupHelper *)> pMemFunSection = ::std::mem_fn(&OGroupHelper::getHeader); if ( bFooterOn ) { pIsOn = ::std::mem_fn(&OGroupHelper::getFooterOn); pMemFunSection = ::std::mem_fn(&OGroupHelper::getFooter); nPos = m_pTree->GetChildCount(pEntry) - 1; } OGroupHelper aGroupHelper(xGroup); if ( pIsOn(&aGroupHelper) ) { if ( bFooterOn ) ++nPos; m_pTree->traverseSection(pMemFunSection(&aGroupHelper),pEntry,bFooterOn ? OUString(RID_SVXBMP_GROUPFOOTER) : OUString(RID_SVXBMP_GROUPHEADER),nPos); } } else if ( PROPERTY_EXPRESSION == _rEvent.PropertyName) { OUString sNewName; _rEvent.NewValue >>= sNewName; m_pTree->SetEntryText(pEntry,sNewName); } else if ( PROPERTY_DATAFIELD == _rEvent.PropertyName || PROPERTY_LABEL == _rEvent.PropertyName || PROPERTY_NAME == _rEvent.PropertyName ) { uno::Reference xProp(_rEvent.Source,uno::UNO_QUERY); m_pTree->SetEntryText(pEntry,lcl_getName(xProp)); } } catch(const uno::Exception &) {} } void NavigatorTree::UserData::_elementInserted( const container::ContainerEvent& _rEvent ) { m_pTree->_elementInserted( _rEvent ); } void NavigatorTree::UserData::_elementRemoved( const container::ContainerEvent& _rEvent ) { m_pTree->_elementRemoved( _rEvent ); } void NavigatorTree::UserData::_elementReplaced( const container::ContainerEvent& _rEvent ) { m_pTree->_elementReplaced( _rEvent ); } void NavigatorTree::UserData::_disposing(const lang::EventObject& _rSource) { m_pTree->_disposing( _rSource ); } Size NavigatorTree::GetOptimalSize() const { return LogicToPixel(Size(100, 70), MapMode(MapUnit::MapAppFont)); } class ONavigatorImpl { public: ONavigatorImpl(OReportController& _rController,ONavigator* _pParent); ONavigatorImpl(const ONavigatorImpl&) = delete; ONavigatorImpl& operator=(const ONavigatorImpl&) = delete; uno::Reference< report::XReportDefinition> m_xReport; ::rptui::OReportController& m_rController; VclPtr m_pNavigatorTree; }; ONavigatorImpl::ONavigatorImpl(OReportController& _rController,ONavigator* _pParent) :m_xReport(_rController.getReportDefinition()) ,m_rController(_rController) ,m_pNavigatorTree(VclPtr::Create(_pParent->get("box"),_rController)) { reportdesign::OReportVisitor aVisitor(m_pNavigatorTree.get()); aVisitor.start(m_xReport); m_pNavigatorTree->Expand(m_pNavigatorTree->find(m_xReport)); lang::EventObject aEvent(m_rController); m_pNavigatorTree->_selectionChanged(aEvent); } ONavigator::ONavigator(vcl::Window* _pParent ,OReportController& _rController) : FloatingWindow( _pParent, "FloatingNavigator", "modules/dbreport/ui/floatingnavigator.ui") { m_pImpl.reset(new ONavigatorImpl(_rController,this)); m_pImpl->m_pNavigatorTree->Show(); m_pImpl->m_pNavigatorTree->GrabFocus(); Show(); } void ONavigator::GetFocus() { Window::GetFocus(); if ( m_pImpl->m_pNavigatorTree.get() ) m_pImpl->m_pNavigatorTree->GrabFocus(); } void ONavigator::dispose() { m_pImpl->m_pNavigatorTree.disposeAndClear(); FloatingWindow::dispose(); } } // rptui /* vim:set shiftwidth=4 softtabstop=4 expandtab: */