/* -*- 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 "GroupExchange.hxx" #include #include #include #include #include #include #include #include #include #include #define HANDLE_ID 0 #define FIELD_EXPRESSION 1 #define GROUPS_START_LEN 5 #define NO_GROUP -1 namespace rptui { using namespace ::com::sun::star; using namespace svt; using namespace ::comphelper; void lcl_addToList_throw( ComboBoxControl& _rListBox, ::std::vector& o_aColumnList,const uno::Reference< container::XNameAccess>& i_xColumns ) { uno::Sequence< OUString > aEntries = i_xColumns->getElementNames(); const OUString* pEntries = aEntries.getConstArray(); sal_Int32 nEntries = aEntries.getLength(); for ( sal_Int32 i = 0; i < nEntries; ++i, ++pEntries ) { uno::Reference< beans::XPropertySet> xColumn(i_xColumns->getByName(*pEntries),uno::UNO_QUERY_THROW); OUString sLabel; if ( xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_LABEL) ) xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel; o_aColumnList.emplace_back(*pEntries,sLabel ); if ( !sLabel.isEmpty() ) _rListBox.InsertEntry( sLabel ); else _rListBox.InsertEntry( *pEntries ); } } /** * Separated out from OFieldExpressionControl to prevent collision of ref-counted base classes */ class OFieldExpressionControl; class OFieldExpressionControlContainerListener : public ::cppu::WeakImplHelper< container::XContainerListener > { VclPtr mpParent; public: explicit OFieldExpressionControlContainerListener(OFieldExpressionControl* pParent) : mpParent(pParent) {} // XEventListener virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; // XContainerListener virtual void SAL_CALL elementInserted(const css::container::ContainerEvent& rEvent) override; virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent& rEvent) override; virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent& rEvent) override; }; class OFieldExpressionControl : public ::svt::EditBrowseBox { ::osl::Mutex m_aMutex; ::std::vector m_aGroupPositions; ::std::vector m_aColumnInfo; VclPtr< ::svt::ComboBoxControl> m_pComboCell; sal_Int32 m_nDataPos; sal_Int32 m_nCurrentPos; ImplSVEvent * m_nDeleteEvent; VclPtr m_pParent; bool m_bIgnoreEvent; rtl::Reference aContainerListener; public: OFieldExpressionControl(OGroupsSortingDialog* _pParentDialog, vcl::Window *_pParent); virtual ~OFieldExpressionControl() override; virtual void dispose() override; // XContainerListener /// @throws css::uno::RuntimeException void elementInserted(const css::container::ContainerEvent& rEvent); /// @throws css::uno::RuntimeException void elementRemoved(const css::container::ContainerEvent& rEvent); virtual Size GetOptimalSize() const override; void fillColumns(const uno::Reference< container::XNameAccess>& _xColumns); void lateInit(); bool IsDeleteAllowed( ); void DeleteRows(); sal_Int32 getGroupPosition(sal_Int32 _nRow) const { return _nRow != BROWSER_ENDOFSELECTION ? m_aGroupPositions[_nRow] : sal_Int32(NO_GROUP); } ::svt::ComboBoxControl* getExpressionControl() const { return m_pComboCell; } /** returns the sequence with the selected groups */ uno::Sequence fillSelectedGroups(); /** move groups given by _aGroups */ void moveGroups(const uno::Sequence& _aGroups,sal_Int32 _nRow,bool _bSelect = true); virtual bool CursorMoving(long nNewRow, sal_uInt16 nNewCol) override; using ::svt::EditBrowseBox::GetRowCount; protected: virtual bool IsTabAllowed(bool bForward) const override; virtual void InitController( ::svt::CellControllerRef& rController, long nRow, sal_uInt16 nCol ) override; virtual ::svt::CellController* GetController( long nRow, sal_uInt16 nCol ) override; virtual void PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColId ) const override; virtual bool SeekRow( long nRow ) override; virtual bool SaveModified() override; virtual OUString GetCellText( long nRow, sal_uInt16 nColId ) const override; virtual RowStatus GetRowStatus(long nRow) const override; virtual void KeyInput(const KeyEvent& rEvt) override; virtual void Command( const CommandEvent& rEvt ) override; // D&D virtual void StartDrag( sal_Int8 nAction, const Point& rPosPixel ) override; virtual sal_Int8 AcceptDrop( const BrowserAcceptDropEvent& rEvt ) override; virtual sal_Int8 ExecuteDrop( const BrowserExecuteDropEvent& rEvt ) override; using BrowseBox::AcceptDrop; using BrowseBox::ExecuteDrop; private: DECL_LINK( CBChangeHdl, ComboBox&, void); public: DECL_LINK( DelayedDelete, void*, void ); }; void OFieldExpressionControlContainerListener::disposing(const css::lang::EventObject& ) {} void OFieldExpressionControlContainerListener::elementInserted(const css::container::ContainerEvent& rEvent) { mpParent->elementInserted(rEvent); } void OFieldExpressionControlContainerListener::elementReplaced(const css::container::ContainerEvent& ) {} void OFieldExpressionControlContainerListener::elementRemoved(const css::container::ContainerEvent& rEvent) { mpParent->elementRemoved(rEvent); } // class OFieldExpressionControl OFieldExpressionControl::OFieldExpressionControl(OGroupsSortingDialog* _pParentDialog, vcl::Window *_pParent) :EditBrowseBox( _pParent, EditBrowseBoxFlags::NONE, WB_TABSTOP, BrowserMode::COLUMNSELECTION | BrowserMode::MULTISELECTION | BrowserMode::AUTOSIZE_LASTCOL | BrowserMode::KEEPHIGHLIGHT | BrowserMode::HLINES | BrowserMode::VLINES) ,m_aGroupPositions(GROUPS_START_LEN,-1) ,m_pComboCell(nullptr) ,m_nDataPos(-1) ,m_nCurrentPos(-1) ,m_nDeleteEvent(nullptr) ,m_pParent(_pParentDialog) ,m_bIgnoreEvent(false) ,aContainerListener(new OFieldExpressionControlContainerListener(this)) { SetBorderStyle(WindowBorderStyle::MONO); } OFieldExpressionControl::~OFieldExpressionControl() { disposeOnce(); } void OFieldExpressionControl::dispose() { uno::Reference< report::XGroups > xGroups = m_pParent->getGroups(); xGroups->removeContainerListener(aContainerListener.get()); // delete events from queue if( m_nDeleteEvent ) Application::RemoveUserEvent( m_nDeleteEvent ); m_pComboCell.disposeAndClear(); m_pParent.clear(); ::svt::EditBrowseBox::dispose(); } uno::Sequence OFieldExpressionControl::fillSelectedGroups() { uno::Sequence aList; ::std::vector vClipboardList; vClipboardList.reserve(GetSelectRowCount()); uno::Reference xGroups = m_pParent->getGroups(); sal_Int32 nCount = xGroups->getCount(); if ( nCount >= 1 ) { for( long nIndex=FirstSelectedRow(); nIndex != SFX_ENDOFSELECTION; nIndex=NextSelectedRow() ) { try { if ( m_aGroupPositions[nIndex] != NO_GROUP ) { uno::Reference< report::XGroup> xOrgGroup(xGroups->getByIndex(m_aGroupPositions[nIndex]),uno::UNO_QUERY); /*uno::Reference< report::XGroup> xCopy = xGroups->createGroup(); ::comphelper::copyProperties(xOrgGroup.get(),xCopy.get());*/ vClipboardList.push_back( uno::makeAny(xOrgGroup) ); } } catch(uno::Exception&) { OSL_FAIL("Can not access group!"); } } if ( !vClipboardList.empty() ) aList = uno::Sequence< uno::Any >(&vClipboardList[0], vClipboardList.size()); } return aList; } void OFieldExpressionControl::StartDrag( sal_Int8 /*_nAction*/ , const Point& /*_rPosPixel*/ ) { if ( m_pParent && !m_pParent->isReadOnly( ) ) { uno::Sequence aClipboardList = fillSelectedGroups(); if( aClipboardList.getLength() ) { rtl::Reference pData = new OGroupExchange(aClipboardList); pData->StartDrag(this, DND_ACTION_MOVE ); } } } sal_Int8 OFieldExpressionControl::AcceptDrop( const BrowserAcceptDropEvent& rEvt ) { sal_Int8 nAction = DND_ACTION_NONE; if ( IsEditing() ) { sal_Int32 nPos = m_pComboCell->GetSelectedEntryPos(); if ( COMBOBOX_ENTRY_NOTFOUND != nPos || !m_pComboCell->GetText().isEmpty() ) SaveModified(); DeactivateCell(); } if ( IsDropFormatSupported( OGroupExchange::getReportGroupId() ) && m_pParent->getGroups()->getCount() > 1 && rEvt.GetWindow() == &GetDataWindow() ) { nAction = DND_ACTION_MOVE; } return nAction; } sal_Int8 OFieldExpressionControl::ExecuteDrop( const BrowserExecuteDropEvent& rEvt ) { sal_Int8 nAction = DND_ACTION_NONE; if ( IsDropFormatSupported( OGroupExchange::getReportGroupId() ) ) { sal_Int32 nRow = GetRowAtYPosPixel(rEvt.maPosPixel.Y(), false); SetNoSelection(); TransferableDataHelper aDropped( rEvt.maDropEvent.Transferable ); uno::Any aDrop = aDropped.GetAny(OGroupExchange::getReportGroupId(), OUString()); uno::Sequence< uno::Any > aGroups; aDrop >>= aGroups; if ( aGroups.getLength() ) { moveGroups(aGroups,nRow); nAction = DND_ACTION_MOVE; } } return nAction; } void OFieldExpressionControl::moveGroups(const uno::Sequence& _aGroups,sal_Int32 _nRow,bool _bSelect) { if ( _aGroups.getLength() ) { m_bIgnoreEvent = true; { sal_Int32 nRow = _nRow; const OUString sUndoAction(RptResId(RID_STR_UNDO_MOVE_GROUP)); const UndoContext aUndoContext( m_pParent->m_pController->getUndoManager(), sUndoAction ); uno::Reference< report::XGroups> xGroups = m_pParent->getGroups(); const uno::Any* pIter = _aGroups.getConstArray(); const uno::Any* pEnd = pIter + _aGroups.getLength(); for(;pIter != pEnd;++pIter) { uno::Reference< report::XGroup> xGroup(*pIter,uno::UNO_QUERY); if ( xGroup.is() ) { uno::Sequence< beans::PropertyValue > aArgs(1); aArgs[0].Name = PROPERTY_GROUP; aArgs[0].Value <<= xGroup; // we use this way to create undo actions m_pParent->m_pController->executeChecked(SID_GROUP_REMOVE,aArgs); aArgs.realloc(2); if ( nRow > xGroups->getCount() ) nRow = xGroups->getCount(); if ( _bSelect ) SelectRow(nRow); aArgs[1].Name = PROPERTY_POSITIONY; aArgs[1].Value <<= nRow; m_pParent->m_pController->executeChecked(SID_GROUP_APPEND,aArgs); ++nRow; } } } m_bIgnoreEvent = false; Invalidate(); } } void OFieldExpressionControl::fillColumns(const uno::Reference< container::XNameAccess>& _xColumns) { m_pComboCell->Clear(); if ( _xColumns.is() ) lcl_addToList_throw(*m_pComboCell,m_aColumnInfo,_xColumns); } void OFieldExpressionControl::lateInit() { uno::Reference< report::XGroups > xGroups = m_pParent->getGroups(); sal_Int32 nGroupsCount = xGroups->getCount(); m_aGroupPositions.resize(::std::max(nGroupsCount,sal_Int32(GROUPS_START_LEN)),NO_GROUP); ::std::vector::iterator aIter = m_aGroupPositions.begin(); for (sal_Int32 i = 0; i < nGroupsCount; ++i,++aIter) *aIter = i; if ( ColCount() == 0 ) { vcl::Font aFont( GetDataWindow().GetFont() ); aFont.SetWeight( WEIGHT_NORMAL ); GetDataWindow().SetFont( aFont ); // Set font of the headline to light aFont = GetFont(); aFont.SetWeight( WEIGHT_LIGHT ); SetFont(aFont); InsertHandleColumn(static_cast(GetTextWidth(OUString('0')) * 4)/*, sal_True */); InsertDataColumn( FIELD_EXPRESSION, RptResId(STR_RPT_EXPRESSION), 100); m_pComboCell = VclPtr::Create( &GetDataWindow() ); m_pComboCell->SetSelectHdl(LINK(this,OFieldExpressionControl,CBChangeHdl)); m_pComboCell->SetHelpId(HID_RPT_FIELDEXPRESSION); m_pComboCell->SetGetFocusHdl(LINK(m_pParent, OGroupsSortingDialog, OnControlFocusGot)); m_pComboCell->SetLoseFocusHdl(LINK(m_pParent, OGroupsSortingDialog, OnControlFocusLost)); // set browse mode BrowserMode nMode(BrowserMode::COLUMNSELECTION | BrowserMode::MULTISELECTION | BrowserMode::KEEPHIGHLIGHT | BrowserMode::HLINES | BrowserMode::VLINES | BrowserMode::AUTOSIZE_LASTCOL | BrowserMode::AUTO_VSCROLL | BrowserMode::AUTO_HSCROLL); if( m_pParent->isReadOnly() ) nMode |= BrowserMode::HIDECURSOR; SetMode(nMode); xGroups->addContainerListener(aContainerListener.get()); } else // not the first call RowRemoved(0, GetRowCount()); RowInserted(0, m_aGroupPositions.size()); } IMPL_LINK_NOARG( OFieldExpressionControl, CBChangeHdl, ComboBox&, void ) { SaveModified(); } bool OFieldExpressionControl::IsTabAllowed(bool /*bForward*/) const { return false; } bool OFieldExpressionControl::SaveModified() { sal_Int32 nRow = GetCurRow(); if ( nRow != BROWSER_ENDOFSELECTION ) { try { bool bAppend = false; uno::Reference< report::XGroup> xGroup; if ( m_aGroupPositions[nRow] == NO_GROUP ) { bAppend = true; OUString sUndoAction(RptResId(RID_STR_UNDO_APPEND_GROUP)); m_pParent->m_pController->getUndoManager().EnterListAction( sUndoAction, OUString(), 0, ViewShellId(-1) ); xGroup = m_pParent->getGroups()->createGroup(); xGroup->setHeaderOn(true); uno::Sequence< beans::PropertyValue > aArgs(2); aArgs[0].Name = PROPERTY_GROUP; aArgs[0].Value <<= xGroup; // find position where to insert the new group sal_Int32 nGroupPos = 0; ::std::vector::iterator aIter = m_aGroupPositions.begin(); ::std::vector::const_iterator aEnd = m_aGroupPositions.begin() + nRow; for(;aIter != aEnd;++aIter) if ( *aIter != NO_GROUP ) nGroupPos = *aIter + 1; aArgs[1].Name = PROPERTY_POSITIONY; aArgs[1].Value <<= nGroupPos; m_bIgnoreEvent = true; m_pParent->m_pController->executeChecked(SID_GROUP_APPEND,aArgs); m_bIgnoreEvent = false; OSL_ENSURE(*aIter == NO_GROUP ,"Illegal iterator!"); *aIter++ = nGroupPos; aEnd = m_aGroupPositions.end(); for(;aIter != aEnd;++aIter) if ( *aIter != NO_GROUP ) ++*aIter; } else xGroup = m_pParent->getGroup(m_aGroupPositions[nRow]); if ( xGroup.is() ) { sal_Int32 nPos = m_pComboCell->GetSelectedEntryPos(); OUString sExpression; if ( COMBOBOX_ENTRY_NOTFOUND == nPos ) sExpression = m_pComboCell->GetText(); else { sExpression = m_aColumnInfo[nPos].sColumnName; } xGroup->setExpression( sExpression ); ::rptui::adjustSectionName(xGroup,nPos); if ( bAppend ) m_pParent->m_pController->getUndoManager().LeaveListAction(); } if ( Controller().is() ) Controller()->ClearModified(); if ( GetRowCount() == m_pParent->getGroups()->getCount() ) { RowInserted( GetRowCount()-1); m_aGroupPositions.push_back(NO_GROUP); } GoToRow(nRow); m_pParent->DisplayData(nRow); } catch(uno::Exception&) { OSL_FAIL("OFieldExpressionControl::SaveModified: Exception caught!"); } } return true; } OUString OFieldExpressionControl::GetCellText( long nRow, sal_uInt16 /*nColId*/ ) const { OUString sText; if ( nRow != BROWSER_ENDOFSELECTION && m_aGroupPositions[nRow] != NO_GROUP ) { try { uno::Reference< report::XGroup> xGroup = m_pParent->getGroup(m_aGroupPositions[nRow]); OUString sExpression = xGroup->getExpression(); for(::std::vector::const_iterator aIter = m_aColumnInfo.begin(); aIter != m_aColumnInfo.end();++aIter) { if ( aIter->sColumnName == sExpression ) { if ( !aIter->sLabel.isEmpty() ) sExpression = aIter->sLabel; break; } } sText = sExpression; } catch (const uno::Exception&) { OSL_FAIL("Exception caught while getting expression value from the group"); } } return sText; } void OFieldExpressionControl::InitController( CellControllerRef& /*rController*/, long nRow, sal_uInt16 nColumnId ) { m_pComboCell->SetText( GetCellText( nRow, nColumnId ) ); } bool OFieldExpressionControl::CursorMoving(long nNewRow, sal_uInt16 nNewCol) { if (!EditBrowseBox::CursorMoving(nNewRow, nNewCol)) return false; m_nDataPos = nNewRow; long nOldDataPos = GetCurRow(); InvalidateStatusCell( m_nDataPos ); InvalidateStatusCell( nOldDataPos ); m_pParent->SaveData( nOldDataPos ); m_pParent->DisplayData( m_nDataPos ); return true; } CellController* OFieldExpressionControl::GetController( long /*nRow*/, sal_uInt16 /*nColumnId*/ ) { ComboBoxCellController* pCellController = new ComboBoxCellController( m_pComboCell ); pCellController->GetComboBox().SetReadOnly(!m_pParent->m_pController->isEditable()); return pCellController; } bool OFieldExpressionControl::SeekRow( long _nRow ) { // the basis class needs the call, because that's how the class knows which line will be painted EditBrowseBox::SeekRow(_nRow); m_nCurrentPos = _nRow; return true; } void OFieldExpressionControl::PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId ) const { OUString aText =GetCellText( m_nCurrentPos, nColumnId ); Point aPos( rRect.TopLeft() ); Size aTextSize( GetDataWindow().GetTextWidth( aText ), GetDataWindow().GetTextHeight() ); if( aPos.X() < rRect.Left() || aPos.X() + aTextSize.Width() > rRect.Right() || aPos.Y() < rRect.Top() || aPos.Y() + aTextSize.Height() > rRect.Bottom() ) rDev.SetClipRegion(vcl::Region(rRect)); rDev.DrawText( aPos, aText ); if( rDev.IsClipRegion() ) rDev.SetClipRegion(); } EditBrowseBox::RowStatus OFieldExpressionControl::GetRowStatus(long nRow) const { if (nRow >= 0 && nRow == m_nDataPos) return EditBrowseBox::CURRENT; if ( nRow != BROWSER_ENDOFSELECTION && nRow < static_cast(m_aGroupPositions.size()) && m_aGroupPositions[nRow] != NO_GROUP ) { try { uno::Reference< report::XGroup> xGroup = m_pParent->getGroup(m_aGroupPositions[nRow]); return (xGroup->getHeaderOn() || xGroup->getFooterOn())? EditBrowseBox::HEADERFOOTER : EditBrowseBox::CLEAN; } catch(uno::Exception&) { OSL_FAIL("Exception caught while try to get a group!"); } } return EditBrowseBox::CLEAN; } // XContainerListener void OFieldExpressionControl::elementInserted(const container::ContainerEvent& evt) { if ( m_bIgnoreEvent ) return; SolarMutexGuard aSolarGuard; ::osl::MutexGuard aGuard( m_aMutex ); sal_Int32 nGroupPos = 0; if ( evt.Accessor >>= nGroupPos ) { if ( nGroupPos >= GetRowCount() ) { sal_Int32 nAddedRows = nGroupPos - GetRowCount(); RowInserted(nAddedRows); for (sal_Int32 i = 0; i < nAddedRows; ++i) m_aGroupPositions.push_back(NO_GROUP); m_aGroupPositions[nGroupPos] = nGroupPos; } else { ::std::vector::iterator aFind = m_aGroupPositions.begin()+ nGroupPos; if ( aFind == m_aGroupPositions.end() ) aFind = ::std::find(m_aGroupPositions.begin(),m_aGroupPositions.end(),NO_GROUP); if ( aFind != m_aGroupPositions.end() ) { if ( *aFind != NO_GROUP ) aFind = m_aGroupPositions.insert(aFind,nGroupPos); else *aFind = nGroupPos; ::std::vector::const_iterator aEnd = m_aGroupPositions.end(); for(++aFind;aFind != aEnd;++aFind) if ( *aFind != NO_GROUP ) ++*aFind; } } Invalidate(); } } void OFieldExpressionControl::elementRemoved(const container::ContainerEvent& evt) { SolarMutexGuard aSolarGuard; ::osl::MutexGuard aGuard( m_aMutex ); if ( m_bIgnoreEvent ) return; sal_Int32 nGroupPos = 0; if ( evt.Accessor >>= nGroupPos ) { std::vector::iterator aEnd = m_aGroupPositions.end(); std::vector::iterator aFind = std::find(m_aGroupPositions.begin(), aEnd, nGroupPos); if (aFind != aEnd) { *aFind = NO_GROUP; for(++aFind;aFind != aEnd;++aFind) if ( *aFind != NO_GROUP ) --*aFind; Invalidate(); } } } bool OFieldExpressionControl::IsDeleteAllowed( ) { return !m_pParent->isReadOnly() && GetSelectRowCount() > 0; } void OFieldExpressionControl::KeyInput( const KeyEvent& rEvt ) { if (IsDeleteAllowed()) { if (rEvt.GetKeyCode().GetCode() == KEY_DELETE && // Delete rows !rEvt.GetKeyCode().IsShift() && !rEvt.GetKeyCode().IsMod1()) { DeleteRows(); return; } } EditBrowseBox::KeyInput(rEvt); } void OFieldExpressionControl::Command(const CommandEvent& rEvt) { switch (rEvt.GetCommand()) { case CommandEventId::ContextMenu: { if (!rEvt.IsMouseEvent()) { EditBrowseBox::Command(rEvt); return; } sal_uInt16 nColId = GetColumnAtXPosPixel(rEvt.GetMousePosPixel().X()); if ( nColId == HANDLE_ID ) { bool bEnable = false; long nIndex = FirstSelectedRow(); while( nIndex != SFX_ENDOFSELECTION && !bEnable ) { if ( m_aGroupPositions[nIndex] != NO_GROUP ) bEnable = true; nIndex = NextSelectedRow(); } VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "modules/dbreport/ui/groupsortmenu.ui", ""); VclPtr aContextMenu(aBuilder.get_menu("menu")); aContextMenu->EnableItem(aContextMenu->GetItemId("delete"), IsDeleteAllowed() && bEnable); if (aContextMenu->Execute(this, rEvt.GetMousePosPixel())) { if( m_nDeleteEvent ) Application::RemoveUserEvent( m_nDeleteEvent ); m_nDeleteEvent = Application::PostUserEvent( LINK(this, OFieldExpressionControl, DelayedDelete), nullptr, true ); } } SAL_FALLTHROUGH; } default: EditBrowseBox::Command(rEvt); } } void OFieldExpressionControl::DeleteRows() { bool bIsEditing = IsEditing(); if (bIsEditing) { DeactivateCell(); } long nIndex = FirstSelectedRow(); if (nIndex == SFX_ENDOFSELECTION) { nIndex = GetCurRow(); } bool bFirstTime = true; long nOldDataPos = nIndex; uno::Sequence< beans::PropertyValue > aArgs(1); aArgs[0].Name = PROPERTY_GROUP; m_bIgnoreEvent = true; while( nIndex >= 0 ) { if ( m_aGroupPositions[nIndex] != NO_GROUP ) { if ( bFirstTime ) { bFirstTime = false; OUString sUndoAction(RptResId(RID_STR_UNDO_REMOVE_SELECTION)); m_pParent->m_pController->getUndoManager().EnterListAction( sUndoAction, OUString(), 0, ViewShellId(-1) ); } sal_Int32 nGroupPos = m_aGroupPositions[nIndex]; uno::Reference< report::XGroup> xGroup = m_pParent->getGroup(nGroupPos); aArgs[0].Value <<= xGroup; // we use this way to create undo actions m_pParent->m_pController->executeChecked(SID_GROUP_REMOVE,aArgs); std::vector::iterator aEnd = m_aGroupPositions.end(); std::vector::iterator aFind = std::find(m_aGroupPositions.begin(), aEnd, nGroupPos); if (aFind != aEnd) { *aFind = NO_GROUP; for(++aFind;aFind != aEnd;++aFind) if ( *aFind != NO_GROUP ) --*aFind; } } nIndex = NextSelectedRow(); } if ( !bFirstTime ) m_pParent->m_pController->getUndoManager().LeaveListAction(); m_nDataPos = GetCurRow(); InvalidateStatusCell( nOldDataPos ); InvalidateStatusCell( m_nDataPos ); ActivateCell(); m_pParent->DisplayData( m_nDataPos ); m_bIgnoreEvent = false; Invalidate(); } IMPL_LINK_NOARG( OFieldExpressionControl, DelayedDelete, void*, void ) { m_nDeleteEvent = nullptr; DeleteRows(); } Size OFieldExpressionControl::GetOptimalSize() const { return LogicToPixel(Size(106, 75), MapMode(MapUnit::MapAppFont)); } // class OGroupsSortingDialog OGroupsSortingDialog::OGroupsSortingDialog(vcl::Window* _pParent, bool _bReadOnly, OReportController* _pController) : FloatingWindow(_pParent, "FloatingSort", "modules/dbreport/ui/floatingsort.ui") , OPropertyChangeListener(m_aMutex) , m_pController(_pController) , m_xGroups(m_pController->getReportDefinition()->getGroups()) , m_bReadOnly(_bReadOnly) { get(m_pToolBox, "toolbox"); m_nMoveUpId = m_pToolBox->GetItemId(0); m_nMoveDownId = m_pToolBox->GetItemId(1); m_nDeleteId = m_pToolBox->GetItemId(2); get(m_pOrderLst, "sorting"); get(m_pHeaderLst, "header"); get(m_pFooterLst, "footer"); get(m_pGroupOnLst, "group"); get(m_pGroupIntervalEd, "interval"); get(m_pKeepTogetherLst, "keep"); get(m_pHelpWindow, "helptext"); m_pHelpWindow->set_height_request(GetTextHeight() * 4); get(m_pProperties, "properties"); m_pFieldExpression = VclPtr::Create(this, get("box")); m_pFieldExpression->set_hexpand(true); m_pFieldExpression->set_vexpand(true); Control* pControlsLst[] = { m_pHeaderLst, m_pFooterLst, m_pGroupOnLst, m_pKeepTogetherLst, m_pOrderLst, m_pGroupIntervalEd}; for (Control* i : pControlsLst) { i->SetGetFocusHdl(LINK(this, OGroupsSortingDialog, OnControlFocusGot)); i->SetLoseFocusHdl(LINK(this, OGroupsSortingDialog, OnControlFocusLost)); i->Show(); } for (size_t i = 0; i < SAL_N_ELEMENTS(pControlsLst) - 1; ++i) static_cast(pControlsLst[i])->SetSelectHdl(LINK(this,OGroupsSortingDialog,LBChangeHdl)); m_pReportListener = new OPropertyChangeMultiplexer(this,m_pController->getReportDefinition().get()); m_pReportListener->addProperty(PROPERTY_COMMAND); m_pReportListener->addProperty(PROPERTY_COMMANDTYPE); m_pFieldExpression->lateInit(); fillColumns(); m_pFieldExpression->Show(); m_pHelpWindow->SetControlBackground( GetSettings().GetStyleSettings().GetFaceColor() ); m_pToolBox->SetLineSpacing(true); m_pToolBox->SetSelectHdl(LINK(this, OGroupsSortingDialog, OnFormatAction)); checkButtons(0); Show(); } OGroupsSortingDialog::~OGroupsSortingDialog() { disposeOnce(); } void OGroupsSortingDialog::dispose() { m_xColumns.clear(); m_pReportListener->dispose(); if ( m_pCurrentGroupListener.is() ) m_pCurrentGroupListener->dispose(); m_pToolBox.clear(); m_pProperties.clear(); m_pOrderLst.clear(); m_pHeaderLst.clear(); m_pFooterLst.clear(); m_pGroupOnLst.clear(); m_pGroupIntervalEd.clear(); m_pKeepTogetherLst.clear(); m_pHelpWindow.clear(); m_pFieldExpression.disposeAndClear(); FloatingWindow::dispose(); } void OGroupsSortingDialog::UpdateData( ) { m_pFieldExpression->Invalidate(); long nCurRow = m_pFieldExpression->GetCurRow(); m_pFieldExpression->DeactivateCell(); m_pFieldExpression->ActivateCell(nCurRow, m_pFieldExpression->GetCurColumnId()); DisplayData(nCurRow); } void OGroupsSortingDialog::DisplayData( sal_Int32 _nRow ) { sal_Int32 nGroupPos = m_pFieldExpression->getGroupPosition(_nRow); bool bEmpty = nGroupPos == NO_GROUP; m_pProperties->Enable(!bEmpty); checkButtons(_nRow); if ( m_pCurrentGroupListener.is() ) m_pCurrentGroupListener->dispose(); m_pCurrentGroupListener = nullptr; if ( !bEmpty && nGroupPos != NO_GROUP ) { uno::Reference< report::XGroup> xGroup = getGroup(nGroupPos); m_pCurrentGroupListener = new OPropertyChangeMultiplexer(this,xGroup.get()); m_pCurrentGroupListener->addProperty(PROPERTY_HEADERON); m_pCurrentGroupListener->addProperty(PROPERTY_FOOTERON); displayGroup(xGroup); } } void OGroupsSortingDialog::SaveData( sal_Int32 _nRow) { sal_Int32 nGroupPos = m_pFieldExpression->getGroupPosition(_nRow); if ( nGroupPos == NO_GROUP ) return; uno::Reference< report::XGroup> xGroup = getGroup(nGroupPos); if ( m_pHeaderLst->IsValueChangedFromSaved() ) xGroup->setHeaderOn( m_pHeaderLst->GetSelectedEntryPos() == 0 ); if ( m_pFooterLst->IsValueChangedFromSaved() ) xGroup->setFooterOn( m_pFooterLst->GetSelectedEntryPos() == 0 ); if ( m_pKeepTogetherLst->IsValueChangedFromSaved() ) xGroup->setKeepTogether( m_pKeepTogetherLst->GetSelectedEntryPos() ); if ( m_pGroupOnLst->IsValueChangedFromSaved() ) { sal_Int16 nGroupOn = static_cast(reinterpret_cast(m_pGroupOnLst->GetSelectedEntryData())); xGroup->setGroupOn( nGroupOn ); } if ( m_pGroupIntervalEd->IsValueChangedFromSaved() ) { xGroup->setGroupInterval( static_cast(m_pGroupIntervalEd->GetValue()) ); m_pGroupIntervalEd->SaveValue(); } if ( m_pOrderLst->IsValueChangedFromSaved() ) xGroup->setSortAscending( m_pOrderLst->GetSelectedEntryPos() == 0 ); ListBox* pControls[] = { m_pHeaderLst, m_pFooterLst, m_pGroupOnLst, m_pKeepTogetherLst, m_pOrderLst}; for (ListBox* pControl : pControls) pControl->SaveValue(); } sal_Int32 OGroupsSortingDialog::getColumnDataType(const OUString& _sColumnName) { sal_Int32 nDataType = sdbc::DataType::VARCHAR; try { if ( !m_xColumns.is() ) fillColumns(); if ( m_xColumns.is() && m_xColumns->hasByName(_sColumnName) ) { uno::Reference< beans::XPropertySet> xColumn(m_xColumns->getByName(_sColumnName),uno::UNO_QUERY); if ( xColumn.is() ) xColumn->getPropertyValue(PROPERTY_TYPE) >>= nDataType; } } catch(uno::Exception&) { OSL_FAIL("Exception caught while getting the type of a column"); } return nDataType; } IMPL_LINK(OGroupsSortingDialog, OnControlFocusGot, Control&, rControl, void ) { if ( m_pFieldExpression && m_pFieldExpression->getExpressionControl() ) { const std::pair pControls[] = { { m_pFieldExpression->getExpressionControl(), STR_RPT_HELP_FIELD }, { m_pHeaderLst, STR_RPT_HELP_HEADER }, { m_pFooterLst, STR_RPT_HELP_FOOTER }, { m_pGroupOnLst, STR_RPT_HELP_GROUPON }, { m_pGroupIntervalEd, STR_RPT_HELP_INTERVAL }, { m_pKeepTogetherLst, STR_RPT_HELP_KEEP }, { m_pOrderLst, STR_RPT_HELP_SORT } }; for (size_t i = 0; i < SAL_N_ELEMENTS(pControls); ++i) { if (&rControl == pControls[i].first) { ListBox* pListBox = dynamic_cast< ListBox* >( &rControl ); if ( pListBox ) pListBox->SaveValue(); NumericField* pNumericField = dynamic_cast< NumericField* >( &rControl ); if ( pNumericField ) pNumericField->SaveValue(); //shows the text given by the id in the multiline edit m_pHelpWindow->SetText(RptResId(pControls[i].second)); break; } } } } IMPL_LINK(OGroupsSortingDialog, OnControlFocusLost, Control&, rControl, void ) { if (m_pFieldExpression && &rControl == m_pGroupIntervalEd) { if ( m_pGroupIntervalEd->IsModified() ) SaveData(m_pFieldExpression->GetCurRow()); } } IMPL_LINK_NOARG( OGroupsSortingDialog, OnFormatAction, ToolBox*, void ) { sal_uInt16 nCommand = m_pToolBox->GetCurItemId(); if ( m_pFieldExpression ) { long nIndex = m_pFieldExpression->GetCurrRow(); sal_Int32 nGroupPos = m_pFieldExpression->getGroupPosition(nIndex); uno::Sequence aClipboardList; if ( nIndex >= 0 && nGroupPos != NO_GROUP ) { aClipboardList.realloc(1); aClipboardList[0] = m_xGroups->getByIndex(nGroupPos); } if ( nCommand == m_nMoveUpId ) { --nIndex; } if ( nCommand == m_nMoveDownId ) { ++nIndex; } if ( nCommand == m_nDeleteId ) { Application::PostUserEvent( LINK(m_pFieldExpression, OFieldExpressionControl, DelayedDelete), nullptr, true ); } else { if ( nIndex >= 0 && aClipboardList.getLength() ) { m_pFieldExpression->SetNoSelection(); m_pFieldExpression->moveGroups(aClipboardList,nIndex,false); m_pFieldExpression->DeactivateCell(); m_pFieldExpression->GoToRow(nIndex); m_pFieldExpression->ActivateCell(nIndex, m_pFieldExpression->GetCurColumnId()); DisplayData(nIndex); } } } } IMPL_LINK( OGroupsSortingDialog, LBChangeHdl, ListBox&, rListBox, void ) { if ( rListBox.IsValueChangedFromSaved() ) { sal_Int32 nRow = m_pFieldExpression->GetCurRow(); sal_Int32 nGroupPos = m_pFieldExpression->getGroupPosition(nRow); if (&rListBox != m_pHeaderLst && &rListBox != m_pFooterLst) { if ( rListBox.IsValueChangedFromSaved() ) SaveData(nRow); if ( &rListBox == m_pGroupOnLst ) m_pGroupIntervalEd->Enable( rListBox.GetSelectedEntryPos() != 0 ); } else if ( nGroupPos != NO_GROUP ) { uno::Reference< report::XGroup> xGroup = getGroup(nGroupPos); uno::Sequence< beans::PropertyValue > aArgs(2); aArgs[1].Name = PROPERTY_GROUP; aArgs[1].Value <<= xGroup; if ( m_pHeaderLst == &rListBox ) aArgs[0].Name = PROPERTY_HEADERON; else aArgs[0].Name = PROPERTY_FOOTERON; aArgs[0].Value <<= rListBox.GetSelectedEntryPos() == 0; m_pController->executeChecked(m_pHeaderLst == &rListBox ? SID_GROUPHEADER : SID_GROUPFOOTER, aArgs); m_pFieldExpression->InvalidateHandleColumn(); } } } void OGroupsSortingDialog::_propertyChanged(const beans::PropertyChangeEvent& _rEvent) { uno::Reference< report::XGroup > xGroup(_rEvent.Source,uno::UNO_QUERY); if ( xGroup.is() ) displayGroup(xGroup); else fillColumns(); } void OGroupsSortingDialog::fillColumns() { m_xColumns = m_pController->getColumns(); m_pFieldExpression->fillColumns(m_xColumns); } void OGroupsSortingDialog::displayGroup(const uno::Reference& _xGroup) { m_pHeaderLst->SelectEntryPos(_xGroup->getHeaderOn() ? 0 : 1 ); m_pFooterLst->SelectEntryPos(_xGroup->getFooterOn() ? 0 : 1 ); sal_Int32 nDataType = getColumnDataType(_xGroup->getExpression()); // first clear whole group on list while(m_pGroupOnLst->GetEntryCount() > 1 ) { m_pGroupOnLst->RemoveEntry(1); } switch(nDataType) { case sdbc::DataType::LONGVARCHAR: case sdbc::DataType::VARCHAR: case sdbc::DataType::CHAR: m_pGroupOnLst->InsertEntry(RptResId(STR_RPT_PREFIXCHARS)); m_pGroupOnLst->SetEntryData(1,reinterpret_cast(report::GroupOn::PREFIX_CHARACTERS)); break; case sdbc::DataType::DATE: case sdbc::DataType::TIME: case sdbc::DataType::TIMESTAMP: { const char* aIds[] = { STR_RPT_YEAR, STR_RPT_QUARTER,STR_RPT_MONTH,STR_RPT_WEEK,STR_RPT_DAY,STR_RPT_HOUR,STR_RPT_MINUTE }; for (sal_uInt16 i = 0; i < SAL_N_ELEMENTS(aIds); ++i) { m_pGroupOnLst->InsertEntry(RptResId(aIds[i])); m_pGroupOnLst->SetEntryData(i+1,reinterpret_cast(i+2)); } } break; default: m_pGroupOnLst->InsertEntry(RptResId(STR_RPT_INTERVAL)); m_pGroupOnLst->SetEntryData(1,reinterpret_cast(report::GroupOn::INTERVAL)); break; } sal_Int32 nPos = 0; switch(_xGroup->getGroupOn()) { case report::GroupOn::DEFAULT: nPos = 0; break; case report::GroupOn::PREFIX_CHARACTERS: nPos = 1; break; case report::GroupOn::YEAR: nPos = 1; break; case report::GroupOn::QUARTAL: nPos = 2; break; case report::GroupOn::MONTH: nPos = 3; break; case report::GroupOn::WEEK: nPos = 4; break; case report::GroupOn::DAY: nPos = 5; break; case report::GroupOn::HOUR: nPos = 6; break; case report::GroupOn::MINUTE: nPos = 7; break; case report::GroupOn::INTERVAL: nPos = 1; break; default: nPos = 0; } m_pGroupOnLst->SelectEntryPos(nPos); m_pGroupIntervalEd->SetText(OUString::number(_xGroup->getGroupInterval())); m_pGroupIntervalEd->SaveValue(); m_pGroupIntervalEd->Enable( nPos != 0 ); m_pKeepTogetherLst->SelectEntryPos(_xGroup->getKeepTogether()); m_pOrderLst->SelectEntryPos(_xGroup->getSortAscending() ? 0 : 1); ListBox* pControls[] = { m_pHeaderLst, m_pFooterLst, m_pGroupOnLst, m_pKeepTogetherLst, m_pOrderLst}; for (ListBox* pControl : pControls) pControl->SaveValue(); ListBox* pControlsLst2[] = { m_pHeaderLst, m_pFooterLst, m_pGroupOnLst, m_pKeepTogetherLst, m_pOrderLst}; bool bReadOnly = !m_pController->isEditable(); for (ListBox* i : pControlsLst2) i->SetReadOnly(bReadOnly); m_pGroupIntervalEd->SetReadOnly(bReadOnly); } void OGroupsSortingDialog::checkButtons(sal_Int32 _nRow) { sal_Int32 nGroupCount = m_xGroups->getCount(); sal_Int32 nRowCount = m_pFieldExpression->GetRowCount(); bool bEnabled = nGroupCount > 1; if (bEnabled && _nRow > 0 ) { m_pToolBox->EnableItem(m_nMoveUpId); } else { m_pToolBox->EnableItem(m_nMoveUpId, false); } if (bEnabled && _nRow < (nRowCount - 1) ) { m_pToolBox->EnableItem(m_nMoveDownId); } else { m_pToolBox->EnableItem(m_nMoveDownId, false); } sal_Int32 nGroupPos = m_pFieldExpression->getGroupPosition(_nRow); if ( nGroupPos != NO_GROUP ) { bool bEnableDelete = nGroupCount > 0; m_pToolBox->EnableItem(m_nDeleteId, bEnableDelete); } else { m_pToolBox->EnableItem(m_nDeleteId, false); } } } // rptui /* vim:set shiftwidth=4 softtabstop=4 expandtab: */