summaryrefslogtreecommitdiffstats
path: root/chart2/source/controller/main
diff options
context:
space:
mode:
Diffstat (limited to 'chart2/source/controller/main')
-rw-r--r--chart2/source/controller/main/ChartController.cxx1655
-rw-r--r--chart2/source/controller/main/ChartController_EditData.cxx52
-rw-r--r--chart2/source/controller/main/ChartController_Insert.cxx987
-rw-r--r--chart2/source/controller/main/ChartController_Position.cxx202
-rw-r--r--chart2/source/controller/main/ChartController_Properties.cxx840
-rw-r--r--chart2/source/controller/main/ChartController_TextEdit.cxx230
-rw-r--r--chart2/source/controller/main/ChartController_Tools.cxx1127
-rw-r--r--chart2/source/controller/main/ChartController_Window.cxx2103
-rw-r--r--chart2/source/controller/main/ChartDropTargetHelper.cxx178
-rw-r--r--chart2/source/controller/main/ChartDropTargetHelper.hxx56
-rw-r--r--chart2/source/controller/main/ChartFrameloader.cxx185
-rw-r--r--chart2/source/controller/main/ChartFrameloader.hxx67
-rw-r--r--chart2/source/controller/main/ChartModelClone.cxx227
-rw-r--r--chart2/source/controller/main/ChartModelClone.hxx75
-rw-r--r--chart2/source/controller/main/ChartTransferable.cxx161
-rw-r--r--chart2/source/controller/main/ChartTransferable.hxx60
-rw-r--r--chart2/source/controller/main/ChartWindow.cxx376
-rw-r--r--chart2/source/controller/main/CommandDispatch.cxx141
-rw-r--r--chart2/source/controller/main/CommandDispatch.hxx130
-rw-r--r--chart2/source/controller/main/CommandDispatchContainer.cxx201
-rw-r--r--chart2/source/controller/main/ControllerCommandDispatch.cxx844
-rw-r--r--chart2/source/controller/main/ControllerCommandDispatch.hxx119
-rw-r--r--chart2/source/controller/main/DragMethod_Base.cxx75
-rw-r--r--chart2/source/controller/main/DragMethod_Base.hxx59
-rw-r--r--chart2/source/controller/main/DragMethod_PieSegment.cxx151
-rw-r--r--chart2/source/controller/main/DragMethod_PieSegment.hxx54
-rw-r--r--chart2/source/controller/main/DragMethod_RotateDiagram.cxx230
-rw-r--r--chart2/source/controller/main/DragMethod_RotateDiagram.hxx86
-rw-r--r--chart2/source/controller/main/DrawCommandDispatch.cxx613
-rw-r--r--chart2/source/controller/main/DrawCommandDispatch.hxx74
-rw-r--r--chart2/source/controller/main/ElementSelector.cxx319
-rw-r--r--chart2/source/controller/main/ElementSelector.hxx99
-rw-r--r--chart2/source/controller/main/FeatureCommandDispatchBase.cxx94
-rw-r--r--chart2/source/controller/main/FeatureCommandDispatchBase.hxx135
-rw-r--r--chart2/source/controller/main/ObjectHierarchy.cxx727
-rw-r--r--chart2/source/controller/main/PositionAndSizeHelper.cxx179
-rw-r--r--chart2/source/controller/main/SelectionHelper.cxx651
-rw-r--r--chart2/source/controller/main/ShapeController.cxx673
-rw-r--r--chart2/source/controller/main/ShapeController.hxx81
-rw-r--r--chart2/source/controller/main/StatusBarCommandDispatch.cxx127
-rw-r--r--chart2/source/controller/main/StatusBarCommandDispatch.hxx94
-rw-r--r--chart2/source/controller/main/ToolbarController.cxx121
-rw-r--r--chart2/source/controller/main/UndoActions.cxx115
-rw-r--r--chart2/source/controller/main/UndoActions.hxx101
-rw-r--r--chart2/source/controller/main/UndoCommandDispatch.cxx146
-rw-r--r--chart2/source/controller/main/UndoCommandDispatch.hxx69
-rw-r--r--chart2/source/controller/main/UndoGuard.cxx152
-rw-r--r--chart2/source/controller/main/UndoGuard.hxx115
48 files changed, 15356 insertions, 0 deletions
diff --git a/chart2/source/controller/main/ChartController.cxx b/chart2/source/controller/main/ChartController.cxx
new file mode 100644
index 0000000000..666d6b6367
--- /dev/null
+++ b/chart2/source/controller/main/ChartController.cxx
@@ -0,0 +1,1655 @@
+/* -*- 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 <memory>
+#include <sal/config.h>
+
+#include <config_wasm_strip.h>
+#include <ChartController.hxx>
+#include <ChartView.hxx>
+#include <servicenames.hxx>
+#include <ResId.hxx>
+#include <dlg_DataSource.hxx>
+#include <ChartModel.hxx>
+#include <ChartModelHelper.hxx>
+#include <ChartType.hxx>
+#include "ControllerCommandDispatch.hxx"
+#include <DataSeries.hxx>
+#include <Diagram.hxx>
+#include <strings.hrc>
+#include <chartview/ExplicitValueProvider.hxx>
+#include <ChartViewHelper.hxx>
+
+#include <ChartWindow.hxx>
+#include <chartview/DrawModelWrapper.hxx>
+#include <DrawViewWrapper.hxx>
+#include <ObjectIdentifier.hxx>
+#include <DiagramHelper.hxx>
+#include <ControllerLockGuard.hxx>
+#include "UndoGuard.hxx"
+#include "ChartDropTargetHelper.hxx"
+
+#include <dlg_ChartType.hxx>
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+#include <AccessibleChartView.hxx>
+#endif
+#include "DrawCommandDispatch.hxx"
+#include "ShapeController.hxx"
+#include "UndoActions.hxx"
+#include <ViewElementListProvider.hxx>
+
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <BaseCoordinateSystem.hxx>
+
+#include <com/sun/star/awt/XVclWindowPeer.hpp>
+#include <com/sun/star/frame/XController2.hpp>
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <com/sun/star/util/XModeChangeBroadcaster.hpp>
+#include <com/sun/star/frame/LayoutManagerEvents.hpp>
+#include <com/sun/star/frame/XLayoutManagerEventBroadcaster.hpp>
+#include <com/sun/star/ui/XSidebar.hpp>
+#include <com/sun/star/chart2/XDataProviderAccess.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <svx/sidebar/SelectionChangeHandler.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <osl/mutex.hxx>
+#include <comphelper/lok.hxx>
+
+#include <sfx2/sidebar/SidebarController.hxx>
+
+#include <com/sun/star/frame/XLayoutManager.hpp>
+
+// this is needed to properly destroy the unique_ptr to the AcceleratorExecute
+// object in the DTOR
+#include <svtools/acceleratorexecute.hxx>
+#include <svx/ActionDescriptionProvider.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+// enable the following define to let the controller listen to model changes and
+// react on this by rebuilding the view
+#define TEST_ENABLE_MODIFY_LISTENER
+
+namespace chart
+{
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::chart2;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+ChartController::ChartController(uno::Reference<uno::XComponentContext> xContext) :
+ m_aLifeTimeManager( nullptr ),
+ m_bSuspended( false ),
+ m_xCC(std::move(xContext)),
+ m_aModel( nullptr, m_aModelMutex ),
+ m_eDragMode(SdrDragMode::Move),
+ m_aDoubleClickTimer("chart2 ChartController m_aDoubleClickTimer"),
+ m_bWaitingForDoubleClick(false),
+ m_bWaitingForMouseUp(false),
+ m_bFieldButtonDown(false),
+ m_bConnectingToView(false),
+ m_bDisposed(false),
+ m_aDispatchContainer( m_xCC ),
+ m_eDrawMode( CHARTDRAW_SELECT ),
+ mpSelectionChangeHandler(new svx::sidebar::SelectionChangeHandler(
+ [this]() { return this->GetContextName(); },
+ this, vcl::EnumContext::Context::Cell))
+{
+ m_aDoubleClickTimer.SetInvokeHandler( LINK( this, ChartController, DoubleClickWaitingHdl ) );
+}
+
+ChartController::~ChartController()
+{
+ stopDoubleClickWaiting();
+}
+
+ChartController::TheModel::TheModel( rtl::Reference<::chart::ChartModel> xModel ) :
+ m_xModel(std::move( xModel )),
+ m_bOwnership( true )
+{
+}
+
+ChartController::TheModel::~TheModel()
+{
+}
+
+void ChartController::TheModel::addListener( ChartController* pController )
+{
+ if(m_xModel)
+ {
+ //if you need to be able to veto against the destruction of the model
+ // you must add as a close listener
+
+ //otherwise you 'can' add as closelistener or 'must' add as dispose event listener
+
+ m_xModel->addCloseListener(
+ static_cast<util::XCloseListener*>(pController) );
+ }
+}
+
+void ChartController::TheModel::removeListener( ChartController* pController )
+{
+ if(m_xModel)
+ m_xModel->removeCloseListener(
+ static_cast<util::XCloseListener*>(pController) );
+}
+
+void ChartController::TheModel::tryTermination()
+{
+ if(!m_bOwnership)
+ return;
+
+ try
+ {
+ if(m_xModel.is())
+ {
+ try
+ {
+ //@todo ? are we allowed to use sal_True here if we have the explicit ownership?
+ //I think yes, because there might be other CloseListeners later in the list which might be interested still
+ //but make sure that we do not throw the CloseVetoException here ourselves
+ //so stop listening before trying to terminate or check the source of queryclosing event
+ m_xModel->close(true);
+
+ m_bOwnership = false;
+ }
+ catch( const util::CloseVetoException& )
+ {
+ //since we have indicated to give up the ownership with parameter true in close call
+ //the one who has thrown the CloseVetoException is the new owner
+
+ SAL_WARN_IF( m_bOwnership, "chart2.main", "a well known owner has caught a CloseVetoException after calling close(true)");
+ m_bOwnership = false;
+ return;
+ }
+
+ }
+ }
+ catch(const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION( "chart2", "Termination of model failed" );
+ }
+}
+
+ChartController::TheModelRef::TheModelRef( TheModel* pTheModel, osl::Mutex& rMutex ) :
+ m_rModelMutex(rMutex)
+{
+ osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
+ m_xTheModel = pTheModel;
+}
+ChartController::TheModelRef::TheModelRef( const TheModelRef& rTheModel, ::osl::Mutex& rMutex ) :
+ m_rModelMutex(rMutex)
+{
+ osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
+ m_xTheModel = rTheModel.m_xTheModel;
+}
+ChartController::TheModelRef& ChartController::TheModelRef::operator=(TheModel* pTheModel)
+{
+ osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
+ m_xTheModel = pTheModel;
+ return *this;
+}
+ChartController::TheModelRef& ChartController::TheModelRef::operator=(const TheModelRef& rTheModel)
+{
+ osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
+ m_xTheModel = rTheModel.operator->();
+ return *this;
+}
+ChartController::TheModelRef::~TheModelRef()
+{
+ osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
+ m_xTheModel.clear();
+}
+bool ChartController::TheModelRef::is() const
+{
+ return m_xTheModel.is();
+}
+
+namespace {
+
+rtl::Reference<ChartType> getChartType(const rtl::Reference<ChartModel>& xChartDoc)
+{
+ rtl::Reference<Diagram > xDiagram = xChartDoc->getFirstChartDiagram();
+ if (!xDiagram.is())
+ return nullptr;
+
+ const std::vector< rtl::Reference< BaseCoordinateSystem > > & xCooSysSequence( xDiagram->getBaseCoordinateSystems());
+ if (xCooSysSequence.empty())
+ return nullptr;
+
+ return xCooSysSequence[0]->getChartTypes2()[0];
+}
+
+}
+
+OUString ChartController::GetContextName()
+{
+ if (m_bDisposed)
+ return OUString();
+
+ uno::Any aAny = getSelection();
+ if (!aAny.hasValue())
+ return "Chart";
+
+ OUString aCID;
+ aAny >>= aCID;
+
+ if (aCID.isEmpty())
+ return "Chart";
+
+ ObjectType eObjectID = ObjectIdentifier::getObjectType(aCID);
+ switch (eObjectID)
+ {
+ case OBJECTTYPE_DATA_SERIES:
+ return "Series";
+ case OBJECTTYPE_DATA_ERRORS_X:
+ case OBJECTTYPE_DATA_ERRORS_Y:
+ case OBJECTTYPE_DATA_ERRORS_Z:
+ return "ErrorBar";
+ case OBJECTTYPE_AXIS:
+ return "Axis";
+ case OBJECTTYPE_GRID:
+ return "Grid";
+ case OBJECTTYPE_DIAGRAM:
+ {
+ rtl::Reference<ChartType> xChartType = getChartType(getChartModel());
+ if (xChartType.is() && xChartType->getChartType() == "com.sun.star.chart2.PieChartType")
+ return "ChartElements";
+ break;
+ }
+ case OBJECTTYPE_DATA_CURVE:
+ case OBJECTTYPE_DATA_AVERAGE_LINE:
+ return "Trendline";
+ default:
+ break;
+ }
+
+ return "Chart";
+}
+
+// private methods
+
+bool ChartController::impl_isDisposedOrSuspended() const
+{
+ if( m_aLifeTimeManager.impl_isDisposed() )
+ return true;
+
+ if( m_bSuspended )
+ {
+ OSL_FAIL( "This Controller is suspended" );
+ return true;
+ }
+ return false;
+}
+
+namespace {
+
+uno::Reference<ui::XSidebar> getSidebarFromModel(const uno::Reference<frame::XModel>& xModel)
+{
+ uno::Reference<container::XChild> xChild(xModel, uno::UNO_QUERY);
+ if (!xChild.is())
+ return nullptr;
+
+ uno::Reference<frame::XModel> xParent (xChild->getParent(), uno::UNO_QUERY);
+ if (!xParent.is())
+ return nullptr;
+
+ uno::Reference<frame::XController2> xController(xParent->getCurrentController(), uno::UNO_QUERY);
+ if (!xController.is())
+ return nullptr;
+
+ uno::Reference<ui::XSidebarProvider> xSidebarProvider = xController->getSidebar();
+ if (!xSidebarProvider.is())
+ return nullptr;
+
+ return xSidebarProvider->getSidebar();
+}
+
+}
+
+// XController
+
+void SAL_CALL ChartController::attachFrame(
+ const uno::Reference<frame::XFrame>& xFrame )
+{
+ SolarMutexGuard aGuard;
+
+ if( impl_isDisposedOrSuspended() ) //@todo? allow attaching the frame while suspended?
+ return; //behave passive if already disposed or suspended
+
+ if(m_xFrame.is()) //what happens, if we do have a Frame already??
+ {
+ //@todo? throw exception?
+ OSL_FAIL( "there is already a frame attached to the controller" );
+ return;
+ }
+
+ //--attach frame
+ m_xFrame = xFrame; //the frameloader is responsible to call xFrame->setComponent
+
+ // Only notify after setting the frame, otherwise notification will fail
+ mpSelectionChangeHandler->Connect();
+
+ uno::Reference<ui::XSidebar> xSidebar = getSidebarFromModel(getChartModel());
+ if (xSidebar.is())
+ {
+ auto pSidebar = dynamic_cast<sfx2::sidebar::SidebarController*>(xSidebar.get());
+ assert(pSidebar);
+ pSidebar->registerSidebarForFrame(this);
+ pSidebar->updateModel(getChartModel());
+ css::lang::EventObject aEvent;
+ mpSelectionChangeHandler->selectionChanged(aEvent);
+ }
+
+ //add as disposelistener to the frame (due to persistent reference) ??...:
+
+ //the frame is considered to be owner of this controller and will live longer than we do
+ //the frame or the disposer of the frame has the duty to call suspend and dispose on this object
+ //so we do not need to add as lang::XEventListener for DisposingEvents right?
+
+ //@todo nothing right???
+
+ //create view @todo is this the correct place here??
+
+ vcl::Window* pParent = nullptr;
+ //get the window parent from the frame to use as parent for our new window
+ if(xFrame.is())
+ {
+ uno::Reference<awt::XWindow> xContainerWindow = xFrame->getContainerWindow();
+ if (xContainerWindow)
+ xContainerWindow->setVisible(true);
+ pParent = VCLUnoHelper::GetWindow( xContainerWindow );
+ }
+
+ {
+ // calls to VCL
+ SolarMutexGuard aSolarGuard;
+ auto pChartWindow = VclPtr<ChartWindow>::Create(this,pParent,pParent?pParent->GetStyle():0);
+ pChartWindow->SetBackground();//no Background
+ m_xViewWindow.set( pChartWindow->GetComponentInterface(), uno::UNO_QUERY );
+ pChartWindow->Show();
+ m_apDropTargetHelper.reset(
+ new ChartDropTargetHelper( pChartWindow->GetDropTarget(), getChartModel()));
+
+ impl_createDrawViewController();
+ }
+
+ //create the menu
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xFrame, uno::UNO_QUERY );
+ if( xPropSet.is() )
+ {
+ try
+ {
+ uno::Reference< css::frame::XLayoutManager > xLayoutManager;
+ xPropSet->getPropertyValue( "LayoutManager" ) >>= xLayoutManager;
+ if ( xLayoutManager.is() )
+ {
+ xLayoutManager->lock();
+ xLayoutManager->requestElement( "private:resource/menubar/menubar" );
+ //@todo: createElement should become unnecessary, remove when #i79198# is fixed
+ xLayoutManager->createElement( "private:resource/toolbar/standardbar" );
+ xLayoutManager->requestElement( "private:resource/toolbar/standardbar" );
+ //@todo: createElement should become unnecessary, remove when #i79198# is fixed
+ xLayoutManager->createElement( "private:resource/toolbar/toolbar" );
+ xLayoutManager->requestElement( "private:resource/toolbar/toolbar" );
+
+ // #i12587# support for shapes in chart
+ xLayoutManager->createElement( "private:resource/toolbar/drawbar" );
+ xLayoutManager->requestElement( "private:resource/toolbar/drawbar" );
+
+ xLayoutManager->requestElement( "private:resource/statusbar/statusbar" );
+ xLayoutManager->unlock();
+
+ // add as listener to get notified when
+ m_xLayoutManagerEventBroadcaster.set( xLayoutManager, uno::UNO_QUERY );
+ if( m_xLayoutManagerEventBroadcaster.is())
+ m_xLayoutManagerEventBroadcaster->addLayoutManagerEventListener( this );
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ }
+ }
+}
+
+//XModeChangeListener
+void SAL_CALL ChartController::modeChanged( const util::ModeChangeEvent& rEvent )
+{
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+ //adjust controller to view status changes
+
+ if( rEvent.NewMode == "dirty" )
+ {
+ //the view has become dirty, we should repaint it if we have a window
+ if( pChartWindow )
+ pChartWindow->ForceInvalidate();
+ }
+ else if( rEvent.NewMode == "invalid" )
+ {
+ //the view is about to become invalid so end all actions on it
+ impl_invalidateAccessible();
+ if( m_pDrawViewWrapper && m_pDrawViewWrapper->IsTextEdit() )
+ this->EndTextEdit();
+ if( m_pDrawViewWrapper )
+ {
+ m_pDrawViewWrapper->UnmarkAll();
+ m_pDrawViewWrapper->HideSdrPage();
+ }
+ }
+ else
+ {
+ //the view was rebuild so we can start some actions on it again
+ if( !m_bConnectingToView )
+ {
+ if(pChartWindow && m_aModel.is() )
+ {
+ m_bConnectingToView = true;
+
+ GetDrawModelWrapper();
+ if(m_pDrawModelWrapper)
+ {
+ {
+ if( m_pDrawViewWrapper )
+ m_pDrawViewWrapper->ReInit();
+ }
+
+ //reselect object
+ if( m_aSelection.hasSelection() )
+ this->impl_selectObjectAndNotiy();
+ else
+ ChartModelHelper::triggerRangeHighlighting( getChartModel() );
+
+ impl_initializeAccessible();
+
+ {
+ if( pChartWindow )
+ pChartWindow->Invalidate();
+ }
+ }
+
+ m_bConnectingToView = false;
+ }
+ }
+ }
+}
+
+sal_Bool SAL_CALL ChartController::attachModel( const uno::Reference< frame::XModel > & xModel )
+{
+ impl_invalidateAccessible();
+
+ //is called to attach the controller to a new model.
+ //return true if attach was successfully, false otherwise (e.g. if you do not work with a model)
+
+ SolarMutexResettableGuard aGuard;
+ if( impl_isDisposedOrSuspended() ) //@todo? allow attaching a new model while suspended?
+ return false; //behave passive if already disposed or suspended
+ aGuard.clear();
+
+ ::chart::ChartModel* pChartModel = dynamic_cast<::chart::ChartModel*>(xModel.get());
+ assert(!xModel || pChartModel);
+
+ TheModelRef aNewModelRef( new TheModel(pChartModel), m_aModelMutex);
+ TheModelRef aOldModelRef(m_aModel,m_aModelMutex);
+ m_aModel = aNewModelRef;
+
+ //--handle relations to the old model if any
+ if( aOldModelRef.is() )
+ {
+ if( m_xChartView.is() )
+ m_xChartView->removeModeChangeListener(this);
+ m_pDrawModelWrapper.reset();
+
+ aOldModelRef->removeListener( this );
+ #ifdef TEST_ENABLE_MODIFY_LISTENER
+ if( aOldModelRef->getModel().is())
+ aOldModelRef->getModel()->removeModifyListener( this );
+#endif
+ }
+
+ //--handle relations to the new model
+ aNewModelRef->addListener( this );
+
+ aGuard.reset(); // lock for m_aDispatchContainer access
+ // set new model at dispatchers
+ m_aDispatchContainer.setModel( aNewModelRef->getModel());
+ rtl::Reference<ControllerCommandDispatch> pDispatch = new ControllerCommandDispatch( m_xCC, this, &m_aDispatchContainer );
+ pDispatch->initialize();
+
+ // the dispatch container will return "this" for all commands returned by
+ // impl_getAvailableCommands(). That means, for those commands dispatch()
+ // is called here at the ChartController.
+ m_aDispatchContainer.setChartDispatch( pDispatch, o3tl::sorted_vector(impl_getAvailableCommands()) );
+
+ rtl::Reference<DrawCommandDispatch> pDrawDispatch = new DrawCommandDispatch( m_xCC, this );
+ pDrawDispatch->initialize();
+ m_aDispatchContainer.setDrawCommandDispatch( pDrawDispatch.get() );
+
+ rtl::Reference<ShapeController> pShapeController = new ShapeController( m_xCC, this );
+ pShapeController->initialize();
+ m_aDispatchContainer.setShapeController( pShapeController.get() );
+ aGuard.clear();
+
+#ifdef TEST_ENABLE_MODIFY_LISTENER
+ if( aNewModelRef->getModel().is())
+ aNewModelRef->getModel()->addModifyListener( this );
+#endif
+
+ // #i119999# Do not do this per default to allow the user to deselect the chart OLE with a single press to ESC
+ // select chart area per default:
+ // select( uno::Any( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) ) );
+
+ rtl::Reference< ChartModel > xFact = getChartModel();
+ if( xFact.is())
+ {
+ m_xChartView = dynamic_cast<::chart::ChartView*>(xFact->createInstance( CHART_VIEW_SERVICE_NAME ).get());
+ GetDrawModelWrapper();
+ m_xChartView->addModeChangeListener(this);
+ }
+
+ //the frameloader is responsible to call xModel->connectController
+ {
+ SolarMutexGuard aGuard2;
+ auto pChartWindow(GetChartWindow());
+ if( pChartWindow )
+ pChartWindow->Invalidate();
+ }
+
+ m_xUndoManager.set( getChartModel()->getUndoManager(), uno::UNO_SET_THROW );
+
+ return true;
+}
+
+uno::Reference< frame::XFrame > SAL_CALL ChartController::getFrame()
+{
+ //provides access to owner frame of this controller
+ //return the frame containing this controller
+
+ return m_xFrame;
+}
+
+uno::Reference< frame::XModel > SAL_CALL ChartController::getModel()
+{
+ return getChartModel();
+}
+
+rtl::Reference<::chart::ChartModel> ChartController::getChartModel()
+{
+ //provides access to currently attached model
+ //returns the currently attached model
+
+ //return nothing, if you do not have a model
+ TheModelRef aModelRef( m_aModel, m_aModelMutex);
+ if(aModelRef.is())
+ return aModelRef->getModel();
+
+ return nullptr;
+}
+
+rtl::Reference<::chart::Diagram> ChartController::getFirstDiagram()
+{
+ return getChartModel()->getFirstChartDiagram();
+}
+
+uno::Any SAL_CALL ChartController::getViewData()
+{
+ //provides access to current view status
+ //set of data that can be used to restore the current view status at later time
+ // by using XController::restoreViewData()
+
+ SolarMutexGuard aGuard;
+ if( impl_isDisposedOrSuspended() )
+ return uno::Any(); //behave passive if already disposed or suspended //@todo? or throw an exception??
+
+ //-- collect current view state
+ uno::Any aRet;
+ //// @todo integrate specialized implementation
+
+ return aRet;
+}
+
+void SAL_CALL ChartController::restoreViewData(
+ const uno::Any& /* Value */ )
+{
+ //restores the view status using the data gotten from a previous call to XController::getViewData()
+
+ SolarMutexGuard aGuard;
+ if( impl_isDisposedOrSuspended() )
+ return; //behave passive if already disposed or suspended //@todo? or throw an exception??
+
+ //// @todo integrate specialized implementation
+}
+
+sal_Bool SAL_CALL ChartController::suspend( sal_Bool bSuspend )
+{
+ //is called to prepare the controller for closing the view
+ //bSuspend==true: force the controller to suspend his work
+ //bSuspend==false try to reactivate the controller
+ //returns true if request was accepted and of course successfully finished, false otherwise
+
+ //we may show dialogs here to ask the user for saving changes ... @todo?
+
+ SolarMutexGuard aGuard;
+ if( m_aLifeTimeManager.impl_isDisposed() )
+ return false; //behave passive if already disposed, return false because request was not accepted //@todo? correct
+
+ if(bool(bSuspend) == m_bSuspended)
+ {
+ OSL_FAIL( "new suspend mode equals old suspend mode" );
+ return true;
+ }
+
+ //change suspend mode
+ m_bSuspended = bSuspend;
+ return true;
+}
+
+// css::frame::XController2
+
+css::uno::Reference<css::awt::XWindow> SAL_CALL ChartController::getComponentWindow()
+{
+ // it is a special characteristic of ChartController
+ // that it simultaneously provides the XWindow functionality
+ return this;
+}
+
+OUString SAL_CALL ChartController::getViewControllerName() { return {}; }
+
+css::uno::Sequence<css::beans::PropertyValue> SAL_CALL ChartController::getCreationArguments()
+{
+ return {};
+}
+
+css::uno::Reference<css::ui::XSidebarProvider> SAL_CALL ChartController::getSidebar() { return {}; }
+
+void ChartController::impl_createDrawViewController()
+{
+ SolarMutexGuard aGuard;
+ if(!m_pDrawViewWrapper)
+ {
+ if( m_pDrawModelWrapper )
+ {
+ bool bLokCalcGlobalRTL = false;
+ if(comphelper::LibreOfficeKit::isActive() && AllSettings::GetLayoutRTL())
+ {
+ rtl::Reference< ChartModel > xChartModel = getChartModel();
+ if (xChartModel.is())
+ {
+ uno::Reference<css::sheet::XSpreadsheetDocument> xSSDoc(xChartModel->getParent(), uno::UNO_QUERY);
+ if (xSSDoc.is())
+ bLokCalcGlobalRTL = true;
+ }
+ }
+
+ m_pDrawViewWrapper.reset( new DrawViewWrapper(m_pDrawModelWrapper->getSdrModel(),GetChartWindow()->GetOutDev()) );
+ m_pDrawViewWrapper->SetNegativeX(bLokCalcGlobalRTL);
+ m_pDrawViewWrapper->attachParentReferenceDevice( getChartModel() );
+ }
+ }
+}
+
+void ChartController::impl_deleteDrawViewController()
+{
+ if( m_pDrawViewWrapper )
+ {
+ SolarMutexGuard aGuard;
+ if( m_pDrawViewWrapper->IsTextEdit() )
+ this->EndTextEdit();
+ m_pDrawViewWrapper.reset();
+ }
+}
+
+// XComponent (base of XController)
+
+void SAL_CALL ChartController::dispose()
+{
+ m_bDisposed = true;
+
+ mpSelectionChangeHandler->selectionChanged(css::lang::EventObject());
+ mpSelectionChangeHandler->Disconnect();
+
+ if (getModel().is())
+ {
+ uno::Reference<ui::XSidebar> xSidebar = getSidebarFromModel(getChartModel());
+ if (sfx2::sidebar::SidebarController* pSidebar = dynamic_cast<sfx2::sidebar::SidebarController*>(xSidebar.get()))
+ {
+ pSidebar->unregisterSidebarForFrame(this);
+ }
+ }
+
+ try
+ {
+ //This object should release all resources and references in the
+ //easiest possible manner
+ //This object must notify all registered listeners using the method
+ //<member>XEventListener::disposing</member>
+
+ //hold no mutex
+ if( !m_aLifeTimeManager.dispose() )
+ return;
+
+// OSL_ENSURE( m_bSuspended, "dispose was called but controller is not suspended" );
+
+ this->stopDoubleClickWaiting();
+
+ //end range highlighting
+ if( m_aModel.is())
+ {
+ uno::Reference< view::XSelectionChangeListener > xSelectionChangeListener;
+ rtl::Reference< ChartModel > xDataReceiver = getChartModel();
+ if( xDataReceiver.is() )
+ xSelectionChangeListener.set( xDataReceiver->getRangeHighlighter(), uno::UNO_QUERY );
+ if( xSelectionChangeListener.is() )
+ {
+ uno::Reference< frame::XController > xController( this );
+ lang::EventObject aEvent( xController );
+ xSelectionChangeListener->disposing( aEvent );
+ }
+ }
+
+ //--release all resources and references
+ {
+ if( m_xChartView.is() )
+ m_xChartView->removeModeChangeListener(this);
+
+ impl_invalidateAccessible();
+ SolarMutexGuard aSolarGuard;
+ impl_deleteDrawViewController();
+ m_pDrawModelWrapper.reset();
+
+ m_apDropTargetHelper.reset();
+
+ //the accessible view is disposed within window destructor of m_pChartWindow
+ if(m_xViewWindow.is())
+ m_xViewWindow->dispose(); //ChartWindow is deleted via UNO due to dispose of m_xViewWindow (triggered by Framework (Controller pretends to be XWindow also))
+ m_xChartView.clear();
+ }
+
+ // remove as listener to layout manager events
+ if( m_xLayoutManagerEventBroadcaster.is())
+ {
+ m_xLayoutManagerEventBroadcaster->removeLayoutManagerEventListener( this );
+ m_xLayoutManagerEventBroadcaster.clear();
+ }
+
+ m_xFrame.clear();
+ m_xUndoManager.clear();
+
+ TheModelRef aModelRef( m_aModel, m_aModelMutex);
+ m_aModel = nullptr;
+
+ if( aModelRef.is())
+ {
+ uno::Reference< frame::XModel > xModel( aModelRef->getModel() );
+ if(xModel.is())
+ xModel->disconnectController( uno::Reference< frame::XController >( this ));
+
+ aModelRef->removeListener( this );
+#ifdef TEST_ENABLE_MODIFY_LISTENER
+ try
+ {
+ if( aModelRef->getModel().is())
+ aModelRef->getModel()->removeModifyListener( this );
+ }
+ catch( const uno::Exception & )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+#endif
+ aModelRef->tryTermination();
+ }
+
+ //// @todo integrate specialized implementation
+ //e.g. release further resources and references
+
+ SolarMutexGuard g;
+ m_aDispatchContainer.DisposeAndClear();
+ }
+ catch( const uno::Exception & )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ assert(!m_xChartView.is());
+ }
+ }
+
+void SAL_CALL ChartController::addEventListener(
+ const uno::Reference<lang::XEventListener>& xListener )
+{
+ if( impl_isDisposedOrSuspended() )//@todo? allow adding of listeners in suspend mode?
+ return; //behave passive if already disposed or suspended
+
+ //--add listener
+ std::unique_lock aGuard2(m_aLifeTimeManager.m_aAccessMutex);
+ m_aLifeTimeManager.m_aEventListeners.addInterface( aGuard2, xListener );
+}
+
+void SAL_CALL ChartController::removeEventListener(
+ const uno::Reference<lang::XEventListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+ if( m_aLifeTimeManager.impl_isDisposed(false) )
+ return; //behave passive if already disposed or suspended
+
+ //--remove listener
+ std::unique_lock aGuard2(m_aLifeTimeManager.m_aAccessMutex);
+ m_aLifeTimeManager.m_aEventListeners.removeInterface( aGuard2, xListener );
+}
+
+// util::XCloseListener
+void SAL_CALL ChartController::queryClosing(
+ const lang::EventObject& rSource,
+ sal_Bool /*bGetsOwnership*/ )
+{
+ //do not use the m_aControllerMutex here because this call is not allowed to block
+
+ TheModelRef aModelRef( m_aModel, m_aModelMutex);
+
+ if( !aModelRef.is() )
+ return;
+
+ if( uno::Reference<XInterface>(static_cast<cppu::OWeakObject*>(aModelRef->getModel().get())) != rSource.Source )
+ {
+ OSL_FAIL( "queryClosing was called on a controller from an unknown source" );
+ return;
+ }
+
+ //@ todo prepare to closing model -> don't start any further hindering actions
+}
+
+void SAL_CALL ChartController::notifyClosing(
+ const lang::EventObject& rSource )
+{
+ //Listener should deregister himself and release all references to the closing object.
+
+ TheModelRef aModelRef( m_aModel, m_aModelMutex);
+ if( !impl_releaseThisModel( rSource.Source ) )
+ return;
+
+ //--stop listening to the closing model
+ aModelRef->removeListener( this );
+
+ // #i79087# If the model using this controller is closed, the frame is
+ // expected to be closed as well
+ Reference< util::XCloseable > xFrameCloseable( m_xFrame, uno::UNO_QUERY );
+ if( xFrameCloseable.is())
+ {
+ try
+ {
+ xFrameCloseable->close( false /* DeliverOwnership */ );
+ m_xFrame.clear();
+ }
+ catch( const util::CloseVetoException & )
+ {
+ // closing was vetoed
+ }
+ }
+}
+
+bool ChartController::impl_releaseThisModel(
+ const uno::Reference< uno::XInterface > & xModel )
+{
+ bool bReleaseModel = false;
+ {
+ ::osl::Guard< ::osl::Mutex > aGuard( m_aModelMutex );
+ if( m_aModel.is() && uno::Reference< uno::XInterface >(static_cast<cppu::OWeakObject*>(m_aModel->getModel().get())) == xModel )
+ {
+ m_aModel = nullptr;
+ m_xUndoManager.clear();
+ bReleaseModel = true;
+ }
+ }
+ if( bReleaseModel )
+ {
+ SolarMutexGuard g;
+ m_aDispatchContainer.setModel( nullptr );
+ }
+ return bReleaseModel;
+}
+
+// util::XEventListener (base of XCloseListener)
+void SAL_CALL ChartController::disposing(
+ const lang::EventObject& rSource )
+{
+ if( !impl_releaseThisModel( rSource.Source ))
+ {
+ if( rSource.Source == m_xLayoutManagerEventBroadcaster )
+ m_xLayoutManagerEventBroadcaster.clear();
+ }
+}
+
+void SAL_CALL ChartController::layoutEvent(
+ const lang::EventObject& aSource,
+ sal_Int16 eLayoutEvent,
+ const uno::Any& /* aInfo */ )
+{
+ if( eLayoutEvent == frame::LayoutManagerEvents::MERGEDMENUBAR )
+ {
+ Reference< frame::XLayoutManager > xLM( aSource.Source, uno::UNO_QUERY );
+ if( xLM.is())
+ {
+ xLM->createElement( "private:resource/statusbar/statusbar" );
+ xLM->requestElement( "private:resource/statusbar/statusbar" );
+ }
+ }
+}
+
+// XDispatchProvider (required interface)
+
+namespace
+{
+
+bool lcl_isFormatObjectCommand( std::u16string_view aCommand )
+{
+ return aCommand == u"MainTitle"
+ || aCommand == u"SubTitle"
+ || aCommand == u"XTitle"
+ || aCommand == u"YTitle"
+ || aCommand == u"ZTitle"
+ || aCommand == u"SecondaryXTitle"
+ || aCommand == u"SecondaryYTitle"
+ || aCommand == u"AllTitles"
+ || aCommand == u"DiagramAxisX"
+ || aCommand == u"DiagramAxisY"
+ || aCommand == u"DiagramAxisZ"
+ || aCommand == u"DiagramAxisA"
+ || aCommand == u"DiagramAxisB"
+ || aCommand == u"DiagramAxisAll"
+ || aCommand == u"DiagramGridXMain"
+ || aCommand == u"DiagramGridYMain"
+ || aCommand == u"DiagramGridZMain"
+ || aCommand == u"DiagramGridXHelp"
+ || aCommand == u"DiagramGridYHelp"
+ || aCommand == u"DiagramGridZHelp"
+ || aCommand == u"DiagramGridAll"
+
+ || aCommand == u"DiagramWall"
+ || aCommand == u"DiagramFloor"
+ || aCommand == u"DiagramArea"
+ || aCommand == u"Legend"
+
+ || aCommand == u"FormatWall"
+ || aCommand == u"FormatFloor"
+ || aCommand == u"FormatChartArea"
+ || aCommand == u"FormatLegend"
+
+ || aCommand == u"FormatTitle"
+ || aCommand == u"FormatAxis"
+ || aCommand == u"FormatDataSeries"
+ || aCommand == u"FormatDataPoint"
+ || aCommand == u"FormatDataLabels"
+ || aCommand == u"FormatDataLabel"
+ || aCommand == u"FormatXErrorBars"
+ || aCommand == u"FormatYErrorBars"
+ || aCommand == u"FormatMeanValue"
+ || aCommand == u"FormatTrendline"
+ || aCommand == u"FormatTrendlineEquation"
+ || aCommand == u"FormatStockLoss"
+ || aCommand == u"FormatStockGain"
+ || aCommand == u"FormatMajorGrid"
+ || aCommand == u"FormatMinorGrid";
+}
+
+} // anonymous namespace
+
+uno::Reference<frame::XDispatch> SAL_CALL
+ ChartController::queryDispatch(
+ const util::URL& rURL,
+ const OUString& rTargetFrameName,
+ sal_Int32 /* nSearchFlags */)
+{
+ SolarMutexGuard aGuard;
+
+ if ( !m_aLifeTimeManager.impl_isDisposed() && getModel().is() )
+ {
+ if( !rTargetFrameName.isEmpty() && rTargetFrameName == "_self" )
+ return m_aDispatchContainer.getDispatchForURL( rURL );
+ }
+ return uno::Reference< frame::XDispatch > ();
+}
+
+uno::Sequence<uno::Reference<frame::XDispatch > >
+ ChartController::queryDispatches(
+ const uno::Sequence<frame::DispatchDescriptor>& xDescripts )
+{
+ SolarMutexGuard g;
+
+ if ( !m_aLifeTimeManager.impl_isDisposed() )
+ {
+ return m_aDispatchContainer.getDispatchesForURLs( xDescripts );
+ }
+ return uno::Sequence<uno::Reference<frame::XDispatch > > ();
+}
+
+// frame::XDispatch
+
+void SAL_CALL ChartController::dispatch(
+ const util::URL& rURL,
+ const uno::Sequence< beans::PropertyValue >& rArgs )
+{
+ OUString aCommand = rURL.Path;
+
+ if(aCommand == "LOKSetTextSelection")
+ {
+ if (rArgs.getLength() == 3)
+ {
+ sal_Int32 nType = -1;
+ rArgs[0].Value >>= nType;
+ sal_Int32 nX = 0;
+ rArgs[1].Value >>= nX;
+ sal_Int32 nY = 0;
+ rArgs[2].Value >>= nY;
+ executeDispatch_LOKSetTextSelection(nType, nX, nY);
+ }
+ }
+ else if (aCommand == "LOKTransform")
+ {
+ if (rArgs[0].Name == "Action")
+ {
+ OUString sAction;
+ if ((rArgs[0].Value >>= sAction) && sAction == "PieSegmentDragging")
+ {
+ if (rArgs[1].Name == "Offset")
+ {
+ sal_Int32 nOffset;
+ if (rArgs[1].Value >>= nOffset)
+ {
+ this->executeDispatch_LOKPieSegmentDragging(nOffset);
+ }
+ }
+ }
+ }
+ else
+ {
+ this->executeDispatch_PositionAndSize(&rArgs);
+ }
+ }
+ else if(aCommand == "FillColor")
+ {
+ if (rArgs.getLength() > 0)
+ {
+ sal_uInt32 nColor;
+ if (rArgs[0].Value >>= nColor)
+ this->executeDispatch_FillColor(nColor);
+ }
+ }
+ else if(aCommand == "XLineColor")
+ {
+ if (rArgs.getLength() > 0)
+ {
+ sal_Int32 nColor = -1;
+ rArgs[0].Value >>= nColor;
+ this->executeDispatch_LineColor(nColor);
+ }
+ }
+ else if(aCommand == "LineWidth")
+ {
+ if (rArgs.getLength() > 0)
+ {
+ sal_Int32 nWidth = -1;
+ rArgs[0].Value >>= nWidth;
+ this->executeDispatch_LineWidth(nWidth);
+ }
+ }
+ else if(aCommand.startsWith("FillGradient"))
+ {
+ this->executeDispatch_FillGradient(aCommand.subView(aCommand.indexOf('=') + 1));
+ }
+ else if(aCommand == "Paste")
+ this->executeDispatch_Paste();
+ else if(aCommand == "Copy" )
+ this->executeDispatch_Copy();
+ else if(aCommand == "Cut" )
+ this->executeDispatch_Cut();
+ else if(aCommand == "DataRanges" )
+ this->executeDispatch_SourceData();
+ else if(aCommand == "Update" ) //Update Chart
+ {
+ ChartViewHelper::setViewToDirtyState( getChartModel() );
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+ if( pChartWindow )
+ pChartWindow->Invalidate();
+ }
+ else if(aCommand == "DiagramData" )
+ this->executeDispatch_EditData();
+ //insert objects
+ else if( aCommand == "InsertTitles"
+ || aCommand == "InsertMenuTitles")
+ this->executeDispatch_InsertTitles();
+ else if( aCommand == "InsertMenuLegend" )
+ this->executeDispatch_OpenLegendDialog();
+ else if( aCommand == "InsertLegend" )
+ this->executeDispatch_InsertLegend();
+ else if( aCommand == "DeleteLegend" )
+ this->executeDispatch_DeleteLegend();
+ else if( aCommand == "InsertMenuDataLabels" )
+ this->executeDispatch_InsertMenu_DataLabels();
+ else if( aCommand == "InsertMenuAxes"
+ || aCommand == "InsertRemoveAxes" )
+ this->executeDispatch_InsertAxes();
+ else if( aCommand == "InsertMenuGrids" )
+ this->executeDispatch_InsertGrid();
+ else if( aCommand == "InsertMenuTrendlines" )
+ this->executeDispatch_InsertMenu_Trendlines();
+ else if( aCommand == "InsertMenuMeanValues" )
+ this->executeDispatch_InsertMenu_MeanValues();
+ else if( aCommand == "InsertMenuXErrorBars" )
+ this->executeDispatch_InsertErrorBars(false);
+ else if( aCommand == "InsertMenuYErrorBars" )
+ this->executeDispatch_InsertErrorBars(true);
+ else if( aCommand == "InsertMenuDataTable" )
+ this->executeDispatch_OpenInsertDataTableDialog();
+ else if( aCommand == "InsertSymbol" )
+ this->executeDispatch_InsertSpecialCharacter();
+ else if( aCommand == "InsertTrendline" )
+ this->executeDispatch_InsertTrendline();
+ else if( aCommand == "DeleteTrendline" )
+ this->executeDispatch_DeleteTrendline();
+ else if( aCommand == "InsertMeanValue" )
+ this->executeDispatch_InsertMeanValue();
+ else if( aCommand == "DeleteMeanValue" )
+ this->executeDispatch_DeleteMeanValue();
+ else if( aCommand == "InsertXErrorBars" )
+ this->executeDispatch_InsertErrorBars(false);
+ else if( aCommand == "InsertYErrorBars" )
+ this->executeDispatch_InsertErrorBars(true);
+ else if( aCommand == "DeleteXErrorBars" )
+ this->executeDispatch_DeleteErrorBars(false);
+ else if( aCommand == "DeleteYErrorBars" )
+ this->executeDispatch_DeleteErrorBars(true);
+ else if( aCommand == "InsertTrendlineEquation" )
+ this->executeDispatch_InsertTrendlineEquation();
+ else if( aCommand == "DeleteTrendlineEquation" )
+ this->executeDispatch_DeleteTrendlineEquation();
+ else if( aCommand == "InsertTrendlineEquationAndR2" )
+ this->executeDispatch_InsertTrendlineEquation( true );
+ else if( aCommand == "InsertR2Value" )
+ this->executeDispatch_InsertR2Value();
+ else if( aCommand == "DeleteR2Value")
+ this->executeDispatch_DeleteR2Value();
+ else if( aCommand == "InsertDataLabels" )
+ this->executeDispatch_InsertDataLabels();
+ else if( aCommand == "InsertDataLabel" )
+ this->executeDispatch_InsertDataLabel();
+ else if( aCommand == "DeleteDataLabels")
+ this->executeDispatch_DeleteDataLabels();
+ else if( aCommand == "DeleteDataLabel" )
+ this->executeDispatch_DeleteDataLabel();
+ else if( aCommand == "ResetAllDataPoints" )
+ this->executeDispatch_ResetAllDataPoints();
+ else if( aCommand == "ResetDataPoint" )
+ this->executeDispatch_ResetDataPoint();
+ else if( aCommand == "InsertAxis" )
+ this->executeDispatch_InsertAxis();
+ else if( aCommand == "InsertMajorGrid" )
+ this->executeDispatch_InsertMajorGrid();
+ else if( aCommand == "InsertMinorGrid" )
+ this->executeDispatch_InsertMinorGrid();
+ else if( aCommand == "InsertAxisTitle" )
+ this->executeDispatch_InsertAxisTitle();
+ else if( aCommand == "DeleteAxis" )
+ this->executeDispatch_DeleteAxis();
+ else if( aCommand == "DeleteMajorGrid")
+ this->executeDispatch_DeleteMajorGrid();
+ else if( aCommand == "DeleteMinorGrid" )
+ this->executeDispatch_DeleteMinorGrid();
+ else if( aCommand == "InsertDataTable" )
+ this->executeDispatch_InsertDataTable();
+ else if( aCommand == "DeleteDataTable" )
+ this->executeDispatch_DeleteDataTable();
+ //format objects
+ else if( aCommand == "FormatSelection" )
+ this->executeDispatch_ObjectProperties();
+ else if( aCommand == "TransformDialog" )
+ {
+ if ( isShapeContext() )
+ {
+ this->impl_ShapeControllerDispatch( rURL, rArgs );
+ }
+ else
+ {
+ this->executeDispatch_PositionAndSize();
+ }
+ }
+ else if( lcl_isFormatObjectCommand(aCommand) )
+ this->executeDispatch_FormatObject(rURL.Path);
+ //more format
+ else if( aCommand == "DiagramType" )
+ this->executeDispatch_ChartType();
+ else if( aCommand == "View3D" )
+ this->executeDispatch_View3D();
+ else if ( aCommand == "Forward" )
+ {
+ if ( isShapeContext() )
+ {
+ this->impl_ShapeControllerDispatch( rURL, rArgs );
+ }
+ else
+ {
+ this->executeDispatch_MoveSeries( true );
+ }
+ }
+ else if ( aCommand == "Backward" )
+ {
+ if ( isShapeContext() )
+ {
+ this->impl_ShapeControllerDispatch( rURL, rArgs );
+ }
+ else
+ {
+ this->executeDispatch_MoveSeries( false );
+ }
+ }
+ else if( aCommand == "NewArrangement")
+ this->executeDispatch_NewArrangement();
+ else if( aCommand == "ToggleLegend" )
+ this->executeDispatch_ToggleLegend();
+ else if( aCommand == "ToggleGridHorizontal" )
+ this->executeDispatch_ToggleGridHorizontal();
+ else if( aCommand == "ToggleGridVertical" )
+ this->executeDispatch_ToggleGridVertical();
+ else if( aCommand == "ScaleText" )
+ this->executeDispatch_ScaleText();
+ else if( aCommand == "StatusBarVisible" )
+ {
+ // workaround: this should not be necessary.
+ uno::Reference< beans::XPropertySet > xPropSet( m_xFrame, uno::UNO_QUERY );
+ if( xPropSet.is() )
+ {
+ uno::Reference< css::frame::XLayoutManager > xLayoutManager;
+ xPropSet->getPropertyValue( "LayoutManager" ) >>= xLayoutManager;
+ if ( xLayoutManager.is() )
+ {
+ bool bIsVisible( xLayoutManager->isElementVisible( "private:resource/statusbar/statusbar" ));
+ if( bIsVisible )
+ {
+ xLayoutManager->hideElement( "private:resource/statusbar/statusbar" );
+ xLayoutManager->destroyElement( "private:resource/statusbar/statusbar" );
+ }
+ else
+ {
+ xLayoutManager->createElement( "private:resource/statusbar/statusbar" );
+ xLayoutManager->showElement( "private:resource/statusbar/statusbar" );
+ }
+ // @todo: update menu state (checkmark next to "Statusbar").
+ }
+ }
+ }
+}
+
+void SAL_CALL ChartController::addStatusListener(
+ const uno::Reference<frame::XStatusListener >& /* xControl */,
+ const util::URL& /* aURL */ )
+{
+ //@todo
+}
+
+void SAL_CALL ChartController::removeStatusListener(
+ const uno::Reference<frame::XStatusListener >& /* xControl */,
+ const util::URL& /* aURL */ )
+{
+ //@todo
+}
+
+// XContextMenuInterception (optional interface)
+void SAL_CALL ChartController::registerContextMenuInterceptor(
+ const uno::Reference< ui::XContextMenuInterceptor >& /* xInterceptor */)
+{
+ //@todo
+}
+
+void SAL_CALL ChartController::releaseContextMenuInterceptor(
+ const uno::Reference< ui::XContextMenuInterceptor > & /* xInterceptor */)
+{
+ //@todo
+}
+
+// ____ XEmbeddedClient ____
+// implementation see: ChartController_EditData.cxx
+
+void ChartController::executeDispatch_ChartType()
+{
+ UndoLiveUpdateGuard aUndoGuard(
+ SchResId( STR_ACTION_EDIT_CHARTTYPE ), m_xUndoManager );
+
+ SolarMutexGuard aSolarGuard;
+ //prepare and open dialog
+ ChartTypeDialog aDlg(GetChartFrame(), getChartModel());
+ if (aDlg.run() == RET_OK)
+ {
+ impl_adaptDataSeriesAutoResize();
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_SourceData()
+{
+ //convert properties to ItemSet
+ rtl::Reference< ::chart::ChartModel > xChartDoc = getChartModel();
+ OSL_ENSURE( xChartDoc.is(), "Invalid XChartDocument" );
+ if( !xChartDoc.is() )
+ return;
+
+ // If there is a data table we should ask user if we really want to destroy it
+ // and switch to data ranges.
+ ChartModel& rModel = *xChartDoc;
+ if ( rModel.hasInternalDataProvider() )
+ {
+ // Check if we will able to create data provider later
+ css::uno::Reference< com::sun::star::chart2::XDataProviderAccess > xCreatorDoc(
+ rModel.getParent(), uno::UNO_QUERY);
+ if (!xCreatorDoc.is())
+ return;
+
+ SolarMutexGuard aSolarGuard;
+
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetChartFrame(),
+ VclMessageType::Question, VclButtonsType::YesNo, SchResId(STR_DLG_REMOVE_DATA_TABLE)));
+ // If "No" then just return
+ if (xQueryBox->run() == RET_NO)
+ return;
+
+ // Remove data table
+ rModel.removeDataProviders();
+
+ // Ask parent document to create new data provider
+
+ uno::Reference< data::XDataProvider > xDataProvider = xCreatorDoc->createDataProvider();
+ SAL_WARN_IF( !xDataProvider.is(), "chart2.main", "Data provider was not created" );
+ if (xDataProvider.is())
+ {
+ rModel.attachDataProvider(xDataProvider);
+ }
+ }
+
+ UndoLiveUpdateGuard aUndoGuard(
+ SchResId(STR_ACTION_EDIT_DATA_RANGES), m_xUndoManager);
+
+ SolarMutexGuard aSolarGuard;
+ ::chart::DataSourceDialog aDlg(GetChartFrame(), xChartDoc);
+ if (aDlg.run() == RET_OK)
+ {
+ impl_adaptDataSeriesAutoResize();
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_MoveSeries( bool bForward )
+{
+ ControllerLockGuardUNO aCLGuard( getChartModel() );
+
+ //get selected series
+ OUString aObjectCID(m_aSelection.getSelectedCID());
+ rtl::Reference< DataSeries > xGivenDataSeries = ObjectIdentifier::getDataSeriesForCID( //yyy todo also legend entries and labels?
+ aObjectCID, getChartModel() );
+
+ UndoGuardWithSelection aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ (bForward ? ActionDescriptionProvider::ActionType::MoveToTop : ActionDescriptionProvider::ActionType::MoveToBottom),
+ SchResId(STR_OBJECT_DATASERIES)),
+ m_xUndoManager );
+
+ bool bChanged = getFirstDiagram()->moveSeries( xGivenDataSeries, bForward );
+ if( bChanged )
+ {
+ m_aSelection.setSelection( ObjectIdentifier::getMovedSeriesCID( aObjectCID, bForward ) );
+ aUndoGuard.commit();
+ }
+}
+
+// ____ XModifyListener ____
+void SAL_CALL ChartController::modified(
+ const lang::EventObject& /* aEvent */ )
+{
+ // the source can also be a subobject of the ChartModel
+ // @todo: change the source in ChartModel to always be the model itself ?
+ //todo? update menu states ?
+}
+
+void ChartController::NotifyUndoActionHdl( std::unique_ptr<SdrUndoAction> pUndoAction )
+{
+ ENSURE_OR_RETURN_VOID( pUndoAction, "invalid Undo action" );
+
+ OUString aObjectCID = m_aSelection.getSelectedCID();
+ if ( !aObjectCID.isEmpty() )
+ return;
+
+ try
+ {
+ rtl::Reference< ChartModel > xSuppUndo = getChartModel();
+ const Reference< document::XUndoManager > xUndoManager( xSuppUndo->getUndoManager(), uno::UNO_SET_THROW );
+ const Reference< document::XUndoAction > xAction( new impl::ShapeUndoElement( std::move(pUndoAction) ) );
+ xUndoManager->addUndoAction( xAction );
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+}
+
+DrawModelWrapper* ChartController::GetDrawModelWrapper()
+{
+ if( !m_pDrawModelWrapper )
+ {
+ if( m_xChartView )
+ m_pDrawModelWrapper = m_xChartView->getDrawModelWrapper();
+ if ( m_pDrawModelWrapper )
+ {
+ m_pDrawModelWrapper->getSdrModel().SetNotifyUndoActionHdl(
+ std::bind(&ChartController::NotifyUndoActionHdl, this, std::placeholders::_1) );
+ }
+ }
+ return m_pDrawModelWrapper.get();
+}
+
+DrawViewWrapper* ChartController::GetDrawViewWrapper()
+{
+ if ( !m_pDrawViewWrapper )
+ {
+ impl_createDrawViewController();
+ }
+ return m_pDrawViewWrapper.get();
+}
+
+
+ChartWindow* ChartController::GetChartWindow() const
+{
+ // clients getting the naked VCL Window from UNO should always have the
+ // solar mutex (and keep it over the lifetime of this ptr), as VCL might
+ // might deinit otherwise
+ DBG_TESTSOLARMUTEX();
+ if(!m_xViewWindow.is())
+ return nullptr;
+ return dynamic_cast<ChartWindow*>(VCLUnoHelper::GetWindow(m_xViewWindow));
+}
+
+weld::Window* ChartController::GetChartFrame()
+{
+ // clients getting the naked VCL Window from UNO should always have the
+ // solar mutex (and keep it over the lifetime of this ptr), as VCL might
+ // might deinit otherwise
+ DBG_TESTSOLARMUTEX();
+ return Application::GetFrameWeld(m_xViewWindow);
+}
+
+bool ChartController::isAdditionalShapeSelected() const
+{
+ return m_aSelection.isAdditionalShapeSelected();
+}
+
+void ChartController::SetAndApplySelection(const Reference<drawing::XShape>& rxShape)
+{
+ if(rxShape.is())
+ {
+ m_aSelection.setSelection(rxShape);
+ m_aSelection.applySelection(GetDrawViewWrapper());
+ }
+}
+
+
+
+uno::Reference< XAccessible > ChartController::CreateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ rtl::Reference< AccessibleChartView > xResult = new AccessibleChartView( GetDrawViewWrapper() );
+ impl_initializeAccessible( *xResult );
+ return xResult;
+#else
+ return uno::Reference< XAccessible >();
+#endif
+}
+
+void ChartController::impl_invalidateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+ if( pChartWindow )
+ {
+ Reference< XInterface > xInit( pChartWindow->GetAccessible(false) );
+ if(xInit.is())
+ {
+ //empty arguments -> invalid accessible
+ dynamic_cast<AccessibleChartView&>(*xInit).initialize();
+ }
+ }
+#endif
+}
+void ChartController::impl_initializeAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+ if( !pChartWindow )
+ return;
+ Reference< XInterface > xInit( pChartWindow->GetAccessible(false) );
+ if(xInit.is())
+ impl_initializeAccessible( dynamic_cast<AccessibleChartView&>(*xInit) );
+#endif
+}
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+void ChartController::impl_initializeAccessible( AccessibleChartView& rAccChartView )
+{
+ uno::Reference< XAccessible > xParent;
+ {
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+ if( pChartWindow )
+ {
+ vcl::Window* pParentWin( pChartWindow->GetAccessibleParentWindow());
+ if( pParentWin )
+ xParent.set( pParentWin->GetAccessible());
+ }
+ }
+
+ rAccChartView.initialize(*this, getChartModel(), m_xChartView, xParent, m_xViewWindow);
+}
+#else
+void ChartController::impl_initializeAccessible( AccessibleChartView& /* rAccChartView */) {}
+#endif
+
+const o3tl::sorted_vector< OUString >& ChartController::impl_getAvailableCommands()
+{
+ static const o3tl::sorted_vector< OUString > s_AvailableCommands {
+ // commands for container forward
+ "AddDirect", "NewDoc", "Open",
+ "Save", "SaveAs", "SendMail",
+ "EditDoc", "ExportDirectToPDF", "PrintDefault",
+
+ // own commands
+ "Cut", "Copy", "Paste",
+ "DataRanges", "DiagramData",
+ // insert objects
+ "InsertMenuTitles", "InsertTitles",
+ "InsertMenuLegend", "InsertLegend", "DeleteLegend",
+ "InsertMenuDataLabels",
+ "InsertMenuAxes", "InsertRemoveAxes", "InsertMenuGrids",
+ "InsertSymbol",
+ "InsertTrendlineEquation", "InsertTrendlineEquationAndR2",
+ "InsertR2Value", "DeleteR2Value",
+ "InsertMenuTrendlines", "InsertTrendline",
+ "InsertMenuMeanValues", "InsertMeanValue",
+ "InsertMenuXErrorBars", "InsertXErrorBars",
+ "InsertMenuYErrorBars", "InsertYErrorBars",
+ "InsertDataLabels", "InsertDataLabel",
+ "DeleteTrendline", "DeleteMeanValue", "DeleteTrendlineEquation",
+ "DeleteXErrorBars", "DeleteYErrorBars",
+ "DeleteDataLabels", "DeleteDataLabel",
+ "InsertMenuDataTable",
+ "InsertDataTable", "DeleteDataTable",
+ //format objects
+ "FormatSelection", "TransformDialog",
+ "DiagramType", "View3D",
+ "Forward", "Backward",
+ "MainTitle", "SubTitle",
+ "XTitle", "YTitle", "ZTitle",
+ "SecondaryXTitle", "SecondaryYTitle",
+ "AllTitles", "Legend",
+ "DiagramAxisX", "DiagramAxisY", "DiagramAxisZ",
+ "DiagramAxisA", "DiagramAxisB", "DiagramAxisAll",
+ "DiagramGridXMain", "DiagramGridYMain", "DiagramGridZMain",
+ "DiagramGridXHelp", "DiagramGridYHelp", "DiagramGridZHelp",
+ "DiagramGridAll",
+ "DiagramWall", "DiagramFloor", "DiagramArea",
+
+ //context menu - format objects entries
+ "FormatWall", "FormatFloor", "FormatChartArea",
+ "FormatLegend",
+
+ "FormatAxis", "FormatTitle",
+ "FormatDataSeries", "FormatDataPoint",
+ "ResetAllDataPoints", "ResetDataPoint",
+ "FormatDataLabels", "FormatDataLabel",
+ "FormatMeanValue", "FormatTrendline", "FormatTrendlineEquation",
+ "FormatXErrorBars", "FormatYErrorBars",
+ "FormatStockLoss", "FormatStockGain",
+
+ "FormatMajorGrid", "InsertMajorGrid", "DeleteMajorGrid",
+ "FormatMinorGrid", "InsertMinorGrid", "DeleteMinorGrid",
+ "InsertAxis", "DeleteAxis", "InsertAxisTitle",
+
+ // toolbar commands
+ "ToggleGridHorizontal", "ToggleGridVertical", "ToggleLegend", "ScaleText",
+ "NewArrangement", "Update",
+ "DefaultColors", "BarWidth", "NumberOfLines",
+ "ArrangeRow",
+ "StatusBarVisible",
+ "ChartElementSelector"};
+ return s_AvailableCommands;
+}
+
+ViewElementListProvider ChartController::getViewElementListProvider()
+{
+ return ViewElementListProvider(m_pDrawModelWrapper.get());
+}
+
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartController_EditData.cxx b/chart2/source/controller/main/ChartController_EditData.cxx
new file mode 100644
index 0000000000..63577edf39
--- /dev/null
+++ b/chart2/source/controller/main/ChartController_EditData.cxx
@@ -0,0 +1,52 @@
+/* -*- 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 <ChartController.hxx>
+#include <ChartModel.hxx>
+
+#include <dlg_DataEditor.hxx>
+#include "UndoGuard.hxx"
+#include <ResId.hxx>
+#include <strings.hrc>
+
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+
+namespace chart
+{
+
+void ChartController::executeDispatch_EditData()
+{
+ rtl::Reference<::chart::ChartModel> xChartDoc( getChartModel(), uno::UNO_QUERY );
+ if (xChartDoc.is())
+ {
+ SolarMutexGuard aSolarGuard;
+ UndoLiveUpdateGuardWithData aUndoGuard(
+ SchResId( STR_ACTION_EDIT_CHART_DATA ),
+ m_xUndoManager );
+ DataEditor aDataEditorDialog(GetChartFrame(), xChartDoc, m_xCC);
+ aDataEditorDialog.run();
+ aUndoGuard.commit();
+ }
+}
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartController_Insert.cxx b/chart2/source/controller/main/ChartController_Insert.cxx
new file mode 100644
index 0000000000..60b059ceff
--- /dev/null
+++ b/chart2/source/controller/main/ChartController_Insert.cxx
@@ -0,0 +1,987 @@
+/* -*- 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 <memory>
+#include <ChartController.hxx>
+#include <ChartView.hxx>
+
+#include <dlg_InsertAxis_Grid.hxx>
+#include <dlg_InsertDataLabel.hxx>
+#include <dlg_InsertLegend.hxx>
+#include <dlg_InsertErrorBars.hxx>
+#include <dlg_InsertTitle.hxx>
+#include <dlg_InsertDataTable.hxx>
+#include <dlg_ObjectProperties.hxx>
+
+#include <Axis.hxx>
+#include <AxisHelper.hxx>
+#include <TitleHelper.hxx>
+#include <DataSeries.hxx>
+#include <DiagramHelper.hxx>
+#include <Diagram.hxx>
+#include <GridProperties.hxx>
+#include <chartview/DrawModelWrapper.hxx>
+#include <chartview/ChartSfxItemIds.hxx>
+#include <NumberFormatterWrapper.hxx>
+#include <ViewElementListProvider.hxx>
+#include <MultipleChartConverters.hxx>
+#include <ControllerLockGuard.hxx>
+#include "UndoGuard.hxx"
+#include <ResId.hxx>
+#include <strings.hrc>
+#include <ReferenceSizeProvider.hxx>
+#include <ObjectIdentifier.hxx>
+#include <RegressionCurveHelper.hxx>
+#include <RegressionCurveItemConverter.hxx>
+#include <StatisticsHelper.hxx>
+#include <ErrorBarItemConverter.hxx>
+#include <DataSeriesHelper.hxx>
+#include <ObjectNameProvider.hxx>
+#include <Legend.hxx>
+#include <LegendHelper.hxx>
+#include <DataTable.hxx>
+#include <RegressionCurveModel.hxx>
+
+#include <com/sun/star/chart2/XRegressionCurve.hpp>
+#include <com/sun/star/chart/ErrorBarStyle.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <svx/ActionDescriptionProvider.hxx>
+
+#include <comphelper/diagnose_ex.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::chart2;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace
+{
+
+void lcl_InsertMeanValueLine( const rtl::Reference< ::chart::DataSeries > & xSeries )
+{
+ if( xSeries.is())
+ {
+ ::chart::RegressionCurveHelper::addMeanValueLine(
+ xSeries, xSeries);
+ }
+}
+
+} // anonymous namespace
+
+namespace chart
+{
+
+void ChartController::executeDispatch_InsertAxes()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_AXES )),
+ m_xUndoManager );
+
+ try
+ {
+ InsertAxisOrGridDialogData aDialogInput;
+ rtl::Reference< Diagram > xDiagram = getFirstDiagram();
+ AxisHelper::getAxisOrGridExistence( aDialogInput.aExistenceList, xDiagram );
+ AxisHelper::getAxisOrGridPossibilities( aDialogInput.aPossibilityList, xDiagram );
+
+ SolarMutexGuard aGuard;
+ SchAxisDlg aDlg(GetChartFrame(), aDialogInput);
+ if (aDlg.run() == RET_OK)
+ {
+ // lock controllers till end of block
+ ControllerLockGuardUNO aCLGuard( getChartModel() );
+
+ InsertAxisOrGridDialogData aDialogOutput;
+ aDlg.getResult(aDialogOutput);
+ std::unique_ptr< ReferenceSizeProvider > pRefSizeProvider(
+ impl_createReferenceSizeProvider());
+ bool bChanged = AxisHelper::changeVisibilityOfAxes( xDiagram
+ , aDialogInput.aExistenceList, aDialogOutput.aExistenceList, m_xCC
+ , pRefSizeProvider.get() );
+ if( bChanged )
+ aUndoGuard.commit();
+ }
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+void ChartController::executeDispatch_InsertGrid()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_GRIDS )),
+ m_xUndoManager );
+
+ try
+ {
+ InsertAxisOrGridDialogData aDialogInput;
+ rtl::Reference< Diagram > xDiagram = getFirstDiagram();
+ AxisHelper::getAxisOrGridExistence( aDialogInput.aExistenceList, xDiagram, false );
+ AxisHelper::getAxisOrGridPossibilities( aDialogInput.aPossibilityList, xDiagram, false );
+
+ SolarMutexGuard aGuard;
+ SchGridDlg aDlg(GetChartFrame(), aDialogInput);//aItemSet, b3D, bNet, bSecondaryX, bSecondaryY );
+ if (aDlg.run() == RET_OK)
+ {
+ // lock controllers till end of block
+ ControllerLockGuardUNO aCLGuard( getChartModel() );
+ InsertAxisOrGridDialogData aDialogOutput;
+ aDlg.getResult( aDialogOutput );
+ bool bChanged = AxisHelper::changeVisibilityOfGrids( xDiagram
+ , aDialogInput.aExistenceList, aDialogOutput.aExistenceList );
+ if( bChanged )
+ aUndoGuard.commit();
+ }
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+void ChartController::executeDispatch_OpenInsertDataTableDialog()
+{
+ SolarMutexGuard aGuard;
+
+ auto aUndoDescription = ActionDescriptionProvider::createDescription(ActionDescriptionProvider::ActionType::Insert, SchResId(STR_DATA_TABLE));
+ UndoGuard aUndoGuard(aUndoDescription, m_xUndoManager);
+
+ rtl::Reference<Diagram> xDiagram = getFirstDiagram();
+
+ InsertDataTableDialog aDialog(GetChartFrame());
+ {
+ // init values
+ DataTableDialogData aData;
+ auto xDataTable = xDiagram->getDataTable();
+ aData.mbShow = xDataTable.is();
+ if (xDataTable.is())
+ {
+ uno::Reference<beans::XPropertySet> xProperties(xDataTable, uno::UNO_QUERY);
+
+ uno::Any aAny = xProperties->getPropertyValue("HBorder");
+ if (aAny.has<bool>())
+ aData.mbHorizontalBorders = aAny.get<bool>();
+
+ aAny = xProperties->getPropertyValue("VBorder");
+ if (aAny.has<bool>())
+ aData.mbVerticalBorders = aAny.get<bool>();
+
+ aAny = xProperties->getPropertyValue("Outline");
+ if (aAny.has<bool>())
+ aData.mbOutline = aAny.get<bool>();
+
+ aAny = xProperties->getPropertyValue("Keys");
+ if (aAny.has<bool>())
+ aData.mbKeys = aAny.get<bool>();
+ }
+ aDialog.init(aData);
+ }
+
+ // show the dialog
+ if (aDialog.run() == RET_OK)
+ {
+ bool bChanged = false;
+
+ auto& rDialogData = aDialog.getDataTableDialogData();
+ auto xDataTable = xDiagram->getDataTable();
+ if (!rDialogData.mbShow && xDataTable.is())
+ {
+ xDiagram->setDataTable(uno::Reference<chart2::XDataTable>());
+ bChanged = true;
+ }
+ else if (rDialogData.mbShow && !xDataTable.is())
+ {
+ uno::Reference<chart2::XDataTable> xNewDataTable(new DataTable);
+ if (xNewDataTable.is())
+ {
+ xDiagram->setDataTable(xNewDataTable);
+ bChanged = true;
+ }
+ }
+
+ // Set the properties
+ xDataTable = xDiagram->getDataTable();
+ if (rDialogData.mbShow && xDataTable.is())
+ {
+ uno::Reference<beans::XPropertySet> xProperties(xDataTable, uno::UNO_QUERY);
+ xProperties->setPropertyValue("HBorder" , uno::Any(rDialogData.mbHorizontalBorders));
+ xProperties->setPropertyValue("VBorder" , uno::Any(rDialogData.mbVerticalBorders));
+ xProperties->setPropertyValue("Outline" , uno::Any(rDialogData.mbOutline));
+ xProperties->setPropertyValue("Keys" , uno::Any(rDialogData.mbKeys));
+ bChanged = true;
+ }
+
+ if (bChanged)
+ aUndoGuard.commit();
+ }
+}
+
+/** Create and insert a data table to the chart */
+void ChartController::executeDispatch_InsertDataTable()
+{
+ auto aUndoDescription = ActionDescriptionProvider::createDescription(ActionDescriptionProvider::ActionType::Insert, SchResId(STR_DATA_TABLE));
+ UndoGuard aUndoGuard(aUndoDescription, m_xUndoManager);
+
+
+ rtl::Reference<Diagram> xDiagram = getFirstDiagram();
+ auto xDataTable = xDiagram->getDataTable();
+ if (!xDataTable.is())
+ {
+ uno::Reference<chart2::XDataTable> xNewDataTable(new DataTable);
+ if (xNewDataTable.is())
+ {
+ xDiagram->setDataTable(xNewDataTable);
+ aUndoGuard.commit();
+ }
+ }
+}
+
+/** Delete a data table from the chart */
+void ChartController::executeDispatch_DeleteDataTable()
+{
+ auto aUndoDescription = ActionDescriptionProvider::createDescription(ActionDescriptionProvider::ActionType::Delete, SchResId(STR_DATA_TABLE));
+ UndoGuard aUndoGuard(aUndoDescription, m_xUndoManager);
+
+ rtl::Reference<Diagram> xDiagram = getFirstDiagram();
+ auto xDataTable = xDiagram->getDataTable();
+ if (xDataTable.is())
+ {
+ // insert a empty data table reference
+ xDiagram->setDataTable(uno::Reference<chart2::XDataTable>());
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_InsertTitles()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_TITLES )),
+ m_xUndoManager );
+
+ try
+ {
+ TitleDialogData aDialogInput;
+ aDialogInput.readFromModel( getChartModel() );
+
+ SolarMutexGuard aGuard;
+ SchTitleDlg aDlg(GetChartFrame(), aDialogInput);
+ if (aDlg.run() == RET_OK)
+ {
+ // lock controllers till end of block
+ ControllerLockGuardUNO aCLGuard( getChartModel() );
+ TitleDialogData aDialogOutput(impl_createReferenceSizeProvider());
+ aDlg.getResult(aDialogOutput);
+ bool bChanged = aDialogOutput.writeDifferenceToModel( getChartModel(), m_xCC, &aDialogInput );
+ if( bChanged )
+ aUndoGuard.commit();
+ }
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+void ChartController::executeDispatch_DeleteLegend()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_LEGEND )),
+ m_xUndoManager );
+
+ LegendHelper::hideLegend(*getChartModel());
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_InsertLegend()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_LEGEND )),
+ m_xUndoManager );
+
+ LegendHelper::showLegend(*getChartModel(), m_xCC);
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_OpenLegendDialog()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_LEGEND )),
+ m_xUndoManager );
+
+ try
+ {
+ //prepare and open dialog
+ SolarMutexGuard aGuard;
+ SchLegendDlg aDlg(GetChartFrame(), m_xCC);
+ aDlg.init( getChartModel() );
+ if (aDlg.run() == RET_OK)
+ {
+ // lock controllers till end of block
+ ControllerLockGuardUNO aCLGuard( getChartModel() );
+ aDlg.writeToModel( getChartModel() );
+ aUndoGuard.commit();
+ }
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+void ChartController::executeDispatch_InsertMenu_DataLabels()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_DATALABELS )),
+ m_xUndoManager );
+
+ //if a series is selected insert labels for that series only:
+ rtl::Reference< DataSeries > xSeries =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel());
+ if( xSeries.is() )
+ {
+ // add labels
+ DataSeriesHelper::insertDataLabelsToSeriesAndAllPoints( xSeries );
+
+ OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) + "=" );
+ OUString aObjectCID = ObjectIdentifier::createClassifiedIdentifierForParticles(
+ ObjectIdentifier::getSeriesParticleFromCID(m_aSelection.getSelectedCID()), aChildParticle );
+
+ bool bSuccess = ChartController::executeDlg_ObjectProperties_withoutUndoGuard( aObjectCID, true );
+ if( bSuccess )
+ aUndoGuard.commit();
+ return;
+ }
+
+ try
+ {
+ wrapper::AllDataLabelItemConverter aItemConverter(
+ getChartModel(),
+ m_pDrawModelWrapper->GetItemPool(),
+ m_pDrawModelWrapper->getSdrModel(),
+ getChartModel() );
+ SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet();
+ aItemConverter.FillItemSet( aItemSet );
+
+ //prepare and open dialog
+ SolarMutexGuard aGuard;
+
+ //get number formatter
+ NumberFormatterWrapper aNumberFormatterWrapper( getChartModel() );
+ SvNumberFormatter* pNumberFormatter = aNumberFormatterWrapper.getSvNumberFormatter();
+
+ DataLabelsDialog aDlg(GetChartFrame(), aItemSet, pNumberFormatter);
+
+ if (aDlg.run() == RET_OK)
+ {
+ SfxItemSet aOutItemSet = aItemConverter.CreateEmptyItemSet();
+ aDlg.FillItemSet(aOutItemSet);
+ // lock controllers till end of block
+ ControllerLockGuardUNO aCLGuard( getChartModel() );
+ bool bChanged = aItemConverter.ApplyItemSet( aOutItemSet );//model should be changed now
+ if( bChanged )
+ aUndoGuard.commit();
+ }
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+void ChartController::executeDispatch_InsertMeanValue()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_AVERAGE_LINE )),
+ m_xUndoManager );
+ lcl_InsertMeanValueLine( ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(),
+ getChartModel() ) );
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_InsertMenu_MeanValues()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_AVERAGE_LINE )),
+ m_xUndoManager );
+
+ rtl::Reference< DataSeries > xSeries =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xSeries.is() )
+ {
+ //if a series is selected insert mean value only for that series:
+ lcl_InsertMeanValueLine( xSeries );
+ }
+ else if (rtl::Reference<Diagram> xDiagram = getFirstDiagram())
+ {
+ std::vector< rtl::Reference< DataSeries > > aSeries =
+ xDiagram->getDataSeries();
+
+ for( const auto& xSrs : aSeries )
+ lcl_InsertMeanValueLine( xSrs );
+ }
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_InsertMenu_Trendlines()
+{
+ OUString aCID = m_aSelection.getSelectedCID();
+
+ rtl::Reference< DataSeries > xSeries =
+ ObjectIdentifier::getDataSeriesForCID( aCID, getChartModel() );
+
+ if( !xSeries.is() )
+ return;
+
+ executeDispatch_InsertTrendline();
+}
+
+void ChartController::executeDispatch_InsertTrendline()
+{
+ rtl::Reference< DataSeries > xRegressionCurveContainer =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel());
+
+ if( !xRegressionCurveContainer.is() )
+ return;
+
+ UndoLiveUpdateGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_CURVE )),
+ m_xUndoManager );
+
+ rtl::Reference< RegressionCurveModel > xCurve =
+ RegressionCurveHelper::addRegressionCurve(
+ SvxChartRegress::Linear,
+ xRegressionCurveContainer );
+
+ if( !xCurve.is())
+ return;
+
+ wrapper::RegressionCurveItemConverter aItemConverter(
+ xCurve, xRegressionCurveContainer, m_pDrawModelWrapper->getSdrModel().GetItemPool(),
+ m_pDrawModelWrapper->getSdrModel(),
+ getChartModel() );
+
+ // open dialog
+ SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet();
+ aItemConverter.FillItemSet( aItemSet );
+ ObjectPropertiesDialogParameter aDialogParameter(
+ ObjectIdentifier::createDataCurveCID(
+ ObjectIdentifier::getSeriesParticleFromCID( m_aSelection.getSelectedCID()),
+ RegressionCurveHelper::getRegressionCurveIndex( xRegressionCurveContainer, xCurve ), false ));
+ aDialogParameter.init( getChartModel() );
+ ViewElementListProvider aViewElementListProvider( m_pDrawModelWrapper.get());
+ SolarMutexGuard aGuard;
+ SchAttribTabDlg aDialog(
+ GetChartFrame(), &aItemSet, &aDialogParameter,
+ &aViewElementListProvider,
+ getChartModel() );
+
+ // note: when a user pressed "OK" but didn't change any settings in the
+ // dialog, the SfxTabDialog returns "Cancel"
+ if( aDialog.run() == RET_OK || aDialog.DialogWasClosedWithOK())
+ {
+ const SfxItemSet* pOutItemSet = aDialog.GetOutputItemSet();
+ if( pOutItemSet )
+ {
+ ControllerLockGuardUNO aCLGuard( getChartModel() );
+ aItemConverter.ApplyItemSet( *pOutItemSet );
+ }
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_InsertErrorBars( bool bYError )
+{
+ ObjectType objType = bYError ? OBJECTTYPE_DATA_ERRORS_Y : OBJECTTYPE_DATA_ERRORS_X;
+
+ //if a series is selected insert error bars for that series only:
+ rtl::Reference< DataSeries > xSeries =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() );
+
+ if( xSeries.is())
+ {
+ UndoLiveUpdateGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert,
+ SchResId( bYError ? STR_OBJECT_ERROR_BARS_Y : STR_OBJECT_ERROR_BARS_X )),
+ m_xUndoManager );
+
+ // add error bars with standard deviation
+ uno::Reference< beans::XPropertySet > xErrorBarProp(
+ StatisticsHelper::addErrorBars( xSeries,
+ css::chart::ErrorBarStyle::STANDARD_DEVIATION,
+ bYError));
+
+ // get an appropriate item converter
+ wrapper::ErrorBarItemConverter aItemConverter(
+ getChartModel(), xErrorBarProp, m_pDrawModelWrapper->getSdrModel().GetItemPool(),
+ m_pDrawModelWrapper->getSdrModel(),
+ getChartModel() );
+
+ // open dialog
+ SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet();
+ aItemSet.Put(SfxBoolItem(SCHATTR_STAT_ERRORBAR_TYPE,bYError));
+ aItemConverter.FillItemSet( aItemSet );
+ ObjectPropertiesDialogParameter aDialogParameter(
+ ObjectIdentifier::createClassifiedIdentifierWithParent(
+ objType, u"", m_aSelection.getSelectedCID()));
+ aDialogParameter.init( getChartModel() );
+ ViewElementListProvider aViewElementListProvider( m_pDrawModelWrapper.get());
+ SolarMutexGuard aGuard;
+ SchAttribTabDlg aDlg(
+ GetChartFrame(), &aItemSet, &aDialogParameter,
+ &aViewElementListProvider,
+ getChartModel() );
+ aDlg.SetAxisMinorStepWidthForErrorBarDecimals(
+ InsertErrorBarsDialog::getAxisMinorStepWidthForErrorBarDecimals( getChartModel(),
+ m_xChartView, m_aSelection.getSelectedCID()));
+
+ // note: when a user pressed "OK" but didn't change any settings in the
+ // dialog, the SfxTabDialog returns "Cancel"
+ if (aDlg.run() == RET_OK || aDlg.DialogWasClosedWithOK())
+ {
+ const SfxItemSet* pOutItemSet = aDlg.GetOutputItemSet();
+ if( pOutItemSet )
+ {
+ ControllerLockGuardUNO aCLGuard( getChartModel() );
+ aItemConverter.ApplyItemSet( *pOutItemSet );
+ }
+ aUndoGuard.commit();
+ }
+ }
+ else
+ {
+ //if no series is selected insert error bars for all series
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert,
+ ObjectNameProvider::getName_ObjectForAllSeries( objType ) ),
+ m_xUndoManager );
+
+ try
+ {
+ wrapper::AllSeriesStatisticsConverter aItemConverter(
+ getChartModel(), m_pDrawModelWrapper->GetItemPool() );
+ SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet();
+ aItemConverter.FillItemSet( aItemSet );
+
+ //prepare and open dialog
+ SolarMutexGuard aGuard;
+ InsertErrorBarsDialog aDlg(
+ GetChartFrame(), aItemSet,
+ getChartModel(),
+ bYError ? ErrorBarResources::ERROR_BAR_Y : ErrorBarResources::ERROR_BAR_X);
+
+ aDlg.SetAxisMinorStepWidthForErrorBarDecimals(
+ InsertErrorBarsDialog::getAxisMinorStepWidthForErrorBarDecimals( getChartModel(), m_xChartView, u"" ) );
+
+ if (aDlg.run() == RET_OK)
+ {
+ SfxItemSet aOutItemSet = aItemConverter.CreateEmptyItemSet();
+ aDlg.FillItemSet( aOutItemSet );
+
+ // lock controllers till end of block
+ ControllerLockGuardUNO aCLGuard( getChartModel() );
+ bool bChanged = aItemConverter.ApplyItemSet( aOutItemSet );//model should be changed now
+ if( bChanged )
+ aUndoGuard.commit();
+ }
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+ }
+}
+
+void ChartController::executeDispatch_InsertTrendlineEquation( bool bInsertR2 )
+{
+ uno::Reference< chart2::XRegressionCurve > xRegCurve(
+ ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() ), uno::UNO_QUERY );
+ if( !xRegCurve.is() )
+ {
+ rtl::Reference< DataSeries > xRegCurveCnt =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ xRegCurve.set( RegressionCurveHelper::getFirstCurveNotMeanValueLine( xRegCurveCnt ) );
+ }
+ if( !xRegCurve.is())
+ return;
+
+ uno::Reference< beans::XPropertySet > xEqProp( xRegCurve->getEquationProperties());
+ if( xEqProp.is())
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_CURVE_EQUATION )),
+ m_xUndoManager );
+ xEqProp->setPropertyValue( "ShowEquation", uno::Any( true ));
+ xEqProp->setPropertyValue( "XName", uno::Any( OUString("x") ));
+ xEqProp->setPropertyValue( "YName", uno::Any( OUString("f(x)") ));
+ xEqProp->setPropertyValue( "ShowCorrelationCoefficient", uno::Any( bInsertR2 ));
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_InsertR2Value()
+{
+ uno::Reference< beans::XPropertySet > xEqProp =
+ ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xEqProp.is())
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_CURVE_EQUATION )),
+ m_xUndoManager );
+ xEqProp->setPropertyValue( "ShowCorrelationCoefficient", uno::Any( true ));
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_DeleteR2Value()
+{
+ uno::Reference< beans::XPropertySet > xEqProp =
+ ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xEqProp.is())
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_CURVE_EQUATION )),
+ m_xUndoManager );
+ xEqProp->setPropertyValue( "ShowCorrelationCoefficient", uno::Any( false ));
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_DeleteMeanValue()
+{
+ rtl::Reference< DataSeries > xRegCurveCnt =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xRegCurveCnt.is())
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_AVERAGE_LINE )),
+ m_xUndoManager );
+ RegressionCurveHelper::removeMeanValueLine( xRegCurveCnt );
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_DeleteTrendline()
+{
+ rtl::Reference< DataSeries > xRegCurveCnt =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xRegCurveCnt.is())
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE )),
+ m_xUndoManager );
+ RegressionCurveHelper::removeAllExceptMeanValueLine( xRegCurveCnt );
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_DeleteTrendlineEquation()
+{
+ rtl::Reference< DataSeries > xRegCurveCnt =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xRegCurveCnt.is())
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE_EQUATION )),
+ m_xUndoManager );
+ RegressionCurveHelper::removeEquations( xRegCurveCnt );
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_DeleteErrorBars( bool bYError )
+{
+ rtl::Reference< DataSeries > xDataSeries =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xDataSeries.is())
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE )),
+ m_xUndoManager );
+ StatisticsHelper::removeErrorBars( xDataSeries, bYError );
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_InsertDataLabels()
+{
+ rtl::Reference< DataSeries > xSeries =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xSeries.is() )
+ {
+ UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Insert,
+ SchResId( STR_OBJECT_DATALABELS )),
+ m_xUndoManager );
+ DataSeriesHelper::insertDataLabelsToSeriesAndAllPoints( xSeries );
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_InsertDataLabel()
+{
+ UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Insert,
+ SchResId( STR_OBJECT_LABEL )),
+ m_xUndoManager );
+ DataSeriesHelper::insertDataLabelToPoint( ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() ) );
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_DeleteDataLabels()
+{
+ rtl::Reference< DataSeries > xSeries =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xSeries.is() )
+ {
+ UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Delete,
+ SchResId( STR_OBJECT_DATALABELS )),
+ m_xUndoManager );
+ DataSeriesHelper::deleteDataLabelsFromSeriesAndAllPoints( xSeries );
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_DeleteDataLabel()
+{
+ UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Delete,
+ SchResId( STR_OBJECT_LABEL )),
+ m_xUndoManager );
+ DataSeriesHelper::deleteDataLabelsFromPoint( ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() ) );
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_ResetAllDataPoints()
+{
+ UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Format,
+ SchResId( STR_OBJECT_DATAPOINTS )),
+ m_xUndoManager );
+ rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xSeries.is() )
+ xSeries->resetAllDataPoints();
+ aUndoGuard.commit();
+}
+void ChartController::executeDispatch_ResetDataPoint()
+{
+ UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Format,
+ SchResId( STR_OBJECT_DATAPOINT )),
+ m_xUndoManager );
+ rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xSeries.is() )
+ {
+ sal_Int32 nPointIndex = ObjectIdentifier::getIndexFromParticleOrCID( m_aSelection.getSelectedCID() );
+ xSeries->resetDataPoint( nPointIndex );
+ }
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_InsertAxisTitle()
+{
+ try
+ {
+ rtl::Reference< Title > xTitle;
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_TITLE )),
+ m_xUndoManager );
+
+ rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ sal_Int32 nDimensionIndex = -1;
+ sal_Int32 nCooSysIndex = -1;
+ sal_Int32 nAxisIndex = -1;
+ AxisHelper::getIndicesForAxis( xAxis, getFirstDiagram(), nCooSysIndex, nDimensionIndex, nAxisIndex );
+
+ TitleHelper::eTitleType eTitleType = TitleHelper::X_AXIS_TITLE;
+ if( nDimensionIndex==0 )
+ eTitleType = nAxisIndex==0 ? TitleHelper::X_AXIS_TITLE : TitleHelper::SECONDARY_X_AXIS_TITLE;
+ else if( nDimensionIndex==1 )
+ eTitleType = nAxisIndex==0 ? TitleHelper::Y_AXIS_TITLE : TitleHelper::SECONDARY_Y_AXIS_TITLE;
+ else
+ eTitleType = TitleHelper::Z_AXIS_TITLE;
+
+ std::unique_ptr< ReferenceSizeProvider > apRefSizeProvider( impl_createReferenceSizeProvider());
+ xTitle = TitleHelper::createTitle( eTitleType, ObjectNameProvider::getTitleNameByType(eTitleType), getChartModel(), m_xCC, apRefSizeProvider.get() );
+ aUndoGuard.commit();
+ }
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+void ChartController::executeDispatch_InsertAxis()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_AXIS )),
+ m_xUndoManager );
+
+ try
+ {
+ rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xAxis.is() )
+ {
+ AxisHelper::makeAxisVisible( xAxis );
+ aUndoGuard.commit();
+ }
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+void ChartController::executeDispatch_DeleteAxis()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_AXIS )),
+ m_xUndoManager );
+
+ try
+ {
+ rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xAxis.is() )
+ {
+ AxisHelper::makeAxisInvisible( xAxis );
+ aUndoGuard.commit();
+ }
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+void ChartController::executeDispatch_InsertMajorGrid()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_GRID )),
+ m_xUndoManager );
+
+ try
+ {
+ rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xAxis.is() )
+ {
+ AxisHelper::makeGridVisible( xAxis->getGridProperties2() );
+ aUndoGuard.commit();
+ }
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+void ChartController::executeDispatch_DeleteMajorGrid()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_GRID )),
+ m_xUndoManager );
+
+ try
+ {
+ rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xAxis.is() )
+ {
+ AxisHelper::makeGridInvisible( xAxis->getGridProperties2() );
+ aUndoGuard.commit();
+ }
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+void ChartController::executeDispatch_InsertMinorGrid()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_GRID )),
+ m_xUndoManager );
+
+ try
+ {
+ rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xAxis.is() )
+ {
+ std::vector< rtl::Reference< ::chart::GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
+ for( rtl::Reference< GridProperties > const & props : aSubGrids)
+ AxisHelper::makeGridVisible( props );
+ aUndoGuard.commit();
+ }
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+void ChartController::executeDispatch_DeleteMinorGrid()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId(STR_OBJECT_GRID)),
+ m_xUndoManager );
+
+ try
+ {
+ rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xAxis.is() )
+ {
+ std::vector< rtl::Reference< ::chart::GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
+ for( rtl::Reference< ::chart::GridProperties > const & props : aSubGrids)
+ AxisHelper::makeGridInvisible( props );
+ aUndoGuard.commit();
+ }
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartController_Position.cxx b/chart2/source/controller/main/ChartController_Position.cxx
new file mode 100644
index 0000000000..9e7194eca8
--- /dev/null
+++ b/chart2/source/controller/main/ChartController_Position.cxx
@@ -0,0 +1,202 @@
+/* -*- 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 <ChartController.hxx>
+
+#include <DrawViewWrapper.hxx>
+#include <PositionAndSizeHelper.hxx>
+#include <ChartModel.hxx>
+#include <ChartModelHelper.hxx>
+#include <ChartView.hxx>
+#include "UndoGuard.hxx"
+#include <ObjectNameProvider.hxx>
+#include <DiagramHelper.hxx>
+#include <chartview/ExplicitValueProvider.hxx>
+#include <CommonConverters.hxx>
+#include <svx/ActionDescriptionProvider.hxx>
+
+#include <comphelper/servicehelper.hxx>
+#include <svx/svxids.hrc>
+#include <svx/rectenum.hxx>
+#include <svl/intitem.hxx>
+#include <svx/svxdlg.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <vcl/svapp.hxx>
+#include <memory>
+
+namespace chart
+{
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::chart2;
+
+static void lcl_getPositionAndSizeFromItemSet( const SfxItemSet& rItemSet, awt::Rectangle& rPosAndSize, const awt::Size& rOriginalSize )
+{
+ tools::Long nPosX(0);
+ tools::Long nPosY(0);
+ tools::Long nSizX(0);
+ tools::Long nSizY(0);
+
+ RectPoint eRP = RectPoint::LT;
+
+ //read position
+ if (const SfxInt32Item* pPosXItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_POS_X))
+ nPosX = pPosXItem->GetValue();
+ if (const SfxInt32Item* pPosYItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_POS_Y))
+ nPosY = pPosYItem->GetValue();
+ //read size
+ if (const SfxUInt32Item* pWidthItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_WIDTH))
+ nSizX = pWidthItem->GetValue();
+ if (const SfxUInt32Item* pHeightItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_HEIGHT))
+ nSizY = pHeightItem->GetValue();
+ if (const SfxUInt16Item* pSizeItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_SIZE_POINT))
+ eRP=static_cast<RectPoint>(pSizeItem->GetValue());
+
+ switch( eRP )
+ {
+ case RectPoint::LT:
+ break;
+ case RectPoint::MT:
+ nPosX += ( rOriginalSize.Width - nSizX ) / 2;
+ break;
+ case RectPoint::RT:
+ nPosX += rOriginalSize.Width - nSizX;
+ break;
+ case RectPoint::LM:
+ nPosY += ( rOriginalSize.Height - nSizY ) / 2;
+ break;
+ case RectPoint::MM:
+ nPosX += ( rOriginalSize.Width - nSizX ) / 2;
+ nPosY += ( rOriginalSize.Height - nSizY ) / 2;
+ break;
+ case RectPoint::RM:
+ nPosX += rOriginalSize.Width - nSizX;
+ nPosY += ( rOriginalSize.Height - nSizY ) / 2;
+ break;
+ case RectPoint::LB:
+ nPosY += rOriginalSize.Height - nSizY;
+ break;
+ case RectPoint::MB:
+ nPosX += ( rOriginalSize.Width - nSizX ) / 2;
+ nPosY += rOriginalSize.Height - nSizY;
+ break;
+ case RectPoint::RB:
+ nPosX += rOriginalSize.Width - nSizX;
+ nPosY += rOriginalSize.Height - nSizY;
+ break;
+ default:
+ break;
+ }
+
+ rPosAndSize = awt::Rectangle(nPosX,nPosY,nSizX,nSizY);
+}
+
+void ChartController::executeDispatch_PositionAndSize(const ::css::uno::Sequence< ::css::beans::PropertyValue >* pArgs)
+{
+ const OUString aCID( m_aSelection.getSelectedCID() );
+
+ if( aCID.isEmpty() )
+ return;
+
+ ObjectType eObjectType = ObjectIdentifier::getObjectType( aCID );
+
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::PosSize,
+ ObjectNameProvider::getName( eObjectType)),
+ m_xUndoManager );
+
+ try
+ {
+ SfxItemSet aItemSet = m_pDrawViewWrapper->getPositionAndSizeItemSetFromMarkedObject();
+ const SfxItemSet* pOutItemSet = nullptr;
+ if (!pArgs)
+ {
+ //prepare and open dialog
+ SdrView* pSdrView = m_pDrawViewWrapper.get();
+ bool bResizePossible = m_aSelection.isResizeableObjectSelected();
+
+ SolarMutexGuard aGuard;
+ SvxAbstractDialogFactory * pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateSchTransformTabDialog(
+ GetChartFrame(), &aItemSet, pSdrView, bResizePossible));
+
+ if( pDlg->Execute() == RET_OK )
+ {
+ pOutItemSet = pDlg->GetOutputItemSet();
+ if (pOutItemSet)
+ aItemSet.Put(*pOutItemSet);//overwrite old values with new values (-> all items are set)
+ }
+ }
+ else
+ {
+ const SfxItemPool* pPool = aItemSet.GetPool();
+ if (!pPool)
+ return;
+
+ for (const auto& aProp: *pArgs)
+ {
+ sal_Int32 nValue = 0;
+ aProp.Value >>= nValue;
+ if (aProp.Name == "TransformPosX") {
+ aItemSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_POS_X, nValue));
+ }
+ else if (aProp.Name == "TransformPosY") {
+ aItemSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_POS_Y, nValue));
+ }
+ else if (aProp.Name == "TransformWidth") {
+ aItemSet.Put(SfxUInt32Item(SID_ATTR_TRANSFORM_WIDTH, static_cast<sal_uInt32>(nValue)));
+ }
+ else if (aProp.Name == "TransformHeight") {
+ aItemSet.Put(SfxUInt32Item(SID_ATTR_TRANSFORM_HEIGHT, static_cast<sal_uInt32>(nValue)));
+ }
+ }
+ }
+
+ if(pOutItemSet || pArgs)
+ {
+ awt::Rectangle aOldObjectRect;
+ if( m_xChartView )
+ aOldObjectRect = m_xChartView->getRectangleOfObject(aCID);
+
+ awt::Rectangle aNewObjectRect;
+ lcl_getPositionAndSizeFromItemSet( aItemSet, aNewObjectRect, ToSize(aOldObjectRect) );
+ awt::Size aPageSize( ChartModelHelper::getPageSize( getChartModel() ) );
+ awt::Rectangle aPageRect( 0,0,aPageSize.Width,aPageSize.Height );
+
+ bool bChanged = false;
+ if ( eObjectType == OBJECTTYPE_LEGEND )
+ {
+ bChanged = DiagramHelper::switchDiagramPositioningToExcludingPositioning(*getChartModel(), false , true);
+ }
+
+ bool bMoved = PositionAndSizeHelper::moveObject( m_aSelection.getSelectedCID(), getChartModel()
+ , aNewObjectRect, aOldObjectRect, aPageRect );
+ if( bMoved || bChanged )
+ aUndoGuard.commit();
+ }
+ }
+ catch(const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartController_Properties.cxx b/chart2/source/controller/main/ChartController_Properties.cxx
new file mode 100644
index 0000000000..5f9e9a7d95
--- /dev/null
+++ b/chart2/source/controller/main/ChartController_Properties.cxx
@@ -0,0 +1,840 @@
+/* -*- 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 <ChartController.hxx>
+#include <ChartView.hxx>
+#include <chartview/DrawModelWrapper.hxx>
+#include <chartview/ChartSfxItemIds.hxx>
+#include <ObjectIdentifier.hxx>
+#include <chartview/ExplicitScaleValues.hxx>
+#include <chartview/ExplicitValueProvider.hxx>
+#include <dlg_ObjectProperties.hxx>
+#include <dlg_View3D.hxx>
+#include <dlg_InsertErrorBars.hxx>
+#include <ViewElementListProvider.hxx>
+#include <DataPointItemConverter.hxx>
+#include <TextLabelItemConverter.hxx>
+#include <AxisItemConverter.hxx>
+#include <MultipleChartConverters.hxx>
+#include <TitleItemConverter.hxx>
+#include <LegendItemConverter.hxx>
+#include <DataTableItemConverter.hxx>
+#include <RegressionCurveItemConverter.hxx>
+#include <RegressionEquationItemConverter.hxx>
+#include <ErrorBarItemConverter.hxx>
+#include <ChartModelHelper.hxx>
+#include <Axis.hxx>
+#include <AxisHelper.hxx>
+#include <TitleHelper.hxx>
+#include <ChartType.hxx>
+#include <ChartTypeHelper.hxx>
+#include <ChartModel.hxx>
+#include <ColorPerPointHelper.hxx>
+#include <DataSeries.hxx>
+#include <DataSeriesProperties.hxx>
+#include <DiagramHelper.hxx>
+#include <Diagram.hxx>
+#include <ControllerLockGuard.hxx>
+#include "UndoGuard.hxx"
+#include <ObjectNameProvider.hxx>
+#include <ResId.hxx>
+#include <strings.hrc>
+#include <ReferenceSizeProvider.hxx>
+#include <RegressionCurveHelper.hxx>
+#include <RegressionCurveModel.hxx>
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <memory>
+
+#include <vcl/svapp.hxx>
+#include <svx/ActionDescriptionProvider.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+namespace chart
+{
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::chart2;
+using namespace ::chart::DataSeriesProperties;
+using ::com::sun::star::uno::Reference;
+
+namespace
+{
+
+wrapper::ItemConverter* createItemConverter(
+ std::u16string_view aObjectCID, const rtl::Reference<::chart::ChartModel>& xChartModel,
+ const uno::Reference<uno::XComponentContext>& xContext, SdrModel& rDrawModel,
+ ExplicitValueProvider* pExplicitValueProvider, ReferenceSizeProvider const * pRefSizeProvider )
+{
+ wrapper::ItemConverter* pItemConverter=nullptr;
+
+ //get type of selected object
+ ObjectType eObjectType = ObjectIdentifier::getObjectType( aObjectCID );
+ if( eObjectType==OBJECTTYPE_UNKNOWN )
+ {
+ OSL_FAIL("unknown ObjectType");
+ return nullptr;
+ }
+
+ std::u16string_view aParticleID = ObjectIdentifier::getParticleID( aObjectCID );
+ bool bAffectsMultipleObjects = aParticleID == u"ALLELEMENTS";
+ if( !bAffectsMultipleObjects )
+ {
+ uno::Reference< beans::XPropertySet > xObjectProperties =
+ ObjectIdentifier::getObjectPropertySet( aObjectCID, xChartModel );
+ if(!xObjectProperties.is())
+ return nullptr;
+ //create itemconverter for a single object
+ switch(eObjectType)
+ {
+ case OBJECTTYPE_PAGE:
+ pItemConverter = new wrapper::GraphicPropertyItemConverter(
+ xObjectProperties, rDrawModel.GetItemPool(),
+ rDrawModel, xChartModel,
+ wrapper::GraphicObjectType::LineAndFillProperties );
+ break;
+ case OBJECTTYPE_TITLE:
+ {
+ std::unique_ptr<awt::Size> pRefSize;
+ if (pRefSizeProvider)
+ pRefSize.reset(new awt::Size(pRefSizeProvider->getPageSize()));
+
+ pItemConverter = new wrapper::TitleItemConverter(
+ xObjectProperties, rDrawModel.GetItemPool(), rDrawModel,
+ xChartModel,
+ pRefSize.get());
+ }
+ break;
+ case OBJECTTYPE_LEGEND:
+ {
+ std::unique_ptr<awt::Size> pRefSize;
+ if (pRefSizeProvider)
+ pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize()));
+
+ pItemConverter = new wrapper::LegendItemConverter(
+ xObjectProperties, rDrawModel.GetItemPool(), rDrawModel,
+ xChartModel,
+ pRefSize.get());
+ }
+ break;
+ case OBJECTTYPE_LEGEND_ENTRY:
+ break;
+ case OBJECTTYPE_DIAGRAM:
+ break;
+ case OBJECTTYPE_DIAGRAM_WALL:
+ case OBJECTTYPE_DIAGRAM_FLOOR:
+ pItemConverter = new wrapper::GraphicPropertyItemConverter(
+ xObjectProperties, rDrawModel.GetItemPool(),
+ rDrawModel, xChartModel,
+ wrapper::GraphicObjectType::LineAndFillProperties );
+ break;
+ case OBJECTTYPE_AXIS:
+ {
+ std::unique_ptr<awt::Size> pRefSize;
+ if (pRefSizeProvider)
+ pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize()));
+
+ // the second property set contains the property CoordinateOrigin
+ // nOriginIndex is the index of the corresponding index of the
+ // origin (x=0, y=1, z=2)
+
+ ExplicitScaleData aExplicitScale;
+ ExplicitIncrementData aExplicitIncrement;
+ if( pExplicitValueProvider )
+ pExplicitValueProvider->getExplicitValuesForAxis(
+ dynamic_cast< Axis* >( xObjectProperties.get() ),
+ aExplicitScale, aExplicitIncrement );
+
+ pItemConverter = new wrapper::AxisItemConverter(
+ xObjectProperties, rDrawModel.GetItemPool(),
+ rDrawModel,
+ xChartModel,
+ &aExplicitScale, &aExplicitIncrement,
+ pRefSize.get() );
+ }
+ break;
+ case OBJECTTYPE_AXIS_UNITLABEL:
+ break;
+ case OBJECTTYPE_DATA_LABELS:
+ case OBJECTTYPE_DATA_LABEL:
+ {
+ std::unique_ptr<awt::Size> pRefSize;
+ if (pRefSizeProvider)
+ pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize()));
+
+ rtl::Reference<DataSeries> xSeries = ObjectIdentifier::getDataSeriesForCID(aObjectCID, xChartModel);
+
+ bool bDataSeries = eObjectType == OBJECTTYPE_DATA_LABELS;
+
+ sal_Int32 nNumberFormat = ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( xObjectProperties );
+ sal_Int32 nPercentNumberFormat = ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel(
+ xObjectProperties, xChartModel);
+
+ pItemConverter = new wrapper::TextLabelItemConverter(
+ xChartModel, xObjectProperties, xSeries,
+ rDrawModel.GetItemPool(), pRefSize.get(), bDataSeries,
+ nNumberFormat, nPercentNumberFormat);
+ }
+ break;
+ case OBJECTTYPE_DATA_SERIES:
+ case OBJECTTYPE_DATA_POINT:
+ {
+ std::unique_ptr<awt::Size> pRefSize;
+ if (pRefSizeProvider)
+ pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize()));
+
+ wrapper::GraphicObjectType eMapTo =
+ wrapper::GraphicObjectType::FilledDataPoint;
+
+ rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( aObjectCID, xChartModel );
+ rtl::Reference< ChartType > xChartType = ChartModelHelper::getChartTypeOfSeries( xChartModel, xSeries );
+
+ rtl::Reference< Diagram > xDiagram = xChartModel->getFirstChartDiagram();
+ sal_Int32 nDimensionCount = xDiagram->getDimension();
+ if( !ChartTypeHelper::isSupportingAreaProperties( xChartType, nDimensionCount ) )
+ eMapTo = wrapper::GraphicObjectType::LineDataPoint;
+
+ bool bDataSeries = eObjectType == OBJECTTYPE_DATA_SERIES;
+
+ //special color for pie chart:
+ bool bUseSpecialFillColor = false;
+ sal_Int32 nSpecialFillColor =0;
+ sal_Int32 nPointIndex = -1; /*-1 for whole series*/
+ if(!bDataSeries)
+ {
+ nPointIndex = o3tl::toInt32(aParticleID);
+ bool bVaryColorsByPoint = false;
+ if( xSeries.is() &&
+ // "VaryColorsByPoint"
+ (xSeries->getFastPropertyValue(PROP_DATASERIES_VARY_COLORS_BY_POINT) >>= bVaryColorsByPoint) &&
+ bVaryColorsByPoint )
+ {
+ if( !ColorPerPointHelper::hasPointOwnColor( xSeries, nPointIndex, xObjectProperties ) )
+ {
+ bUseSpecialFillColor = true;
+ OSL_ASSERT( xDiagram.is());
+ uno::Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme() );
+ if( xColorScheme.is())
+ nSpecialFillColor = xColorScheme->getColorByIndex( nPointIndex );
+ }
+ }
+ }
+ sal_Int32 nNumberFormat=ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( xObjectProperties );
+ sal_Int32 nPercentNumberFormat=ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel(
+ xObjectProperties, xChartModel);
+
+ pItemConverter = new wrapper::DataPointItemConverter( xChartModel, xContext,
+ xObjectProperties, xSeries, rDrawModel.GetItemPool(), rDrawModel,
+ xChartModel,
+ eMapTo, pRefSize.get(), bDataSeries, bUseSpecialFillColor, nSpecialFillColor, true,
+ nNumberFormat, nPercentNumberFormat, nPointIndex );
+ break;
+ }
+ case OBJECTTYPE_GRID:
+ case OBJECTTYPE_SUBGRID:
+ case OBJECTTYPE_DATA_AVERAGE_LINE:
+ pItemConverter = new wrapper::GraphicPropertyItemConverter(
+ xObjectProperties, rDrawModel.GetItemPool(),
+ rDrawModel, xChartModel,
+ wrapper::GraphicObjectType::LineProperties );
+ break;
+
+ case OBJECTTYPE_DATA_ERRORS_X:
+ case OBJECTTYPE_DATA_ERRORS_Y:
+ case OBJECTTYPE_DATA_ERRORS_Z:
+ pItemConverter = new wrapper::ErrorBarItemConverter(
+ xChartModel, xObjectProperties, rDrawModel.GetItemPool(),
+ rDrawModel, xChartModel);
+ break;
+
+ case OBJECTTYPE_DATA_CURVE:
+ pItemConverter = new wrapper::RegressionCurveItemConverter(
+ xObjectProperties,
+ ObjectIdentifier::getDataSeriesForCID( aObjectCID, xChartModel ),
+ rDrawModel.GetItemPool(), rDrawModel,
+ xChartModel);
+ break;
+ case OBJECTTYPE_DATA_CURVE_EQUATION:
+ {
+ std::unique_ptr<awt::Size> pRefSize;
+ if (pRefSizeProvider)
+ pRefSize.reset(new awt::Size(pRefSizeProvider->getPageSize()));
+
+ pItemConverter = new wrapper::RegressionEquationItemConverter(
+ xObjectProperties, rDrawModel.GetItemPool(), rDrawModel,
+ xChartModel,
+ pRefSize.get());
+ break;
+ }
+ case OBJECTTYPE_DATA_STOCK_RANGE:
+ break;
+ case OBJECTTYPE_DATA_STOCK_LOSS:
+ case OBJECTTYPE_DATA_STOCK_GAIN:
+ pItemConverter = new wrapper::GraphicPropertyItemConverter(
+ xObjectProperties, rDrawModel.GetItemPool(),
+ rDrawModel, xChartModel,
+ wrapper::GraphicObjectType::LineAndFillProperties );
+ break;
+ case OBJECTTYPE_DATA_TABLE:
+ {
+ pItemConverter = new wrapper::DataTableItemConverter(
+ xObjectProperties, rDrawModel.GetItemPool(),
+ rDrawModel, xChartModel);
+ }
+ break;
+ default: //OBJECTTYPE_UNKNOWN
+ break;
+ }
+ }
+ else
+ {
+ //create itemconverter for all objects of given type
+ switch(eObjectType)
+ {
+ case OBJECTTYPE_TITLE:
+ pItemConverter = new wrapper::AllTitleItemConverter( xChartModel, rDrawModel.GetItemPool(),
+ rDrawModel, xChartModel);
+ break;
+ case OBJECTTYPE_AXIS:
+ {
+ std::unique_ptr<awt::Size> pRefSize;
+ if (pRefSizeProvider)
+ pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize()));
+
+ pItemConverter = new wrapper::AllAxisItemConverter(
+ xChartModel, rDrawModel.GetItemPool(),
+ rDrawModel, pRefSize.get());
+ }
+ break;
+ case OBJECTTYPE_GRID:
+ case OBJECTTYPE_SUBGRID:
+ pItemConverter = new wrapper::AllGridItemConverter( xChartModel, rDrawModel.GetItemPool(),
+ rDrawModel, xChartModel);
+ break;
+ default: //for this type it is not supported to change all elements at once
+ break;
+ }
+
+ }
+ return pItemConverter;
+}
+
+OUString lcl_getTitleCIDForCommand( std::string_view rDispatchCommand, const rtl::Reference<::chart::ChartModel> & xChartModel )
+{
+ if( rDispatchCommand == "AllTitles")
+ return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_TITLE, u"ALLELEMENTS" );
+
+ TitleHelper::eTitleType nTitleType( TitleHelper::MAIN_TITLE );
+ if( rDispatchCommand == "SubTitle" )
+ nTitleType = TitleHelper::SUB_TITLE;
+ else if( rDispatchCommand == "XTitle" )
+ nTitleType = TitleHelper::X_AXIS_TITLE;
+ else if( rDispatchCommand == "YTitle" )
+ nTitleType = TitleHelper::Y_AXIS_TITLE;
+ else if( rDispatchCommand == "ZTitle" )
+ nTitleType = TitleHelper::Z_AXIS_TITLE;
+ else if( rDispatchCommand == "SecondaryXTitle" )
+ nTitleType = TitleHelper::SECONDARY_X_AXIS_TITLE;
+ else if( rDispatchCommand == "SecondaryYTitle" )
+ nTitleType = TitleHelper::SECONDARY_Y_AXIS_TITLE;
+
+ rtl::Reference< Title > xTitle( TitleHelper::getTitle( nTitleType, xChartModel ) );
+ return ObjectIdentifier::createClassifiedIdentifierForObject( xTitle, xChartModel );
+}
+
+OUString lcl_getAxisCIDForCommand( std::string_view rDispatchCommand, const rtl::Reference<::chart::ChartModel>& xChartModel )
+{
+ if( rDispatchCommand == "DiagramAxisAll")
+ return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_AXIS, u"ALLELEMENTS" );
+
+ sal_Int32 nDimensionIndex=0;
+ bool bMainAxis=true;
+ if( rDispatchCommand == "DiagramAxisX")
+ {
+ nDimensionIndex=0; bMainAxis=true;
+ }
+ else if( rDispatchCommand == "DiagramAxisY")
+ {
+ nDimensionIndex=1; bMainAxis=true;
+ }
+ else if( rDispatchCommand == "DiagramAxisZ")
+ {
+ nDimensionIndex=2; bMainAxis=true;
+ }
+ else if( rDispatchCommand == "DiagramAxisA")
+ {
+ nDimensionIndex=0; bMainAxis=false;
+ }
+ else if( rDispatchCommand == "DiagramAxisB")
+ {
+ nDimensionIndex=1; bMainAxis=false;
+ }
+
+ rtl::Reference< Diagram > xDiagram = xChartModel->getFirstChartDiagram();
+ rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram );
+ return ObjectIdentifier::createClassifiedIdentifierForObject( xAxis, xChartModel );
+}
+
+OUString lcl_getGridCIDForCommand( std::string_view rDispatchCommand, const rtl::Reference<::chart::ChartModel>& xChartModel )
+{
+ rtl::Reference< Diagram > xDiagram = xChartModel->getFirstChartDiagram();
+
+ if( rDispatchCommand == "DiagramGridAll")
+ return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_GRID, u"ALLELEMENTS" );
+
+ sal_Int32 nDimensionIndex=0;
+ bool bMainGrid=true;
+
+ //x and y is swapped in the commands
+
+ if( rDispatchCommand == "DiagramGridYMain")
+ {
+ nDimensionIndex=0; bMainGrid=true;
+ }
+ else if( rDispatchCommand == "DiagramGridXMain")
+ {
+ nDimensionIndex=1; bMainGrid=true;
+ }
+ else if( rDispatchCommand == "DiagramGridZMain")
+ {
+ nDimensionIndex=2; bMainGrid=true;
+ }
+ else if( rDispatchCommand == "DiagramGridYHelp")
+ {
+ nDimensionIndex=0; bMainGrid=false;
+ }
+ else if( rDispatchCommand == "DiagramGridXHelp")
+ {
+ nDimensionIndex=1; bMainGrid=false;
+ }
+ else if( rDispatchCommand == "DiagramGridZHelp")
+ {
+ nDimensionIndex=2; bMainGrid=false;
+ }
+
+ rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, true/*bMainAxis*/, xDiagram );
+
+ sal_Int32 nSubGridIndex= bMainGrid ? -1 : 0;
+ OUString aCID( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartModel, nSubGridIndex ) );
+ return aCID;
+}
+
+OUString lcl_getErrorCIDForCommand( const ObjectType eDispatchType, const ObjectType &eSelectedType, const OUString &rSelectedCID)
+{
+ if( eSelectedType == eDispatchType )
+ return rSelectedCID;
+
+ return ObjectIdentifier::createClassifiedIdentifierWithParent( eDispatchType, u"", rSelectedCID );
+}
+
+OUString lcl_getObjectCIDForCommand( std::string_view rDispatchCommand, const rtl::Reference<::chart::ChartModel> & xChartDocument, const OUString& rSelectedCID )
+{
+ ObjectType eObjectType = OBJECTTYPE_UNKNOWN;
+
+ const ObjectType eSelectedType = ObjectIdentifier::getObjectType( rSelectedCID );
+ rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rSelectedCID, xChartDocument );
+
+ //legend
+ if( rDispatchCommand == "Legend" || rDispatchCommand == "FormatLegend" )
+ {
+ eObjectType = OBJECTTYPE_LEGEND;
+ //@todo set particular aParticleID if we have more than one legend
+ }
+ //wall floor area
+ else if( rDispatchCommand == "DiagramWall" || rDispatchCommand == "FormatWall" )
+ {
+ //OBJECTTYPE_DIAGRAM;
+ eObjectType = OBJECTTYPE_DIAGRAM_WALL;
+ //@todo set particular aParticleID if we have more than one diagram
+ }
+ else if( rDispatchCommand == "DiagramFloor" || rDispatchCommand == "FormatFloor" )
+ {
+ eObjectType = OBJECTTYPE_DIAGRAM_FLOOR;
+ //@todo set particular aParticleID if we have more than one diagram
+ }
+ else if( rDispatchCommand == "DiagramArea" || rDispatchCommand == "FormatChartArea" )
+ {
+ eObjectType = OBJECTTYPE_PAGE;
+ }
+ //title
+ else if( rDispatchCommand == "MainTitle"
+ || rDispatchCommand == "SubTitle"
+ || rDispatchCommand == "XTitle"
+ || rDispatchCommand == "YTitle"
+ || rDispatchCommand == "ZTitle"
+ || rDispatchCommand == "SecondaryXTitle"
+ || rDispatchCommand == "SecondaryYTitle"
+ || rDispatchCommand == "AllTitles"
+ )
+ {
+ return lcl_getTitleCIDForCommand( rDispatchCommand, xChartDocument );
+ }
+ //axis
+ else if( rDispatchCommand == "DiagramAxisX"
+ || rDispatchCommand == "DiagramAxisY"
+ || rDispatchCommand == "DiagramAxisZ"
+ || rDispatchCommand == "DiagramAxisA"
+ || rDispatchCommand == "DiagramAxisB"
+ || rDispatchCommand == "DiagramAxisAll"
+ )
+ {
+ return lcl_getAxisCIDForCommand( rDispatchCommand, xChartDocument );
+ }
+ //grid
+ else if( rDispatchCommand == "DiagramGridYMain"
+ || rDispatchCommand == "DiagramGridXMain"
+ || rDispatchCommand == "DiagramGridZMain"
+ || rDispatchCommand == "DiagramGridYHelp"
+ || rDispatchCommand == "DiagramGridXHelp"
+ || rDispatchCommand == "DiagramGridZHelp"
+ || rDispatchCommand == "DiagramGridAll"
+ )
+ {
+ return lcl_getGridCIDForCommand( rDispatchCommand, xChartDocument );
+ }
+ //data series
+ else if( rDispatchCommand == "FormatDataSeries" )
+ {
+ if( eSelectedType == OBJECTTYPE_DATA_SERIES )
+ return rSelectedCID;
+ else
+ return ObjectIdentifier::createClassifiedIdentifier(
+ OBJECTTYPE_DATA_SERIES, ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ) );
+ }
+ //data point
+ else if( rDispatchCommand == "FormatDataPoint" )
+ {
+ return rSelectedCID;
+ }
+ //data labels
+ else if( rDispatchCommand == "FormatDataLabels" )
+ {
+ if( eSelectedType == OBJECTTYPE_DATA_LABELS )
+ return rSelectedCID;
+ else
+ return ObjectIdentifier::createClassifiedIdentifierWithParent(
+ OBJECTTYPE_DATA_LABELS, u"", rSelectedCID );
+ }
+ //data labels
+ else if( rDispatchCommand == "FormatDataLabel" )
+ {
+ if( eSelectedType == OBJECTTYPE_DATA_LABEL )
+ return rSelectedCID;
+ else
+ {
+ sal_Int32 nPointIndex = o3tl::toInt32(ObjectIdentifier::getParticleID( rSelectedCID ));
+ if( nPointIndex>=0 )
+ {
+ OUString aSeriesParticle = ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID );
+ OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) + "=" );
+ OUString aLabelsCID = ObjectIdentifier::createClassifiedIdentifierForParticles( aSeriesParticle, aChildParticle );
+ OUString aLabelCID_Stub = ObjectIdentifier::createClassifiedIdentifierWithParent(
+ OBJECTTYPE_DATA_LABEL, u"", aLabelsCID );
+
+ return ObjectIdentifier::createPointCID( aLabelCID_Stub, nPointIndex );
+ }
+ }
+ }
+ //mean value line
+ else if( rDispatchCommand == "FormatMeanValue" )
+ {
+ if( eSelectedType == OBJECTTYPE_DATA_AVERAGE_LINE )
+ return rSelectedCID;
+ else
+ return ObjectIdentifier::createDataCurveCID(
+ ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ),
+ RegressionCurveHelper::getRegressionCurveIndex( xSeries,
+ RegressionCurveHelper::getMeanValueLine( xSeries ) ), true );
+ }
+ //trend line
+ else if( rDispatchCommand == "FormatTrendline" )
+ {
+ if( eSelectedType == OBJECTTYPE_DATA_CURVE )
+ return rSelectedCID;
+ else
+ return ObjectIdentifier::createDataCurveCID(
+ ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ),
+ RegressionCurveHelper::getRegressionCurveIndex( xSeries,
+ RegressionCurveHelper::getFirstCurveNotMeanValueLine( xSeries ) ), false );
+ }
+ //trend line equation
+ else if( rDispatchCommand == "FormatTrendlineEquation" )
+ {
+ if( eSelectedType == OBJECTTYPE_DATA_CURVE_EQUATION )
+ return rSelectedCID;
+ else
+ return ObjectIdentifier::createDataCurveEquationCID(
+ ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ),
+ RegressionCurveHelper::getRegressionCurveIndex( xSeries,
+ RegressionCurveHelper::getFirstCurveNotMeanValueLine( xSeries ) ) );
+ }
+ // y error bars
+ else if( rDispatchCommand == "FormatXErrorBars" )
+ {
+ return lcl_getErrorCIDForCommand(OBJECTTYPE_DATA_ERRORS_X, eSelectedType, rSelectedCID );
+ }
+ // y error bars
+ else if( rDispatchCommand == "FormatYErrorBars" )
+ {
+ return lcl_getErrorCIDForCommand(OBJECTTYPE_DATA_ERRORS_Y, eSelectedType, rSelectedCID );
+ }
+ // axis
+ else if( rDispatchCommand == "FormatAxis" )
+ {
+ if( eSelectedType == OBJECTTYPE_AXIS )
+ return rSelectedCID;
+ else
+ {
+ rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( rSelectedCID, xChartDocument );
+ return ObjectIdentifier::createClassifiedIdentifierForObject( xAxis , xChartDocument );
+ }
+ }
+ // major grid
+ else if( rDispatchCommand == "FormatMajorGrid" )
+ {
+ if( eSelectedType == OBJECTTYPE_GRID )
+ return rSelectedCID;
+ else
+ {
+ rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( rSelectedCID, xChartDocument );
+ return ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartDocument );
+ }
+
+ }
+ // minor grid
+ else if( rDispatchCommand == "FormatMinorGrid" )
+ {
+ if( eSelectedType == OBJECTTYPE_SUBGRID )
+ return rSelectedCID;
+ else
+ {
+ rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( rSelectedCID, xChartDocument );
+ return ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartDocument, 0 /*sub grid index*/ );
+ }
+ }
+ // title
+ else if( rDispatchCommand == "FormatTitle" )
+ {
+ if( eSelectedType == OBJECTTYPE_TITLE )
+ return rSelectedCID;
+ }
+ // stock loss
+ else if( rDispatchCommand == "FormatStockLoss" )
+ {
+ if( eSelectedType == OBJECTTYPE_DATA_STOCK_LOSS )
+ return rSelectedCID;
+ else
+ return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DATA_STOCK_LOSS, u"");
+ }
+ // stock gain
+ else if( rDispatchCommand == "FormatStockGain" )
+ {
+ if( eSelectedType == OBJECTTYPE_DATA_STOCK_GAIN )
+ return rSelectedCID;
+ else
+ return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DATA_STOCK_GAIN, u"" );
+ }
+
+ return ObjectIdentifier::createClassifiedIdentifier(
+ eObjectType,
+ u"" ); // aParticleID
+}
+
+}
+// anonymous namespace
+
+void ChartController::executeDispatch_FormatObject(std::u16string_view rDispatchCommand)
+{
+ rtl::Reference<::chart::ChartModel> xChartDocument( getChartModel() );
+ OString aCommand( OUStringToOString( rDispatchCommand, RTL_TEXTENCODING_ASCII_US ) );
+ OUString rObjectCID = lcl_getObjectCIDForCommand( aCommand, xChartDocument, m_aSelection.getSelectedCID() );
+ executeDlg_ObjectProperties( rObjectCID );
+}
+
+void ChartController::executeDispatch_ObjectProperties()
+{
+ executeDlg_ObjectProperties( m_aSelection.getSelectedCID() );
+}
+
+namespace
+{
+
+OUString lcl_getFormatCIDforSelectedCID( const OUString& rSelectedCID )
+{
+ OUString aFormatCID(rSelectedCID);
+
+ //get type of selected object
+ ObjectType eObjectType = ObjectIdentifier::getObjectType( aFormatCID );
+
+ // some legend entries are handled as if they were data series
+ if( eObjectType==OBJECTTYPE_LEGEND_ENTRY )
+ {
+ std::u16string_view aParentParticle( ObjectIdentifier::getFullParentParticle( rSelectedCID ) );
+ aFormatCID = ObjectIdentifier::createClassifiedIdentifierForParticle( aParentParticle );
+ }
+
+ // treat diagram as wall
+ if( eObjectType==OBJECTTYPE_DIAGRAM )
+ aFormatCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" );
+
+ return aFormatCID;
+}
+
+}//end anonymous namespace
+
+void ChartController::executeDlg_ObjectProperties( const OUString& rSelectedObjectCID )
+{
+ OUString aObjectCID = lcl_getFormatCIDforSelectedCID( rSelectedObjectCID );
+
+ UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Format,
+ ObjectNameProvider::getName( ObjectIdentifier::getObjectType( aObjectCID ))),
+ m_xUndoManager );
+
+ bool bSuccess = ChartController::executeDlg_ObjectProperties_withoutUndoGuard( aObjectCID, false );
+ if( bSuccess )
+ aUndoGuard.commit();
+}
+
+bool ChartController::executeDlg_ObjectProperties_withoutUndoGuard(
+ const OUString& rObjectCID, bool bSuccessOnUnchanged )
+{
+ //return true if the properties were changed successfully
+ bool bRet = false;
+ if( rObjectCID.isEmpty() )
+ {
+ return bRet;
+ }
+ try
+ {
+ //get type of object
+ ObjectType eObjectType = ObjectIdentifier::getObjectType( rObjectCID );
+ if( eObjectType==OBJECTTYPE_UNKNOWN )
+ {
+ return bRet;
+ }
+ if( eObjectType==OBJECTTYPE_DIAGRAM_WALL || eObjectType==OBJECTTYPE_DIAGRAM_FLOOR )
+ {
+ if( !getFirstDiagram()->isSupportingFloorAndWall() )
+ return bRet;
+ }
+
+ //convert properties to ItemSet
+
+ std::unique_ptr<ReferenceSizeProvider> pRefSizeProv(impl_createReferenceSizeProvider());
+
+ rtl::Reference<::chart::ChartModel> xChartDoc(getChartModel());
+
+ std::unique_ptr<wrapper::ItemConverter> pItemConverter(
+ createItemConverter( rObjectCID, xChartDoc, m_xCC,
+ m_pDrawModelWrapper->getSdrModel(),
+ m_xChartView.get(),
+ pRefSizeProv.get()));
+
+ if (!pItemConverter)
+ return bRet;
+
+ SfxItemSet aItemSet = pItemConverter->CreateEmptyItemSet();
+
+ if ( eObjectType == OBJECTTYPE_DATA_ERRORS_X || eObjectType == OBJECTTYPE_DATA_ERRORS_Y )
+ aItemSet.Put(SfxBoolItem(SCHATTR_STAT_ERRORBAR_TYPE, eObjectType == OBJECTTYPE_DATA_ERRORS_Y ));
+
+ pItemConverter->FillItemSet(aItemSet);
+
+ //prepare dialog
+ ObjectPropertiesDialogParameter aDialogParameter( rObjectCID );
+ aDialogParameter.init(xChartDoc);
+ ViewElementListProvider aViewElementListProvider( m_pDrawModelWrapper.get() );
+
+ SolarMutexGuard aGuard;
+ SchAttribTabDlg aDlg(
+ GetChartFrame(), &aItemSet, &aDialogParameter,
+ &aViewElementListProvider,
+ xChartDoc );
+
+ if(aDialogParameter.HasSymbolProperties())
+ {
+ uno::Reference< beans::XPropertySet > xObjectProperties =
+ ObjectIdentifier::getObjectPropertySet( rObjectCID, xChartDoc );
+ wrapper::DataPointItemConverter aSymbolItemConverter( xChartDoc, m_xCC
+ , xObjectProperties, ObjectIdentifier::getDataSeriesForCID( rObjectCID, xChartDoc )
+ , m_pDrawModelWrapper->getSdrModel().GetItemPool()
+ , m_pDrawModelWrapper->getSdrModel()
+ , xChartDoc
+ , wrapper::GraphicObjectType::FilledDataPoint );
+
+ SfxItemSet aSymbolShapeProperties(aSymbolItemConverter.CreateEmptyItemSet() );
+ aSymbolItemConverter.FillItemSet( aSymbolShapeProperties );
+
+ sal_Int32 const nStandardSymbol=0;//@todo get from somewhere
+ std::optional<Graphic> oAutoSymbolGraphic(std::in_place, aViewElementListProvider.GetSymbolGraphic( nStandardSymbol, &aSymbolShapeProperties ) );
+ // note: the dialog takes the ownership of pSymbolShapeProperties and pAutoSymbolGraphic
+ aDlg.setSymbolInformation( std::move(aSymbolShapeProperties), std::move(oAutoSymbolGraphic) );
+ }
+ if( aDialogParameter.HasStatisticProperties() )
+ {
+ aDlg.SetAxisMinorStepWidthForErrorBarDecimals(
+ InsertErrorBarsDialog::getAxisMinorStepWidthForErrorBarDecimals( xChartDoc, m_xChartView, rObjectCID ) );
+ }
+
+ //open the dialog
+ if (aDlg.run() == RET_OK || (bSuccessOnUnchanged && aDlg.DialogWasClosedWithOK()))
+ {
+ const SfxItemSet* pOutItemSet = aDlg.GetOutputItemSet();
+ if(pOutItemSet)
+ {
+ ControllerLockGuardUNO aCLGuard(xChartDoc);
+ (void)pItemConverter->ApplyItemSet(*pOutItemSet); //model should be changed now
+ bRet = true;
+ }
+ }
+ }
+ catch( const util::CloseVetoException& )
+ {
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+ return bRet;
+}
+
+void ChartController::executeDispatch_View3D()
+{
+ try
+ {
+ UndoLiveUpdateGuard aUndoGuard(
+ SchResId( STR_ACTION_EDIT_3D_VIEW ),
+ m_xUndoManager );
+
+ //open dialog
+ SolarMutexGuard aSolarGuard;
+ View3DDialog aDlg(GetChartFrame(), getChartModel());
+ if (aDlg.run() == RET_OK)
+ aUndoGuard.commit();
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartController_TextEdit.cxx b/chart2/source/controller/main/ChartController_TextEdit.cxx
new file mode 100644
index 0000000000..f2d21779ba
--- /dev/null
+++ b/chart2/source/controller/main/ChartController_TextEdit.cxx
@@ -0,0 +1,230 @@
+/* -*- 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 <config_wasm_strip.h>
+
+#include <ChartController.hxx>
+
+#include <ResId.hxx>
+#include "UndoGuard.hxx"
+#include <DrawViewWrapper.hxx>
+#include <ChartWindow.hxx>
+#include <ChartModel.hxx>
+#include <ChartView.hxx>
+#include <TitleHelper.hxx>
+#include <ObjectIdentifier.hxx>
+#include <ControllerLockGuard.hxx>
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+#include <AccessibleTextHelper.hxx>
+#endif
+#include <strings.hrc>
+#include <chartview/DrawModelWrapper.hxx>
+#include <osl/diagnose.h>
+
+#include <svx/svdoutl.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/svxids.hrc>
+#include <editeng/editids.hrc>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/chart2/XTitle.hpp>
+#include <svl/stritem.hxx>
+#include <editeng/fontitem.hxx>
+#include <memory>
+
+namespace chart
+{
+using namespace ::com::sun::star;
+
+void ChartController::executeDispatch_EditText( const Point* pMousePixel )
+{
+ StartTextEdit( pMousePixel );
+}
+
+void ChartController::StartTextEdit( const Point* pMousePixel )
+{
+ //the first marked object will be edited
+
+ SolarMutexGuard aGuard;
+ SdrObject* pTextObj = m_pDrawViewWrapper->getTextEditObject();
+ if(!pTextObj)
+ return;
+
+ OSL_PRECOND(!m_pTextActionUndoGuard,
+ "ChartController::StartTextEdit: already have a TextUndoGuard!?");
+ m_pTextActionUndoGuard.reset( new UndoGuard(
+ SchResId( STR_ACTION_EDIT_TEXT ), m_xUndoManager ) );
+ SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner();
+
+ //#i77362 change notification for changes on additional shapes are missing
+ if( m_xChartView.is() )
+ m_xChartView->setPropertyValue( "SdrViewIsInEditMode", uno::Any(true) );
+
+ auto pChartWindow(GetChartWindow());
+
+ bool bEdit = m_pDrawViewWrapper->SdrBeginTextEdit( pTextObj
+ , m_pDrawViewWrapper->GetPageView()
+ , pChartWindow
+ , false //bIsNewObj
+ , pOutliner
+ , nullptr //pOutlinerView
+ , true //bDontDeleteOutliner
+ , true //bOnlyOneView
+ );
+ if(!bEdit)
+ return;
+
+ m_pDrawViewWrapper->SetEditMode();
+
+ // #i12587# support for shapes in chart
+ if ( pMousePixel )
+ {
+ OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView();
+ if ( pOutlinerView )
+ {
+ MouseEvent aEditEvt( *pMousePixel, 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, 0 );
+ pOutlinerView->MouseButtonDown( aEditEvt );
+ pOutlinerView->MouseButtonUp( aEditEvt );
+ }
+ }
+
+ if (pChartWindow)
+ {
+ //we invalidate the outliner region because the outliner has some
+ //paint problems (some characters are painted twice a little bit shifted)
+ pChartWindow->Invalidate( m_pDrawViewWrapper->GetMarkedObjBoundRect() );
+ }
+}
+
+bool ChartController::EndTextEdit()
+{
+ m_pDrawViewWrapper->SdrEndTextEdit();
+
+ //#i77362 change notification for changes on additional shapes are missing
+ if( m_xChartView.is() )
+ m_xChartView->setPropertyValue( "SdrViewIsInEditMode", uno::Any(false) );
+
+ SdrObject* pTextObject = m_pDrawViewWrapper->getTextEditObject();
+ if(!pTextObject)
+ return false;
+
+ SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner();
+ OutlinerParaObject* pParaObj = pTextObject->GetOutlinerParaObject();
+ if( !pParaObj || !pOutliner )
+ return true;
+
+ pOutliner->SetText( *pParaObj );
+
+ OUString aString = pOutliner->GetText(
+ pOutliner->GetParagraph( 0 ),
+ pOutliner->GetParagraphCount() );
+
+ OUString aObjectCID = m_aSelection.getSelectedCID();
+ if ( !aObjectCID.isEmpty() )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet =
+ ObjectIdentifier::getObjectPropertySet( aObjectCID, getChartModel() );
+
+ // lock controllers till end of block
+ ControllerLockGuardUNO aCLGuard( getChartModel() );
+
+ Title* pTitle = dynamic_cast<Title*>(xPropSet.get());
+ TitleHelper::setCompleteString( aString, pTitle, m_xCC );
+
+ OSL_ENSURE(m_pTextActionUndoGuard, "ChartController::EndTextEdit: no TextUndoGuard!");
+ if (m_pTextActionUndoGuard)
+ m_pTextActionUndoGuard->commit();
+ }
+ m_pTextActionUndoGuard.reset();
+ return true;
+}
+
+void ChartController::executeDispatch_InsertSpecialCharacter()
+{
+ SolarMutexGuard aGuard;
+ if( !m_pDrawViewWrapper)
+ {
+ OSL_ENSURE( m_pDrawViewWrapper, "No DrawViewWrapper for ChartController" );
+ return;
+ }
+ if( !m_pDrawViewWrapper->IsTextEdit() )
+ StartTextEdit();
+
+ SvxAbstractDialogFactory * pFact = SvxAbstractDialogFactory::Create();
+
+ SfxAllItemSet aSet( m_pDrawModelWrapper->GetItemPool() );
+ aSet.Put( SfxBoolItem( FN_PARAM_1, false ) );
+
+ //set fixed current font
+ aSet.Put( SfxBoolItem( FN_PARAM_2, true ) ); //maybe not necessary in future
+
+ vcl::Font aCurFont = m_pDrawViewWrapper->getOutliner()->GetRefDevice()->GetFont();
+ aSet.Put( SvxFontItem( aCurFont.GetFamilyType(), aCurFont.GetFamilyName(), aCurFont.GetStyleName(), aCurFont.GetPitch(), aCurFont.GetCharSet(), SID_ATTR_CHAR_FONT ) );
+
+ ScopedVclPtr<SfxAbstractDialog> pDlg(pFact->CreateCharMapDialog(GetChartFrame(), aSet, nullptr));
+ if( pDlg->Execute() != RET_OK )
+ return;
+
+ const SfxItemSet* pSet = pDlg->GetOutputItemSet();
+ OUString aString;
+ if (pSet)
+ if (const SfxStringItem* pCharMapItem = pSet->GetItemIfSet(SID_CHARMAP))
+ aString = pCharMapItem->GetValue();
+
+ OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView();
+ SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner();
+
+ if(!pOutliner || !pOutlinerView)
+ return;
+
+ // insert string to outliner
+
+ // prevent flicker
+ pOutlinerView->HideCursor();
+ pOutliner->SetUpdateLayout(false);
+
+ // delete current selection by inserting empty String, so current
+ // attributes become unique (sel. has to be erased anyway)
+ pOutlinerView->InsertText(OUString());
+
+ pOutlinerView->InsertText(aString, true);
+
+ ESelection aSel = pOutlinerView->GetSelection();
+ aSel.nStartPara = aSel.nEndPara;
+ aSel.nStartPos = aSel.nEndPos;
+ pOutlinerView->SetSelection(aSel);
+
+ // show changes
+ pOutliner->SetUpdateLayout(true);
+ pOutlinerView->ShowCursor();
+}
+
+rtl::Reference< ::chart::AccessibleTextHelper >
+ ChartController::createAccessibleTextContext()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ return new AccessibleTextHelper( m_pDrawViewWrapper.get() );
+#else
+ return {};
+#endif
+}
+
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartController_Tools.cxx b/chart2/source/controller/main/ChartController_Tools.cxx
new file mode 100644
index 0000000000..48dbfaf7f6
--- /dev/null
+++ b/chart2/source/controller/main/ChartController_Tools.cxx
@@ -0,0 +1,1127 @@
+/* -*- 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 <ChartController.hxx>
+#include <ChartWindow.hxx>
+#include <ChartModel.hxx>
+#include <ChartModelHelper.hxx>
+#include <ChartType.hxx>
+#include <TitleHelper.hxx>
+#include <ThreeDHelper.hxx>
+#include <DataSeries.hxx>
+#include <DataSeriesHelper.hxx>
+#include "UndoGuard.hxx"
+#include <ControllerLockGuard.hxx>
+#include <ResId.hxx>
+#include <strings.hrc>
+#include <ObjectIdentifier.hxx>
+#include <ReferenceSizeProvider.hxx>
+#include <chartview/DrawModelWrapper.hxx>
+#include "ChartTransferable.hxx"
+#include <DrawViewWrapper.hxx>
+#include <Legend.hxx>
+#include <LegendHelper.hxx>
+#include <Axis.hxx>
+#include <AxisHelper.hxx>
+#include <RegressionCurveModel.hxx>
+#include <RegressionCurveHelper.hxx>
+#include "ShapeController.hxx"
+#include <DiagramHelper.hxx>
+#include <Diagram.hxx>
+#include <ObjectNameProvider.hxx>
+#include <unonames.hxx>
+
+#include <com/sun/star/awt/Gradient.hpp>
+#include <com/sun/star/chart2/DataPointLabel.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
+#include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
+#include <com/sun/star/chart/ErrorBarStyle.hpp>
+#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
+
+#include <docmodel/uno/UnoGradientTools.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/outliner.hxx>
+#include <svx/ActionDescriptionProvider.hxx>
+#include <vcl/transfer.hxx>
+#include <sot/storage.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/TypeSerializer.hxx>
+#include <svx/unomodel.hxx>
+#include <svx/svdmodel.hxx>
+#include <unotools/streamwrap.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/svditer.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/unopage.hxx>
+#include <svx/unoshape.hxx>
+#include <PropertyHelper.hxx>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <tools/debug.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <tools/UnitConversion.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace chart
+{
+
+namespace
+{
+
+bool lcl_deleteDataSeries(
+ std::u16string_view rCID,
+ const rtl::Reference<::chart::ChartModel> & xModel,
+ const Reference< document::XUndoManager > & xUndoManager )
+{
+ bool bResult = false;
+ rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rCID, xModel );
+ if( xSeries.is() && xModel.is())
+ {
+ rtl::Reference< ::chart::ChartType > xChartType =
+ DataSeriesHelper::getChartTypeOfSeries( xSeries, xModel->getFirstChartDiagram());
+ if( xChartType.is())
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_DATASERIES )),
+ xUndoManager );
+
+ rtl::Reference< Diagram > xDiagram = xModel->getFirstChartDiagram();
+ rtl::Reference< Axis > xAxis = xDiagram->getAttachedAxis( xSeries );
+
+ DataSeriesHelper::deleteSeries( xSeries, xChartType );
+
+ AxisHelper::hideAxisIfNoDataIsAttached( xAxis, xDiagram );
+
+ bResult = true;
+ aUndoGuard.commit();
+ }
+ }
+ return bResult;
+}
+
+bool lcl_deleteDataCurve(
+ std::u16string_view rCID,
+ const rtl::Reference<::chart::ChartModel> & xModel,
+ const Reference< document::XUndoManager > & xUndoManager )
+{
+ bool bResult = false;
+
+ uno::Reference< beans::XPropertySet > xProperties(
+ ObjectIdentifier::getObjectPropertySet( rCID, xModel));
+
+ uno::Reference< chart2::XRegressionCurve > xRegressionCurve( xProperties, uno::UNO_QUERY );
+
+ if( xRegressionCurve.is())
+ {
+ uno::Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer(
+ ObjectIdentifier::getObjectPropertySet(
+ ObjectIdentifier::getFullParentParticle( rCID ), xModel), uno::UNO_QUERY );
+
+ if( xRegressionCurveContainer.is())
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE )),
+ xUndoManager );
+
+ xRegressionCurveContainer->removeRegressionCurve( xRegressionCurve );
+
+ bResult = true;
+ aUndoGuard.commit();
+ }
+ }
+ return bResult;
+}
+
+} // anonymous namespace
+
+std::unique_ptr<ReferenceSizeProvider> ChartController::impl_createReferenceSizeProvider()
+{
+ awt::Size aPageSize( ChartModelHelper::getPageSize( getChartModel() ) );
+
+ return std::make_unique<ReferenceSizeProvider>(aPageSize, getChartModel());
+}
+
+void ChartController::impl_adaptDataSeriesAutoResize()
+{
+ std::unique_ptr<ReferenceSizeProvider> pRefSizeProvider(impl_createReferenceSizeProvider());
+ if (pRefSizeProvider)
+ pRefSizeProvider->setValuesAtAllDataSeries();
+}
+
+void ChartController::executeDispatch_NewArrangement()
+{
+ // remove manual positions at titles, legend and the diagram, remove manual
+ // size at the diagram
+
+ try
+ {
+ rtl::Reference<::chart::ChartModel> xModel( getChartModel() );
+ rtl::Reference< Diagram > xDiagram = xModel->getFirstChartDiagram();
+ if( xDiagram.is())
+ {
+ UndoGuard aUndoGuard(
+ SchResId( STR_ACTION_REARRANGE_CHART ),
+ m_xUndoManager );
+ ControllerLockGuardUNO aCtlLockGuard( xModel );
+
+ // diagram
+ xDiagram->setPropertyToDefault( "RelativeSize");
+ xDiagram->setPropertyToDefault( "RelativePosition");
+ xDiagram->setPropertyToDefault( "PosSizeExcludeAxes");
+
+ // 3d rotation
+ xDiagram->set3DSettingsToDefault();
+
+ // legend
+ rtl::Reference< Legend > xLegend = xDiagram->getLegend2();
+ if( xLegend.is())
+ {
+ xLegend->setPropertyToDefault( "RelativePosition");
+ xLegend->setPropertyToDefault( "RelativeSize");
+ xLegend->setPropertyToDefault( "AnchorPosition");
+ }
+
+ // titles
+ for( sal_Int32 eType = TitleHelper::TITLE_BEGIN;
+ eType < TitleHelper::NORMAL_TITLE_END;
+ ++eType )
+ {
+ rtl::Reference< Title > xTitleState =
+ TitleHelper::getTitle(
+ static_cast< TitleHelper::eTitleType >( eType ), xModel );
+ if( xTitleState.is())
+ xTitleState->setPropertyToDefault( "RelativePosition");
+ }
+
+ // regression curve equations
+ std::vector< rtl::Reference< RegressionCurveModel > > aRegressionCurves =
+ xDiagram->getAllRegressionCurvesNotMeanValueLine();
+
+ // reset equation position
+ for( const auto& xCurve : aRegressionCurves )
+ RegressionCurveHelper::resetEquationPosition( xCurve );
+
+ aUndoGuard.commit();
+ }
+ }
+ catch( const uno::RuntimeException & )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+}
+
+void ChartController::executeDispatch_ScaleText()
+{
+ SolarMutexGuard aSolarGuard;
+ UndoGuard aUndoGuard(
+ SchResId( STR_ACTION_SCALE_TEXT ),
+ m_xUndoManager );
+ ControllerLockGuardUNO aCtlLockGuard( getChartModel() );
+
+ std::unique_ptr<ReferenceSizeProvider> pRefSizeProv(impl_createReferenceSizeProvider());
+ OSL_ASSERT(pRefSizeProv);
+ if (pRefSizeProv)
+ pRefSizeProv->toggleAutoResizeState();
+
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_Paste()
+{
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+ if( !pChartWindow )
+ return;
+
+ Graphic aGraphic;
+ // paste location: center of window
+ Point aPos = pChartWindow->PixelToLogic( tools::Rectangle(Point{}, pChartWindow->GetSizePixel()).Center());
+
+ // handle different formats
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pChartWindow ));
+ if( aDataHelper.GetTransferable().is())
+ {
+ if ( aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ) )
+ {
+ tools::SvRef<SotTempStream> xStm;
+ if ( aDataHelper.GetSotStorageStream( SotClipboardFormatId::DRAWING, xStm ) )
+ {
+ xStm->Seek( 0 );
+ Reference< io::XInputStream > xInputStream( new utl::OInputStreamWrapper( *xStm ) );
+
+ std::unique_ptr< SdrModel > spModel(
+ new SdrModel());
+
+ if ( SvxDrawingLayerImport( spModel.get(), xInputStream ) )
+ {
+ impl_PasteShapes( spModel.get() );
+ }
+ }
+ }
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) )
+ {
+ // graphic exchange format (graphic manager bitmap format?)
+ tools::SvRef<SotTempStream> xStm;
+ if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::SVXB, xStm ))
+ {
+ TypeSerializer aSerializer(*xStm);
+ aSerializer.readGraphic(aGraphic);
+ }
+ }
+ else if( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ))
+ {
+ // meta file
+ GDIMetaFile aMetafile;
+ if( aDataHelper.GetGDIMetaFile( SotClipboardFormatId::GDIMETAFILE, aMetafile ))
+ aGraphic = Graphic( aMetafile );
+ }
+ else if( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP ))
+ {
+ // bitmap (non-graphic-manager)
+ BitmapEx aBmpEx;
+ if( aDataHelper.GetBitmapEx( SotClipboardFormatId::BITMAP, aBmpEx ))
+ aGraphic = Graphic( aBmpEx );
+ }
+ else if( aDataHelper.HasFormat( SotClipboardFormatId::STRING ))
+ {
+ OUString aString;
+ if( aDataHelper.GetString( SotClipboardFormatId::STRING, aString ) && m_pDrawModelWrapper )
+ {
+ if( m_pDrawViewWrapper )
+ {
+ OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView();
+ if( pOutlinerView )//in case of edit mode insert into edited string
+ pOutlinerView->InsertText( aString );
+ else
+ {
+ impl_PasteStringAsTextShape( aString, awt::Point( 0, 0 ) );
+ }
+ }
+ }
+ }
+ }
+
+ if( aGraphic.GetType() != GraphicType::NONE )
+ {
+ Reference< graphic::XGraphic > xGraphic( aGraphic.GetXGraphic());
+ if( xGraphic.is())
+ impl_PasteGraphic( xGraphic, aPos );
+ }
+}
+
+// note: aPosition is ignored for now. The object is always pasted centered to
+// the page
+void ChartController::impl_PasteGraphic(
+ uno::Reference< graphic::XGraphic > const & xGraphic,
+ const ::Point & /* aPosition */ )
+{
+ DBG_TESTSOLARMUTEX();
+ // note: the XPropertySet of the model is the old API. Also the property
+ // "AdditionalShapes" that is used there.
+ rtl::Reference< ChartModel > xModel = getChartModel();
+ DrawModelWrapper * pDrawModelWrapper( GetDrawModelWrapper());
+ if( ! (xGraphic.is() && xModel.is()))
+ return;
+ rtl::Reference<SvxGraphicObject> xGraphicShape = new SvxGraphicObject(nullptr);
+ xGraphicShape->setShapeKind(SdrObjKind::Graphic);
+
+ uno::Reference< drawing::XShapes > xPage = pDrawModelWrapper->getMainDrawPage();
+ if( xPage.is())
+ {
+ xPage->add( xGraphicShape );
+ //need to change the model state manually
+ xModel->setModified( true );
+ //select new shape
+ m_aSelection.setSelection( xGraphicShape );
+ m_aSelection.applySelection( m_pDrawViewWrapper.get() );
+ }
+ xGraphicShape->SvxShape::setPropertyValue( "Graphic", uno::Any( xGraphic ));
+
+ awt::Size aGraphicSize( 1000, 1000 );
+ bool bGotGraphicSize = false;
+ try
+ {
+ bGotGraphicSize = xGraphicShape->SvxShape::getPropertyValue( "Size100thMM") >>= aGraphicSize;
+ }
+ catch (css::beans::UnknownPropertyException& )
+ {}
+ auto pChartWindow(GetChartWindow());
+ // first try size in 100th mm, then pixel size
+ if( !bGotGraphicSize )
+ {
+ bool bGotSizePixel = false;
+ try
+ {
+ bGotSizePixel = xGraphicShape->SvxShape::getPropertyValue( "SizePixel") >>= aGraphicSize;
+ }
+ catch (css::beans::UnknownPropertyException& )
+ {}
+ if ( bGotSizePixel && pChartWindow )
+ {
+ ::Size aVCLSize( pChartWindow->PixelToLogic( Size( aGraphicSize.Width, aGraphicSize.Height )));
+ aGraphicSize.Width = aVCLSize.getWidth();
+ aGraphicSize.Height = aVCLSize.getHeight();
+ }
+ }
+ xGraphicShape->setSize( aGraphicSize );
+ xGraphicShape->setPosition( awt::Point( 0, 0 ) );
+}
+
+void ChartController::impl_PasteShapes( SdrModel* pModel )
+{
+ DrawModelWrapper* pDrawModelWrapper( GetDrawModelWrapper() );
+ if ( !(pDrawModelWrapper && m_pDrawViewWrapper) )
+ return;
+
+ Reference< drawing::XDrawPage > xDestPage( pDrawModelWrapper->getMainDrawPage() );
+ SdrPage* pDestPage = GetSdrPageFromXDrawPage( xDestPage );
+ if ( !pDestPage )
+ return;
+
+ Reference< drawing::XShape > xSelShape;
+ m_pDrawViewWrapper->BegUndo( SvxResId( RID_SVX_3D_UNDO_EXCHANGE_PASTE ) );
+ sal_uInt16 nCount = pModel->GetPageCount();
+ for ( sal_uInt16 i = 0; i < nCount; ++i )
+ {
+ const SdrPage* pPage = pModel->GetPage( i );
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ while ( aIter.IsMore() )
+ {
+ SdrObject* pObj(aIter.Next());
+ // Clone to new SdrModel
+ rtl::Reference<SdrObject> pNewObj;
+ if (pObj)
+ pNewObj = pObj->CloneSdrObject(pDrawModelWrapper->getSdrModel());
+
+ if ( pNewObj )
+ {
+ // set position
+ Reference< drawing::XShape > xShape( pNewObj->getUnoShape(), uno::UNO_QUERY );
+ if ( xShape.is() )
+ {
+ xShape->setPosition( awt::Point( 0, 0 ) );
+ }
+
+ pDestPage->InsertObject( pNewObj.get() );
+ m_pDrawViewWrapper->AddUndo( std::make_unique<SdrUndoInsertObj>( *pNewObj ) );
+ xSelShape = xShape;
+ }
+ }
+ }
+
+ rtl::Reference< ChartModel > xModifiable = getChartModel();
+ if ( xModifiable.is() )
+ {
+ xModifiable->setModified( true );
+ }
+
+ // select last inserted shape
+ m_aSelection.setSelection( xSelShape );
+ m_aSelection.applySelection( m_pDrawViewWrapper.get() );
+
+ m_pDrawViewWrapper->EndUndo();
+
+ impl_switchDiagramPositioningToExcludingPositioning();
+}
+
+void ChartController::impl_PasteStringAsTextShape( const OUString& rString, const awt::Point& rPosition )
+{
+ DrawModelWrapper* pDrawModelWrapper( GetDrawModelWrapper() );
+ if ( !(pDrawModelWrapper && m_pDrawViewWrapper) )
+ return;
+
+ const Reference< drawing::XDrawPage >& xDrawPage( pDrawModelWrapper->getMainDrawPage() );
+ OSL_ASSERT( xDrawPage.is() );
+
+ if ( !xDrawPage )
+ return;
+
+ try
+ {
+ rtl::Reference<SvxShapeText> xTextShape = new SvxShapeText(nullptr);
+ xTextShape->setShapeKind(SdrObjKind::Text);
+ xDrawPage->add( xTextShape );
+
+ xTextShape->setString( rString );
+
+ float fCharHeight = 10.0;
+ xTextShape->SvxShape::setPropertyValue( "TextAutoGrowHeight", uno::Any( true ) );
+ xTextShape->SvxShape::setPropertyValue( "TextAutoGrowWidth", uno::Any( true ) );
+ xTextShape->SvxShape::setPropertyValue( "CharHeight", uno::Any( fCharHeight ) );
+ xTextShape->SvxShape::setPropertyValue( "CharHeightAsian", uno::Any( fCharHeight ) );
+ xTextShape->SvxShape::setPropertyValue( "CharHeightComplex", uno::Any( fCharHeight ) );
+ xTextShape->SvxShape::setPropertyValue( "TextVerticalAdjust", uno::Any( drawing::TextVerticalAdjust_CENTER ) );
+ xTextShape->SvxShape::setPropertyValue( "TextHorizontalAdjust", uno::Any( drawing::TextHorizontalAdjust_CENTER ) );
+ xTextShape->SvxShape::setPropertyValue( "CharFontName", uno::Any( OUString("Albany") ) );
+
+ xTextShape->setPosition( rPosition );
+
+ m_aSelection.setSelection( xTextShape );
+ m_aSelection.applySelection( m_pDrawViewWrapper.get() );
+
+ SdrObject* pObj = DrawViewWrapper::getSdrObject( xTextShape );
+ if ( pObj )
+ {
+ m_pDrawViewWrapper->BegUndo( SvxResId( RID_SVX_3D_UNDO_EXCHANGE_PASTE ) );
+ m_pDrawViewWrapper->AddUndo( std::make_unique<SdrUndoInsertObj>( *pObj ) );
+ m_pDrawViewWrapper->EndUndo();
+
+ impl_switchDiagramPositioningToExcludingPositioning();
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+}
+
+void ChartController::executeDispatch_Copy()
+{
+ SolarMutexGuard aSolarGuard;
+ if (!m_pDrawViewWrapper)
+ return;
+
+ OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView();
+ if (pOutlinerView)
+ pOutlinerView->Copy();
+ else
+ {
+ SdrObject* pSelectedObj = nullptr;
+ ObjectIdentifier aSelOID(m_aSelection.getSelectedOID());
+
+ if (aSelOID.isAutoGeneratedObject())
+ pSelectedObj = m_pDrawModelWrapper->getNamedSdrObject( aSelOID.getObjectCID() );
+ else if (aSelOID.isAdditionalShape())
+ pSelectedObj = DrawViewWrapper::getSdrObject( aSelOID.getAdditionalShape() );
+
+ if (pSelectedObj)
+ {
+ Reference<datatransfer::clipboard::XClipboard> xClipboard(GetChartWindow()->GetClipboard());
+ if (xClipboard.is())
+ {
+ Reference< datatransfer::XTransferable > xTransferable(
+ new ChartTransferable(m_pDrawModelWrapper->getSdrModel(),
+ pSelectedObj, aSelOID.isAdditionalShape()));
+ xClipboard->setContents(xTransferable, Reference< datatransfer::clipboard::XClipboardOwner >());
+ }
+ }
+ }
+}
+
+void ChartController::executeDispatch_Cut()
+{
+ executeDispatch_Copy();
+ executeDispatch_Delete();
+}
+
+bool ChartController::isObjectDeleteable( const uno::Any& rSelection )
+{
+ ObjectIdentifier aSelOID( rSelection );
+ if ( aSelOID.isAutoGeneratedObject() )
+ {
+ const OUString& aSelObjCID( aSelOID.getObjectCID() );
+ ObjectType aObjectType(ObjectIdentifier::getObjectType( aSelObjCID ));
+
+ switch(aObjectType)
+ {
+ case OBJECTTYPE_TITLE:
+ case OBJECTTYPE_LEGEND:
+ case OBJECTTYPE_DATA_SERIES:
+ case OBJECTTYPE_LEGEND_ENTRY:
+ case OBJECTTYPE_DATA_CURVE_EQUATION:
+ case OBJECTTYPE_DATA_CURVE:
+ case OBJECTTYPE_DATA_AVERAGE_LINE:
+ case OBJECTTYPE_DATA_ERRORS_X:
+ case OBJECTTYPE_DATA_ERRORS_Y:
+ case OBJECTTYPE_DATA_ERRORS_Z:
+ case OBJECTTYPE_DATA_LABELS:
+ case OBJECTTYPE_DATA_LABEL:
+ case OBJECTTYPE_AXIS:
+ case OBJECTTYPE_GRID:
+ case OBJECTTYPE_SUBGRID:
+ return true;
+ default:
+ break;
+ }
+ }
+ else if ( aSelOID.isAdditionalShape() )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool ChartController::isShapeContext() const
+{
+ return m_aSelection.isAdditionalShapeSelected() ||
+ ( m_pDrawViewWrapper && m_pDrawViewWrapper->AreObjectsMarked() &&
+ ( m_pDrawViewWrapper->GetCurrentObjIdentifier() == SdrObjKind::Text ) );
+}
+
+void ChartController::impl_ClearSelection()
+{
+ if( m_aSelection.hasSelection())
+ {
+ m_aSelection.clearSelection();
+ impl_notifySelectionChangeListeners();
+ }
+}
+
+bool ChartController::executeDispatch_Delete()
+{
+ bool bReturn = false;
+
+ // remove the selected object
+ OUString aCID( m_aSelection.getSelectedCID() );
+ if( !aCID.isEmpty() )
+ {
+ if( !isObjectDeleteable( uno::Any( aCID ) ) )
+ return false;
+
+ //remove chart object
+ rtl::Reference< ChartModel > xChartDoc = getChartModel();
+ if( !xChartDoc.is() )
+ return false;
+
+ ObjectType aObjectType( ObjectIdentifier::getObjectType( aCID ));
+ switch( aObjectType )
+ {
+ case OBJECTTYPE_TITLE:
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_TITLE )),
+ m_xUndoManager );
+ TitleHelper::removeTitle(
+ ObjectIdentifier::getTitleTypeForCID( aCID ), getChartModel() );
+ bReturn = true;
+ aUndoGuard.commit();
+ break;
+ }
+ case OBJECTTYPE_LEGEND:
+ {
+ rtl::Reference< Diagram > xDiagram( xChartDoc->getFirstChartDiagram());
+ if( xDiagram.is())
+ {
+ rtl::Reference< Legend > xLegend( xDiagram->getLegend2() );
+ if( xLegend.is())
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_LEGEND )),
+ m_xUndoManager );
+ xLegend->setPropertyValue( "Show", uno::Any( false ));
+ bReturn = true;
+ aUndoGuard.commit();
+ }
+ }
+ break;
+ }
+
+ case OBJECTTYPE_DATA_SERIES:
+ bReturn = lcl_deleteDataSeries( aCID, getChartModel(), m_xUndoManager );
+ break;
+
+ case OBJECTTYPE_LEGEND_ENTRY:
+ {
+ ObjectType eParentObjectType = ObjectIdentifier::getObjectType(
+ ObjectIdentifier::getFullParentParticle( aCID ));
+ if( eParentObjectType == OBJECTTYPE_DATA_SERIES )
+ {
+ bReturn = lcl_deleteDataSeries( aCID, getChartModel(), m_xUndoManager );
+ }
+ else if( eParentObjectType == OBJECTTYPE_DATA_CURVE )
+ {
+ sal_Int32 nEndPos = aCID.lastIndexOf(':');
+ OUString aParentCID = aCID.copy(0, nEndPos);
+
+ bReturn = lcl_deleteDataCurve(aParentCID, getChartModel(), m_xUndoManager );
+ }
+ else if( eParentObjectType == OBJECTTYPE_DATA_AVERAGE_LINE )
+ {
+ executeDispatch_DeleteMeanValue();
+ bReturn = true;
+ }
+ break;
+ }
+
+ case OBJECTTYPE_DATA_AVERAGE_LINE:
+ {
+ uno::Reference< chart2::XRegressionCurveContainer > xRegCurveCnt(
+ ObjectIdentifier::getObjectPropertySet(
+ ObjectIdentifier::getFullParentParticle( aCID ), getChartModel()), uno::UNO_QUERY );
+ if( xRegCurveCnt.is())
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_AVERAGE_LINE )),
+ m_xUndoManager );
+ RegressionCurveHelper::removeMeanValueLine( xRegCurveCnt );
+ bReturn = true;
+ aUndoGuard.commit();
+ }
+ }
+ break;
+
+ case OBJECTTYPE_DATA_CURVE:
+ {
+ bReturn = lcl_deleteDataCurve( aCID, getChartModel(), m_xUndoManager );
+ }
+ break;
+
+ case OBJECTTYPE_DATA_CURVE_EQUATION:
+ {
+ uno::Reference< beans::XPropertySet > xEqProp(
+ ObjectIdentifier::getObjectPropertySet( aCID, getChartModel()));
+
+ if( xEqProp.is())
+ {
+ rtl::Reference<::chart::ChartModel> xModel( getChartModel() );
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE_EQUATION )),
+ m_xUndoManager );
+ {
+ ControllerLockGuardUNO aCtlLockGuard( xModel );
+ xEqProp->setPropertyValue( "ShowEquation", uno::Any( false ));
+ xEqProp->setPropertyValue( "XName", uno::Any( OUString("x") ));
+ xEqProp->setPropertyValue( "YName", uno::Any( OUString("f(x)") ));
+ xEqProp->setPropertyValue( "ShowCorrelationCoefficient", uno::Any( false ));
+ }
+ bReturn = true;
+ aUndoGuard.commit();
+ }
+ }
+ break;
+
+ case OBJECTTYPE_DATA_ERRORS_X:
+ case OBJECTTYPE_DATA_ERRORS_Y:
+ case OBJECTTYPE_DATA_ERRORS_Z:
+ {
+ uno::Reference< beans::XPropertySet > xErrorBarProp(
+ ObjectIdentifier::getObjectPropertySet( aCID, getChartModel() ));
+ if( xErrorBarProp.is())
+ {
+ TranslateId pId;
+
+ if ( aObjectType == OBJECTTYPE_DATA_ERRORS_X )
+ pId = STR_OBJECT_ERROR_BARS_X;
+ else if ( aObjectType == OBJECTTYPE_DATA_ERRORS_Y )
+ pId = STR_OBJECT_ERROR_BARS_Y;
+ else
+ pId = STR_OBJECT_ERROR_BARS_Z;
+
+ rtl::Reference<::chart::ChartModel> xModel( getChartModel() );
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId(pId)),
+ m_xUndoManager);
+ {
+ ControllerLockGuardUNO aCtlLockGuard( xModel );
+ xErrorBarProp->setPropertyValue(
+ "ErrorBarStyle",
+ uno::Any( css::chart::ErrorBarStyle::NONE ));
+ }
+ bReturn = true;
+ aUndoGuard.commit();
+ }
+ break;
+ }
+
+ case OBJECTTYPE_DATA_LABELS:
+ case OBJECTTYPE_DATA_LABEL:
+ {
+ uno::Reference< beans::XPropertySet > xObjectProperties =
+ ObjectIdentifier::getObjectPropertySet( aCID, getChartModel() );
+ if( xObjectProperties.is() )
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete,
+ SchResId( aObjectType == OBJECTTYPE_DATA_LABEL ? STR_OBJECT_LABEL : STR_OBJECT_DATALABELS )),
+ m_xUndoManager );
+ chart2::DataPointLabel aLabel;
+ xObjectProperties->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel;
+ aLabel.ShowNumber = false;
+ aLabel.ShowNumberInPercent = false;
+ aLabel.ShowCategoryName = false;
+ aLabel.ShowLegendSymbol = false;
+ aLabel.ShowCustomLabel = false;
+ aLabel.ShowSeriesName = false;
+ if( aObjectType == OBJECTTYPE_DATA_LABELS )
+ {
+ rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( aCID, getChartModel() );
+ DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, CHART_UNONAME_LABEL, uno::Any(aLabel) );
+ DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, CHART_UNONAME_CUSTOM_LABEL_FIELDS, uno::Any() );
+ }
+ else
+ {
+ xObjectProperties->setPropertyValue(CHART_UNONAME_LABEL, uno::Any(aLabel));
+ xObjectProperties->setPropertyValue(CHART_UNONAME_CUSTOM_LABEL_FIELDS, uno::Any());
+ }
+ bReturn = true;
+ aUndoGuard.commit();
+ }
+ break;
+ }
+ case OBJECTTYPE_AXIS:
+ {
+ executeDispatch_DeleteAxis();
+ bReturn = true;
+ break;
+ }
+ case OBJECTTYPE_GRID:
+ {
+ executeDispatch_DeleteMajorGrid();
+ bReturn = true;
+ break;
+ }
+ case OBJECTTYPE_SUBGRID:
+ {
+ executeDispatch_DeleteMinorGrid();
+ bReturn = true;
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ //remove additional shape
+ impl_ClearSelection();
+ {
+ SolarMutexGuard aSolarGuard;
+ if ( m_pDrawViewWrapper )
+ {
+ m_pDrawViewWrapper->DeleteMarked();
+ bReturn = true;
+ }
+ }
+ }
+ return bReturn;
+}
+
+void ChartController::executeDispatch_ToggleLegend()
+{
+ rtl::Reference< ChartModel > xModel = getChartModel();
+ UndoGuard aUndoGuard(
+ SchResId( STR_ACTION_TOGGLE_LEGEND ), m_xUndoManager );
+ rtl::Reference< Legend > xLegendProp = LegendHelper::getLegend(*xModel);
+ bool bChanged = false;
+ if( xLegendProp.is())
+ {
+ try
+ {
+ bool bShow = false;
+ if( xLegendProp->getPropertyValue( "Show") >>= bShow )
+ {
+ xLegendProp->setPropertyValue( "Show", uno::Any( ! bShow ));
+ bChanged = true;
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ }
+ else
+ {
+ xLegendProp = LegendHelper::getLegend(*xModel, m_xCC, true);
+ if( xLegendProp.is())
+ bChanged = true;
+ }
+
+ if( bChanged )
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_ToggleGridHorizontal()
+{
+ UndoGuard aUndoGuard(
+ SchResId( STR_ACTION_TOGGLE_GRID_HORZ ), m_xUndoManager );
+ rtl::Reference< Diagram > xDiagram( getFirstDiagram() );
+ if( !xDiagram.is())
+ return;
+
+ sal_Int32 nDimensionIndex = 1;
+ sal_Int32 nCooSysIndex = 0;
+
+ bool bHasMajorYGrid = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, true, xDiagram );
+ bool bHasMinorYGrid = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, false, xDiagram );
+
+ if( bHasMajorYGrid )
+ {
+ if ( bHasMinorYGrid )
+ {
+ AxisHelper::hideGrid( nDimensionIndex, nCooSysIndex, true, xDiagram );
+ AxisHelper::hideGrid( nDimensionIndex, nCooSysIndex, false, xDiagram );
+ }
+ else
+ {
+ AxisHelper::showGrid( nDimensionIndex, nCooSysIndex, false, xDiagram );
+ }
+ }
+ else
+ {
+ AxisHelper::showGrid( nDimensionIndex, nCooSysIndex, true, xDiagram );
+ }
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_ToggleGridVertical()
+{
+ UndoGuard aUndoGuard(
+ SchResId( STR_ACTION_TOGGLE_GRID_VERTICAL ), m_xUndoManager );
+ rtl::Reference< Diagram > xDiagram( getFirstDiagram() );
+ if( !xDiagram.is())
+ return;
+
+ sal_Int32 nDimensionIndex = 0;
+ sal_Int32 nCooSysIndex = 0;
+
+ bool bHasMajorXGrid = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, true, xDiagram );
+ bool bHasMinorXGrid = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, false, xDiagram );
+ if( bHasMajorXGrid )
+ {
+ if (bHasMinorXGrid)
+ {
+ AxisHelper::hideGrid( nDimensionIndex, nCooSysIndex, true, xDiagram );
+ AxisHelper::hideGrid( nDimensionIndex, nCooSysIndex, false, xDiagram );
+ }
+ else
+ {
+ AxisHelper::showGrid( nDimensionIndex, nCooSysIndex, false, xDiagram );
+ }
+ }
+ else
+ {
+ AxisHelper::showGrid( nDimensionIndex, nCooSysIndex, true, xDiagram );
+ }
+
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_FillColor(sal_uInt32 nColor)
+{
+ try
+ {
+ OUString aCID( m_aSelection.getSelectedCID() );
+ rtl::Reference<::chart::ChartModel> xChartModel = getChartModel();
+ if( xChartModel.is() )
+ {
+ Reference< beans::XPropertySet > xPointProperties(
+ ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) );
+ if( xPointProperties.is() )
+ xPointProperties->setPropertyValue( "FillColor", uno::Any( nColor ) );
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION( "chart2" );
+ }
+}
+
+void ChartController::executeDispatch_FillGradient(std::u16string_view sJSONGradient)
+{
+ basegfx::BGradient aBGradient = basegfx::BGradient::fromJSON(sJSONGradient);
+ css::awt::Gradient aGradient = model::gradient::createUnoGradient2(aBGradient);
+
+ try
+ {
+ OUString aCID( m_aSelection.getSelectedCID() );
+ rtl::Reference<::chart::ChartModel> xChartModel = getChartModel();
+
+ if( xChartModel.is() )
+ {
+ Reference< beans::XPropertySet > xPropSet(
+ ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) );
+
+ if( xPropSet.is() )
+ {
+ OUString aPrefferedName =
+ OUString::number(static_cast<sal_Int32>(Color(aBGradient.GetColorStops().front().getStopColor())))
+ + OUString::number(static_cast<sal_Int32>(Color(aBGradient.GetColorStops().back().getStopColor())))
+ + OUString::number(static_cast<sal_Int32>(aBGradient.GetAngle().get()));
+
+ OUString aNewName = PropertyHelper::addGradientUniqueNameToTable(css::uno::Any(aGradient),
+ xChartModel,
+ aPrefferedName);
+
+ xPropSet->setPropertyValue("FillGradientName", css::uno::Any(aNewName));
+ }
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+void ChartController::executeDispatch_LineColor(sal_uInt32 nColor)
+{
+ try
+ {
+ OUString aCID( m_aSelection.getSelectedCID() );
+ rtl::Reference<::chart::ChartModel> xChartModel = getChartModel();
+ if( xChartModel.is() )
+ {
+ Reference< beans::XPropertySet > xPropSet(
+ ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) );
+
+ ObjectType eType = ObjectIdentifier::getObjectType(aCID);
+ if (eType == OBJECTTYPE_DIAGRAM)
+ {
+ css::uno::Reference<css::chart2::XDiagram> xDiagram(
+ xPropSet, css::uno::UNO_QUERY);
+ if (xDiagram.is())
+ xPropSet.set(xDiagram->getWall());
+ }
+
+ if( xPropSet.is() )
+ xPropSet->setPropertyValue( "LineColor", css::uno::Any( Color(ColorTransparency, nColor) ) );
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION( "chart2" );
+ }
+}
+
+void ChartController::executeDispatch_LineWidth(sal_uInt32 nWidth)
+{
+ try
+ {
+ OUString aCID( m_aSelection.getSelectedCID() );
+ rtl::Reference<::chart::ChartModel> xChartModel = getChartModel();
+ if( xChartModel.is() )
+ {
+ Reference< beans::XPropertySet > xPropSet(
+ ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) );
+
+ ObjectType eType = ObjectIdentifier::getObjectType(aCID);
+ if (eType == OBJECTTYPE_DIAGRAM)
+ {
+ css::uno::Reference<css::chart2::XDiagram> xDiagram(
+ xPropSet, css::uno::UNO_QUERY);
+ if (xDiagram.is())
+ xPropSet.set(xDiagram->getWall());
+ }
+
+ if( xPropSet.is() )
+ xPropSet->setPropertyValue( "LineWidth", css::uno::Any( nWidth ) );
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION( "chart2" );
+ }
+}
+
+void ChartController::executeDispatch_LOKSetTextSelection(int nType, int nX, int nY)
+{
+ if (!m_pDrawViewWrapper)
+ return;
+
+ if (!m_pDrawViewWrapper->IsTextEdit())
+ return;
+
+ OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView();
+ if (!pOutlinerView)
+ return;
+
+ EditView& rEditView = pOutlinerView->GetEditView();
+ Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY));
+ switch (nType)
+ {
+ case LOK_SETTEXTSELECTION_START:
+ rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/false, /*bClearMark=*/false);
+ break;
+ case LOK_SETTEXTSELECTION_END:
+ rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/false);
+ break;
+ case LOK_SETTEXTSELECTION_RESET:
+ rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/true);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+void ChartController::executeDispatch_LOKPieSegmentDragging( int nOffset )
+{
+ try
+ {
+ OUString aCID( m_aSelection.getSelectedCID() );
+ rtl::Reference<::chart::ChartModel> xChartModel = getChartModel();
+ if( xChartModel.is() )
+ {
+ Reference< beans::XPropertySet > xPointProperties(
+ ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) );
+ if( xPointProperties.is() )
+ xPointProperties->setPropertyValue( "Offset", uno::Any( nOffset / 100.0 ) );
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+}
+
+void ChartController::impl_ShapeControllerDispatch( const util::URL& rURL, const Sequence< beans::PropertyValue >& rArgs )
+{
+ Reference< frame::XDispatch > xDispatch( m_aDispatchContainer.getShapeController() );
+ if ( xDispatch.is() )
+ {
+ xDispatch->dispatch( rURL, rArgs );
+ }
+}
+
+void ChartController::impl_switchDiagramPositioningToExcludingPositioning()
+{
+ UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::PosSize,
+ ObjectNameProvider::getName( OBJECTTYPE_DIAGRAM)),
+ m_xUndoManager );
+ if (DiagramHelper::switchDiagramPositioningToExcludingPositioning(*getChartModel(), true, true))
+ aUndoGuard.commit();
+}
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartController_Window.cxx b/chart2/source/controller/main/ChartController_Window.cxx
new file mode 100644
index 0000000000..1bdb1f2ed4
--- /dev/null
+++ b/chart2/source/controller/main/ChartController_Window.cxx
@@ -0,0 +1,2103 @@
+/* -*- 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 <sal/config.h>
+
+#include <string_view>
+
+#include <ChartController.hxx>
+#include <ChartView.hxx>
+#include <PositionAndSizeHelper.hxx>
+#include <ObjectIdentifier.hxx>
+#include <ChartWindow.hxx>
+#include <ResId.hxx>
+#include <ChartModel.hxx>
+#include <ChartModelHelper.hxx>
+#include <ChartType.hxx>
+#include <DiagramHelper.hxx>
+#include <Diagram.hxx>
+#include <TitleHelper.hxx>
+#include "UndoGuard.hxx"
+#include <ControllerLockGuard.hxx>
+#include <ObjectNameProvider.hxx>
+#include <strings.hrc>
+#include "DragMethod_PieSegment.hxx"
+#include "DragMethod_RotateDiagram.hxx"
+#include <ObjectHierarchy.hxx>
+#include <chartview/ExplicitValueProvider.hxx>
+#include <RelativePositionHelper.hxx>
+#include <chartview/DrawModelWrapper.hxx>
+#include <RegressionCurveHelper.hxx>
+#include <RegressionCurveModel.hxx>
+#include <StatisticsHelper.hxx>
+#include <DataSeries.hxx>
+#include <DataSeriesHelper.hxx>
+#include <DataSeriesProperties.hxx>
+#include <Axis.hxx>
+#include <AxisHelper.hxx>
+#include <LegendHelper.hxx>
+#include <servicenames_charttypes.hxx>
+#include "DrawCommandDispatch.hxx"
+#include <PopupRequest.hxx>
+#include "ControllerCommandDispatch.hxx"
+
+#include <com/sun/star/chart2/RelativePosition.hpp>
+#include <com/sun/star/chart2/RelativeSize.hpp>
+#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
+
+#include <com/sun/star/awt/PopupMenuDirection.hpp>
+#include <com/sun/star/frame/DispatchHelper.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/frame/XPopupMenuController.hpp>
+#include <com/sun/star/util/XUpdatable.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+
+#include <comphelper/lok.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <sfx2/viewsh.hxx>
+#include <svx/ActionDescriptionProvider.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/svddrgmt.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <svtools/acceleratorexecute.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <toolkit/awt/vclxmenu.hxx>
+#include <sal/log.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <boost/property_tree/json_parser.hpp>
+#include <sfx2/dispatch.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
+#define DRGPIX 2 // Drag MinMove in Pixel
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::chart2;
+using namespace ::chart::DataSeriesProperties;
+using ::com::sun::star::uno::Reference;
+
+namespace chart
+{
+
+namespace
+{
+bool lcl_GrowAndShiftLogic(
+ RelativePosition & rInOutRelPos,
+ RelativeSize & rInOutRelSize,
+ const awt::Size & rRefSize,
+ double fGrowLogicX,
+ double fGrowLogicY )
+{
+ if( rRefSize.Width == 0 ||
+ rRefSize.Height == 0 )
+ return false;
+
+ double fRelativeGrowX = fGrowLogicX / rRefSize.Width;
+ double fRelativeGrowY = fGrowLogicY / rRefSize.Height;
+
+ return ::chart::RelativePositionHelper::centerGrow(
+ rInOutRelPos, rInOutRelSize,
+ fRelativeGrowX, fRelativeGrowY );
+}
+
+bool lcl_MoveObjectLogic(
+ RelativePosition & rInOutRelPos,
+ RelativeSize const & rObjectSize,
+ const awt::Size & rRefSize,
+ double fShiftLogicX,
+ double fShiftLogicY )
+{
+ if( rRefSize.Width == 0 ||
+ rRefSize.Height == 0 )
+ return false;
+
+ double fRelativeShiftX = fShiftLogicX / rRefSize.Width;
+ double fRelativeShiftY = fShiftLogicY / rRefSize.Height;
+
+ return ::chart::RelativePositionHelper::moveObject(
+ rInOutRelPos, rObjectSize,
+ fRelativeShiftX, fRelativeShiftY );
+}
+
+void lcl_insertMenuCommand(
+ const uno::Reference< awt::XPopupMenu > & xMenu,
+ sal_Int16 nId, const OUString & rCommand )
+{
+ xMenu->insertItem( nId, "", 0, -1 );
+ xMenu->setCommand( nId, rCommand );
+}
+
+OUString lcl_getFormatCommandForObjectCID( std::u16string_view rCID )
+{
+ OUString aDispatchCommand( ".uno:FormatSelection" );
+
+ ObjectType eObjectType = ObjectIdentifier::getObjectType( rCID );
+
+ switch(eObjectType)
+ {
+ case OBJECTTYPE_DIAGRAM:
+ case OBJECTTYPE_DIAGRAM_WALL:
+ aDispatchCommand = ".uno:FormatWall";
+ break;
+ case OBJECTTYPE_DIAGRAM_FLOOR:
+ aDispatchCommand = ".uno:FormatFloor";
+ break;
+ case OBJECTTYPE_PAGE:
+ aDispatchCommand = ".uno:FormatChartArea";
+ break;
+ case OBJECTTYPE_LEGEND:
+ aDispatchCommand = ".uno:FormatLegend";
+ break;
+ case OBJECTTYPE_TITLE:
+ aDispatchCommand = ".uno:FormatTitle";
+ break;
+ case OBJECTTYPE_LEGEND_ENTRY:
+ aDispatchCommand = ".uno:FormatDataSeries";
+ break;
+ case OBJECTTYPE_AXIS:
+ case OBJECTTYPE_AXIS_UNITLABEL:
+ aDispatchCommand = ".uno:FormatAxis";
+ break;
+ case OBJECTTYPE_GRID:
+ aDispatchCommand = ".uno:FormatMajorGrid";
+ break;
+ case OBJECTTYPE_SUBGRID:
+ aDispatchCommand = ".uno:FormatMinorGrid";
+ break;
+ case OBJECTTYPE_DATA_LABELS:
+ aDispatchCommand = ".uno:FormatDataLabels";
+ break;
+ case OBJECTTYPE_DATA_SERIES:
+ aDispatchCommand = ".uno:FormatDataSeries";
+ break;
+ case OBJECTTYPE_DATA_LABEL:
+ aDispatchCommand = ".uno:FormatDataLabel";
+ break;
+ case OBJECTTYPE_DATA_POINT:
+ aDispatchCommand = ".uno:FormatDataPoint";
+ break;
+ case OBJECTTYPE_DATA_AVERAGE_LINE:
+ aDispatchCommand = ".uno:FormatMeanValue";
+ break;
+ case OBJECTTYPE_DATA_ERRORS_X:
+ aDispatchCommand = ".uno:FormatXErrorBars";
+ break;
+ case OBJECTTYPE_DATA_ERRORS_Y:
+ aDispatchCommand = ".uno:FormatYErrorBars";
+ break;
+ case OBJECTTYPE_DATA_ERRORS_Z:
+ aDispatchCommand = ".uno:FormatZErrorBars";
+ break;
+ case OBJECTTYPE_DATA_CURVE:
+ aDispatchCommand = ".uno:FormatTrendline";
+ break;
+ case OBJECTTYPE_DATA_CURVE_EQUATION:
+ aDispatchCommand = ".uno:FormatTrendlineEquation";
+ break;
+ case OBJECTTYPE_DATA_STOCK_RANGE:
+ aDispatchCommand = ".uno:FormatSelection";
+ break;
+ case OBJECTTYPE_DATA_STOCK_LOSS:
+ aDispatchCommand = ".uno:FormatStockLoss";
+ break;
+ case OBJECTTYPE_DATA_STOCK_GAIN:
+ aDispatchCommand = ".uno:FormatStockGain";
+ break;
+ default: //OBJECTTYPE_UNKNOWN
+ break;
+ }
+ return aDispatchCommand;
+}
+
+} // anonymous namespace
+
+// awt::XWindow
+void SAL_CALL ChartController::setPosSize(
+ sal_Int32 X,
+ sal_Int32 Y,
+ sal_Int32 Width,
+ sal_Int32 Height,
+ sal_Int16 Flags )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+ auto pChartWindow(GetChartWindow());
+
+ if(!(xWindow.is() && pChartWindow))
+ return;
+
+ Size aLogicSize = pChartWindow->PixelToLogic( Size( Width, Height ), MapMode( MapUnit::Map100thMM ) );
+
+ //todo: for standalone chart: detect whether we are standalone
+ //change map mode to fit new size
+ awt::Size aModelPageSize = ChartModelHelper::getPageSize( getChartModel() );
+ sal_Int32 nScaleXNumerator = aLogicSize.Width();
+ sal_Int32 nScaleXDenominator = aModelPageSize.Width;
+ sal_Int32 nScaleYNumerator = aLogicSize.Height();
+ sal_Int32 nScaleYDenominator = aModelPageSize.Height;
+ MapMode aNewMapMode(
+ MapUnit::Map100thMM,
+ Point(0,0),
+ Fraction(nScaleXNumerator, nScaleXDenominator),
+ Fraction(nScaleYNumerator, nScaleYDenominator) );
+ pChartWindow->SetMapMode(aNewMapMode);
+ pChartWindow->setPosSizePixel( X, Y, Width, Height, static_cast<PosSizeFlags>(Flags) );
+
+ //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100%
+ if( m_xChartView.is() )
+ {
+ auto aZoomFactors(::comphelper::InitPropertySequence({
+ { "ScaleXNumerator", uno::Any( nScaleXNumerator ) },
+ { "ScaleXDenominator", uno::Any( nScaleXDenominator ) },
+ { "ScaleYNumerator", uno::Any( nScaleYNumerator ) },
+ { "ScaleYDenominator", uno::Any( nScaleYDenominator ) }
+ }));
+ m_xChartView->setPropertyValue( "ZoomFactors", uno::Any( aZoomFactors ));
+ }
+
+ //a correct work area is at least necessary for correct values in the position and size dialog and for dragging area
+ if(m_pDrawViewWrapper)
+ {
+ tools::Rectangle aRect(Point(0,0), pChartWindow->GetOutDev()->GetOutputSize());
+ m_pDrawViewWrapper->SetWorkArea( aRect );
+ }
+ pChartWindow->Invalidate();
+}
+
+awt::Rectangle SAL_CALL ChartController::getPosSize()
+{
+ //@todo
+ awt::Rectangle aRet(0, 0, 0, 0);
+
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+ if(xWindow.is())
+ aRet = xWindow->getPosSize();
+
+ return aRet;
+}
+
+void SAL_CALL ChartController::setVisible( sal_Bool Visible )
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->setVisible( Visible );
+}
+
+void SAL_CALL ChartController::setEnable( sal_Bool Enable )
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->setEnable( Enable );
+}
+
+void SAL_CALL ChartController::setFocus()
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->setFocus();
+}
+
+void SAL_CALL ChartController::addWindowListener(
+ const uno::Reference< awt::XWindowListener >& xListener )
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->addWindowListener( xListener );
+}
+
+void SAL_CALL ChartController::removeWindowListener(
+ const uno::Reference< awt::XWindowListener >& xListener )
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->removeWindowListener( xListener );
+}
+
+void SAL_CALL ChartController::addFocusListener(
+ const uno::Reference< awt::XFocusListener >& xListener )
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->addFocusListener( xListener );
+}
+
+void SAL_CALL ChartController::removeFocusListener(
+ const uno::Reference< awt::XFocusListener >& xListener )
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->removeFocusListener( xListener );
+}
+
+void SAL_CALL ChartController::addKeyListener(
+ const uno::Reference< awt::XKeyListener >& xListener )
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->addKeyListener( xListener );
+}
+
+void SAL_CALL ChartController::removeKeyListener(
+ const uno::Reference< awt::XKeyListener >& xListener )
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->removeKeyListener( xListener );
+}
+
+void SAL_CALL ChartController::addMouseListener(
+ const uno::Reference< awt::XMouseListener >& xListener )
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->addMouseListener( xListener );
+}
+
+void SAL_CALL ChartController::removeMouseListener(
+ const uno::Reference< awt::XMouseListener >& xListener )
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->removeMouseListener( xListener );
+}
+
+void SAL_CALL ChartController::addMouseMotionListener(
+ const uno::Reference< awt::XMouseMotionListener >& xListener )
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->addMouseMotionListener( xListener );
+}
+
+void SAL_CALL ChartController::removeMouseMotionListener(
+ const uno::Reference< awt::XMouseMotionListener >& xListener )
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->removeMouseMotionListener( xListener );
+}
+
+void SAL_CALL ChartController::addPaintListener(
+ const uno::Reference< awt::XPaintListener >& xListener )
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->addPaintListener( xListener );
+}
+
+void SAL_CALL ChartController::removePaintListener(
+ const uno::Reference< awt::XPaintListener >& xListener )
+{
+ //@todo
+ uno::Reference<awt::XWindow> xWindow = m_xViewWindow;
+
+ if(xWindow.is())
+ xWindow->removePaintListener( xListener );
+}
+
+// impl vcl window controller methods
+void ChartController::PrePaint()
+{
+ // forward VCLs PrePaint window event to DrawingLayer
+ DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get();
+
+ if (pDrawViewWrapper)
+ {
+ pDrawViewWrapper->PrePaint();
+ }
+}
+
+void ChartController::execute_Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ try
+ {
+ rtl::Reference<ChartModel> xModel(getChartModel());
+ //OSL_ENSURE( xModel.is(), "ChartController::execute_Paint: have no model to paint");
+ if (!xModel.is())
+ return;
+
+ //better performance for big data
+ if (m_xChartView.is())
+ {
+ awt::Size aResolution(1000, 1000);
+ {
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+ if (pChartWindow)
+ {
+ aResolution.Width = pChartWindow->GetSizePixel().Width();
+ aResolution.Height = pChartWindow->GetSizePixel().Height();
+ }
+ }
+ m_xChartView->setPropertyValue( "Resolution", uno::Any( aResolution ));
+ }
+
+ if (m_xChartView.is())
+ m_xChartView->update();
+
+ {
+ SolarMutexGuard aGuard;
+ DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get();
+ if (pDrawViewWrapper)
+ pDrawViewWrapper->CompleteRedraw(&rRenderContext, vcl::Region(rRect));
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ catch( ... )
+ {
+ }
+}
+
+static bool isDoubleClick( const MouseEvent& rMEvt )
+{
+ return rMEvt.GetClicks() == 2 && rMEvt.IsLeft() &&
+ !rMEvt.IsMod1() && !rMEvt.IsMod2() && !rMEvt.IsShift();
+}
+
+void ChartController::startDoubleClickWaiting()
+{
+ SolarMutexGuard aGuard;
+
+ m_bWaitingForDoubleClick = true;
+
+ sal_uInt64 nDblClkTime = 500;
+ auto pChartWindow(GetChartWindow());
+ if( pChartWindow )
+ {
+ const MouseSettings& rMSettings = pChartWindow->GetSettings().GetMouseSettings();
+ nDblClkTime = rMSettings.GetDoubleClickTime();
+ }
+ m_aDoubleClickTimer.SetTimeout( nDblClkTime );
+ m_aDoubleClickTimer.Start();
+}
+
+void ChartController::stopDoubleClickWaiting()
+{
+ m_aDoubleClickTimer.Stop();
+ m_bWaitingForDoubleClick = false;
+}
+
+IMPL_LINK_NOARG(ChartController, DoubleClickWaitingHdl, Timer *, void)
+{
+ m_bWaitingForDoubleClick = false;
+
+ if( m_bWaitingForMouseUp || !m_aSelection.maybeSwitchSelectionAfterSingleClickWasEnsured() )
+ return;
+
+ impl_selectObjectAndNotiy();
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+ if( pChartWindow )
+ {
+ vcl::Window::PointerState aPointerState( pChartWindow->GetPointerState() );
+ MouseEvent aMouseEvent(
+ aPointerState.maPos,
+ 1/*nClicks*/,
+ MouseEventModifiers::NONE,
+ static_cast< sal_uInt16 >( aPointerState.mnState )/*nButtons*/,
+ 0/*nModifier*/ );
+ impl_SetMousePointer( aMouseEvent );
+ }
+}
+
+void ChartController::execute_MouseButtonDown( const MouseEvent& rMEvt )
+{
+ SolarMutexGuard aGuard;
+
+ m_bWaitingForMouseUp = true;
+ m_bFieldButtonDown = false;
+
+ if( isDoubleClick(rMEvt) )
+ stopDoubleClickWaiting();
+ else
+ startDoubleClickWaiting();
+
+ m_aSelection.remindSelectionBeforeMouseDown();
+
+ DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get();
+ auto pChartWindow(GetChartWindow());
+ if(!pChartWindow || !pDrawViewWrapper )
+ return;
+
+ Point aMPos = pChartWindow->PixelToLogic(rMEvt.GetPosPixel());
+
+ // Check if button was clicked
+ SdrObject* pObject = pDrawViewWrapper->getHitObject(aMPos);
+ if (pObject)
+ {
+ OUString aCID = pObject->GetName();
+ if (aCID.startsWith("FieldButton"))
+ {
+ m_bFieldButtonDown = true;
+ return; // Don't take any action if button was clicked
+ }
+ }
+
+ if ( rMEvt.GetButtons() == MOUSE_LEFT )
+ {
+ pChartWindow->GrabFocus();
+ pChartWindow->CaptureMouse();
+ }
+
+ if( pDrawViewWrapper->IsTextEdit() )
+ {
+ SdrViewEvent aVEvt;
+ if ( pDrawViewWrapper->IsTextEditHit( aMPos ) ||
+ // #i12587# support for shapes in chart
+ ( rMEvt.IsRight() && pDrawViewWrapper->PickAnything( rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt ) == SdrHitKind::MarkedObject ) )
+ {
+ pDrawViewWrapper->MouseButtonDown(rMEvt, pChartWindow->GetOutDev());
+ return;
+ }
+ else
+ {
+ EndTextEdit();
+ }
+ }
+
+ //abort running action
+ if( pDrawViewWrapper->IsAction() )
+ {
+ if( rMEvt.IsRight() )
+ pDrawViewWrapper->BckAction();
+ return;
+ }
+
+ if( isDoubleClick(rMEvt) ) //do not change selection if double click
+ return;//double click is handled further in mousebutton up
+
+ SdrHdl* pHitSelectionHdl = nullptr;
+ //switch from move to resize if handle is hit on a resizable object
+ if( m_aSelection.isResizeableObjectSelected() )
+ pHitSelectionHdl = pDrawViewWrapper->PickHandle( aMPos );
+ //only change selection if no selection handles are hit
+ if( !pHitSelectionHdl )
+ {
+ // #i12587# support for shapes in chart
+ if ( m_eDrawMode == CHARTDRAW_INSERT &&
+ ( !pDrawViewWrapper->IsMarkedHit( aMPos ) || !m_aSelection.isDragableObjectSelected() ) )
+ {
+ if ( m_aSelection.hasSelection() )
+ {
+ m_aSelection.clearSelection();
+ }
+ if ( !pDrawViewWrapper->IsAction() )
+ {
+ if ( pDrawViewWrapper->GetCurrentObjIdentifier() == SdrObjKind::Caption )
+ {
+ Size aCaptionSize( 2268, 1134 );
+ pDrawViewWrapper->BegCreateCaptionObj( aMPos, aCaptionSize );
+ }
+ else
+ {
+ pDrawViewWrapper->BegCreateObj( aMPos);
+ }
+ SdrObject* pObj = pDrawViewWrapper->GetCreateObj();
+ DrawCommandDispatch* pDrawCommandDispatch = m_aDispatchContainer.getDrawCommandDispatch();
+ if ( pObj && m_pDrawModelWrapper && pDrawCommandDispatch )
+ {
+ SfxItemSet aSet( m_pDrawModelWrapper->GetItemPool() );
+ pDrawCommandDispatch->setAttributes( pObj );
+ pDrawCommandDispatch->setLineEnds( aSet );
+ pObj->SetMergedItemSet( aSet );
+ }
+ }
+ impl_SetMousePointer( rMEvt );
+ return;
+ }
+
+ m_aSelection.adaptSelectionToNewPos(
+ aMPos,
+ pDrawViewWrapper,
+ rMEvt.IsRight(),
+ m_bWaitingForDoubleClick );
+
+ if( !m_aSelection.isRotateableObjectSelected( getChartModel() ) )
+ {
+ m_eDragMode = SdrDragMode::Move;
+ pDrawViewWrapper->SetDragMode(m_eDragMode);
+ }
+
+ m_aSelection.applySelection(pDrawViewWrapper);
+ }
+ if( m_aSelection.isDragableObjectSelected()
+ && !rMEvt.IsRight() )
+ {
+ //start drag
+ sal_uInt16 nDrgLog = static_cast<sal_uInt16>(pChartWindow->PixelToLogic(Size(DRGPIX,0)).Width());
+ SdrDragMethod* pDragMethod = nullptr;
+
+ //change selection to 3D scene if rotate mode
+ SdrDragMode eDragMode = pDrawViewWrapper->GetDragMode();
+ if( eDragMode==SdrDragMode::Rotate )
+ {
+ E3dScene* pScene = SelectionHelper::getSceneToRotate( pDrawViewWrapper->getNamedSdrObject( m_aSelection.getSelectedCID() ) );
+ if( pScene )
+ {
+ DragMethod_RotateDiagram::RotationDirection eRotationDirection(DragMethod_RotateDiagram::ROTATIONDIRECTION_FREE);
+ if(pHitSelectionHdl)
+ {
+ SdrHdlKind eKind = pHitSelectionHdl->GetKind();
+ if( eKind==SdrHdlKind::Upper || eKind==SdrHdlKind::Lower )
+ eRotationDirection = DragMethod_RotateDiagram::ROTATIONDIRECTION_X;
+ else if( eKind==SdrHdlKind::Left || eKind==SdrHdlKind::Right )
+ eRotationDirection = DragMethod_RotateDiagram::ROTATIONDIRECTION_Y;
+ else if( eKind==SdrHdlKind::UpperLeft || eKind==SdrHdlKind::UpperRight || eKind==SdrHdlKind::LowerLeft || eKind==SdrHdlKind::LowerRight )
+ eRotationDirection = DragMethod_RotateDiagram::ROTATIONDIRECTION_Z;
+ }
+ pDragMethod = new DragMethod_RotateDiagram( *pDrawViewWrapper, m_aSelection.getSelectedCID(), getChartModel(), eRotationDirection );
+ }
+ }
+ else
+ {
+ std::u16string_view aDragMethodServiceName( ObjectIdentifier::getDragMethodServiceName( m_aSelection.getSelectedCID() ) );
+ if( aDragMethodServiceName == ObjectIdentifier::getPieSegmentDragMethodServiceName() )
+ pDragMethod = new DragMethod_PieSegment( *pDrawViewWrapper, m_aSelection.getSelectedCID(), getChartModel() );
+ }
+ pDrawViewWrapper->SdrView::BegDragObj(aMPos, nullptr, pHitSelectionHdl, nDrgLog, pDragMethod);
+ }
+
+ impl_SetMousePointer( rMEvt );
+}
+
+void ChartController::execute_MouseMove( const MouseEvent& rMEvt )
+{
+ SolarMutexGuard aGuard;
+
+ DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get();
+ auto pChartWindow(GetChartWindow());
+ if(!pChartWindow || !pDrawViewWrapper)
+ return;
+
+ if( m_pDrawViewWrapper->IsTextEdit() )
+ {
+ if( m_pDrawViewWrapper->MouseMove(rMEvt,pChartWindow->GetOutDev()) )
+ return;
+ }
+
+ if(pDrawViewWrapper->IsAction())
+ {
+ pDrawViewWrapper->MovAction( pChartWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+ }
+
+ impl_SetMousePointer( rMEvt );
+}
+
+void ChartController::execute_MouseButtonUp( const MouseEvent& rMEvt )
+{
+ ControllerLockGuardUNO aCLGuard( getChartModel() );
+ bool bMouseUpWithoutMouseDown = !m_bWaitingForMouseUp;
+ m_bWaitingForMouseUp = false;
+ bool bNotifySelectionChange = false;
+ {
+ SolarMutexGuard aGuard;
+
+ DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get();
+ auto pChartWindow(GetChartWindow());
+ if(!pChartWindow || !pDrawViewWrapper)
+ return;
+
+ Point aMPos = pChartWindow->PixelToLogic(rMEvt.GetPosPixel());
+
+ // Check if button was clicked
+ if (m_bFieldButtonDown)
+ {
+ m_bFieldButtonDown = false;
+ SdrObject* pObject = pDrawViewWrapper->getHitObject(aMPos);
+ if (pObject)
+ {
+ OUString aCID = pObject->GetName();
+ if (aCID.startsWith("FieldButton"))
+ {
+ sendPopupRequest(aCID, pObject->GetCurrentBoundRect());
+ return;
+ }
+ }
+ }
+
+ if(pDrawViewWrapper->IsTextEdit())
+ {
+ if( pDrawViewWrapper->MouseButtonUp(rMEvt,pChartWindow->GetOutDev()) )
+ return;
+ }
+
+ // #i12587# support for shapes in chart
+ if ( m_eDrawMode == CHARTDRAW_INSERT && pDrawViewWrapper->IsCreateObj() )
+ {
+ pDrawViewWrapper->EndCreateObj( SdrCreateCmd::ForceEnd );
+ {
+ HiddenUndoContext aUndoContext( m_xUndoManager );
+ // don't want the positioning Undo action to appear in the UI
+ impl_switchDiagramPositioningToExcludingPositioning();
+ }
+ if ( pDrawViewWrapper->AreObjectsMarked() )
+ {
+ if ( pDrawViewWrapper->GetCurrentObjIdentifier() == SdrObjKind::Text )
+ {
+ executeDispatch_EditText();
+ }
+ else
+ {
+ SdrObject* pObj = pDrawViewWrapper->getSelectedObject();
+ if ( pObj )
+ {
+ uno::Reference< drawing::XShape > xShape( pObj->getUnoShape(), uno::UNO_QUERY );
+ if ( xShape.is() )
+ {
+ m_aSelection.setSelection( xShape );
+ m_aSelection.applySelection( pDrawViewWrapper );
+ }
+ }
+ }
+ }
+ else
+ {
+ m_aSelection.adaptSelectionToNewPos( aMPos, pDrawViewWrapper, rMEvt.IsRight(), m_bWaitingForDoubleClick );
+ m_aSelection.applySelection( pDrawViewWrapper );
+ setDrawMode( CHARTDRAW_SELECT );
+ }
+ }
+ else if ( pDrawViewWrapper->IsDragObj() )
+ {
+ bool bDraggingDone = false;
+ SdrDragMethod* pDragMethod = pDrawViewWrapper->SdrView::GetDragMethod();
+ bool bIsMoveOnly = pDragMethod && pDragMethod->getMoveOnly();
+ DragMethod_Base* pChartDragMethod = dynamic_cast< DragMethod_Base* >(pDragMethod);
+ if( pChartDragMethod )
+ {
+ UndoGuard aUndoGuard( pChartDragMethod->getUndoDescription(),
+ m_xUndoManager );
+
+ if( pDrawViewWrapper->EndDragObj() )
+ {
+ bDraggingDone = true;
+ aUndoGuard.commit();
+ }
+ }
+
+ if( !bDraggingDone && pDrawViewWrapper->EndDragObj() )
+ {
+ try
+ {
+ //end move or size
+ SdrObject* pObj = pDrawViewWrapper->getSelectedObject();
+ if( pObj )
+ {
+ tools::Rectangle aObjectRect = pObj->GetSnapRect();
+ tools::Rectangle aOldObjectRect = pObj->GetLastBoundRect();
+ awt::Size aPageSize( ChartModelHelper::getPageSize( getChartModel() ) );
+ tools::Rectangle aPageRect( 0,0,aPageSize.Width,aPageSize.Height );
+
+ const E3dObject* pE3dObject(DynCastE3dObject(pObj));
+ if(nullptr != pE3dObject)
+ {
+ E3dScene* pScene(pE3dObject->getRootE3dSceneFromE3dObject());
+ if(nullptr != pScene)
+ {
+ aObjectRect = pScene->GetSnapRect();
+ }
+ }
+
+ ActionDescriptionProvider::ActionType eActionType(ActionDescriptionProvider::ActionType::Move);
+ if( !bIsMoveOnly && m_aSelection.isResizeableObjectSelected() )
+ eActionType = ActionDescriptionProvider::ActionType::Resize;
+
+ ObjectType eObjectType = ObjectIdentifier::getObjectType( m_aSelection.getSelectedCID() );
+
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription( eActionType, ObjectNameProvider::getName( eObjectType)),
+ m_xUndoManager );
+
+ bool bChanged = false;
+ rtl::Reference< ChartModel > xModel = getChartModel();
+ if ( eObjectType == OBJECTTYPE_LEGEND )
+ bChanged = DiagramHelper::switchDiagramPositioningToExcludingPositioning( *xModel, false , true );
+
+ bool bMoved = PositionAndSizeHelper::moveObject( m_aSelection.getSelectedCID()
+ , xModel
+ , awt::Rectangle(aObjectRect.Left(),aObjectRect.Top(),aObjectRect.getOpenWidth(),aObjectRect.getOpenHeight())
+ , awt::Rectangle(aOldObjectRect.Left(), aOldObjectRect.Top(), 0, 0)
+ , awt::Rectangle(aPageRect.Left(),aPageRect.Top(),aPageRect.getOpenWidth(),aPageRect.getOpenHeight()) );
+
+ if( bMoved || bChanged )
+ {
+ bDraggingDone = true;
+ aUndoGuard.commit();
+ }
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ //all wanted model changes will take effect
+ //and all unwanted view modifications are cleaned
+ }
+
+ if( !bDraggingDone ) //mouse wasn't moved while dragging
+ {
+ bool bClickedTwiceOnDragableObject = SelectionHelper::isDragableObjectHitTwice( aMPos, m_aSelection.getSelectedCID(), *pDrawViewWrapper );
+ bool bIsRotateable = m_aSelection.isRotateableObjectSelected( getChartModel() );
+
+ //toggle between move and rotate
+ if( bIsRotateable && bClickedTwiceOnDragableObject && m_eDragMode==SdrDragMode::Move )
+ m_eDragMode=SdrDragMode::Rotate;
+ else
+ m_eDragMode=SdrDragMode::Move;
+
+ pDrawViewWrapper->SetDragMode(m_eDragMode);
+
+ if( !m_bWaitingForDoubleClick && m_aSelection.maybeSwitchSelectionAfterSingleClickWasEnsured() )
+ {
+ impl_selectObjectAndNotiy();
+ }
+ }
+ else
+ m_aSelection.resetPossibleSelectionAfterSingleClickWasEnsured();
+ }
+
+ //@todo ForcePointer(&rMEvt);
+ pChartWindow->ReleaseMouse();
+
+ // In tiled rendering drag mode could be not yet over on the call
+ // that should handle the double-click, so better to perform this check
+ // always.
+ if( isDoubleClick(rMEvt) && !bMouseUpWithoutMouseDown /*#i106966#*/ )
+ {
+ Point aMousePixel = rMEvt.GetPosPixel();
+ execute_DoubleClick( &aMousePixel );
+ }
+
+ if( m_aSelection.isSelectionDifferentFromBeforeMouseDown() )
+ bNotifySelectionChange = true;
+ }
+
+ impl_SetMousePointer( rMEvt );
+
+ if(bNotifySelectionChange)
+ impl_notifySelectionChangeListeners();
+}
+
+void ChartController::execute_DoubleClick( const Point* pMousePixel )
+{
+ const SfxViewShell* pViewShell = SfxViewShell::Current();
+ bool isMobilePhone = pViewShell && pViewShell->isLOKMobilePhone();
+ if (isMobilePhone)
+ return;
+
+ bool bEditText = false;
+ if ( m_aSelection.hasSelection() )
+ {
+ OUString aCID( m_aSelection.getSelectedCID() );
+ if ( !aCID.isEmpty() )
+ {
+ ObjectType eObjectType = ObjectIdentifier::getObjectType( aCID );
+ if ( eObjectType == OBJECTTYPE_TITLE )
+ {
+ bEditText = true;
+ }
+ }
+ else
+ {
+ // #i12587# support for shapes in chart
+ SdrObject* pObj = DrawViewWrapper::getSdrObject( m_aSelection.getSelectedAdditionalShape() );
+ if ( DynCastSdrTextObj(pObj) != nullptr )
+ {
+ bEditText = true;
+ }
+ }
+ }
+
+ if ( bEditText )
+ {
+ executeDispatch_EditText( pMousePixel );
+ }
+ else
+ {
+ executeDispatch_ObjectProperties();
+ }
+}
+
+void ChartController::execute_Resize()
+{
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+ if(pChartWindow)
+ pChartWindow->Invalidate();
+}
+
+void ChartController::execute_Command( const CommandEvent& rCEvt )
+{
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+ bool bIsAction = false;
+ {
+ DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get();
+ if(!pChartWindow || !pDrawViewWrapper)
+ return;
+ bIsAction = m_pDrawViewWrapper->IsAction();
+ }
+
+ // pop-up menu
+ if(rCEvt.GetCommand() == CommandEventId::ContextMenu && !bIsAction)
+ {
+ {
+ if(pChartWindow)
+ pChartWindow->ReleaseMouse();
+ }
+
+ if( m_aSelection.isSelectionDifferentFromBeforeMouseDown() )
+ impl_notifySelectionChangeListeners();
+
+ rtl::Reference< VCLXPopupMenu > xPopupMenu = new VCLXPopupMenu();
+
+ Point aPos( rCEvt.GetMousePosPixel() );
+ if( !rCEvt.IsMouseEvent() )
+ {
+ if(pChartWindow)
+ aPos = pChartWindow->GetPointerState().maPos;
+ }
+
+ OUString aMenuName;
+ if ( isShapeContext() )
+ // #i12587# support for shapes in chart
+ aMenuName = m_pDrawViewWrapper->IsTextEdit() ? std::u16string_view( u"drawtext" ) : std::u16string_view( u"draw" );
+ else
+ {
+ ObjectType eObjectType = ObjectIdentifier::getObjectType( m_aSelection.getSelectedCID() );
+
+ // todo: the context menu should be specified by an xml file in uiconfig
+ sal_Int16 nUniqueId = 1;
+ if (eObjectType != OBJECTTYPE_DATA_TABLE)
+ {
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:Cut" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:Copy" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:Paste" );
+ xPopupMenu->insertSeparator( -1 );
+ }
+
+ rtl::Reference< Diagram > xDiagram = getFirstDiagram();
+
+ OUString aFormatCommand( lcl_getFormatCommandForObjectCID( m_aSelection.getSelectedCID() ) );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, aFormatCommand );
+
+ //some commands for dataseries and points:
+
+ if( eObjectType == OBJECTTYPE_DATA_SERIES || eObjectType == OBJECTTYPE_DATA_POINT )
+ {
+ bool bIsPoint = ( eObjectType == OBJECTTYPE_DATA_POINT );
+ rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ rtl::Reference< RegressionCurveModel > xTrendline = RegressionCurveHelper::getFirstCurveNotMeanValueLine( xSeries );
+ bool bHasEquation = RegressionCurveHelper::hasEquation( xTrendline );
+ rtl::Reference< RegressionCurveModel > xMeanValue = RegressionCurveHelper::getMeanValueLine( xSeries );
+ bool bHasYErrorBars = StatisticsHelper::hasErrorBars( xSeries );
+ bool bHasXErrorBars = StatisticsHelper::hasErrorBars( xSeries, false );
+ bool bHasDataLabelsAtSeries = DataSeriesHelper::hasDataLabelsAtSeries( xSeries );
+ bool bHasDataLabelsAtPoints = DataSeriesHelper::hasDataLabelsAtPoints( xSeries );
+ bool bHasDataLabelAtPoint = false;
+ sal_Int32 nPointIndex = -1;
+ if( bIsPoint )
+ {
+ nPointIndex = ObjectIdentifier::getIndexFromParticleOrCID( m_aSelection.getSelectedCID() );
+ bHasDataLabelAtPoint = DataSeriesHelper::hasDataLabelAtPoint( xSeries, nPointIndex );
+ }
+ bool bSelectedPointIsFormatted = false;
+ bool bHasFormattedDataPointsOtherThanSelected = false;
+
+ if( xSeries.is() )
+ {
+ uno::Sequence< sal_Int32 > aAttributedDataPointIndexList;
+ // "AttributedDataPoints"
+ if( xSeries->getFastPropertyValue( PROP_DATASERIES_ATTRIBUTED_DATA_POINTS ) >>= aAttributedDataPointIndexList )
+ {
+ if( aAttributedDataPointIndexList.hasElements() )
+ {
+ if( bIsPoint )
+ {
+ auto aIt = std::find( std::as_const(aAttributedDataPointIndexList).begin(), std::as_const(aAttributedDataPointIndexList).end(), nPointIndex );
+ if( aIt != std::as_const(aAttributedDataPointIndexList).end())
+ bSelectedPointIsFormatted = true;
+ else
+ bHasFormattedDataPointsOtherThanSelected = true;
+ }
+ else
+ bHasFormattedDataPointsOtherThanSelected = true;
+ }
+ }
+ }
+
+ if( bIsPoint )
+ {
+ if( bHasDataLabelAtPoint )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatDataLabel" );
+ if( !bHasDataLabelAtPoint )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertDataLabel" );
+ else
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteDataLabel" );
+ if( bSelectedPointIsFormatted )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:ResetDataPoint" );
+
+ xPopupMenu->insertSeparator( -1 );
+
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatDataSeries" );
+ }
+
+ rtl::Reference< ChartType > xChartType( xDiagram->getChartTypeOfSeries( xSeries ) );
+ if( xChartType->getChartType() == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK )
+ {
+ try
+ {
+ bool bJapaneseStyle = false;
+ xChartType->getPropertyValue( "Japanese" ) >>= bJapaneseStyle;
+
+ if( bJapaneseStyle )
+ {
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatStockLoss" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatStockGain" );
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ }
+
+ if( bHasDataLabelsAtSeries )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatDataLabels" );
+ if( bHasEquation )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatTrendlineEquation" );
+ if( xMeanValue.is() )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatMeanValue" );
+ if( bHasXErrorBars )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatXErrorBars" );
+ if( bHasYErrorBars )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatYErrorBars" );
+
+ xPopupMenu->insertSeparator( -1 );
+
+ if( !bHasDataLabelsAtSeries )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertDataLabels" );
+
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertTrendline" );
+
+ if( !xMeanValue.is() )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertMeanValue" );
+ if( !bHasXErrorBars )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertXErrorBars" );
+ if( !bHasYErrorBars )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertYErrorBars" );
+ if( bHasDataLabelsAtSeries || ( bHasDataLabelsAtPoints && bHasFormattedDataPointsOtherThanSelected ) )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteDataLabels" );
+ if( bHasEquation )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteTrendlineEquation" );
+ if( xMeanValue.is() )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteMeanValue" );
+ if( bHasXErrorBars )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteXErrorBars" );
+ if( bHasYErrorBars )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteYErrorBars" );
+
+ if( bHasFormattedDataPointsOtherThanSelected )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:ResetAllDataPoints" );
+
+ xPopupMenu->insertSeparator( -1 );
+
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId, ".uno:ArrangeRow" );
+ rtl::Reference< VCLXPopupMenu > xArrangePopupMenu = new VCLXPopupMenu();
+ sal_Int16 nSubId = nUniqueId + 1;
+ lcl_insertMenuCommand( xArrangePopupMenu, nSubId++, ".uno:Forward" );
+ lcl_insertMenuCommand( xArrangePopupMenu, nSubId, ".uno:Backward" );
+ xPopupMenu->setPopupMenu( nUniqueId, xArrangePopupMenu );
+ nUniqueId = nSubId;
+ ++nUniqueId;
+ }
+ else if( eObjectType == OBJECTTYPE_DATA_CURVE )
+ {
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteTrendline" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatTrendlineEquation" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertTrendlineEquation" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertTrendlineEquationAndR2" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertR2Value" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteTrendlineEquation" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteR2Value" );
+ }
+ else if( eObjectType == OBJECTTYPE_DATA_CURVE_EQUATION )
+ {
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertR2Value" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteR2Value" );
+ }
+
+ //some commands for axes: and grids
+
+ else if( eObjectType == OBJECTTYPE_AXIS || eObjectType == OBJECTTYPE_GRID || eObjectType == OBJECTTYPE_SUBGRID )
+ {
+ rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() );
+ if( xAxis.is() && xDiagram.is() )
+ {
+ sal_Int32 nDimensionIndex = -1;
+ sal_Int32 nCooSysIndex = -1;
+ sal_Int32 nAxisIndex = -1;
+ AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex );
+ bool bIsSecondaryAxis = nAxisIndex!=0;
+ bool bIsAxisVisible = AxisHelper::isAxisVisible( xAxis );
+ bool bIsMajorGridVisible = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, true /*bMainGrid*/, xDiagram );
+ bool bIsMinorGridVisible = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, false /*bMainGrid*/, xDiagram );
+ bool bHasTitle = !TitleHelper::getCompleteString( xAxis->getTitleObject2() ).isEmpty();
+
+ if( eObjectType != OBJECTTYPE_AXIS && bIsAxisVisible )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatAxis" );
+ if( eObjectType != OBJECTTYPE_GRID && bIsMajorGridVisible && !bIsSecondaryAxis )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatMajorGrid" );
+ if( eObjectType != OBJECTTYPE_SUBGRID && bIsMinorGridVisible && !bIsSecondaryAxis )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatMinorGrid" );
+
+ xPopupMenu->insertSeparator( -1 );
+
+ if( eObjectType != OBJECTTYPE_AXIS && !bIsAxisVisible )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertAxis" );
+ if( eObjectType != OBJECTTYPE_GRID && !bIsMajorGridVisible && !bIsSecondaryAxis )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertMajorGrid" );
+ if( eObjectType != OBJECTTYPE_SUBGRID && !bIsMinorGridVisible && !bIsSecondaryAxis )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertMinorGrid" );
+ if( !bHasTitle )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertAxisTitle" );
+
+ if( bIsAxisVisible )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteAxis" );
+ if( bIsMajorGridVisible && !bIsSecondaryAxis )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteMajorGrid" );
+ if( bIsMinorGridVisible && !bIsSecondaryAxis )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteMinorGrid" );
+ if (bIsAxisVisible)
+ lcl_insertMenuCommand(xPopupMenu, nUniqueId++, ".uno:InsertDataTable");
+ }
+ }
+ else if (eObjectType == OBJECTTYPE_DATA_TABLE)
+ {
+ lcl_insertMenuCommand(xPopupMenu, nUniqueId++, ".uno:DeleteDataTable");
+ }
+
+ if( eObjectType == OBJECTTYPE_DATA_STOCK_LOSS )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatStockGain" );
+ else if( eObjectType == OBJECTTYPE_DATA_STOCK_GAIN )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatStockLoss" );
+
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:TransformDialog" );
+
+ if( eObjectType == OBJECTTYPE_PAGE || eObjectType == OBJECTTYPE_DIAGRAM
+ || eObjectType == OBJECTTYPE_DIAGRAM_WALL
+ || eObjectType == OBJECTTYPE_DIAGRAM_FLOOR
+ || eObjectType == OBJECTTYPE_UNKNOWN )
+ {
+ if( eObjectType != OBJECTTYPE_UNKNOWN )
+ xPopupMenu->insertSeparator( -1 );
+ bool bHasLegend = LegendHelper::hasLegend( xDiagram );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertTitles" );
+ if( !bHasLegend )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertLegend" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertRemoveAxes" );
+ if( bHasLegend )
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteLegend" );
+ }
+
+ xPopupMenu->insertSeparator( -1 );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DiagramType" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DataRanges" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DiagramData" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:View3D" );
+ }
+
+ css::uno::Sequence< css::uno::Any > aArgs{
+ css::uno::Any(comphelper::makePropertyValue( "IsContextMenu", true )),
+ css::uno::Any(comphelper::makePropertyValue( "Frame", m_xFrame )),
+ css::uno::Any(comphelper::makePropertyValue( "Value", aMenuName ))
+ };
+
+ css::uno::Reference< css::frame::XPopupMenuController > xPopupController(
+ m_xCC->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.comp.framework.ResourceMenuController", aArgs, m_xCC ), css::uno::UNO_QUERY );
+
+ if ( !xPopupController.is() || !xPopupMenu.is() )
+ return;
+
+ xPopupController->setPopupMenu( xPopupMenu );
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (SfxViewShell* pViewShell = SfxViewShell::Current())
+ {
+ ControllerCommandDispatch* pCommandDispatch = dynamic_cast<ControllerCommandDispatch*>(m_aDispatchContainer.getChartDispatcher().get());
+ if (pCommandDispatch)
+ {
+ for (int nPos = 0, nCount = xPopupMenu->getItemCount(); nPos < nCount; ++nPos)
+ {
+ auto nItemId = xPopupMenu->getItemId(nPos);
+ OUString aCommandURL = xPopupMenu->getCommand(nItemId);
+ if (!pCommandDispatch->commandAvailable(aCommandURL))
+ xPopupMenu->enableItem(nItemId, false);
+ }
+ }
+
+ boost::property_tree::ptree aMenu = SfxDispatcher::fillPopupMenu(xPopupMenu);
+ boost::property_tree::ptree aRoot;
+ aRoot.add_child("menu", aMenu);
+
+ std::stringstream aStream;
+ boost::property_tree::write_json(aStream, aRoot, true);
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_MENU, OString(aStream.str()));
+ }
+ }
+ else
+ {
+ xPopupMenu->execute( css::uno::Reference< css::awt::XWindowPeer >( m_xFrame->getContainerWindow(), css::uno::UNO_QUERY ),
+ css::awt::Rectangle( aPos.X(), aPos.Y(), 0, 0 ),
+ css::awt::PopupMenuDirection::EXECUTE_DEFAULT );
+ }
+
+ css::uno::Reference< css::lang::XComponent > xComponent( xPopupController, css::uno::UNO_QUERY );
+ if ( xComponent.is() )
+ xComponent->dispose();
+ }
+ else if( ( rCEvt.GetCommand() == CommandEventId::StartExtTextInput ) ||
+ ( rCEvt.GetCommand() == CommandEventId::ExtTextInput ) ||
+ ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput ) ||
+ ( rCEvt.GetCommand() == CommandEventId::InputContextChange ) )
+ {
+ //#i84417# enable editing with IME
+ m_pDrawViewWrapper->Command( rCEvt, pChartWindow );
+ }
+}
+
+bool ChartController::execute_KeyInput( const KeyEvent& rKEvt )
+{
+ SolarMutexGuard aGuard;
+ bool bReturn=false;
+
+ DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get();
+ auto pChartWindow(GetChartWindow());
+ if (!pChartWindow || !pDrawViewWrapper)
+ return bReturn;
+
+ // handle accelerators
+ if (!m_apAccelExecute && m_xFrame.is() && m_xCC.is())
+ {
+ m_apAccelExecute = ::svt::AcceleratorExecute::createAcceleratorHelper();
+ OSL_ASSERT(m_apAccelExecute);
+ if (m_apAccelExecute)
+ m_apAccelExecute->init( m_xCC, m_xFrame );
+ }
+
+ vcl::KeyCode aKeyCode( rKEvt.GetKeyCode());
+ sal_uInt16 nCode = aKeyCode.GetCode();
+ bool bAlternate = aKeyCode.IsMod2();
+ bool bCtrl = aKeyCode.IsMod1();
+
+ if (m_apAccelExecute)
+ bReturn = m_apAccelExecute->execute( aKeyCode );
+ if( bReturn )
+ return bReturn;
+
+ {
+ if( pDrawViewWrapper->IsTextEdit() )
+ {
+ if( pDrawViewWrapper->KeyInput(rKEvt, pChartWindow) )
+ {
+ bReturn = true;
+ if( nCode == KEY_ESCAPE )
+ {
+ EndTextEdit();
+ }
+ }
+ }
+ }
+
+ // keyboard accessibility
+ ObjectType eObjectType = ObjectIdentifier::getObjectType( m_aSelection.getSelectedCID() );
+ if( ! bReturn )
+ {
+ // Navigation (Tab/F3/Home/End)
+ rtl::Reference<::chart::ChartModel> xChartDoc( getChartModel() );
+ ObjectKeyNavigation aObjNav( m_aSelection.getSelectedOID(), xChartDoc, m_xChartView.get() );
+ awt::KeyEvent aKeyEvent( ::svt::AcceleratorExecute::st_VCLKey2AWTKey( aKeyCode ));
+ bReturn = aObjNav.handleKeyEvent( aKeyEvent );
+ if( bReturn )
+ {
+ const ObjectIdentifier& aNewOID = aObjNav.getCurrentSelection();
+ uno::Any aNewSelection;
+ if ( aNewOID.isValid() && !ObjectHierarchy::isRootNode( aNewOID ) )
+ {
+ aNewSelection = aNewOID.getAny();
+ }
+ if ( m_eDragMode == SdrDragMode::Rotate && !SelectionHelper::isRotateableObject( aNewOID.getObjectCID(), getChartModel() ) )
+ {
+ m_eDragMode = SdrDragMode::Move;
+ }
+ bReturn = select( aNewSelection );
+ }
+ }
+
+ // Position and Size (+/-/arrow-keys) or pie segment dragging
+ if( ! bReturn )
+ {
+ // pie segment dragging
+ // note: could also be done for data series
+ if( eObjectType == OBJECTTYPE_DATA_POINT &&
+ ObjectIdentifier::getDragMethodServiceName( m_aSelection.getSelectedCID() ) ==
+ ObjectIdentifier::getPieSegmentDragMethodServiceName())
+ {
+ bool bDrag = false;
+ bool bDragInside = false;
+ if( nCode == KEY_ADD ||
+ nCode == KEY_SUBTRACT )
+ {
+ bDrag = true;
+ bDragInside = ( nCode == KEY_SUBTRACT );
+ }
+ else if(
+ nCode == KEY_LEFT ||
+ nCode == KEY_RIGHT ||
+ nCode == KEY_UP ||
+ nCode == KEY_DOWN )
+ {
+ bDrag = true;
+ std::u16string_view aParameter( ObjectIdentifier::getDragParameterString( m_aSelection.getSelectedCID() ));
+ sal_Int32 nOffsetPercentDummy( 0 );
+ awt::Point aMinimumPosition( 0, 0 );
+ awt::Point aMaximumPosition( 0, 0 );
+ ObjectIdentifier::parsePieSegmentDragParameterString(
+ aParameter, nOffsetPercentDummy, aMinimumPosition, aMaximumPosition );
+ aMaximumPosition.Y -= aMinimumPosition.Y;
+ aMaximumPosition.X -= aMinimumPosition.X;
+
+ bDragInside =
+ (nCode == KEY_RIGHT && (aMaximumPosition.X < 0)) ||
+ (nCode == KEY_LEFT && (aMaximumPosition.X > 0)) ||
+ (nCode == KEY_DOWN && (aMaximumPosition.Y < 0)) ||
+ (nCode == KEY_UP && (aMaximumPosition.Y > 0));
+ }
+
+ if( bDrag )
+ {
+ double fAmount = bAlternate ? 0.01 : 0.05;
+ if( bDragInside )
+ fAmount *= -1.0;
+
+ bReturn = impl_DragDataPoint( m_aSelection.getSelectedCID(), fAmount );
+ }
+ }
+ else
+ {
+ // size
+ if( nCode == KEY_ADD ||
+ nCode == KEY_SUBTRACT )
+ {
+ if( eObjectType == OBJECTTYPE_DIAGRAM )
+ {
+ // default 1 mm in each direction
+ double fGrowAmountX = 200.0;
+ double fGrowAmountY = 200.0;
+ if (bAlternate)
+ {
+ // together with Alt-key: 1 px in each direction
+ Size aPixelSize = pChartWindow->PixelToLogic( Size( 2, 2 ));
+ fGrowAmountX = static_cast< double >( aPixelSize.Width());
+ fGrowAmountY = static_cast< double >( aPixelSize.Height());
+ }
+ if( nCode == KEY_SUBTRACT )
+ {
+ fGrowAmountX = -fGrowAmountX;
+ fGrowAmountY = -fGrowAmountY;
+ }
+ bReturn = impl_moveOrResizeObject(
+ m_aSelection.getSelectedCID(), CENTERED_RESIZE_OBJECT, fGrowAmountX, fGrowAmountY );
+ }
+ }
+ // position
+ else if( nCode == KEY_LEFT ||
+ nCode == KEY_RIGHT ||
+ nCode == KEY_UP ||
+ nCode == KEY_DOWN )
+ {
+ if( m_aSelection.isDragableObjectSelected() )
+ {
+ // default 1 mm
+ double fShiftAmountX = 100.0;
+ double fShiftAmountY = 100.0;
+ if (bAlternate)
+ {
+ // together with Alt-key: 1 px
+ Size aPixelSize = pChartWindow->PixelToLogic( Size( 1, 1 ));
+ fShiftAmountX = static_cast< double >( aPixelSize.Width());
+ fShiftAmountY = static_cast< double >( aPixelSize.Height());
+ }
+ switch( nCode )
+ {
+ case KEY_LEFT:
+ fShiftAmountX = -fShiftAmountX;
+ fShiftAmountY = 0.0;
+ break;
+ case KEY_RIGHT:
+ fShiftAmountY = 0.0;
+ break;
+ case KEY_UP:
+ fShiftAmountX = 0.0;
+ fShiftAmountY = -fShiftAmountY;
+ break;
+ case KEY_DOWN:
+ fShiftAmountX = 0.0;
+ break;
+ }
+ if( !m_aSelection.getSelectedCID().isEmpty() )
+ {
+ //move chart objects
+ if (eObjectType == OBJECTTYPE_DATA_LABEL)
+ {
+ SdrObject* pObj = pDrawViewWrapper->getSelectedObject();
+ if (pObj)
+ {
+ tools::Rectangle aRect = pObj->GetSnapRect();
+ awt::Size aPageSize(ChartModelHelper::getPageSize(getChartModel()));
+ if ((fShiftAmountX > 0.0 && (aRect.Right() + fShiftAmountX > aPageSize.Width)) ||
+ (fShiftAmountX < 0.0 && (aRect.Left() + fShiftAmountX < 0)) ||
+ (fShiftAmountY > 0.0 && (aRect.Bottom() + fShiftAmountY > aPageSize.Height)) ||
+ (fShiftAmountY < 0.0 && (aRect.Top() + fShiftAmountY < 0)))
+ bReturn = false;
+ else
+ bReturn = PositionAndSizeHelper::moveObject(
+ m_aSelection.getSelectedCID(), getChartModel(),
+ awt::Rectangle(aRect.Left() + fShiftAmountX, aRect.Top() + fShiftAmountY, aRect.getOpenWidth(), aRect.getOpenHeight()),
+ awt::Rectangle(aRect.Left(), aRect.Top(), 0, 0),
+ awt::Rectangle(0, 0, aPageSize.Width, aPageSize.Height));
+ }
+ }
+ else
+ bReturn = impl_moveOrResizeObject(
+ m_aSelection.getSelectedCID(), MOVE_OBJECT, fShiftAmountX, fShiftAmountY );
+ }
+ else
+ {
+ //move additional shapes
+ uno::Reference< drawing::XShape > xShape( m_aSelection.getSelectedAdditionalShape() );
+ if( xShape.is() )
+ {
+ awt::Point aPos( xShape->getPosition() );
+ awt::Size aSize( xShape->getSize() );
+ awt::Size aPageSize( ChartModelHelper::getPageSize( getChartModel() ) );
+ aPos.X = static_cast< tools::Long >( static_cast< double >( aPos.X ) + fShiftAmountX );
+ aPos.Y = static_cast< tools::Long >( static_cast< double >( aPos.Y ) + fShiftAmountY );
+ if( aPos.X + aSize.Width > aPageSize.Width )
+ aPos.X = aPageSize.Width - aSize.Width;
+ if( aPos.X < 0 )
+ aPos.X = 0;
+ if( aPos.Y + aSize.Height > aPageSize.Height )
+ aPos.Y = aPageSize.Height - aSize.Height;
+ if( aPos.Y < 0 )
+ aPos.Y = 0;
+
+ xShape->setPosition( aPos );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // dumping the shape
+ if( !bReturn && bCtrl && nCode == KEY_F12)
+ {
+ rtl::Reference< ChartModel > xChartModel = getChartModel();
+ if(xChartModel.is())
+ {
+ OUString aDump = xChartModel->dump("shapes");
+ SAL_WARN("chart2", aDump);
+ }
+ }
+
+ // text edit
+ if( ! bReturn &&
+ nCode == KEY_F2 )
+ {
+ if( eObjectType == OBJECTTYPE_TITLE )
+ {
+ executeDispatch_EditText();
+ bReturn = true;
+ }
+ }
+
+ // deactivate inplace mode (this code should be unnecessary, but
+ // unfortunately is not)
+ if( ! bReturn &&
+ nCode == KEY_ESCAPE )
+ {
+ uno::Reference< frame::XDispatchHelper > xDispatchHelper( frame::DispatchHelper::create(m_xCC) );
+ uno::Sequence< beans::PropertyValue > aArgs;
+ xDispatchHelper->executeDispatch(
+ uno::Reference< frame::XDispatchProvider >( m_xFrame, uno::UNO_QUERY ),
+ ".uno:TerminateInplaceActivation",
+ "_parent",
+ frame::FrameSearchFlag::PARENT,
+ aArgs );
+ bReturn = true;
+ }
+
+ if( ! bReturn &&
+ (nCode == KEY_DELETE || nCode == KEY_BACKSPACE ))
+ {
+ bReturn = executeDispatch_Delete();
+ if( ! bReturn )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pChartWindow->GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ SchResId(STR_ACTION_NOTPOSSIBLE)));
+ xInfoBox->run();
+ }
+ }
+
+ return bReturn;
+}
+
+bool ChartController::requestQuickHelp(
+ ::Point aAtLogicPosition,
+ bool bIsBalloonHelp,
+ OUString & rOutQuickHelpText,
+ awt::Rectangle & rOutEqualRect )
+{
+ rtl::Reference<::chart::ChartModel> xChartModel;
+ if( m_aModel.is())
+ xChartModel = getChartModel();
+ if( !xChartModel.is())
+ return false;
+
+ // help text
+ OUString aCID;
+ if( m_pDrawViewWrapper )
+ {
+ aCID = SelectionHelper::getHitObjectCID(
+ aAtLogicPosition, *m_pDrawViewWrapper );
+ }
+ bool bResult( !aCID.isEmpty());
+
+ if( bResult )
+ {
+ // get help text
+ rOutQuickHelpText = ObjectNameProvider::getHelpText( aCID, xChartModel, bIsBalloonHelp /* bVerbose */ );
+
+ // set rectangle
+ if( m_xChartView )
+ rOutEqualRect = m_xChartView->getRectangleOfObject( aCID, true );
+ }
+
+ return bResult;
+}
+
+// XSelectionSupplier (optional interface)
+sal_Bool SAL_CALL ChartController::select( const uno::Any& rSelection )
+{
+ bool bSuccess = false;
+
+ if ( rSelection.hasValue() )
+ {
+ const uno::Type& rType = rSelection.getValueType();
+ if ( rType == cppu::UnoType< OUString >::get() )
+ {
+ OUString aNewCID;
+ if ( ( rSelection >>= aNewCID ) && m_aSelection.setSelection( aNewCID ) )
+ {
+ bSuccess = true;
+ }
+ }
+ else if ( rType == cppu::UnoType<drawing::XShape>::get() )
+ {
+ uno::Reference< drawing::XShape > xShape;
+ if ( ( rSelection >>= xShape ) && m_aSelection.setSelection( xShape ) )
+ {
+ bSuccess = true;
+ }
+ }
+ }
+ else
+ {
+ if ( m_aSelection.hasSelection() )
+ {
+ m_aSelection.clearSelection();
+ bSuccess = true;
+ }
+ }
+
+ if ( bSuccess )
+ {
+ SolarMutexGuard aGuard;
+ if ( m_pDrawViewWrapper && m_pDrawViewWrapper->IsTextEdit() )
+ {
+ EndTextEdit();
+ }
+ impl_selectObjectAndNotiy();
+ auto pChartWindow(GetChartWindow());
+ if ( pChartWindow )
+ {
+ pChartWindow->Invalidate();
+ }
+ return true;
+ }
+
+ return false;
+}
+
+uno::Any SAL_CALL ChartController::getSelection()
+{
+ uno::Any aReturn;
+ if ( m_aSelection.hasSelection() )
+ {
+ OUString aCID( m_aSelection.getSelectedCID() );
+ if ( !aCID.isEmpty() )
+ {
+ aReturn <<= aCID;
+ }
+ else
+ {
+ // #i12587# support for shapes in chart
+ aReturn <<= m_aSelection.getSelectedAdditionalShape();
+ }
+ }
+ return aReturn;
+}
+
+void SAL_CALL ChartController::addSelectionChangeListener( const uno::Reference<view::XSelectionChangeListener> & xListener )
+{
+ SolarMutexGuard aGuard;
+ if( impl_isDisposedOrSuspended() )//@todo? allow adding of listeners in suspend mode?
+ return; //behave passive if already disposed or suspended
+
+ //--add listener
+ std::unique_lock aGuard2(m_aLifeTimeManager.m_aAccessMutex);
+ m_aLifeTimeManager.m_aSelectionChangeListeners.addInterface( aGuard2, xListener );
+}
+
+void SAL_CALL ChartController::removeSelectionChangeListener( const uno::Reference<view::XSelectionChangeListener> & xListener )
+{
+ SolarMutexGuard aGuard;
+ if( impl_isDisposedOrSuspended() ) //@todo? allow removing of listeners in suspend mode?
+ return; //behave passive if already disposed or suspended
+
+ //--remove listener
+ std::unique_lock aGuard2(m_aLifeTimeManager.m_aAccessMutex);
+ m_aLifeTimeManager.m_aSelectionChangeListeners.removeInterface( aGuard2, xListener );
+}
+
+void ChartController::impl_notifySelectionChangeListeners()
+{
+ std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
+ if( m_aLifeTimeManager.m_aSelectionChangeListeners.getLength(aGuard) )
+ {
+ uno::Reference< view::XSelectionSupplier > xSelectionSupplier(this);
+ lang::EventObject aEvent( xSelectionSupplier );
+ m_aLifeTimeManager.m_aSelectionChangeListeners.notifyEach(aGuard, &view::XSelectionChangeListener::selectionChanged, aEvent);
+ }
+}
+
+void ChartController::impl_selectObjectAndNotiy()
+{
+ {
+ SolarMutexGuard aGuard;
+ DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get();
+ if( pDrawViewWrapper )
+ {
+ pDrawViewWrapper->SetDragMode( m_eDragMode );
+ m_aSelection.applySelection( m_pDrawViewWrapper.get() );
+ }
+ }
+ impl_notifySelectionChangeListeners();
+}
+
+bool ChartController::impl_moveOrResizeObject(
+ const OUString & rCID,
+ eMoveOrResizeType eType,
+ double fAmountLogicX,
+ double fAmountLogicY )
+{
+ bool bResult = false;
+ bool bNeedResize = ( eType == CENTERED_RESIZE_OBJECT );
+
+ rtl::Reference<::chart::ChartModel> xChartModel( getChartModel() );
+ uno::Reference< beans::XPropertySet > xObjProp(
+ ObjectIdentifier::getObjectPropertySet( rCID, xChartModel ));
+ if( xObjProp.is())
+ {
+ awt::Size aRefSize = ChartModelHelper::getPageSize( xChartModel );
+
+ chart2::RelativePosition aRelPos;
+ chart2::RelativeSize aRelSize;
+ bool bDeterminePos = !(xObjProp->getPropertyValue( "RelativePosition") >>= aRelPos);
+ bool bDetermineSize = !bNeedResize || !(xObjProp->getPropertyValue( "RelativeSize") >>= aRelSize);
+
+ if( ( bDeterminePos || bDetermineSize ) &&
+ ( aRefSize.Width > 0 && aRefSize.Height > 0 ) )
+ {
+ ExplicitValueProvider * pValueProvider( m_xChartView.get() );
+ if( pValueProvider )
+ {
+ awt::Rectangle aRect( pValueProvider->getRectangleOfObject( rCID ));
+ double fWidth = static_cast< double >( aRefSize.Width );
+ double fHeight = static_cast< double >( aRefSize.Height );
+ if( bDetermineSize )
+ {
+ aRelSize.Primary = static_cast< double >( aRect.Width ) / fWidth;
+ aRelSize.Secondary = static_cast< double >( aRect.Height ) / fHeight;
+ }
+ if( bDeterminePos )
+ {
+ if( bNeedResize && aRelSize.Primary > 0.0 && aRelSize.Secondary > 0.0 )
+ {
+ aRelPos.Primary = (static_cast< double >( aRect.X ) / fWidth) +
+ (aRelSize.Primary / 2.0);
+ aRelPos.Secondary = (static_cast< double >( aRect.Y ) / fHeight) +
+ (aRelSize.Secondary / 2.0);
+ aRelPos.Anchor = drawing::Alignment_CENTER;
+ }
+ else
+ {
+ aRelPos.Primary = static_cast< double >( aRect.X ) / fWidth;
+ aRelPos.Secondary = static_cast< double >( aRect.Y ) / fHeight;
+ aRelPos.Anchor = drawing::Alignment_TOP_LEFT;
+ }
+ }
+ }
+ }
+
+ if( eType == CENTERED_RESIZE_OBJECT )
+ bResult = lcl_GrowAndShiftLogic( aRelPos, aRelSize, aRefSize, fAmountLogicX, fAmountLogicY );
+ else if( eType == MOVE_OBJECT )
+ bResult = lcl_MoveObjectLogic( aRelPos, aRelSize, aRefSize, fAmountLogicX, fAmountLogicY );
+
+ if( bResult )
+ {
+ ActionDescriptionProvider::ActionType eActionType(ActionDescriptionProvider::ActionType::Move);
+ if( bNeedResize )
+ eActionType = ActionDescriptionProvider::ActionType::Resize;
+
+ ObjectType eObjectType = ObjectIdentifier::getObjectType( rCID );
+ UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription(
+ eActionType, ObjectNameProvider::getName( eObjectType )), m_xUndoManager );
+ {
+ ControllerLockGuardUNO aCLGuard( xChartModel );
+ xObjProp->setPropertyValue( "RelativePosition", uno::Any( aRelPos ));
+ if( bNeedResize || (eObjectType == OBJECTTYPE_DIAGRAM) )//Also set an explicit size at the diagram when an explicit position is set
+ xObjProp->setPropertyValue( "RelativeSize", uno::Any( aRelSize ));
+ }
+ aUndoGuard.commit();
+ }
+ }
+ return bResult;
+}
+
+bool ChartController::impl_DragDataPoint( std::u16string_view rCID, double fAdditionalOffset )
+{
+ bool bResult = false;
+ if( fAdditionalOffset < -1.0 || fAdditionalOffset > 1.0 || fAdditionalOffset == 0.0 )
+ return bResult;
+
+ sal_Int32 nDataPointIndex = ObjectIdentifier::getIndexFromParticleOrCID( rCID );
+ rtl::Reference< DataSeries > xSeries =
+ ObjectIdentifier::getDataSeriesForCID( rCID, getChartModel() );
+ if( xSeries.is())
+ {
+ try
+ {
+ uno::Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex( nDataPointIndex ));
+ double fOffset = 0.0;
+ if( xPointProp.is() &&
+ (xPointProp->getPropertyValue( "Offset" ) >>= fOffset ) &&
+ (( fAdditionalOffset > 0.0 && fOffset < 1.0 ) || (fOffset > 0.0)) )
+ {
+ fOffset += fAdditionalOffset;
+ if( fOffset > 1.0 )
+ fOffset = 1.0;
+ else if( fOffset < 0.0 )
+ fOffset = 0.0;
+ xPointProp->setPropertyValue( "Offset", uno::Any( fOffset ));
+ bResult = true;
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ }
+
+ return bResult;
+}
+
+void ChartController::impl_SetMousePointer( const MouseEvent & rEvent )
+{
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+
+ if (!m_pDrawViewWrapper || !pChartWindow)
+ return;
+
+ Point aMousePos( pChartWindow->PixelToLogic( rEvent.GetPosPixel()));
+ sal_uInt16 nModifier = rEvent.GetModifier();
+ bool bLeftDown = rEvent.IsLeft();
+
+ // Check if object is for field button and set the normal arrow pointer in this case
+ SdrObject* pObject = m_pDrawViewWrapper->getHitObject(aMousePos);
+ if (pObject && pObject->GetName().startsWith("FieldButton"))
+ {
+ pChartWindow->SetPointer(PointerStyle::Arrow);
+ return;
+ }
+
+ if ( m_pDrawViewWrapper->IsTextEdit() )
+ {
+ if( m_pDrawViewWrapper->IsTextEditHit( aMousePos ) )
+ {
+ pChartWindow->SetPointer( m_pDrawViewWrapper->GetPreferredPointer(
+ aMousePos, pChartWindow->GetOutDev(), nModifier, bLeftDown ) );
+ return;
+ }
+ }
+ else if( m_pDrawViewWrapper->IsAction() )
+ {
+ return;//don't change pointer during running action
+ }
+
+ SdrHdl* pHitSelectionHdl = nullptr;
+ if( m_aSelection.isResizeableObjectSelected() )
+ pHitSelectionHdl = m_pDrawViewWrapper->PickHandle( aMousePos );
+
+ if( pHitSelectionHdl )
+ {
+ PointerStyle aPointer = m_pDrawViewWrapper->GetPreferredPointer(
+ aMousePos, pChartWindow->GetOutDev(), nModifier, bLeftDown );
+ bool bForceArrowPointer = false;
+
+ ObjectIdentifier aOID( m_aSelection.getSelectedOID() );
+
+ switch( aPointer)
+ {
+ case PointerStyle::NSize:
+ case PointerStyle::SSize:
+ case PointerStyle::WSize:
+ case PointerStyle::ESize:
+ case PointerStyle::NWSize:
+ case PointerStyle::NESize:
+ case PointerStyle::SWSize:
+ case PointerStyle::SESize:
+ if( ! m_aSelection.isResizeableObjectSelected() )
+ bForceArrowPointer = true;
+ break;
+ case PointerStyle::Move:
+ if ( !aOID.isDragableObject() )
+ bForceArrowPointer = true;
+ break;
+ case PointerStyle::MovePoint:
+ case PointerStyle::MoveBezierWeight:
+ // there is no point-editing in a chart
+ // the PointerStyle::MoveBezierWeight appears in 3d data points
+ bForceArrowPointer = true;
+ break;
+ default:
+ break;
+ }
+
+ if( bForceArrowPointer )
+ pChartWindow->SetPointer( PointerStyle::Arrow );
+ else
+ pChartWindow->SetPointer( aPointer );
+
+ return;
+ }
+
+ // #i12587# support for shapes in chart
+ if ( m_eDrawMode == CHARTDRAW_INSERT &&
+ ( !m_pDrawViewWrapper->IsMarkedHit( aMousePos ) || !m_aSelection.isDragableObjectSelected() ) )
+ {
+ PointerStyle ePointerStyle = PointerStyle::DrawRect;
+ SdrObjKind eKind = m_pDrawViewWrapper->GetCurrentObjIdentifier();
+ switch ( eKind )
+ {
+ case SdrObjKind::Line:
+ {
+ ePointerStyle = PointerStyle::DrawLine;
+ }
+ break;
+ case SdrObjKind::Rectangle:
+ case SdrObjKind::CustomShape:
+ {
+ ePointerStyle = PointerStyle::DrawRect;
+ }
+ break;
+ case SdrObjKind::CircleOrEllipse:
+ {
+ ePointerStyle = PointerStyle::DrawEllipse;
+ }
+ break;
+ case SdrObjKind::FreehandLine:
+ {
+ ePointerStyle = PointerStyle::DrawPolygon;
+ }
+ break;
+ case SdrObjKind::Text:
+ {
+ ePointerStyle = PointerStyle::DrawText;
+ }
+ break;
+ case SdrObjKind::Caption:
+ {
+ ePointerStyle = PointerStyle::DrawCaption;
+ }
+ break;
+ default:
+ {
+ ePointerStyle = PointerStyle::DrawRect;
+ }
+ break;
+ }
+ pChartWindow->SetPointer( ePointerStyle );
+ return;
+ }
+
+ OUString aHitObjectCID(
+ SelectionHelper::getHitObjectCID(
+ aMousePos, *m_pDrawViewWrapper, true /*bGetDiagramInsteadOf_Wall*/ ));
+
+ if( m_pDrawViewWrapper->IsTextEdit() )
+ {
+ if( aHitObjectCID == m_aSelection.getSelectedCID() )
+ {
+ pChartWindow->SetPointer( PointerStyle::Arrow );
+ return;
+ }
+ }
+
+ if( aHitObjectCID.isEmpty() )
+ {
+ //additional shape was hit
+ pChartWindow->SetPointer( PointerStyle::Move );
+ }
+ else if( ObjectIdentifier::isDragableObject( aHitObjectCID ) )
+ {
+ if( (m_eDragMode == SdrDragMode::Rotate)
+ && SelectionHelper::isRotateableObject( aHitObjectCID
+ , getChartModel() ) )
+ pChartWindow->SetPointer( PointerStyle::Rotate );
+ else
+ {
+ ObjectType eHitObjectType = ObjectIdentifier::getObjectType( aHitObjectCID );
+ if( eHitObjectType == OBJECTTYPE_DATA_POINT )
+ {
+ if( !ObjectIdentifier::areSiblings(aHitObjectCID,m_aSelection.getSelectedCID())
+ && !ObjectIdentifier::areIdenticalObjects(aHitObjectCID,m_aSelection.getSelectedCID()) )
+ {
+ pChartWindow->SetPointer( PointerStyle::Arrow );
+ return;
+ }
+ }
+ pChartWindow->SetPointer( PointerStyle::Move );
+ }
+ }
+ else
+ pChartWindow->SetPointer( PointerStyle::Arrow );
+}
+
+void ChartController::sendPopupRequest(std::u16string_view rCID, tools::Rectangle aRectangle)
+{
+ ChartModel* pChartModel = m_aModel->getModel().get();
+ if (!pChartModel)
+ return;
+
+ uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider;
+ xPivotTableDataProvider.set(pChartModel->getDataProvider(), uno::UNO_QUERY);
+ if (!xPivotTableDataProvider.is())
+ return;
+
+ OUString sPivotTableName = xPivotTableDataProvider->getPivotTableName();
+
+ css::uno::Reference<css::awt::XRequestCallback> xPopupRequest = pChartModel->getPopupRequest();
+ PopupRequest* pPopupRequest = dynamic_cast<PopupRequest*>(xPopupRequest.get());
+ if (!pPopupRequest)
+ return;
+
+ // Get dimension index from CID
+ size_t nStartPos = rCID.rfind('.');
+ nStartPos++;
+ sal_Int32 nEndPos = rCID.size();
+ std::u16string_view sDimensionIndex = rCID.substr(nStartPos, nEndPos - nStartPos);
+ sal_Int32 nDimensionIndex = o3tl::toInt32(sDimensionIndex);
+
+ awt::Rectangle xRectangle {
+ sal_Int32(aRectangle.Left()),
+ sal_Int32(aRectangle.Top()),
+ sal_Int32(aRectangle.GetWidth()),
+ sal_Int32(aRectangle.GetHeight())
+ };
+
+ uno::Sequence<beans::PropertyValue> aCallbackData = comphelper::InitPropertySequence(
+ {
+ {"Rectangle", uno::Any(xRectangle)},
+ {"DimensionIndex", uno::Any(sal_Int32(nDimensionIndex))},
+ {"PivotTableName", uno::Any(sPivotTableName)},
+ });
+
+ pPopupRequest->getCallback()->notify(uno::Any(aCallbackData));
+}
+
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartDropTargetHelper.cxx b/chart2/source/controller/main/ChartDropTargetHelper.cxx
new file mode 100644
index 0000000000..fc6762598a
--- /dev/null
+++ b/chart2/source/controller/main/ChartDropTargetHelper.cxx
@@ -0,0 +1,178 @@
+/* -*- 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 "ChartDropTargetHelper.hxx"
+#include <DataSource.hxx>
+#include <DataSourceHelper.hxx>
+#include <ChartModel.hxx>
+#include <Diagram.hxx>
+
+#include <com/sun/star/chart2/data/XDataProvider.hpp>
+
+#include <sot/formats.hxx>
+#include <utility>
+#include <vector>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace
+{
+
+std::vector< OUString > lcl_getStringsFromByteSequence(
+ const Sequence< sal_Int8 > & aByteSequence )
+{
+ std::vector< OUString > aResult;
+ const sal_Int32 nLength = aByteSequence.getLength();
+ const char * pBytes( reinterpret_cast< const char* >( aByteSequence.getConstArray()));
+ sal_Int32 nStartPos = 0;
+ for( sal_Int32 nPos=0; nPos<nLength; ++nPos )
+ {
+ if( pBytes[nPos] == '\0' )
+ {
+ aResult.emplace_back( pBytes + nStartPos, (nPos - nStartPos), RTL_TEXTENCODING_ASCII_US );
+ nStartPos = nPos + 1;
+ }
+ }
+ return aResult;
+}
+
+} // anonymous namespace
+
+namespace chart
+{
+
+ChartDropTargetHelper::ChartDropTargetHelper(
+ const Reference< datatransfer::dnd::XDropTarget >& rxDropTarget,
+ rtl::Reference<::chart::ChartModel> xChartDocument ) :
+ DropTargetHelper( rxDropTarget ),
+ m_xChartDocument(std::move( xChartDocument ))
+{}
+
+ChartDropTargetHelper::~ChartDropTargetHelper()
+{}
+
+bool ChartDropTargetHelper::satisfiesPrerequisites() const
+{
+ return ( m_xChartDocument.is() &&
+ ! m_xChartDocument->hasInternalDataProvider());
+}
+
+sal_Int8 ChartDropTargetHelper::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ sal_Int8 nResult = DND_ACTION_NONE;
+
+ if( ( rEvt.mnAction == DND_ACTION_COPY ||
+ rEvt.mnAction == DND_ACTION_MOVE ) &&
+ satisfiesPrerequisites() &&
+ IsDropFormatSupported( SotClipboardFormatId::LINK ) )
+ {
+ // @todo: check if the data is suitable. Is this possible without XTransferable?
+ nResult = rEvt.mnAction;
+ }
+
+ return nResult;
+}
+
+sal_Int8 ChartDropTargetHelper::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ sal_Int8 nResult = DND_ACTION_NONE;
+
+ if( ( rEvt.mnAction == DND_ACTION_COPY ||
+ rEvt.mnAction == DND_ACTION_MOVE ) &&
+ rEvt.maDropEvent.Transferable.is() &&
+ satisfiesPrerequisites())
+ {
+ TransferableDataHelper aDataHelper( rEvt.maDropEvent.Transferable );
+ if( aDataHelper.HasFormat( SotClipboardFormatId::LINK ))
+ {
+ Sequence<sal_Int8> aBytes = aDataHelper.GetSequence(SotClipboardFormatId::LINK, OUString());
+ if (aBytes.hasElements())
+ {
+ std::vector< OUString > aStrings( lcl_getStringsFromByteSequence( aBytes ));
+ if( aStrings.size() >= 3 && aStrings[0] == "soffice" )
+ {
+ OUString aRangeString( aStrings[2] );
+ if( m_xChartDocument.is())
+ {
+ Reference< frame::XModel > xParentModel( m_xChartDocument->getParent(), uno::UNO_QUERY );
+ if( xParentModel.is() &&
+ m_xChartDocument.is())
+ {
+ // @todo: get the title somehow and compare it to
+ // aDocName if successful (the document is the
+ // parent)
+ rtl::Reference< Diagram > xDiagram = m_xChartDocument->getFirstChartDiagram();
+ Reference< chart2::data::XDataProvider > xDataProvider( m_xChartDocument->getDataProvider());
+ if( xDataProvider.is() && xDiagram.is() &&
+ DataSourceHelper::allArgumentsForRectRangeDetected( m_xChartDocument ))
+ {
+ rtl::Reference< DataSource > xDataSource1 =
+ DataSourceHelper::pressUsedDataIntoRectangularFormat( m_xChartDocument );
+ Sequence< beans::PropertyValue > aArguments(
+ xDataProvider->detectArguments( xDataSource1 ));
+
+ OUString aOldRange;
+ beans::PropertyValue * pCellRange = nullptr;
+ for( sal_Int32 i=0; i<aArguments.getLength(); ++i )
+ {
+ if ( aArguments[i].Name == "CellRangeRepresentation" )
+ {
+ pCellRange = (aArguments.getArray() + i);
+ aArguments[i].Value >>= aOldRange;
+ break;
+ }
+ }
+ if( pCellRange )
+ {
+ // copy means add ranges, move means replace
+ if( rEvt.mnAction == DND_ACTION_COPY )
+ {
+ // @todo: using implicit knowledge that ranges can be
+ // merged with ";". This should be done more general
+ pCellRange->Value <<= aOldRange + ";" + aRangeString;
+ }
+ // move means replace range
+ else
+ {
+ pCellRange->Value <<= aRangeString;
+ }
+
+ Reference< chart2::data::XDataSource > xDataSource2 =
+ xDataProvider->createDataSource( aArguments );
+ xDiagram->setDiagramData( xDataSource2, aArguments );
+
+ // always return copy state to avoid deletion of the dragged range
+ nResult = DND_ACTION_COPY;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return nResult;
+}
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartDropTargetHelper.hxx b/chart2/source/controller/main/ChartDropTargetHelper.hxx
new file mode 100644
index 0000000000..ab573f1cd6
--- /dev/null
+++ b/chart2/source/controller/main/ChartDropTargetHelper.hxx
@@ -0,0 +1,56 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <vcl/transfer.hxx>
+#include <rtl/ref.hxx>
+
+namespace com::sun::star {
+ namespace chart2 {
+ class XChartDocument;
+ }
+}
+
+namespace chart
+{
+class ChartModel;
+
+class ChartDropTargetHelper : public DropTargetHelper
+{
+public:
+ ChartDropTargetHelper() = delete;
+ explicit ChartDropTargetHelper(
+ const css::uno::Reference< css::datatransfer::dnd::XDropTarget >& rxDropTarget,
+ rtl::Reference<::chart::ChartModel> xChartDocument );
+ virtual ~ChartDropTargetHelper() override;
+
+protected:
+
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+
+private:
+ bool satisfiesPrerequisites() const;
+
+ rtl::Reference<::chart::ChartModel> m_xChartDocument;
+};
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartFrameloader.cxx b/chart2/source/controller/main/ChartFrameloader.cxx
new file mode 100644
index 0000000000..2ff4558800
--- /dev/null
+++ b/chart2/source/controller/main/ChartFrameloader.cxx
@@ -0,0 +1,185 @@
+/* -*- 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 "ChartFrameloader.hxx"
+#include <servicenames.hxx>
+#include <MediaDescriptorHelper.hxx>
+#include <ChartController.hxx>
+#include <ChartModel.hxx>
+#include <unotools/fcm.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/frame/XLoadable.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <comphelper/diagnose_ex.hxx>
+
+namespace chart
+{
+
+using namespace ::com::sun::star;
+
+ChartFrameLoader::ChartFrameLoader(
+ uno::Reference<uno::XComponentContext> const & xContext)
+ : m_bCancelRequired( false )
+{
+ m_xCC = xContext;
+ m_oCancelFinished.reset();
+}
+
+ChartFrameLoader::~ChartFrameLoader()
+{
+}
+
+bool ChartFrameLoader::impl_checkCancel()
+{
+ if(m_bCancelRequired)
+ {
+ m_oCancelFinished.set();
+ return true;
+ }
+ return false;
+}
+
+// lang::XServiceInfo
+
+OUString SAL_CALL ChartFrameLoader::getImplementationName()
+{
+ return CHART_FRAMELOADER_SERVICE_IMPLEMENTATION_NAME;
+}
+
+sal_Bool SAL_CALL ChartFrameLoader::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL ChartFrameLoader::getSupportedServiceNames()
+{
+ return { CHART_FRAMELOADER_SERVICE_NAME };
+}
+
+// frame::XFrameLoader
+
+sal_Bool SAL_CALL ChartFrameLoader::load( const uno::Sequence< beans::PropertyValue >& rMediaDescriptor, const uno::Reference<frame::XFrame >& xFrame )
+{
+ //@todo ? need to add as terminate listener to desktop?
+
+ uno::Reference< frame::XModel > xModel;
+ bool bHaveLoadedModel = false;
+
+ utl::MediaDescriptor aMediaDescriptor(rMediaDescriptor);
+ {
+ utl::MediaDescriptor::const_iterator aIt( aMediaDescriptor.find( utl::MediaDescriptor::PROP_MODEL));
+ if( aIt != aMediaDescriptor.end())
+ {
+ xModel.set( (*aIt).second.get< uno::Reference< frame::XModel > >());
+ bHaveLoadedModel = true;
+ }
+ }
+
+ //create and initialize the model
+ if( ! xModel.is())
+ {
+ //@todo?? load mechanism to cancel during loading of document
+ xModel = new ChartModel(m_xCC);
+
+ if( impl_checkCancel() )
+ return false;
+ }
+
+ //create the controller(+XWindow)
+ rtl::Reference< ChartController > xController = new ChartController(m_xCC);
+
+ if( impl_checkCancel() )
+ return false;
+
+ //connect frame, controller and model one to each other:
+ if(xModel.is())
+ {
+ utl::ConnectFrameControllerModel(xFrame, xController, xModel);
+ }
+
+ // call initNew() or load() at XLoadable
+ if(bHaveLoadedModel)
+ return true;
+
+ try
+ {
+ utl::MediaDescriptor::const_iterator aIt( aMediaDescriptor.find( utl::MediaDescriptor::PROP_URL));
+ if( aIt != aMediaDescriptor.end())
+ {
+ OUString aURL( (*aIt).second.get< OUString >());
+ if( aURL.startsWith( "private:factory/schart" ) )
+ {
+ // create new file
+ uno::Reference< frame::XLoadable > xLoadable( xModel, uno::UNO_QUERY_THROW );
+ xLoadable->initNew();
+ }
+ else
+ {
+ // use the URL as BaseURL, similar to what SfxBaseModel effectively does
+ if (!aURL.isEmpty())
+ {
+ aMediaDescriptor[utl::MediaDescriptor::PROP_DOCUMENTBASEURL] <<= aURL;
+ }
+ aMediaDescriptor.addInputStream();
+ uno::Sequence< beans::PropertyValue > aCompleteMediaDescriptor;
+ aMediaDescriptor >> aCompleteMediaDescriptor;
+ apphelper::MediaDescriptorHelper aMDHelper( aCompleteMediaDescriptor );
+
+ // load file
+ // @todo: replace: aMediaDescriptorHelper.getReducedForModel()
+ uno::Reference< frame::XLoadable > xLoadable( xModel, uno::UNO_QUERY_THROW );
+ xLoadable->load( aCompleteMediaDescriptor );
+
+ //resize standalone files to get correct size:
+ if( aMDHelper.ISSET_FilterName && aMDHelper.FilterName == "StarChart 5.0" )
+ {
+ uno::Reference<awt::XWindow> xComponentWindow = xController->getComponentWindow();
+ awt::Rectangle aRect( xComponentWindow->getPosSize() );
+ xComponentWindow->setPosSize( aRect.X, aRect.Y, aRect.Width, aRect.Height, 0 );
+ }
+ }
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+
+ return true;
+}
+
+void SAL_CALL ChartFrameLoader::cancel()
+{
+ m_oCancelFinished.reset();
+ m_bCancelRequired = true;
+ m_oCancelFinished.wait();
+ m_bCancelRequired = false;
+}
+
+} //namespace chart
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_chart2_ChartFrameLoader_get_implementation(css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new chart::ChartFrameLoader(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartFrameloader.hxx b/chart2/source/controller/main/ChartFrameloader.hxx
new file mode 100644
index 0000000000..99f0ffd069
--- /dev/null
+++ b/chart2/source/controller/main/ChartFrameloader.hxx
@@ -0,0 +1,67 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <osl/conditn.hxx>
+#include <com/sun/star/frame/XSynchronousFrameLoader.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace chart
+{
+
+class ChartFrameLoader : public ::cppu::WeakImplHelper<
+ css::frame::XSynchronousFrameLoader
+ , css::lang::XServiceInfo
+ >
+{
+private:
+ css::uno::Reference< css::uno::XComponentContext> m_xCC;
+ bool m_bCancelRequired;
+ ::osl::Condition m_oCancelFinished;
+
+private:
+ bool impl_checkCancel();
+
+public:
+ ChartFrameLoader() = delete;
+
+ explicit ChartFrameLoader(css::uno::Reference< css::uno::XComponentContext > const & xContext);
+ virtual ~ChartFrameLoader() override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // css::frame::XFrameLoader
+
+ virtual sal_Bool SAL_CALL
+ load( const css::uno::Sequence< css::beans::PropertyValue >& rMediaDescriptor
+ ,const css::uno::Reference< css::frame::XFrame >& xFrame ) override;
+
+ virtual void SAL_CALL
+ cancel() override;
+};
+
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartModelClone.cxx b/chart2/source/controller/main/ChartModelClone.cxx
new file mode 100644
index 0000000000..6e620a32da
--- /dev/null
+++ b/chart2/source/controller/main/ChartModelClone.cxx
@@ -0,0 +1,227 @@
+/* -*- 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 "ChartModelClone.hxx"
+#include <ChartModel.hxx>
+#include <ChartModelHelper.hxx>
+#include <ControllerLockGuard.hxx>
+#include <DataSource.hxx>
+#include <DataSourceHelper.hxx>
+
+#include <com/sun/star/chart2/XAnyDescriptionAccess.hpp>
+#include <com/sun/star/chart2/XInternalDataProvider.hpp>
+#include <com/sun/star/util/XCloneable.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/chart2/XTitled.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/chart2/data/XLabeledDataSequence.hpp>
+
+#include <comphelper/property.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+namespace chart
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::util::XCloneable;
+ using ::com::sun::star::chart2::XChartDocument;
+ using ::com::sun::star::chart2::XInternalDataProvider;
+ using ::com::sun::star::chart2::XAnyDescriptionAccess;
+ using ::com::sun::star::view::XSelectionSupplier;
+ using ::com::sun::star::chart2::data::XLabeledDataSequence;
+
+ // = helper
+ namespace
+ {
+ rtl::Reference<::chart::ChartModel> lcl_cloneModel( const rtl::Reference<::chart::ChartModel> & xModel )
+ {
+ try
+ {
+ return new ChartModel(*xModel);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ return nullptr;
+ }
+
+ }
+
+ // = ChartModelClone
+ ChartModelClone::ChartModelClone( const rtl::Reference<::chart::ChartModel>& i_model, const ModelFacet i_facet )
+ {
+ m_xModelClone = lcl_cloneModel( i_model );
+
+ try
+ {
+ if ( i_facet == E_MODEL_WITH_DATA )
+ {
+ ENSURE_OR_THROW( m_xModelClone && m_xModelClone->hasInternalDataProvider(), "invalid chart model" );
+
+ const Reference< XCloneable > xCloneable( m_xModelClone->getDataProvider(), UNO_QUERY_THROW );
+ m_xDataClone.set( xCloneable->createClone(), UNO_QUERY_THROW );
+ }
+
+ if ( i_facet == E_MODEL_WITH_SELECTION )
+ {
+ const Reference< XSelectionSupplier > xSelSupp( m_xModelClone->getCurrentController(), UNO_QUERY_THROW );
+ m_aSelection = xSelSupp->getSelection();
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ }
+
+ ChartModelClone::~ChartModelClone()
+ {
+ if ( !impl_isDisposed() )
+ dispose();
+ }
+
+ void ChartModelClone::dispose()
+ {
+ if ( impl_isDisposed() )
+ return;
+
+ m_xModelClone.clear();
+ m_xDataClone.clear();
+ m_aSelection.clear();
+ }
+
+ ModelFacet ChartModelClone::getFacet() const
+ {
+ if ( m_aSelection.hasValue() )
+ return E_MODEL_WITH_SELECTION;
+ if ( m_xDataClone.is() )
+ return E_MODEL_WITH_DATA;
+ return E_MODEL;
+ }
+
+ void ChartModelClone::applyToModel( const rtl::Reference<::chart::ChartModel>& i_model ) const
+ {
+ applyModelContentToModel( i_model, m_xModelClone, m_xDataClone );
+
+ if ( m_aSelection.hasValue() )
+ {
+ try
+ {
+ Reference< XSelectionSupplier > xCurrentSelectionSuppl( i_model->getCurrentController(), UNO_QUERY_THROW );
+ xCurrentSelectionSuppl->select( m_aSelection );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ }
+ }
+
+ namespace
+ {
+ void ImplApplyDataToModel( const Reference< XModel >& i_model, const Reference< XInternalDataProvider > & i_data )
+ {
+ Reference< XChartDocument > xDoc( i_model, UNO_QUERY );
+ OSL_ASSERT( xDoc.is() && xDoc->hasInternalDataProvider() );
+
+ // copy data from stored internal data provider
+ if( xDoc.is() && xDoc->hasInternalDataProvider())
+ {
+ Reference< XAnyDescriptionAccess > xCurrentData( xDoc->getDataProvider(), UNO_QUERY );
+ Reference< XAnyDescriptionAccess > xSavedData( i_data, UNO_QUERY );
+ if ( xCurrentData.is() && xSavedData.is() )
+ {
+ xCurrentData->setData( xSavedData->getData() );
+ xCurrentData->setAnyRowDescriptions( xSavedData->getAnyRowDescriptions());
+ xCurrentData->setAnyColumnDescriptions( xSavedData->getAnyColumnDescriptions());
+ }
+ }
+ }
+ }
+
+ void ChartModelClone::applyModelContentToModel( const rtl::Reference<::chart::ChartModel>& i_model,
+ const rtl::Reference<::chart::ChartModel>& i_modelToCopyFrom,
+ const Reference< XInternalDataProvider >& i_data )
+ {
+ ENSURE_OR_RETURN_VOID( i_model.is(), "ChartModelElement::applyModelContentToModel: invalid source model!" );
+ ENSURE_OR_RETURN_VOID( i_modelToCopyFrom.is(), "ChartModelElement::applyModelContentToModel: invalid source model!" );
+ try
+ {
+ // locked controllers of destination
+ ControllerLockGuardUNO aLockedControllers( i_model );
+
+ // propagate the correct flag for plotting of hidden values to the data provider and all used sequences
+ ChartModelHelper::setIncludeHiddenCells(ChartModelHelper::isIncludeHiddenCells( i_modelToCopyFrom ), *i_model);
+
+ // diagram
+ i_model->setFirstDiagram( i_modelToCopyFrom->getFirstDiagram() );
+
+ // main title
+ i_model->setTitleObject( i_modelToCopyFrom->getTitleObject() );
+
+ // page background
+ ::comphelper::copyProperties(
+ i_modelToCopyFrom->getPageBackground(),
+ i_model->getPageBackground() );
+
+ // apply data (not applied in standard Undo)
+ if ( i_data.is() )
+ ImplApplyDataToModel( i_model, i_data );
+
+ // register all sequences at the internal data provider to get adapted
+ // indexes when columns are added/removed
+ if ( i_model->hasInternalDataProvider() )
+ {
+ Reference< XInternalDataProvider > xNewDataProvider( i_model->getDataProvider(), UNO_QUERY );
+ rtl::Reference< DataSource > xUsedData = DataSourceHelper::getUsedData( *i_model );
+ if ( xUsedData.is() && xNewDataProvider.is() )
+ {
+ const Sequence< Reference< XLabeledDataSequence > > aData( xUsedData->getDataSequences() );
+ for( Reference< XLabeledDataSequence > const & labeledDataSeq : aData )
+ {
+ xNewDataProvider->registerDataSequenceForChanges( labeledDataSeq->getValues() );
+ xNewDataProvider->registerDataSequenceForChanges( labeledDataSeq->getLabel() );
+ }
+ }
+ }
+
+ // restore modify status
+ if ( !i_modelToCopyFrom->isModified() )
+ {
+ i_model->setModified( false );
+ }
+ // \-- locked controllers of destination
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ }
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartModelClone.hxx b/chart2/source/controller/main/ChartModelClone.hxx
new file mode 100644
index 0000000000..41cf7fc109
--- /dev/null
+++ b/chart2/source/controller/main/ChartModelClone.hxx
@@ -0,0 +1,75 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <rtl/ref.hxx>
+
+namespace com::sun::star::chart2 { class XInternalDataProvider; }
+namespace com::sun::star::frame { class XModel; }
+
+namespace chart
+{
+class ChartModel;
+
+ enum ModelFacet
+ {
+ E_MODEL,
+ E_MODEL_WITH_DATA,
+ E_MODEL_WITH_SELECTION
+ };
+
+ class ChartModelClone
+ {
+ public:
+ ChartModelClone(
+ const rtl::Reference<::chart::ChartModel>& i_model,
+ const ModelFacet i_facet
+ );
+
+ ~ChartModelClone();
+
+ ChartModelClone(const ChartModelClone&) = delete;
+ const ChartModelClone& operator=(const ChartModelClone&) = delete;
+
+ ModelFacet getFacet() const;
+
+ void applyToModel( const rtl::Reference<::chart::ChartModel>& i_model ) const;
+
+ static void applyModelContentToModel(
+ const rtl::Reference<::chart::ChartModel> & i_model,
+ const rtl::Reference<::chart::ChartModel> & i_modelToCopyFrom,
+ const css::uno::Reference< css::chart2::XInternalDataProvider > & i_data );
+
+ void dispose();
+
+ private:
+ bool impl_isDisposed() const { return !m_xModelClone.is(); }
+
+ private:
+ rtl::Reference<::chart::ChartModel> m_xModelClone;
+ css::uno::Reference< css::chart2::XInternalDataProvider > m_xDataClone;
+ css::uno::Any m_aSelection;
+ };
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartTransferable.cxx b/chart2/source/controller/main/ChartTransferable.cxx
new file mode 100644
index 0000000000..2f27902ba1
--- /dev/null
+++ b/chart2/source/controller/main/ChartTransferable.cxx
@@ -0,0 +1,161 @@
+/* -*- 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 <sal/config.h>
+
+#include <memory>
+
+#include "ChartTransferable.hxx"
+
+#include <sot/exchange.hxx>
+#include <sot/storage.hxx>
+#include <unotools/streamwrap.hxx>
+#include <vcl/graph.hxx>
+#include <svl/itempool.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/unomodel.hxx>
+#include <svx/svdview.hxx>
+#include <osl/diagnose.h>
+
+constexpr sal_uInt32 CHARTTRANSFER_OBJECTTYPE_DRAWMODEL = 1;
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+
+namespace chart
+{
+
+ChartTransferable::ChartTransferable(
+ SdrModel& rSdrModel,
+ SdrObject* pSelectedObj,
+ bool bDrawing)
+ : m_bDrawing(bDrawing)
+{
+ std::unique_ptr<SdrExchangeView> pExchgView(std::make_unique<SdrView>( rSdrModel ));
+ SdrPageView* pPv = pExchgView->ShowSdrPage( rSdrModel.GetPage( 0 ));
+ if( pSelectedObj )
+ pExchgView->MarkObj( pSelectedObj, pPv );
+ else
+ pExchgView->MarkAllObj( pPv );
+ Graphic aGraphic( pExchgView->GetMarkedObjMetaFile(true));
+ m_xMetaFileGraphic.set( aGraphic.GetXGraphic());
+ if ( m_bDrawing )
+ {
+ m_xMarkedObjModel = pExchgView->CreateMarkedObjModel();
+ }
+}
+
+ChartTransferable::~ChartTransferable()
+{}
+
+void ChartTransferable::AddSupportedFormats()
+{
+ if ( m_bDrawing )
+ {
+ AddFormat( SotClipboardFormatId::DRAWING );
+ }
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+}
+
+bool ChartTransferable::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
+{
+ SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
+ bool bResult = false;
+
+ if( HasFormat( nFormat ))
+ {
+ if ( nFormat == SotClipboardFormatId::DRAWING )
+ {
+ bResult = SetObject(m_xMarkedObjModel.get(), CHARTTRANSFER_OBJECTTYPE_DRAWMODEL, rFlavor);
+ }
+ else if ( nFormat == SotClipboardFormatId::GDIMETAFILE )
+ {
+ Graphic aGraphic( m_xMetaFileGraphic );
+ bResult = SetGDIMetaFile( aGraphic.GetGDIMetaFile() );
+ }
+ else if( nFormat == SotClipboardFormatId::BITMAP )
+ {
+ Graphic aGraphic( m_xMetaFileGraphic );
+ bResult = SetBitmapEx( aGraphic.GetBitmapEx(), rFlavor );
+ }
+ }
+
+ return bResult;
+}
+
+bool ChartTransferable::WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId,
+ const datatransfer::DataFlavor& /* rFlavor */ )
+{
+ // called from SetObject, put data into stream
+
+ bool bRet = false;
+ switch ( nUserObjectId )
+ {
+ case CHARTTRANSFER_OBJECTTYPE_DRAWMODEL:
+ {
+ SdrModel* pMarkedObjModel = static_cast< SdrModel* >( pUserObject );
+ if ( pMarkedObjModel )
+ {
+ rxOStm->SetBufferSize( 0xff00 );
+
+ // for the changed pool defaults from drawing layer pool set those
+ // attributes as hard attributes to preserve them for saving
+ const SfxItemPool& rItemPool = pMarkedObjModel->GetItemPool();
+ const SvxFontHeightItem& rDefaultFontHeight = rItemPool.GetDefaultItem( EE_CHAR_FONTHEIGHT );
+ sal_uInt16 nCount = pMarkedObjModel->GetPageCount();
+ for ( sal_uInt16 i = 0; i < nCount; ++i )
+ {
+ const SdrPage* pPage = pMarkedObjModel->GetPage( i );
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ while ( aIter.IsMore() )
+ {
+ SdrObject* pObj = aIter.Next();
+ const SvxFontHeightItem& rItem = pObj->GetMergedItem( EE_CHAR_FONTHEIGHT );
+ if ( rItem.GetHeight() == rDefaultFontHeight.GetHeight() )
+ {
+ pObj->SetMergedItem( rDefaultFontHeight );
+ }
+ }
+ }
+
+ Reference< io::XOutputStream > xDocOut( new utl::OOutputStreamWrapper( *rxOStm ) );
+ SvxDrawingLayerExport( pMarkedObjModel, xDocOut );
+
+ bRet = ( rxOStm->GetError() == ERRCODE_NONE );
+ }
+ }
+ break;
+ default:
+ {
+ OSL_FAIL( "ChartTransferable::WriteObject: unknown object id" );
+ }
+ break;
+ }
+ return bRet;
+}
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartTransferable.hxx b/chart2/source/controller/main/ChartTransferable.hxx
new file mode 100644
index 0000000000..fd782864bf
--- /dev/null
+++ b/chart2/source/controller/main/ChartTransferable.hxx
@@ -0,0 +1,60 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <vcl/transfer.hxx>
+
+namespace com::sun::star {
+ namespace graphic {
+ class XGraphic;
+ }
+}
+
+class SdrModel;
+class SdrObject;
+
+namespace chart
+{
+
+class ChartTransferable : public TransferableHelper
+{
+public:
+ explicit ChartTransferable(
+ SdrModel& rSdrModel,
+ SdrObject* pSelectedObj,
+ bool bDrawing );
+ virtual ~ChartTransferable() override;
+
+protected:
+
+ // implementation of TransferableHelper methods
+ virtual void AddSupportedFormats() override;
+ virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override;
+ virtual bool WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId,
+ const css::datatransfer::DataFlavor& rFlavor ) override;
+
+private:
+ css::uno::Reference< css::graphic::XGraphic > m_xMetaFileGraphic;
+ std::unique_ptr<SdrModel> m_xMarkedObjModel;
+ bool m_bDrawing;
+};
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ChartWindow.cxx b/chart2/source/controller/main/ChartWindow.cxx
new file mode 100644
index 0000000000..60ab7eb0ed
--- /dev/null
+++ b/chart2/source/controller/main/ChartWindow.cxx
@@ -0,0 +1,376 @@
+/* -*- 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 <config_wasm_strip.h>
+#include <ChartWindow.hxx>
+#include <ChartController.hxx>
+#include <helpids.h>
+#include <uiobject.hxx>
+
+#include <vcl/help.hxx>
+#include <vcl/settings.hxx>
+
+#include <sfx2/ipclient.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <comphelper/lok.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+::tools::Rectangle lcl_AWTRectToVCLRect( const css::awt::Rectangle & rAWTRect )
+{
+ ::tools::Rectangle aResult(rAWTRect.X, rAWTRect.Y);
+ aResult.setWidth( rAWTRect.Width );
+ aResult.setHeight( rAWTRect.Height );
+ return aResult;
+}
+} // anonymous namespace
+
+namespace chart
+{
+
+ChartWindow::ChartWindow( ChartController* pController, vcl::Window* pParent, WinBits nStyle )
+ : Window(pParent, nStyle)
+ , m_pWindowController( pController )
+ , m_bInPaint(false)
+ , m_pViewShellWindow( nullptr )
+{
+ set_id("chart_window");
+ SetHelpId( HID_SCH_WIN_DOCUMENT );
+ SetMapMode( MapMode(MapUnit::Map100thMM) );
+ adjustHighContrastMode();
+ // chart does not depend on exact pixel painting => enable antialiased drawing
+ GetOutDev()->SetAntialiasing( AntialiasingFlags::Enable | GetOutDev()->GetAntialiasing() );
+ EnableRTL( false );
+ if( pParent )
+ pParent->EnableRTL( false );// #i96215# necessary for a correct position of the context menu in rtl mode
+}
+
+ChartWindow::~ChartWindow()
+{
+ disposeOnce();
+}
+
+void ChartWindow::dispose()
+{
+ m_pWindowController = nullptr;
+ m_pViewShellWindow.clear();
+ vcl::Window::dispose();
+}
+
+void ChartWindow::PrePaint(vcl::RenderContext& )
+{
+ // forward VCLs PrePaint window event to DrawingLayer
+ if (m_pWindowController)
+ {
+ m_pWindowController->PrePaint();
+ }
+}
+
+void ChartWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ if (comphelper::LibreOfficeKit::isActive() && !rRenderContext.IsVirtual())
+ return;
+
+ m_bInPaint = true;
+ if (m_pWindowController)
+ {
+ m_pWindowController->execute_Paint(rRenderContext, rRect);
+ }
+ else
+ {
+ Window::Paint(rRenderContext, rRect);
+ }
+ m_bInPaint = false;
+}
+
+void ChartWindow::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if( m_pWindowController )
+ m_pWindowController->execute_MouseButtonDown(rMEvt);
+ else
+ Window::MouseButtonDown(rMEvt);
+}
+
+void ChartWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ if( m_pWindowController )
+ m_pWindowController->execute_MouseMove( rMEvt );
+ else
+ Window::MouseMove( rMEvt );
+}
+
+void ChartWindow::Tracking( const TrackingEvent& rTEvt )
+{
+ if( !m_pWindowController )
+ Window::Tracking( rTEvt );
+}
+
+void ChartWindow::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ if( m_pWindowController )
+ m_pWindowController->execute_MouseButtonUp( rMEvt );
+ else
+ Window::MouseButtonUp( rMEvt );
+}
+
+void ChartWindow::Resize()
+{
+ if( m_pWindowController )
+ m_pWindowController->execute_Resize();
+ else
+ Window::Resize();
+}
+
+void ChartWindow::Activate()
+{
+ if( !m_pWindowController )
+ Window::Activate();
+}
+void ChartWindow::Deactivate()
+{
+ if( !m_pWindowController )
+ Window::Deactivate();
+}
+void ChartWindow::GetFocus()
+{
+ if( !m_pWindowController )
+ Window::GetFocus();
+}
+void ChartWindow::LoseFocus()
+{
+ if( !m_pWindowController )
+ Window::LoseFocus();
+}
+
+void ChartWindow::Command( const CommandEvent& rCEvt )
+{
+ if( m_pWindowController )
+ m_pWindowController->execute_Command( rCEvt );
+ else
+ Window::Command( rCEvt );
+}
+
+void ChartWindow::KeyInput( const KeyEvent& rKEvt )
+{
+ if( m_pWindowController )
+ {
+ if( !m_pWindowController->execute_KeyInput(rKEvt) )
+ Window::KeyInput(rKEvt);
+ }
+ else
+ Window::KeyInput( rKEvt );
+}
+
+uno::Reference< css::accessibility::XAccessible > ChartWindow::CreateAccessible()
+{
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if( m_pWindowController )
+ return m_pWindowController->CreateAccessible();
+ else
+ return Window::CreateAccessible();
+#else
+ return uno::Reference< css::accessibility::XAccessible >();
+#endif
+}
+
+void ChartWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ vcl::Window::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ adjustHighContrastMode();
+ }
+}
+
+void ChartWindow::RequestHelp( const HelpEvent& rHEvt )
+{
+ bool bHelpHandled = false;
+ if( ( rHEvt.GetMode() & HelpEventMode::QUICK ) &&
+ m_pWindowController )
+ {
+ Point aLogicHitPos = PixelToLogic( GetPointerPosPixel());
+ OUString aQuickHelpText;
+ awt::Rectangle aHelpRect;
+ bool bIsBalloonHelp( Help::IsBalloonHelpEnabled() );
+ bHelpHandled = m_pWindowController->requestQuickHelp( aLogicHitPos, bIsBalloonHelp, aQuickHelpText, aHelpRect );
+
+ if( bHelpHandled )
+ {
+ tools::Rectangle aPixelRect(LogicToPixel(lcl_AWTRectToVCLRect(aHelpRect)));
+ tools::Rectangle aScreenRect(OutputToScreenPixel(aPixelRect.TopLeft()),
+ OutputToScreenPixel(aPixelRect.BottomRight()));
+
+ if( bIsBalloonHelp )
+ Help::ShowBalloon(this, rHEvt.GetMousePosPixel(), aScreenRect, aQuickHelpText);
+ else
+ Help::ShowQuickHelp(this, aScreenRect, aQuickHelpText);
+ }
+ }
+
+ if( !bHelpHandled )
+ vcl::Window::RequestHelp( rHEvt );
+}
+
+void ChartWindow::adjustHighContrastMode()
+{
+ static const DrawModeFlags nContrastMode =
+ DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill |
+ DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient;
+
+ bool bUseContrast = GetSettings().GetStyleSettings().GetHighContrastMode();
+ GetOutDev()->SetDrawMode( bUseContrast ? nContrastMode : DrawModeFlags::Default );
+}
+
+void ChartWindow::ForceInvalidate()
+{
+ vcl::Window::Invalidate();
+}
+void ChartWindow::ImplInvalidate( const vcl::Region* rRegion, InvalidateFlags nFlags )
+{
+ if( m_bInPaint ) // #i101928# superfluous paint calls while entering and editing charts"
+ return;
+ vcl::Window::ImplInvalidate( rRegion, nFlags );
+}
+
+void ChartWindow::LogicInvalidate(const tools::Rectangle* pRectangle)
+{
+ SfxViewShell* pCurrentShell = SfxViewShell::Current();
+ if ( nullptr == pCurrentShell )
+ return;
+ tools::Rectangle aResultRectangle;
+ if (!pRectangle)
+ {
+ // we have to invalidate the whole chart area not the whole document
+ aResultRectangle = GetBoundingBox();
+ }
+ else
+ {
+ tools::Rectangle aRectangle(*pRectangle);
+ // When dragging shapes the map mode is disabled.
+ if (IsMapModeEnabled())
+ {
+ if (GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+ {
+ aRectangle = o3tl::convert(aRectangle, o3tl::Length::mm100, o3tl::Length::twip);
+ }
+ }
+ else
+ {
+ aRectangle = PixelToLogic(aRectangle, MapMode(MapUnit::MapTwip));
+ }
+
+ vcl::Window* pEditWin = GetParentEditWin();
+ if (pEditWin)
+ {
+ MapMode aCWMapMode = GetMapMode();
+ constexpr auto p = o3tl::getConversionMulDiv(o3tl::Length::px, o3tl::Length::twip);
+ const auto& scaleX = aCWMapMode.GetScaleX();
+ const auto& scaleY = aCWMapMode.GetScaleY();
+ const auto nXNum = p.first * scaleX.GetDenominator();
+ const auto nXDen = p.second * scaleX.GetNumerator();
+ const auto nYNum = p.first * scaleY.GetDenominator();
+ const auto nYDen = p.second * scaleY.GetNumerator();
+
+ if (!IsMapModeEnabled())
+ {
+ aRectangle = aRectangle.scale(scaleX.GetDenominator(), scaleX.GetNumerator(),
+ scaleY.GetDenominator(), scaleY.GetNumerator());
+ }
+
+ Point aOffset = this->GetOffsetPixelFrom(*pEditWin).scale(nXNum, nXDen, nYNum, nYDen);
+
+ aRectangle = tools::Rectangle(aRectangle.TopLeft() + aOffset, aRectangle.GetSize());
+ }
+
+ aResultRectangle = aRectangle;
+ }
+ SfxLokHelper::notifyInvalidation(pCurrentShell, &aResultRectangle);
+}
+
+FactoryFunction ChartWindow::GetUITestFactory() const
+{
+ return ChartWindowUIObject::create;
+}
+
+ChartController* ChartWindow::GetController()
+{
+ return m_pWindowController;
+}
+
+vcl::Window* ChartWindow::GetParentEditWin()
+{
+ if (m_pViewShellWindow)
+ return m_pViewShellWindow.get();
+
+ // So, you are thinking, why do not invoke pCurrentShell->GetWindow() ?
+ // Because in Impress the parent edit win is not view shell window.
+ SfxViewShell* pCurrentShell = SfxViewShell::Current();
+ if( pCurrentShell )
+ {
+ SfxInPlaceClient* pIPClient = pCurrentShell->GetIPClient();
+ if (pIPClient)
+ {
+ vcl::Window* pRootWin = pIPClient->GetEditWin();
+ if(pRootWin && pRootWin->IsAncestorOf(*this))
+ {
+ m_pViewShellWindow = pRootWin;
+ return m_pViewShellWindow.get();
+ }
+ }
+ }
+ return nullptr;
+}
+
+tools::Rectangle ChartWindow::GetBoundingBox()
+{
+ tools::Rectangle aBBox;
+
+ vcl::Window* pRootWin = GetParentEditWin();
+ if (pRootWin)
+ {
+ // In all cases, the following code fragment
+ // returns the chart bounding box in twips.
+ MapMode aCWMapMode = GetMapMode();
+ constexpr auto p = o3tl::getConversionMulDiv(o3tl::Length::px, o3tl::Length::twip);
+ const auto& scaleX = aCWMapMode.GetScaleX();
+ const auto& scaleY = aCWMapMode.GetScaleY();
+ const auto nXNum = p.first * scaleX.GetDenominator();
+ const auto nXDen = p.second * scaleX.GetNumerator();
+ const auto nYNum = p.first * scaleY.GetDenominator();
+ const auto nYDen = p.second * scaleY.GetNumerator();
+
+ Point aOffset = GetOffsetPixelFrom(*pRootWin);
+ aOffset.setX( o3tl::convert(aOffset.X(), nXNum, nXDen) );
+ aOffset.setY( o3tl::convert(aOffset.Y(), nYNum, nYDen) );
+ Size aSize = GetSizePixel();
+ aSize.setWidth( o3tl::convert(aSize.Width(), nXNum, nXDen) );
+ aSize.setHeight( o3tl::convert(aSize.Height(), nYNum, nYDen) );
+ aBBox = tools::Rectangle(aOffset, aSize);
+ }
+ return aBBox;
+}
+
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/CommandDispatch.cxx b/chart2/source/controller/main/CommandDispatch.cxx
new file mode 100644
index 0000000000..37a56e1512
--- /dev/null
+++ b/chart2/source/controller/main/CommandDispatch.cxx
@@ -0,0 +1,141 @@
+/* -*- 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 "CommandDispatch.hxx"
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace chart
+{
+
+CommandDispatch::CommandDispatch(
+ const Reference< uno::XComponentContext > & xContext ) :
+ m_xContext( xContext )
+{
+}
+
+CommandDispatch::~CommandDispatch()
+{}
+
+void CommandDispatch::initialize()
+{}
+
+// ____ WeakComponentImplHelperBase ____
+/// is called when this is disposed
+void CommandDispatch::disposing(std::unique_lock<std::mutex>& rGuard)
+{
+ Reference< uno::XInterface > xEventSource(static_cast< cppu::OWeakObject* >( this ));
+ for( auto& rElement : m_aListeners )
+ rElement.second.disposeAndClear( rGuard, xEventSource );
+ m_aListeners.clear();
+}
+
+// ____ XDispatch ____
+void SAL_CALL CommandDispatch::dispatch( const util::URL& /* URL */, const Sequence< beans::PropertyValue >& /* Arguments */ )
+{}
+
+void SAL_CALL CommandDispatch::addStatusListener( const Reference< frame::XStatusListener >& Control, const util::URL& URL )
+{
+ {
+ std::unique_lock g(m_aMutex);
+ tListenerMap::iterator aIt( m_aListeners.find( URL.Complete ));
+ if( aIt == m_aListeners.end())
+ {
+ aIt = m_aListeners.emplace(
+ std::piecewise_construct,
+ std::forward_as_tuple(URL.Complete),
+ std::forward_as_tuple()).first;
+ }
+ assert( aIt != m_aListeners.end());
+
+ aIt->second.addInterface( g, Control );
+ }
+ fireStatusEvent( URL.Complete, Control );
+}
+
+void SAL_CALL CommandDispatch::removeStatusListener( const Reference< frame::XStatusListener >& Control, const util::URL& URL )
+{
+ std::unique_lock g(m_aMutex);
+ tListenerMap::iterator aIt( m_aListeners.find( URL.Complete ));
+ if( aIt != m_aListeners.end())
+ (*aIt).second.removeInterface( g, Control );
+}
+
+// ____ XModifyListener ____
+void SAL_CALL CommandDispatch::modified( const lang::EventObject& /* aEvent */ )
+{
+ fireAllStatusEvents( nullptr );
+}
+
+// ____ XEventListener (base of XModifyListener) ____
+void SAL_CALL CommandDispatch::disposing( const lang::EventObject& /* Source */ )
+{}
+
+void CommandDispatch::fireAllStatusEvents(
+ const css::uno::Reference< css::frame::XStatusListener > & xSingleListener )
+{
+ fireStatusEvent( OUString(), xSingleListener );
+}
+
+void CommandDispatch::fireStatusEventForURL(
+ const OUString & rURL,
+ const uno::Any & rState,
+ bool bEnabled,
+ const Reference< frame::XStatusListener > & xSingleListener /* = 0 */)
+{
+ // prepare event to send
+ util::URL aURL;
+ aURL.Complete = rURL;
+ if( !m_xURLTransformer.is())
+ {
+ m_xURLTransformer.set( util::URLTransformer::create(m_xContext) );
+ }
+ m_xURLTransformer->parseStrict( aURL );
+
+ frame::FeatureStateEvent aEventToSend(
+ static_cast< cppu::OWeakObject* >( this ), // Source
+ aURL, // FeatureURL
+ OUString(), // FeatureDescriptor
+ bEnabled, // IsEnabled
+ false, // Requery
+ rState // State
+ );
+
+ // send event either to single listener or all registered ones
+ if( xSingleListener.is())
+ xSingleListener->statusChanged( aEventToSend );
+ else
+ {
+ tListenerMap::iterator aIt( m_aListeners.find( aURL.Complete ));
+ if( aIt != m_aListeners.end())
+ {
+ std::unique_lock g(m_aMutex);
+ aIt->second.notifyEach(g, &css::frame::XStatusListener::statusChanged, aEventToSend);
+ }
+ }
+}
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/CommandDispatch.hxx b/chart2/source/controller/main/CommandDispatch.hxx
new file mode 100644
index 0000000000..41171926b6
--- /dev/null
+++ b/chart2/source/controller/main/CommandDispatch.hxx
@@ -0,0 +1,130 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <comphelper/compbase.hxx>
+#include <comphelper/interfacecontainer4.hxx>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/util/XModifyListener.hpp>
+
+#include <map>
+#include <memory>
+
+namespace com::sun::star::uno { class XComponentContext; }
+namespace com::sun::star::util { class XURLTransformer; }
+
+namespace chart
+{
+
+namespace impl
+{
+typedef ::comphelper::WeakComponentImplHelper<
+ css::frame::XDispatch,
+ css::util::XModifyListener >
+ CommandDispatch_Base;
+}
+
+/** This is the base class for an XDispatch.
+ */
+class CommandDispatch : public impl::CommandDispatch_Base
+{
+public:
+ explicit CommandDispatch( const css::uno::Reference< css::uno::XComponentContext > & xContext );
+ virtual ~CommandDispatch() override;
+
+ // late initialisation, especially for adding as listener
+ virtual void initialize();
+
+protected:
+ /** sends a status event for a specific command to all registered listeners
+ or only the one given when set.
+
+ This method should be overridden. The implementation should call
+ fireStatusEventForURL and pass the xSingleListener argument to this
+ method unchanged.
+
+ @param rURL
+ If empty, all available status events must be fired, otherwise only
+ the one for the given command.
+
+ @param xSingleListener
+ If set, the event is only sent to this listener rather than to all
+ registered ones. Whenever a listener adds itself, this method is
+ called with this parameter set to give an initial state.
+ */
+ virtual void fireStatusEvent(
+ const OUString & rURL,
+ const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ) = 0;
+
+ /** calls fireStatusEvent( OUString, xSingleListener )
+ */
+ void fireAllStatusEvents(
+ const css::uno::Reference< css::frame::XStatusListener > & xSingleListener );
+
+ /** sends a status event for a specific command to all registered listeners
+ or only the one given when set.
+
+ @param xSingleListener
+ If set, the event is only sent to this listener rather than to all
+ registered ones. Whenever a listener adds itself, this method is
+ called with this parameter set to give an initial state.
+ */
+ void fireStatusEventForURL(
+ const OUString & rURL,
+ const css::uno::Any & rState,
+ bool bEnabled,
+ const css::uno::Reference< css::frame::XStatusListener > & xSingleListener );
+
+ // ____ XDispatch ____
+ virtual void SAL_CALL dispatch(
+ const css::util::URL& URL,
+ const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+ virtual void SAL_CALL addStatusListener(
+ const css::uno::Reference< css::frame::XStatusListener >& Control,
+ const css::util::URL& URL ) override;
+ virtual void SAL_CALL removeStatusListener(
+ const css::uno::Reference< css::frame::XStatusListener >& Control,
+ const css::util::URL& URL ) override;
+
+ // ____ WeakComponentImplHelperBase ____
+ /// is called when this is disposed
+ virtual void disposing(std::unique_lock<std::mutex>& rGuard) override;
+
+ // ____ XModifyListener ____
+ virtual void SAL_CALL modified(
+ const css::lang::EventObject& aEvent ) override;
+
+ // ____ XEventListener (base of XModifyListener) ____
+ virtual void SAL_CALL disposing(
+ const css::lang::EventObject& Source ) override;
+
+private:
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::util::XURLTransformer > m_xURLTransformer;
+
+ typedef std::map< OUString, ::comphelper::OInterfaceContainerHelper4<css::frame::XStatusListener> >
+ tListenerMap;
+
+ tListenerMap m_aListeners;
+
+};
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/CommandDispatchContainer.cxx b/chart2/source/controller/main/CommandDispatchContainer.cxx
new file mode 100644
index 0000000000..c16a0e45be
--- /dev/null
+++ b/chart2/source/controller/main/CommandDispatchContainer.cxx
@@ -0,0 +1,201 @@
+/* -*- 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 <CommandDispatchContainer.hxx>
+#include "UndoCommandDispatch.hxx"
+#include "StatusBarCommandDispatch.hxx"
+#include <DisposeHelper.hxx>
+#include "DrawCommandDispatch.hxx"
+#include "ShapeController.hxx"
+#include <ChartModel.hxx>
+
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <osl/diagnose.h>
+#include <rtl/ref.hxx>
+
+#include <o3tl/sorted_vector.hxx>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace chart
+{
+
+CommandDispatchContainer::CommandDispatchContainer(
+ const Reference< uno::XComponentContext > & xContext )
+ :m_xContext( xContext )
+ ,m_pDrawCommandDispatch( nullptr )
+ ,m_pShapeController( nullptr )
+{
+}
+
+void CommandDispatchContainer::setModel(
+ const rtl::Reference<::chart::ChartModel> & xModel )
+{
+ // remove all existing dispatcher that base on the old model
+ m_aCachedDispatches.clear();
+ DisposeHelper::DisposeAllElements( m_aToBeDisposedDispatches );
+ m_aToBeDisposedDispatches.clear();
+ m_xModel = xModel.get();
+}
+
+void CommandDispatchContainer::setChartDispatch(
+ const Reference< frame::XDispatch >& rChartDispatch,
+ o3tl::sorted_vector< OUString > && rChartCommands )
+{
+ OSL_ENSURE(rChartDispatch.is(),"Invalid fall back dispatcher!");
+ m_xChartDispatcher.set( rChartDispatch );
+ m_aChartCommands = std::move(rChartCommands);
+ m_aToBeDisposedDispatches.push_back( m_xChartDispatcher );
+}
+
+Reference< frame::XDispatch > CommandDispatchContainer::getDispatchForURL(
+ const util::URL & rURL )
+{
+ static const o3tl::sorted_vector< OUString > s_aContainerDocumentCommands {
+ "AddDirect", "NewDoc", "Open",
+ "Save", "SaveAs", "SendMail",
+ "EditDoc", "ExportDirectToPDF", "PrintDefault"};
+
+ Reference< frame::XDispatch > xResult;
+ tDispatchMap::const_iterator aIt( m_aCachedDispatches.find( rURL.Complete ));
+ if( aIt != m_aCachedDispatches.end())
+ {
+ xResult.set( (*aIt).second );
+ }
+ else
+ {
+ rtl::Reference< ::chart::ChartModel > xModel( m_xModel );
+
+ if( xModel.is() && ( rURL.Path == "Undo" || rURL.Path == "Redo" ||
+ rURL.Path == "GetUndoStrings" || rURL.Path == "GetRedoStrings" ) )
+ {
+ rtl::Reference<CommandDispatch> pDispatch = new UndoCommandDispatch( m_xContext, xModel );
+ xResult.set( pDispatch );
+ pDispatch->initialize();
+ m_aCachedDispatches[ ".uno:Undo" ].set( xResult );
+ m_aCachedDispatches[ ".uno:Redo" ].set( xResult );
+ m_aCachedDispatches[ ".uno:GetUndoStrings" ].set( xResult );
+ m_aCachedDispatches[ ".uno:GetRedoStrings" ].set( xResult );
+ m_aToBeDisposedDispatches.push_back( xResult );
+ }
+ else if( xModel.is() && ( rURL.Path == "Context" || rURL.Path == "ModifiedStatus" ) )
+ {
+ Reference< view::XSelectionSupplier > xSelSupp( xModel->getCurrentController(), uno::UNO_QUERY );
+ rtl::Reference<CommandDispatch> pDispatch = new StatusBarCommandDispatch( m_xContext, xModel, xSelSupp );
+ xResult.set( pDispatch );
+ pDispatch->initialize();
+ m_aCachedDispatches[ ".uno:Context" ].set( xResult );
+ m_aCachedDispatches[ ".uno:ModifiedStatus" ].set( xResult );
+ m_aToBeDisposedDispatches.push_back( xResult );
+ }
+ else if( xModel.is() &&
+ (s_aContainerDocumentCommands.find( rURL.Path ) != s_aContainerDocumentCommands.end()) )
+ {
+ xResult.set( getContainerDispatchForURL( xModel->getCurrentController(), rURL ));
+ // ToDo: can those dispatches be cached?
+ m_aCachedDispatches[ rURL.Complete ].set( xResult );
+ }
+ else if( m_xChartDispatcher.is() &&
+ (m_aChartCommands.find( rURL.Path ) != m_aChartCommands.end()) )
+ {
+ xResult.set( m_xChartDispatcher );
+ m_aCachedDispatches[ rURL.Complete ].set( xResult );
+ }
+ // #i12587# support for shapes in chart
+ // Note, that the chart dispatcher must be queried first, because
+ // the chart dispatcher is the default dispatcher for all context
+ // sensitive commands.
+ else if ( m_pDrawCommandDispatch && m_pDrawCommandDispatch->isFeatureSupported( rURL.Complete ) )
+ {
+ xResult.set( m_pDrawCommandDispatch );
+ m_aCachedDispatches[ rURL.Complete ].set( xResult );
+ }
+ else if ( m_pShapeController && m_pShapeController->isFeatureSupported( rURL.Complete ) )
+ {
+ xResult.set( m_pShapeController );
+ m_aCachedDispatches[ rURL.Complete ].set( xResult );
+ }
+ }
+
+ return xResult;
+}
+
+Sequence< Reference< frame::XDispatch > > CommandDispatchContainer::getDispatchesForURLs(
+ const Sequence< frame::DispatchDescriptor > & aDescriptors )
+{
+ sal_Int32 nCount = aDescriptors.getLength();
+ uno::Sequence< uno::Reference< frame::XDispatch > > aRet( nCount );
+ auto aRetRange = asNonConstRange(aRet);
+
+ for( sal_Int32 nPos = 0; nPos < nCount; ++nPos )
+ {
+ if ( aDescriptors[ nPos ].FrameName == "_self" )
+ aRetRange[ nPos ] = getDispatchForURL( aDescriptors[ nPos ].FeatureURL );
+ }
+ return aRet;
+}
+
+void CommandDispatchContainer::DisposeAndClear()
+{
+ m_aCachedDispatches.clear();
+ DisposeHelper::DisposeAllElements( m_aToBeDisposedDispatches );
+ m_aToBeDisposedDispatches.clear();
+ m_xChartDispatcher.clear();
+ m_aChartCommands.clear();
+ m_pDrawCommandDispatch = nullptr;
+ m_pShapeController = nullptr;
+}
+
+Reference< frame::XDispatch > CommandDispatchContainer::getContainerDispatchForURL(
+ const Reference< frame::XController > & xChartController,
+ const util::URL & rURL )
+{
+ Reference< frame::XDispatch > xResult;
+ if( xChartController.is())
+ {
+ Reference< frame::XFrame > xFrame( xChartController->getFrame());
+ if( xFrame.is())
+ {
+ Reference< frame::XDispatchProvider > xDispProv( xFrame->getCreator(), uno::UNO_QUERY );
+ if( xDispProv.is())
+ xResult.set( xDispProv->queryDispatch( rURL, "_self", 0 ));
+ }
+ }
+ return xResult;
+}
+
+void CommandDispatchContainer::setDrawCommandDispatch( DrawCommandDispatch* pDispatch )
+{
+ m_pDrawCommandDispatch = pDispatch;
+ m_aToBeDisposedDispatches.emplace_back( pDispatch );
+}
+
+void CommandDispatchContainer::setShapeController( ShapeController* pController )
+{
+ m_pShapeController = pController;
+ m_aToBeDisposedDispatches.emplace_back( pController );
+}
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ControllerCommandDispatch.cxx b/chart2/source/controller/main/ControllerCommandDispatch.cxx
new file mode 100644
index 0000000000..5317c1c47c
--- /dev/null
+++ b/chart2/source/controller/main/ControllerCommandDispatch.cxx
@@ -0,0 +1,844 @@
+/* -*- 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 "ControllerCommandDispatch.hxx"
+#include <ChartModelHelper.hxx>
+#include <ChartModel.hxx>
+#include <DiagramHelper.hxx>
+#include <Diagram.hxx>
+#include <Axis.hxx>
+#include <AxisHelper.hxx>
+#include <TitleHelper.hxx>
+#include <LegendHelper.hxx>
+#include <ObjectIdentifier.hxx>
+#include <ChartType.hxx>
+#include <ChartTypeHelper.hxx>
+#include <ChartController.hxx>
+#include <RegressionCurveHelper.hxx>
+#include <DataSeries.hxx>
+#include <DataSeriesHelper.hxx>
+#include <StatisticsHelper.hxx>
+#include <ReferenceSizeProvider.hxx>
+#include "ShapeController.hxx"
+
+#include <vcl/svapp.hxx>
+#include <sal/log.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/lok.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/objsh.hxx>
+
+#include <com/sun/star/chart2/XRegressionCurve.hpp>
+#include <com/sun/star/chart2/XDataProviderAccess.hpp>
+
+// only needed until #i68864# is fixed
+#include <com/sun/star/frame/XLayoutManager.hpp>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace
+{
+bool lcl_isStatusBarVisible( const Reference< frame::XController > & xController )
+{
+ bool bIsStatusBarVisible = false;
+ // Status-Bar visible, workaround: this should not be necessary. @todo:
+ // remove when Issue #i68864# is fixed
+ if( xController.is())
+ {
+ Reference< beans::XPropertySet > xPropSet( xController->getFrame(), uno::UNO_QUERY );
+ if( xPropSet.is() )
+ {
+ uno::Reference< css::frame::XLayoutManager > xLayoutManager;
+ xPropSet->getPropertyValue( "LayoutManager" ) >>= xLayoutManager;
+ if ( xLayoutManager.is() )
+ bIsStatusBarVisible = xLayoutManager->isElementVisible( "private:resource/statusbar/statusbar" );
+ }
+ }
+ return bIsStatusBarVisible;
+}
+
+} // anonymous namespace
+
+namespace chart
+{
+
+namespace impl
+{
+
+/// Constants for moving the series.
+namespace {
+ bool const MOVE_SERIES_FORWARD = true;
+ bool const MOVE_SERIES_BACKWARD = false;
+}
+
+/** Represents the current state of the controller (needed for issue 63017).
+
+ You can set the state by calling update(). After this call the state is
+ preserved in this class until the next call to update().
+
+ This is useful, not to say necessary, for enabling and disabling of menu
+ entries (e.g. format>arrangement). As the status requests are sent very
+ frequently it would be impossible, from a performance point of view, to
+ query the current status every time directly at the model. So this class
+ serves as a cache for the state.
+*/
+struct ControllerState
+{
+ ControllerState();
+
+ void update( const Reference< frame::XController > & xController,
+ const rtl::Reference<::chart::ChartModel> & xModel );
+
+ // -- State variables -------
+ bool bHasSelectedObject;
+ bool bIsPositionableObject;
+ bool bIsTextObject;
+ bool bIsDeleteableObjectSelected;
+ bool bIsFormateableObjectSelected;
+
+ // May the selected series be moved forward or backward (cf
+ // format>arrangement).
+ bool bMayMoveSeriesForward;
+ bool bMayMoveSeriesBackward;
+
+ // trendlines
+ bool bMayAddMenuTrendline;
+ bool bMayAddTrendline;
+ bool bMayAddTrendlineEquation;
+ bool bMayAddR2Value;
+ bool bMayAddMeanValue;
+ bool bMayAddXErrorBars;
+ bool bMayAddYErrorBars;
+
+ bool bMayDeleteTrendline;
+ bool bMayDeleteTrendlineEquation;
+ bool bMayDeleteR2Value;
+ bool bMayDeleteMeanValue;
+ bool bMayDeleteXErrorBars;
+ bool bMayDeleteYErrorBars;
+
+ bool bMayFormatTrendline;
+ bool bMayFormatTrendlineEquation;
+ bool bMayFormatMeanValue;
+ bool bMayFormatXErrorBars;
+ bool bMayFormatYErrorBars;
+};
+
+ControllerState::ControllerState() :
+ bHasSelectedObject( false ),
+ bIsPositionableObject( false ),
+ bIsTextObject(false),
+ bIsDeleteableObjectSelected(false),
+ bIsFormateableObjectSelected(false),
+ bMayMoveSeriesForward( false ),
+ bMayMoveSeriesBackward( false ),
+ bMayAddMenuTrendline( false ),
+ bMayAddTrendline( false ),
+ bMayAddTrendlineEquation( false ),
+ bMayAddR2Value( false ),
+ bMayAddMeanValue( false ),
+ bMayAddXErrorBars( false ),
+ bMayAddYErrorBars( false ),
+ bMayDeleteTrendline( false ),
+ bMayDeleteTrendlineEquation( false ),
+ bMayDeleteR2Value( false ),
+ bMayDeleteMeanValue( false ),
+ bMayDeleteXErrorBars( false ),
+ bMayDeleteYErrorBars( false ),
+ bMayFormatTrendline( false ),
+ bMayFormatTrendlineEquation( false ),
+ bMayFormatMeanValue( false ),
+ bMayFormatXErrorBars( false ),
+ bMayFormatYErrorBars( false )
+{}
+
+void ControllerState::update(
+ const Reference< frame::XController > & xController,
+ const rtl::Reference<::chart::ChartModel> & xModel )
+{
+ Reference< view::XSelectionSupplier > xSelectionSupplier(
+ xController, uno::UNO_QUERY );
+
+ // Update ControllerState variables.
+ if( !xSelectionSupplier.is())
+ return;
+
+ uno::Any aSelObj( xSelectionSupplier->getSelection() );
+ ObjectIdentifier aSelOID( aSelObj );
+ OUString aSelObjCID( aSelOID.getObjectCID() );
+
+ bHasSelectedObject = aSelOID.isValid();
+
+ ObjectType aObjectType(ObjectIdentifier::getObjectType( aSelObjCID ));
+
+ bIsPositionableObject = (aObjectType != OBJECTTYPE_DATA_POINT) && aSelOID.isDragableObject();
+ bIsTextObject = aObjectType == OBJECTTYPE_TITLE;
+
+ rtl::Reference< Diagram > xDiagram = xModel->getFirstChartDiagram();
+ bIsFormateableObjectSelected = bHasSelectedObject && aSelOID.isAutoGeneratedObject();
+ if( aObjectType==OBJECTTYPE_DIAGRAM || aObjectType==OBJECTTYPE_DIAGRAM_WALL || aObjectType==OBJECTTYPE_DIAGRAM_FLOOR )
+ bIsFormateableObjectSelected = xDiagram->isSupportingFloorAndWall();
+
+ rtl::Reference< DataSeries > xGivenDataSeries =
+ ObjectIdentifier::getDataSeriesForCID(
+ aSelObjCID, xModel );
+
+ bIsDeleteableObjectSelected = ChartController::isObjectDeleteable( aSelObj );
+
+ bMayMoveSeriesForward = (aObjectType!=OBJECTTYPE_DATA_POINT) && xDiagram && xDiagram->isSeriesMoveable(
+ xGivenDataSeries,
+ MOVE_SERIES_FORWARD );
+
+ bMayMoveSeriesBackward = (aObjectType!=OBJECTTYPE_DATA_POINT) && xDiagram && xDiagram->isSeriesMoveable(
+ xGivenDataSeries,
+ MOVE_SERIES_BACKWARD );
+
+ bMayAddMenuTrendline = false;
+ bMayAddTrendline = false;
+ bMayAddTrendlineEquation = false;
+ bMayAddR2Value = false;
+ bMayAddMeanValue = false;
+ bMayAddXErrorBars = false;
+ bMayAddYErrorBars = false;
+ bMayDeleteTrendline = false;
+ bMayDeleteTrendlineEquation = false;
+ bMayDeleteR2Value = false;
+ bMayDeleteMeanValue = false;
+ bMayDeleteXErrorBars = false;
+ bMayDeleteYErrorBars = false;
+ bMayFormatTrendline = false;
+ bMayFormatTrendlineEquation = false;
+ bMayFormatMeanValue = false;
+ bMayFormatXErrorBars = false;
+ bMayFormatYErrorBars = false;
+ if( !bHasSelectedObject )
+ return;
+
+ if( xGivenDataSeries.is())
+ {
+ bMayAddMenuTrendline = true;
+ sal_Int32 nDimensionCount = xDiagram->getDimension();
+ rtl::Reference< ::chart::ChartType > xFirstChartType(
+ DataSeriesHelper::getChartTypeOfSeries( xGivenDataSeries, xDiagram ));
+
+ // trend lines/mean value line
+ if( (aObjectType == OBJECTTYPE_DATA_SERIES || aObjectType == OBJECTTYPE_DATA_POINT)
+ && ChartTypeHelper::isSupportingRegressionProperties( xFirstChartType, nDimensionCount ))
+ {
+ // Trendline
+ bMayAddTrendline = true;
+
+ // Mean Value
+ bMayFormatMeanValue = bMayDeleteMeanValue = RegressionCurveHelper::hasMeanValueLine( xGivenDataSeries );
+ bMayAddMeanValue = ! bMayDeleteMeanValue;
+ }
+
+ // error bars
+ if( (aObjectType == OBJECTTYPE_DATA_SERIES || aObjectType == OBJECTTYPE_DATA_POINT)
+ && ChartTypeHelper::isSupportingStatisticProperties( xFirstChartType, nDimensionCount ))
+ {
+ bMayFormatXErrorBars = bMayDeleteXErrorBars = StatisticsHelper::hasErrorBars( xGivenDataSeries, false );
+ bMayAddXErrorBars = ! bMayDeleteXErrorBars;
+
+ bMayFormatYErrorBars = bMayDeleteYErrorBars = StatisticsHelper::hasErrorBars( xGivenDataSeries );
+ bMayAddYErrorBars = ! bMayDeleteYErrorBars;
+ }
+ }
+
+ if( aObjectType == OBJECTTYPE_DATA_AVERAGE_LINE )
+ bMayFormatMeanValue = true;
+
+ if( aObjectType == OBJECTTYPE_DATA_ERRORS_X)
+ bMayFormatXErrorBars = true;
+
+ if( aObjectType == OBJECTTYPE_DATA_ERRORS_Y )
+ bMayFormatYErrorBars = true;
+
+ if( aObjectType == OBJECTTYPE_DATA_CURVE )
+ {
+ bMayFormatTrendline = true;
+ bMayDeleteTrendline = true;
+ uno::Reference< chart2::XRegressionCurve > xRegCurve(
+ ObjectIdentifier::getObjectPropertySet( aSelObjCID, xModel ), uno::UNO_QUERY );
+
+ // Trendline Equation
+ bMayFormatTrendlineEquation = bMayDeleteTrendlineEquation = RegressionCurveHelper::hasEquation( xRegCurve );
+ bMayAddTrendlineEquation = !bMayDeleteTrendlineEquation;
+ bMayAddR2Value = RegressionCurveHelper::MayHaveCorrelationCoefficient( xRegCurve ) && bMayAddTrendlineEquation;
+ }
+ else if( aObjectType == OBJECTTYPE_DATA_CURVE_EQUATION )
+ {
+ bMayFormatTrendlineEquation = true;
+ bool bHasR2Value = false;
+ bool bMayHaveR2 = true;
+ try
+ {
+ uno::Reference< beans::XPropertySet > xEquationProperties =
+ ObjectIdentifier::getObjectPropertySet( aSelObjCID, xModel );
+ if( xEquationProperties.is() )
+ {
+ xEquationProperties->getPropertyValue( "ShowCorrelationCoefficient" ) >>= bHasR2Value;
+ xEquationProperties->getPropertyValue( "MayHaveCorrelationCoefficient" ) >>= bMayHaveR2;
+ }
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+ bMayAddR2Value = !bHasR2Value && bMayHaveR2;
+ bMayDeleteR2Value = bHasR2Value;
+ }
+}
+
+/** Represents the current state of the model.
+
+ You can set the state by calling update(). After this call the state is
+ preserved in this class until the next call to update().
+
+ This is useful, not to say necessary, for enabling and disabling of menu
+ entries and toolbar icons. As the status requests are sent very frequently
+ it would be impossible, from a performance point of view, to query the
+ current status every time directly at the model. So this class serves as a
+ cache for the state.
+ */
+struct ModelState
+{
+ ModelState();
+
+ void update( const rtl::Reference<::chart::ChartModel> & xModel );
+
+ bool HasAnyAxis() const;
+ bool HasAnyGrid() const;
+ bool HasAnyTitle() const;
+
+ bool bIsReadOnly;
+ bool bIsThreeD;
+ bool bHasOwnData;
+ bool bHasDataFromPivotTable;
+
+ bool bHasMainTitle;
+ bool bHasSubTitle;
+ bool bHasXAxisTitle;
+ bool bHasYAxisTitle;
+ bool bHasZAxisTitle;
+ bool bHasSecondaryXAxisTitle;
+ bool bHasSecondaryYAxisTitle;
+
+ bool bHasXAxis;
+ bool bHasYAxis;
+ bool bHasZAxis;
+ bool bHasAAxis;
+ bool bHasBAxis;
+
+ bool bHasMainXGrid;
+ bool bHasMainYGrid;
+ bool bHasMainZGrid;
+ bool bHasHelpXGrid;
+ bool bHasHelpYGrid;
+ bool bHasHelpZGrid;
+
+ bool bHasAutoScaledText;
+ bool bHasLegend;
+ bool bHasWall;
+ bool bHasFloor;
+
+ bool bSupportsStatistics;
+ bool bSupportsAxes;
+
+ bool bDataTable = false;
+};
+
+ModelState::ModelState() :
+ bIsReadOnly(true),
+ bIsThreeD(false),
+ bHasOwnData(false),
+ bHasDataFromPivotTable(false),
+ bHasMainTitle(false),
+ bHasSubTitle(false),
+ bHasXAxisTitle(false),
+ bHasYAxisTitle(false),
+ bHasZAxisTitle(false),
+ bHasSecondaryXAxisTitle(false),
+ bHasSecondaryYAxisTitle(false),
+ bHasXAxis(false),
+ bHasYAxis(false),
+ bHasZAxis(false),
+ bHasAAxis(false),
+ bHasBAxis(false),
+ bHasMainXGrid(false),
+ bHasMainYGrid(false),
+ bHasMainZGrid(false),
+ bHasHelpXGrid(false),
+ bHasHelpYGrid(false),
+ bHasHelpZGrid(false),
+ bHasAutoScaledText(false),
+ bHasLegend(false),
+ bHasWall(false),
+ bHasFloor(false),
+ bSupportsStatistics(false),
+ bSupportsAxes(false)
+{}
+
+void ModelState::update( const rtl::Reference<::chart::ChartModel> & xModel )
+{
+ rtl::Reference< Diagram > xDiagram = xModel->getFirstChartDiagram();
+
+ bIsReadOnly = xModel->isReadonly();
+
+ sal_Int32 nDimensionCount = 0;
+ if (xDiagram)
+ nDimensionCount = xDiagram->getDimension();
+
+ rtl::Reference< ChartType > xFirstChartType;
+ if (xDiagram)
+ xFirstChartType = xDiagram->getChartTypeByIndex( 0 );
+ bSupportsStatistics = ChartTypeHelper::isSupportingStatisticProperties( xFirstChartType, nDimensionCount );
+ bSupportsAxes = ChartTypeHelper::isSupportingMainAxis( xFirstChartType, nDimensionCount, 0 );
+
+ bIsThreeD = (nDimensionCount == 3);
+ if (xModel.is())
+ {
+ bHasOwnData = xModel->hasInternalDataProvider();
+ bHasDataFromPivotTable = !bHasOwnData && xModel->isDataFromPivotTable();
+ }
+
+ bHasMainTitle = TitleHelper::getTitle( TitleHelper::MAIN_TITLE, xModel ).is();
+ bHasSubTitle = TitleHelper::getTitle( TitleHelper::SUB_TITLE, xModel ).is();
+ bHasXAxisTitle = TitleHelper::getTitle( TitleHelper::X_AXIS_TITLE, xModel ).is();
+ bHasYAxisTitle = TitleHelper::getTitle( TitleHelper::Y_AXIS_TITLE, xModel ).is();
+ bHasZAxisTitle = TitleHelper::getTitle( TitleHelper::Z_AXIS_TITLE, xModel ).is();
+ bHasSecondaryXAxisTitle = TitleHelper::getTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, xModel ).is();
+ bHasSecondaryYAxisTitle = TitleHelper::getTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, xModel ).is();
+
+ bHasXAxis = bSupportsAxes && AxisHelper::getAxis( 0, true, xDiagram ).is();
+ bHasYAxis = bSupportsAxes && AxisHelper::getAxis( 1, true, xDiagram ).is();
+ bHasZAxis = bSupportsAxes && AxisHelper::getAxis( 2, true, xDiagram ).is();
+ bHasAAxis = bSupportsAxes && AxisHelper::getAxis( 0, false, xDiagram ).is();
+ bHasBAxis = bSupportsAxes && AxisHelper::getAxis( 1, false, xDiagram ).is();
+
+ bHasMainXGrid = bSupportsAxes && AxisHelper::isGridShown( 0, 0, true, xDiagram );
+ bHasMainYGrid = bSupportsAxes && AxisHelper::isGridShown( 1, 0, true, xDiagram );
+ bHasMainZGrid = bSupportsAxes && AxisHelper::isGridShown( 2, 0, true, xDiagram );
+ bHasHelpXGrid = bSupportsAxes && AxisHelper::isGridShown( 0, 0, false, xDiagram );
+ bHasHelpYGrid = bSupportsAxes && AxisHelper::isGridShown( 1, 0, false, xDiagram );
+ bHasHelpZGrid = bSupportsAxes && AxisHelper::isGridShown( 2, 0, false, xDiagram );
+
+ bHasAutoScaledText =
+ (ReferenceSizeProvider::getAutoResizeState( xModel ) ==
+ ReferenceSizeProvider::AUTO_RESIZE_YES);
+
+ bHasLegend = LegendHelper::hasLegend( xDiagram );
+ bHasWall = xDiagram && xDiagram->isSupportingFloorAndWall();
+ bHasFloor = bHasWall && bIsThreeD;
+
+ bDataTable = xDiagram.is() && xDiagram->getDataTable().is();
+}
+
+bool ModelState::HasAnyAxis() const
+{
+ return bHasXAxis || bHasYAxis || bHasZAxis || bHasAAxis || bHasBAxis;
+}
+
+bool ModelState::HasAnyGrid() const
+{
+ return bHasMainXGrid || bHasMainYGrid || bHasMainZGrid ||
+ bHasHelpXGrid || bHasHelpYGrid || bHasHelpZGrid;
+}
+
+bool ModelState::HasAnyTitle() const
+{
+ return bHasMainTitle || bHasSubTitle || bHasXAxisTitle || bHasYAxisTitle || bHasZAxisTitle || bHasSecondaryXAxisTitle || bHasSecondaryYAxisTitle;
+}
+
+} // namespace impl
+
+ControllerCommandDispatch::ControllerCommandDispatch(
+ const Reference< uno::XComponentContext > & xContext,
+ ChartController* pController, CommandDispatchContainer* pContainer ) :
+ impl::ControllerCommandDispatch_Base( xContext ),
+ m_xChartController( pController ),
+ m_xSelectionSupplier( Reference< view::XSelectionSupplier >( pController ) ),
+ m_xDispatch( Reference< frame::XDispatch >( pController ) ),
+ m_apModelState( new impl::ModelState() ),
+ m_apControllerState( new impl::ControllerState() ),
+ m_pDispatchContainer( pContainer )
+{
+}
+
+ControllerCommandDispatch::~ControllerCommandDispatch()
+{
+}
+
+void ControllerCommandDispatch::initialize()
+{
+ if( !m_xChartController.is())
+ return;
+
+ rtl::Reference<::chart::ChartModel> xModel( m_xChartController->getChartModel());
+ OSL_ASSERT( xModel.is());
+ if( xModel.is())
+ xModel->addModifyListener( this );
+
+ // Listen selection modifications (Arrangement feature - issue 63017).
+ if( m_xSelectionSupplier.is() )
+ m_xSelectionSupplier->addSelectionChangeListener( this );
+
+ if( m_apModelState && xModel.is())
+ m_apModelState->update( xModel );
+
+ if( m_apControllerState && xModel.is())
+ m_apControllerState->update( m_xChartController, xModel );
+
+ updateCommandAvailability();
+}
+
+void ControllerCommandDispatch::fireStatusEventForURLImpl(
+ const OUString & rURL,
+ const Reference< frame::XStatusListener > & xSingleListener )
+{
+ std::map< OUString, uno::Any >::const_iterator aArgIt( m_aCommandArguments.find( rURL ));
+ if( aArgIt != m_aCommandArguments.end())
+ fireStatusEventForURL( rURL, aArgIt->second, commandAvailable( rURL ), xSingleListener );
+ else
+ fireStatusEventForURL( rURL, uno::Any(), commandAvailable( rURL ), xSingleListener );
+}
+
+void ControllerCommandDispatch::updateCommandAvailability()
+{
+ bool bModelStateIsValid = (m_apModelState != nullptr);
+ bool bControllerStateIsValid = (m_apControllerState != nullptr);
+ // Model and controller states exist.
+ OSL_ASSERT( bModelStateIsValid );
+ OSL_ASSERT( bControllerStateIsValid );
+
+ // read-only
+ bool bIsWritable = bModelStateIsValid && (! m_apModelState->bIsReadOnly);
+ bool bShapeContext = m_xChartController.is() && m_xChartController->isShapeContext();
+
+ bool bEnableDataTableDialog = false;
+ bool bCanCreateDataProvider = false;
+
+ if ( m_xChartController.is() )
+ {
+ Reference< beans::XPropertySet > xProps( m_xChartController->getModel(), uno::UNO_QUERY );
+ if ( xProps.is() )
+ {
+ try
+ {
+ xProps->getPropertyValue("EnableDataTableDialog") >>= bEnableDataTableDialog;
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+ }
+
+ rtl::Reference< ChartModel > xChartModel = m_xChartController->getChartModel();
+ OSL_ENSURE(xChartModel.is(), "Invalid XChartDocument");
+ if ( xChartModel.is() )
+ {
+ css::uno::Reference< com::sun::star::chart2::XDataProviderAccess > xCreatorDoc(xChartModel->getParent(), uno::UNO_QUERY);
+ bCanCreateDataProvider = xCreatorDoc.is();
+ }
+ }
+
+ // edit commands
+ m_aCommandAvailability[ ".uno:Cut" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bIsDeleteableObjectSelected;
+ m_aCommandAvailability[ ".uno:Copy" ] = bControllerStateIsValid && m_apControllerState->bHasSelectedObject;
+ m_aCommandAvailability[ ".uno:Paste" ] = bIsWritable;
+
+ // toolbar commands
+ m_aCommandAvailability[ ".uno:ToggleGridHorizontal" ] = bIsWritable;
+ m_aCommandArguments[ ".uno:ToggleGridHorizontal" ] <<= bModelStateIsValid && m_apModelState->bHasMainYGrid;
+ m_aCommandAvailability[ ".uno:ToggleGridVertical" ] = bIsWritable;
+ m_aCommandArguments[ ".uno:ToggleGridVertical" ] <<= bModelStateIsValid && m_apModelState->bHasMainXGrid;
+
+ m_aCommandAvailability[ ".uno:ToggleLegend" ] = bIsWritable;
+ m_aCommandArguments[ ".uno:ToggleLegend" ] <<= bModelStateIsValid && m_apModelState->bHasLegend;
+
+ m_aCommandAvailability[ ".uno:NewArrangement" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:Update" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:DefaultColors" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:BarWidth" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:NumberOfLines" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:ArrangeRow" ] =
+ bShapeContext || ( bIsWritable && bControllerStateIsValid && ( m_apControllerState->bMayMoveSeriesForward || m_apControllerState->bMayMoveSeriesBackward ) );
+
+ // insert objects
+ m_aCommandAvailability[ ".uno:InsertTitles" ] = m_aCommandAvailability[ ".uno:InsertMenuTitles" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:InsertLegend" ] = m_aCommandAvailability[ ".uno:InsertMenuLegend" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:DeleteLegend" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:InsertMenuDataLabels" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:InsertRemoveAxes" ] = m_aCommandAvailability[ ".uno:InsertMenuAxes" ] = bIsWritable && m_apModelState->bSupportsAxes;
+ m_aCommandAvailability[ ".uno:InsertMenuGrids" ] = bIsWritable && m_apModelState->bSupportsAxes;
+ m_aCommandAvailability[ ".uno:InsertMenuTrendlines" ] = bIsWritable && m_apModelState->bSupportsStatistics && bControllerStateIsValid && m_apControllerState->bMayAddMenuTrendline;
+ m_aCommandAvailability[ ".uno:InsertMenuMeanValues" ] = bIsWritable && m_apModelState->bSupportsStatistics;
+ m_aCommandAvailability[ ".uno:InsertMenuXErrorBars" ] = bIsWritable && m_apModelState->bSupportsStatistics;
+ m_aCommandAvailability[ ".uno:InsertMenuYErrorBars" ] = bIsWritable && m_apModelState->bSupportsStatistics;
+ m_aCommandAvailability[ ".uno:InsertSymbol" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bIsTextObject;
+ m_aCommandAvailability[ ".uno:InsertMenuDataTable" ] = bIsWritable;
+
+ // format objects
+ bool bFormatObjectAvailable = bIsWritable && bControllerStateIsValid && m_apControllerState->bIsFormateableObjectSelected;
+ m_aCommandAvailability[ ".uno:FormatSelection" ] = bFormatObjectAvailable;
+ m_aCommandAvailability[ ".uno:FormatAxis" ] = bFormatObjectAvailable;
+ m_aCommandAvailability[ ".uno:FormatTitle" ] = bFormatObjectAvailable;
+ m_aCommandAvailability[ ".uno:FormatDataSeries" ] = bFormatObjectAvailable;
+ m_aCommandAvailability[ ".uno:FormatDataPoint" ] = bFormatObjectAvailable;
+ m_aCommandAvailability[ ".uno:FormatDataLabels" ] = bFormatObjectAvailable;
+ m_aCommandAvailability[ ".uno:FormatDataLabel" ] = bFormatObjectAvailable;
+ m_aCommandAvailability[ ".uno:FormatXErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayFormatXErrorBars;
+ m_aCommandAvailability[ ".uno:FormatYErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayFormatYErrorBars;
+ m_aCommandAvailability[ ".uno:FormatMeanValue" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayFormatMeanValue;
+ m_aCommandAvailability[ ".uno:FormatTrendline" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayFormatTrendline;
+ m_aCommandAvailability[ ".uno:FormatTrendlineEquation" ] = bFormatObjectAvailable && bControllerStateIsValid && m_apControllerState->bMayFormatTrendlineEquation;
+ m_aCommandAvailability[ ".uno:FormatStockLoss" ] = bFormatObjectAvailable;
+ m_aCommandAvailability[ ".uno:FormatStockGain" ] = bFormatObjectAvailable;
+
+ m_aCommandAvailability[ ".uno:DiagramType" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:Legend" ] = bIsWritable && m_apModelState->bHasLegend;
+ m_aCommandAvailability[ ".uno:DiagramWall" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasWall;
+ m_aCommandAvailability[ ".uno:DiagramArea" ] = bIsWritable;
+
+ m_aCommandAvailability[ ".uno:TransformDialog" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bHasSelectedObject && m_apControllerState->bIsPositionableObject;
+
+ // 3d commands
+ m_aCommandAvailability[ ".uno:View3D" ] = bIsWritable && bModelStateIsValid && m_apModelState->bIsThreeD;
+ m_aCommandAvailability[ ".uno:DiagramFloor" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasFloor;
+
+ //some more format commands with different ui text
+ m_aCommandAvailability[ ".uno:FormatWall" ] = m_aCommandAvailability[ ".uno:DiagramWall" ];
+ m_aCommandAvailability[ ".uno:FormatFloor" ] = m_aCommandAvailability[ ".uno:DiagramFloor" ];
+ m_aCommandAvailability[ ".uno:FormatChartArea" ] = m_aCommandAvailability[ ".uno:DiagramArea" ];
+ m_aCommandAvailability[ ".uno:FormatLegend" ] = m_aCommandAvailability[ ".uno:Legend" ];
+
+ // depending on own data and ability to create new data provider
+ m_aCommandAvailability[".uno:DataRanges"] = bIsWritable && bModelStateIsValid && !m_apModelState->bHasDataFromPivotTable
+ && ((m_apModelState->bHasOwnData && bCanCreateDataProvider) || !m_apModelState->bHasOwnData);
+ m_aCommandAvailability[ ".uno:DiagramData" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasOwnData && bEnableDataTableDialog;
+
+ // titles
+ m_aCommandAvailability[ ".uno:MainTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasMainTitle;
+ m_aCommandAvailability[ ".uno:SubTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasSubTitle;
+ m_aCommandAvailability[ ".uno:XTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasXAxisTitle;
+ m_aCommandAvailability[ ".uno:YTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasYAxisTitle;
+ m_aCommandAvailability[ ".uno:ZTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasZAxisTitle;
+ m_aCommandAvailability[ ".uno:SecondaryXTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasSecondaryXAxisTitle;
+ m_aCommandAvailability[ ".uno:SecondaryYTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasSecondaryYAxisTitle;
+ m_aCommandAvailability[ ".uno:AllTitles" ] = bIsWritable && bModelStateIsValid && m_apModelState->HasAnyTitle();
+
+ // text
+ m_aCommandAvailability[ ".uno:ScaleText" ] = bIsWritable && bModelStateIsValid ;
+ m_aCommandArguments[ ".uno:ScaleText" ] <<= bModelStateIsValid && m_apModelState->bHasAutoScaledText;
+
+ // axes
+ m_aCommandAvailability[ ".uno:DiagramAxisX" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasXAxis;
+ m_aCommandAvailability[ ".uno:DiagramAxisY" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasYAxis;
+ m_aCommandAvailability[ ".uno:DiagramAxisZ" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasZAxis;
+ m_aCommandAvailability[ ".uno:DiagramAxisA" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasAAxis;
+ m_aCommandAvailability[ ".uno:DiagramAxisB" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasBAxis;
+ m_aCommandAvailability[ ".uno:DiagramAxisAll" ] = bIsWritable && bModelStateIsValid && m_apModelState->HasAnyAxis();
+
+ // grids
+ // note: x and y are swapped in the commands!
+ m_aCommandAvailability[ ".uno:DiagramGridYMain" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasMainXGrid;
+ m_aCommandAvailability[ ".uno:DiagramGridXMain" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasMainYGrid;
+ m_aCommandAvailability[ ".uno:DiagramGridZMain" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasMainZGrid;
+ m_aCommandAvailability[ ".uno:DiagramGridYHelp" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasHelpXGrid;
+ m_aCommandAvailability[ ".uno:DiagramGridXHelp" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasHelpYGrid;
+ m_aCommandAvailability[ ".uno:DiagramGridZHelp" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasHelpZGrid;
+ m_aCommandAvailability[ ".uno:DiagramGridAll" ] = bIsWritable && bModelStateIsValid && m_apModelState->HasAnyGrid();
+
+ // series arrangement
+ m_aCommandAvailability[ ".uno:Forward" ] = ( bShapeContext ? isShapeControllerCommandAvailable( ".uno:Forward" ) :
+ ( bIsWritable && bControllerStateIsValid && m_apControllerState->bMayMoveSeriesForward && bEnableDataTableDialog ) );
+ m_aCommandAvailability[ ".uno:Backward" ] = ( bShapeContext ? isShapeControllerCommandAvailable( ".uno:Backward" ) :
+ ( bIsWritable && bControllerStateIsValid && m_apControllerState->bMayMoveSeriesBackward && bEnableDataTableDialog ) );
+
+ m_aCommandAvailability[ ".uno:InsertDataLabels" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:InsertDataLabel" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:InsertMeanValue" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddMeanValue;
+ m_aCommandAvailability[ ".uno:InsertTrendline" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddTrendline;
+ const bool bInsertTrendlineEquation = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddTrendlineEquation;
+ m_aCommandAvailability[ ".uno:InsertTrendlineEquation" ] = bInsertTrendlineEquation;
+ m_aCommandAvailability[ ".uno:InsertTrendlineEquationAndR2" ] = bInsertTrendlineEquation && m_apControllerState->bMayAddR2Value;
+ m_aCommandAvailability[ ".uno:InsertR2Value" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddR2Value
+ && !m_apControllerState->bMayAddTrendlineEquation;
+ m_aCommandAvailability[ ".uno:DeleteR2Value" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteR2Value;
+
+ m_aCommandAvailability[ ".uno:InsertXErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddXErrorBars;
+ m_aCommandAvailability[ ".uno:InsertYErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddYErrorBars;
+
+ m_aCommandAvailability[ ".uno:DeleteDataLabels" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:DeleteDataLabel" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:DeleteTrendline" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteTrendline;
+ m_aCommandAvailability[ ".uno:DeleteTrendlineEquation" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteTrendlineEquation;
+ m_aCommandAvailability[ ".uno:DeleteMeanValue" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteMeanValue;
+ m_aCommandAvailability[ ".uno:DeleteXErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteXErrorBars;
+ m_aCommandAvailability[ ".uno:DeleteYErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteYErrorBars;
+
+ m_aCommandAvailability[ ".uno:ResetDataPoint" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:ResetAllDataPoints" ] = bIsWritable;
+
+ m_aCommandAvailability[ ".uno:InsertAxis" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:DeleteAxis" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:InsertAxisTitle" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:FormatMajorGrid" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:InsertMajorGrid" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:DeleteMajorGrid" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:FormatMinorGrid" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:InsertMinorGrid" ] = bIsWritable;
+ m_aCommandAvailability[ ".uno:DeleteMinorGrid" ] = bIsWritable;
+
+ // data table
+ m_aCommandAvailability[ ".uno:InsertDataTable" ] = bIsWritable && bModelStateIsValid && !m_apModelState->bDataTable;
+ m_aCommandAvailability[ ".uno:DeleteDataTable" ] = bIsWritable && bModelStateIsValid && m_apModelState->bDataTable;
+}
+
+bool ControllerCommandDispatch::commandAvailable( const OUString & rCommand )
+{
+ std::map< OUString, bool >::const_iterator aIt( m_aCommandAvailability.find( rCommand ));
+ if( aIt != m_aCommandAvailability.end())
+ return aIt->second;
+ SAL_WARN("chart2", "commandAvailable: command not in availability map:" << rCommand);
+ return false;
+}
+
+bool ControllerCommandDispatch::isShapeControllerCommandAvailable( const OUString& rCommand )
+{
+ ShapeController* pShapeController(nullptr);
+ {
+ SolarMutexGuard g;
+ if (m_pDispatchContainer)
+ pShapeController = m_pDispatchContainer->getShapeController();
+ }
+ if ( pShapeController )
+ {
+ FeatureState aState( pShapeController->getState( rCommand ) );
+ return aState.bEnabled;
+ }
+ return false;
+}
+
+void ControllerCommandDispatch::fireStatusEvent(
+ const OUString & rURL,
+ const Reference< frame::XStatusListener > & xSingleListener /* = 0 */ )
+{
+ bool bIsChartSelectorURL = rURL == ".uno:ChartElementSelector";
+ if( rURL.isEmpty() || bIsChartSelectorURL )
+ {
+ uno::Any aArg;
+ aArg <<= Reference< frame::XController >(m_xChartController);
+ fireStatusEventForURL( ".uno:ChartElementSelector", aArg, true, xSingleListener );
+ }
+
+ if( rURL.isEmpty() )
+ {
+ for (auto const& elem : m_aCommandAvailability)
+ fireStatusEventForURLImpl( elem.first, xSingleListener );
+ }
+ else if( !bIsChartSelectorURL )
+ fireStatusEventForURLImpl( rURL, xSingleListener );
+
+ // statusbar. Should be handled by base implementation
+ // @todo: remove if Issue 68864 is fixed
+ if( rURL.isEmpty() || rURL == ".uno:StatusBarVisible" )
+ {
+ bool bIsStatusBarVisible( lcl_isStatusBarVisible( m_xChartController ));
+ fireStatusEventForURL( ".uno:StatusBarVisible", uno::Any( bIsStatusBarVisible ), true, xSingleListener );
+ }
+}
+
+// ____ XDispatch ____
+void SAL_CALL ControllerCommandDispatch::dispatch(
+ const util::URL& URL,
+ const Sequence< beans::PropertyValue >& Arguments )
+{
+ if( commandAvailable( URL.Complete ))
+ m_xDispatch->dispatch( URL, Arguments );
+}
+
+// ____ WeakComponentImplHelperBase ____
+/// is called when this is disposed
+void ControllerCommandDispatch::disposing(std::unique_lock<std::mutex>& /*rGuard*/)
+{
+ m_xChartController.clear();
+ m_xDispatch.clear();
+ m_xSelectionSupplier.clear();
+}
+
+// ____ XEventListener (base of XModifyListener) ____
+void SAL_CALL ControllerCommandDispatch::disposing( const lang::EventObject& /* Source */ )
+{
+ m_xChartController.clear();
+ m_xDispatch.clear();
+ m_xSelectionSupplier.clear();
+}
+
+// ____ XModifyListener ____
+void SAL_CALL ControllerCommandDispatch::modified( const lang::EventObject& aEvent )
+{
+ bool bUpdateCommandAvailability = false;
+
+ // Update the "ModelState" Struct.
+ if( m_apModelState && m_xChartController.is())
+ {
+ m_apModelState->update( m_xChartController->getChartModel());
+ bUpdateCommandAvailability = true;
+ }
+
+ // Update the "ControllerState" Struct.
+ if( m_apControllerState && m_xChartController.is())
+ {
+ m_apControllerState->update( m_xChartController, m_xChartController->getChartModel());
+ bUpdateCommandAvailability = true;
+ }
+
+ if( bUpdateCommandAvailability )
+ updateCommandAvailability();
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (SfxViewShell* pViewShell = SfxViewShell::Current())
+ if (SfxObjectShell* pObjSh = pViewShell->GetObjectShell())
+ pObjSh->SetModified();
+ }
+
+ CommandDispatch::modified( aEvent );
+}
+
+// ____ XSelectionChangeListener ____
+void SAL_CALL ControllerCommandDispatch::selectionChanged( const lang::EventObject& aEvent )
+{
+ // Update the "ControllerState" Struct.
+ if( m_apControllerState && m_xChartController.is())
+ {
+ m_apControllerState->update( m_xChartController, m_xChartController->getChartModel());
+ updateCommandAvailability();
+ }
+
+ CommandDispatch::modified( aEvent );
+}
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ControllerCommandDispatch.hxx b/chart2/source/controller/main/ControllerCommandDispatch.hxx
new file mode 100644
index 0000000000..6a5e441e8e
--- /dev/null
+++ b/chart2/source/controller/main/ControllerCommandDispatch.hxx
@@ -0,0 +1,119 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include "CommandDispatch.hxx"
+#include <com/sun/star/view/XSelectionChangeListener.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+
+#include <memory>
+
+namespace com::sun::star::view { class XSelectionSupplier; }
+
+namespace chart
+{
+
+class ChartController;
+class CommandDispatchContainer;
+
+namespace impl
+{
+struct ModelState;
+struct ControllerState;
+
+// #i63017# : need to implement the XSelectionChangeListener in order
+// to update the ControllerState when the selection changes.
+typedef ::cppu::ImplInheritanceHelper<
+ CommandDispatch,
+ css::view::XSelectionChangeListener >
+ ControllerCommandDispatch_Base;
+}
+
+/** This class is a CommandDispatch that is responsible for all commands that
+ the ChartController supports.
+
+ This class determines which commands are currently available (via the model
+ state) and if an available command is called forwards it to the
+ ChartController.
+ */
+class ControllerCommandDispatch : public impl::ControllerCommandDispatch_Base
+{
+public:
+ explicit ControllerCommandDispatch(
+ const css::uno::Reference< css::uno::XComponentContext > & xContext,
+ ChartController* pController, CommandDispatchContainer* pContainer );
+ virtual ~ControllerCommandDispatch() override;
+
+ // late initialisation, especially for adding as listener
+ virtual void initialize() override;
+
+ bool commandAvailable( const OUString & rCommand );
+
+protected:
+ // ____ XDispatch ____
+ virtual void SAL_CALL dispatch(
+ const css::util::URL& URL,
+ const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+
+ // ____ WeakComponentImplHelperBase ____
+ /// is called when this is disposed
+ virtual void disposing(std::unique_lock<std::mutex>& rGuard) override;
+
+ // ____ XEventListener (base of XModifyListener) ____
+ virtual void SAL_CALL disposing(
+ const css::lang::EventObject& Source ) override;
+
+ virtual void fireStatusEvent(
+ const OUString & rURL,
+ const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ) override;
+
+ // ____ XModifyListener ____
+ virtual void SAL_CALL modified(
+ const css::lang::EventObject& aEvent ) override;
+
+ // ____ XSelectionChangeListener ____
+ virtual void SAL_CALL selectionChanged(
+ const css::lang::EventObject& aEvent ) override;
+
+private:
+ void fireStatusEventForURLImpl(
+ const OUString & rURL,
+ const css::uno::Reference< css::frame::XStatusListener > & xSingleListener );
+
+ void updateCommandAvailability();
+
+ bool isShapeControllerCommandAvailable( const OUString& rCommand );
+
+ rtl::Reference<ChartController> m_xChartController;
+ css::uno::Reference< css::view::XSelectionSupplier > m_xSelectionSupplier;
+ css::uno::Reference< css::frame::XDispatch > m_xDispatch;
+
+ std::unique_ptr< impl::ModelState > m_apModelState;
+ std::unique_ptr< impl::ControllerState > m_apControllerState;
+
+ mutable std::map< OUString, bool > m_aCommandAvailability;
+ mutable std::map< OUString, css::uno::Any > m_aCommandArguments;
+
+ CommandDispatchContainer* m_pDispatchContainer;
+};
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/DragMethod_Base.cxx b/chart2/source/controller/main/DragMethod_Base.cxx
new file mode 100644
index 0000000000..5e46dc327b
--- /dev/null
+++ b/chart2/source/controller/main/DragMethod_Base.cxx
@@ -0,0 +1,75 @@
+/* -*- 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 "DragMethod_Base.hxx"
+#include <DrawViewWrapper.hxx>
+#include <ChartModel.hxx>
+#include <ObjectNameProvider.hxx>
+#include <ObjectIdentifier.hxx>
+
+#include <svx/ActionDescriptionProvider.hxx>
+#include <utility>
+#include <vcl/ptrstyle.hxx>
+
+namespace chart
+{
+
+using namespace ::com::sun::star;
+
+DragMethod_Base::DragMethod_Base( DrawViewWrapper& rDrawViewWrapper
+ , OUString aObjectCID
+ , const rtl::Reference<::chart::ChartModel>& xChartModel
+ , ActionDescriptionProvider::ActionType eActionType )
+ : SdrDragMethod( rDrawViewWrapper )
+ , m_rDrawViewWrapper(rDrawViewWrapper)
+ , m_aObjectCID(std::move(aObjectCID))
+ , m_eActionType( eActionType )
+ , m_xChartModel( xChartModel.get() )
+{
+ setMoveOnly(true);
+}
+DragMethod_Base::~DragMethod_Base()
+{
+}
+
+rtl::Reference<::chart::ChartModel> DragMethod_Base::getChartModel() const
+{
+ return m_xChartModel.get();
+}
+
+OUString DragMethod_Base::getUndoDescription() const
+{
+ return ActionDescriptionProvider::createDescription(
+ m_eActionType,
+ ObjectNameProvider::getName( ObjectIdentifier::getObjectType( m_aObjectCID )));
+}
+OUString DragMethod_Base::GetSdrDragComment() const
+{
+ return getUndoDescription();
+}
+PointerStyle DragMethod_Base::GetSdrDragPointer() const
+{
+ if( IsDraggingPoints() || IsDraggingGluePoints() )
+ return PointerStyle::MovePoint;
+ else
+ return PointerStyle::Move;
+}
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/DragMethod_Base.hxx b/chart2/source/controller/main/DragMethod_Base.hxx
new file mode 100644
index 0000000000..1a65938890
--- /dev/null
+++ b/chart2/source/controller/main/DragMethod_Base.hxx
@@ -0,0 +1,59 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <svx/ActionDescriptionProvider.hxx>
+#include <svx/svddrgmt.hxx>
+#include <unotools/weakref.hxx>
+
+namespace chart { class DrawViewWrapper; }
+namespace com::sun::star::frame { class XModel; }
+
+namespace chart
+{
+class ChartModel;
+
+class DragMethod_Base : public SdrDragMethod
+{
+public:
+ DragMethod_Base( DrawViewWrapper& rDrawViewWrapper, OUString aObjectCID
+ , const rtl::Reference<::chart::ChartModel>& xChartModel
+ , ActionDescriptionProvider::ActionType eActionType = ActionDescriptionProvider::ActionType::Move );
+ virtual ~DragMethod_Base() override;
+
+ OUString getUndoDescription() const;
+
+ virtual OUString GetSdrDragComment() const override;
+ virtual PointerStyle GetSdrDragPointer() const override;
+
+protected:
+ rtl::Reference<::chart::ChartModel> getChartModel() const;
+
+protected:
+ DrawViewWrapper& m_rDrawViewWrapper;
+ OUString m_aObjectCID;
+ ActionDescriptionProvider::ActionType m_eActionType;
+
+private:
+ unotools::WeakReference<::chart::ChartModel> m_xChartModel;
+};
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/DragMethod_PieSegment.cxx b/chart2/source/controller/main/DragMethod_PieSegment.cxx
new file mode 100644
index 0000000000..5bd85faaf9
--- /dev/null
+++ b/chart2/source/controller/main/DragMethod_PieSegment.cxx
@@ -0,0 +1,151 @@
+/* -*- 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 "DragMethod_PieSegment.hxx"
+#include <DrawViewWrapper.hxx>
+#include <ChartModel.hxx>
+#include <strings.hrc>
+#include <ResId.hxx>
+#include <ObjectIdentifier.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/Point.hpp>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+namespace chart
+{
+
+using namespace ::com::sun::star;
+using ::com::sun::star::uno::Reference;
+using ::basegfx::B2DVector;
+
+DragMethod_PieSegment::DragMethod_PieSegment( DrawViewWrapper& rDrawViewWrapper
+ , const OUString& rObjectCID
+ , const rtl::Reference<::chart::ChartModel>& xChartModel )
+ : DragMethod_Base( rDrawViewWrapper, rObjectCID, xChartModel )
+ , m_aStartVector(100.0,100.0)
+ , m_fInitialOffset(0.0)
+ , m_fAdditionalOffset(0.0)
+ , m_aDragDirection(1000.0,1000.0)
+ , m_fDragRange( 1.0 )
+{
+ std::u16string_view aParameter( ObjectIdentifier::getDragParameterString( m_aObjectCID ) );
+
+ sal_Int32 nOffsetPercent(0);
+ awt::Point aMinimumPosition(0,0);
+ awt::Point aMaximumPosition(0,0);
+
+ ObjectIdentifier::parsePieSegmentDragParameterString(
+ aParameter, nOffsetPercent, aMinimumPosition, aMaximumPosition );
+
+ m_fInitialOffset = nOffsetPercent / 100.0;
+ if( m_fInitialOffset < 0.0 )
+ m_fInitialOffset = 0.0;
+ if( m_fInitialOffset > 1.0 )
+ m_fInitialOffset = 1.0;
+ B2DVector aMinVector( aMinimumPosition.X, aMinimumPosition.Y );
+ B2DVector aMaxVector( aMaximumPosition.X, aMaximumPosition.Y );
+ m_aDragDirection = aMaxVector - aMinVector;
+ m_fDragRange = m_aDragDirection.scalar( m_aDragDirection );
+ if( m_fDragRange == 0.0 )
+ m_fDragRange = 1.0;
+}
+DragMethod_PieSegment::~DragMethod_PieSegment()
+{
+}
+OUString DragMethod_PieSegment::GetSdrDragComment() const
+{
+ OUString aStr = SchResId(STR_STATUS_PIE_SEGMENT_EXPLODED);
+ aStr = aStr.replaceFirst( "%PERCENTVALUE", OUString::number( static_cast<sal_Int32>((m_fAdditionalOffset+m_fInitialOffset)*100.0) ));
+ return aStr;
+}
+bool DragMethod_PieSegment::BeginSdrDrag()
+{
+ Point aStart( DragStat().GetStart() );
+ m_aStartVector = B2DVector( aStart.X(), aStart.Y() );
+ Show();
+ return true;
+}
+void DragMethod_PieSegment::MoveSdrDrag(const Point& rPnt)
+{
+ if( !DragStat().CheckMinMoved(rPnt) )
+ return;
+
+ //calculate new offset
+ B2DVector aShiftVector( B2DVector( rPnt.X(), rPnt.Y() ) - m_aStartVector );
+ m_fAdditionalOffset = m_aDragDirection.scalar( aShiftVector )/m_fDragRange; // projection
+
+ if( m_fAdditionalOffset < -m_fInitialOffset )
+ m_fAdditionalOffset = -m_fInitialOffset;
+ else if( m_fAdditionalOffset > (1.0-m_fInitialOffset) )
+ m_fAdditionalOffset = 1.0 - m_fInitialOffset;
+
+ B2DVector aNewPosVector = m_aStartVector + (m_aDragDirection * m_fAdditionalOffset);
+ Point aNewPos( static_cast<tools::Long>(aNewPosVector.getX()), static_cast<tools::Long>(aNewPosVector.getY()) );
+ if( aNewPos != DragStat().GetNow() )
+ {
+ Hide();
+ DragStat().NextMove( aNewPos );
+ Show();
+ }
+}
+bool DragMethod_PieSegment::EndSdrDrag(bool /*bCopy*/)
+{
+ Hide();
+
+ try
+ {
+ rtl::Reference<::chart::ChartModel> xChartModel( getChartModel() );
+ if( xChartModel.is() )
+ {
+ Reference< beans::XPropertySet > xPointProperties(
+ ObjectIdentifier::getObjectPropertySet( m_aObjectCID, xChartModel ) );
+ if( xPointProperties.is() )
+ xPointProperties->setPropertyValue( "Offset", uno::Any( m_fAdditionalOffset+m_fInitialOffset ));
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+
+ return true;
+}
+basegfx::B2DHomMatrix DragMethod_PieSegment::getCurrentTransformation() const
+{
+ basegfx::B2DHomMatrix aRetval;
+
+ aRetval.translate(DragStat().GetDX(), DragStat().GetDY());
+
+ return aRetval;
+}
+void DragMethod_PieSegment::createSdrDragEntries()
+{
+ SdrObject* pObj = m_rDrawViewWrapper.getSelectedObject();
+ SdrPageView* pPV = m_rDrawViewWrapper.GetPageView();
+
+ if( pObj && pPV )
+ {
+ basegfx::B2DPolyPolygon aNewPolyPolygon(pObj->TakeXorPoly());
+ addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(std::move(aNewPolyPolygon))));
+ }
+}
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/DragMethod_PieSegment.hxx b/chart2/source/controller/main/DragMethod_PieSegment.hxx
new file mode 100644
index 0000000000..8cb498373f
--- /dev/null
+++ b/chart2/source/controller/main/DragMethod_PieSegment.hxx
@@ -0,0 +1,54 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include "DragMethod_Base.hxx"
+#include <basegfx/vector/b2dvector.hxx>
+
+namespace chart
+{
+
+class DragMethod_PieSegment : public DragMethod_Base
+{
+public:
+ DragMethod_PieSegment( DrawViewWrapper& rDrawViewWrapper, const OUString& rObjectCID
+ , const rtl::Reference<::chart::ChartModel>& xChartModel );
+ virtual ~DragMethod_PieSegment() override;
+
+ virtual OUString GetSdrDragComment() const override;
+ virtual bool BeginSdrDrag() override;
+ virtual void MoveSdrDrag(const Point& rPnt) override;
+ virtual bool EndSdrDrag(bool bCopy) override;
+
+ virtual basegfx::B2DHomMatrix getCurrentTransformation() const override;
+
+protected:
+ virtual void createSdrDragEntries() override;
+
+private:
+ ::basegfx::B2DVector m_aStartVector;
+ double m_fInitialOffset;
+ double m_fAdditionalOffset;
+ ::basegfx::B2DVector m_aDragDirection;
+ double m_fDragRange;
+};
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/DragMethod_RotateDiagram.cxx b/chart2/source/controller/main/DragMethod_RotateDiagram.cxx
new file mode 100644
index 0000000000..0ae2f2803c
--- /dev/null
+++ b/chart2/source/controller/main/DragMethod_RotateDiagram.cxx
@@ -0,0 +1,230 @@
+/* -*- 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 "DragMethod_RotateDiagram.hxx"
+#include <DrawViewWrapper.hxx>
+
+#include <SelectionHelper.hxx>
+#include <ChartModelHelper.hxx>
+#include <ChartModel.hxx>
+#include <DiagramHelper.hxx>
+#include <Diagram.hxx>
+#include <ChartType.hxx>
+#include <ChartTypeHelper.hxx>
+#include <ThreeDHelper.hxx>
+#include <defines.hxx>
+#include <svx/sdr/overlay/overlaypolypolygon.hxx>
+
+#include <svx/scene3d.hxx>
+#include <basegfx/matrix/b3dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <drawinglayer/geometry/viewinformation3d.hxx>
+
+namespace chart
+{
+
+using namespace ::com::sun::star;
+
+DragMethod_RotateDiagram::DragMethod_RotateDiagram( DrawViewWrapper& rDrawViewWrapper
+ , const OUString& rObjectCID
+ , const rtl::Reference<::chart::ChartModel>& xChartModel
+ , RotationDirection eRotationDirection )
+ : DragMethod_Base( rDrawViewWrapper, rObjectCID, xChartModel, ActionDescriptionProvider::ActionType::Rotate )
+ , m_pScene(nullptr)
+ , m_aReferenceRect(100,100,100,100)
+ , m_aStartPos(0,0)
+ , m_fInitialXAngleRad(0.0)
+ , m_fInitialYAngleRad(0.0)
+ , m_fInitialZAngleRad(0.0)
+ , m_fAdditionalXAngleRad(0.0)
+ , m_fAdditionalYAngleRad(0.0)
+ , m_fAdditionalZAngleRad(0.0)
+ , m_nInitialHorizontalAngleDegree(0)
+ , m_nInitialVerticalAngleDegree(0)
+ , m_nAdditionalHorizontalAngleDegree(0)
+ , m_nAdditionalVerticalAngleDegree(0)
+ , m_eRotationDirection(eRotationDirection)
+ , m_bRightAngledAxes(false)
+{
+ m_pScene = SelectionHelper::getSceneToRotate( rDrawViewWrapper.getNamedSdrObject( rObjectCID ) );
+ SdrObject* pObj = rDrawViewWrapper.getSelectedObject();
+ if(!(pObj && m_pScene))
+ return;
+
+ m_aReferenceRect = pObj->GetLogicRect();
+
+ m_aWireframePolyPolygon = m_pScene->CreateWireframe();
+
+ rtl::Reference< Diagram > xDiagram = getChartModel()->getFirstChartDiagram();
+ if( !xDiagram.is() )
+ return;
+
+ xDiagram->getRotation(
+ m_nInitialHorizontalAngleDegree, m_nInitialVerticalAngleDegree );
+
+ xDiagram->getRotationAngle(
+ m_fInitialXAngleRad, m_fInitialYAngleRad, m_fInitialZAngleRad );
+
+ if( ChartTypeHelper::isSupportingRightAngledAxes(
+ xDiagram->getChartTypeByIndex( 0 ) ) )
+ xDiagram->getPropertyValue("RightAngledAxes") >>= m_bRightAngledAxes;
+ if(m_bRightAngledAxes)
+ {
+ if( m_eRotationDirection==ROTATIONDIRECTION_Z )
+ m_eRotationDirection=ROTATIONDIRECTION_FREE;
+ ThreeDHelper::adaptRadAnglesForRightAngledAxes( m_fInitialXAngleRad, m_fInitialYAngleRad );
+ }
+}
+DragMethod_RotateDiagram::~DragMethod_RotateDiagram()
+{
+}
+OUString DragMethod_RotateDiagram::GetSdrDragComment() const
+{
+ return OUString();
+}
+bool DragMethod_RotateDiagram::BeginSdrDrag()
+{
+ m_aStartPos = DragStat().GetStart();
+ Show();
+ return true;
+}
+void DragMethod_RotateDiagram::MoveSdrDrag(const Point& rPnt)
+{
+ if( !DragStat().CheckMinMoved(rPnt) )
+ return;
+
+ Hide();
+
+ //calculate new angle
+ double fX = M_PI_2 * static_cast<double>(rPnt.Y() - m_aStartPos.Y())
+ / (m_aReferenceRect.GetHeight() > 0 ? static_cast<double>(m_aReferenceRect.GetHeight()) : 1.0);
+ double fY = M_PI * static_cast<double>(rPnt.X() - m_aStartPos.X())
+ / (m_aReferenceRect.GetWidth() > 0 ? static_cast<double>(m_aReferenceRect.GetWidth()) : 1.0);
+
+ if( m_eRotationDirection != ROTATIONDIRECTION_Y )
+ m_fAdditionalYAngleRad = fY;
+ else
+ m_fAdditionalYAngleRad = 0.0;
+ if( m_eRotationDirection != ROTATIONDIRECTION_X )
+ m_fAdditionalXAngleRad = fX;
+ else
+ m_fAdditionalXAngleRad = 0.0;
+ m_fAdditionalZAngleRad = 0.0;
+
+ if( m_eRotationDirection == ROTATIONDIRECTION_Z )
+ {
+ m_fAdditionalXAngleRad = 0.0;
+ m_fAdditionalYAngleRad = 0.0;
+
+ double fCx = m_aReferenceRect.Center().X();
+ double fCy = m_aReferenceRect.Center().Y();
+
+ m_fAdditionalZAngleRad = atan((fCx - m_aStartPos.X())/(m_aStartPos.Y()-fCy))
+ + atan((fCx - rPnt.X())/(fCy-rPnt.Y()));
+ }
+
+ m_nAdditionalHorizontalAngleDegree = static_cast<sal_Int32>(basegfx::rad2deg(m_fAdditionalXAngleRad));
+ m_nAdditionalVerticalAngleDegree = -static_cast<sal_Int32>(basegfx::rad2deg(m_fAdditionalYAngleRad));
+
+ DragStat().NextMove(rPnt);
+ Show();
+}
+bool DragMethod_RotateDiagram::EndSdrDrag(bool /*bCopy*/)
+{
+ Hide();
+
+ if( m_bRightAngledAxes || m_eRotationDirection==ROTATIONDIRECTION_Z )
+ {
+ double fResultX = m_fInitialXAngleRad + m_fAdditionalXAngleRad;
+ double fResultY = m_fInitialYAngleRad + m_fAdditionalYAngleRad;
+ double fResultZ = m_fInitialZAngleRad + m_fAdditionalZAngleRad;
+
+ if(m_bRightAngledAxes)
+ ThreeDHelper::adaptRadAnglesForRightAngledAxes( fResultX, fResultY );
+
+ rtl::Reference<Diagram> xDiagram = getChartModel()->getFirstChartDiagram();
+ if (xDiagram)
+ xDiagram->setRotationAngle( fResultX, fResultY, fResultZ );
+ }
+ else
+ {
+ rtl::Reference<Diagram> xDiagram = getChartModel()->getFirstChartDiagram();
+ if (xDiagram)
+ xDiagram->setRotation(
+ m_nInitialHorizontalAngleDegree+m_nAdditionalHorizontalAngleDegree, m_nInitialVerticalAngleDegree+m_nAdditionalVerticalAngleDegree );
+ }
+
+ return true;
+}
+void DragMethod_RotateDiagram::CreateOverlayGeometry(
+ sdr::overlay::OverlayManager& rOverlayManager,
+ const sdr::contact::ObjectContact& rObjectContact)
+{
+ ::basegfx::B3DHomMatrix aCurrentTransform;
+ aCurrentTransform.translate( -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0,
+ -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0,
+ -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0 );
+
+ double fResultX = m_fInitialXAngleRad + m_fAdditionalXAngleRad;
+ double fResultY = m_fInitialYAngleRad + m_fAdditionalYAngleRad;
+ double fResultZ = m_fInitialZAngleRad + m_fAdditionalZAngleRad;
+
+ if(!m_bRightAngledAxes)
+ {
+ if( m_eRotationDirection!=ROTATIONDIRECTION_Z )
+ {
+ ThreeDHelper::convertElevationRotationDegToXYZAngleRad(
+ m_nInitialHorizontalAngleDegree+m_nAdditionalHorizontalAngleDegree, -(m_nInitialVerticalAngleDegree+m_nAdditionalVerticalAngleDegree)
+ , fResultX, fResultY, fResultZ );
+ }
+ aCurrentTransform.rotate( fResultX, fResultY, fResultZ );
+ }
+ else
+ {
+ ThreeDHelper::adaptRadAnglesForRightAngledAxes( fResultX, fResultY );
+ aCurrentTransform.shearXY(fResultY,-fResultX);
+ }
+
+ if(!(m_aWireframePolyPolygon.count() && m_pScene))
+ return;
+
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(m_pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+ const basegfx::B3DHomMatrix aWorldToView(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection() * aViewInfo3D.getOrientation());
+ const basegfx::B3DHomMatrix aTransform(aWorldToView * aCurrentTransform);
+
+ // transform to relative scene coordinates
+ basegfx::B2DPolyPolygon aPolyPolygon(basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(m_aWireframePolyPolygon, aTransform));
+
+ // transform to 2D view coordinates
+ aPolyPolygon.transform(rVCScene.getObjectTransformation());
+
+ std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(
+ new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
+ std::move(aPolyPolygon)));
+
+ insertNewlyCreatedOverlayObjectForSdrDragMethod(
+ std::move(pNew),
+ rObjectContact,
+ rOverlayManager);
+}
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/DragMethod_RotateDiagram.hxx b/chart2/source/controller/main/DragMethod_RotateDiagram.hxx
new file mode 100644
index 0000000000..69e9050eeb
--- /dev/null
+++ b/chart2/source/controller/main/DragMethod_RotateDiagram.hxx
@@ -0,0 +1,86 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include "DragMethod_Base.hxx"
+
+#include <basegfx/polygon/b3dpolypolygon.hxx>
+
+class E3dScene;
+namespace chart { class DrawViewWrapper; }
+
+namespace chart
+{
+
+class DragMethod_RotateDiagram : public DragMethod_Base
+{
+public:
+ enum RotationDirection
+ {
+ ROTATIONDIRECTION_FREE,
+ ROTATIONDIRECTION_X,
+ ROTATIONDIRECTION_Y,
+ ROTATIONDIRECTION_Z
+ };
+
+ DragMethod_RotateDiagram( DrawViewWrapper& rDrawViewWrapper
+ , const OUString& rObjectCID
+ , const rtl::Reference<::chart::ChartModel>& xChartModel
+ , RotationDirection eRotationDirection
+ );
+ virtual ~DragMethod_RotateDiagram() override;
+
+ virtual OUString GetSdrDragComment() const override;
+
+ virtual bool BeginSdrDrag() override;
+ virtual void MoveSdrDrag(const Point& rPnt) override;
+ virtual bool EndSdrDrag(bool bCopy) override;
+
+ virtual void CreateOverlayGeometry(
+ sdr::overlay::OverlayManager& rOverlayManager,
+ const sdr::contact::ObjectContact& rObjectContact) override;
+
+private:
+ E3dScene* m_pScene;
+
+ tools::Rectangle m_aReferenceRect;
+ Point m_aStartPos;
+ basegfx::B3DPolyPolygon m_aWireframePolyPolygon;
+
+ double m_fInitialXAngleRad;
+ double m_fInitialYAngleRad;
+ double m_fInitialZAngleRad;
+
+ double m_fAdditionalXAngleRad;
+ double m_fAdditionalYAngleRad;
+ double m_fAdditionalZAngleRad;
+
+ sal_Int32 m_nInitialHorizontalAngleDegree;
+ sal_Int32 m_nInitialVerticalAngleDegree;
+
+ sal_Int32 m_nAdditionalHorizontalAngleDegree;
+ sal_Int32 m_nAdditionalVerticalAngleDegree;
+
+ RotationDirection m_eRotationDirection;
+ bool m_bRightAngledAxes;
+};
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/DrawCommandDispatch.cxx b/chart2/source/controller/main/DrawCommandDispatch.cxx
new file mode 100644
index 0000000000..1446059a02
--- /dev/null
+++ b/chart2/source/controller/main/DrawCommandDispatch.cxx
@@ -0,0 +1,613 @@
+/* -*- 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 "DrawCommandDispatch.hxx"
+#include <ChartController.hxx>
+#include <DrawViewWrapper.hxx>
+#include <chartview/DrawModelWrapper.hxx>
+
+#include <com/sun/star/frame/CommandGroup.hpp>
+#include <o3tl/unsafe_downcast.hxx>
+#include <o3tl/string_view.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/itempool.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/gallery.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xtable.hxx>
+#include <svx/sdtagitm.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::frame;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+
+namespace chart
+{
+
+DrawCommandDispatch::DrawCommandDispatch( const Reference< uno::XComponentContext >& rxContext,
+ ChartController* pController )
+ :FeatureCommandDispatchBase( rxContext )
+ ,m_pChartController( pController )
+{
+}
+
+DrawCommandDispatch::~DrawCommandDispatch()
+{
+}
+
+bool DrawCommandDispatch::isFeatureSupported( const OUString& rCommandURL )
+{
+ ChartCommandID nFeatureId = ChartCommandID::NONE;
+ OUString aBaseCommand;
+ OUString aCustomShapeType;
+ return parseCommandURL( rCommandURL, &nFeatureId, &aBaseCommand, &aCustomShapeType );
+}
+
+static ::basegfx::B2DPolyPolygon getPolygon(TranslateId pResId, const SdrModel& rModel)
+{
+ ::basegfx::B2DPolyPolygon aReturn;
+ XLineEndListRef pLineEndList = rModel.GetLineEndList();
+ if ( pLineEndList.is() )
+ {
+ OUString aName(SvxResId(pResId));
+ tools::Long nCount = pLineEndList->Count();
+ for ( tools::Long nIndex = 0; nIndex < nCount; ++nIndex )
+ {
+ const XLineEndEntry* pEntry = pLineEndList->GetLineEnd(nIndex);
+ if ( pEntry->GetName() == aName )
+ {
+ aReturn = pEntry->GetLineEnd();
+ break;
+ }
+ }
+ }
+ return aReturn;
+}
+
+void DrawCommandDispatch::setAttributes( SdrObject* pObj )
+{
+ if ( !m_pChartController )
+ return;
+
+ DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper();
+ DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper();
+ if ( !(pDrawModelWrapper && pDrawViewWrapper && pDrawViewWrapper->GetCurrentObjIdentifier() == SdrObjKind::CustomShape) )
+ return;
+
+ bool bAttributesAppliedFromGallery = false;
+ if ( GalleryExplorer::GetSdrObjCount( GALLERY_THEME_POWERPOINT ) )
+ {
+ std::vector< OUString > aObjList;
+ if ( GalleryExplorer::FillObjListTitle( GALLERY_THEME_POWERPOINT, aObjList ) )
+ {
+ for ( size_t i = 0; i < aObjList.size(); ++i )
+ {
+ if ( aObjList[ i ].equalsIgnoreAsciiCase( m_aCustomShapeType ) )
+ {
+ FmFormModel aModel;
+ SfxItemPool& rPool(aModel.GetItemPool());
+ rPool.FreezeIdRanges();
+
+ if ( GalleryExplorer::GetSdrObj( GALLERY_THEME_POWERPOINT, i, &aModel ) )
+ {
+ const SdrObject* pSourceObj = aModel.GetPage( 0 )->GetObj( 0 );
+ if ( pSourceObj )
+ {
+ const SfxItemSet& rSource = pSourceObj->GetMergedItemSet();
+ SfxItemSetFixed<
+ // Ranges from SdrAttrObj:
+ SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST,
+ SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTDIRECTION,
+ // Graphic attributes, 3D
+ // properties, CustomShape
+ // properties:
+ SDRATTR_GRAF_FIRST,
+ SDRATTR_CUSTOMSHAPE_LAST,
+ // Range from SdrTextObj:
+ EE_ITEMS_START, EE_ITEMS_END>
+ aDest(pObj->getSdrModelFromSdrObject().GetItemPool());
+ aDest.Set( rSource );
+ pObj->SetMergedItemSet( aDest );
+ Degree100 nAngle = pSourceObj->GetRotateAngle();
+ if ( nAngle )
+ pObj->NbcRotate( pObj->GetSnapRect().Center(), nAngle );
+ bAttributesAppliedFromGallery = true;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ if ( !bAttributesAppliedFromGallery )
+ {
+ pObj->SetMergedItem( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_CENTER ) );
+ pObj->SetMergedItem( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_BLOCK ) );
+ pObj->SetMergedItem( makeSdrTextAutoGrowHeightItem( false ) );
+
+ o3tl::unsafe_downcast< SdrObjCustomShape* >( pObj )->MergeDefaultAttributes( &m_aCustomShapeType );
+ }
+}
+
+void DrawCommandDispatch::setLineEnds( SfxItemSet& rAttr )
+{
+ if ( !(m_nFeatureId == ChartCommandID::DrawLineArrowEnd && m_pChartController) )
+ return;
+
+ DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper();
+ DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper();
+ if ( !(pDrawModelWrapper && pDrawViewWrapper) )
+ return;
+
+ ::basegfx::B2DPolyPolygon aArrow( getPolygon( RID_SVXSTR_ARROW, pDrawModelWrapper->getSdrModel() ) );
+ if ( !aArrow.count() )
+ {
+ ::basegfx::B2DPolygon aNewArrow;
+ aNewArrow.append( ::basegfx::B2DPoint( 10.0, 0.0 ) );
+ aNewArrow.append( ::basegfx::B2DPoint( 0.0, 30.0) );
+ aNewArrow.append( ::basegfx::B2DPoint( 20.0, 30.0 ) );
+ aNewArrow.setClosed( true );
+ aArrow.append( aNewArrow );
+ }
+
+ SfxItemSet aSet(pDrawViewWrapper->GetModel().GetItemPool());
+ pDrawViewWrapper->GetAttributes( aSet );
+
+ tools::Long nWidth = 300; // (1/100th mm)
+ if ( aSet.GetItemState( XATTR_LINEWIDTH ) != SfxItemState::DONTCARE )
+ {
+ tools::Long nValue = aSet.Get( XATTR_LINEWIDTH ).GetValue();
+ if ( nValue > 0 )
+ {
+ nWidth = nValue * 3;
+ }
+ }
+
+ rAttr.Put( XLineEndItem( SvxResId( RID_SVXSTR_ARROW ), aArrow ) );
+ rAttr.Put( XLineEndWidthItem( nWidth ) );
+}
+
+// WeakComponentImplHelperBase
+void DrawCommandDispatch::disposing(std::unique_lock<std::mutex>& /*rGuard*/)
+{
+}
+
+// XEventListener
+void DrawCommandDispatch::disposing( const lang::EventObject& /* Source */ )
+{
+}
+
+FeatureState DrawCommandDispatch::getState( const OUString& rCommand )
+{
+ FeatureState aReturn;
+ aReturn.bEnabled = false;
+ aReturn.aState <<= false;
+
+ ChartCommandID nFeatureId = ChartCommandID::NONE;
+ OUString aBaseCommand;
+ OUString aCustomShapeType;
+ if ( parseCommandURL( rCommand, &nFeatureId, &aBaseCommand, &aCustomShapeType ) )
+ {
+ switch ( nFeatureId )
+ {
+ case ChartCommandID::DrawObjectSelect:
+ case ChartCommandID::DrawLine:
+ case ChartCommandID::DrawLineArrowEnd:
+ case ChartCommandID::DrawRect:
+ case ChartCommandID::DrawEllipse:
+ case ChartCommandID::DrawFreelineNoFill:
+ case ChartCommandID::DrawText:
+ case ChartCommandID::DrawCaption:
+ case ChartCommandID::DrawToolboxCsBasic:
+ case ChartCommandID::DrawToolboxCsSymbol:
+ case ChartCommandID::DrawToolboxCsArrow:
+ case ChartCommandID::DrawToolboxCsFlowchart:
+ case ChartCommandID::DrawToolboxCsCallout:
+ case ChartCommandID::DrawToolboxCsStar:
+ {
+ aReturn.bEnabled = true;
+ aReturn.aState <<= false;
+ }
+ break;
+ default:
+ {
+ aReturn.bEnabled = false;
+ aReturn.aState <<= false;
+ }
+ break;
+ }
+ }
+
+ return aReturn;
+}
+
+void DrawCommandDispatch::execute( const OUString& rCommand, const Sequence< beans::PropertyValue>& rArgs )
+{
+ ChartDrawMode eDrawMode = CHARTDRAW_SELECT;
+ SdrObjKind eKind = SdrObjKind::NONE;
+
+ ChartCommandID nFeatureId = ChartCommandID::NONE;
+ OUString aBaseCommand;
+ OUString aCustomShapeType;
+ if ( !parseCommandURL( rCommand, &nFeatureId, &aBaseCommand, &aCustomShapeType ) )
+ return;
+
+ bool bCreate = false;
+ m_nFeatureId = nFeatureId;
+ m_aCustomShapeType = aCustomShapeType;
+
+ switch ( nFeatureId )
+ {
+ case ChartCommandID::DrawObjectSelect:
+ {
+ eDrawMode = CHARTDRAW_SELECT;
+ eKind = SdrObjKind::NONE;
+ }
+ break;
+ case ChartCommandID::DrawLine:
+ case ChartCommandID::DrawLineArrowEnd:
+ {
+ eDrawMode = CHARTDRAW_INSERT;
+ eKind = SdrObjKind::Line;
+ }
+ break;
+ case ChartCommandID::DrawRect:
+ {
+ eDrawMode = CHARTDRAW_INSERT;
+ eKind = SdrObjKind::Rectangle;
+ }
+ break;
+ case ChartCommandID::DrawEllipse:
+ {
+ eDrawMode = CHARTDRAW_INSERT;
+ eKind = SdrObjKind::CircleOrEllipse;
+ }
+ break;
+ case ChartCommandID::DrawFreelineNoFill:
+ {
+ eDrawMode = CHARTDRAW_INSERT;
+ eKind = SdrObjKind::FreehandLine;
+ }
+ break;
+ case ChartCommandID::DrawText:
+ {
+ eDrawMode = CHARTDRAW_INSERT;
+ eKind = SdrObjKind::Text;
+ bCreate = true;
+ }
+ break;
+ case ChartCommandID::DrawCaption:
+ {
+ eDrawMode = CHARTDRAW_INSERT;
+ eKind = SdrObjKind::Caption;
+ }
+ break;
+ case ChartCommandID::DrawToolboxCsBasic:
+ case ChartCommandID::DrawToolboxCsSymbol:
+ case ChartCommandID::DrawToolboxCsArrow:
+ case ChartCommandID::DrawToolboxCsFlowchart:
+ case ChartCommandID::DrawToolboxCsCallout:
+ case ChartCommandID::DrawToolboxCsStar:
+ {
+ eDrawMode = CHARTDRAW_INSERT;
+ eKind = SdrObjKind::CustomShape;
+ }
+ break;
+ default:
+ {
+ eDrawMode = CHARTDRAW_SELECT;
+ eKind = SdrObjKind::NONE;
+ }
+ break;
+ }
+
+ if ( !m_pChartController )
+ return;
+
+ DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper();
+ if ( !pDrawViewWrapper )
+ return;
+
+ SolarMutexGuard aGuard;
+ m_pChartController->setDrawMode( eDrawMode );
+ setInsertObj(eKind);
+ if ( bCreate )
+ {
+ pDrawViewWrapper->SetCreateMode();
+ }
+
+ const beans::PropertyValue* pIter = rArgs.getConstArray();
+ const beans::PropertyValue* pEnd = pIter + rArgs.getLength();
+ const beans::PropertyValue* pKeyModifier = std::find_if(pIter, pEnd,
+ [](const beans::PropertyValue& lhs)
+ {return lhs.Name == "KeyModifier";} );
+ sal_Int16 nKeyModifier = 0;
+ if ( !(pKeyModifier != pEnd && ( pKeyModifier->Value >>= nKeyModifier ) && nKeyModifier == KEY_MOD1) )
+ return;
+
+ if ( eDrawMode != CHARTDRAW_INSERT )
+ return;
+
+ rtl::Reference<SdrObject> pObj = createDefaultObject( nFeatureId );
+ if ( pObj )
+ {
+ SdrPageView* pPageView = pDrawViewWrapper->GetSdrPageView();
+ if (pDrawViewWrapper->InsertObjectAtView(pObj.get(), *pPageView))
+ m_pChartController->SetAndApplySelection(Reference<drawing::XShape>(pObj->getUnoShape(), uno::UNO_QUERY));
+ if ( nFeatureId == ChartCommandID::DrawText )
+ {
+ m_pChartController->StartTextEdit();
+ }
+ }
+}
+
+void DrawCommandDispatch::describeSupportedFeatures()
+{
+ implDescribeSupportedFeature( ".uno:SelectObject", ChartCommandID::DrawObjectSelect, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:Line", ChartCommandID::DrawLine, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:LineArrowEnd", ChartCommandID::DrawLineArrowEnd, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:Rect", ChartCommandID::DrawRect, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:Ellipse", ChartCommandID::DrawEllipse, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:Freeline_Unfilled", ChartCommandID::DrawFreelineNoFill, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DrawText", ChartCommandID::DrawText, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DrawCaption", ChartCommandID::DrawCaption, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:BasicShapes", ChartCommandID::DrawToolboxCsBasic, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:SymbolShapes", ChartCommandID::DrawToolboxCsSymbol, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:ArrowShapes", ChartCommandID::DrawToolboxCsArrow, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:FlowChartShapes", ChartCommandID::DrawToolboxCsFlowchart, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:CalloutShapes", ChartCommandID::DrawToolboxCsCallout, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:StarShapes", ChartCommandID::DrawToolboxCsStar, CommandGroup::INSERT );
+}
+
+void DrawCommandDispatch::setInsertObj(SdrObjKind eObj)
+{
+ DrawViewWrapper* pDrawViewWrapper = ( m_pChartController ? m_pChartController->GetDrawViewWrapper() : nullptr );
+ if ( pDrawViewWrapper )
+ {
+ pDrawViewWrapper->SetCurrentObj( eObj /*, Inventor */);
+ }
+}
+
+rtl::Reference<SdrObject> DrawCommandDispatch::createDefaultObject( const ChartCommandID nID )
+{
+ rtl::Reference<SdrObject> pObj;
+ DrawViewWrapper* pDrawViewWrapper = ( m_pChartController ? m_pChartController->GetDrawViewWrapper() : nullptr );
+ DrawModelWrapper* pDrawModelWrapper = ( m_pChartController ? m_pChartController->GetDrawModelWrapper() : nullptr );
+
+ if ( pDrawViewWrapper && pDrawModelWrapper )
+ {
+ Reference< drawing::XDrawPage > xDrawPage( pDrawModelWrapper->getMainDrawPage() );
+ SdrPage* pPage = GetSdrPageFromXDrawPage( xDrawPage );
+ if ( pPage )
+ {
+ SolarMutexGuard aGuard;
+
+ pObj = SdrObjFactory::MakeNewObject(
+ pDrawModelWrapper->getSdrModel(),
+ pDrawViewWrapper->GetCurrentObjInventor(),
+ pDrawViewWrapper->GetCurrentObjIdentifier());
+
+ if ( pObj )
+ {
+ Size aObjectSize( 4000, 2500 );
+ tools::Rectangle aPageRect( tools::Rectangle( Point( 0, 0 ), pPage->GetSize() ) );
+ Point aObjectPos = aPageRect.Center();
+ aObjectPos.AdjustX( -(aObjectSize.Width() / 2) );
+ aObjectPos.AdjustY( -(aObjectSize.Height() / 2) );
+ tools::Rectangle aRect( aObjectPos, aObjectSize );
+
+ switch ( nID )
+ {
+ case ChartCommandID::DrawLine:
+ case ChartCommandID::DrawLineArrowEnd:
+ {
+ if ( auto const pathObj = dynamic_cast<SdrPathObj*>( pObj.get()) )
+ {
+ Point aStart = aRect.TopLeft();
+ Point aEnd = aRect.BottomRight();
+ sal_Int32 nYMiddle( ( aRect.Top() + aRect.Bottom() ) / 2 );
+ basegfx::B2DPolygon aPoly;
+ aPoly.append( basegfx::B2DPoint( aStart.X(), nYMiddle ) );
+ aPoly.append( basegfx::B2DPoint( aEnd.X(), nYMiddle ) );
+ pathObj->SetPathPoly(basegfx::B2DPolyPolygon(aPoly));
+ SfxItemSet aSet( pDrawModelWrapper->GetItemPool() );
+ setLineEnds( aSet );
+ pObj->SetMergedItemSet( aSet );
+ }
+ }
+ break;
+ case ChartCommandID::DrawFreelineNoFill:
+ {
+ if ( auto const pathObj = dynamic_cast<SdrPathObj*>( pObj.get()) )
+ {
+ basegfx::B2DPolygon aInnerPoly;
+ aInnerPoly.append( basegfx::B2DPoint( aRect.Left(), aRect.Bottom() ) );
+ aInnerPoly.appendBezierSegment(
+ basegfx::B2DPoint( aRect.Left(), aRect.Top() ),
+ basegfx::B2DPoint( aRect.Center().X(), aRect.Top() ),
+ basegfx::B2DPoint( aRect.Center().X(), aRect.Center().Y() ) );
+ aInnerPoly.appendBezierSegment(
+ basegfx::B2DPoint( aRect.Center().X(), aRect.Bottom() ),
+ basegfx::B2DPoint( aRect.Right(), aRect.Bottom() ),
+ basegfx::B2DPoint( aRect.Right(), aRect.Top() ) );
+ basegfx::B2DPolyPolygon aPoly;
+ aPoly.append( aInnerPoly );
+ pathObj->SetPathPoly(aPoly);
+ }
+ }
+ break;
+ case ChartCommandID::DrawText:
+ case ChartCommandID::DrawTextVertical:
+ {
+ if ( SdrTextObj* pTextObj = DynCastSdrTextObj( pObj.get()) )
+ {
+ pTextObj->SetLogicRect( aRect );
+ bool bVertical = ( nID == ChartCommandID::DrawTextVertical );
+ pTextObj->SetVerticalWriting( bVertical );
+ if ( bVertical )
+ {
+ SfxItemSet aSet( pDrawModelWrapper->GetItemPool() );
+ aSet.Put( makeSdrTextAutoGrowWidthItem( true ) );
+ aSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
+ aSet.Put( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_TOP ) );
+ aSet.Put( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_RIGHT ) );
+ pTextObj->SetMergedItemSet( aSet );
+ }
+ }
+ }
+ break;
+ case ChartCommandID::DrawCaption:
+ case ChartCommandID::DrawCaptionVertical:
+ {
+ if ( SdrCaptionObj* pCaptionObj = dynamic_cast<SdrCaptionObj*>( pObj.get()) )
+ {
+ bool bIsVertical( nID == ChartCommandID::DrawCaptionVertical );
+ pCaptionObj->SetVerticalWriting( bIsVertical );
+ if ( bIsVertical )
+ {
+ SfxItemSet aSet( pObj->GetMergedItemSet() );
+ aSet.Put( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_CENTER ) );
+ aSet.Put( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_RIGHT ) );
+ pObj->SetMergedItemSet( aSet );
+ }
+ pCaptionObj->SetLogicRect( aRect );
+ pCaptionObj->SetTailPos(
+ aRect.TopLeft() - Point( aRect.GetWidth() / 2, aRect.GetHeight() / 2 ) );
+ }
+ }
+ break;
+ default:
+ {
+ pObj->SetLogicRect( aRect );
+ SfxItemSet aSet( pDrawModelWrapper->GetItemPool() );
+ setAttributes( pObj.get() );
+ pObj->SetMergedItemSet( aSet );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return pObj;
+}
+
+bool DrawCommandDispatch::parseCommandURL( const OUString& rCommandURL, ChartCommandID* pnFeatureId,
+ OUString* pBaseCommand, OUString* pCustomShapeType )
+{
+ bool bFound = true;
+ ChartCommandID nFeatureId = ChartCommandID::NONE;
+ OUString aBaseCommand;
+ OUString aType;
+
+ sal_Int32 nIndex = std::min(sal_Int32(1), rCommandURL.getLength());
+ std::u16string_view aToken = o3tl::getToken(rCommandURL, 0, '.', nIndex );
+ if ( nIndex == -1 || aToken.empty() )
+ {
+ aBaseCommand = rCommandURL;
+ SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( aBaseCommand );
+ if ( aIter != m_aSupportedFeatures.end() )
+ {
+ nFeatureId = aIter->second.nFeatureId;
+
+ switch ( nFeatureId )
+ {
+ case ChartCommandID::DrawToolboxCsBasic:
+ {
+ aType = "diamond";
+ }
+ break;
+ case ChartCommandID::DrawToolboxCsSymbol:
+ {
+ aType = "smiley";
+ }
+ break;
+ case ChartCommandID::DrawToolboxCsArrow:
+ {
+ aType = "left-right-arrow";
+ }
+ break;
+ case ChartCommandID::DrawToolboxCsFlowchart:
+ {
+ aType = "flowchart-internal-storage";
+ }
+ break;
+ case ChartCommandID::DrawToolboxCsCallout:
+ {
+ aType = "round-rectangular-callout";
+ }
+ break;
+ case ChartCommandID::DrawToolboxCsStar:
+ {
+ aType = "star5";
+ }
+ break;
+ default:
+ {
+ }
+ break;
+ }
+ }
+ else
+ {
+ bFound = false;
+ }
+ }
+ else
+ {
+ aBaseCommand = rCommandURL.copy( 0, nIndex - 1 );
+ SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( aBaseCommand );
+ if ( aIter != m_aSupportedFeatures.end() )
+ {
+ nFeatureId = aIter->second.nFeatureId;
+ aType = rCommandURL.getToken( 0, '.', nIndex );
+ }
+ else
+ {
+ bFound = false;
+ }
+ }
+
+ *pnFeatureId = nFeatureId;
+ *pBaseCommand = aBaseCommand;
+ *pCustomShapeType = aType;
+
+ return bFound;
+}
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/DrawCommandDispatch.hxx b/chart2/source/controller/main/DrawCommandDispatch.hxx
new file mode 100644
index 0000000000..65200cca63
--- /dev/null
+++ b/chart2/source/controller/main/DrawCommandDispatch.hxx
@@ -0,0 +1,74 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <svx/svdobjkind.hxx>
+#include "FeatureCommandDispatchBase.hxx"
+#include <rtl/ref.hxx>
+
+class SfxItemSet;
+class SdrObject;
+
+namespace chart
+{
+
+class ChartController;
+
+/** This is a CommandDispatch implementation for drawing objects.
+ */
+class DrawCommandDispatch: public FeatureCommandDispatchBase
+{
+public:
+ DrawCommandDispatch( const css::uno::Reference< css::uno::XComponentContext >& rxContext, ChartController* pController );
+ virtual ~DrawCommandDispatch() override;
+
+ virtual bool isFeatureSupported( const OUString& rCommandURL ) override;
+
+ void setAttributes( SdrObject* pObj );
+ void setLineEnds( SfxItemSet& rAttr );
+
+protected:
+ // WeakComponentImplHelperBase
+ virtual void disposing( std::unique_lock<std::mutex>& rGuard ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // state of a feature
+ virtual FeatureState getState( const OUString& rCommand ) override;
+
+ // execute a feature
+ virtual void execute( const OUString& rCommand, const css::uno::Sequence< css::beans::PropertyValue>& rArgs ) override;
+
+ // all the features which should be handled by this class
+ virtual void describeSupportedFeatures() override;
+
+private:
+ void setInsertObj(SdrObjKind eObj);
+ rtl::Reference<SdrObject> createDefaultObject( const ChartCommandID nID );
+
+ bool parseCommandURL( const OUString& rCommandURL, ChartCommandID* pnFeatureId, OUString* pBaseCommand, OUString* pCustomShapeType );
+
+ ChartController* m_pChartController;
+ OUString m_aCustomShapeType;
+};
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ElementSelector.cxx b/chart2/source/controller/main/ElementSelector.cxx
new file mode 100644
index 0000000000..d538108ae8
--- /dev/null
+++ b/chart2/source/controller/main/ElementSelector.cxx
@@ -0,0 +1,319 @@
+/* -*- 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 "ElementSelector.hxx"
+#include <ObjectNameProvider.hxx>
+#include <ObjectHierarchy.hxx>
+#include <servicenames.hxx>
+#include <DrawViewWrapper.hxx>
+#include <ResId.hxx>
+#include <strings.hrc>
+#include <ObjectIdentifier.hxx>
+#include <ChartController.hxx>
+#include <ChartModel.hxx>
+
+#include <cppuhelper/supportsservice.hxx>
+#include <o3tl/safeint.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/svapp.hxx>
+
+namespace chart { class ExplicitValueProvider; }
+
+namespace chart
+{
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace
+{
+constexpr OUStringLiteral lcl_aServiceName
+ = u"com.sun.star.comp.chart.ElementSelectorToolbarController";
+}
+
+SelectorListBox::SelectorListBox(vcl::Window* pParent)
+ : InterimItemWindow(pParent, "modules/schart/ui/combobox.ui", "ComboBox")
+ , m_xWidget(m_xBuilder->weld_combo_box("combobox"))
+ , m_bReleaseFocus(true)
+{
+ InitControlBase(m_xWidget.get());
+
+ m_xWidget->connect_key_press(LINK(this, SelectorListBox, KeyInputHdl));
+ m_xWidget->connect_changed(LINK(this, SelectorListBox, SelectHdl));
+ m_xWidget->connect_focus_out(LINK(this, SelectorListBox, FocusOutHdl));
+
+ ::Size aLogicalSize(75, 0);
+ ::Size aPixelSize = LogicToPixel(aLogicalSize, MapMode(MapUnit::MapAppFont));
+ m_xWidget->set_size_request(aPixelSize.Width(), -1);
+ SetSizePixel(m_xContainer->get_preferred_size());
+}
+
+void SelectorListBox::dispose()
+{
+ m_xWidget.reset();
+ InterimItemWindow::dispose();
+}
+
+SelectorListBox::~SelectorListBox()
+{
+ disposeOnce();
+}
+
+static void lcl_addObjectsToList( const ObjectHierarchy& rHierarchy, const ObjectIdentifier & rParent, std::vector< ListBoxEntryData >& rEntries
+ , const sal_Int32 nHierarchyDepth, const rtl::Reference<::chart::ChartModel>& xChartDoc )
+{
+ ObjectHierarchy::tChildContainer aChildren( rHierarchy.getChildren(rParent) );
+ for (auto const& child : aChildren)
+ {
+ ListBoxEntryData aEntry;
+ aEntry.OID = child;
+ aEntry.UIName = ObjectNameProvider::getNameForCID( child.getObjectCID(), xChartDoc );
+ aEntry.nHierarchyDepth = nHierarchyDepth;
+ rEntries.push_back(aEntry);
+ lcl_addObjectsToList( rHierarchy, child, rEntries, nHierarchyDepth+1, xChartDoc );
+ }
+}
+
+void SelectorListBox::SetChartController( const rtl::Reference< ::chart::ChartController >& xChartController )
+{
+ m_xChartController = xChartController.get();
+}
+
+void SelectorListBox::UpdateChartElementsListAndSelection()
+{
+ m_xWidget->clear();
+ m_aEntries.clear();
+
+ rtl::Reference< ::chart::ChartController > xChartController = m_xChartController.get();
+ if( xChartController.is() )
+ {
+ ObjectIdentifier aSelectedOID( xChartController->getSelection() );
+ OUString aSelectedCID = aSelectedOID.getObjectCID();
+
+ rtl::Reference<::chart::ChartModel> xChartDoc = xChartController->getChartModel();
+ ObjectType eType( aSelectedOID.getObjectType() );
+ bool bAddSelectionToList = false;
+ if ( eType == OBJECTTYPE_DATA_POINT || eType == OBJECTTYPE_DATA_LABEL || eType == OBJECTTYPE_SHAPE )
+ bAddSelectionToList = true;
+
+ Reference< uno::XInterface > xChartView;
+ rtl::Reference< ChartModel > xFact = xChartController->getChartModel();
+ if( xFact.is() )
+ xChartView = xFact->createInstance( CHART_VIEW_SERVICE_NAME );
+ ExplicitValueProvider* pExplicitValueProvider = nullptr; //ExplicitValueProvider::getExplicitValueProvider(xChartView); this creates all visible data points, that's too much
+ ObjectHierarchy aHierarchy( xChartDoc, pExplicitValueProvider, true /*bFlattenDiagram*/, true /*bOrderingForElementSelector*/ );
+ lcl_addObjectsToList( aHierarchy, ::chart::ObjectHierarchy::getRootNodeOID(), m_aEntries, 0, xChartDoc );
+
+ if( bAddSelectionToList )
+ {
+ if ( aSelectedOID.isAutoGeneratedObject() )
+ {
+ OUString aSeriesCID = ObjectIdentifier::createClassifiedIdentifierForParticle( ObjectIdentifier::getSeriesParticleFromCID( aSelectedCID ) );
+ std::vector< ListBoxEntryData >::iterator aIt = std::find_if(m_aEntries.begin(), m_aEntries.end(),
+ [&aSeriesCID](const ListBoxEntryData& rEntry) { return rEntry.OID.getObjectCID().match(aSeriesCID); });
+ if (aIt != m_aEntries.end())
+ {
+ ListBoxEntryData aEntry;
+ aEntry.UIName = ObjectNameProvider::getNameForCID( aSelectedCID, xChartDoc );
+ aEntry.OID = aSelectedOID;
+ ++aIt;
+ if( aIt != m_aEntries.end() )
+ m_aEntries.insert(aIt, aEntry);
+ else
+ m_aEntries.push_back( aEntry );
+ }
+ }
+ else if ( aSelectedOID.isAdditionalShape() )
+ {
+ ListBoxEntryData aEntry;
+ SdrObject* pSelectedObj = DrawViewWrapper::getSdrObject( aSelectedOID.getAdditionalShape() );
+ OUString aName = pSelectedObj ? pSelectedObj->GetName() : OUString();
+ aEntry.UIName = ( aName.isEmpty() ? SchResId( STR_OBJECT_SHAPE ) : aName );
+ aEntry.OID = aSelectedOID;
+ m_aEntries.push_back( aEntry );
+ }
+ }
+
+ m_xWidget->freeze();
+ sal_uInt16 nEntryPosToSelect = 0; bool bSelectionFound = false;
+ sal_uInt16 nN=0;
+ for (auto const& entry : m_aEntries)
+ {
+ // tdf#152087 strip any newlines from the entry
+ m_xWidget->append_text(entry.UIName.replaceAll("\n", " "));
+ if ( !bSelectionFound && aSelectedOID == entry.OID )
+ {
+ nEntryPosToSelect = nN;
+ bSelectionFound = true;
+ }
+ ++nN;
+ }
+ m_xWidget->thaw();
+
+ if( bSelectionFound )
+ m_xWidget->set_active(nEntryPosToSelect);
+ }
+ m_xWidget->save_value(); //remind current selection pos
+}
+
+void SelectorListBox::ReleaseFocus_Impl()
+{
+ if ( !m_bReleaseFocus )
+ {
+ m_bReleaseFocus = true;
+ return;
+ }
+
+ rtl::Reference< ::chart::ChartController > xController = m_xChartController.get();
+ Reference< frame::XFrame > xFrame( xController->getFrame() );
+ if ( xFrame.is() && xFrame->getContainerWindow().is() )
+ xFrame->getContainerWindow()->setFocus();
+}
+
+IMPL_LINK(SelectorListBox, SelectHdl, weld::ComboBox&, rComboBox, void)
+{
+ if (rComboBox.changed_by_direct_pick())
+ {
+ const sal_Int32 nPos = rComboBox.get_active();
+ if (o3tl::make_unsigned(nPos) < m_aEntries.size())
+ {
+ ObjectIdentifier aOID = m_aEntries[nPos].OID;
+ rtl::Reference< ::chart::ChartController > xController = m_xChartController.get();
+ if( xController.is() )
+ xController->select( aOID.getAny() );
+ }
+ ReleaseFocus_Impl();
+ }
+}
+
+IMPL_LINK(SelectorListBox, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bHandled = false;
+
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+
+ switch ( nCode )
+ {
+ case KEY_RETURN:
+ case KEY_TAB:
+ {
+ if ( nCode == KEY_TAB )
+ m_bReleaseFocus = false;
+ else
+ bHandled = true;
+ SelectHdl(*m_xWidget);
+ break;
+ }
+
+ case KEY_ESCAPE:
+ m_xWidget->set_active_text(m_xWidget->get_saved_value()); //restore saved selection
+ ReleaseFocus_Impl();
+ break;
+ }
+
+ return bHandled || ChildKeyInput(rKEvt);
+}
+
+IMPL_LINK_NOARG(SelectorListBox, FocusOutHdl, weld::Widget&, void)
+{
+ if (m_xWidget && !m_xWidget->has_focus()) // comboboxes can be comprised of multiple widgets, ensure all have lost focus
+ m_xWidget->set_active_text(m_xWidget->get_saved_value());
+}
+
+OUString SAL_CALL ElementSelectorToolbarController::getImplementationName()
+{
+ return lcl_aServiceName;
+}
+
+sal_Bool SAL_CALL ElementSelectorToolbarController::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL ElementSelectorToolbarController::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+ElementSelectorToolbarController::ElementSelectorToolbarController()
+{
+}
+ElementSelectorToolbarController::~ElementSelectorToolbarController()
+{
+}
+// XInterface
+Any SAL_CALL ElementSelectorToolbarController::queryInterface( const Type& _rType )
+{
+ Any aReturn = ToolboxController::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ElementSelectorToolbarController_BASE::queryInterface(_rType);
+ return aReturn;
+}
+void SAL_CALL ElementSelectorToolbarController::acquire() noexcept
+{
+ ToolboxController::acquire();
+}
+void SAL_CALL ElementSelectorToolbarController::release() noexcept
+{
+ ToolboxController::release();
+}
+void SAL_CALL ElementSelectorToolbarController::statusChanged( const frame::FeatureStateEvent& rEvent )
+{
+ if( m_apSelectorListBox )
+ {
+ SolarMutexGuard aSolarMutexGuard;
+ if ( rEvent.FeatureURL.Path == "ChartElementSelector" )
+ {
+ Reference< frame::XController > xChartController;
+ rEvent.State >>= xChartController;
+ ::chart::ChartController* pController = dynamic_cast<::chart::ChartController*>(xChartController.get());
+ assert(!xChartController || pController);
+ m_apSelectorListBox->SetChartController( pController );
+ m_apSelectorListBox->UpdateChartElementsListAndSelection();
+ }
+ }
+}
+uno::Reference< awt::XWindow > SAL_CALL ElementSelectorToolbarController::createItemWindow( const uno::Reference< awt::XWindow >& xParent )
+{
+ uno::Reference< awt::XWindow > xItemWindow;
+ if( !m_apSelectorListBox )
+ {
+ VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( xParent );
+ if( pParent )
+ {
+ m_apSelectorListBox.reset(VclPtr<SelectorListBox>::Create(pParent));
+ }
+ }
+ if( m_apSelectorListBox )
+ xItemWindow = VCLUnoHelper::GetInterface( m_apSelectorListBox.get() );
+ return xItemWindow;
+}
+
+} // chart2
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_chart_ElementSelectorToolbarController_get_implementation(css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new chart::ElementSelectorToolbarController );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ElementSelector.hxx b/chart2/source/controller/main/ElementSelector.hxx
new file mode 100644
index 0000000000..fb1e4e0527
--- /dev/null
+++ b/chart2/source/controller/main/ElementSelector.hxx
@@ -0,0 +1,99 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <ObjectIdentifier.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase1.hxx>
+#include <svtools/toolboxcontroller.hxx>
+
+#include <vcl/InterimItemWindow.hxx>
+#include <unotools/weakref.hxx>
+
+namespace chart
+{
+class ChartController;
+
+struct ListBoxEntryData
+{
+ OUString UIName;
+ ObjectIdentifier OID;
+ sal_Int32 nHierarchyDepth;
+
+ ListBoxEntryData() : nHierarchyDepth(0)
+ {
+ }
+};
+
+class SelectorListBox final : public InterimItemWindow
+{
+public:
+ SelectorListBox(vcl::Window* pParent);
+ virtual void dispose() override;
+ virtual ~SelectorListBox() override;
+
+ void ReleaseFocus_Impl();
+
+ void SetChartController( const rtl::Reference< ::chart::ChartController >& xChartController );
+ void UpdateChartElementsListAndSelection();
+
+private:
+ unotools::WeakReference<::chart::ChartController> m_xChartController;
+ std::unique_ptr<weld::ComboBox> m_xWidget;
+
+ std::vector<ListBoxEntryData> m_aEntries;
+
+ bool m_bReleaseFocus;
+
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+ DECL_LINK(FocusOutHdl, weld::Widget&, void);
+};
+
+typedef ::cppu::ImplHelper1 < css::lang::XServiceInfo> ElementSelectorToolbarController_BASE;
+
+class ElementSelectorToolbarController : public ::svt::ToolboxController
+ , public ElementSelectorToolbarController_BASE
+{
+public:
+ explicit ElementSelectorToolbarController();
+ virtual ~ElementSelectorToolbarController() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XStatusListener
+ virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override;
+ // XToolbarController
+ virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override;
+
+private:
+ VclPtr< SelectorListBox > m_apSelectorListBox;
+};
+
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/FeatureCommandDispatchBase.cxx b/chart2/source/controller/main/FeatureCommandDispatchBase.cxx
new file mode 100644
index 0000000000..b1c5f72d1d
--- /dev/null
+++ b/chart2/source/controller/main/FeatureCommandDispatchBase.cxx
@@ -0,0 +1,94 @@
+/* -*- 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 "FeatureCommandDispatchBase.hxx"
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace chart
+{
+
+FeatureCommandDispatchBase::FeatureCommandDispatchBase( const Reference< uno::XComponentContext >& rxContext )
+ :CommandDispatch( rxContext )
+ ,m_nFeatureId( ChartCommandID::NONE )
+{
+}
+
+FeatureCommandDispatchBase::~FeatureCommandDispatchBase()
+{
+}
+
+void FeatureCommandDispatchBase::initialize()
+{
+ CommandDispatch::initialize();
+ describeSupportedFeatures();
+}
+
+bool FeatureCommandDispatchBase::isFeatureSupported( const OUString& rCommandURL )
+{
+ SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( rCommandURL );
+ return aIter != m_aSupportedFeatures.end();
+}
+
+void FeatureCommandDispatchBase::fireStatusEvent( const OUString& rURL,
+ const Reference< frame::XStatusListener >& xSingleListener /* = 0 */ )
+{
+ if ( rURL.isEmpty() )
+ {
+ for (auto const& elem : m_aSupportedFeatures)
+ {
+ FeatureState aFeatureState( getState(elem.first) );
+ fireStatusEventForURL( elem.first, aFeatureState.aState, aFeatureState.bEnabled, xSingleListener );
+ }
+ }
+ else
+ {
+ FeatureState aFeatureState( getState( rURL ) );
+ fireStatusEventForURL( rURL, aFeatureState.aState, aFeatureState.bEnabled, xSingleListener );
+ }
+}
+
+// XDispatch
+void FeatureCommandDispatchBase::dispatch( const util::URL& URL,
+ const Sequence< beans::PropertyValue >& Arguments )
+{
+ OUString aCommand( URL.Complete );
+ if ( getState( aCommand ).bEnabled )
+ {
+ execute( aCommand, Arguments );
+ }
+}
+
+void FeatureCommandDispatchBase::implDescribeSupportedFeature( const char* pAsciiCommandURL,
+ ChartCommandID nId, sal_Int16 nGroup )
+{
+ ControllerFeature aFeature;
+ aFeature.Command = OUString::createFromAscii( pAsciiCommandURL );
+ aFeature.nFeatureId = nId;
+ aFeature.GroupId = nGroup;
+
+ m_aSupportedFeatures[ aFeature.Command ] = aFeature;
+}
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/FeatureCommandDispatchBase.hxx b/chart2/source/controller/main/FeatureCommandDispatchBase.hxx
new file mode 100644
index 0000000000..3ceb35ad12
--- /dev/null
+++ b/chart2/source/controller/main/FeatureCommandDispatchBase.hxx
@@ -0,0 +1,135 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include "CommandDispatch.hxx"
+
+#include <com/sun/star/frame/DispatchInformation.hpp>
+
+enum class ChartCommandID
+{
+ NONE = 0,
+
+ //Draw Command Ids:
+ DrawObjectSelect = 1,
+ DrawLine = 2,
+ DrawLineArrowEnd = 3,
+ DrawRect = 4,
+ DrawEllipse = 5,
+ DrawFreelineNoFill = 6,
+ DrawText = 7,
+ DrawTextVertical = 8,
+ DrawCaption = 9,
+ DrawCaptionVertical = 10,
+ DrawToolboxCsBasic = 11,
+ DrawToolboxCsSymbol = 12,
+ DrawToolboxCsArrow = 13,
+ DrawToolboxCsFlowchart = 14,
+ DrawToolboxCsCallout = 15,
+ DrawToolboxCsStar = 16,
+
+ //Shape Controller Command Ids:
+ ShapeFormatLine = 21,
+ ShapeFormatArea = 22,
+ ShapeTextAttributes = 23,
+ ShapeTransformDialog = 24,
+ ShapeObjectTitleDescription = 25,
+ ShapeRenameObject = 26,
+ ShapeBringToFront = 28,
+ ShapeForward = 29,
+ ShapeBackward = 30,
+ ShapeSendToBack = 31,
+ ShapeFontDialog = 35,
+ ShapeParagraphDialog = 36
+};
+
+
+namespace chart
+{
+
+struct ControllerFeature: public css::frame::DispatchInformation
+{
+ ChartCommandID nFeatureId;
+};
+
+typedef std::map< OUString,
+ ControllerFeature > SupportedFeatures;
+
+struct FeatureState
+{
+ bool bEnabled;
+ css::uno::Any aState;
+
+ FeatureState() : bEnabled( false ) { }
+};
+
+/** This is a base class for CommandDispatch implementations with feature support.
+ */
+class FeatureCommandDispatchBase: public CommandDispatch
+{
+public:
+ explicit FeatureCommandDispatchBase( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+ virtual ~FeatureCommandDispatchBase() override;
+
+ // late initialisation, especially for adding as listener
+ virtual void initialize() override;
+
+ virtual bool isFeatureSupported( const OUString& rCommandURL );
+
+protected:
+ // XDispatch
+ virtual void SAL_CALL dispatch( const css::util::URL& URL,
+ const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+
+ virtual void fireStatusEvent( const OUString& rURL,
+ const css::uno::Reference< css::frame::XStatusListener >& xSingleListener ) override;
+
+ // state of a feature
+ virtual FeatureState getState( const OUString& rCommand ) = 0;
+
+ // execute a feature
+ virtual void execute( const OUString& rCommand, const css::uno::Sequence< css::beans::PropertyValue>& rArgs ) = 0;
+
+ // all the features which should be handled by this class
+ virtual void describeSupportedFeatures() = 0;
+
+ /** describes a feature supported by the controller
+
+ Must not be called outside <member>describeSupportedFeatures</member>.
+
+ @param pAsciiCommandURL
+ the URL of the feature command
+ @param nId
+ the id of the feature. Later references to this feature usually happen by id, not by
+ URL.
+ @param nGroup
+ the command group of the feature. This is important for configuring the controller UI
+ by the user, see also <type scope="css::frame">CommandGroup</type>.
+ */
+ void implDescribeSupportedFeature( const char* pAsciiCommandURL, ChartCommandID nId,
+ sal_Int16 nGroup );
+
+ mutable SupportedFeatures m_aSupportedFeatures;
+
+ ChartCommandID m_nFeatureId;
+};
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ObjectHierarchy.cxx b/chart2/source/controller/main/ObjectHierarchy.cxx
new file mode 100644
index 0000000000..44846850dc
--- /dev/null
+++ b/chart2/source/controller/main/ObjectHierarchy.cxx
@@ -0,0 +1,727 @@
+/* -*- 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 <ObjectHierarchy.hxx>
+#include <ObjectIdentifier.hxx>
+#include <ChartModelHelper.hxx>
+#include <DiagramHelper.hxx>
+#include <Diagram.hxx>
+#include <RegressionCurveHelper.hxx>
+#include <RegressionCurveModel.hxx>
+#include <Axis.hxx>
+#include <AxisHelper.hxx>
+#include <chartview/ExplicitValueProvider.hxx>
+#include <ChartType.hxx>
+#include <ChartTypeHelper.hxx>
+#include <ChartModel.hxx>
+#include <DataSeries.hxx>
+#include <DataSeriesHelper.hxx>
+#include <GridProperties.hxx>
+#include <LegendHelper.hxx>
+#include <chartview/DrawModelWrapper.hxx>
+#include <unonames.hxx>
+#include <BaseCoordinateSystem.hxx>
+
+#include <map>
+#include <algorithm>
+#include <cstddef>
+
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/chart/ErrorBarStyle.hpp>
+
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/awt/Key.hpp>
+#include <com/sun/star/awt/KeyModifier.hpp>
+#include <utility>
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::chart2;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace
+{
+
+void lcl_getChildOIDs(
+ ::chart::ObjectHierarchy::tChildContainer& rOutChildren,
+ const Reference< container::XIndexAccess >& xShapes )
+{
+ if( !xShapes.is())
+ return;
+
+ sal_Int32 nCount = xShapes->getCount();
+ for( sal_Int32 i=0; i<nCount; ++i)
+ {
+ Reference< beans::XPropertySet > xShapeProp( xShapes->getByIndex( i ), uno::UNO_QUERY );
+ if( xShapeProp.is())
+ {
+ Reference< beans::XPropertySetInfo > xInfo( xShapeProp->getPropertySetInfo());
+ OUString aName;
+ if( xInfo.is() &&
+ xInfo->hasPropertyByName( "Name") &&
+ (xShapeProp->getPropertyValue( "Name") >>= aName ) &&
+ !aName.isEmpty() &&
+ ::chart::ObjectIdentifier::isCID( aName ))
+ {
+ rOutChildren.emplace_back( aName );
+ }
+ Reference< container::XIndexAccess > xNewShapes( xShapeProp, uno::UNO_QUERY );
+ if( xNewShapes.is())
+ lcl_getChildOIDs( rOutChildren, xNewShapes );
+ }
+ }
+}
+
+void lcl_addAxisTitle( const rtl::Reference< ::chart::Axis >& xAxis, ::chart::ObjectHierarchy::tChildContainer& rContainer, const rtl::Reference<::chart::ChartModel>& xChartModel )
+{
+ if( xAxis.is())
+ {
+ Reference< XTitle > xAxisTitle( xAxis->getTitleObject());
+ if( xAxisTitle.is())
+ rContainer.emplace_back( ::chart::ObjectIdentifier::createClassifiedIdentifierForObject( xAxisTitle, xChartModel ) );
+ }
+}
+
+} // anonymous namespace
+
+namespace chart
+{
+
+void ObjectHierarchy::createTree( const rtl::Reference<::chart::ChartModel>& xChartDocument )
+{
+ m_aChildMap.clear();
+
+ if( !xChartDocument.is() )
+ return;
+
+ //@todo: change ObjectIdentifier to take an XChartDocument rather than XModel
+ rtl::Reference< Diagram > xDiagram = xChartDocument->getFirstChartDiagram();
+ ObjectIdentifier aDiaOID;
+ if( xDiagram.is() )
+ aDiaOID = ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( static_cast<cppu::OWeakObject*>(xDiagram.get()), xChartDocument ) );
+ tChildContainer aTopLevelContainer;
+
+ // First Level
+
+ // Chart Area
+ if( m_bOrderingForElementSelector )
+ {
+ aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) );
+ if( xDiagram.is() )
+ {
+ aTopLevelContainer.push_back( aDiaOID );
+ createWallAndFloor( aTopLevelContainer, xDiagram );
+ createLegendTree( aTopLevelContainer, xChartDocument, xDiagram );
+ }
+ }
+
+ // Main Title
+ Reference< XTitle > xMainTitle( xChartDocument->getTitleObject());
+ if( xMainTitle.is())
+ aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForObject( xMainTitle, xChartDocument ) );
+
+ if( xDiagram.is())
+ {
+ // Sub Title. Note: This is interpreted of being top level
+ Reference< XTitle > xSubTitle( xDiagram->getTitleObject());
+ if( xSubTitle.is())
+ aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForObject( xSubTitle, xChartDocument ) );
+
+ if( !m_bOrderingForElementSelector )
+ {
+ // Axis Titles. Note: These are interpreted of being top level
+ const std::vector< rtl::Reference< Axis > > aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram );
+ for( rtl::Reference< Axis > const & axis : aAxes )
+ lcl_addAxisTitle( axis, aTopLevelContainer, xChartDocument );
+
+ // Diagram
+ aTopLevelContainer.push_back( aDiaOID );
+ }
+
+ if( m_bFlattenDiagram )
+ createDiagramTree( aTopLevelContainer, xChartDocument, xDiagram );
+ else
+ {
+ tChildContainer aSubContainer;
+ createDiagramTree( aSubContainer, xChartDocument, xDiagram );
+ if( !aSubContainer.empty() )
+ m_aChildMap[ aDiaOID ] = aSubContainer;
+ }
+
+ if( !m_bOrderingForElementSelector )
+ createLegendTree( aTopLevelContainer, xChartDocument, xDiagram );
+ }
+
+ // #i12587# support for shapes in chart
+ if ( !m_bOrderingForElementSelector )
+ {
+ createAdditionalShapesTree( aTopLevelContainer );
+ }
+
+ // Chart Area
+ if( !m_bOrderingForElementSelector )
+ aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) );
+
+ if( ! aTopLevelContainer.empty())
+ m_aChildMap[ObjectHierarchy::getRootNodeOID()] = aTopLevelContainer;
+}
+
+void ObjectHierarchy::createLegendTree(
+ tChildContainer & rContainer,
+ const rtl::Reference<::chart::ChartModel> & xChartDoc,
+ const rtl::Reference< Diagram > & xDiagram )
+{
+ if( !(xDiagram.is() && LegendHelper::hasLegend( xDiagram )) )
+ return;
+
+ ObjectIdentifier aLegendOID( ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xDiagram->getLegend(), xChartDoc ) ) );
+ rContainer.push_back( aLegendOID );
+
+ // iterate over child shapes of legend and search for matching CIDs
+ if( m_pExplicitValueProvider )
+ {
+ rtl::Reference< SvxShapeGroupAnyD > xLegendShapeContainer =
+ dynamic_cast<SvxShapeGroupAnyD*>(
+ m_pExplicitValueProvider->getShapeForCID( aLegendOID.getObjectCID() ).get() );
+ tChildContainer aLegendEntryOIDs;
+ lcl_getChildOIDs( aLegendEntryOIDs, xLegendShapeContainer );
+
+ m_aChildMap[ aLegendOID ] = aLegendEntryOIDs;
+ }
+}
+
+void ObjectHierarchy::createAxesTree(
+ tChildContainer & rContainer,
+ const rtl::Reference<::chart::ChartModel> & xChartDoc,
+ const rtl::Reference< Diagram > & xDiagram )
+{
+ sal_Int32 nDimensionCount = xDiagram->getDimension();
+ rtl::Reference< ChartType > xChartType( xDiagram->getChartTypeByIndex( 0 ) );
+ bool bSupportsAxesGrids = ChartTypeHelper::isSupportingMainAxis( xChartType, nDimensionCount, 0 );
+ if( !bSupportsAxesGrids )
+ return;
+
+ // Data Table
+ uno::Reference<chart2::XDataTable> xDataTable = xDiagram->getDataTable();
+ if (xDataTable.is())
+ {
+ rContainer.push_back(ObjectIdentifier::createClassifiedIdentifierForObject(xDataTable, xChartDoc));
+ }
+
+ // Axes
+ std::vector< rtl::Reference< Axis > > aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram, /* bOnlyVisible = */ true );
+ if( !m_bOrderingForElementSelector )
+ {
+ for (const auto & rAxis : std::as_const(aAxes))
+ rContainer.push_back( ObjectIdentifier::createClassifiedIdentifierForObject( rAxis, xChartDoc ) );
+ }
+
+ // get all axes, also invisible ones
+ aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram );
+ // Grids
+ for( rtl::Reference< Axis > const & xAxis : aAxes )
+ {
+ if(!xAxis.is())
+ continue;
+
+ sal_Int32 nCooSysIndex = 0;
+ sal_Int32 nDimensionIndex = 0;
+ sal_Int32 nAxisIndex = 0;
+ AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex );
+ if( nAxisIndex>0 && !ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount ) )
+ continue;
+
+ if( m_bOrderingForElementSelector )
+ {
+ // axis
+ if( AxisHelper::isAxisVisible( xAxis ) )
+ rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForObject( xAxis, xChartDoc ) );
+
+ // axis title
+ lcl_addAxisTitle( xAxis, rContainer, xChartDoc );
+ }
+
+ rtl::Reference< ::chart::GridProperties > xGridProperties( xAxis->getGridProperties2() );
+ if( AxisHelper::isGridVisible( xGridProperties ) )
+ {
+ //main grid
+ rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartDoc ) );
+ }
+
+ std::vector< rtl::Reference< ::chart::GridProperties > > aSubGrids( xAxis->getSubGridProperties2() );
+ for( size_t nSubGrid = 0; nSubGrid < aSubGrids.size(); ++nSubGrid )
+ {
+ if( AxisHelper::isGridVisible( aSubGrids[nSubGrid] ) )
+ {
+ //sub grid
+ rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartDoc, nSubGrid ) );
+ }
+ }
+ }
+}
+
+void ObjectHierarchy::createWallAndFloor(
+ tChildContainer & rContainer,
+ const rtl::Reference< Diagram > & xDiagram )
+{
+ sal_Int32 nDimensionCount = xDiagram->getDimension();
+ bool bIsThreeD = ( nDimensionCount == 3 );
+ bool bHasWall = xDiagram->isSupportingFloorAndWall();
+ if( bHasWall && bIsThreeD )
+ {
+ rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) );
+
+ Reference< beans::XPropertySet > xFloor( xDiagram->getFloor());
+ if( xFloor.is())
+ rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_FLOOR, u"" ) );
+ }
+
+}
+
+void ObjectHierarchy::createDiagramTree(
+ tChildContainer & rContainer,
+ const rtl::Reference<::chart::ChartModel> & xChartDoc,
+ const rtl::Reference< Diagram > & xDiagram )
+{
+ if( !m_bOrderingForElementSelector )
+ {
+ createDataSeriesTree( rContainer, xDiagram );
+ createAxesTree( rContainer, xChartDoc, xDiagram );
+ createWallAndFloor( rContainer, xDiagram );
+ }
+ else
+ {
+ createAxesTree( rContainer, xChartDoc, xDiagram );
+ createDataSeriesTree( rContainer, xDiagram );
+ }
+}
+
+void ObjectHierarchy::createDataSeriesTree(
+ tChildContainer & rOutDiagramSubContainer,
+ const rtl::Reference< Diagram > & xDiagram )
+{
+ try
+ {
+ sal_Int32 nDimensionCount = xDiagram->getDimension();
+ std::vector< rtl::Reference< BaseCoordinateSystem > > aCooSysSeq(
+ xDiagram->getBaseCoordinateSystems());
+ for( std::size_t nCooSysIdx=0; nCooSysIdx<aCooSysSeq.size(); ++nCooSysIdx )
+ {
+ std::vector< rtl::Reference< ChartType > > aChartTypeSeq( aCooSysSeq[nCooSysIdx]->getChartTypes2());
+ for( std::size_t nCTIdx=0; nCTIdx<aChartTypeSeq.size(); ++nCTIdx )
+ {
+ rtl::Reference< ChartType > xChartType( aChartTypeSeq[nCTIdx] );
+ std::vector< rtl::Reference< DataSeries > > aSeriesSeq( xChartType->getDataSeries2() );
+ const sal_Int32 nNumberOfSeries =
+ ChartTypeHelper::getNumberOfDisplayedSeries( xChartType, aSeriesSeq.size());
+
+ for( sal_Int32 nSeriesIdx=0; nSeriesIdx<nNumberOfSeries; ++nSeriesIdx )
+ {
+ OUString aSeriesParticle(
+ ObjectIdentifier::createParticleForSeries(
+ 0, nCooSysIdx, nCTIdx, nSeriesIdx ));
+ ObjectIdentifier aSeriesOID(
+ ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForParticle( aSeriesParticle ) ) );
+ rOutDiagramSubContainer.push_back( aSeriesOID );
+
+ tChildContainer aSeriesSubContainer;
+
+ rtl::Reference< DataSeries > const & xSeries = aSeriesSeq[nSeriesIdx];
+
+ // data labels
+ if( DataSeriesHelper::hasDataLabelsAtSeries( xSeries ) )
+ {
+ OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) + "=" );
+ aSeriesSubContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForParticles( aSeriesParticle, aChildParticle ) );
+ }
+
+ // Statistics
+ if( ChartTypeHelper::isSupportingStatisticProperties( xChartType, nDimensionCount ) )
+ {
+ const std::vector< rtl::Reference< RegressionCurveModel > > & rCurves( xSeries->getRegressionCurves2());
+ for( size_t nCurveIdx=0; nCurveIdx<rCurves.size(); ++nCurveIdx )
+ {
+ bool bIsAverageLine = RegressionCurveHelper::isMeanValueLine( rCurves[nCurveIdx] );
+ aSeriesSubContainer.emplace_back( ObjectIdentifier::createDataCurveCID( aSeriesParticle, nCurveIdx, bIsAverageLine ) );
+ if( RegressionCurveHelper::hasEquation( rCurves[nCurveIdx] ) )
+ {
+ aSeriesSubContainer.emplace_back( ObjectIdentifier::createDataCurveEquationCID( aSeriesParticle, nCurveIdx ) );
+ }
+ }
+ Reference< beans::XPropertySet > xErrorBarProp;
+ if( (xSeries->getPropertyValue( CHART_UNONAME_ERRORBAR_Y) >>= xErrorBarProp) &&
+ xErrorBarProp.is())
+ {
+ sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE;
+ if( ( xErrorBarProp->getPropertyValue( "ErrorBarStyle") >>= nStyle ) &&
+ ( nStyle != css::chart::ErrorBarStyle::NONE ) )
+ {
+ aSeriesSubContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierWithParent(
+ OBJECTTYPE_DATA_ERRORS_Y, u"", aSeriesParticle ) );
+ }
+ }
+
+ if( (xSeries->getPropertyValue(CHART_UNONAME_ERRORBAR_X) >>= xErrorBarProp) &&
+ xErrorBarProp.is())
+ {
+ sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE;
+ if( ( xErrorBarProp->getPropertyValue( "ErrorBarStyle") >>= nStyle ) &&
+ ( nStyle != css::chart::ErrorBarStyle::NONE ) )
+ {
+ aSeriesSubContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierWithParent(
+ OBJECTTYPE_DATA_ERRORS_X, u"", aSeriesParticle ) );
+ }
+ }
+ }
+
+ // Data Points
+ // iterate over child shapes of legend and search for matching CIDs
+ if( m_pExplicitValueProvider )
+ {
+ rtl::Reference< SvxShapeGroupAnyD > xSeriesShapeContainer =
+ dynamic_cast<SvxShapeGroupAnyD*>(
+ m_pExplicitValueProvider->getShapeForCID( aSeriesOID.getObjectCID() ).get() );
+ lcl_getChildOIDs( aSeriesSubContainer, xSeriesShapeContainer );
+ }
+
+ if( ! aSeriesSubContainer.empty())
+ m_aChildMap[ aSeriesOID ] = aSeriesSubContainer;
+ }
+ }
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+}
+
+void ObjectHierarchy::createAdditionalShapesTree(tChildContainer& rContainer)
+{
+ try
+ {
+ if ( m_pExplicitValueProvider )
+ {
+ rtl::Reference<SvxDrawPage> xDrawPage( m_pExplicitValueProvider->getDrawModelWrapper()->getMainDrawPage() );
+ Reference< drawing::XShapes > xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) );
+ sal_Int32 nCount = xDrawPage->getCount();
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ Reference< drawing::XShape > xShape;
+ if ( xDrawPage->getByIndex( i ) >>= xShape )
+ {
+ if ( xShape.is() && xShape != xChartRoot )
+ {
+ rContainer.emplace_back( xShape );
+ }
+ }
+ }
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+}
+
+bool ObjectHierarchy::hasChildren( const ObjectIdentifier& rParent ) const
+{
+ if ( rParent.isValid() )
+ {
+ tChildMap::const_iterator aIt( m_aChildMap.find( rParent ));
+ if( aIt != m_aChildMap.end())
+ return ! (aIt->second.empty());
+ }
+ return false;
+}
+
+const ObjectHierarchy::tChildContainer & ObjectHierarchy::getChildren( const ObjectIdentifier& rParent ) const
+{
+ if ( rParent.isValid() )
+ {
+ tChildMap::const_iterator aIt( m_aChildMap.find( rParent ));
+ if( aIt != m_aChildMap.end())
+ return aIt->second;
+ }
+ static const tChildContainer EMPTY;
+ return EMPTY;
+}
+
+const ObjectHierarchy::tChildContainer & ObjectHierarchy::getSiblings( const ObjectIdentifier& rNode ) const
+{
+ if ( rNode.isValid() && !ObjectHierarchy::isRootNode( rNode ) )
+ {
+ for (auto const& child : m_aChildMap)
+ {
+ tChildContainer::const_iterator aElemIt(
+ std::find( child.second.begin(), child.second.end(), rNode ));
+ if( aElemIt != child.second.end())
+ return child.second;
+ }
+ }
+ static const tChildContainer EMPTY;
+ return EMPTY;
+}
+
+ObjectIdentifier ObjectHierarchy::getParentImpl(
+ const ObjectIdentifier & rParentOID,
+ const ObjectIdentifier & rOID ) const
+{
+ // search children
+ tChildContainer aChildren( getChildren( rParentOID ));
+ tChildContainer::const_iterator aIt(
+ std::find( aChildren.begin(), aChildren.end(), rOID ));
+ // recursion end
+ if( aIt != aChildren.end())
+ return rParentOID;
+
+ for (auto const& child : aChildren)
+ {
+ // recursion
+ ObjectIdentifier aTempParent( getParentImpl( child, rOID ));
+ if ( aTempParent.isValid() )
+ {
+ // exit on success
+ return aTempParent;
+ }
+ }
+
+ // exit on fail
+ return ObjectIdentifier();
+}
+
+ObjectIdentifier ObjectHierarchy::getParent(
+ const ObjectIdentifier & rOID ) const
+{
+ return getParentImpl( ObjectHierarchy::getRootNodeOID(), rOID );
+}
+
+ObjectHierarchy::ObjectHierarchy(
+ const rtl::Reference<::chart::ChartModel> & xChartDocument,
+ ExplicitValueProvider * pExplicitValueProvider /* = 0 */,
+ bool bFlattenDiagram /* = false */,
+ bool bOrderingForElementSelector /* = false */) :
+ m_pExplicitValueProvider( pExplicitValueProvider ),
+ m_bFlattenDiagram( bFlattenDiagram ),
+ m_bOrderingForElementSelector( bOrderingForElementSelector )
+{
+ createTree( xChartDocument );
+ // don't remember this helper to avoid access after lifetime
+ m_pExplicitValueProvider = nullptr;
+}
+
+ObjectHierarchy::~ObjectHierarchy()
+{}
+
+ObjectIdentifier ObjectHierarchy::getRootNodeOID()
+{
+ return ObjectIdentifier( "ROOT" );
+}
+
+bool ObjectHierarchy::isRootNode( const ObjectIdentifier& rOID )
+{
+ return ( rOID == ObjectHierarchy::getRootNodeOID() );
+}
+
+const ObjectHierarchy::tChildContainer & ObjectHierarchy::getTopLevelChildren() const
+{
+ return getChildren( ObjectHierarchy::getRootNodeOID());
+}
+
+sal_Int32 ObjectHierarchy::getIndexInParent(
+ const ObjectIdentifier& rNode ) const
+{
+ ObjectIdentifier aParentOID( getParent( rNode ));
+ const tChildContainer & aChildren( getChildren( aParentOID ) );
+ sal_Int32 nIndex = 0;
+ for (auto const& child : aChildren)
+ {
+ if ( child == rNode )
+ return nIndex;
+ ++nIndex;
+ }
+ return -1;
+}
+
+ObjectKeyNavigation::ObjectKeyNavigation(
+ ObjectIdentifier aCurrentOID,
+ rtl::Reference<::chart::ChartModel> xChartDocument,
+ ExplicitValueProvider * pExplicitValueProvider /* = 0 */ ) :
+ m_aCurrentOID(std::move( aCurrentOID )),
+ m_xChartDocument(std::move( xChartDocument )),
+ m_pExplicitValueProvider( pExplicitValueProvider )
+{
+ if ( !m_aCurrentOID.isValid() )
+ {
+ setCurrentSelection( ObjectHierarchy::getRootNodeOID() );
+ }
+}
+
+bool ObjectKeyNavigation::handleKeyEvent(
+ const awt::KeyEvent & rEvent )
+{
+ bool bResult = false;
+
+ switch( rEvent.KeyCode )
+ {
+ case awt::Key::TAB:
+ if( rEvent.Modifiers & awt::KeyModifier::SHIFT )
+ bResult = previous();
+ else
+ bResult = next();
+ break;
+ case awt::Key::HOME:
+ bResult = first();
+ break;
+ case awt::Key::END:
+ bResult = last();
+ break;
+ case awt::Key::F3:
+ if( rEvent.Modifiers & awt::KeyModifier::SHIFT )
+ bResult = up();
+ else
+ bResult = down();
+ break;
+ case awt::Key::ESCAPE:
+ setCurrentSelection( ObjectIdentifier() );
+ bResult = true;
+ break;
+ default:
+ bResult = false;
+ break;
+ }
+ return bResult;
+}
+
+void ObjectKeyNavigation::setCurrentSelection( const ObjectIdentifier& rOID )
+{
+ m_aCurrentOID = rOID;
+}
+
+bool ObjectKeyNavigation::first()
+{
+ ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider );
+ ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) );
+ bool bResult = !aSiblings.empty();
+ if( bResult )
+ setCurrentSelection( aSiblings.front());
+ else
+ bResult = veryFirst();
+ return bResult;
+}
+
+bool ObjectKeyNavigation::last()
+{
+ ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider );
+ ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) );
+ bool bResult = !aSiblings.empty();
+ if( bResult )
+ setCurrentSelection( aSiblings.back());
+ else
+ bResult = veryLast();
+ return bResult;
+}
+
+bool ObjectKeyNavigation::next()
+{
+ ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider );
+ ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) );
+ bool bResult = !aSiblings.empty();
+ if( bResult )
+ {
+ ObjectHierarchy::tChildContainer::const_iterator aIt(
+ std::find( aSiblings.begin(), aSiblings.end(), getCurrentSelection()));
+ assert(aIt != aSiblings.end());
+ if( ++aIt == aSiblings.end())
+ aIt = aSiblings.begin();
+ setCurrentSelection( *aIt );
+ }
+ else
+ bResult = veryFirst();
+
+ return bResult;
+}
+
+bool ObjectKeyNavigation::previous()
+{
+ ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider );
+ ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection()));
+ bool bResult = !aSiblings.empty();
+ if( bResult )
+ {
+ ObjectHierarchy::tChildContainer::const_iterator aIt(
+ std::find( aSiblings.begin(), aSiblings.end(), getCurrentSelection()));
+ OSL_ASSERT( aIt != aSiblings.end());
+ if( aIt == aSiblings.begin())
+ aIt = aSiblings.end();
+ --aIt;
+ setCurrentSelection( *aIt );
+ }
+ else
+ bResult = veryLast();
+ return bResult;
+}
+
+bool ObjectKeyNavigation::up()
+{
+ ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider );
+ bool bResult = !ObjectHierarchy::isRootNode( getCurrentSelection());
+ if( bResult )
+ setCurrentSelection( aHierarchy.getParent( getCurrentSelection()));
+ return bResult;
+}
+
+bool ObjectKeyNavigation::down()
+{
+ ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider );
+ bool bResult = aHierarchy.hasChildren( getCurrentSelection());
+ if( bResult )
+ {
+ ObjectHierarchy::tChildContainer aChildren = aHierarchy.getChildren( getCurrentSelection());
+ OSL_ASSERT( !aChildren.empty());
+ setCurrentSelection( aChildren.front());
+ }
+ return bResult;
+}
+
+bool ObjectKeyNavigation::veryFirst()
+{
+ ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider );
+ ObjectHierarchy::tChildContainer aChildren( aHierarchy.getTopLevelChildren());
+ bool bResult = !aChildren.empty();
+ if( bResult )
+ setCurrentSelection( aChildren.front());
+ return bResult;
+}
+
+bool ObjectKeyNavigation::veryLast()
+{
+ ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider );
+ ObjectHierarchy::tChildContainer aChildren( aHierarchy.getTopLevelChildren());
+ bool bResult = !aChildren.empty();
+ if( bResult )
+ setCurrentSelection( aChildren.back());
+ return bResult;
+}
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/PositionAndSizeHelper.cxx b/chart2/source/controller/main/PositionAndSizeHelper.cxx
new file mode 100644
index 0000000000..50678d145b
--- /dev/null
+++ b/chart2/source/controller/main/PositionAndSizeHelper.cxx
@@ -0,0 +1,179 @@
+/* -*- 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 <PositionAndSizeHelper.hxx>
+#include <ControllerLockGuard.hxx>
+#include <com/sun/star/chart/ChartLegendExpansion.hpp>
+#include <com/sun/star/chart2/RelativePosition.hpp>
+#include <com/sun/star/chart2/RelativeSize.hpp>
+#include <tools/gen.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <ChartModel.hxx>
+#include <Diagram.hxx>
+
+namespace chart
+{
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::chart2;
+
+bool PositionAndSizeHelper::moveObject( ObjectType eObjectType
+ , const uno::Reference< beans::XPropertySet >& xObjectProp
+ , const awt::Rectangle& rNewPositionAndSize
+ , const awt::Rectangle& rOldPositionAndSize
+ , const awt::Rectangle& rPageRectangle
+ )
+{
+ if(!xObjectProp.is())
+ return false;
+ tools::Rectangle aObjectRect( Point(rNewPositionAndSize.X,rNewPositionAndSize.Y), Size(rNewPositionAndSize.Width,rNewPositionAndSize.Height) );
+ tools::Rectangle aPageRect( Point(rPageRectangle.X,rPageRectangle.Y), Size(rPageRectangle.Width,rPageRectangle.Height) );
+
+ // every following branch divides by width and height
+ if (aPageRect.getOpenWidth() == 0 || aPageRect.getOpenHeight() == 0)
+ return false;
+
+ if( eObjectType==OBJECTTYPE_TITLE )
+ {
+ //@todo decide whether x is primary or secondary
+ chart2::RelativePosition aRelativePosition;
+ aRelativePosition.Anchor = drawing::Alignment_CENTER;
+ //the anchor point at the title object is top/middle
+ Point aPos = aObjectRect.TopLeft();
+ aRelativePosition.Primary = (double(aPos.X())+double(aObjectRect.getOpenWidth())/2.0)/double(aPageRect.getOpenWidth());
+ aRelativePosition.Secondary = (double(aPos.Y())+double(aObjectRect.getOpenHeight())/2.0)/double(aPageRect.getOpenHeight());
+ xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) );
+ }
+ else if( eObjectType == OBJECTTYPE_DATA_LABEL )
+ {
+ RelativePosition aAbsolutePosition;
+ RelativePosition aCustomLabelPosition;
+ aAbsolutePosition.Primary = double(rOldPositionAndSize.X) / double(aPageRect.getOpenWidth());
+ aAbsolutePosition.Secondary = double(rOldPositionAndSize.Y) / double(aPageRect.getOpenHeight());
+
+ if( xObjectProp->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition )
+ {
+ aAbsolutePosition.Primary -= aCustomLabelPosition.Primary;
+ aAbsolutePosition.Secondary -= aCustomLabelPosition.Secondary;
+ }
+
+ //the anchor point at the data label object is top/left
+ Point aPos = aObjectRect.TopLeft();
+ double fRotation = 0.0;
+ xObjectProp->getPropertyValue("TextRotation") >>= fRotation;
+ if( fRotation == 90.0 )
+ aPos = aObjectRect.BottomLeft();
+ else if( fRotation == 270.0 )
+ aPos = aObjectRect.TopRight();
+
+ aCustomLabelPosition.Primary = double(aPos.X()) / double(aPageRect.getOpenWidth()) - aAbsolutePosition.Primary;
+ aCustomLabelPosition.Secondary = double(aPos.Y()) / double(aPageRect.getOpenHeight()) - aAbsolutePosition.Secondary;
+ xObjectProp->setPropertyValue("CustomLabelPosition", uno::Any(aCustomLabelPosition));
+ }
+ else if( eObjectType==OBJECTTYPE_DATA_CURVE_EQUATION )
+ {
+ //@todo decide whether x is primary or secondary
+ chart2::RelativePosition aRelativePosition;
+ aRelativePosition.Anchor = drawing::Alignment_TOP_LEFT;
+ //the anchor point at the title object is top/middle
+ Point aPos = aObjectRect.TopLeft();
+ aRelativePosition.Primary = double(aPos.X())/double(aPageRect.getOpenWidth());
+ aRelativePosition.Secondary = double(aPos.Y())/double(aPageRect.getOpenHeight());
+ xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) );
+ }
+ else if(eObjectType==OBJECTTYPE_LEGEND)
+ {
+ xObjectProp->setPropertyValue( "Expansion", uno::Any(css::chart::ChartLegendExpansion_CUSTOM));
+ chart2::RelativePosition aRelativePosition;
+ chart2::RelativeSize aRelativeSize;
+ Point aAnchor = aObjectRect.TopLeft();
+
+ aRelativePosition.Primary =
+ static_cast< double >( aAnchor.X()) /
+ static_cast< double >( aPageRect.getOpenWidth() );
+ aRelativePosition.Secondary =
+ static_cast< double >( aAnchor.Y()) /
+ static_cast< double >( aPageRect.getOpenHeight());
+
+ xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) );
+
+ aRelativeSize.Primary =
+ static_cast< double >( aObjectRect.getOpenWidth()) /
+ static_cast< double >( aPageRect.getOpenWidth() );
+ if (aRelativeSize.Primary > 1.0)
+ aRelativeSize.Primary = 1.0;
+ aRelativeSize.Secondary =
+ static_cast< double >( aObjectRect.getOpenHeight()) /
+ static_cast< double >( aPageRect.getOpenHeight());
+ if (aRelativeSize.Secondary > 1.0)
+ aRelativeSize.Secondary = 1.0;
+
+ xObjectProp->setPropertyValue( "RelativeSize", uno::Any(aRelativeSize) );
+ }
+ else if(eObjectType==OBJECTTYPE_DIAGRAM || eObjectType==OBJECTTYPE_DIAGRAM_WALL || eObjectType==OBJECTTYPE_DIAGRAM_FLOOR)
+ {
+ //@todo decide whether x is primary or secondary
+
+ //set position:
+ chart2::RelativePosition aRelativePosition;
+ aRelativePosition.Anchor = drawing::Alignment_CENTER;
+
+ Point aPos = aObjectRect.Center();
+ aRelativePosition.Primary = double(aPos.X())/double(aPageRect.getOpenWidth());
+ aRelativePosition.Secondary = double(aPos.Y())/double(aPageRect.getOpenHeight());
+ xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) );
+
+ //set size:
+ RelativeSize aRelativeSize;
+ //the anchor points for the diagram are in the middle of the diagram
+ //and in the middle of the page
+ aRelativeSize.Primary = double(aObjectRect.getOpenWidth())/double(aPageRect.getOpenWidth());
+ aRelativeSize.Secondary = double(aObjectRect.getOpenHeight())/double(aPageRect.getOpenHeight());
+ xObjectProp->setPropertyValue( "RelativeSize", uno::Any(aRelativeSize) );
+ }
+ else
+ return false;
+ return true;
+}
+
+bool PositionAndSizeHelper::moveObject( std::u16string_view rObjectCID
+ , const rtl::Reference<::chart::ChartModel>& xChartModel
+ , const awt::Rectangle& rNewPositionAndSize
+ , const awt::Rectangle& rOldPositionAndSize
+ , const awt::Rectangle& rPageRectangle
+ )
+{
+ ControllerLockGuardUNO aLockedControllers( xChartModel );
+
+ awt::Rectangle aNewPositionAndSize( rNewPositionAndSize );
+
+ uno::Reference< beans::XPropertySet > xObjectProp = ObjectIdentifier::getObjectPropertySet( rObjectCID, xChartModel );
+ ObjectType eObjectType( ObjectIdentifier::getObjectType( rObjectCID ) );
+ if(eObjectType==OBJECTTYPE_DIAGRAM || eObjectType==OBJECTTYPE_DIAGRAM_WALL || eObjectType==OBJECTTYPE_DIAGRAM_FLOOR)
+ {
+ xObjectProp = ObjectIdentifier::getDiagramForCID( rObjectCID, xChartModel );
+ if(!xObjectProp.is())
+ return false;
+ }
+ return moveObject( eObjectType, xObjectProp, aNewPositionAndSize, rOldPositionAndSize, rPageRectangle );
+}
+
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/SelectionHelper.cxx b/chart2/source/controller/main/SelectionHelper.cxx
new file mode 100644
index 0000000000..11fc5d9fae
--- /dev/null
+++ b/chart2/source/controller/main/SelectionHelper.cxx
@@ -0,0 +1,651 @@
+/* -*- 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 <SelectionHelper.hxx>
+#include <ObjectIdentifier.hxx>
+#include <DiagramHelper.hxx>
+#include <Diagram.hxx>
+#include <ChartModelHelper.hxx>
+#include <ChartModel.hxx>
+
+#include <svx/svdpage.hxx>
+#include <svx/svditer.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/svdopath.hxx>
+#include <vcl/svapp.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <osl/diagnose.h>
+
+namespace chart
+{
+using namespace ::com::sun::star;
+
+namespace
+{
+
+OUString lcl_getObjectName( SdrObject const * pObj )
+{
+ if(pObj)
+ return pObj->GetName();
+ return OUString();
+}
+
+void impl_selectObject( SdrObject* pObjectToSelect, DrawViewWrapper& rDrawViewWrapper )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if(pObjectToSelect)
+ {
+ SelectionHelper aSelectionHelper( pObjectToSelect );
+ SdrObject* pMarkObj = aSelectionHelper.getObjectToMark();
+ rDrawViewWrapper.setMarkHandleProvider(&aSelectionHelper);
+ rDrawViewWrapper.MarkObject(pMarkObj);
+ rDrawViewWrapper.setMarkHandleProvider(nullptr);
+ }
+}
+
+}//anonymous namespace
+
+bool Selection::hasSelection() const
+{
+ return m_aSelectedOID.isValid();
+}
+
+OUString const & Selection::getSelectedCID() const
+{
+ return m_aSelectedOID.getObjectCID();
+}
+
+uno::Reference< drawing::XShape > const & Selection::getSelectedAdditionalShape() const
+{
+ return m_aSelectedOID.getAdditionalShape();
+}
+
+bool Selection::setSelection( const OUString& rCID )
+{
+ if ( rCID != m_aSelectedOID.getObjectCID() )
+ {
+ m_aSelectedOID = ObjectIdentifier( rCID );
+ return true;
+ }
+ return false;
+}
+
+bool Selection::setSelection( const uno::Reference< drawing::XShape >& xShape )
+{
+ if ( !( xShape == m_aSelectedOID.getAdditionalShape() ) )
+ {
+ clearSelection();
+ m_aSelectedOID = ObjectIdentifier( xShape );
+ return true;
+ }
+ return false;
+}
+
+void Selection::clearSelection()
+{
+ m_aSelectedOID = ObjectIdentifier();
+ m_aSelectedOID_beforeMouseDown = ObjectIdentifier();
+ m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
+}
+
+bool Selection::maybeSwitchSelectionAfterSingleClickWasEnsured()
+{
+ if ( m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid()
+ && m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing != m_aSelectedOID )
+ {
+ m_aSelectedOID = m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing;
+ m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
+ return true;
+ }
+ return false;
+}
+
+void Selection::resetPossibleSelectionAfterSingleClickWasEnsured()
+{
+ if ( m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid() )
+ {
+ m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
+ }
+}
+
+void Selection::remindSelectionBeforeMouseDown()
+{
+ m_aSelectedOID_beforeMouseDown = m_aSelectedOID;
+}
+
+bool Selection::isSelectionDifferentFromBeforeMouseDown() const
+{
+ return ( m_aSelectedOID != m_aSelectedOID_beforeMouseDown );
+}
+
+void Selection::applySelection( DrawViewWrapper* pDrawViewWrapper )
+{
+ if( !pDrawViewWrapper )
+ return;
+
+ {
+ SolarMutexGuard aSolarGuard;
+ pDrawViewWrapper->UnmarkAll();
+ }
+ SdrObject* pObjectToSelect = nullptr;
+ if ( m_aSelectedOID.isAutoGeneratedObject() )
+ {
+ pObjectToSelect = pDrawViewWrapper->getNamedSdrObject( m_aSelectedOID.getObjectCID() );
+ }
+ else if( m_aSelectedOID.isAdditionalShape() )
+ {
+ pObjectToSelect = DrawViewWrapper::getSdrObject( m_aSelectedOID.getAdditionalShape() );
+ }
+
+ impl_selectObject( pObjectToSelect, *pDrawViewWrapper );
+}
+
+void Selection::adaptSelectionToNewPos( const Point& rMousePos, DrawViewWrapper const * pDrawViewWrapper
+ , bool bIsRightMouse, bool bWaitingForDoubleClick )
+{
+ if( !pDrawViewWrapper )
+ return;
+
+ //do not toggle multiclick selection if right clicked on the selected object or waiting for double click
+ bool bAllowMultiClickSelectionChange = !bIsRightMouse && !bWaitingForDoubleClick;
+
+ ObjectIdentifier aLastSelectedObject( m_aSelectedOID );
+
+ SolarMutexGuard aSolarGuard;
+
+ //bAllowMultiClickSelectionChange==true -> a second click on the same object can lead to a changed selection (e.g. series -> single data point)
+
+ //get object to select:
+ {
+ m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
+
+ //the search for the object to select starts with the hit object deepest in the grouping hierarchy (a leaf in the tree)
+ //further we travel along the grouping hierarchy from child to parent
+ SdrObject* pNewObj = pDrawViewWrapper->getHitObject(rMousePos);
+ m_aSelectedOID = ObjectIdentifier( lcl_getObjectName( pNewObj ) );//name of pNewObj
+
+ //ignore handle only objects for hit test
+ while( pNewObj && m_aSelectedOID.getObjectCID().match( "HandlesOnly" ) )
+ {
+ pNewObj->SetMarkProtect(true);
+ pNewObj = pDrawViewWrapper->getHitObject(rMousePos);
+ m_aSelectedOID = ObjectIdentifier( lcl_getObjectName( pNewObj ) );
+ }
+
+ //accept only named objects while searching for the object to select
+ //this call may change m_aSelectedOID
+ if ( SelectionHelper::findNamedParent( pNewObj, m_aSelectedOID, true ) )
+ {
+ //if the so far found object is a multi click object further steps are necessary
+ while( ObjectIdentifier::isMultiClickObject( m_aSelectedOID.getObjectCID() ) )
+ {
+ bool bSameObjectAsLastSelected = ( aLastSelectedObject == m_aSelectedOID );
+ if( bSameObjectAsLastSelected )
+ {
+ //if the same child is clicked again don't go up further
+ break;
+ }
+ if ( ObjectIdentifier::areSiblings( aLastSelectedObject.getObjectCID(), m_aSelectedOID.getObjectCID() ) )
+ {
+ //if a sibling of the last selected object is clicked don't go up further
+ break;
+ }
+ ObjectIdentifier aLastChild = m_aSelectedOID;
+ if ( !SelectionHelper::findNamedParent( pNewObj, m_aSelectedOID, false ) )
+ {
+ //take the one found so far
+ break;
+ }
+ //if the last selected object is found don't go up further
+ //but take the last child if selection change is allowed
+ if ( aLastSelectedObject == m_aSelectedOID )
+ {
+ if( bAllowMultiClickSelectionChange )
+ {
+ m_aSelectedOID = aLastChild;
+ }
+ else
+ m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = aLastChild;
+ break;
+ }
+ }
+
+ OSL_ENSURE(m_aSelectedOID.isValid(), "somehow lost selected object");
+ }
+ else
+ {
+ //maybe an additional shape was hit
+ if ( pNewObj )
+ {
+ m_aSelectedOID = ObjectIdentifier( uno::Reference< drawing::XShape >( pNewObj->getUnoShape(), uno::UNO_QUERY ) );
+ }
+ else
+ {
+ m_aSelectedOID = ObjectIdentifier();
+ }
+ }
+
+ if ( !m_aSelectedOID.isAdditionalShape() )
+ {
+ OUString aPageCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) );//@todo read CID from model
+
+ if ( !m_aSelectedOID.isAutoGeneratedObject() )
+ {
+ m_aSelectedOID = ObjectIdentifier( aPageCID );
+ }
+
+ //check whether the diagram was hit but not selected (e.g. because it has no filling):
+ OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) );
+ OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) );//@todo read CID from model
+ bool bBackGroundHit = m_aSelectedOID.getObjectCID() == aPageCID || m_aSelectedOID.getObjectCID() == aWallCID || !m_aSelectedOID.isAutoGeneratedObject();
+ if( bBackGroundHit )
+ {
+ //todo: if more than one diagram is available in future do check the list of all diagrams here
+ SdrObject* pDiagram = pDrawViewWrapper->getNamedSdrObject( aDiagramCID );
+ if( pDiagram )
+ {
+ if( DrawViewWrapper::IsObjectHit( pDiagram, rMousePos ) )
+ {
+ m_aSelectedOID = ObjectIdentifier( aDiagramCID );
+ }
+ }
+ }
+ //check whether the legend was hit but not selected (e.g. because it has no filling):
+ if( bBackGroundHit || m_aSelectedOID.getObjectCID() == aDiagramCID )
+ {
+ OUString aLegendCID( ObjectIdentifier::createClassifiedIdentifierForParticle( ObjectIdentifier::createParticleForLegend(nullptr) ) );//@todo read CID from model
+ SdrObject* pLegend = pDrawViewWrapper->getNamedSdrObject( aLegendCID );
+ if( pLegend )
+ {
+ if( DrawViewWrapper::IsObjectHit( pLegend, rMousePos ) )
+ {
+ m_aSelectedOID = ObjectIdentifier( aLegendCID );
+ }
+ }
+ }
+ }
+ }
+
+ if ( bIsRightMouse && m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid() )
+ {
+ m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
+ }
+}
+
+bool Selection::isResizeableObjectSelected() const
+{
+ ObjectType eObjectType = m_aSelectedOID.getObjectType();
+ switch( eObjectType )
+ {
+ case OBJECTTYPE_DIAGRAM:
+ case OBJECTTYPE_DIAGRAM_WALL:
+ case OBJECTTYPE_SHAPE:
+ case OBJECTTYPE_LEGEND:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Selection::isRotateableObjectSelected( const rtl::Reference<::chart::ChartModel>& xChartModel ) const
+{
+ return SelectionHelper::isRotateableObject( m_aSelectedOID.getObjectCID(), xChartModel );
+}
+
+bool Selection::isDragableObjectSelected() const
+{
+ return m_aSelectedOID.isDragableObject();
+}
+
+bool Selection::isAdditionalShapeSelected() const
+{
+ return m_aSelectedOID.isAdditionalShape();
+}
+
+bool SelectionHelper::findNamedParent( SdrObject*& pInOutObject
+ , OUString& rOutName
+ , bool bGivenObjectMayBeResult )
+{
+ SolarMutexGuard aSolarGuard;
+ //find the deepest named group
+ SdrObject* pObj = pInOutObject;
+ OUString aName;
+ if( bGivenObjectMayBeResult )
+ aName = lcl_getObjectName( pObj );
+
+ while( pObj && !ObjectIdentifier::isCID( aName ) )
+ {
+ SdrObjList* pObjList = pObj->getParentSdrObjListFromSdrObject();
+ if( !pObjList )
+ return false;
+ SdrObject* pOwner = pObjList->getSdrObjectFromSdrObjList();
+ if( !pOwner )
+ return false;
+ pObj = pOwner;
+ aName = lcl_getObjectName( pObj );
+ }
+
+ if(!pObj)
+ return false;
+ if(aName.isEmpty())
+ return false;
+
+ pInOutObject = pObj;
+ rOutName = aName;
+ return true;
+}
+
+bool SelectionHelper::findNamedParent( SdrObject*& pInOutObject
+ , ObjectIdentifier& rOutObject
+ , bool bGivenObjectMayBeResult )
+{
+ OUString aName;
+ if ( findNamedParent( pInOutObject, aName, bGivenObjectMayBeResult ) )
+ {
+ rOutObject = ObjectIdentifier( aName );
+ return true;
+ }
+ return false;
+}
+
+bool SelectionHelper::isDragableObjectHitTwice( const Point& rMPos
+ , const OUString& rNameOfSelectedObject
+ , const DrawViewWrapper& rDrawViewWrapper )
+{
+ if(rNameOfSelectedObject.isEmpty())
+ return false;
+ if( !ObjectIdentifier::isDragableObject(rNameOfSelectedObject) )
+ return false;
+ SolarMutexGuard aSolarGuard;
+ SdrObject* pObj = rDrawViewWrapper.getNamedSdrObject( rNameOfSelectedObject );
+ return DrawViewWrapper::IsObjectHit( pObj, rMPos );
+}
+
+OUString SelectionHelper::getHitObjectCID(
+ const Point& rMPos,
+ DrawViewWrapper const & rDrawViewWrapper,
+ bool bGetDiagramInsteadOf_Wall )
+{
+ SolarMutexGuard aSolarGuard;
+ OUString aRet;
+
+ SdrObject* pNewObj = rDrawViewWrapper.getHitObject(rMPos);
+ aRet = lcl_getObjectName( pNewObj );//name of pNewObj
+
+ //ignore handle only objects for hit test
+ while( pNewObj && aRet.match("HandlesOnly") )
+ {
+ pNewObj->SetMarkProtect(true);
+ pNewObj = rDrawViewWrapper.getHitObject(rMPos);
+ aRet = lcl_getObjectName( pNewObj );
+ }
+
+ //accept only named objects while searching for the object to select
+ if( !findNamedParent( pNewObj, aRet, true ) )
+ {
+ aRet.clear();
+ }
+
+ OUString aPageCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) );//@todo read CID from model
+ //get page when nothing was hit
+ if( aRet.isEmpty() && !pNewObj )
+ {
+ aRet = aPageCID;
+ }
+
+ //get diagram instead wall or page if hit inside diagram
+ if( !aRet.isEmpty() )
+ {
+ if( aRet == aPageCID )
+ {
+ OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) );
+ //todo: if more than one diagram is available in future do check the list of all diagrams here
+ SdrObject* pDiagram = rDrawViewWrapper.getNamedSdrObject( aDiagramCID );
+ if( pDiagram )
+ {
+ if( DrawViewWrapper::IsObjectHit( pDiagram, rMPos ) )
+ {
+ aRet = aDiagramCID;
+ }
+ }
+ }
+ else if( bGetDiagramInsteadOf_Wall )
+ {
+ OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) );//@todo read CID from model
+
+ if( aRet == aWallCID )
+ {
+ OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) );
+ aRet = aDiagramCID;
+ }
+ }
+ }
+
+ return aRet;
+ // \\- solar mutex
+}
+
+bool SelectionHelper::isRotateableObject( std::u16string_view rCID
+ , const rtl::Reference<::chart::ChartModel>& xChartModel )
+{
+ if( !ObjectIdentifier::isRotateableObject( rCID ) )
+ return false;
+
+ sal_Int32 nDimensionCount = xChartModel->getFirstChartDiagram()->getDimension();
+
+ return nDimensionCount == 3;
+}
+
+SelectionHelper::SelectionHelper( SdrObject* pSelectedObj )
+ : m_pSelectedObj( pSelectedObj ), m_pMarkObj(nullptr)
+{
+
+}
+SelectionHelper::~SelectionHelper()
+{
+}
+
+bool SelectionHelper::getFrameDragSingles()
+{
+ //true == green == surrounding handles
+ return DynCastE3dObject( m_pSelectedObj) == nullptr;
+}
+
+SdrObject* SelectionHelper::getMarkHandlesObject( SdrObject* pObj )
+{
+ if(!pObj)
+ return nullptr;
+ OUString aName( lcl_getObjectName( pObj ) );
+ if( aName.match("MarkHandles") || aName.match("HandlesOnly") )
+ return pObj;
+ if( !aName.isEmpty() )//don't get the markhandles of a different object
+ return nullptr;
+
+ //search for a child with name "MarkHandles" or "HandlesOnly"
+ SolarMutexGuard aSolarGuard;
+ SdrObjList* pSubList = pObj->GetSubList();
+ if(pSubList)
+ {
+ SdrObjListIter aIterator(pSubList, SdrIterMode::Flat);
+ while (aIterator.IsMore())
+ {
+ SdrObject* pMarkHandles = SelectionHelper::getMarkHandlesObject( aIterator.Next() );
+ if( pMarkHandles )
+ return pMarkHandles;
+ }
+ }
+ return nullptr;
+}
+
+SdrObject* SelectionHelper::getObjectToMark()
+{
+ //return the selected object itself
+ //or a specific other object if that exists
+ SdrObject* pObj = m_pSelectedObj;
+ m_pMarkObj = pObj;
+
+ //search for a child with name "MarkHandles" or "HandlesOnly"
+ if(pObj)
+ {
+ SolarMutexGuard aSolarGuard;
+ SdrObjList* pSubList = pObj->GetSubList();
+ if(pSubList)
+ {
+ SdrObjListIter aIterator(pSubList, SdrIterMode::Flat);
+ while (aIterator.IsMore())
+ {
+ SdrObject* pMarkHandles = SelectionHelper::getMarkHandlesObject( aIterator.Next() );
+ if( pMarkHandles )
+ {
+ m_pMarkObj = pMarkHandles;
+ break;
+ }
+ }
+ }
+ }
+ return m_pMarkObj;
+}
+
+E3dScene* SelectionHelper::getSceneToRotate( SdrObject* pObj )
+{
+ //search whether the object or one of its children is a 3D object
+ //if so, return the accessory 3DScene
+
+ E3dObject* pRotateable = nullptr;
+
+ if(pObj)
+ {
+ pRotateable = DynCastE3dObject(pObj);
+ if( !pRotateable )
+ {
+ SolarMutexGuard aSolarGuard;
+ SdrObjList* pSubList = pObj->GetSubList();
+ if(pSubList)
+ {
+ SdrObjListIter aIterator(pSubList, SdrIterMode::DeepWithGroups);
+ while( aIterator.IsMore() && !pRotateable )
+ {
+ pRotateable = DynCastE3dObject(aIterator.Next());
+ }
+ }
+ }
+ }
+
+ E3dScene* pScene(nullptr);
+
+ if(pRotateable)
+ {
+ SolarMutexGuard aSolarGuard;
+ pScene = pRotateable->getRootE3dSceneFromE3dObject();
+ }
+
+ return pScene;
+}
+
+bool SelectionHelper::getMarkHandles( SdrHdlList& rHdlList )
+{
+ SolarMutexGuard aSolarGuard;
+
+ //@todo -> more flexible handle creation
+ //2 scenarios possible:
+ //1. add an additional invisible shape as a child to the selected object
+ //this child needs to be named somehow and handles need to be generated there from...
+ //or 2. offer a central service per view where renderer and so can register for handle creation for a special shape
+ //.. or 3. feature from drawinglayer to create handles for each shape... (bad performance... ?) ?
+
+ //scenario 1 is now used:
+ //if a child with name MarkHandles exists
+ //this child is marked instead of the logical selected object
+
+/*
+ //if a special mark object was found
+ //that object should be used for marking only
+ if( m_pMarkObj != m_pSelectedObj)
+ return false;
+*/
+ //if a special mark object was found
+ //that object should be used to create handles from
+ if( m_pMarkObj && m_pMarkObj != m_pSelectedObj)
+ {
+ rHdlList.Clear();
+ if( auto pPathObj = dynamic_cast<const SdrPathObj*>( m_pMarkObj) )
+ {
+ //if th object is a polygon
+ //from each point a handle is generated
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon = pPathObj->GetPathPoly();
+ for( sal_uInt32 nN = 0; nN < rPolyPolygon.count(); nN++)
+ {
+ const ::basegfx::B2DPolygon& aPolygon(rPolyPolygon.getB2DPolygon(nN));
+ for( sal_uInt32 nM = 0; nM < aPolygon.count(); nM++)
+ {
+ const ::basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(nM));
+ rHdlList.AddHdl(std::make_unique<SdrHdl>(Point(basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY())), SdrHdlKind::Poly));
+ }
+ }
+ return true;
+ }
+ else
+ return false; //use the special MarkObject for marking
+ }
+
+ //@todo:
+ //add and document good marking defaults ...
+
+ rHdlList.Clear();
+
+ SdrObject* pObj = m_pSelectedObj;
+ if(!pObj)
+ return false;
+ SdrObjList* pSubList = pObj->GetSubList();
+ if( !pSubList )//no group object !pObj->IsGroupObject()
+ return false;
+
+ OUString aName( lcl_getObjectName( pObj ) );
+ ObjectType eObjectType( ObjectIdentifier::getObjectType( aName ) );
+ if( eObjectType == OBJECTTYPE_DATA_POINT
+ || eObjectType == OBJECTTYPE_DATA_LABEL
+ || eObjectType == OBJECTTYPE_LEGEND_ENTRY
+ || eObjectType == OBJECTTYPE_AXIS_UNITLABEL )
+ {
+ return false;
+ }
+
+ SdrObjListIter aIterator(pSubList, SdrIterMode::Flat);
+
+ while (aIterator.IsMore())
+ {
+ SdrObject* pSubObj = aIterator.Next();
+ if( eObjectType == OBJECTTYPE_DATA_SERIES )
+ {
+ OUString aSubName( lcl_getObjectName( pSubObj ) );
+ ObjectType eSubObjectType( ObjectIdentifier::getObjectType( aSubName ) );
+ if( eSubObjectType!=OBJECTTYPE_DATA_POINT )
+ return false;
+ }
+
+ Point aPos = pSubObj->GetCurrentBoundRect().Center();
+ rHdlList.AddHdl(std::make_unique<SdrHdl>(aPos,SdrHdlKind::Poly));
+ }
+ return true;
+}
+
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ShapeController.cxx b/chart2/source/controller/main/ShapeController.cxx
new file mode 100644
index 0000000000..97715b07c2
--- /dev/null
+++ b/chart2/source/controller/main/ShapeController.cxx
@@ -0,0 +1,673 @@
+/* -*- 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 "ShapeController.hxx"
+#include <ChartController.hxx>
+#include <ViewElementListProvider.hxx>
+#include <dlg_ShapeFont.hxx>
+#include <dlg_ShapeParagraph.hxx>
+#include <ChartModel.hxx>
+#include <chartview/DrawModelWrapper.hxx>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/frame/CommandGroup.hpp>
+
+#include <vcl/svapp.hxx>
+#include <editeng/formatbreakitem.hxx>
+#include <editeng/editids.hrc>
+#include <editeng/eeitem.hxx>
+#include <editeng/hyphenzoneitem.hxx>
+#include <editeng/orphitem.hxx>
+#include <editeng/spltitem.hxx>
+#include <svx/svxdlg.hxx>
+#include <editeng/widwitem.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::frame;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace chart
+{
+
+ShapeController::ShapeController( const Reference< uno::XComponentContext >& rxContext,
+ ChartController* pController )
+ :FeatureCommandDispatchBase( rxContext )
+ ,m_pChartController( pController )
+{
+}
+
+ShapeController::~ShapeController()
+{
+}
+
+// WeakComponentImplHelperBase
+void ShapeController::disposing(std::unique_lock<std::mutex>& /*rGuard*/)
+{
+}
+
+// XEventListener
+void ShapeController::disposing( const lang::EventObject& /* Source */ )
+{
+}
+
+FeatureState ShapeController::getState( const OUString& rCommand )
+{
+ FeatureState aReturn;
+ aReturn.bEnabled = false;
+ aReturn.aState <<= false;
+
+ bool bWritable = false;
+ if ( m_pChartController )
+ {
+ rtl::Reference< ChartModel > xStorable = m_pChartController->getChartModel();
+ if ( xStorable.is() )
+ {
+ bWritable = !xStorable->isReadonly();
+ }
+ }
+
+ SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( rCommand );
+ if ( aIter != m_aSupportedFeatures.end() )
+ {
+ ChartCommandID nFeatureId = aIter->second.nFeatureId;
+ switch ( nFeatureId )
+ {
+ case ChartCommandID::ShapeFormatLine:
+ case ChartCommandID::ShapeFormatArea:
+ case ChartCommandID::ShapeTextAttributes:
+ case ChartCommandID::ShapeTransformDialog:
+ case ChartCommandID::ShapeObjectTitleDescription:
+ case ChartCommandID::ShapeRenameObject:
+ {
+ aReturn.bEnabled = bWritable;
+ aReturn.aState <<= false;
+ }
+ break;
+ case ChartCommandID::ShapeBringToFront:
+ case ChartCommandID::ShapeForward:
+ {
+ aReturn.bEnabled = ( bWritable && isForwardPossible() );
+ aReturn.aState <<= false;
+ }
+ break;
+ case ChartCommandID::ShapeBackward:
+ case ChartCommandID::ShapeSendToBack:
+ {
+
+ aReturn.bEnabled = ( bWritable && isBackwardPossible() );
+ aReturn.aState <<= false;
+ }
+ break;
+ case ChartCommandID::ShapeFontDialog:
+ case ChartCommandID::ShapeParagraphDialog:
+ {
+ aReturn.bEnabled = bWritable;
+ aReturn.aState <<= false;
+ }
+ break;
+ default:
+ {
+ aReturn.bEnabled = false;
+ aReturn.aState <<= false;
+ }
+ break;
+ }
+ }
+
+ return aReturn;
+}
+
+void ShapeController::execute( const OUString& rCommand, const Sequence< beans::PropertyValue>& )
+{
+ SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( rCommand );
+ if ( aIter == m_aSupportedFeatures.end() )
+ return;
+
+ ChartCommandID nFeatureId = aIter->second.nFeatureId;
+ switch ( nFeatureId )
+ {
+ case ChartCommandID::ShapeFormatLine:
+ {
+ executeDispatch_FormatLine();
+ }
+ break;
+ case ChartCommandID::ShapeFormatArea:
+ {
+ executeDispatch_FormatArea();
+ }
+ break;
+ case ChartCommandID::ShapeTextAttributes:
+ {
+ executeDispatch_TextAttributes();
+ }
+ break;
+ case ChartCommandID::ShapeTransformDialog:
+ {
+ executeDispatch_TransformDialog();
+ }
+ break;
+ case ChartCommandID::ShapeObjectTitleDescription:
+ {
+ executeDispatch_ObjectTitleDescription();
+ }
+ break;
+ case ChartCommandID::ShapeRenameObject:
+ {
+ executeDispatch_RenameObject();
+ }
+ break;
+ case ChartCommandID::ShapeBringToFront:
+ case ChartCommandID::ShapeForward:
+ case ChartCommandID::ShapeBackward:
+ case ChartCommandID::ShapeSendToBack:
+ {
+ executeDispatch_ChangeZOrder( nFeatureId );
+ }
+ break;
+ case ChartCommandID::ShapeFontDialog:
+ {
+ executeDispatch_FontDialog();
+ }
+ break;
+ case ChartCommandID::ShapeParagraphDialog:
+ {
+ executeDispatch_ParagraphDialog();
+ }
+ break;
+ default:
+ {
+ }
+ break;
+ }
+}
+
+void ShapeController::describeSupportedFeatures()
+{
+ implDescribeSupportedFeature( ".uno:FormatLine", ChartCommandID::ShapeFormatLine, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:FormatArea", ChartCommandID::ShapeFormatArea, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:TextAttributes", ChartCommandID::ShapeTextAttributes, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:TransformDialog", ChartCommandID::ShapeTransformDialog, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:ObjectTitleDescription", ChartCommandID::ShapeObjectTitleDescription, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:RenameObject", ChartCommandID::ShapeRenameObject, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:BringToFront", ChartCommandID::ShapeBringToFront, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:Forward", ChartCommandID::ShapeForward, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:Backward", ChartCommandID::ShapeBackward, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:SendToBack", ChartCommandID::ShapeSendToBack, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:FontDialog", ChartCommandID::ShapeFontDialog, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:ParagraphDialog", ChartCommandID::ShapeParagraphDialog, CommandGroup::EDIT );
+}
+
+IMPL_LINK( ShapeController, CheckNameHdl, AbstractSvxObjectNameDialog&, rDialog, bool )
+{
+ OUString aName;
+ rDialog.GetName( aName );
+
+ if ( !aName.isEmpty() )
+ {
+ DrawViewWrapper* pDrawViewWrapper = ( m_pChartController ? m_pChartController->GetDrawViewWrapper() : nullptr );
+ if ( pDrawViewWrapper && pDrawViewWrapper->getNamedSdrObject( aName ) )
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+void ShapeController::executeDispatch_FormatLine()
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pChartController )
+ return;
+
+ weld::Window* pChartWindow(m_pChartController->GetChartFrame());
+ DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper();
+ DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper();
+ if ( !(pChartWindow && pDrawModelWrapper && pDrawViewWrapper) )
+ return;
+
+ SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject();
+ SfxItemSet aAttr( pDrawViewWrapper->GetDefaultAttr() );
+ bool bHasMarked = pDrawViewWrapper->AreObjectsMarked();
+ if ( bHasMarked )
+ {
+ pDrawViewWrapper->MergeAttrFromMarked( aAttr, false );
+ }
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr< SfxAbstractTabDialog > pDlg(
+ pFact->CreateSvxLineTabDialog(pChartWindow, &aAttr, &pDrawModelWrapper->getSdrModel(),
+ pSelectedObj, bHasMarked));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet();
+ if ( bHasMarked )
+ {
+ pDrawViewWrapper->SetAttrToMarked( *pOutAttr, false );
+ }
+ else
+ {
+ pDrawViewWrapper->SetDefaultAttr( *pOutAttr, false );
+ }
+ }
+}
+
+void ShapeController::executeDispatch_FormatArea()
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pChartController )
+ return;
+
+ weld::Window* pChartWindow(m_pChartController->GetChartFrame());
+ DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper();
+ DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper();
+ if ( !(pChartWindow && pDrawModelWrapper && pDrawViewWrapper) )
+ return;
+
+ SfxItemSet aAttr( pDrawViewWrapper->GetDefaultAttr() );
+ bool bHasMarked = pDrawViewWrapper->AreObjectsMarked();
+ if ( bHasMarked )
+ {
+ pDrawViewWrapper->MergeAttrFromMarked( aAttr, false );
+ }
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr< AbstractSvxAreaTabDialog > pDlg(
+ pFact->CreateSvxAreaTabDialog(pChartWindow, &aAttr, &pDrawModelWrapper->getSdrModel(), true, false));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet();
+ if ( bHasMarked )
+ {
+ pDrawViewWrapper->SetAttrToMarked( *pOutAttr, false );
+ }
+ else
+ {
+ pDrawViewWrapper->SetDefaultAttr( *pOutAttr, false );
+ }
+ }
+}
+
+void ShapeController::executeDispatch_TextAttributes()
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pChartController )
+ return;
+
+ weld::Window* pChartWindow(m_pChartController->GetChartFrame());
+ DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper();
+ if ( !(pChartWindow && pDrawViewWrapper) )
+ return;
+
+ SfxItemSet aAttr( pDrawViewWrapper->GetDefaultAttr() );
+ bool bHasMarked = pDrawViewWrapper->AreObjectsMarked();
+ if ( bHasMarked )
+ {
+ pDrawViewWrapper->MergeAttrFromMarked( aAttr, false );
+ }
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr< SfxAbstractTabDialog > pDlg(
+ pFact->CreateTextTabDialog(pChartWindow, &aAttr, pDrawViewWrapper));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet();
+ if ( bHasMarked )
+ {
+ pDrawViewWrapper->SetAttributes( *pOutAttr );
+ }
+ else
+ {
+ pDrawViewWrapper->SetDefaultAttr( *pOutAttr, false );
+ }
+ }
+}
+
+void ShapeController::executeDispatch_TransformDialog()
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pChartController )
+ return;
+
+ weld::Window* pChartWindow(m_pChartController->GetChartFrame());
+ DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper();
+ if ( !(pChartWindow && pDrawViewWrapper) )
+ return;
+
+ SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject();
+ if ( pSelectedObj && pSelectedObj->GetObjIdentifier() == SdrObjKind::Caption )
+ {
+ // item set for caption
+ SfxItemSet aAttr(pDrawViewWrapper->GetModel().GetItemPool());
+ pDrawViewWrapper->GetAttributes( aAttr );
+ // item set for position and size
+ SfxItemSet aGeoAttr( pDrawViewWrapper->GetGeoAttrFromMarked() );
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr< SfxAbstractTabDialog > pDlg(
+ pFact->CreateCaptionDialog(pChartWindow, pDrawViewWrapper));
+ const WhichRangesContainer& pRange = pDlg->GetInputRanges( *aAttr.GetPool() );
+ SfxItemSet aCombAttr( *aAttr.GetPool(), pRange );
+ aCombAttr.Put( aAttr );
+ aCombAttr.Put( aGeoAttr );
+ pDlg->SetInputSet( &aCombAttr );
+ if ( pDlg->Execute() == RET_OK )
+ {
+ const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet();
+ pDrawViewWrapper->SetAttributes( *pOutAttr );
+ pDrawViewWrapper->SetGeoAttrToMarked( *pOutAttr );
+ }
+ }
+ else
+ {
+ SfxItemSet aGeoAttr( pDrawViewWrapper->GetGeoAttrFromMarked() );
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr< SfxAbstractTabDialog > pDlg(
+ pFact->CreateSvxTransformTabDialog(pChartWindow, &aGeoAttr, pDrawViewWrapper));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet();
+ pDrawViewWrapper->SetGeoAttrToMarked( *pOutAttr );
+ }
+ }
+}
+
+void ShapeController::executeDispatch_ObjectTitleDescription()
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pChartController )
+ return;
+
+ DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper();
+ if ( !(pDrawViewWrapper && pDrawViewWrapper->GetMarkedObjectCount() == 1) )
+ return;
+
+ SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject();
+ if ( !pSelectedObj )
+ return;
+
+ OUString aTitle( pSelectedObj->GetTitle() );
+ OUString aDescription( pSelectedObj->GetDescription() );
+ bool isDecorative(pSelectedObj->IsDecorative());
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ weld::Window* pChartWindow(m_pChartController->GetChartFrame());
+ ScopedVclPtr< AbstractSvxObjectTitleDescDialog > pDlg(
+ pFact->CreateSvxObjectTitleDescDialog(pChartWindow, aTitle, aDescription, isDecorative));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ pDlg->GetTitle( aTitle );
+ pDlg->GetDescription( aDescription );
+ pDlg->IsDecorative(isDecorative);
+ pSelectedObj->SetTitle( aTitle );
+ pSelectedObj->SetDescription( aDescription );
+ pSelectedObj->SetDecorative(isDecorative);
+ }
+}
+
+void ShapeController::executeDispatch_RenameObject()
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pChartController )
+ return;
+
+ DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper();
+ if ( !(pDrawViewWrapper && pDrawViewWrapper->GetMarkedObjectCount() == 1) )
+ return;
+
+ SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject();
+ if ( !pSelectedObj )
+ return;
+
+ OUString aName = pSelectedObj->GetName();
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ weld::Window* pChartWindow(m_pChartController->GetChartFrame());
+ ScopedVclPtr< AbstractSvxObjectNameDialog > pDlg(
+ pFact->CreateSvxObjectNameDialog(pChartWindow, aName));
+ pDlg->SetCheckNameHdl( LINK( this, ShapeController, CheckNameHdl ) );
+ if ( pDlg->Execute() == RET_OK )
+ {
+ pDlg->GetName(aName);
+ if (pSelectedObj->GetName() == aName)
+ {
+ pSelectedObj->SetName( aName );
+ }
+ }
+}
+
+void ShapeController::executeDispatch_ChangeZOrder( ChartCommandID nId )
+{
+ SolarMutexGuard aGuard;
+ DrawViewWrapper* pDrawViewWrapper = ( m_pChartController ? m_pChartController->GetDrawViewWrapper() : nullptr );
+ if ( !pDrawViewWrapper )
+ return;
+
+ switch ( nId )
+ {
+ case ChartCommandID::ShapeBringToFront:
+ {
+ if ( isForwardPossible() )
+ {
+ pDrawViewWrapper->PutMarkedToTop();
+ }
+ }
+ break;
+ case ChartCommandID::ShapeForward:
+ {
+ if ( isForwardPossible() )
+ {
+ pDrawViewWrapper->MovMarkedToTop();
+ }
+ }
+ break;
+ case ChartCommandID::ShapeBackward:
+ {
+ if ( isBackwardPossible() )
+ {
+ pDrawViewWrapper->MovMarkedToBtm();
+ }
+ }
+ break;
+ case ChartCommandID::ShapeSendToBack:
+ {
+ if ( isBackwardPossible() )
+ {
+ SdrObject* pFirstObj = getFirstAdditionalShape();
+ pDrawViewWrapper->PutMarkedBehindObj( pFirstObj );
+ }
+ }
+ break;
+ default:
+ {
+ }
+ break;
+ }
+}
+
+void ShapeController::executeDispatch_FontDialog()
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pChartController )
+ return;
+
+ weld::Window* pChartWindow(m_pChartController->GetChartFrame());
+ DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper();
+ DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper();
+ if ( pChartWindow && pDrawModelWrapper && pDrawViewWrapper )
+ {
+ SfxItemSet aAttr(pDrawViewWrapper->GetModel().GetItemPool());
+ pDrawViewWrapper->GetAttributes( aAttr );
+ ViewElementListProvider aViewElementListProvider( pDrawModelWrapper );
+ ShapeFontDialog aDlg(pChartWindow, &aAttr, &aViewElementListProvider);
+ if (aDlg.run() == RET_OK)
+ {
+ const SfxItemSet* pOutAttr = aDlg.GetOutputItemSet();
+ pDrawViewWrapper->SetAttributes( *pOutAttr );
+ }
+ }
+}
+
+void ShapeController::executeDispatch_ParagraphDialog()
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pChartController )
+ return;
+
+ weld::Window* pChartWindow(m_pChartController->GetChartFrame());
+ DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper();
+ if ( !(pChartWindow && pDrawViewWrapper) )
+ return;
+
+ SfxItemPool& rPool = pDrawViewWrapper->GetModel().GetItemPool();
+ SfxItemSet aAttr( rPool );
+ pDrawViewWrapper->GetAttributes( aAttr );
+
+ SfxItemSetFixed<
+ EE_ITEMS_START, EE_ITEMS_END,
+ SID_ATTR_PARA_PAGEBREAK, SID_ATTR_PARA_WIDOWS> aNewAttr(rPool);
+ aNewAttr.Put( aAttr );
+ aNewAttr.Put( SvxHyphenZoneItem( false, SID_ATTR_PARA_HYPHENZONE ) );
+ aNewAttr.Put( SvxFormatBreakItem( SvxBreak::NONE, SID_ATTR_PARA_PAGEBREAK ) );
+ aNewAttr.Put( SvxFormatSplitItem( true, SID_ATTR_PARA_SPLIT) );
+ aNewAttr.Put( SvxWidowsItem( 0, SID_ATTR_PARA_WIDOWS) );
+ aNewAttr.Put( SvxOrphansItem( 0, SID_ATTR_PARA_ORPHANS) );
+
+ ShapeParagraphDialog aDlg(pChartWindow, &aNewAttr);
+ if (aDlg.run() == RET_OK)
+ {
+ const SfxItemSet* pOutAttr = aDlg.GetOutputItemSet();
+ pDrawViewWrapper->SetAttributes( *pOutAttr );
+ }
+}
+
+SdrObject* ShapeController::getFirstAdditionalShape()
+{
+ SdrObject* pFirstObj = nullptr;
+
+ try
+ {
+ DrawModelWrapper* pDrawModelWrapper = ( m_pChartController ? m_pChartController->GetDrawModelWrapper() : nullptr );
+ if ( pDrawModelWrapper )
+ {
+ Reference< drawing::XShape > xFirstShape;
+ rtl::Reference<SvxDrawPage> xDrawPage( pDrawModelWrapper->getMainDrawPage() );
+ Reference< drawing::XShapes > xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) );
+ sal_Int32 nCount = xDrawPage->getCount();
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ Reference< drawing::XShape > xShape;
+ if ( xDrawPage->getByIndex( i ) >>= xShape )
+ {
+ if ( xShape.is() && xShape != xChartRoot )
+ {
+ xFirstShape = xShape;
+ break;
+ }
+ }
+ }
+ if ( xFirstShape.is() )
+ {
+ pFirstObj = DrawViewWrapper::getSdrObject( xFirstShape );
+ }
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+
+ return pFirstObj;
+}
+
+SdrObject* ShapeController::getLastAdditionalShape()
+{
+ SdrObject* pLastObj = nullptr;
+
+ try
+ {
+ DrawModelWrapper* pDrawModelWrapper = ( m_pChartController ? m_pChartController->GetDrawModelWrapper() : nullptr );
+ if ( pDrawModelWrapper )
+ {
+ Reference< drawing::XShape > xLastShape;
+ rtl::Reference<SvxDrawPage> xDrawPage( pDrawModelWrapper->getMainDrawPage() );
+ Reference< drawing::XShapes > xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) );
+ sal_Int32 nCount = xDrawPage->getCount();
+ for ( sal_Int32 i = nCount - 1; i >= 0; --i )
+ {
+ Reference< drawing::XShape > xShape;
+ if ( xDrawPage->getByIndex( i ) >>= xShape )
+ {
+ if ( xShape.is() && xShape != xChartRoot )
+ {
+ xLastShape = xShape;
+ break;
+ }
+ }
+ }
+ if ( xLastShape.is() )
+ {
+ pLastObj = DrawViewWrapper::getSdrObject( xLastShape );
+ }
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+
+ return pLastObj;
+}
+
+bool ShapeController::isBackwardPossible()
+{
+ if ( m_pChartController && m_pChartController->isAdditionalShapeSelected() )
+ {
+ SolarMutexGuard aGuard;
+ DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper();
+ if ( pDrawViewWrapper )
+ {
+ SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject();
+ SdrObject* pFirstObj = getFirstAdditionalShape();
+ if ( pSelectedObj && pFirstObj && pSelectedObj != pFirstObj )
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool ShapeController::isForwardPossible()
+{
+ if ( m_pChartController && m_pChartController->isAdditionalShapeSelected() )
+ {
+ SolarMutexGuard aGuard;
+ DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper();
+ if ( pDrawViewWrapper )
+ {
+ SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject();
+ SdrObject* pLastObj = getLastAdditionalShape();
+ if ( pSelectedObj && pLastObj && pSelectedObj != pLastObj )
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ShapeController.hxx b/chart2/source/controller/main/ShapeController.hxx
new file mode 100644
index 0000000000..cdd8002ce2
--- /dev/null
+++ b/chart2/source/controller/main/ShapeController.hxx
@@ -0,0 +1,81 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include "FeatureCommandDispatchBase.hxx"
+#include <tools/link.hxx>
+
+class AbstractSvxObjectNameDialog;
+class SdrObject;
+
+namespace chart
+{
+
+class ChartController;
+
+/** This is a CommandDispatch implementation for shapes.
+ */
+class ShapeController: public FeatureCommandDispatchBase
+{
+ friend class ControllerCommandDispatch;
+
+public:
+ ShapeController( const css::uno::Reference< css::uno::XComponentContext >& rxContext, ChartController* pController );
+ virtual ~ShapeController() override;
+
+protected:
+ // WeakComponentImplHelperBase
+ virtual void disposing(std::unique_lock<std::mutex>& rGuard) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // state of a feature
+ virtual FeatureState getState( const OUString& rCommand ) override;
+
+ // execute a feature
+ virtual void execute( const OUString& rCommand, const css::uno::Sequence< css::beans::PropertyValue>& rArgs ) override;
+
+ // all the features which should be handled by this class
+ virtual void describeSupportedFeatures() override;
+
+private:
+ DECL_LINK( CheckNameHdl, AbstractSvxObjectNameDialog&, bool);
+
+ void executeDispatch_FormatLine();
+ void executeDispatch_FormatArea();
+ void executeDispatch_TextAttributes();
+ void executeDispatch_TransformDialog();
+ void executeDispatch_ObjectTitleDescription();
+ void executeDispatch_RenameObject();
+ void executeDispatch_ChangeZOrder( ChartCommandID nId );
+ void executeDispatch_FontDialog();
+ void executeDispatch_ParagraphDialog();
+
+ SdrObject* getFirstAdditionalShape();
+ SdrObject* getLastAdditionalShape();
+ bool isBackwardPossible();
+ bool isForwardPossible();
+
+ ChartController* m_pChartController;
+};
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/StatusBarCommandDispatch.cxx b/chart2/source/controller/main/StatusBarCommandDispatch.cxx
new file mode 100644
index 0000000000..e3c1f038b0
--- /dev/null
+++ b/chart2/source/controller/main/StatusBarCommandDispatch.cxx
@@ -0,0 +1,127 @@
+/* -*- 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 "StatusBarCommandDispatch.hxx"
+#include <ObjectNameProvider.hxx>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <ChartModel.hxx>
+#include <utility>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace chart
+{
+
+StatusBarCommandDispatch::StatusBarCommandDispatch(
+ const Reference< uno::XComponentContext > & xContext,
+ rtl::Reference<::chart::ChartModel> xModel,
+ const Reference< view::XSelectionSupplier > & xSelSupp ) :
+ impl::StatusBarCommandDispatch_Base( xContext ),
+ m_xChartModel(std::move( xModel )),
+ m_xSelectionSupplier( xSelSupp ),
+ m_bIsModified( false )
+{}
+
+StatusBarCommandDispatch::~StatusBarCommandDispatch()
+{}
+
+void StatusBarCommandDispatch::initialize()
+{
+ if( m_xChartModel.is())
+ {
+ m_xChartModel->addModifyListener( this );
+ }
+
+ if( m_xSelectionSupplier.is())
+ {
+ m_xSelectionSupplier->addSelectionChangeListener( this );
+ }
+}
+
+void StatusBarCommandDispatch::fireStatusEvent(
+ const OUString & rURL,
+ const Reference< frame::XStatusListener > & xSingleListener /* = 0 */ )
+{
+ bool bFireAll( rURL.isEmpty() );
+ bool bFireContext( bFireAll || rURL == ".uno:Context" );
+ bool bFireModified( bFireAll || rURL == ".uno:ModifiedStatus" );
+
+ if( bFireContext && m_xChartModel.is())
+ {
+ uno::Any aArg;
+ aArg <<= ObjectNameProvider::getSelectedObjectText( m_aSelectedOID.getObjectCID(), m_xChartModel );
+ fireStatusEventForURL( ".uno:Context", aArg, true, xSingleListener );
+ }
+ if( bFireModified )
+ {
+ uno::Any aArg;
+ if( m_bIsModified )
+ aArg <<= OUString("*");
+ fireStatusEventForURL( ".uno:ModifiedStatus", aArg, true, xSingleListener );
+ }
+}
+
+// ____ XDispatch ____
+void SAL_CALL StatusBarCommandDispatch::dispatch(
+ const util::URL& /* URL */,
+ const Sequence< beans::PropertyValue >& /* Arguments */ )
+{
+ // nothing to do here
+}
+
+// ____ WeakComponentImplHelperBase ____
+/// is called when this is disposed
+void StatusBarCommandDispatch::disposing(std::unique_lock<std::mutex>& /*rGuard*/)
+{
+ m_xChartModel.clear();
+ m_xSelectionSupplier.clear();
+}
+
+// ____ XEventListener (base of XModifyListener) ____
+void SAL_CALL StatusBarCommandDispatch::disposing( const lang::EventObject& /* Source */ )
+{
+ m_xChartModel.clear();
+ m_xSelectionSupplier.clear();
+}
+
+// ____ XModifyListener ____
+void SAL_CALL StatusBarCommandDispatch::modified( const lang::EventObject& aEvent )
+{
+ if( m_xChartModel.is())
+ m_bIsModified = m_xChartModel->isModified();
+
+ CommandDispatch::modified( aEvent );
+}
+
+// ____ XSelectionChangeListener ____
+void SAL_CALL StatusBarCommandDispatch::selectionChanged( const lang::EventObject& /* aEvent */ )
+{
+ if( m_xSelectionSupplier.is())
+ m_aSelectedOID = ObjectIdentifier( m_xSelectionSupplier->getSelection() );
+ else
+ m_aSelectedOID = ObjectIdentifier();
+ fireAllStatusEvents( nullptr );
+}
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/StatusBarCommandDispatch.hxx b/chart2/source/controller/main/StatusBarCommandDispatch.hxx
new file mode 100644
index 0000000000..ae9dcaf4f6
--- /dev/null
+++ b/chart2/source/controller/main/StatusBarCommandDispatch.hxx
@@ -0,0 +1,94 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include "CommandDispatch.hxx"
+#include <ObjectIdentifier.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/view/XSelectionChangeListener.hpp>
+#include <rtl/ref.hxx>
+
+namespace com::sun::star::frame { class XModel; }
+namespace com::sun::star::util { class XModifiable; }
+namespace com::sun::star::view { class XSelectionSupplier; }
+
+namespace chart
+{
+
+/** This is a CommandDispatch implementation for all commands the status bar offers
+
+ This class reads the information needed from the XModel passed here.
+ */
+
+namespace impl
+{
+typedef ::cppu::ImplInheritanceHelper<
+ CommandDispatch,
+ css::view::XSelectionChangeListener >
+ StatusBarCommandDispatch_Base;
+}
+
+class StatusBarCommandDispatch : public impl::StatusBarCommandDispatch_Base
+{
+public:
+ explicit StatusBarCommandDispatch(
+ const css::uno::Reference< css::uno::XComponentContext > & xContext,
+ rtl::Reference<::chart::ChartModel> xModel,
+ const css::uno::Reference< css::view::XSelectionSupplier > & xSelSupp );
+ virtual ~StatusBarCommandDispatch() override;
+
+ // late initialisation, especially for adding as listener
+ virtual void initialize() override;
+
+protected:
+ // ____ XDispatch ____
+ virtual void SAL_CALL dispatch(
+ const css::util::URL& URL,
+ const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+
+ // ____ WeakComponentImplHelperBase ____
+ /// is called when this is disposed
+ virtual void disposing(std::unique_lock<std::mutex>& rGuard) override;
+
+ // ____ XModifyListener (override from CommandDispatch) ____
+ virtual void SAL_CALL modified(
+ const css::lang::EventObject& aEvent ) override;
+
+ // ____ XEventListener (base of XModifyListener) ____
+ virtual void SAL_CALL disposing(
+ const css::lang::EventObject& Source ) override;
+
+ virtual void fireStatusEvent(
+ const OUString & rURL,
+ const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ) override;
+
+ // ____ XSelectionChangeListener ____
+ virtual void SAL_CALL selectionChanged(
+ const css::lang::EventObject& aEvent ) override;
+
+private:
+ rtl::Reference<::chart::ChartModel> m_xChartModel;
+ css::uno::Reference< css::view::XSelectionSupplier > m_xSelectionSupplier;
+ bool m_bIsModified;
+ ObjectIdentifier m_aSelectedOID;
+};
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/ToolbarController.cxx b/chart2/source/controller/main/ToolbarController.cxx
new file mode 100644
index 0000000000..17df7c7c8b
--- /dev/null
+++ b/chart2/source/controller/main/ToolbarController.cxx
@@ -0,0 +1,121 @@
+/* -*- 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/.
+ */
+
+#include <ChartToolbarController.hxx>
+
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XFramesSupplier.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <sal/log.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace chart {
+
+ChartToolbarController::ChartToolbarController(const css::uno::Sequence<css::uno::Any>& rProperties)
+{
+ for (const auto& rProperty : rProperties)
+ {
+ css::beans::PropertyValue aPropValue;
+ rProperty >>= aPropValue;
+ if (aPropValue.Name == "Frame")
+ {
+ mxFramesSupplier.set(aPropValue.Value, css::uno::UNO_QUERY);
+ break;
+ }
+ }
+}
+
+ChartToolbarController::~ChartToolbarController()
+{
+}
+
+void ChartToolbarController::execute(sal_Int16 /*nKeyModifier*/)
+{
+}
+
+void ChartToolbarController::click()
+{
+ css::uno::Reference<css::frame::XFrame> xActiveFrame = mxFramesSupplier->getActiveFrame();
+ if (!xActiveFrame.is())
+ return;
+
+ css::uno::Reference<css::frame::XController> xActiveController = xActiveFrame->getController();
+ if (!xActiveController.is())
+ return;
+
+ css::uno::Reference<css::frame::XDispatch> xDispatch(xActiveController, css::uno::UNO_QUERY);
+ if (!xDispatch.is())
+ return;
+
+ css::util::URL aURL;
+ aURL.Path = "FormatSelection";
+ xDispatch->dispatch(aURL, css::uno::Sequence<css::beans::PropertyValue>());
+}
+
+void ChartToolbarController::doubleClick()
+{
+ SAL_INFO("chart2", "double clicked");
+}
+
+
+css::uno::Reference<css::awt::XWindow> ChartToolbarController::createPopupWindow()
+{
+ return css::uno::Reference<css::awt::XWindow>();
+}
+
+css::uno::Reference<css::awt::XWindow> ChartToolbarController::createItemWindow(
+ const css::uno::Reference<css::awt::XWindow>& /*rParent*/)
+{
+ return css::uno::Reference<css::awt::XWindow>();
+}
+
+void ChartToolbarController::statusChanged(const css::frame::FeatureStateEvent& /*rEvent*/)
+{
+
+}
+
+void ChartToolbarController::disposing(const css::lang::EventObject& /*rSource*/)
+{
+}
+
+void ChartToolbarController::initialize(const css::uno::Sequence<css::uno::Any>& /*rAny*/)
+{
+}
+
+void ChartToolbarController::update()
+{
+}
+
+
+OUString ChartToolbarController::getImplementationName()
+{
+ return "org.libreoffice.chart2.Chart2ToolboxController";
+}
+
+sal_Bool ChartToolbarController::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> ChartToolbarController::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ToolbarController" };
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_libreoffice_chart2_Chart2ToolboxController(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const & rProperties)
+{
+ return cppu::acquire(new ::chart::ChartToolbarController(rProperties));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/UndoActions.cxx b/chart2/source/controller/main/UndoActions.cxx
new file mode 100644
index 0000000000..cf2de5eb5a
--- /dev/null
+++ b/chart2/source/controller/main/UndoActions.cxx
@@ -0,0 +1,115 @@
+/* -*- 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 "UndoActions.hxx"
+#include "ChartModelClone.hxx"
+#include <ChartModel.hxx>
+
+#include <com/sun/star/lang/DisposedException.hpp>
+
+#include <svx/svdundo.hxx>
+
+#include <memory>
+#include <utility>
+
+using namespace ::com::sun::star;
+
+namespace chart::impl
+{
+ using ::com::sun::star::lang::DisposedException;
+
+UndoElement::UndoElement( OUString i_actionString, rtl::Reference<::chart::ChartModel> i_documentModel, std::shared_ptr< ChartModelClone > i_modelClone )
+ :m_sActionString(std::move( i_actionString ))
+ ,m_xDocumentModel(std::move( i_documentModel ))
+ ,m_pModelClone(std::move( i_modelClone ))
+{
+}
+
+UndoElement::~UndoElement()
+{
+}
+
+void UndoElement::disposing(std::unique_lock<std::mutex>&)
+{
+ if ( m_pModelClone )
+ m_pModelClone->dispose();
+ m_pModelClone.reset();
+ m_xDocumentModel.clear();
+}
+
+OUString SAL_CALL UndoElement::getTitle()
+{
+ return m_sActionString;
+}
+
+void UndoElement::impl_toggleModelState()
+{
+ // get a snapshot of the current state of our model
+ auto pNewClone = std::make_shared<ChartModelClone>( m_xDocumentModel, m_pModelClone->getFacet() );
+ // apply the previous snapshot to our model
+ m_pModelClone->applyToModel( m_xDocumentModel );
+ // remember the new snapshot, for the next toggle
+ m_pModelClone = pNewClone;
+}
+
+void SAL_CALL UndoElement::undo( )
+{
+ impl_toggleModelState();
+}
+
+void SAL_CALL UndoElement::redo( )
+{
+ impl_toggleModelState();
+}
+
+// = ShapeUndoElement
+
+ShapeUndoElement::ShapeUndoElement( std::unique_ptr<SdrUndoAction> xSdrUndoAction )
+ :m_xAction( std::move(xSdrUndoAction) )
+{
+}
+
+ShapeUndoElement::~ShapeUndoElement()
+{
+}
+
+OUString SAL_CALL ShapeUndoElement::getTitle()
+{
+ if ( !m_xAction )
+ throw DisposedException( OUString(), *this );
+ return m_xAction->GetComment();
+}
+
+void SAL_CALL ShapeUndoElement::undo( )
+{
+ if ( !m_xAction )
+ throw DisposedException( OUString(), *this );
+ m_xAction->Undo();
+}
+
+void SAL_CALL ShapeUndoElement::redo( )
+{
+ if ( !m_xAction )
+ throw DisposedException( OUString(), *this );
+ m_xAction->Redo();
+}
+
+} // namespace chart::impl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/UndoActions.hxx b/chart2/source/controller/main/UndoActions.hxx
new file mode 100644
index 0000000000..a86479e167
--- /dev/null
+++ b/chart2/source/controller/main/UndoActions.hxx
@@ -0,0 +1,101 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <com/sun/star/document/XUndoAction.hpp>
+
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+#include <comphelper/compbase.hxx>
+
+#include <memory>
+
+namespace com::sun::star::frame { class XModel; }
+
+class SdrUndoAction;
+
+namespace chart
+{
+class ChartModel;
+class ChartModelClone;
+
+namespace impl
+{
+
+typedef comphelper::WeakComponentImplHelper< css::document::XUndoAction > UndoElement_TBase;
+
+class UndoElement final : public UndoElement_TBase
+{
+public:
+ /** creates a new undo action
+
+ @param i_actionString
+ is the title of the Undo action
+ @param i_documentModel
+ is the actual document model which the undo actions operates on
+ @param i_modelClone
+ is the cloned model from before the changes, which the Undo action represents, have been applied.
+ Upon <member>invoking</member>, the clone model is applied to the document model.
+ */
+ UndoElement( OUString i_actionString,
+ rtl::Reference<::chart::ChartModel> i_documentModel,
+ std::shared_ptr< ChartModelClone > i_modelClone
+ );
+ virtual ~UndoElement() override;
+
+ UndoElement(const UndoElement&) = delete;
+ const UndoElement& operator=(const UndoElement&) = delete;
+
+ // XUndoAction
+ virtual OUString SAL_CALL getTitle() override;
+ virtual void SAL_CALL undo( ) override;
+ virtual void SAL_CALL redo( ) override;
+
+ // WeakComponentImplHelper
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+private:
+ void impl_toggleModelState();
+
+private:
+ OUString m_sActionString;
+ rtl::Reference<::chart::ChartModel> m_xDocumentModel;
+ std::shared_ptr< ChartModelClone > m_pModelClone;
+};
+
+typedef comphelper::WeakComponentImplHelper< css::document::XUndoAction > ShapeUndoElement_TBase;
+class ShapeUndoElement final : public ShapeUndoElement_TBase
+{
+public:
+ explicit ShapeUndoElement( std::unique_ptr<SdrUndoAction> xSdrUndoAction );
+ virtual ~ShapeUndoElement() override;
+
+ // XUndoAction
+ virtual OUString SAL_CALL getTitle() override;
+ virtual void SAL_CALL undo( ) override;
+ virtual void SAL_CALL redo( ) override;
+
+private:
+ std::unique_ptr<SdrUndoAction> m_xAction;
+};
+
+} // namespace impl
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/UndoCommandDispatch.cxx b/chart2/source/controller/main/UndoCommandDispatch.cxx
new file mode 100644
index 0000000000..c90fac3f40
--- /dev/null
+++ b/chart2/source/controller/main/UndoCommandDispatch.cxx
@@ -0,0 +1,146 @@
+/* -*- 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 "UndoCommandDispatch.hxx"
+#include <ChartModel.hxx>
+
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+#include <com/sun/star/document/UndoFailedException.hpp>
+
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+#include <svtools/strings.hrc>
+#include <svtools/svtresid.hxx>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace chart
+{
+
+UndoCommandDispatch::UndoCommandDispatch(
+ const Reference< uno::XComponentContext > & xContext,
+ rtl::Reference<::chart::ChartModel> xModel ) :
+ CommandDispatch( xContext ),
+ m_xModel(std::move( xModel ))
+{
+ m_xUndoManager.set( m_xModel->getUndoManager(), uno::UNO_SET_THROW );
+}
+
+UndoCommandDispatch::~UndoCommandDispatch()
+{}
+
+void UndoCommandDispatch::initialize()
+{
+ Reference< util::XModifyBroadcaster > xBroadcaster( m_xUndoManager, uno::UNO_QUERY );
+ ENSURE_OR_RETURN_VOID( xBroadcaster.is(), "UndoCommandDispatch::initialize: missing modification broadcaster interface!" );
+ xBroadcaster->addModifyListener( this );
+}
+
+void UndoCommandDispatch::fireStatusEvent(
+ const OUString & rURL,
+ const Reference< frame::XStatusListener > & xSingleListener /* = 0 */ )
+{
+ if( !m_xUndoManager.is() )
+ return;
+
+ const bool bFireAll = rURL.isEmpty();
+ uno::Any aUndoState, aRedoState, aUndoStrings, aRedoStrings;
+ if( m_xUndoManager->isUndoPossible())
+ aUndoState <<= SvtResId( STR_UNDO ) + m_xUndoManager->getCurrentUndoActionTitle();
+ if( m_xUndoManager->isRedoPossible())
+ aRedoState <<= SvtResId( STR_REDO ) + m_xUndoManager->getCurrentRedoActionTitle();
+
+ aUndoStrings <<= m_xUndoManager->getAllUndoActionTitles();
+ aRedoStrings <<= m_xUndoManager->getAllRedoActionTitles();
+
+ if( bFireAll || rURL == ".uno:Undo" )
+ fireStatusEventForURL( ".uno:Undo", aUndoState, m_xUndoManager->isUndoPossible(), xSingleListener );
+ if( bFireAll || rURL == ".uno:Redo" )
+ fireStatusEventForURL( ".uno:Redo", aRedoState, m_xUndoManager->isRedoPossible(), xSingleListener );
+ if( bFireAll || rURL == ".uno:GetUndoStrings" )
+ fireStatusEventForURL( ".uno:GetUndoStrings", aUndoStrings, true, xSingleListener );
+ if( bFireAll || rURL == ".uno:GetRedoStrings" )
+ fireStatusEventForURL( ".uno:GetRedoStrings", aRedoStrings, true, xSingleListener );
+}
+
+// ____ XDispatch ____
+void SAL_CALL UndoCommandDispatch::dispatch(
+ const util::URL& URL,
+ const Sequence< beans::PropertyValue >& Arguments )
+{
+ if( !m_xUndoManager.is() )
+ return;
+
+ // why is it necessary to lock the solar mutex here?
+ SolarMutexGuard aSolarGuard;
+ try
+ {
+ sal_Int16 nCount( 1 );
+ if ( Arguments.hasElements() && Arguments[0].Name == URL.Path )
+ Arguments[0].Value >>= nCount;
+
+ while ( nCount-- )
+ {
+ if ( URL.Path == "Undo" )
+ m_xUndoManager->undo();
+ else
+ m_xUndoManager->redo();
+ }
+ }
+ catch( const document::UndoFailedException& )
+ {
+ // silently ignore
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ // \--
+}
+
+// ____ WeakComponentImplHelperBase ____
+/// is called when this is disposed
+void UndoCommandDispatch::disposing(std::unique_lock<std::mutex>& /*rGuard*/)
+{
+ Reference< util::XModifyBroadcaster > xBroadcaster( m_xUndoManager, uno::UNO_QUERY );
+ OSL_ENSURE( xBroadcaster.is(), "UndoCommandDispatch::initialize: missing modification broadcaster interface!" );
+ if( xBroadcaster.is() )
+ {
+ xBroadcaster->removeModifyListener( this );
+ }
+
+ m_xUndoManager.clear();
+ m_xModel.clear();
+}
+
+// ____ XEventListener (base of XModifyListener) ____
+void SAL_CALL UndoCommandDispatch::disposing( const lang::EventObject& /* Source */ )
+{
+ m_xUndoManager.clear();
+ m_xModel.clear();
+}
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/UndoCommandDispatch.hxx b/chart2/source/controller/main/UndoCommandDispatch.hxx
new file mode 100644
index 0000000000..f872387c76
--- /dev/null
+++ b/chart2/source/controller/main/UndoCommandDispatch.hxx
@@ -0,0 +1,69 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include "CommandDispatch.hxx"
+#include <rtl/ref.hxx>
+
+namespace com::sun::star::document { class XUndoManager; }
+namespace com::sun::star::frame { class XModel; }
+
+namespace chart
+{
+class ChartModel;
+
+/** This is a CommandDispatch implementation for Undo and Redo.
+ */
+class UndoCommandDispatch : public CommandDispatch
+{
+public:
+ explicit UndoCommandDispatch(
+ const css::uno::Reference< css::uno::XComponentContext > & xContext,
+ rtl::Reference<::chart::ChartModel> xModel );
+ virtual ~UndoCommandDispatch() override;
+
+ // late initialisation, especially for adding as listener
+ virtual void initialize() override;
+
+protected:
+ // ____ XDispatch ____
+ virtual void SAL_CALL dispatch(
+ const css::util::URL& URL,
+ const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+
+ // ____ WeakComponentImplHelperBase ____
+ /// is called when this is disposed
+ virtual void disposing(std::unique_lock<std::mutex>& rGuard) override;
+
+ // ____ XEventListener (base of XModifyListener) ____
+ virtual void SAL_CALL disposing(
+ const css::lang::EventObject& Source ) override;
+
+ virtual void fireStatusEvent(
+ const OUString & rURL,
+ const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ) override;
+
+private:
+ rtl::Reference<::chart::ChartModel> m_xModel;
+ css::uno::Reference< css::document::XUndoManager > m_xUndoManager;
+};
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/UndoGuard.cxx b/chart2/source/controller/main/UndoGuard.cxx
new file mode 100644
index 0000000000..4e870c36d0
--- /dev/null
+++ b/chart2/source/controller/main/UndoGuard.cxx
@@ -0,0 +1,152 @@
+/* -*- 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 "UndoGuard.hxx"
+#include "ChartModelClone.hxx"
+#include "UndoActions.hxx"
+#include <ChartModel.hxx>
+
+#include <com/sun/star/document/XUndoManager.hpp>
+#include <utility>
+
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+
+namespace chart
+{
+
+UndoGuard::UndoGuard( OUString i_undoString, const uno::Reference< document::XUndoManager > & i_undoManager,
+ const ModelFacet i_facet )
+ :m_xUndoManager( i_undoManager )
+ ,m_aUndoString(std::move( i_undoString ))
+ ,m_bActionPosted( false )
+{
+ m_xChartModel = dynamic_cast<::chart::ChartModel*>(i_undoManager->getParent().get());
+ assert(m_xChartModel);
+ m_pDocumentSnapshot = std::make_shared<ChartModelClone>( m_xChartModel, i_facet );
+}
+
+UndoGuard::~UndoGuard()
+{
+ if ( m_pDocumentSnapshot )
+ discardSnapshot();
+}
+
+void UndoGuard::commit()
+{
+ if ( !m_bActionPosted && m_pDocumentSnapshot )
+ {
+ try
+ {
+ const Reference< document::XUndoAction > xAction( new impl::UndoElement( m_aUndoString, m_xChartModel, m_pDocumentSnapshot ) );
+ m_pDocumentSnapshot.reset(); // don't dispose, it's data went over to the UndoElement
+ m_xUndoManager->addUndoAction( xAction );
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ }
+ m_bActionPosted = true;
+}
+
+void UndoGuard::rollback()
+{
+ ENSURE_OR_RETURN_VOID( !!m_pDocumentSnapshot, "no snapshot!" );
+ m_pDocumentSnapshot->applyToModel( m_xChartModel );
+ discardSnapshot();
+}
+
+void UndoGuard::discardSnapshot()
+{
+ ENSURE_OR_RETURN_VOID( !!m_pDocumentSnapshot, "no snapshot!" );
+ m_pDocumentSnapshot->dispose();
+ m_pDocumentSnapshot.reset();
+}
+
+UndoLiveUpdateGuard::UndoLiveUpdateGuard( const OUString& i_undoString, const uno::Reference< document::XUndoManager >& i_undoManager )
+ :UndoGuard( i_undoString, i_undoManager, E_MODEL )
+{
+}
+
+UndoLiveUpdateGuard::~UndoLiveUpdateGuard()
+{
+ if ( !isActionPosted() )
+ rollback();
+}
+
+UndoLiveUpdateGuardWithData::UndoLiveUpdateGuardWithData(
+ const OUString& i_undoString, const uno::Reference< document::XUndoManager >& i_undoManager )
+ :UndoGuard( i_undoString, i_undoManager, E_MODEL_WITH_DATA )
+{
+}
+
+UndoLiveUpdateGuardWithData::~UndoLiveUpdateGuardWithData()
+{
+ if ( !isActionPosted() )
+ rollback();
+}
+
+UndoGuardWithSelection::UndoGuardWithSelection(
+ const OUString& i_undoString, const uno::Reference< document::XUndoManager >& i_undoManager )
+ :UndoGuard( i_undoString, i_undoManager, E_MODEL_WITH_SELECTION )
+{
+}
+
+UndoGuardWithSelection::~UndoGuardWithSelection()
+{
+ if ( !isActionPosted() )
+ rollback();
+}
+
+HiddenUndoContext::HiddenUndoContext( const Reference< document::XUndoManager > & i_undoManager )
+ :m_xUndoManager( i_undoManager )
+{
+ ENSURE_OR_THROW( m_xUndoManager.is(), "invalid undo manager!" );
+ try
+ {
+ m_xUndoManager->enterHiddenUndoContext();
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ m_xUndoManager.clear();
+ // prevents the leaveUndoContext in the dtor
+ }
+}
+
+HiddenUndoContext::~HiddenUndoContext()
+{
+ try
+ {
+ if ( m_xUndoManager.is() )
+ m_xUndoManager->leaveUndoContext();
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+}
+
+} // namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/controller/main/UndoGuard.hxx b/chart2/source/controller/main/UndoGuard.hxx
new file mode 100644
index 0000000000..90443a247a
--- /dev/null
+++ b/chart2/source/controller/main/UndoGuard.hxx
@@ -0,0 +1,115 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include "ChartModelClone.hxx"
+
+#include <rtl/ustring.hxx>
+
+#include <memory>
+
+namespace com::sun::star::document { class XUndoManager; }
+namespace com::sun::star::frame { class XModel; }
+
+namespace chart
+{
+
+/** A guard which does nothing, unless you explicitly call commitAction. In particular, in its destructor, it
+ does neither auto-commit nor auto-rollback the model changes.
+ */
+class UndoGuard
+{
+public:
+ explicit UndoGuard(
+ OUString i_undoMessage,
+ const css::uno::Reference< css::document::XUndoManager > & i_undoManager,
+ const ModelFacet i_facet = E_MODEL
+ );
+ ~UndoGuard();
+
+ void commit();
+ void rollback();
+
+protected:
+ bool isActionPosted() const { return m_bActionPosted; }
+
+private:
+ void discardSnapshot();
+
+private:
+ rtl::Reference<::chart::ChartModel> m_xChartModel;
+ const css::uno::Reference< css::document::XUndoManager > m_xUndoManager;
+
+ std::shared_ptr< ChartModelClone > m_pDocumentSnapshot;
+ OUString m_aUndoString;
+ bool m_bActionPosted;
+};
+
+/** A guard which, in its destructor, restores the model state it found in the constructor. If
+ <member>commitAction</member> is called inbetween, the restoration is not performed.
+ */
+class UndoLiveUpdateGuard : public UndoGuard
+{
+public:
+ explicit UndoLiveUpdateGuard(
+ const OUString& i_undoMessage,
+ const css::uno::Reference< css::document::XUndoManager > & i_undoManager
+ );
+ ~UndoLiveUpdateGuard();
+};
+
+/** Same as UndoLiveUpdateGuard but with additional storage of the chart's data.
+ Only use this if the data has internal data.
+ */
+class UndoLiveUpdateGuardWithData :
+ public UndoGuard
+{
+public:
+ explicit UndoLiveUpdateGuardWithData(
+ const OUString& i_undoMessage,
+ const css::uno::Reference< css::document::XUndoManager > & i_undoManager
+ );
+ ~UndoLiveUpdateGuardWithData();
+};
+
+class UndoGuardWithSelection : public UndoGuard
+{
+public:
+ explicit UndoGuardWithSelection(
+ const OUString& i_undoMessage,
+ const css::uno::Reference< css::document::XUndoManager > & i_undoManager
+ );
+ virtual ~UndoGuardWithSelection();
+};
+
+class HiddenUndoContext
+{
+public:
+ explicit HiddenUndoContext(
+ const css::uno::Reference< css::document::XUndoManager > & i_undoManager
+ );
+ ~HiddenUndoContext();
+
+private:
+ css::uno::Reference< css::document::XUndoManager > m_xUndoManager;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */