From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- reportdesign/source/ui/dlg/GroupsSorting.cxx | 1181 ++++++++++++++++++++++++++ 1 file changed, 1181 insertions(+) create mode 100644 reportdesign/source/ui/dlg/GroupsSorting.cxx (limited to 'reportdesign/source/ui/dlg/GroupsSorting.cxx') diff --git a/reportdesign/source/ui/dlg/GroupsSorting.cxx b/reportdesign/source/ui/dlg/GroupsSorting.cxx new file mode 100644 index 000000000..e0599d83a --- /dev/null +++ b/reportdesign/source/ui/dlg/GroupsSorting.cxx @@ -0,0 +1,1181 @@ +/* -*- 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 "GroupExchange.hxx" +#include +#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; + + static void lcl_addToList_throw( weld::ComboBox& _rListBox, ::std::vector& o_aColumnList,const uno::Reference< container::XNameAccess>& i_xColumns ) + { + const uno::Sequence< OUString > aEntries = i_xColumns->getElementNames(); + for ( const OUString& rEntry : aEntries ) + { + uno::Reference< beans::XPropertySet> xColumn(i_xColumns->getByName(rEntry),uno::UNO_QUERY_THROW); + OUString sLabel; + if ( xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_LABEL) ) + xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel; + o_aColumnList.emplace_back(rEntry,sLabel ); + if ( !sLabel.isEmpty() ) + _rListBox.append_text( sLabel ); + else + _rListBox.append_text( rEntry ); + } + } + +/** + * Separated out from OFieldExpressionControl to prevent collision of ref-counted base classes + */ +class OFieldExpressionControl; + +namespace { + +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; + OGroupsSortingDialog* m_pParent; + bool m_bIgnoreEvent; + rtl::Reference aContainerListener; + +public: + OFieldExpressionControl(OGroupsSortingDialog* pParentDialog, const css::uno::Reference &rParent); + 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( ) const; + void DeleteRows(); + + sal_Int32 getGroupPosition(sal_Int32 _nRow) const { return _nRow != BROWSER_ENDOFSELECTION ? m_aGroupPositions[_nRow] : sal_Int32(NO_GROUP); } + + /** 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(sal_Int32 nNewRow, sal_uInt16 nNewCol) override; + using ::svt::EditBrowseBox::GetRowCount; +protected: + virtual bool IsTabAllowed(bool bForward) const override; + + virtual void InitController( ::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol ) override; + virtual ::svt::CellController* GetController( sal_Int32 nRow, sal_uInt16 nCol ) override; + virtual void PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColId ) const override; + virtual bool SeekRow( sal_Int32 nRow ) override; + virtual bool SaveModified() override; + virtual OUString GetCellText( sal_Int32 nRow, sal_uInt16 nColId ) const override; + virtual RowStatus GetRowStatus(sal_Int32 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, weld::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); } + +OFieldExpressionControl::OFieldExpressionControl(OGroupsSortingDialog* pParentDialog, const css::uno::Reference &rParent) + :EditBrowseBox( VCLUnoHelper::GetWindow(rParent), 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); + + // delete events from queue + if( m_nDeleteEvent ) + Application::RemoveUserEvent( m_nDeleteEvent ); + + m_pComboCell.disposeAndClear(); + m_pParent = nullptr; + ::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( tools::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::Any(xOrgGroup) ); + } + } + catch(uno::Exception&) + { + OSL_FAIL("Can not access group!"); + } + } + if ( !vClipboardList.empty() ) + aList = uno::Sequence< uno::Any >(vClipboardList.data(), 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.hasElements() ) + { + 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() ) + { + weld::ComboBox& rComboBox = m_pComboCell->get_widget(); + sal_Int32 nPos = rComboBox.get_active(); + if (nPos != -1 || !rComboBox.get_active_text().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.hasElements() ) + { + moveGroups(aGroups,nRow); + nAction = DND_ACTION_MOVE; + } + } + return nAction; +} + +void OFieldExpressionControl::moveGroups(const uno::Sequence& _aGroups,sal_Int32 _nRow,bool _bSelect) +{ + if ( !_aGroups.hasElements() ) + return; + + 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(); + for(const uno::Any& rGroup : _aGroups) + { + uno::Reference< report::XGroup> xGroup(rGroup,uno::UNO_QUERY); + if ( xGroup.is() ) + { + uno::Sequence< beans::PropertyValue > aArgs{ comphelper::makePropertyValue( + PROPERTY_GROUP, xGroup) }; + // we use this way to create undo actions + m_pParent->m_pController->executeChecked(SID_GROUP_REMOVE,aArgs); + aArgs.realloc(2); + auto pArgs = aArgs.getArray(); + if ( nRow > xGroups->getCount() ) + nRow = xGroups->getCount(); + if ( _bSelect ) + SelectRow(nRow); + pArgs[1].Name = PROPERTY_POSITIONY; + pArgs[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) +{ + weld::ComboBox& rComboBox = m_pComboCell->get_widget(); + rComboBox.clear(); + if ( _xColumns.is() ) + lcl_addToList_throw(rComboBox, 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() ); + weld::ComboBox& rComboBox = m_pComboCell->get_widget(); + rComboBox.connect_changed(LINK(this,OFieldExpressionControl,CBChangeHdl)); + m_pComboCell->SetHelpId(HID_RPT_FIELDEXPRESSION); + + m_pComboCell->SetFocusInHdl(LINK(m_pParent, OGroupsSortingDialog, OnControlFocusGot)); + + + // 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); + } + else + // not the first call + RowRemoved(0, GetRowCount()); + + RowInserted(0, m_aGroupPositions.size()); +} + +IMPL_LINK_NOARG( OFieldExpressionControl, CBChangeHdl, weld::ComboBox&, void ) +{ + SaveModified(); +} + +bool OFieldExpressionControl::IsTabAllowed(bool /*bForward*/) const +{ + return false; +} + +bool OFieldExpressionControl::SaveModified() +{ + sal_Int32 nRow = GetCurRow(); + if ( nRow == BROWSER_ENDOFSELECTION ) + return true; + + 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); + + // 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; + uno::Sequence< beans::PropertyValue > aArgs{ + comphelper::makePropertyValue(PROPERTY_GROUP, xGroup), + comphelper::makePropertyValue(PROPERTY_POSITIONY, 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() ) + { + weld::ComboBox& rComboBox = m_pComboCell->get_widget(); + sal_Int32 nPos = rComboBox.get_active(); + OUString sExpression; + if (nPos == -1) + sExpression = rComboBox.get_active_text(); + 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()->SaveValue(); + if ( GetRowCount() == m_pParent->getGroups()->getCount() ) + { + RowInserted( GetRowCount()-1); + m_aGroupPositions.push_back(NO_GROUP); + } + + GoToRow(nRow); + m_pParent->DisplayData(nRow); + } + catch(uno::Exception&) + { + TOOLS_WARN_EXCEPTION( "reportdesign", "OFieldExpressionControl::SaveModified"); + } + + return true; +} + +OUString OFieldExpressionControl::GetCellText( sal_Int32 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(); + + auto aIter = std::find_if(m_aColumnInfo.begin(), m_aColumnInfo.end(), + [&sExpression](const ColumnInfo& rColumnInfo) { return rColumnInfo.sColumnName == sExpression; }); + if (aIter != m_aColumnInfo.end() && !aIter->sLabel.isEmpty()) + sExpression = aIter->sLabel; + sText = sExpression; + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION( "reportdesign", "Exception caught while getting expression value from the group"); + } + } + return sText; +} + +void OFieldExpressionControl::InitController( CellControllerRef& /*rController*/, sal_Int32 nRow, sal_uInt16 nColumnId ) +{ + weld::ComboBox& rComboBox = m_pComboCell->get_widget(); + rComboBox.set_entry_text(GetCellText(nRow, nColumnId)); +} + +bool OFieldExpressionControl::CursorMoving(sal_Int32 nNewRow, sal_uInt16 nNewCol) +{ + + if (!EditBrowseBox::CursorMoving(nNewRow, nNewCol)) + return false; + m_nDataPos = nNewRow; + tools::Long nOldDataPos = GetCurRow(); + InvalidateStatusCell( m_nDataPos ); + InvalidateStatusCell( nOldDataPos ); + + m_pParent->SaveData( nOldDataPos ); + m_pParent->DisplayData( m_nDataPos ); + return true; +} + +CellController* OFieldExpressionControl::GetController( sal_Int32 /*nRow*/, sal_uInt16 /*nColumnId*/ ) +{ + ComboBoxCellController* pCellController = new ComboBoxCellController( m_pComboCell ); + pCellController->GetComboBox().set_entry_editable(m_pParent->m_pController->isEditable()); + return pCellController; +} + +bool OFieldExpressionControl::SeekRow( sal_Int32 _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(sal_Int32 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&) + { + TOOLS_WARN_EXCEPTION( "reportdesign", "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) ) + return; + + 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) ) + return; + + 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( ) const +{ + 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 = GetColumnId(GetColumnAtXPosPixel(rEvt.GetMousePosPixel().X())); + + if ( nColId == HANDLE_ID ) + { + bool bEnable = false; + tools::Long nIndex = FirstSelectedRow(); + while( nIndex != SFX_ENDOFSELECTION && !bEnable ) + { + if ( m_aGroupPositions[nIndex] != NO_GROUP ) + bEnable = true; + nIndex = NextSelectedRow(); + } + + ::tools::Rectangle aRect(rEvt.GetMousePosPixel(), Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr xBuilder(Application::CreateBuilder(pPopupParent, "modules/dbreport/ui/groupsortmenu.ui")); + std::unique_ptr xContextMenu(xBuilder->weld_menu("menu")); + xContextMenu->set_sensitive("delete", IsDeleteAllowed() && bEnable); + if (!xContextMenu->popup_at_rect(pPopupParent, aRect).isEmpty()) + { + if( m_nDeleteEvent ) + Application::RemoveUserEvent( m_nDeleteEvent ); + m_nDeleteEvent = Application::PostUserEvent( LINK(this, OFieldExpressionControl, DelayedDelete), nullptr, true ); + } + } + [[fallthrough]]; + } + default: + EditBrowseBox::Command(rEvt); + } + +} + +void OFieldExpressionControl::DeleteRows() +{ + + bool bIsEditing = IsEditing(); + if (bIsEditing) + { + DeactivateCell(); + } + tools::Long nIndex = FirstSelectedRow(); + if (nIndex == SFX_ENDOFSELECTION) + { + nIndex = GetCurRow(); + } + bool bFirstTime = true; + + tools::Long nOldDataPos = nIndex; + 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); + uno::Sequence< beans::PropertyValue > aArgs{ comphelper::makePropertyValue( + PROPERTY_GROUP, 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)); +} + +OGroupsSortingDialog::OGroupsSortingDialog(weld::Window* pParent, bool bReadOnly, + OReportController* pController) + : GenericDialogController(pParent, "modules/dbreport/ui/floatingsort.ui", "FloatingSort") + , OPropertyChangeListener(m_aMutex) + , m_pController(pController) + , m_xGroups(m_pController->getReportDefinition()->getGroups()) + , m_bReadOnly(bReadOnly) + , m_xToolBox(m_xBuilder->weld_toolbar("toolbox")) + , m_xProperties(m_xBuilder->weld_widget("properties")) + , m_xOrderLst(m_xBuilder->weld_combo_box("sorting")) + , m_xHeaderLst(m_xBuilder->weld_combo_box("header")) + , m_xFooterLst(m_xBuilder->weld_combo_box("footer")) + , m_xGroupOnLst(m_xBuilder->weld_combo_box("group")) + , m_xGroupIntervalEd(m_xBuilder->weld_spin_button("interval")) + , m_xKeepTogetherLst(m_xBuilder->weld_combo_box("keep")) + , m_xHelpWindow(m_xBuilder->weld_label("helptext")) + , m_xBox(m_xBuilder->weld_container("box")) + , m_xTableCtrlParent(m_xBox->CreateChildFrame()) + , m_xFieldExpression(VclPtr::Create(this, m_xTableCtrlParent)) +{ + m_xHelpWindow->set_size_request(-1, m_xHelpWindow->get_text_height() * 4); + m_xFieldExpression->set_hexpand(true); + m_xFieldExpression->set_vexpand(true); + + weld::Widget* pControlsLst[] = { m_xHeaderLst.get(), m_xFooterLst.get(), m_xGroupOnLst.get(), + m_xKeepTogetherLst.get(), m_xOrderLst.get(), m_xGroupIntervalEd.get() }; + for (weld::Widget* i : pControlsLst) + { + i->connect_focus_in(LINK(this, OGroupsSortingDialog, OnWidgetFocusGot)); + i->show(); + } + + m_xGroupIntervalEd->connect_focus_out(LINK(this, OGroupsSortingDialog, OnWidgetFocusLost)); + + for (size_t i = 0; i < SAL_N_ELEMENTS(pControlsLst) - 1; ++i) + dynamic_cast(*pControlsLst[i]).connect_changed(LINK(this,OGroupsSortingDialog,LBChangeHdl)); + + m_pReportListener = new OPropertyChangeMultiplexer(this, m_pController->getReportDefinition()); + m_pReportListener->addProperty(PROPERTY_COMMAND); + m_pReportListener->addProperty(PROPERTY_COMMANDTYPE); + + m_xFieldExpression->lateInit(); + fillColumns(); + Size aPrefSize = m_xFieldExpression->GetOptimalSize(); + m_xBox->set_size_request(aPrefSize.Width(), aPrefSize.Height()); + m_xFieldExpression->Show(); + + m_xToolBox->connect_clicked(LINK(this, OGroupsSortingDialog, OnFormatAction)); + + checkButtons(0); +} + +OGroupsSortingDialog::~OGroupsSortingDialog() +{ + m_pReportListener->dispose(); + if ( m_pCurrentGroupListener.is() ) + m_pCurrentGroupListener->dispose(); + m_xFieldExpression.disposeAndClear(); + m_xTableCtrlParent->dispose(); + m_xTableCtrlParent.clear(); +} + +void OGroupsSortingDialog::UpdateData( ) +{ + m_xFieldExpression->Invalidate(); + sal_Int32 nCurRow = m_xFieldExpression->GetCurRow(); + m_xFieldExpression->DeactivateCell(); + m_xFieldExpression->ActivateCell(nCurRow, m_xFieldExpression->GetCurColumnId()); + DisplayData(nCurRow); +} + +void OGroupsSortingDialog::DisplayData( sal_Int32 _nRow ) +{ + const sal_Int32 nGroupPos = m_xFieldExpression->getGroupPosition(_nRow); + const bool bEmpty = nGroupPos == NO_GROUP; + m_xProperties->set_sensitive(!bEmpty); + + checkButtons(_nRow); + + if ( m_pCurrentGroupListener.is() ) + m_pCurrentGroupListener->dispose(); + m_pCurrentGroupListener = nullptr; + if (!bEmpty) + { + uno::Reference< report::XGroup> xGroup = getGroup(nGroupPos); + + m_pCurrentGroupListener = new OPropertyChangeMultiplexer(this, xGroup); + m_pCurrentGroupListener->addProperty(PROPERTY_HEADERON); + m_pCurrentGroupListener->addProperty(PROPERTY_FOOTERON); + + displayGroup(xGroup); + } +} + +void OGroupsSortingDialog::SaveData( sal_Int32 _nRow) +{ + sal_Int32 nGroupPos = m_xFieldExpression->getGroupPosition(_nRow); + if ( nGroupPos == NO_GROUP ) + return; + + uno::Reference< report::XGroup> xGroup = getGroup(nGroupPos); + if (m_xHeaderLst->get_value_changed_from_saved()) + xGroup->setHeaderOn( m_xHeaderLst->get_active() == 0 ); + if (m_xFooterLst->get_value_changed_from_saved()) + xGroup->setFooterOn( m_xFooterLst->get_active() == 0 ); + if (m_xKeepTogetherLst->get_value_changed_from_saved()) + xGroup->setKeepTogether( m_xKeepTogetherLst->get_active() ); + if (m_xGroupOnLst->get_value_changed_from_saved()) + { + auto nGroupOn = m_xGroupOnLst->get_active_id().toInt32(); + xGroup->setGroupOn( nGroupOn ); + } + if (m_xGroupIntervalEd->get_value_changed_from_saved()) + { + xGroup->setGroupInterval(m_xGroupIntervalEd->get_value()); + m_xGroupIntervalEd->save_value(); + } + if ( m_xOrderLst->get_value_changed_from_saved() ) + xGroup->setSortAscending( m_xOrderLst->get_active() == 0 ); + + weld::ComboBox* pControls[] = { m_xHeaderLst.get(), m_xFooterLst.get(), m_xGroupOnLst.get(), + m_xKeepTogetherLst.get(), m_xOrderLst.get() }; + for (weld::ComboBox* pControl : pControls) + pControl->save_value(); +} + +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&) + { + TOOLS_WARN_EXCEPTION( "reportdesign", "Exception caught while getting the type of a column"); + } + + return nDataType; +} + +IMPL_LINK_NOARG(OGroupsSortingDialog, OnControlFocusGot, LinkParamNone*, void ) +{ + m_xHelpWindow->set_label(RptResId(STR_RPT_HELP_FIELD)); +} + +IMPL_LINK(OGroupsSortingDialog, OnWidgetFocusGot, weld::Widget&, rControl, void ) +{ + const std::pair pControls[] = { + { m_xHeaderLst.get(), STR_RPT_HELP_HEADER }, + { m_xFooterLst.get(), STR_RPT_HELP_FOOTER }, + { m_xGroupOnLst.get(), STR_RPT_HELP_GROUPON }, + { m_xGroupIntervalEd.get(), STR_RPT_HELP_INTERVAL }, + { m_xKeepTogetherLst.get(), STR_RPT_HELP_KEEP }, + { m_xOrderLst.get(), STR_RPT_HELP_SORT } + }; + for (size_t i = 0; i < SAL_N_ELEMENTS(pControls); ++i) + { + if (&rControl == pControls[i].first) + { + weld::ComboBox* pListBox = dynamic_cast( &rControl ); + if ( pListBox ) + pListBox->save_value(); + weld::SpinButton* pNumericField = dynamic_cast(&rControl); + if ( pNumericField ) + pNumericField->save_value(); + //shows the text given by the id in the multiline edit + m_xHelpWindow->set_label(RptResId(pControls[i].second)); + break; + } + } +} + +IMPL_LINK_NOARG(OGroupsSortingDialog, OnWidgetFocusLost, weld::Widget&, void) +{ + if (m_xFieldExpression) + { + if (m_xGroupIntervalEd->get_value_changed_from_saved()) + SaveData(m_xFieldExpression->GetCurRow()); + } +} + +IMPL_LINK(OGroupsSortingDialog, OnFormatAction, const OString&, rCommand, void) +{ + if ( !m_xFieldExpression ) + return; + + tools::Long nIndex = m_xFieldExpression->GetCurrRow(); + sal_Int32 nGroupPos = m_xFieldExpression->getGroupPosition(nIndex); + uno::Sequence aClipboardList; + if ( nIndex >= 0 && nGroupPos != NO_GROUP ) + { + aClipboardList = { m_xGroups->getByIndex(nGroupPos) }; + } + if (rCommand == "up") + { + --nIndex; + } + if (rCommand == "down") + { + ++nIndex; + } + if (rCommand == "delete") + { + Application::PostUserEvent(LINK(m_xFieldExpression, OFieldExpressionControl, DelayedDelete)); + } + else + { + if ( nIndex >= 0 && aClipboardList.hasElements() ) + { + m_xFieldExpression->SetNoSelection(); + m_xFieldExpression->moveGroups(aClipboardList,nIndex,false); + m_xFieldExpression->DeactivateCell(); + m_xFieldExpression->GoToRow(nIndex); + m_xFieldExpression->ActivateCell(nIndex, m_xFieldExpression->GetCurColumnId()); + DisplayData(nIndex); + } + } +} + +IMPL_LINK( OGroupsSortingDialog, LBChangeHdl, weld::ComboBox&, rListBox, void ) +{ + if ( !rListBox.get_value_changed_from_saved() ) + return; + + sal_Int32 nRow = m_xFieldExpression->GetCurRow(); + sal_Int32 nGroupPos = m_xFieldExpression->getGroupPosition(nRow); + if (&rListBox != m_xHeaderLst.get() && &rListBox != m_xFooterLst.get()) + { + if ( rListBox.get_value_changed_from_saved() ) + SaveData(nRow); + if ( &rListBox == m_xGroupOnLst.get() ) + m_xGroupIntervalEd->set_sensitive(rListBox.get_active() != 0); + } + else if ( nGroupPos != NO_GROUP ) + { + uno::Reference< report::XGroup> xGroup = getGroup(nGroupPos); + const OUString aHeaderFooterOnName(( m_xHeaderLst.get() == &rListBox ) + ? std::u16string_view(PROPERTY_HEADERON) + : std::u16string_view(PROPERTY_FOOTERON)); + uno::Sequence< beans::PropertyValue > aArgs{ + comphelper::makePropertyValue(aHeaderFooterOnName, rListBox.get_active() == 0), + comphelper::makePropertyValue(PROPERTY_GROUP, xGroup) + }; + m_pController->executeChecked(m_xHeaderLst.get() == &rListBox ? SID_GROUPHEADER : SID_GROUPFOOTER, aArgs); + m_xFieldExpression->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_xFieldExpression->fillColumns(m_xColumns); +} + +void OGroupsSortingDialog::displayGroup(const uno::Reference& _xGroup) +{ + m_xHeaderLst->set_active(_xGroup->getHeaderOn() ? 0 : 1 ); + m_xFooterLst->set_active(_xGroup->getFooterOn() ? 0 : 1 ); + sal_Int32 nDataType = getColumnDataType(_xGroup->getExpression()); + + // first clear whole group on list + while (m_xGroupOnLst->get_count() > 1 ) + { + m_xGroupOnLst->remove(1); + } + + switch(nDataType) + { + case sdbc::DataType::LONGVARCHAR: + case sdbc::DataType::VARCHAR: + case sdbc::DataType::CHAR: + m_xGroupOnLst->append(OUString::number(report::GroupOn::PREFIX_CHARACTERS), RptResId(STR_RPT_PREFIXCHARS)); + break; + case sdbc::DataType::DATE: + case sdbc::DataType::TIME: + case sdbc::DataType::TIMESTAMP: + { + const TranslateId aIds[] = { STR_RPT_YEAR, STR_RPT_QUARTER,STR_RPT_MONTH,STR_RPT_WEEK,STR_RPT_DAY,STR_RPT_HOUR,STR_RPT_MINUTE }; + for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i) + { + m_xGroupOnLst->append(OUString::number(i+2), RptResId(aIds[i])); + } + } + break; + default: + m_xGroupOnLst->append(OUString::number(report::GroupOn::INTERVAL), RptResId(STR_RPT_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_xGroupOnLst->set_active(nPos); + m_xGroupIntervalEd->set_value(_xGroup->getGroupInterval()); + m_xGroupIntervalEd->save_value(); + m_xGroupIntervalEd->set_sensitive( nPos != 0 ); + m_xKeepTogetherLst->set_active(_xGroup->getKeepTogether()); + m_xOrderLst->set_active(_xGroup->getSortAscending() ? 0 : 1); + + weld::ComboBox* pControls[] = { m_xHeaderLst.get(), m_xFooterLst.get(), m_xGroupOnLst.get(), + m_xKeepTogetherLst.get(), m_xOrderLst.get() }; + for (weld::ComboBox* pControl : pControls) + pControl->save_value(); + + bool bReadOnly = !m_pController->isEditable(); + for (weld::ComboBox* pControl : pControls) + pControl->set_sensitive(!bReadOnly); + m_xGroupIntervalEd->set_editable(!bReadOnly); +} + +void OGroupsSortingDialog::checkButtons(sal_Int32 _nRow) +{ + sal_Int32 nGroupCount = m_xGroups->getCount(); + sal_Int32 nRowCount = m_xFieldExpression->GetRowCount(); + bool bEnabled = nGroupCount > 1; + + if (bEnabled && _nRow > 0 ) + { + m_xToolBox->set_item_sensitive("up", true); + } + else + { + m_xToolBox->set_item_sensitive("up", false); + } + if (bEnabled && _nRow < (nRowCount - 1) ) + { + m_xToolBox->set_item_sensitive("down", true); + } + else + { + m_xToolBox->set_item_sensitive("down", false); + } + + sal_Int32 nGroupPos = m_xFieldExpression->getGroupPosition(_nRow); + if ( nGroupPos != NO_GROUP ) + { + bool bEnableDelete = nGroupCount > 0; + m_xToolBox->set_item_sensitive("delete", bEnableDelete); + } + else + { + m_xToolBox->set_item_sensitive("delete", false); + } +} + +} // rptui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3