summaryrefslogtreecommitdiffstats
path: root/reportdesign/source/ui/dlg
diff options
context:
space:
mode:
Diffstat (limited to 'reportdesign/source/ui/dlg')
-rw-r--r--reportdesign/source/ui/dlg/AddField.cxx352
-rw-r--r--reportdesign/source/ui/dlg/CondFormat.cxx449
-rw-r--r--reportdesign/source/ui/dlg/Condition.cxx379
-rw-r--r--reportdesign/source/ui/dlg/Condition.hxx183
-rw-r--r--reportdesign/source/ui/dlg/DateTime.cxx209
-rw-r--r--reportdesign/source/ui/dlg/Formula.cxx275
-rw-r--r--reportdesign/source/ui/dlg/GroupExchange.cxx68
-rw-r--r--reportdesign/source/ui/dlg/GroupExchange.hxx43
-rw-r--r--reportdesign/source/ui/dlg/GroupsSorting.cxx1181
-rw-r--r--reportdesign/source/ui/dlg/Navigator.cxx814
-rw-r--r--reportdesign/source/ui/dlg/PageNumber.cxx104
-rw-r--r--reportdesign/source/ui/dlg/dlgpage.cxx78
12 files changed, 4135 insertions, 0 deletions
diff --git a/reportdesign/source/ui/dlg/AddField.cxx b/reportdesign/source/ui/dlg/AddField.cxx
new file mode 100644
index 0000000000..631a7f7d90
--- /dev/null
+++ b/reportdesign/source/ui/dlg/AddField.cxx
@@ -0,0 +1,352 @@
+/* -*- 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 <AddField.hxx>
+#include <UITools.hxx>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/XDocumentDataSource.hpp>
+
+#include <utility>
+#include <vcl/svapp.hxx>
+
+#include <comphelper/diagnose_ex.hxx>
+
+#include <connectivity/dbtools.hxx>
+#include <core_resource.hxx>
+#include <helpids.h>
+#include <strings.hrc>
+#include <strings.hxx>
+
+#include <comphelper/sequence.hxx>
+
+namespace rptui
+{
+
+using namespace ::com::sun::star;
+using namespace sdbc;
+using namespace sdb;
+using namespace uno;
+using namespace datatransfer;
+using namespace beans;
+using namespace lang;
+using namespace container;
+using namespace ::svx;
+
+IMPL_LINK(OAddFieldWindow, DragBeginHdl, bool&, rUnsetDragIcon, bool)
+{
+ rUnsetDragIcon = false;
+ if (m_xListBox->get_selected_index() == -1)
+ {
+ // no drag without a field
+ return true;
+ }
+
+ m_xHelper->setDescriptors(getSelectedFieldDescriptors());
+ return false;
+}
+
+OAddFieldWindow::OAddFieldWindow(weld::Window* pParent, uno::Reference< beans::XPropertySet > xRowSet)
+ : GenericDialogController(pParent, "modules/dbreport/ui/floatingfield.ui", "FloatingField")
+ , ::comphelper::OPropertyChangeListener(m_aMutex)
+ , ::comphelper::OContainerListener(m_aMutex)
+ , m_xRowSet(std::move(xRowSet))
+ , m_xActions(m_xBuilder->weld_toolbar("toolbox"))
+ , m_xListBox(m_xBuilder->weld_tree_view("treeview"))
+ , m_nCommandType(0)
+ , m_bEscapeProcessing(false)
+{
+ m_xListBox->set_help_id(HID_RPT_FIELD_SEL);
+ m_xListBox->set_selection_mode(SelectionMode::Multiple);
+ m_xHelper.set(new svx::OMultiColumnTransferable);
+ rtl::Reference<TransferDataContainer> xHelper(m_xHelper);
+ m_xListBox->enable_drag_source(xHelper, DND_ACTION_COPYMOVE | DND_ACTION_LINK);
+ m_xListBox->connect_drag_begin(LINK(this, OAddFieldWindow, DragBeginHdl));
+
+ m_xDialog->connect_container_focus_changed(LINK(this, OAddFieldWindow, FocusChangeHdl));
+
+ m_xDialog->set_help_id(HID_RPT_FIELD_SEL_WIN);
+
+ m_xActions->connect_clicked(LINK(this, OAddFieldWindow, OnSortAction));
+ m_xActions->set_item_active("up", true);
+ m_xListBox->make_sorted();
+ m_xActions->set_item_sensitive("insert", false);
+
+ m_xListBox->connect_row_activated(LINK( this, OAddFieldWindow, OnDoubleClickHdl ) );
+ m_xListBox->connect_changed(LINK( this, OAddFieldWindow, OnSelectHdl ) );
+ m_xListBox->set_size_request(m_xListBox->get_approximate_digit_width() * 45, m_xListBox->get_height_rows(8));
+
+ if (!m_xRowSet.is())
+ return;
+
+ try
+ {
+ // be notified when the settings of report definition change
+ m_pChangeListener = new ::comphelper::OPropertyChangeMultiplexer( this, m_xRowSet );
+ m_pChangeListener->addProperty( PROPERTY_COMMAND );
+ m_pChangeListener->addProperty( PROPERTY_COMMANDTYPE );
+ m_pChangeListener->addProperty( PROPERTY_ESCAPEPROCESSING );
+ m_pChangeListener->addProperty( PROPERTY_FILTER );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("reportdesign");
+ }
+}
+
+OAddFieldWindow::~OAddFieldWindow()
+{
+ m_aListBoxData.clear();
+ if (m_pChangeListener.is())
+ m_pChangeListener->dispose();
+ if ( m_pContainerListener.is() )
+ m_pContainerListener->dispose();
+}
+
+IMPL_LINK_NOARG(OAddFieldWindow, FocusChangeHdl, weld::Container&, void)
+{
+ if (m_xDialog->has_toplevel_focus())
+ m_xListBox->grab_focus();
+}
+
+uno::Sequence< beans::PropertyValue > OAddFieldWindow::getSelectedFieldDescriptors()
+{
+ std::vector<beans::PropertyValue> aArgs;
+
+ m_xListBox->selected_foreach([this, &aArgs](weld::TreeIter& rEntry){
+ // build a descriptor for the currently selected field
+ svx::ODataAccessDescriptor aDescriptor;
+ fillDescriptor(rEntry, aDescriptor);
+ aArgs.push_back(beans::PropertyValue());
+ aArgs.back().Value <<= aDescriptor.createPropertyValueSequence();
+
+ return false;
+ });
+
+ return comphelper::containerToSequence(aArgs);
+}
+
+void OAddFieldWindow::_propertyChanged( const beans::PropertyChangeEvent& _evt )
+{
+ OSL_ENSURE( _evt.Source == m_xRowSet, "OAddFieldWindow::_propertyChanged: where did this come from?" );
+ Update();
+}
+
+void OAddFieldWindow::addToList(const uno::Sequence< OUString >& rEntries)
+{
+ for (const OUString& rEntry : rEntries)
+ {
+ m_aListBoxData.emplace_back(new ColumnInfo(rEntry));
+ OUString sId(weld::toId(m_aListBoxData.back().get()));
+ m_xListBox->append(sId, rEntry);
+ }
+}
+
+void OAddFieldWindow::addToList(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_QUERY_THROW);
+ OUString sLabel;
+ if ( xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_LABEL) )
+ xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel;
+ m_aListBoxData.emplace_back(new ColumnInfo(rEntry, sLabel));
+ OUString sId(weld::toId(m_aListBoxData.back().get()));
+ if ( !sLabel.isEmpty() )
+ m_xListBox->append(sId, sLabel);
+ else
+ m_xListBox->append(sId, rEntry);
+ }
+}
+
+void OAddFieldWindow::Update()
+{
+ SolarMutexGuard aSolarGuard;
+
+ if ( m_pContainerListener.is() )
+ m_pContainerListener->dispose();
+ m_pContainerListener = nullptr;
+ m_xColumns.clear();
+
+ try
+ {
+ // ListBox loeschen
+ m_xListBox->clear();
+ m_aListBoxData.clear();
+ const OUString aIds[] = { "up", "down" };
+ for (size_t j = 0; j< std::size(aIds); ++j)
+ m_xActions->set_item_sensitive(aIds[j], false);
+
+ OUString aTitle(RptResId(RID_STR_FIELDSELECTION));
+ m_xDialog->set_title(aTitle);
+ if ( m_xRowSet.is() )
+ {
+ OUString sCommand( m_aCommandName );
+ sal_Int32 nCommandType( m_nCommandType );
+ bool bEscapeProcessing( m_bEscapeProcessing );
+ OUString sFilter( m_sFilter );
+
+ OSL_VERIFY( m_xRowSet->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand );
+ OSL_VERIFY( m_xRowSet->getPropertyValue( PROPERTY_COMMANDTYPE ) >>= nCommandType );
+ OSL_VERIFY( m_xRowSet->getPropertyValue( PROPERTY_ESCAPEPROCESSING ) >>= bEscapeProcessing );
+ OSL_VERIFY( m_xRowSet->getPropertyValue( PROPERTY_FILTER ) >>= sFilter );
+
+ m_aCommandName = sCommand;
+ m_nCommandType = nCommandType;
+ m_bEscapeProcessing = bEscapeProcessing;
+ m_sFilter = sFilter;
+
+ // add the columns to the list
+ uno::Reference< sdbc::XConnection> xCon = getConnection();
+ if ( xCon.is() && !m_aCommandName.isEmpty() )
+ m_xColumns = dbtools::getFieldsByCommandDescriptor( xCon, GetCommandType(), GetCommand(), m_xHoldAlive );
+ if ( m_xColumns.is() )
+ {
+ addToList(m_xColumns);
+ uno::Reference< container::XContainer> xContainer(m_xColumns,uno::UNO_QUERY);
+ if ( xContainer.is() )
+ m_pContainerListener = new ::comphelper::OContainerListenerAdapter(this,xContainer);
+ }
+
+ // add the parameter columns to the list
+ uno::Reference< css::sdbc::XRowSet > xRowSet(m_xRowSet,uno::UNO_QUERY);
+ Sequence< OUString > aParamNames( getParameterNames( xRowSet ) );
+ addToList(aParamNames);
+
+ // set title
+ aTitle += " " + m_aCommandName;
+ m_xDialog->set_title(aTitle);
+ if ( !m_aCommandName.isEmpty() )
+ {
+ for (size_t i = 0; i < std::size(aIds); ++i)
+ m_xActions->set_item_sensitive(aIds[i], true);
+ }
+ OnSelectHdl(*m_xListBox);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("reportdesign");
+ }
+}
+
+uno::Reference< sdbc::XConnection> OAddFieldWindow::getConnection() const
+{
+ return uno::Reference< sdbc::XConnection>(m_xRowSet->getPropertyValue( PROPERTY_ACTIVECONNECTION ),uno::UNO_QUERY);
+}
+
+void OAddFieldWindow::fillDescriptor(const weld::TreeIter& rSelected, svx::ODataAccessDescriptor& rDescriptor)
+{
+ if (!m_xColumns.is())
+ return;
+
+ uno::Reference<container::XChild> xChild(getConnection(),uno::UNO_QUERY);
+ if ( xChild.is( ) )
+ {
+ uno::Reference<sdb::XDocumentDataSource> xDocument( xChild->getParent(), uno::UNO_QUERY );
+ if ( xDocument.is() )
+ {
+ uno::Reference<frame::XModel> xModel(xDocument->getDatabaseDocument(),uno::UNO_QUERY);
+ if ( xModel.is() )
+ rDescriptor[ DataAccessDescriptorProperty::DatabaseLocation ] <<= xModel->getURL();
+ }
+ }
+
+ rDescriptor[ svx::DataAccessDescriptorProperty::Command ] <<= GetCommand();
+ rDescriptor[ svx::DataAccessDescriptorProperty::CommandType ] <<= GetCommandType();
+ rDescriptor[ svx::DataAccessDescriptorProperty::EscapeProcessing ] <<= m_bEscapeProcessing;
+ rDescriptor[ svx::DataAccessDescriptorProperty::Connection ] <<= getConnection();
+
+ ColumnInfo* pInfo = weld::fromId<ColumnInfo*>(m_xListBox->get_id(rSelected));
+ rDescriptor[ svx::DataAccessDescriptorProperty::ColumnName ] <<= pInfo->sColumnName;
+ if ( m_xColumns->hasByName( pInfo->sColumnName ) )
+ rDescriptor[ svx::DataAccessDescriptorProperty::ColumnObject ] = m_xColumns->getByName(pInfo->sColumnName);
+}
+
+void OAddFieldWindow::_elementInserted( const container::ContainerEvent& _rEvent )
+{
+ OUString sName;
+ if ( !((_rEvent.Accessor >>= sName) && m_xColumns->hasByName(sName)) )
+ return;
+
+ uno::Reference< beans::XPropertySet> xColumn(m_xColumns->getByName(sName),UNO_QUERY_THROW);
+ OUString sLabel;
+ if ( xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_LABEL) )
+ xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel;
+ m_aListBoxData.emplace_back(new ColumnInfo(sName, sLabel));
+ OUString sId(weld::toId(m_aListBoxData.back().get()));
+ if (!sLabel.isEmpty())
+ m_xListBox->append(sId, sLabel);
+ else
+ m_xListBox->append(sId, sName);
+}
+
+void OAddFieldWindow::_elementRemoved( const container::ContainerEvent& /*_rEvent*/ )
+{
+ m_xListBox->clear();
+ m_aListBoxData.clear();
+ if ( m_xColumns.is() )
+ addToList(m_xColumns);
+}
+
+void OAddFieldWindow::_elementReplaced( const container::ContainerEvent& /*_rEvent*/ )
+{
+}
+
+IMPL_LINK_NOARG( OAddFieldWindow, OnSelectHdl, weld::TreeView&, void )
+{
+ m_xActions->set_item_sensitive("insert", m_xListBox->get_selected_index() != -1);
+}
+
+IMPL_LINK_NOARG( OAddFieldWindow, OnDoubleClickHdl, weld::TreeView&, bool )
+{
+ m_aCreateLink.Call(*this);
+ return true;
+}
+
+IMPL_LINK(OAddFieldWindow, OnSortAction, const OUString&, rCurItem, void)
+{
+ if (rCurItem == "insert")
+ {
+ OnDoubleClickHdl(*m_xListBox);
+ return;
+ }
+
+ const OUString aIds[] = { "up", "down" };
+
+ if (rCurItem == "delete")
+ {
+ for (size_t j = 0; j< std::size(aIds); ++j)
+ m_xActions->set_item_active(aIds[j], false);
+
+ m_xListBox->make_unsorted();
+ Update();
+ return;
+ }
+
+ for (size_t j = 0; j< std::size(aIds); ++j)
+ m_xActions->set_item_active(aIds[j], rCurItem == aIds[j]);
+
+ m_xListBox->make_sorted();
+ if (m_xActions->get_item_active("down"))
+ m_xListBox->set_sort_order(false);
+}
+
+} // namespace rptui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/reportdesign/source/ui/dlg/CondFormat.cxx b/reportdesign/source/ui/dlg/CondFormat.cxx
new file mode 100644
index 0000000000..41173c9323
--- /dev/null
+++ b/reportdesign/source/ui/dlg/CondFormat.cxx
@@ -0,0 +1,449 @@
+/* -*- 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 <CondFormat.hxx>
+
+#include <strings.hxx>
+#include <strings.hrc>
+#include <core_resource.hxx>
+#include <ReportController.hxx>
+#include "Condition.hxx"
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <o3tl/safeint.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+
+#include <comphelper/diagnose_ex.hxx>
+
+#include <comphelper/property.hxx>
+#include <comphelper/propertyvalue.hxx>
+
+#include <algorithm>
+#include <UndoActions.hxx>
+
+
+namespace rptui
+{
+
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::beans::PropertyValue;
+ using ::com::sun::star::uno::Any;
+
+ using namespace ::com::sun::star::report;
+
+ void ConditionalFormattingDialog::impl_setPrefHeight(bool bFirst)
+ {
+ if (!m_bConstructed && !bFirst)
+ return;
+
+ //allow dialog to resize itself
+ size_t nCount = impl_getConditionCount();
+ if (!nCount)
+ return;
+
+ auto nHeight = m_aConditions[0]->get_preferred_size().Height();
+ size_t nVisibleConditions = ::std::min(nCount, MAX_CONDITIONS);
+ nHeight *= nVisibleConditions;
+ nHeight += 2;
+ if (nHeight != m_xScrollWindow->get_size_request().Height())
+ {
+ m_xScrollWindow->set_size_request(-1, nHeight);
+ if (!bFirst)
+ m_xDialog->resize_to_request();
+ }
+ }
+
+ ConditionalFormattingDialog::ConditionalFormattingDialog(
+ weld::Window* _pParent, const Reference< XReportControlModel >& _rxFormatConditions, ::rptui::OReportController& _rController)
+ : GenericDialogController(_pParent, "modules/dbreport/ui/condformatdialog.ui", "CondFormat")
+ , m_rController(_rController)
+ , m_xFormatConditions(_rxFormatConditions)
+ , m_bConstructed(false)
+ , m_xScrollWindow(m_xBuilder->weld_scrolled_window("scrolledwindow"))
+ , m_xConditionPlayground(m_xBuilder->weld_box("condPlaygroundDrawingarea"))
+ {
+ OSL_ENSURE( m_xFormatConditions.is(), "ConditionalFormattingDialog::ConditionalFormattingDialog: ReportControlModel is NULL -> Prepare for GPF!" );
+
+ m_xCopy.set( m_xFormatConditions->createClone(), UNO_QUERY_THROW );
+
+ m_xScrollWindow->connect_vadjustment_changed(LINK(this, ConditionalFormattingDialog, OnScroll));
+
+ impl_initializeConditions();
+
+ impl_setPrefHeight(true);
+
+ m_bConstructed = true;
+ }
+
+ ConditionalFormattingDialog::~ConditionalFormattingDialog()
+ {
+ }
+
+ void ConditionalFormattingDialog::impl_updateConditionIndicies()
+ {
+ sal_Int32 nIndex = 0;
+ for (const auto& rxCondition : m_aConditions)
+ {
+ rxCondition->setConditionIndex( nIndex, impl_getConditionCount() );
+ m_xConditionPlayground->reorder_child(rxCondition->get_widget(), nIndex);
+ ++nIndex;
+ }
+ }
+
+ void ConditionalFormattingDialog::impl_conditionCountChanged()
+ {
+ if ( m_aConditions.empty() )
+ impl_addCondition_nothrow( 0 );
+
+ impl_setPrefHeight(false);
+
+ impl_updateConditionIndicies();
+ impl_layoutAll();
+ }
+
+ void ConditionalFormattingDialog::addCondition( size_t _nAddAfterIndex )
+ {
+ OSL_PRECOND( _nAddAfterIndex < impl_getConditionCount(), "ConditionalFormattingDialog::addCondition: illegal condition index!" );
+ impl_addCondition_nothrow( _nAddAfterIndex + 1 );
+ }
+
+
+ void ConditionalFormattingDialog::deleteCondition( size_t _nCondIndex )
+ {
+ impl_deleteCondition_nothrow( _nCondIndex );
+ }
+
+
+ void ConditionalFormattingDialog::impl_addCondition_nothrow( size_t _nNewCondIndex )
+ {
+ try
+ {
+ if ( _nNewCondIndex > o3tl::make_unsigned(m_xCopy->getCount()) )
+ throw IllegalArgumentException();
+
+ Reference< XFormatCondition > xCond = m_xCopy->createFormatCondition();
+ ::comphelper::copyProperties(m_xCopy, xCond);
+ m_xCopy->insertByIndex( _nNewCondIndex, Any( xCond ) );
+ auto xCon = std::make_unique<Condition>(m_xConditionPlayground.get(), m_xDialog.get(), *this, m_rController);
+ xCon->setCondition(xCond);
+ m_xConditionPlayground->reorder_child(xCon->get_widget(), _nNewCondIndex);
+ m_aConditions.insert(m_aConditions.begin() + _nNewCondIndex, std::move(xCon));
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("reportdesign");
+ }
+
+ impl_conditionCountChanged();
+
+ impl_ensureConditionVisible( _nNewCondIndex );
+ }
+
+ void ConditionalFormattingDialog::impl_focusCondition( size_t _nCondIndex )
+ {
+ OSL_PRECOND( _nCondIndex < impl_getConditionCount(),
+ "ConditionalFormattingDialog::impl_focusCondition: illegal index!" );
+
+ impl_ensureConditionVisible( _nCondIndex );
+ m_aConditions[ _nCondIndex ]->grab_focus();
+ }
+
+ void ConditionalFormattingDialog::impl_deleteCondition_nothrow( size_t _nCondIndex )
+ {
+ OSL_PRECOND( _nCondIndex < impl_getConditionCount(),
+ "ConditionalFormattingDialog::impl_deleteCondition_nothrow: illegal index!" );
+
+ bool bLastCondition = ( impl_getConditionCount() == 1 );
+
+ bool bSetNewFocus = false;
+ size_t nNewFocusIndex( _nCondIndex );
+ try
+ {
+ if ( !bLastCondition )
+ m_xCopy->removeByIndex( _nCondIndex );
+
+ Conditions::iterator pos = m_aConditions.begin() + _nCondIndex;
+ if ( bLastCondition )
+ {
+ Reference< XFormatCondition > xFormatCondition( m_xCopy->getByIndex( 0 ), UNO_QUERY_THROW );
+ xFormatCondition->setFormula( OUString() );
+ (*pos)->setCondition( xFormatCondition );
+ }
+ else
+ {
+ bSetNewFocus = (*pos)->has_focus();
+
+ auto xMovedCondition = std::move(*pos);
+ m_aConditions.erase(pos);
+ m_xConditionPlayground->move(xMovedCondition->get_widget(), nullptr);
+ }
+
+ if ( bSetNewFocus )
+ {
+ if ( nNewFocusIndex >= impl_getConditionCount() )
+ nNewFocusIndex = impl_getConditionCount() - 1;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("reportdesign");
+ }
+
+ impl_conditionCountChanged();
+ if ( bSetNewFocus )
+ impl_focusCondition( nNewFocusIndex );
+ }
+
+
+ void ConditionalFormattingDialog::impl_moveCondition_nothrow( size_t _nCondIndex, bool _bMoveUp )
+ {
+ size_t nOldConditionIndex( _nCondIndex );
+ size_t nNewConditionIndex( _bMoveUp ? _nCondIndex - 1 : _nCondIndex + 1 );
+
+ // do this in two steps, so we don't become inconsistent if any of the UNO actions fails
+ Any aMovedCondition;
+ std::unique_ptr<Condition> xMovedCondition;
+ try
+ {
+ aMovedCondition = m_xCopy->getByIndex( static_cast<sal_Int32>(nOldConditionIndex) );
+ m_xCopy->removeByIndex( static_cast<sal_Int32>(nOldConditionIndex) );
+
+ Conditions::iterator aRemovePos( m_aConditions.begin() + nOldConditionIndex );
+ xMovedCondition = std::move(*aRemovePos);
+ m_aConditions.erase( aRemovePos );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("reportdesign");
+ return;
+ }
+
+ try
+ {
+ m_xCopy->insertByIndex( static_cast<sal_Int32>(nNewConditionIndex), aMovedCondition );
+ m_aConditions.insert(m_aConditions.begin() + nNewConditionIndex, std::move(xMovedCondition));
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("reportdesign");
+ }
+
+ // at least the two swapped conditions need to know their new index
+ impl_updateConditionIndicies();
+
+ // ensure the moved condition is visible
+ impl_ensureConditionVisible( nNewConditionIndex );
+ }
+
+ IMPL_LINK_NOARG(ConditionalFormattingDialog, OnScroll, weld::ScrolledWindow&, void)
+ {
+ size_t nFirstCondIndex( impl_getFirstVisibleConditionIndex() );
+ size_t nFocusCondIndex = impl_getFocusedConditionIndex( nFirstCondIndex );
+
+ if ( nFocusCondIndex < nFirstCondIndex )
+ impl_focusCondition( nFirstCondIndex );
+ else if ( nFocusCondIndex >= nFirstCondIndex + MAX_CONDITIONS )
+ impl_focusCondition( nFirstCondIndex + MAX_CONDITIONS - 1 );
+ }
+
+ void ConditionalFormattingDialog::impl_layoutAll()
+ {
+ // scrollbar visibility
+ if ( m_aConditions.size() <= MAX_CONDITIONS )
+ // normalize the position, so it can, in all situations, be used as top index
+ m_xScrollWindow->vadjustment_set_value(0);
+ }
+
+ void ConditionalFormattingDialog::impl_initializeConditions()
+ {
+ try
+ {
+ sal_Int32 nCount = m_xCopy->getCount();
+ for ( sal_Int32 i = 0; i < nCount ; ++i )
+ {
+ auto xCon = std::make_unique<Condition>(m_xConditionPlayground.get(), m_xDialog.get(), *this, m_rController);
+ Reference< XFormatCondition > xCond( m_xCopy->getByIndex(i), UNO_QUERY );
+ m_xConditionPlayground->reorder_child(xCon->get_widget(), i);
+ xCon->setCondition(xCond);
+ xCon->updateToolbar(xCond);
+ m_aConditions.push_back(std::move(xCon));
+ }
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("Can not access format condition!");
+ }
+
+ impl_conditionCountChanged();
+ }
+
+ void ConditionalFormattingDialog::applyCommand(size_t _nCondIndex, sal_uInt16 _nCommandId, const ::Color& rColor)
+ {
+ OSL_PRECOND( _nCommandId, "ConditionalFormattingDialog::applyCommand: illegal command id!" );
+ try
+ {
+ Reference< XReportControlFormat > xReportControlFormat( m_xCopy->getByIndex( _nCondIndex ), UNO_QUERY_THROW );
+
+ Sequence< PropertyValue > aArgs{
+ comphelper::makePropertyValue(REPORTCONTROLFORMAT, xReportControlFormat),
+ comphelper::makePropertyValue(CURRENT_WINDOW, m_xDialog->GetXWindow()),
+ comphelper::makePropertyValue(PROPERTY_FONTCOLOR, rColor)
+ };
+
+ // we use this way to create undo actions
+ m_rController.executeUnChecked(_nCommandId,aArgs);
+ m_aConditions[ _nCondIndex ]->updateToolbar(xReportControlFormat);
+ }
+ catch( Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("reportdesign");
+ }
+ }
+
+
+ void ConditionalFormattingDialog::moveConditionUp( size_t _nCondIndex )
+ {
+ OSL_PRECOND( _nCondIndex > 0, "ConditionalFormattingDialog::moveConditionUp: cannot move up the first condition!" );
+ if ( _nCondIndex > 0 )
+ impl_moveCondition_nothrow( _nCondIndex, true );
+ }
+
+
+ void ConditionalFormattingDialog::moveConditionDown( size_t _nCondIndex )
+ {
+ OSL_PRECOND( _nCondIndex < impl_getConditionCount(), "ConditionalFormattingDialog::moveConditionDown: cannot move down the last condition!" );
+ if ( _nCondIndex < impl_getConditionCount() )
+ impl_moveCondition_nothrow( _nCondIndex, false );
+ }
+
+ OUString ConditionalFormattingDialog::getDataField() const
+ {
+ OUString sDataField;
+ try
+ {
+ sDataField = m_xFormatConditions->getDataField();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("reportdesign");
+ }
+ return sDataField;
+ }
+
+ short ConditionalFormattingDialog::run()
+ {
+ short nRet = GenericDialogController::run();
+ if (nRet == RET_OK)
+ {
+ const OUString sUndoAction( RptResId( RID_STR_UNDO_CONDITIONAL_FORMATTING ) );
+ const UndoContext aUndoContext( m_rController.getUndoManager(), sUndoAction );
+ try
+ {
+ sal_Int32 j(0), i(0);
+ for ( Conditions::const_iterator cond = m_aConditions.begin();
+ cond != m_aConditions.end();
+ ++cond, ++i
+ )
+ {
+ Reference< XFormatCondition > xCond( m_xCopy->getByIndex(i), UNO_QUERY_THROW );
+ (*cond)->fillFormatCondition( xCond );
+
+ if ( (*cond)->isEmpty() )
+ continue;
+
+ Reference< XFormatCondition > xNewCond;
+ bool bAppend = j >= m_xFormatConditions->getCount();
+ if ( bAppend )
+ {
+ xNewCond = m_xFormatConditions->createFormatCondition();
+ m_xFormatConditions->insertByIndex( i, Any( xNewCond ) );
+ }
+ else
+ xNewCond.set( m_xFormatConditions->getByIndex(j), UNO_QUERY );
+ ++j;
+
+ ::comphelper::copyProperties(xCond, xNewCond);
+ }
+
+ for ( sal_Int32 k = m_xFormatConditions->getCount()-1; k >= j; --k )
+ m_xFormatConditions->removeByIndex(k);
+
+ ::comphelper::copyProperties( m_xCopy, m_xFormatConditions );
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("reportdesign");
+ nRet = RET_NO;
+ }
+ }
+ return nRet;
+ }
+
+ size_t ConditionalFormattingDialog::impl_getFirstVisibleConditionIndex() const
+ {
+ auto nHeight = m_aConditions[0]->get_preferred_size().Height();
+ return m_xScrollWindow->vadjustment_get_value() / nHeight;
+ }
+
+ size_t ConditionalFormattingDialog::impl_getLastVisibleConditionIndex() const
+ {
+ return ::std::min( impl_getFirstVisibleConditionIndex() + MAX_CONDITIONS, impl_getConditionCount() ) - 1;
+ }
+
+ size_t ConditionalFormattingDialog::impl_getFocusedConditionIndex( sal_Int32 _nFallBackIfNone ) const
+ {
+ auto cond = std::find_if(m_aConditions.begin(), m_aConditions.end(),
+ [](const std::unique_ptr<Condition>& rxCondition) { return rxCondition->has_focus(); });
+ if (cond != m_aConditions.end())
+ return static_cast<size_t>(std::distance(m_aConditions.begin(), cond));
+ return _nFallBackIfNone;
+ }
+
+ void ConditionalFormattingDialog::impl_scrollTo( size_t nTopCondIndex )
+ {
+ OSL_PRECOND( nTopCondIndex + MAX_CONDITIONS <= impl_getConditionCount(),
+ "ConditionalFormattingDialog::impl_scrollTo: illegal index!" );
+
+ auto nHeight = m_aConditions[0]->get_preferred_size().Height();
+ m_xScrollWindow->vadjustment_set_value(nTopCondIndex * nHeight);
+ OnScroll(*m_xScrollWindow);
+ }
+
+ void ConditionalFormattingDialog::impl_ensureConditionVisible( size_t _nCondIndex )
+ {
+ OSL_PRECOND( _nCondIndex < impl_getConditionCount(),
+ "ConditionalFormattingDialog::impl_ensureConditionVisible: illegal index!" );
+
+ if ( _nCondIndex < impl_getFirstVisibleConditionIndex() )
+ impl_scrollTo( _nCondIndex );
+ else if ( _nCondIndex > impl_getLastVisibleConditionIndex() )
+ impl_scrollTo( _nCondIndex - MAX_CONDITIONS + 1 );
+ }
+
+
+} // rptui
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/reportdesign/source/ui/dlg/Condition.cxx b/reportdesign/source/ui/dlg/Condition.cxx
new file mode 100644
index 0000000000..c442e4ccfc
--- /dev/null
+++ b/reportdesign/source/ui/dlg/Condition.cxx
@@ -0,0 +1,379 @@
+/* -*- 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 "Condition.hxx"
+#include <UITools.hxx>
+#include <CondFormat.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <ReportController.hxx>
+#include <reportformula.hxx>
+
+#include <svx/PaletteManager.hxx>
+#include <svx/svxids.hrc>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+#include <comphelper/diagnose_ex.hxx>
+
+namespace rptui
+{
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+
+ConditionField::ConditionField(Condition* pParent, std::unique_ptr<weld::Entry> xSubEdit,
+ std::unique_ptr<weld::Button> xFormula)
+ : m_pParent(pParent)
+ , m_xSubEdit(std::move(xSubEdit))
+ , m_xFormula(std::move(xFormula))
+{
+ m_xFormula->set_label("...");
+ m_xFormula->connect_clicked( LINK( this, ConditionField, OnFormula ) );
+}
+
+IMPL_LINK_NOARG(ConditionField, OnFormula, weld::Button&, void)
+{
+ OUString sFormula(m_xSubEdit->get_text());
+ const sal_Int32 nLen = sFormula.getLength();
+ if ( nLen )
+ {
+ ReportFormula aFormula( sFormula );
+ sFormula = aFormula.getCompleteFormula();
+ }
+ uno::Reference< awt::XWindow> xInspectorWindow = m_pParent->GetXWindow();
+ uno::Reference< beans::XPropertySet> xProp(m_pParent->getController().getRowSet(),uno::UNO_QUERY);
+ if ( rptui::openDialogFormula_nothrow( sFormula, m_pParent->getController().getContext(),xInspectorWindow,xProp ) )
+ {
+ ReportFormula aFormula( sFormula );
+ m_xSubEdit->set_text(aFormula.getUndecoratedContent());
+ }
+}
+
+ConditionColorWrapper::ConditionColorWrapper(Condition* pControl, sal_uInt16 nSlotId)
+ : mpControl(pControl)
+ , mnSlotId(nSlotId)
+{
+}
+
+void ConditionColorWrapper::operator()(
+ [[maybe_unused]] const OUString& /*rCommand*/, const NamedColor& rNamedColor)
+{
+ mpControl->ApplyCommand(mnSlotId, rNamedColor);
+}
+
+// = Condition
+Condition::Condition(weld::Container* pParent, weld::Window* pDialog, IConditionalFormatAction& _rAction, ::rptui::OReportController& _rController)
+ : m_xPaletteManager(std::make_shared<PaletteManager>())
+ , m_aBackColorWrapper(this, SID_BACKGROUND_COLOR)
+ , m_aForeColorWrapper(this, SID_ATTR_CHAR_COLOR2)
+ , m_rController(_rController)
+ , m_rAction(_rAction)
+ , m_nCondIndex(0)
+ , m_pDialog(pDialog)
+ , m_xBuilder(Application::CreateBuilder(pParent, "modules/dbreport/ui/conditionwin.ui"))
+ , m_xContainer(m_xBuilder->weld_container("ConditionWin"))
+ , m_xHeader(m_xBuilder->weld_label("headerLabel"))
+ , m_xConditionType(m_xBuilder->weld_combo_box("typeCombobox"))
+ , m_xOperationList(m_xBuilder->weld_combo_box("opCombobox"))
+ , m_xOperandGlue(m_xBuilder->weld_label("andLabel"))
+ , m_xActions(m_xBuilder->weld_toolbar("formatToolbox"))
+ , m_xPreview(new weld::CustomWeld(*m_xBuilder, "previewDrawingarea", m_aPreview))
+ , m_xMoveUp(m_xBuilder->weld_button("upButton"))
+ , m_xMoveDown(m_xBuilder->weld_button("downButton"))
+ , m_xAddCondition(m_xBuilder->weld_button("addButton"))
+ , m_xRemoveCondition(m_xBuilder->weld_button("removeButton"))
+{
+ m_xCondLHS.reset(new ConditionField(this, m_xBuilder->weld_entry("lhsEntry"), m_xBuilder->weld_button("lhsButton")));
+ m_xCondRHS.reset(new ConditionField(this, m_xBuilder->weld_entry("rhsEntry"), m_xBuilder->weld_button("rhsButton")));
+
+ m_xCondLHS->grab_focus();
+
+ m_xConditionType->connect_changed( LINK( this, Condition, OnTypeSelected ) );
+
+ m_xOperationList->connect_changed( LINK( this, Condition, OnOperationSelected ) );
+
+ m_xActions->connect_clicked(LINK(this, Condition, OnFormatAction));
+
+ m_xMoveUp->connect_clicked( LINK( this, Condition, OnConditionAction ) );
+ m_xMoveDown->connect_clicked( LINK( this, Condition, OnConditionAction ) );
+ m_xAddCondition->connect_clicked( LINK( this, Condition, OnConditionAction ) );
+ m_xRemoveCondition->connect_clicked( LINK( this, Condition, OnConditionAction ) );
+
+ m_xConditionType->set_active(0);
+ m_xOperationList->set_active(0);
+
+ SetBackgroundDropdownClick();
+ SetForegroundDropdownClick();
+
+ m_xContainer->show();
+
+ ConditionalExpressionFactory::getKnownConditionalExpressions( m_aConditionalExpressions );
+}
+
+sal_uInt16 Condition::mapToolbarItemToSlotId(std::u16string_view rItemId)
+{
+ if (rItemId == u"bold")
+ return SID_ATTR_CHAR_WEIGHT;
+ if (rItemId == u"italic")
+ return SID_ATTR_CHAR_POSTURE;
+ if (rItemId == u"underline")
+ return SID_ATTR_CHAR_UNDERLINE;
+ if (rItemId == u"background")
+ return SID_BACKGROUND_COLOR;
+ if (rItemId == u"foreground")
+ return SID_ATTR_CHAR_COLOR2;
+ if (rItemId == u"fontdialog")
+ return SID_CHAR_DLG;
+ return 0;
+}
+
+Condition::~Condition()
+{
+}
+
+void Condition::SetBackgroundDropdownClick()
+{
+ m_xBackColorFloat.reset(new ColorWindow(
+ OUString() /*m_aCommandURL*/,
+ m_xPaletteManager,
+ m_aColorStatus,
+ SID_BACKGROUND_COLOR,
+ nullptr,
+ MenuOrToolMenuButton(m_xActions.get(), "background"),
+ [this]{ return m_pDialog; },
+ m_aBackColorWrapper));
+
+ m_xActions->set_item_popover("background", m_xBackColorFloat->getTopLevel());
+}
+
+void Condition::SetForegroundDropdownClick()
+{
+ m_xForeColorFloat.reset(new ColorWindow(
+ OUString() /*m_aCommandURL*/,
+ m_xPaletteManager,
+ m_aColorStatus,
+ SID_ATTR_CHAR_COLOR2,
+ nullptr,
+ MenuOrToolMenuButton(m_xActions.get(), "foreground"),
+ [this]{ return m_pDialog; },
+ m_aForeColorWrapper));
+
+ m_xActions->set_item_popover("foreground", m_xForeColorFloat->getTopLevel());
+}
+
+
+IMPL_LINK(Condition, OnFormatAction, const OUString&, rIdent, void)
+{
+ ApplyCommand(mapToolbarItemToSlotId(rIdent),
+ NamedColor(COL_AUTO, "#" + COL_AUTO.AsRGBHexString()));
+}
+
+IMPL_LINK(Condition, OnConditionAction, weld::Button&, rClickedButton, void)
+{
+ if ( &rClickedButton == m_xMoveUp.get() )
+ m_rAction.moveConditionUp( getConditionIndex() );
+ else if ( &rClickedButton == m_xMoveDown.get() )
+ m_rAction.moveConditionDown( getConditionIndex() );
+ else if ( &rClickedButton == m_xAddCondition.get() )
+ m_rAction.addCondition( getConditionIndex() );
+ else if ( &rClickedButton == m_xRemoveCondition.get() )
+ m_rAction.deleteCondition( getConditionIndex() );
+}
+
+void Condition::ApplyCommand( sal_uInt16 _nCommandId, const NamedColor& rNamedColor )
+{
+ m_rAction.applyCommand(m_nCondIndex, _nCommandId, rNamedColor.m_aColor);
+}
+
+IMPL_LINK_NOARG( Condition, OnTypeSelected, weld::ComboBox&, void )
+{
+ impl_layoutOperands();
+}
+
+IMPL_LINK_NOARG( Condition, OnOperationSelected, weld::ComboBox&, void )
+{
+ impl_layoutOperands();
+}
+
+void Condition::impl_layoutOperands()
+{
+ const ConditionType eType( impl_getCurrentConditionType() );
+ const ComparisonOperation eOperation( impl_getCurrentComparisonOperation() );
+
+ const bool bIsExpression = ( eType == eExpression );
+ const bool bHaveRHS =
+ ( ( eType == eFieldValueComparison )
+ && ( ( eOperation == eBetween )
+ || ( eOperation == eNotBetween )
+ )
+ );
+
+ // the "condition type" list box
+ m_xOperationList->set_visible( !bIsExpression );
+ m_xOperandGlue->set_visible( bHaveRHS );
+ m_xCondRHS->set_visible( bHaveRHS );
+}
+
+void Condition::impl_setCondition( const OUString& _rConditionFormula )
+{
+ // determine the condition's type and comparison operation
+ ConditionType eType( eFieldValueComparison );
+ ComparisonOperation eOperation( eBetween );
+
+ // LHS and RHS, matched below
+ OUString sLHS, sRHS;
+
+ if ( !_rConditionFormula.isEmpty() )
+ {
+ // the unprefixed expression which forms the condition
+ ReportFormula aFormula( _rConditionFormula );
+ OSL_ENSURE( aFormula.getType() == ReportFormula::Expression, "Condition::setCondition: illegal formula!" );
+ OUString sExpression;
+ if ( aFormula.getType() == ReportFormula::Expression )
+ sExpression = aFormula.getExpression();
+ // as fallback, if the below matching does not succeed, assume
+ // the whole expression is the LHS
+ eType = eExpression;
+ sLHS = sExpression;
+
+ // the data field (or expression) to which our control is bound
+ const ReportFormula aFieldContentFormula( m_rAction.getDataField() );
+ const OUString sUnprefixedFieldContent( aFieldContentFormula.getBracketedFieldOrExpression() );
+
+ // check whether one of the Field Value Expression Factories recognizes the expression
+ for (const auto& [rOperation, rxConditionalExpression] : m_aConditionalExpressions)
+ {
+ if ( rxConditionalExpression->matchExpression( sExpression, sUnprefixedFieldContent, sLHS, sRHS ) )
+ {
+ eType = eFieldValueComparison;
+ eOperation = rOperation;
+ break;
+ }
+ }
+ }
+
+ // update UI
+ m_xConditionType->set_active(static_cast<sal_uInt16>(eType));
+ m_xOperationList->set_active(static_cast<sal_uInt16>(eOperation));
+ m_xCondLHS->set_text( sLHS );
+ m_xCondRHS->set_text( sRHS );
+
+ // re-layout
+ impl_layoutOperands();
+}
+
+
+void Condition::setCondition( const uno::Reference< report::XFormatCondition >& _rxCondition )
+{
+ OSL_PRECOND( _rxCondition.is(), "Condition::setCondition: empty condition object!" );
+ if ( !_rxCondition.is() )
+ return;
+
+ OUString sConditionFormula;
+ try
+ {
+ if ( _rxCondition.is() )
+ sConditionFormula = _rxCondition->getFormula();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("reportdesign");
+ }
+ impl_setCondition( sConditionFormula );
+ updateToolbar( _rxCondition );
+}
+
+
+void Condition::updateToolbar(const uno::Reference< report::XReportControlFormat >& _xReportControlFormat)
+{
+ OUString aItems[] = { "bold", "italic", "underline", "fontdialog" };
+
+ OSL_ENSURE(_xReportControlFormat.is(),"XReportControlFormat is NULL!");
+ if ( !_xReportControlFormat.is() )
+ return;
+
+ for (size_t j = 0; j < SAL_N_ELEMENTS(aItems); ++j)
+ {
+ m_xActions->set_item_active(aItems[j], OReportController::isFormatCommandEnabled(mapToolbarItemToSlotId(aItems[j]),
+ _xReportControlFormat));
+ }
+
+ try
+ {
+ vcl::Font aBaseFont( Application::GetDefaultDevice()->GetSettings().GetStyleSettings().GetAppFont() );
+ SvxFont aFont( VCLUnoHelper::CreateFont( _xReportControlFormat->getFontDescriptor(), aBaseFont ) );
+ aFont.SetFontHeight(o3tl::convert(aFont.GetFontHeight(), o3tl::Length::pt, o3tl::Length::twip));
+ aFont.SetEmphasisMark( static_cast< FontEmphasisMark >( _xReportControlFormat->getControlTextEmphasis() ) );
+ aFont.SetRelief( static_cast< FontRelief >( _xReportControlFormat->getCharRelief() ) );
+ aFont.SetColor( Color(ColorTransparency, _xReportControlFormat->getCharColor()) );
+ m_aPreview.SetFont( aFont, aFont, aFont );
+ m_aPreview.SetTextLineColor( Color( ColorTransparency, _xReportControlFormat->getCharUnderlineColor() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("reportdesign");
+ }
+}
+
+void Condition::fillFormatCondition(const uno::Reference< report::XFormatCondition >& _xCondition)
+{
+ const ConditionType eType( impl_getCurrentConditionType() );
+ const ComparisonOperation eOperation( impl_getCurrentComparisonOperation() );
+
+ const OUString sLHS( m_xCondLHS->get_text() );
+ const OUString sRHS( m_xCondRHS->get_text() );
+
+ OUString sUndecoratedFormula( sLHS );
+
+ if ( eType == eFieldValueComparison )
+ {
+ ReportFormula aFieldContentFormula( m_rAction.getDataField() );
+ OUString sUnprefixedFieldContent( aFieldContentFormula.getBracketedFieldOrExpression() );
+
+ PConditionalExpression pFactory( m_aConditionalExpressions[ eOperation ] );
+ sUndecoratedFormula = pFactory->assembleExpression( sUnprefixedFieldContent, sLHS, sRHS );
+ }
+
+ ReportFormula aFormula( ReportFormula::Expression, sUndecoratedFormula );
+ _xCondition->setFormula( aFormula.getCompleteFormula() );
+}
+
+void Condition::setConditionIndex( size_t _nCondIndex, size_t _nCondCount )
+{
+ m_nCondIndex = _nCondIndex;
+ OUString sHeader( RptResId( STR_NUMBERED_CONDITION ) );
+ sHeader = sHeader.replaceFirst( "$number$", OUString::number( _nCondIndex + 1) );
+ m_xHeader->set_label( sHeader );
+
+ m_xMoveUp->set_sensitive(_nCondIndex > 0);
+ OSL_PRECOND( _nCondCount > 0, "Condition::setConditionIndex: having no conditions at all is nonsense!" );
+ m_xMoveDown->set_sensitive(_nCondIndex < _nCondCount - 1);
+}
+
+bool Condition::isEmpty() const
+{
+ return m_xCondLHS->get_text().isEmpty();
+}
+
+} // rptui
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/reportdesign/source/ui/dlg/Condition.hxx b/reportdesign/source/ui/dlg/Condition.hxx
new file mode 100644
index 0000000000..a5e02d09bd
--- /dev/null
+++ b/reportdesign/source/ui/dlg/Condition.hxx
@@ -0,0 +1,183 @@
+/* -*- 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 .
+ */
+
+#ifndef INCLUDED_REPORTDESIGN_SOURCE_UI_DLG_CONDITION_HXX
+#define INCLUDED_REPORTDESIGN_SOURCE_UI_DLG_CONDITION_HXX
+
+#include <conditionalexpression.hxx>
+
+#include <com/sun/star/report/XFormatCondition.hpp>
+
+#include <svx/colorwindow.hxx>
+#include <svx/fntctrl.hxx>
+
+#include <vcl/customweld.hxx>
+#include <vcl/weld.hxx>
+
+#include <memory>
+
+namespace rptui
+{
+ class OColorPopup;
+ class OReportController;
+ class IConditionalFormatAction;
+ class Condition;
+
+ class ConditionField
+ {
+ Condition* m_pParent;
+ std::unique_ptr<weld::Entry> m_xSubEdit;
+ std::unique_ptr<weld::Button> m_xFormula;
+
+ DECL_LINK(OnFormula, weld::Button&, void);
+ public:
+ ConditionField(Condition* pParent, std::unique_ptr<weld::Entry> xSubEdit, std::unique_ptr<weld::Button> xFormula);
+ void grab_focus() { m_xSubEdit->grab_focus(); }
+ void set_visible(bool bShow) { m_xSubEdit->set_visible(bShow); m_xFormula->set_visible(bShow); }
+ void set_text(const OUString& rText) { m_xSubEdit->set_text(rText); }
+ OUString get_text() const { return m_xSubEdit->get_text(); }
+ };
+
+ class ConditionColorWrapper
+ {
+ public:
+ ConditionColorWrapper(Condition* pControl, sal_uInt16 nSlotId);
+ void operator()(const OUString& rCommand, const NamedColor& rColor);
+ // ColorSelectFunction signature
+ private:
+ Condition* mpControl;
+ sal_uInt16 mnSlotId;
+ };
+
+ //= Condition
+
+ class Condition
+ {
+ std::shared_ptr<PaletteManager> m_xPaletteManager;
+ ColorStatus m_aColorStatus;
+ ConditionColorWrapper m_aBackColorWrapper;
+ ConditionColorWrapper m_aForeColorWrapper;
+
+ ::rptui::OReportController& m_rController;
+ IConditionalFormatAction& m_rAction;
+
+ size_t m_nCondIndex;
+
+ ConditionalExpressions m_aConditionalExpressions;
+
+ SvxFontPrevWindow m_aPreview;
+ weld::Window* m_pDialog;
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xContainer;
+ std::unique_ptr<weld::Label> m_xHeader;
+ std::unique_ptr<weld::ComboBox> m_xConditionType;
+ std::unique_ptr<weld::ComboBox> m_xOperationList;
+ std::unique_ptr<ConditionField> m_xCondLHS;
+ std::unique_ptr<weld::Label> m_xOperandGlue;
+ std::unique_ptr<ConditionField> m_xCondRHS;
+ std::unique_ptr<weld::Toolbar> m_xActions;
+ std::unique_ptr<weld::CustomWeld> m_xPreview;
+ std::unique_ptr<weld::Button> m_xMoveUp;
+ std::unique_ptr<weld::Button> m_xMoveDown;
+ std::unique_ptr<weld::Button> m_xAddCondition;
+ std::unique_ptr<weld::Button> m_xRemoveCondition;
+ std::unique_ptr<ColorWindow> m_xBackColorFloat;
+ std::unique_ptr<ColorWindow> m_xForeColorFloat;
+
+ void SetBackgroundDropdownClick();
+ void SetForegroundDropdownClick();
+
+ DECL_LINK( OnFormatAction, const OUString&, void );
+ DECL_LINK( OnConditionAction, weld::Button&, void );
+
+ public:
+ Condition(weld::Container* pParent, weld::Window* pDialog, IConditionalFormatAction& rAction, ::rptui::OReportController& rController);
+ ~Condition();
+
+ /** sets the props at the control
+ @param _xCondition the source
+ */
+ void setCondition(const css::uno::Reference< css::report::XFormatCondition >& _xCondition);
+
+ /** fills from the control
+ _xCondition the destination
+ */
+ void fillFormatCondition(const css::uno::Reference< css::report::XFormatCondition >& _xCondition);
+
+ /** updates the toolbar
+ _xCondition the destination
+ */
+ void updateToolbar(const css::uno::Reference< css::report::XReportControlFormat >& _xCondition);
+
+ /// tells the condition its new index within the dialog's condition array
+ void setConditionIndex( size_t _nCondIndex, size_t _nCondCount );
+
+ /// returns the condition's index within the dialog's condition array
+ size_t getConditionIndex() const { return m_nCondIndex; }
+
+ /** determines whether the condition is actually empty
+ */
+ bool isEmpty() const;
+
+ /** forward to the parent class
+ */
+ void ApplyCommand( sal_uInt16 _nCommandId, const NamedColor& rNamedColor );
+
+ ::rptui::OReportController& getController() const { return m_rController; }
+
+ static sal_uInt16 mapToolbarItemToSlotId(std::u16string_view rItemId);
+
+ css::uno::Reference<css::awt::XWindow> GetXWindow() const { return m_pDialog->GetXWindow(); }
+
+ void grab_focus() { m_xContainer->grab_focus(); }
+ bool has_focus() const { return m_xContainer->has_focus(); }
+ Size get_preferred_size() const { return m_xContainer->get_preferred_size(); }
+ weld::Widget* get_widget() const { return m_xContainer.get(); }
+
+ private:
+ void impl_layoutOperands();
+
+ inline ConditionType
+ impl_getCurrentConditionType() const;
+
+ inline ComparisonOperation
+ impl_getCurrentComparisonOperation() const;
+
+ void impl_setCondition( const OUString& _rConditionFormula );
+
+ private:
+ DECL_LINK( OnTypeSelected, weld::ComboBox&, void );
+ DECL_LINK( OnOperationSelected, weld::ComboBox&, void );
+ };
+
+ inline ConditionType Condition::impl_getCurrentConditionType() const
+ {
+ return sal::static_int_cast<ConditionType>(m_xConditionType->get_active());
+ }
+
+ inline ComparisonOperation Condition::impl_getCurrentComparisonOperation() const
+ {
+ return sal::static_int_cast<ComparisonOperation>(m_xOperationList->get_active());
+ }
+
+} // namespace rptui
+
+#endif // INCLUDED_REPORTDESIGN_SOURCE_UI_DLG_CONDITION_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/reportdesign/source/ui/dlg/DateTime.cxx b/reportdesign/source/ui/dlg/DateTime.cxx
new file mode 100644
index 0000000000..90c57927cd
--- /dev/null
+++ b/reportdesign/source/ui/dlg/DateTime.cxx
@@ -0,0 +1,209 @@
+/* -*- 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 <DateTime.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <rptui_slotid.hrc>
+#include <connectivity/dbconversion.hxx>
+#include <unotools/syslocale.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <strings.hxx>
+#include <ReportController.hxx>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/XNumberFormatPreviewer.hpp>
+#include <algorithm>
+
+namespace rptui
+{
+using namespace ::com::sun::star;
+using namespace ::comphelper;
+
+
+
+ODateTimeDialog::ODateTimeDialog(weld::Window* _pParent, uno::Reference< report::XSection > _xHoldAlive,
+ OReportController* _pController)
+ : GenericDialogController(_pParent, "modules/dbreport/ui/datetimedialog.ui", "DateTimeDialog")
+
+ , m_pController(_pController)
+ , m_xHoldAlive(std::move(_xHoldAlive))
+ , m_xDate(m_xBuilder->weld_check_button("date"))
+ , m_xFTDateFormat(m_xBuilder->weld_label("datelistbox_label"))
+ , m_xDateListBox(m_xBuilder->weld_combo_box("datelistbox"))
+ , m_xTime(m_xBuilder->weld_check_button("time"))
+ , m_xFTTimeFormat(m_xBuilder->weld_label("timelistbox_label"))
+ , m_xTimeListBox(m_xBuilder->weld_combo_box("timelistbox"))
+ , m_xPB_OK(m_xBuilder->weld_button("ok"))
+{
+ try
+ {
+ SvtSysLocale aSysLocale;
+ m_nLocale = aSysLocale.GetLanguageTag().getLocale();
+ // Fill listbox with all well known date types
+ InsertEntry(util::NumberFormat::DATE);
+ InsertEntry(util::NumberFormat::TIME);
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ m_xDateListBox->set_active(0);
+ m_xTimeListBox->set_active(0);
+
+ weld::CheckButton* aCheckBoxes[] = { m_xDate.get(), m_xTime.get() };
+ for (weld::CheckButton* pCheckBox : aCheckBoxes)
+ pCheckBox->connect_toggled(LINK(this,ODateTimeDialog,CBClickHdl));
+ CBClickHdl(*m_xTime);
+}
+
+void ODateTimeDialog::InsertEntry(sal_Int16 _nNumberFormatId)
+{
+ const bool bTime = util::NumberFormat::TIME == _nNumberFormatId;
+ weld::ComboBox* pListBox = m_xDateListBox.get();
+ if (bTime)
+ pListBox = m_xTimeListBox.get();
+
+ const uno::Reference< util::XNumberFormatter> xNumberFormatter = m_pController->getReportNumberFormatter();
+ const uno::Reference< util::XNumberFormats> xFormats = xNumberFormatter->getNumberFormatsSupplier()->getNumberFormats();
+ const uno::Sequence<sal_Int32> aFormatKeys = xFormats->queryKeys(_nNumberFormatId,m_nLocale,true);
+ for (const sal_Int32 nFormatKey : aFormatKeys)
+ {
+ pListBox->append(OUString::number(nFormatKey), getFormatStringByKey(nFormatKey,xFormats,bTime));
+ }
+}
+
+short ODateTimeDialog::run()
+{
+ short nRet = GenericDialogController::run();
+ if (nRet == RET_OK && (m_xDate->get_active() || m_xTime->get_active()))
+ {
+ try
+ {
+ sal_Int32 nLength = 0;
+ uno::Sequence<beans::PropertyValue> aValues( 6 );
+ auto pValues = aValues.getArray();
+ pValues[nLength].Name = PROPERTY_SECTION;
+ pValues[nLength++].Value <<= m_xHoldAlive;
+
+ pValues[nLength].Name = PROPERTY_TIME_STATE;
+ pValues[nLength++].Value <<= m_xTime->get_active();
+
+ pValues[nLength].Name = PROPERTY_DATE_STATE;
+ pValues[nLength++].Value <<= m_xDate->get_active();
+
+ pValues[nLength].Name = PROPERTY_FORMATKEYDATE;
+ pValues[nLength++].Value <<= getFormatKey(true);
+
+ pValues[nLength].Name = PROPERTY_FORMATKEYTIME;
+ pValues[nLength++].Value <<= getFormatKey(false);
+
+ OutputDevice* pDefDev = Application::GetDefaultDevice();
+ sal_Int32 nWidth = 0;
+ if ( m_xDate->get_active() )
+ {
+ OUString sDateFormat = m_xDateListBox->get_active_text();
+ nWidth = OutputDevice::LogicToLogic(pDefDev->PixelToLogic(Size(pDefDev->GetCtrlTextWidth(sDateFormat),0)).Width(),
+ pDefDev->GetMapMode().GetMapUnit(),MapUnit::Map100thMM);
+ }
+ if ( m_xTime->get_active() )
+ {
+ OUString sDateFormat = m_xTimeListBox->get_active_text();
+ nWidth = ::std::max<sal_Int32>(OutputDevice::LogicToLogic(pDefDev->PixelToLogic(Size(pDefDev->GetCtrlTextWidth(sDateFormat),0)).Width(),
+ pDefDev->GetMapMode().GetMapUnit(),MapUnit::Map100thMM),nWidth);
+ }
+
+ if ( nWidth > 4000 )
+ {
+ pValues[nLength].Name = PROPERTY_WIDTH;
+ pValues[nLength++].Value <<= nWidth;
+ }
+
+ m_pController->executeChecked(SID_DATETIME,aValues);
+ }
+ catch (const uno::Exception&)
+ {
+ nRet = RET_NO;
+ }
+ }
+ return nRet;
+}
+
+OUString ODateTimeDialog::getFormatStringByKey(::sal_Int32 _nNumberFormatKey,const uno::Reference< util::XNumberFormats>& _xFormats,bool _bTime)
+{
+ uno::Reference< beans::XPropertySet> xFormSet = _xFormats->getByKey(_nNumberFormatKey);
+ OSL_ENSURE(xFormSet.is(),"XPropertySet is null!");
+ OUString sFormat;
+ xFormSet->getPropertyValue("FormatString") >>= sFormat;
+
+ double nValue = 0;
+ if ( _bTime )
+ {
+ tools::Time aCurrentTime( tools::Time::SYSTEM );
+ nValue = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(aCurrentTime.GetTime()));
+ }
+ else
+ {
+ Date aCurrentDate( Date::SYSTEM );
+ static css::util::Date STANDARD_DB_DATE(30,12,1899);
+ nValue = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(aCurrentDate.GetDate()),STANDARD_DB_DATE);
+ }
+
+ uno::Reference< util::XNumberFormatPreviewer> xPreviewer(m_pController->getReportNumberFormatter(),uno::UNO_QUERY);
+ OSL_ENSURE(xPreviewer.is(),"XNumberFormatPreviewer is null!");
+ return xPreviewer->convertNumberToPreviewString(sFormat,nValue,m_nLocale,true);
+}
+
+IMPL_LINK_NOARG(ODateTimeDialog, CBClickHdl, weld::Toggleable&, void)
+{
+ const bool bDate = m_xDate->get_active();
+ m_xFTDateFormat->set_sensitive(bDate);
+ m_xDateListBox->set_sensitive(bDate);
+
+ const bool bTime = m_xTime->get_active();
+ m_xFTTimeFormat->set_sensitive(bTime);
+ m_xTimeListBox->set_sensitive(bTime);
+
+ if (!bDate && !bTime)
+ {
+ m_xPB_OK->set_sensitive(false);
+ }
+ else
+ {
+ m_xPB_OK->set_sensitive(true);
+ }
+}
+
+sal_Int32 ODateTimeDialog::getFormatKey(bool _bDate) const
+{
+ sal_Int32 nFormatKey;
+ if ( _bDate )
+ {
+ nFormatKey = m_xDateListBox->get_active_id().toInt32();
+ }
+ else
+ {
+ nFormatKey = m_xTimeListBox->get_active_id().toInt32();
+ }
+ return nFormatKey;
+}
+
+} // rptui
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/reportdesign/source/ui/dlg/Formula.cxx b/reportdesign/source/ui/dlg/Formula.cxx
new file mode 100644
index 0000000000..9cad568ec6
--- /dev/null
+++ b/reportdesign/source/ui/dlg/Formula.cxx
@@ -0,0 +1,275 @@
+/* -*- 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 <unotools/viewoptions.hxx>
+#include <formula/formdata.hxx>
+#include <formula/funcutl.hxx>
+#include <formula/tokenarray.hxx>
+#include <formula/FormulaCompiler.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <memory>
+
+#include <Formula.hxx>
+#include <AddField.hxx>
+#include <utility>
+#include <helpids.h>
+
+
+namespace rptui
+{
+ using namespace formula;
+ using namespace ::com::sun::star;
+
+
+// initialization / shared functions for the dialog
+
+
+FormulaDialog::FormulaDialog(weld::Window* pParent
+ , const uno::Reference<lang::XMultiServiceFactory>& _xServiceFactory
+ , const std::shared_ptr< IFunctionManager >& _pFunctionMgr
+ , const OUString& _sFormula
+ , css::uno::Reference < css::beans::XPropertySet > _xRowSet
+ , svl::SharedStringPool& rStrPool )
+ : FormulaModalDialog( pParent, _pFunctionMgr.get(),this)
+ ,m_aFunctionManager(_pFunctionMgr)
+ ,m_xFormulaData(new FormEditData())
+ ,m_xRowSet(std::move(_xRowSet))
+ ,m_pEdit(nullptr)
+ ,m_sFormula("=")
+ ,m_nStart(0)
+ ,m_nEnd(1)
+ ,mrStringPool(rStrPool)
+{
+ if ( !_sFormula.isEmpty() )
+ {
+ if ( _sFormula[0] != '=' )
+ m_sFormula += _sFormula;
+ else
+ m_sFormula = _sFormula;
+ }
+ m_xParser.set(_xServiceFactory->createInstance("org.libreoffice.report.pentaho.SOFormulaParser"),uno::UNO_QUERY);
+ if ( m_xParser.is() )
+ m_xOpCodeMapper = m_xParser->getFormulaOpCodeMapper();
+ fill();
+}
+
+void FormulaDialog::notifyChange()
+{
+}
+
+void FormulaDialog::fill()
+{
+ SetMeText(m_sFormula);
+ Update(m_sFormula);
+ CheckMatrix(m_sFormula);
+ Update();
+}
+
+FormulaDialog::~FormulaDialog()
+{
+ if ( m_xAddField )
+ {
+ SvtViewOptions aDlgOpt( EViewType::Window, HID_RPT_FIELD_SEL_WIN );
+ aDlgOpt.SetWindowState(m_xAddField->getDialog()->get_window_state(vcl::WindowDataMask::Pos | vcl::WindowDataMask::State | vcl::WindowDataMask::Minimized));
+
+ if (m_xAddField->getDialog()->get_visible())
+ m_xAddField->response(RET_CANCEL);
+
+ m_xAddField.reset();
+ }
+
+ StoreFormEditData(m_xFormulaData.get());
+ m_pEdit = nullptr;
+}
+
+// functions for right side
+
+bool FormulaDialog::calculateValue( const OUString& rStrExp, OUString& rStrResult, bool /*bMatrixFormula*/ )
+{
+ rStrResult = rStrExp;
+ return false;
+}
+
+std::shared_ptr<formula::FormulaCompiler> FormulaDialog::getCompiler() const
+{
+ return nullptr;
+}
+
+std::unique_ptr<formula::FormulaCompiler> FormulaDialog::createCompiler( formula::FormulaTokenArray& rArray ) const
+{
+ return std::unique_ptr<formula::FormulaCompiler>(new FormulaCompiler(rArray));
+}
+
+void FormulaDialog::doClose(bool _bOk)
+{
+ response(_bOk ? RET_OK : RET_CANCEL);
+}
+
+void FormulaDialog::insertEntryToLRUList(const IFunctionDescription* /*_pDesc*/)
+{
+}
+void FormulaDialog::showReference(const OUString& /*_sFormula*/)
+{
+}
+void FormulaDialog::dispatch(bool /*_bOK*/, bool /*_bMatrixChecked*/)
+{
+}
+void FormulaDialog::setDispatcherLock( bool /*bLock*/ )
+{
+}
+void FormulaDialog::deleteFormData()
+{
+}
+void FormulaDialog::clear()
+{
+}
+void FormulaDialog::switchBack()
+{
+}
+FormEditData* FormulaDialog::getFormEditData() const
+{
+ return m_xFormulaData.get();
+}
+void FormulaDialog::setCurrentFormula(const OUString& _sReplacement)
+{
+ const sal_Int32 nOldLen = m_nEnd - m_nStart;
+ const sal_Int32 nNewLen = _sReplacement.getLength();
+ if (nOldLen)
+ m_sFormula = m_sFormula.replaceAt( m_nStart, nOldLen, u"" );
+ if (nNewLen)
+ m_sFormula = m_sFormula.replaceAt( m_nStart, 0, _sReplacement );
+ m_nEnd = m_nStart + nNewLen;
+}
+void FormulaDialog::setSelection(sal_Int32 _nStart, sal_Int32 _nEnd)
+{
+ if ( _nStart <= _nEnd )
+ {
+ m_nStart = _nStart;
+ m_nEnd = _nEnd;
+ }
+ else
+ {
+ m_nEnd = _nStart;
+ m_nStart = _nEnd;
+ }
+}
+void FormulaDialog::getSelection(sal_Int32& _nStart, sal_Int32& _nEnd) const
+{
+ _nStart = m_nStart;
+ _nEnd = m_nEnd;
+}
+OUString FormulaDialog::getCurrentFormula() const
+{
+ return m_sFormula;
+}
+IFunctionManager* FormulaDialog::getFunctionManager()
+{
+ return m_aFunctionManager.get();
+}
+
+void FormulaDialog::ShowReference(const OUString& /*_sRef*/)
+{
+}
+
+void FormulaDialog::HideReference( bool /*bDoneRefMode*/)
+{
+}
+
+void FormulaDialog::ReleaseFocus( RefEdit* /*pEdit*/)
+{
+}
+
+void FormulaDialog::ToggleCollapsed( RefEdit* _pEdit, RefButton* _pButton)
+{
+ ::std::pair<RefButton*,RefEdit*> aPair = RefInputStartBefore( _pEdit, _pButton );
+ m_pEdit = aPair.second;
+ if ( m_pEdit )
+ m_pEdit->GetWidget()->hide();
+ if ( aPair.first )
+ aPair.first->GetWidget()->hide();
+
+ if (!m_xAddField)
+ {
+ m_xAddField = std::make_shared<OAddFieldWindow>(m_xDialog.get(), m_xRowSet);
+ m_xAddField->SetCreateHdl(LINK( this, FormulaDialog, OnClickHdl ) );
+ SvtViewOptions aDlgOpt( EViewType::Window, HID_RPT_FIELD_SEL_WIN );
+ if ( aDlgOpt.Exists() )
+ {
+ m_xAddField->getDialog()->set_window_state(aDlgOpt.GetWindowState());
+
+ }
+
+ m_xAddField->Update();
+ }
+ RefInputStartAfter();
+
+ if (!m_xAddField->getDialog()->get_visible())
+ weld::DialogController::runAsync(m_xAddField, [this](sal_Int32 /*nResult*/) { m_xAddField.reset(); });
+}
+
+IMPL_LINK( FormulaDialog, OnClickHdl, OAddFieldWindow& ,_rAddFieldDlg, void)
+{
+ const uno::Sequence< beans::PropertyValue > aArgs = _rAddFieldDlg.getSelectedFieldDescriptors();
+ // we use this way to create undo actions
+ if ( m_pEdit && aArgs.getLength() == 1)
+ {
+ uno::Sequence< beans::PropertyValue > aValue;
+ aArgs[0].Value >>= aValue;
+ svx::ODataAccessDescriptor aDescriptor(aValue);
+ OUString sName;
+ aDescriptor[ svx::DataAccessDescriptorProperty::ColumnName ] >>= sName;
+ if ( !sName.isEmpty() )
+ {
+ sName = "[" + sName + "]";
+ m_pEdit->SetText(sName);
+ }
+ }
+ m_pEdit = nullptr;
+ if (_rAddFieldDlg.getDialog()->get_visible())
+ _rAddFieldDlg.response(RET_CANCEL);
+ RefInputDoneAfter();
+}
+
+uno::Reference< sheet::XFormulaParser> FormulaDialog::getFormulaParser() const
+{
+ return m_xParser;
+}
+
+uno::Reference< sheet::XFormulaOpCodeMapper> FormulaDialog::getFormulaOpCodeMapper() const
+{
+ return m_xOpCodeMapper;
+}
+
+table::CellAddress FormulaDialog::getReferencePosition() const
+{
+ return table::CellAddress();
+}
+
+::std::unique_ptr<formula::FormulaTokenArray> FormulaDialog::convertToTokenArray(const uno::Sequence< sheet::FormulaToken >& _aTokenList)
+{
+ ::std::unique_ptr<formula::FormulaTokenArray> pArray(new FormulaTokenArray());
+ pArray->Fill(_aTokenList, mrStringPool, nullptr);
+ return pArray;
+}
+
+} // rptui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/reportdesign/source/ui/dlg/GroupExchange.cxx b/reportdesign/source/ui/dlg/GroupExchange.cxx
new file mode 100644
index 0000000000..7b749c3f4b
--- /dev/null
+++ b/reportdesign/source/ui/dlg/GroupExchange.cxx
@@ -0,0 +1,68 @@
+/* -*- 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 "GroupExchange.hxx"
+#include <sot/formats.hxx>
+#include <osl/diagnose.h>
+
+namespace rptui
+{
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+
+ SotClipboardFormatId OGroupExchange::getReportGroupId()
+ {
+ static SotClipboardFormatId s_nReportFormat = static_cast<SotClipboardFormatId>(-1);
+ if ( static_cast<SotClipboardFormatId>(-1) == s_nReportFormat )
+ {
+ s_nReportFormat = SotExchange::RegisterFormatName("application/x-openoffice;windows_formatname=\"reportdesign.GroupFormat\"");
+ OSL_ENSURE(static_cast<SotClipboardFormatId>(-1) != s_nReportFormat, "Bad exchange id!");
+ }
+ return s_nReportFormat;
+ }
+ OGroupExchange::OGroupExchange(const uno::Sequence< uno::Any >& _aGroupRow)
+ : m_aGroupRow(_aGroupRow)
+ {
+ }
+
+ void OGroupExchange::AddSupportedFormats()
+ {
+ if ( m_aGroupRow.hasElements() )
+ {
+ AddFormat(OGroupExchange::getReportGroupId());
+ }
+ }
+
+ bool OGroupExchange::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
+ {
+ SotClipboardFormatId nFormat = SotExchange::GetFormat(rFlavor);
+ if(nFormat == OGroupExchange::getReportGroupId() )
+ {
+ return SetAny(uno::Any(m_aGroupRow));
+ }
+ return false;
+ }
+
+ void OGroupExchange::ObjectReleased()
+ {
+ m_aGroupRow.realloc(0);
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/reportdesign/source/ui/dlg/GroupExchange.hxx b/reportdesign/source/ui/dlg/GroupExchange.hxx
new file mode 100644
index 0000000000..6154e75ae4
--- /dev/null
+++ b/reportdesign/source/ui/dlg/GroupExchange.hxx
@@ -0,0 +1,43 @@
+/* -*- 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 .
+ */
+#ifndef INCLUDED_REPORTDESIGN_SOURCE_UI_DLG_GROUPEXCHANGE_HXX
+#define INCLUDED_REPORTDESIGN_SOURCE_UI_DLG_GROUPEXCHANGE_HXX
+
+#include <vcl/transfer.hxx>
+
+namespace rptui
+{
+ /** clipboard class for group rows in the groups and sorting dialog
+ */
+ class OGroupExchange : public TransferableHelper
+ {
+ css::uno::Sequence< css::uno::Any> m_aGroupRow;
+ public:
+ explicit OGroupExchange(const css::uno::Sequence< css::uno::Any>& _aGroupRow);
+
+ static SotClipboardFormatId getReportGroupId();
+ protected:
+ virtual void AddSupportedFormats() override;
+ virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override;
+ virtual void ObjectReleased() override;
+ };
+}
+#endif // INCLUDED_REPORTDESIGN_SOURCE_UI_DLG_GROUPEXCHANGE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/reportdesign/source/ui/dlg/GroupsSorting.cxx b/reportdesign/source/ui/dlg/GroupsSorting.cxx
new file mode 100644
index 0000000000..38697ca128
--- /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 <GroupsSorting.hxx>
+#include <svtools/editbrowsebox.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/report/GroupOn.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+
+#include <strings.hrc>
+#include <rptui_slotid.hrc>
+#include <core_resource.hxx>
+#include <helpids.h>
+#include "GroupExchange.hxx"
+#include <UITools.hxx>
+#include <UndoActions.hxx>
+#include <strings.hxx>
+#include <ReportController.hxx>
+#include <ColumnInfo.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+#include <algorithm>
+
+#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<ColumnInfo>& 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<OFieldExpressionControl> 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<sal_Int32> m_aGroupPositions;
+ ::std::vector<ColumnInfo> 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<OFieldExpressionControlContainerListener> aContainerListener;
+
+public:
+ OFieldExpressionControl(OGroupsSortingDialog* pParentDialog, const css::uno::Reference<css::awt::XWindow> &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<uno::Any> fillSelectedGroups();
+
+ /** move groups given by _aGroups
+ */
+ void moveGroups(const uno::Sequence<uno::Any>& _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<css::awt::XWindow> &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<uno::Any> OFieldExpressionControl::fillSelectedGroups()
+{
+ uno::Sequence<uno::Any> aList;
+ ::std::vector<uno::Any> vClipboardList;
+ vClipboardList.reserve(GetSelectRowCount());
+
+ uno::Reference<report::XGroups> 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<uno::Any> aClipboardList = fillSelectedGroups();
+
+ if( aClipboardList.hasElements() )
+ {
+ rtl::Reference<OGroupExchange> 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<uno::Any>& _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<sal_Int32>(nGroupsCount,sal_Int32(GROUPS_START_LEN)),NO_GROUP);
+ ::std::vector<sal_Int32>::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<sal_uInt16>(GetTextWidth(OUString('0')) * 4)/*, sal_True */);
+ InsertDataColumn( FIELD_EXPRESSION, RptResId(STR_RPT_EXPRESSION), 100);
+
+ m_pComboCell = VclPtr<ComboBoxControl>::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<sal_Int32>::iterator aIter = m_aGroupPositions.begin();
+ ::std::vector<sal_Int32>::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<tools::Long>(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<sal_Int32>::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<sal_Int32>::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<sal_Int32>::iterator aEnd = m_aGroupPositions.end();
+ std::vector<sal_Int32>::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<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "modules/dbreport/ui/groupsortmenu.ui"));
+ std::unique_ptr<weld::Menu> 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<sal_Int32>::iterator aEnd = m_aGroupPositions.end();
+ std::vector<sal_Int32>::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<OFieldExpressionControl>::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<weld::ComboBox&>(*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<weld::Widget*, TranslateId> 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<weld::ComboBox*>( &rControl );
+ if ( pListBox )
+ pListBox->save_value();
+ weld::SpinButton* pNumericField = dynamic_cast<weld::SpinButton*>(&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 OUString&, rCommand, void)
+{
+ if ( !m_xFieldExpression )
+ return;
+
+ tools::Long nIndex = m_xFieldExpression->GetCurrRow();
+ sal_Int32 nGroupPos = m_xFieldExpression->getGroupPosition(nIndex);
+ uno::Sequence<uno::Any> 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<report::XGroup>& _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: */
diff --git a/reportdesign/source/ui/dlg/Navigator.cxx b/reportdesign/source/ui/dlg/Navigator.cxx
new file mode 100644
index 0000000000..690d90ca1b
--- /dev/null
+++ b/reportdesign/source/ui/dlg/Navigator.cxx
@@ -0,0 +1,814 @@
+/* -*- 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 <Navigator.hxx>
+
+#include <strings.hxx>
+#include <bitmaps.hlst>
+#include <ReportController.hxx>
+#include <UITools.hxx>
+#include <reportformula.hxx>
+#include <com/sun/star/report/XFixedText.hpp>
+#include <com/sun/star/report/XFixedLine.hpp>
+#include <com/sun/star/report/XFormattedField.hpp>
+#include <com/sun/star/report/XImageControl.hpp>
+#include <com/sun/star/report/XShape.hpp>
+#include <helpids.h>
+#include <strings.hrc>
+#include <rptui_slotid.hrc>
+#include <comphelper/propmultiplex.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/containermultiplexer.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/SelectionMultiplex.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/commandevent.hxx>
+#include <ReportVisitor.hxx>
+#include <core_resource.hxx>
+#include <rtl/ref.hxx>
+#include <svx/svxids.hrc>
+
+#include <memory>
+#include <string_view>
+
+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() ? RID_SVXBMP_INSERT_VFIXEDLINE : 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(" : " + xFixedText->getLabel());
+ }
+ else if ( xReportModel.is() && _xElement->getPropertySetInfo()->hasPropertyByName(PROPERTY_DATAFIELD) )
+ {
+ ReportFormula aFormula( xReportModel->getDataField() );
+ if ( aFormula.isValid() )
+ {
+ sName.append(" : " + aFormula.getUndecoratedContent() );
+ }
+ }
+ return sName.makeStringAndClear();
+}
+
+class NavigatorTree : public ::cppu::BaseMutex
+ , 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;
+ NavigatorTree* m_pTree;
+ public:
+ UserData(NavigatorTree* pTree, uno::Reference<uno::XInterface> 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;
+ };
+
+ std::unique_ptr<weld::TreeView> m_xTreeView;
+ OReportController& m_rController;
+ std::unique_ptr<weld::TreeIter> m_xMasterReport;
+ ::rtl::Reference< comphelper::OPropertyChangeMultiplexer> m_pReportListener;
+ ::rtl::Reference< comphelper::OSelectionChangeMultiplexer> m_pSelectionListener;
+
+ void insertEntry(const OUString& rName, const weld::TreeIter* pParent, const OUString& rImageId, int nPosition, const UserData* pData, weld::TreeIter& rRet);
+
+ void traverseSection(const uno::Reference<report::XSection>& xSection, const weld::TreeIter* pParent, const OUString& rImageId, int nPosition = -1);
+ void traverseFunctions(const uno::Reference< report::XFunctions>& xFunctions, const weld::TreeIter* pParent);
+
+protected:
+ // 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(std::unique_ptr<weld::TreeView>, OReportController& rController);
+ virtual ~NavigatorTree() override;
+
+ DECL_LINK(OnEntrySelDesel, weld::TreeView&, void);
+ DECL_LINK(CommandHdl, const CommandEvent&, bool);
+
+ 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;
+
+ bool find(const uno::Reference<uno::XInterface>& xContent, weld::TreeIter& rIter);
+ void removeEntry(const weld::TreeIter& rEntry, bool bRemove = true);
+
+ void grab_focus() { m_xTreeView->grab_focus(); }
+
+ void set_text(const weld::TreeIter& rIter, const OUString& rStr)
+ {
+ m_xTreeView->set_text(rIter, rStr);
+ }
+
+ void expand_row(const weld::TreeIter& rIter)
+ {
+ m_xTreeView->expand_row(rIter);
+ }
+
+ std::unique_ptr<weld::TreeIter> make_iterator() const
+ {
+ return m_xTreeView->make_iterator();
+ }
+
+ int iter_n_children(const weld::TreeIter& rIter) const
+ {
+ return m_xTreeView->iter_n_children(rIter);
+ }
+};
+
+NavigatorTree::NavigatorTree(std::unique_ptr<weld::TreeView> xTreeView, OReportController& rController)
+ : OPropertyChangeListener(m_aMutex)
+ , m_xTreeView(std::move(xTreeView))
+ , m_rController(rController)
+{
+ m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 25, m_xTreeView->get_height_rows(18));
+
+ m_pReportListener = new OPropertyChangeMultiplexer(this,m_rController.getReportDefinition());
+ 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);
+
+ m_xTreeView->set_help_id(HID_REPORT_NAVIGATOR_TREE);
+
+ m_xTreeView->set_selection_mode(SelectionMode::Multiple);
+
+ m_xTreeView->connect_changed(LINK(this, NavigatorTree, OnEntrySelDesel));
+ m_xTreeView->connect_popup_menu(LINK(this, NavigatorTree, CommandHdl));
+}
+
+NavigatorTree::~NavigatorTree()
+{
+ m_xTreeView->all_foreach([this](weld::TreeIter& rIter) {
+ UserData* pData = weld::fromId<UserData*>(m_xTreeView->get_id(rIter));
+ delete pData;
+ return false;
+ });
+ m_pSelectionListener->dispose();
+ m_pReportListener->dispose();
+}
+
+namespace
+{
+ sal_uInt16 mapIdent(std::u16string_view rIdent)
+ {
+ if (rIdent == u"sorting")
+ return SID_SORTINGANDGROUPING;
+ else if (rIdent == u"page")
+ return SID_PAGEHEADERFOOTER;
+ else if (rIdent == u"report")
+ return SID_REPORTHEADERFOOTER;
+ else if (rIdent == u"function")
+ return SID_RPT_NEW_FUNCTION;
+ else if (rIdent == u"properties")
+ return SID_SHOW_PROPERTYBROWSER;
+ else if (rIdent == u"delete")
+ return SID_DELETE;
+ return 0;
+ }
+}
+
+IMPL_LINK(NavigatorTree, CommandHdl, const CommandEvent&, rEvt, bool)
+{
+ bool bHandled = false;
+ switch( rEvt.GetCommand())
+ {
+ case CommandEventId::ContextMenu:
+ {
+ UserData* pData = weld::fromId<UserData*>(m_xTreeView->get_selected_id());
+ if (!pData)
+ break;
+
+ 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());
+
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), "modules/dbreport/ui/navigatormenu.ui"));
+ std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu"));
+
+ const OUString aIds[] = { "sorting", "page", "report", "function", "properties", "delete" };
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
+ {
+ sal_uInt16 nSId = mapIdent(aIds[i]);
+
+ if (aIds[i] == "page" || aIds[i] == "report" || aIds[i] == "properties")
+ xContextMenu->set_active(aIds[i], m_rController.isCommandChecked(nSId));
+ bool bEnabled = m_rController.isCommandEnabled(nSId);
+ if (nSId == SID_RPT_NEW_FUNCTION)
+ xContextMenu->set_sensitive(aIds[i], m_rController.isEditable() && (xSupplier.is() || xFunctions.is()));
+ // special condition, check for function and group
+ else if (nSId == SID_DELETE)
+ xContextMenu->set_sensitive(aIds[i], bDeleteAllowed);
+ else
+ xContextMenu->set_sensitive(aIds[i], bEnabled);
+ }
+
+ // the point that was clicked on
+ ::Point aWhere(rEvt.GetMousePosPixel());
+ OUString sCurItemIdent = xContextMenu->popup_at_rect(m_xTreeView.get(), tools::Rectangle(aWhere, Size(1,1)));
+ if (!sCurItemIdent.isEmpty())
+ {
+ sal_uInt16 nId = mapIdent(sCurItemIdent);
+ uno::Sequence< beans::PropertyValue> aArgs;
+ if ( nId == SID_RPT_NEW_FUNCTION )
+ {
+ aArgs.realloc(1);
+ aArgs.getArray()[0].Value <<= (xFunctions.is() ? xFunctions : xSupplier->getFunctions());
+ }
+ else if ( nId == SID_DELETE )
+ {
+ if ( xGroup.is() )
+ nId = SID_GROUP_REMOVE;
+ aArgs = { comphelper::makePropertyValue(PROPERTY_GROUP, pData->getContent()) };
+ }
+ m_rController.executeUnChecked(nId,aArgs);
+ }
+
+ bHandled = true;
+ }
+ break;
+ default: break;
+ }
+
+ return bHandled;
+}
+
+IMPL_LINK_NOARG(NavigatorTree, OnEntrySelDesel, weld::TreeView&, void)
+{
+ if ( !m_pSelectionListener->locked() )
+ {
+ m_pSelectionListener->lock();
+ std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
+ bool bEntry = m_xTreeView->get_cursor(xEntry.get());
+ uno::Any aSelection;
+ if (bEntry && m_xTreeView->is_selected(*xEntry))
+ aSelection <<= weld::fromId<UserData*>(m_xTreeView->get_id(*xEntry))->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;
+ std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
+ if ( !aSelection.hasElements() )
+ {
+ uno::Reference< uno::XInterface> xSelection(aSec,uno::UNO_QUERY);
+ bool bEntry = find(xSelection, *xEntry);
+ if (bEntry && !m_xTreeView->is_selected(*xEntry))
+ {
+ m_xTreeView->select(*xEntry);
+ m_xTreeView->set_cursor(*xEntry);
+ }
+ else if (!bEntry)
+ m_xTreeView->unselect_all();
+ }
+ else
+ {
+ for (const uno::Reference<report::XReportComponent>& rElem : std::as_const(aSelection))
+ {
+ bool bEntry = find(rElem, *xEntry);
+ if (bEntry && !m_xTreeView->is_selected(*xEntry))
+ {
+ m_xTreeView->select(*xEntry);
+ m_xTreeView->set_cursor(*xEntry);
+ }
+ }
+ }
+ m_pSelectionListener->unlock();
+}
+
+void NavigatorTree::insertEntry(const OUString& rName, const weld::TreeIter* pParent, const OUString& rImageId,
+ int nPosition, const UserData* pData, weld::TreeIter& rRet)
+{
+ OUString sId = pData ? weld::toId(pData) : OUString();
+ m_xTreeView->insert(pParent, nPosition, &rName, &sId, nullptr, nullptr, false, &rRet);
+ if (!rImageId.isEmpty())
+ m_xTreeView->set_image(rRet, rImageId);
+}
+
+void NavigatorTree::traverseSection(const uno::Reference<report::XSection>& xSection, const weld::TreeIter* pParent, const OUString& rImageId, int nPosition)
+{
+ std::unique_ptr<weld::TreeIter> xSectionIter = m_xTreeView->make_iterator();
+ std::unique_ptr<weld::TreeIter> xScratch = m_xTreeView->make_iterator();
+ insertEntry(xSection->getName(), pParent, rImageId, nPosition, new UserData(this, xSection), *xSectionIter);
+ 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), xSectionIter.get(), lcl_getImageId(xElement), -1, new UserData(this, xElement), *xScratch);
+ uno::Reference< report::XReportDefinition> xSubReport(xElement,uno::UNO_QUERY);
+ if ( xSubReport.is() )
+ {
+ bool bMasterReport = find(xSection->getReportDefinition(), *xScratch);
+ if (!bMasterReport)
+ m_xMasterReport.reset();
+ else
+ m_xMasterReport = m_xTreeView->make_iterator(xScratch.get());
+ reportdesign::OReportVisitor aSubVisitor(this);
+ aSubVisitor.start(xSubReport);
+ }
+ }
+}
+
+void NavigatorTree::traverseFunctions(const uno::Reference< report::XFunctions>& xFunctions, const weld::TreeIter* pParent)
+{
+ std::unique_ptr<weld::TreeIter> xFunctionIter = m_xTreeView->make_iterator();
+ std::unique_ptr<weld::TreeIter> xScratch = m_xTreeView->make_iterator();
+ insertEntry(RptResId(RID_STR_FUNCTIONS), pParent, RID_SVXBMP_RPT_NEW_FUNCTION, -1, new UserData(this, xFunctions), *xFunctionIter);
+ 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(), xFunctionIter.get(), RID_SVXBMP_RPT_NEW_FUNCTION, -1, new UserData(this,xElement), *xScratch);
+ }
+}
+
+bool NavigatorTree::find(const uno::Reference<uno::XInterface>& xContent, weld::TreeIter& rRet)
+{
+ bool bRet = false;
+ if (xContent.is())
+ {
+ m_xTreeView->all_foreach([this, &xContent, &bRet, &rRet](weld::TreeIter& rIter) {
+ UserData* pData = weld::fromId<UserData*>(m_xTreeView->get_id(rIter));
+ if (pData->getContent() == xContent)
+ {
+ m_xTreeView->copy_iterator(rIter, rRet);
+ bRet = true;
+ return true;
+ }
+ return false;
+ });
+ }
+ return bRet;
+}
+
+// ITraverseReport
+
+void NavigatorTree::traverseReport(const uno::Reference< report::XReportDefinition>& xReport)
+{
+ std::unique_ptr<weld::TreeIter> xScratch = m_xTreeView->make_iterator();
+ insertEntry(xReport->getName(), m_xMasterReport.get(), RID_SVXBMP_SELECT_REPORT,-1, new UserData(this, xReport), *xScratch);
+}
+
+void NavigatorTree::traverseReportFunctions(const uno::Reference< report::XFunctions>& xFunctions)
+{
+ std::unique_ptr<weld::TreeIter> xReport = m_xTreeView->make_iterator();
+ bool bReport = find(xFunctions->getParent(), *xReport);
+ if (!bReport)
+ xReport.reset();
+ traverseFunctions(xFunctions, xReport.get());
+}
+
+void NavigatorTree::traverseReportHeader(const uno::Reference< report::XSection>& xSection)
+{
+ std::unique_ptr<weld::TreeIter> xReport = m_xTreeView->make_iterator();
+ bool bReport = find(xSection->getReportDefinition(), *xReport);
+ if (!bReport)
+ xReport.reset();
+ traverseSection(xSection, xReport.get(), RID_SVXBMP_REPORTHEADERFOOTER);
+}
+
+void NavigatorTree::traverseReportFooter(const uno::Reference< report::XSection>& xSection)
+{
+ std::unique_ptr<weld::TreeIter> xReport = m_xTreeView->make_iterator();
+ bool bReport = find(xSection->getReportDefinition(), *xReport);
+ if (!bReport)
+ xReport.reset();
+ traverseSection(xSection, xReport.get(), RID_SVXBMP_REPORTHEADERFOOTER);
+}
+
+void NavigatorTree::traversePageHeader(const uno::Reference< report::XSection>& xSection)
+{
+ std::unique_ptr<weld::TreeIter> xReport = m_xTreeView->make_iterator();
+ bool bReport = find(xSection->getReportDefinition(), *xReport);
+ if (!bReport)
+ xReport.reset();
+ traverseSection(xSection, xReport.get(), RID_SVXBMP_PAGEHEADERFOOTER);
+}
+
+void NavigatorTree::traversePageFooter(const uno::Reference< report::XSection>& xSection)
+{
+ std::unique_ptr<weld::TreeIter> xReport = m_xTreeView->make_iterator();
+ bool bReport = find(xSection->getReportDefinition(), *xReport);
+ if (!bReport)
+ xReport.reset();
+ traverseSection(xSection, xReport.get(), RID_SVXBMP_PAGEHEADERFOOTER);
+}
+
+void NavigatorTree::traverseGroups(const uno::Reference< report::XGroups>& xGroups)
+{
+ std::unique_ptr<weld::TreeIter> xReport = m_xTreeView->make_iterator();
+ bool bReport = find(xGroups->getReportDefinition(), *xReport);
+ if (!bReport)
+ xReport.reset();
+ std::unique_ptr<weld::TreeIter> xScratch = m_xTreeView->make_iterator();
+ insertEntry(RptResId(RID_STR_GROUPS), xReport.get(), RID_SVXBMP_SORTINGANDGROUPING, -1, new UserData(this, xGroups), *xScratch);
+}
+
+void NavigatorTree::traverseGroup(const uno::Reference< report::XGroup>& xGroup)
+{
+ uno::Reference< report::XGroups> xGroups(xGroup->getParent(),uno::UNO_QUERY);
+ std::unique_ptr<weld::TreeIter> xGroupsIter = m_xTreeView->make_iterator();
+ bool bGroups = find(xGroups, *xGroupsIter);
+ OSL_ENSURE(bGroups, "No Groups inserted so far. Why!");
+ if (!bGroups)
+ xGroupsIter.reset();
+ std::unique_ptr<weld::TreeIter> xScratch = m_xTreeView->make_iterator();
+ insertEntry(xGroup->getExpression(), xGroupsIter.get(), RID_SVXBMP_GROUP, rptui::getPositionInIndexAccess(xGroups,xGroup), new UserData(this,xGroup), *xScratch);
+}
+
+void NavigatorTree::traverseGroupFunctions(const uno::Reference< report::XFunctions>& xFunctions)
+{
+ std::unique_ptr<weld::TreeIter> xReport = m_xTreeView->make_iterator();
+ bool bReport = find(xFunctions->getParent(), *xReport);
+ if (!bReport)
+ xReport.reset();
+ traverseFunctions(xFunctions, xReport.get());
+}
+
+void NavigatorTree::traverseGroupHeader(const uno::Reference< report::XSection>& xSection)
+{
+ std::unique_ptr<weld::TreeIter> xReport = m_xTreeView->make_iterator();
+ bool bReport = find(xSection->getGroup(), *xReport);
+ OSL_ENSURE(bReport, "No group found");
+ if (!bReport)
+ xReport.reset();
+ traverseSection(xSection, xReport.get(), RID_SVXBMP_GROUPHEADER, 1);
+}
+
+void NavigatorTree::traverseGroupFooter(const uno::Reference< report::XSection>& xSection)
+{
+ std::unique_ptr<weld::TreeIter> xReport = m_xTreeView->make_iterator();
+ bool bReport = find(xSection->getGroup(), *xReport);
+ OSL_ENSURE(bReport, "No group found");
+ if (!bReport)
+ xReport.reset();
+ traverseSection(xSection, xReport.get(), RID_SVXBMP_GROUPFOOTER);
+}
+
+void NavigatorTree::traverseDetail(const uno::Reference< report::XSection>& xSection)
+{
+ uno::Reference< report::XReportDefinition> xReport = xSection->getReportDefinition();
+ std::unique_ptr<weld::TreeIter> xParent = m_xTreeView->make_iterator();
+ bool bParent = find(xReport, *xParent);
+ if (!bParent)
+ xParent.reset();
+ traverseSection(xSection, xParent.get(), RID_SVXBMP_ICON_DETAIL);
+}
+
+void NavigatorTree::_propertyChanged(const beans::PropertyChangeEvent& _rEvent)
+{
+ uno::Reference< report::XReportDefinition> xReport(_rEvent.Source,uno::UNO_QUERY);
+ if ( !xReport.is() )
+ return;
+
+ bool bEnabled = false;
+ _rEvent.NewValue >>= bEnabled;
+ if ( !bEnabled )
+ return;
+
+ std::unique_ptr<weld::TreeIter> xParent = m_xTreeView->make_iterator();
+ bool bParent = find(xReport, *xParent);
+ if (!bParent)
+ xParent.reset();
+ if ( _rEvent.PropertyName == PROPERTY_REPORTHEADERON )
+ {
+ int nPos = xReport->getReportHeaderOn() ? 2 : 1;
+ traverseSection(xReport->getReportHeader(),xParent.get(),RID_SVXBMP_REPORTHEADERFOOTER,nPos);
+ }
+ else if ( _rEvent.PropertyName == PROPERTY_PAGEHEADERON )
+ {
+ traverseSection(xReport->getPageHeader(),xParent.get(), RID_SVXBMP_PAGEHEADERFOOTER,1);
+ }
+ else if ( _rEvent.PropertyName == PROPERTY_PAGEFOOTERON )
+ traverseSection(xReport->getPageFooter(),xParent.get(), RID_SVXBMP_PAGEHEADERFOOTER);
+ else if ( _rEvent.PropertyName == PROPERTY_REPORTFOOTERON )
+ {
+ int nPos = -1;
+ if (xReport->getPageFooterOn() && xParent)
+ nPos = m_xTreeView->iter_n_children(*xParent) - 1;
+ traverseSection(xReport->getReportFooter(),xParent.get(),RID_SVXBMP_REPORTHEADERFOOTER,nPos);
+ }
+}
+
+void NavigatorTree::_elementInserted( const container::ContainerEvent& _rEvent )
+{
+ std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
+ bool bEntry = find(_rEvent.Source, *xEntry);
+ if (!bEntry)
+ xEntry.reset();
+ uno::Reference<beans::XPropertySet> 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);
+ std::unique_ptr<weld::TreeIter> xScratch = m_xTreeView->make_iterator();
+ insertEntry(sName, xEntry.get(), (!xElement.is() ? RID_SVXBMP_RPT_NEW_FUNCTION : lcl_getImageId(xElement)),
+ -1, new UserData(this,xProp), *xScratch);
+ }
+ if (bEntry && !m_xTreeView->get_row_expanded(*xEntry))
+ m_xTreeView->expand_row(*xEntry);
+}
+
+void NavigatorTree::_elementRemoved( const container::ContainerEvent& _rEvent )
+{
+ uno::Reference<beans::XPropertySet> xProp(_rEvent.Element,uno::UNO_QUERY);
+ std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
+ bool bEntry = find(xProp, *xEntry);
+ OSL_ENSURE(bEntry,"NavigatorTree::_elementRemoved: No Entry found!");
+
+ if (bEntry)
+ {
+ removeEntry(*xEntry);
+ }
+}
+
+void NavigatorTree::_elementReplaced( const container::ContainerEvent& _rEvent )
+{
+ uno::Reference<beans::XPropertySet> xProp(_rEvent.ReplacedElement,uno::UNO_QUERY);
+ std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
+ bool bEntry = find(xProp, *xEntry);
+ if (bEntry)
+ {
+ UserData* pData = weld::fromId<UserData*>(m_xTreeView->get_id(*xEntry));
+ xProp.set(_rEvent.Element,uno::UNO_QUERY);
+ pData->setContent(xProp);
+ OUString sName;
+ xProp->getPropertyValue(PROPERTY_NAME) >>= sName;
+ m_xTreeView->set_text(*xEntry, sName);
+ }
+}
+
+void NavigatorTree::_disposing(const lang::EventObject& _rSource)
+{
+ std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
+ if (find(_rSource.Source, *xEntry))
+ removeEntry(*xEntry);
+}
+
+void NavigatorTree::removeEntry(const weld::TreeIter& rEntry, bool bRemove)
+{
+ std::unique_ptr<weld::TreeIter> xChild = m_xTreeView->make_iterator(&rEntry);
+ bool bChild = m_xTreeView->iter_children(*xChild);
+ while (bChild)
+ {
+ removeEntry(*xChild, false);
+ bChild = m_xTreeView->iter_next_sibling(*xChild);
+ }
+ delete weld::fromId<UserData*>(m_xTreeView->get_id(rEntry));
+ if (bRemove)
+ m_xTreeView->remove(rEntry);
+}
+
+NavigatorTree::UserData::UserData(NavigatorTree* pTree,uno::Reference<uno::XInterface> xContent)
+ : OPropertyChangeListener(m_aMutex)
+ , OContainerListener(m_aMutex)
+ , m_xContent(std::move(xContent))
+ , m_pTree(pTree)
+{
+ uno::Reference<beans::XPropertySet> 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)
+{
+ std::unique_ptr<weld::TreeIter> xEntry = m_pTree->make_iterator();
+ bool bEntry = m_pTree->find(_rEvent.Source, *xEntry);
+ OSL_ENSURE(bEntry,"No entry could be found! Why not!");
+ if (!bEntry)
+ return;
+ 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<bool(OGroupHelper *)> pIsOn = ::std::mem_fn(&OGroupHelper::getHeaderOn);
+ ::std::function<uno::Reference<report::XSection>(OGroupHelper *)> pMemFunSection = ::std::mem_fn(&OGroupHelper::getHeader);
+ if ( bFooterOn )
+ {
+ pIsOn = ::std::mem_fn(&OGroupHelper::getFooterOn);
+ pMemFunSection = ::std::mem_fn(&OGroupHelper::getFooter);
+ nPos = m_pTree->iter_n_children(*xEntry) - 1;
+ }
+
+ OGroupHelper aGroupHelper(xGroup);
+ if ( pIsOn(&aGroupHelper) )
+ {
+ if ( bFooterOn )
+ ++nPos;
+ m_pTree->traverseSection(pMemFunSection(&aGroupHelper),xEntry.get(),bFooterOn ? RID_SVXBMP_GROUPFOOTER : RID_SVXBMP_GROUPHEADER,nPos);
+ }
+ }
+ else if ( PROPERTY_EXPRESSION == _rEvent.PropertyName)
+ {
+ OUString sNewName;
+ _rEvent.NewValue >>= sNewName;
+ m_pTree->set_text(*xEntry, sNewName);
+ }
+ else if ( PROPERTY_DATAFIELD == _rEvent.PropertyName || PROPERTY_LABEL == _rEvent.PropertyName || PROPERTY_NAME == _rEvent.PropertyName )
+ {
+ uno::Reference<beans::XPropertySet> xProp(_rEvent.Source,uno::UNO_QUERY);
+ m_pTree->set_text(*xEntry, 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 );
+}
+
+ONavigator::ONavigator(weld::Window* pParent, OReportController& rController)
+ : GenericDialogController(pParent, "modules/dbreport/ui/floatingnavigator.ui", "FloatingNavigator")
+ , m_xReport(rController.getReportDefinition())
+ , m_xNavigatorTree(std::make_unique<NavigatorTree>(m_xBuilder->weld_tree_view("treeview"), rController))
+{
+ reportdesign::OReportVisitor aVisitor(m_xNavigatorTree.get());
+ aVisitor.start(m_xReport);
+ std::unique_ptr<weld::TreeIter> xScratch = m_xNavigatorTree->make_iterator();
+ if (m_xNavigatorTree->find(m_xReport, *xScratch))
+ m_xNavigatorTree->expand_row(*xScratch);
+ lang::EventObject aEvent(rController);
+ m_xNavigatorTree->_selectionChanged(aEvent);
+ m_xNavigatorTree->grab_focus();
+
+ m_xDialog->connect_container_focus_changed(LINK(this, ONavigator, FocusChangeHdl));
+}
+
+ONavigator::~ONavigator()
+{
+}
+
+IMPL_LINK_NOARG(ONavigator, FocusChangeHdl, weld::Container&, void)
+{
+ if (m_xDialog->has_toplevel_focus())
+ m_xNavigatorTree->grab_focus();
+}
+
+} // rptui
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/reportdesign/source/ui/dlg/PageNumber.cxx b/reportdesign/source/ui/dlg/PageNumber.cxx
new file mode 100644
index 0000000000..1e267fb1fb
--- /dev/null
+++ b/reportdesign/source/ui/dlg/PageNumber.cxx
@@ -0,0 +1,104 @@
+/* -*- 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 <PageNumber.hxx>
+#include <rptui_slotid.hrc>
+#include <RptDef.hxx>
+
+#include <strings.hxx>
+#include <ReportController.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <utility>
+
+namespace rptui
+{
+using namespace ::com::sun::star;
+using namespace ::comphelper;
+
+
+
+OPageNumberDialog::OPageNumberDialog(weld::Window* pParent,
+ uno::Reference< report::XReportDefinition > _xHoldAlive,
+ OReportController* _pController)
+ : GenericDialogController(pParent, "modules/dbreport/ui/pagenumberdialog.ui", "PageNumberDialog")
+ , m_pController(_pController)
+ , m_xHoldAlive(std::move(_xHoldAlive))
+ , m_xPageNofM(m_xBuilder->weld_radio_button("pagenofm"))
+ , m_xTopPage(m_xBuilder->weld_radio_button("toppage"))
+ , m_xAlignmentLst(m_xBuilder->weld_combo_box("alignment"))
+ , m_xShowNumberOnFirstPage(m_xBuilder->weld_check_button("shownumberonfirstpage"))
+{
+ m_xShowNumberOnFirstPage->hide();
+}
+
+OPageNumberDialog::~OPageNumberDialog()
+{
+}
+
+short OPageNumberDialog::run()
+{
+ short nRet = GenericDialogController::run();
+ if (nRet == RET_OK)
+ {
+ try
+ {
+ sal_Int32 nControlMaxSize = 3000;
+ sal_Int32 nPosX = 0;
+ sal_Int32 nPos2X = 0;
+ awt::Size aRptSize = getStyleProperty<awt::Size>(m_xHoldAlive,PROPERTY_PAPERSIZE);
+ switch (m_xAlignmentLst->get_active())
+ {
+ case 0: // left
+ nPosX = getStyleProperty<sal_Int32>(m_xHoldAlive,PROPERTY_LEFTMARGIN);
+ break;
+ case 1: // middle
+ nPosX = getStyleProperty<sal_Int32>(m_xHoldAlive,PROPERTY_LEFTMARGIN) + (aRptSize.Width - getStyleProperty<sal_Int32>(m_xHoldAlive,PROPERTY_LEFTMARGIN) - getStyleProperty<sal_Int32>(m_xHoldAlive,PROPERTY_RIGHTMARGIN) - nControlMaxSize) / 2;
+ break;
+ case 2: // right
+ nPosX = (aRptSize.Width - getStyleProperty<sal_Int32>(m_xHoldAlive,PROPERTY_RIGHTMARGIN) - nControlMaxSize);
+ break;
+ case 3: // inner
+ case 4: // outer
+ nPosX = getStyleProperty<sal_Int32>(m_xHoldAlive,PROPERTY_LEFTMARGIN);
+ nPos2X = (aRptSize.Width - getStyleProperty<sal_Int32>(m_xHoldAlive,PROPERTY_RIGHTMARGIN) - nControlMaxSize);
+ break;
+ default:
+ break;
+ }
+ if (m_xAlignmentLst->get_active() > 2)
+ nPosX = nPos2X;
+
+ uno::Sequence<beans::PropertyValue> aValues( comphelper::InitPropertySequence({
+ { PROPERTY_POSITION, uno::Any(awt::Point(nPosX,0)) },
+ { PROPERTY_PAGEHEADERON, uno::Any(m_xTopPage->get_active()) },
+ { PROPERTY_STATE, uno::Any(m_xPageNofM->get_active()) }
+ }));
+
+ m_pController->executeChecked(SID_INSERT_FLD_PGNUMBER,aValues);
+ }
+ catch(uno::Exception&)
+ {
+ }
+ }
+ return nRet;
+}
+
+} // rptui
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/reportdesign/source/ui/dlg/dlgpage.cxx b/reportdesign/source/ui/dlg/dlgpage.cxx
new file mode 100644
index 0000000000..7e99ba19d4
--- /dev/null
+++ b/reportdesign/source/ui/dlg/dlgpage.cxx
@@ -0,0 +1,78 @@
+/* -*- 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 <svx/dialogs.hrc>
+#include <sfx2/sfxdlg.hxx>
+#include <dlgpage.hxx>
+#include <svl/cjkoptions.hxx>
+#include <osl/diagnose.h>
+
+namespace rptui
+{
+/*************************************************************************
+|*
+|* constructor of the tab dialogs: Add the page to the dialog
+|*
+\************************************************************************/
+
+ORptPageDialog::ORptPageDialog(weld::Window* pParent, const SfxItemSet* pAttr, const OUString &rDialog)
+ : SfxTabDialogController(pParent, "modules/dbreport/ui/" +
+ rDialog.toAsciiLowerCase() + ".ui", rDialog, pAttr)
+{
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+
+ if (rDialog == "BackgroundDialog")
+ {
+ AddTabPage("background", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BKG ), nullptr );
+ }
+ else if (rDialog == "PageDialog")
+ {
+ AddTabPage("page", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_PAGE ), nullptr );
+ AddTabPage("background", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BKG ), nullptr );
+ }
+ else if (rDialog == "CharDialog")
+ {
+ AddTabPage("font", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_NAME ), nullptr );
+ AddTabPage("fonteffects", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_EFFECTS ), nullptr );
+ AddTabPage("position", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_POSITION ), nullptr );
+ AddTabPage("asianlayout", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_TWOLINES ), nullptr );
+ AddTabPage("background", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BKG ), nullptr );
+ AddTabPage("alignment", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_ALIGNMENT ), nullptr );
+ }
+ else
+ OSL_FAIL("Unknown page id");
+
+ if ( !SvtCJKOptions::IsDoubleLinesEnabled() )
+ RemoveTabPage("asianlayout");
+}
+
+void ORptPageDialog::PageCreated(const OUString& rId, SfxTabPage &rPage)
+{
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ if (rId == "background")
+ {
+ rPage.PageCreated(aSet);
+ }
+}
+
+} // namespace rptui
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */