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.cxx1659
-rw-r--r--chart2/source/controller/main/ChartController_EditData.cxx55
-rw-r--r--chart2/source/controller/main/ChartController_Insert.cxx877
-rw-r--r--chart2/source/controller/main/ChartController_Position.cxx210
-rw-r--r--chart2/source/controller/main/ChartController_Properties.cxx829
-rw-r--r--chart2/source/controller/main/ChartController_TextEdit.cxx220
-rw-r--r--chart2/source/controller/main/ChartController_Tools.cxx990
-rw-r--r--chart2/source/controller/main/ChartController_Window.cxx2121
-rw-r--r--chart2/source/controller/main/ChartDropTargetHelper.cxx176
-rw-r--r--chart2/source/controller/main/ChartDropTargetHelper.hxx58
-rw-r--r--chart2/source/controller/main/ChartFrameloader.cxx201
-rw-r--r--chart2/source/controller/main/ChartFrameloader.hxx70
-rw-r--r--chart2/source/controller/main/ChartModelClone.cxx249
-rw-r--r--chart2/source/controller/main/ChartModelClone.hxx76
-rw-r--r--chart2/source/controller/main/ChartTransferable.cxx164
-rw-r--r--chart2/source/controller/main/ChartTransferable.hxx64
-rw-r--r--chart2/source/controller/main/ChartWindow.cxx392
-rw-r--r--chart2/source/controller/main/CommandDispatch.cxx170
-rw-r--r--chart2/source/controller/main/CommandDispatch.hxx136
-rw-r--r--chart2/source/controller/main/CommandDispatchContainer.cxx198
-rw-r--r--chart2/source/controller/main/ConfigurationAccess.cxx99
-rw-r--r--chart2/source/controller/main/ControllerCommandDispatch.cxx837
-rw-r--r--chart2/source/controller/main/ControllerCommandDispatch.hxx123
-rw-r--r--chart2/source/controller/main/DragMethod_Base.cxx77
-rw-r--r--chart2/source/controller/main/DragMethod_Base.hxx62
-rw-r--r--chart2/source/controller/main/DragMethod_PieSegment.cxx152
-rw-r--r--chart2/source/controller/main/DragMethod_PieSegment.hxx58
-rw-r--r--chart2/source/controller/main/DragMethod_RotateDiagram.cxx229
-rw-r--r--chart2/source/controller/main/DragMethod_RotateDiagram.hxx90
-rw-r--r--chart2/source/controller/main/DrawCommandDispatch.cxx619
-rw-r--r--chart2/source/controller/main/DrawCommandDispatch.h42
-rw-r--r--chart2/source/controller/main/DrawCommandDispatch.hxx76
-rw-r--r--chart2/source/controller/main/ElementSelector.cxx328
-rw-r--r--chart2/source/controller/main/ElementSelector.hxx104
-rw-r--r--chart2/source/controller/main/FeatureCommandDispatchBase.cxx94
-rw-r--r--chart2/source/controller/main/FeatureCommandDispatchBase.hxx101
-rw-r--r--chart2/source/controller/main/ObjectHierarchy.cxx845
-rw-r--r--chart2/source/controller/main/PositionAndSizeHelper.cxx180
-rw-r--r--chart2/source/controller/main/SelectionHelper.cxx650
-rw-r--r--chart2/source/controller/main/ShapeController.cxx676
-rw-r--r--chart2/source/controller/main/ShapeController.hxx85
-rw-r--r--chart2/source/controller/main/StatusBarCommandDispatch.cxx128
-rw-r--r--chart2/source/controller/main/StatusBarCommandDispatch.hxx97
-rw-r--r--chart2/source/controller/main/ToolbarController.cxx124
-rw-r--r--chart2/source/controller/main/UndoActions.cxx123
-rw-r--r--chart2/source/controller/main/UndoActions.hxx115
-rw-r--r--chart2/source/controller/main/UndoCommandDispatch.cxx147
-rw-r--r--chart2/source/controller/main/UndoCommandDispatch.hxx71
-rw-r--r--chart2/source/controller/main/UndoGuard.cxx151
-rw-r--r--chart2/source/controller/main/UndoGuard.hxx118
50 files changed, 15516 insertions, 0 deletions
diff --git a/chart2/source/controller/main/ChartController.cxx b/chart2/source/controller/main/ChartController.cxx
new file mode 100644
index 000000000..f81b26118
--- /dev/null
+++ b/chart2/source/controller/main/ChartController.cxx
@@ -0,0 +1,1659 @@
+/* -*- 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 <set>
+
+#include <ChartController.hxx>
+#include <servicenames.hxx>
+#include <ResId.hxx>
+#include <dlg_DataSource.hxx>
+#include <ChartModel.hxx>
+#include <ChartModelHelper.hxx>
+#include "ControllerCommandDispatch.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>
+#include <AccessibleChartView.hxx>
+#include "DrawCommandDispatch.hxx"
+#include "ShapeController.hxx"
+#include "UndoActions.hxx"
+#include <ViewElementListProvider.hxx>
+
+#include <cppuhelper/supportsservice.hxx>
+
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/chart2/data/XDataReceiver.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/util/XModifyBroadcaster.hpp>
+#include <com/sun/star/frame/LayoutManagerEvents.hpp>
+#include <com/sun/star/frame/XLayoutManagerEventBroadcaster.hpp>
+#include <com/sun/star/document/XUndoManagerSupplier.hpp>
+#include <com/sun/star/ui/XSidebar.hpp>
+#include <com/sun/star/chart2/XChartTypeContainer.hpp>
+#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
+#include <com/sun/star/chart2/XDataProviderAccess.hpp>
+
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <svx/sidebar/SelectionChangeHandler.hxx>
+#include <toolkit/awt/vclxwindow.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <osl/mutex.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 <tools/diagnose_ex.h>
+
+// 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> const & xContext) :
+ m_aLifeTimeManager( nullptr ),
+ m_bSuspended( false ),
+ m_xCC(xContext), //@todo is it allowed to hold this context??
+ m_aModelMutex(),
+ m_aModel( nullptr, m_aModelMutex ),
+ m_xViewWindow(),
+ m_xChartView(),
+ m_pDrawModelWrapper(),
+ m_eDragMode(SdrDragMode::Move),
+ 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( const uno::Reference< frame::XModel > & xModel ) :
+ m_xModel( xModel ),
+ m_bOwnership( true )
+{
+ m_xCloseable =
+ uno::Reference< util::XCloseable >( xModel, uno::UNO_QUERY );
+}
+
+ChartController::TheModel::~TheModel()
+{
+}
+
+void ChartController::TheModel::addListener( ChartController* pController )
+{
+ if(m_xCloseable.is())
+ {
+ //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_xCloseable->addCloseListener(
+ static_cast<util::XCloseListener*>(pController) );
+ }
+ else if( m_xModel.is() )
+ {
+ //we need to add as dispose event listener
+ m_xModel->addEventListener(
+ static_cast<util::XCloseListener*>(pController) );
+ }
+
+}
+
+void ChartController::TheModel::removeListener( ChartController* pController )
+{
+ if(m_xCloseable.is())
+ m_xCloseable->removeCloseListener(
+ static_cast<util::XCloseListener*>(pController) );
+
+ else if( m_xModel.is() )
+ m_xModel->removeEventListener(
+ static_cast<util::XCloseListener*>(pController) );
+}
+
+void ChartController::TheModel::tryTermination()
+{
+ if(!m_bOwnership)
+ return;
+
+ try
+ {
+ if(m_xCloseable.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_xCloseable->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;
+ }
+
+ }
+ else if( m_xModel.is() )
+ {
+ //@todo correct??
+ m_xModel->dispose();
+ 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 {
+
+css::uno::Reference<css::chart2::XChartType> getChartType(
+ const css::uno::Reference<css::chart2::XChartDocument>& xChartDoc)
+{
+ Reference <chart2::XDiagram > xDiagram = xChartDoc->getFirstDiagram();
+ if (!xDiagram.is()) {
+ return css::uno::Reference<css::chart2::XChartType>();
+ }
+
+ Reference< chart2::XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY_THROW );
+
+ Sequence< Reference< chart2::XCoordinateSystem > > xCooSysSequence( xCooSysContainer->getCoordinateSystems());
+ if (!xCooSysSequence.hasElements()) {
+ return css::uno::Reference<css::chart2::XChartType>();
+ }
+
+ Reference< chart2::XChartTypeContainer > xChartTypeContainer( xCooSysSequence[0], uno::UNO_QUERY_THROW );
+
+ Sequence< Reference< chart2::XChartType > > xChartTypeSequence( xChartTypeContainer->getChartTypes() );
+
+ return xChartTypeSequence[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";
+ break;
+ 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:
+ {
+ css::uno::Reference<css::chart2::XChartType> xChartType = getChartType(css::uno::Reference<css::chart2::XChartDocument>(getModel(), uno::UNO_QUERY));
+ 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;
+}
+
+// lang::XServiceInfo
+
+OUString SAL_CALL ChartController::getImplementationName()
+{
+ return CHART_CONTROLLER_SERVICE_IMPLEMENTATION_NAME;
+}
+
+sal_Bool SAL_CALL ChartController::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL ChartController::getSupportedServiceNames()
+{
+ return {
+ CHART_CONTROLLER_SERVICE_NAME,
+ "com.sun.star.frame.Controller"
+ //// @todo : add additional services if you support any further
+ };
+}
+
+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
+
+ mpSelectionChangeHandler->Connect();
+
+ uno::Reference<ui::XSidebar> xSidebar = getSidebarFromModel(getModel());
+ if (xSidebar.is())
+ {
+ auto pSidebar = dynamic_cast<sfx2::sidebar::SidebarController*>(xSidebar.get());
+ assert(pSidebar);
+ sfx2::sidebar::SidebarController::registerSidebarForFrame(pSidebar, this);
+ pSidebar->updateModel(getModel());
+ css::lang::EventObject aEvent;
+ mpSelectionChangeHandler->selectionChanged(aEvent);
+ }
+
+ 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
+
+ //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();
+ VCLXWindow* pParentComponent = comphelper::getUnoTunnelImplementation<VCLXWindow>(xContainerWindow);
+ assert(pParentComponent);
+ if (pParentComponent)
+ pParentComponent->setVisible(true);
+
+ pParent = VCLUnoHelper::GetWindow( xContainerWindow ).get();
+ }
+
+ {
+ // 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(),
+ uno::Reference< chart2::XChartDocument >( getModel(), uno::UNO_QUERY )));
+
+ 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( getModel() );
+
+ 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();
+
+ TheModelRef aNewModelRef( new TheModel( xModel), m_aModelMutex);
+ TheModelRef aOldModelRef(m_aModel,m_aModelMutex);
+ m_aModel = aNewModelRef;
+
+ //--handle relations to the old model if any
+ if( aOldModelRef.is() )
+ {
+ uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY );
+ if( xViewBroadcaster.is() )
+ xViewBroadcaster->removeModeChangeListener(this);
+ m_pDrawModelWrapper.reset();
+
+ aOldModelRef->removeListener( this );
+ #ifdef TEST_ENABLE_MODIFY_LISTENER
+ uno::Reference< util::XModifyBroadcaster > xMBroadcaster( aOldModelRef->getModel(),uno::UNO_QUERY );
+ if( xMBroadcaster.is())
+ xMBroadcaster->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());
+ 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, impl_getAvailableCommands() );
+
+ DrawCommandDispatch* pDrawDispatch = new DrawCommandDispatch( m_xCC, this );
+ pDrawDispatch->initialize();
+ m_aDispatchContainer.setDrawCommandDispatch( pDrawDispatch );
+
+ ShapeController* pShapeController = new ShapeController( m_xCC, this );
+ pShapeController->initialize();
+ m_aDispatchContainer.setShapeController( pShapeController );
+ aGuard.clear();
+
+#ifdef TEST_ENABLE_MODIFY_LISTENER
+ uno::Reference< util::XModifyBroadcaster > xMBroadcaster( aNewModelRef->getModel(),uno::UNO_QUERY );
+ if( xMBroadcaster.is())
+ xMBroadcaster->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() ) ) );
+
+ uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
+ if( xFact.is())
+ {
+ m_xChartView = xFact->createInstance( CHART_VIEW_SERVICE_NAME );
+ GetDrawModelWrapper();
+ uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY );
+ if( xViewBroadcaster.is() )
+ xViewBroadcaster->addModeChangeListener(this);
+ }
+
+ //the frameloader is responsible to call xModel->connectController
+ {
+ SolarMutexGuard aGuard2;
+ auto pChartWindow(GetChartWindow());
+ if( pChartWindow )
+ pChartWindow->Invalidate();
+ }
+
+ uno::Reference< document::XUndoManagerSupplier > xSuppUndo( getModel(), uno::UNO_QUERY_THROW );
+ m_xUndoManager.set( xSuppUndo->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()
+{
+ //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 uno::Reference< frame::XModel > ();
+}
+
+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;
+}
+
+void ChartController::impl_createDrawViewController()
+{
+ SolarMutexGuard aGuard;
+ if(!m_pDrawViewWrapper)
+ {
+ if( m_pDrawModelWrapper )
+ {
+ m_pDrawViewWrapper.reset( new DrawViewWrapper(m_pDrawModelWrapper->getSdrModel(),GetChartWindow()) );
+ m_pDrawViewWrapper->attachParentReferenceDevice( getModel() );
+ }
+ }
+}
+
+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;
+
+ if (getModel().is())
+ {
+ uno::Reference<ui::XSidebar> xSidebar = getSidebarFromModel(getModel());
+ if (sfx2::sidebar::SidebarController* pSidebar = dynamic_cast<sfx2::sidebar::SidebarController*>(xSidebar.get()))
+ {
+ sfx2::sidebar::SidebarController::unregisterSidebarForFrame(pSidebar, this);
+ }
+ }
+ mpSelectionChangeHandler->selectionChanged(css::lang::EventObject());
+ mpSelectionChangeHandler->Disconnect();
+
+ 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;
+ uno::Reference< chart2::data::XDataReceiver > xDataReceiver( getModel(), uno::UNO_QUERY );
+ 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
+ {
+ uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY );
+ if( xViewBroadcaster.is() )
+ xViewBroadcaster->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.set( nullptr );
+ }
+
+ 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
+ {
+ uno::Reference< util::XModifyBroadcaster > xMBroadcaster( aModelRef->getModel(),uno::UNO_QUERY );
+ if( xMBroadcaster.is())
+ xMBroadcaster->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 )
+{
+ SolarMutexGuard aGuard;
+ if( impl_isDisposedOrSuspended() )//@todo? allow adding of listeners in suspend mode?
+ return; //behave passive if already disposed or suspended
+
+ //--add listener
+ m_aLifeTimeManager.m_aListenerContainer.addInterface( cppu::UnoType<lang::XEventListener>::get(), 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
+ m_aLifeTimeManager.m_aListenerContainer.removeInterface( cppu::UnoType<lang::XEventListener>::get(), 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( aModelRef->getModel() != 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() && m_aModel->getModel() == 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.set( nullptr );
+ }
+}
+
+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( const OUString& aCommand )
+{
+ return aCommand == "MainTitle"
+ || aCommand == "SubTitle"
+ || aCommand == "XTitle"
+ || aCommand == "YTitle"
+ || aCommand == "ZTitle"
+ || aCommand == "SecondaryXTitle"
+ || aCommand == "SecondaryYTitle"
+ || aCommand == "AllTitles"
+ || aCommand == "DiagramAxisX"
+ || aCommand == "DiagramAxisY"
+ || aCommand == "DiagramAxisZ"
+ || aCommand == "DiagramAxisA"
+ || aCommand == "DiagramAxisB"
+ || aCommand == "DiagramAxisAll"
+ || aCommand == "DiagramGridXMain"
+ || aCommand == "DiagramGridYMain"
+ || aCommand == "DiagramGridZMain"
+ || aCommand == "DiagramGridXHelp"
+ || aCommand == "DiagramGridYHelp"
+ || aCommand == "DiagramGridZHelp"
+ || aCommand == "DiagramGridAll"
+
+ || aCommand == "DiagramWall"
+ || aCommand == "DiagramFloor"
+ || aCommand == "DiagramArea"
+ || aCommand == "Legend"
+
+ || aCommand == "FormatWall"
+ || aCommand == "FormatFloor"
+ || aCommand == "FormatChartArea"
+ || aCommand == "FormatLegend"
+
+ || aCommand == "FormatTitle"
+ || aCommand == "FormatAxis"
+ || aCommand == "FormatDataSeries"
+ || aCommand == "FormatDataPoint"
+ || aCommand == "FormatDataLabels"
+ || aCommand == "FormatDataLabel"
+ || aCommand == "FormatXErrorBars"
+ || aCommand == "FormatYErrorBars"
+ || aCommand == "FormatMeanValue"
+ || aCommand == "FormatTrendline"
+ || aCommand == "FormatTrendlineEquation"
+ || aCommand == "FormatStockLoss"
+ || aCommand == "FormatStockGain"
+ || aCommand == "FormatMajorGrid"
+ || aCommand == "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 == "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( getModel() );
+ 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 == "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();
+ //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(), getModel());
+ if (aDlg.run() == RET_OK)
+ {
+ impl_adaptDataSeriesAutoResize();
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_SourceData()
+{
+ //convert properties to ItemSet
+ uno::Reference< XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
+ 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 = dynamic_cast<ChartModel&>(*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, m_xCC);
+ if (aDlg.run() == RET_OK)
+ {
+ impl_adaptDataSeriesAutoResize();
+ aUndoGuard.commit();
+ }
+}
+
+void ChartController::executeDispatch_MoveSeries( bool bForward )
+{
+ ControllerLockGuardUNO aCLGuard( getModel() );
+
+ //get selected series
+ OUString aObjectCID(m_aSelection.getSelectedCID());
+ uno::Reference< XDataSeries > xGivenDataSeries( ObjectIdentifier::getDataSeriesForCID( //yyy todo also legend entries and labels?
+ aObjectCID, getModel() ) );
+
+ UndoGuardWithSelection aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ (bForward ? ActionDescriptionProvider::ActionType::MoveToTop : ActionDescriptionProvider::ActionType::MoveToBottom),
+ SchResId(STR_OBJECT_DATASERIES)),
+ m_xUndoManager );
+
+ bool bChanged = DiagramHelper::moveSeries( ChartModelHelper::findDiagram( getModel() ), xGivenDataSeries, bForward );
+ if( bChanged )
+ {
+ m_aSelection.setSelection( ObjectIdentifier::getMovedSeriesCID( aObjectCID, bForward ) );
+ aUndoGuard.commit();
+ }
+}
+
+// ____ XMultiServiceFactory ____
+uno::Reference< uno::XInterface > SAL_CALL
+ ChartController::createInstance( const OUString& aServiceSpecifier )
+{
+ uno::Reference< uno::XInterface > xResult;
+
+ if( aServiceSpecifier == CHART_ACCESSIBLE_TEXT_SERVICE_NAME )
+ xResult.set( impl_createAccessibleTextContext());
+ return xResult;
+}
+
+uno::Reference< uno::XInterface > SAL_CALL
+ ChartController::createInstanceWithArguments(
+ const OUString& ServiceSpecifier,
+ const uno::Sequence< uno::Any >& /* Arguments */ )
+{
+ // ignore Arguments
+ return createInstance( ServiceSpecifier );
+}
+
+uno::Sequence< OUString > SAL_CALL
+ ChartController::getAvailableServiceNames()
+{
+ uno::Sequence< OUString > aServiceNames { CHART_ACCESSIBLE_TEXT_SERVICE_NAME };
+ return aServiceNames;
+}
+
+// ____ 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
+ {
+ const Reference< document::XUndoManagerSupplier > xSuppUndo( getModel(), uno::UNO_QUERY_THROW );
+ 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 )
+ {
+ ExplicitValueProvider* pProvider = comphelper::getUnoTunnelImplementation<ExplicitValueProvider>( m_xChartView );
+ if( pProvider )
+ m_pDrawModelWrapper = pProvider->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();
+}
+
+
+VclPtr<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).get());
+}
+
+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()
+{
+ uno::Reference< XAccessible > xResult = new AccessibleChartView( GetDrawViewWrapper() );
+ impl_initializeAccessible( uno::Reference< lang::XInitialization >( xResult, uno::UNO_QUERY ) );
+ return xResult;
+}
+
+void ChartController::impl_invalidateAccessible()
+{
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+ if( pChartWindow )
+ {
+ Reference< lang::XInitialization > xInit( pChartWindow->GetAccessible(false), uno::UNO_QUERY );
+ if(xInit.is())
+ {
+ uno::Sequence< uno::Any > aArguments(3);//empty arguments -> invalid accessible
+ xInit->initialize(aArguments);
+ }
+ }
+}
+void ChartController::impl_initializeAccessible()
+{
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+ if( pChartWindow )
+ this->impl_initializeAccessible( Reference< lang::XInitialization >( pChartWindow->GetAccessible(false), uno::UNO_QUERY ) );
+}
+void ChartController::impl_initializeAccessible( const uno::Reference< lang::XInitialization >& xInit )
+{
+ if(!xInit.is())
+ return;
+
+ uno::Sequence< uno::Any > aArguments(5);
+ aArguments[0] <<= uno::Reference<view::XSelectionSupplier>(this);
+ aArguments[1] <<= getModel();
+ aArguments[2] <<= m_xChartView;
+ uno::Reference< XAccessible > xParent;
+ {
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+ if( pChartWindow )
+ {
+ vcl::Window* pParentWin( pChartWindow->GetAccessibleParentWindow());
+ if( pParentWin )
+ xParent.set( pParentWin->GetAccessible());
+ }
+ }
+ aArguments[3] <<= xParent;
+ aArguments[4] <<= m_xViewWindow;
+
+ xInit->initialize(aArguments);
+}
+
+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",
+ //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
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_chart2_ChartController_get_implementation(css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new chart::ChartController(context));
+}
+
+/* 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 000000000..e9820cab3
--- /dev/null
+++ b/chart2/source/controller/main/ChartController_EditData.cxx
@@ -0,0 +1,55 @@
+/* -*- 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 <ChartWindow.hxx>
+#include <ChartController.hxx>
+
+#include <dlg_DataEditor.hxx>
+#include "UndoGuard.hxx"
+#include <ResId.hxx>
+#include <strings.hrc>
+
+#include <vcl/svapp.hxx>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+
+namespace chart
+{
+
+void ChartController::executeDispatch_EditData()
+{
+ Reference< chart2::XChartDocument > xChartDoc( getModel(), 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 000000000..85f7ea5c3
--- /dev/null
+++ b/chart2/source/controller/main/ChartController_Insert.cxx
@@ -0,0 +1,877 @@
+/* -*- 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 <dlg_InsertAxis_Grid.hxx>
+#include <dlg_InsertDataLabel.hxx>
+#include <dlg_InsertLegend.hxx>
+#include <dlg_InsertErrorBars.hxx>
+#include <dlg_InsertTitle.hxx>
+#include <dlg_ObjectProperties.hxx>
+
+#include <ChartModel.hxx>
+#include <ChartModelHelper.hxx>
+#include <AxisHelper.hxx>
+#include <TitleHelper.hxx>
+#include <DiagramHelper.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 <LegendHelper.hxx>
+
+#include <com/sun/star/chart2/XRegressionCurve.hpp>
+#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/chart/ErrorBarStyle.hpp>
+#include <svx/ActionDescriptionProvider.hxx>
+
+#include <tools/diagnose_ex.h>
+#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 uno::Reference< chart2::XDataSeries > & xSeries )
+{
+ uno::Reference< chart2::XRegressionCurveContainer > xRegCurveCnt(
+ xSeries, uno::UNO_QUERY );
+ if( xRegCurveCnt.is())
+ {
+ ::chart::RegressionCurveHelper::addMeanValueLine(
+ xRegCurveCnt, uno::Reference< beans::XPropertySet >( xSeries, uno::UNO_QUERY ));
+ }
+}
+
+} // anonymous namespace
+
+namespace chart
+{
+
+void ChartController::executeDispatch_InsertAxes()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_AXES )),
+ m_xUndoManager );
+
+ try
+ {
+ InsertAxisOrGridDialogData aDialogInput;
+ uno::Reference< XDiagram > xDiagram = ChartModelHelper::findDiagram(getModel());
+ AxisHelper::getAxisOrGridExcistence( 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( getModel() );
+
+ 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;
+ uno::Reference< XDiagram > xDiagram = ChartModelHelper::findDiagram(getModel());
+ AxisHelper::getAxisOrGridExcistence( 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( getModel() );
+ 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_InsertTitles()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_TITLES )),
+ m_xUndoManager );
+
+ try
+ {
+ TitleDialogData aDialogInput;
+ aDialogInput.readFromModel( getModel() );
+
+ SolarMutexGuard aGuard;
+ SchTitleDlg aDlg(GetChartFrame(), aDialogInput);
+ if (aDlg.run() == RET_OK)
+ {
+ // lock controllers till end of block
+ ControllerLockGuardUNO aCLGuard( getModel() );
+ TitleDialogData aDialogOutput(impl_createReferenceSizeProvider());
+ aDlg.getResult(aDialogOutput);
+ bool bChanged = aDialogOutput.writeDifferenceToModel( getModel(), 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 );
+
+ ChartModel& rModel = dynamic_cast<ChartModel&>(*getModel());
+ LegendHelper::hideLegend(rModel);
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_InsertLegend()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_LEGEND )),
+ m_xUndoManager );
+
+ ChartModel& rModel = dynamic_cast<ChartModel&>(*getModel());
+ LegendHelper::showLegend(rModel, 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( getModel() );
+ if (aDlg.run() == RET_OK)
+ {
+ // lock controllers till end of block
+ ControllerLockGuardUNO aCLGuard( getModel() );
+ aDlg.writeToModel( getModel() );
+ 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:
+ uno::Reference< chart2::XDataSeries > xSeries =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getModel());
+ 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(
+ getModel(),
+ m_pDrawModelWrapper->GetItemPool(),
+ m_pDrawModelWrapper->getSdrModel(),
+ uno::Reference< lang::XMultiServiceFactory >( getModel(), uno::UNO_QUERY ));
+ SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet();
+ aItemConverter.FillItemSet( aItemSet );
+
+ //prepare and open dialog
+ SolarMutexGuard aGuard;
+
+ //get number formatter
+ uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( getModel(), uno::UNO_QUERY );
+ NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier );
+ 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( getModel() );
+ 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(),
+ getModel() ) );
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_InsertMenu_MeanValues()
+{
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_AVERAGE_LINE )),
+ m_xUndoManager );
+
+ uno::Reference< chart2::XDataSeries > xSeries =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getModel() );
+ if( xSeries.is() )
+ {
+ //if a series is selected insert mean value only for that series:
+ lcl_InsertMeanValueLine( xSeries );
+ }
+ else
+ {
+ std::vector< uno::Reference< chart2::XDataSeries > > aSeries(
+ DiagramHelper::getDataSeriesFromDiagram( ChartModelHelper::findDiagram( getModel() )));
+
+ for( const auto& xSrs : aSeries )
+ lcl_InsertMeanValueLine( xSrs );
+ }
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_InsertMenu_Trendlines()
+{
+ OUString aCID = m_aSelection.getSelectedCID();
+
+ uno::Reference< chart2::XDataSeries > xSeries =
+ ObjectIdentifier::getDataSeriesForCID( aCID, getModel() );
+
+ if( !xSeries.is() )
+ return;
+
+ executeDispatch_InsertTrendline();
+}
+
+void ChartController::executeDispatch_InsertTrendline()
+{
+ uno::Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer(
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getModel()), uno::UNO_QUERY );
+
+ if( !xRegressionCurveContainer.is() )
+ return;
+
+ UndoLiveUpdateGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_CURVE )),
+ m_xUndoManager );
+
+ uno::Reference< chart2::XRegressionCurve > xCurve =
+ RegressionCurveHelper::addRegressionCurve(
+ SvxChartRegress::Linear,
+ xRegressionCurveContainer );
+
+ uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY );
+
+ if( !xProperties.is())
+ return;
+
+ wrapper::RegressionCurveItemConverter aItemConverter(
+ xProperties, xRegressionCurveContainer, m_pDrawModelWrapper->getSdrModel().GetItemPool(),
+ m_pDrawModelWrapper->getSdrModel(),
+ uno::Reference< lang::XMultiServiceFactory >( getModel(), uno::UNO_QUERY ));
+
+ // 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( getModel() );
+ ViewElementListProvider aViewElementListProvider( m_pDrawModelWrapper.get());
+ SolarMutexGuard aGuard;
+ SchAttribTabDlg aDialog(
+ GetChartFrame(), &aItemSet, &aDialogParameter,
+ &aViewElementListProvider,
+ uno::Reference< util::XNumberFormatsSupplier >(
+ getModel(), uno::UNO_QUERY ) );
+
+ // 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( getModel() );
+ 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:
+ uno::Reference< chart2::XDataSeries > xSeries =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getModel() );
+
+ 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(
+ getModel(), xErrorBarProp, m_pDrawModelWrapper->getSdrModel().GetItemPool(),
+ m_pDrawModelWrapper->getSdrModel(),
+ uno::Reference< lang::XMultiServiceFactory >( getModel(), uno::UNO_QUERY ));
+
+ // open dialog
+ SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet();
+ aItemSet.Put(SfxBoolItem(SCHATTR_STAT_ERRORBAR_TYPE,bYError));
+ aItemConverter.FillItemSet( aItemSet );
+ ObjectPropertiesDialogParameter aDialogParameter(
+ ObjectIdentifier::createClassifiedIdentifierWithParent(
+ objType, OUString(), m_aSelection.getSelectedCID()));
+ aDialogParameter.init( getModel() );
+ ViewElementListProvider aViewElementListProvider( m_pDrawModelWrapper.get());
+ SolarMutexGuard aGuard;
+ SchAttribTabDlg aDlg(
+ GetChartFrame(), &aItemSet, &aDialogParameter,
+ &aViewElementListProvider,
+ uno::Reference< util::XNumberFormatsSupplier >(
+ getModel(), uno::UNO_QUERY ) );
+ aDlg.SetAxisMinorStepWidthForErrorBarDecimals(
+ InsertErrorBarsDialog::getAxisMinorStepWidthForErrorBarDecimals( getModel(),
+ 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( getModel() );
+ 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(
+ getModel(), m_pDrawModelWrapper->GetItemPool() );
+ SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet();
+ aItemConverter.FillItemSet( aItemSet );
+
+ //prepare and open dialog
+ SolarMutexGuard aGuard;
+ InsertErrorBarsDialog aDlg(
+ GetChartFrame(), aItemSet,
+ uno::Reference< chart2::XChartDocument >( getModel(), uno::UNO_QUERY ),
+ bYError ? ErrorBarResources::ERROR_BAR_Y : ErrorBarResources::ERROR_BAR_X);
+
+ aDlg.SetAxisMinorStepWidthForErrorBarDecimals(
+ InsertErrorBarsDialog::getAxisMinorStepWidthForErrorBarDecimals( getModel(), m_xChartView, OUString() ) );
+
+ if (aDlg.run() == RET_OK)
+ {
+ SfxItemSet aOutItemSet = aItemConverter.CreateEmptyItemSet();
+ aDlg.FillItemSet( aOutItemSet );
+
+ // lock controllers till end of block
+ ControllerLockGuardUNO aCLGuard( getModel() );
+ 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(), getModel() ), uno::UNO_QUERY );
+ if( !xRegCurve.is() )
+ {
+ uno::Reference< chart2::XRegressionCurveContainer > xRegCurveCnt(
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getModel() ), uno::UNO_QUERY );
+ 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(), getModel() );
+ 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(), getModel() );
+ 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()
+{
+ uno::Reference< chart2::XRegressionCurveContainer > xRegCurveCnt(
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getModel() ), uno::UNO_QUERY );
+ 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()
+{
+ uno::Reference< chart2::XRegressionCurveContainer > xRegCurveCnt(
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getModel() ), uno::UNO_QUERY );
+ 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()
+{
+ uno::Reference< chart2::XRegressionCurveContainer > xRegCurveCnt(
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getModel() ), uno::UNO_QUERY );
+ 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 )
+{
+ uno::Reference< chart2::XDataSeries > xDataSeries(
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getModel() ));
+ 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()
+{
+ uno::Reference< chart2::XDataSeries > xSeries =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getModel() );
+ 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(), getModel() ) );
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_DeleteDataLabels()
+{
+ uno::Reference< chart2::XDataSeries > xSeries =
+ ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getModel() );
+ 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(), getModel() ) );
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_ResetAllDataPoints()
+{
+ UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Format,
+ SchResId( STR_OBJECT_DATAPOINTS )),
+ m_xUndoManager );
+ uno::Reference< chart2::XDataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getModel() );
+ if( xSeries.is() )
+ xSeries->resetAllDataPoints();
+ aUndoGuard.commit();
+}
+void ChartController::executeDispatch_ResetDataPoint()
+{
+ UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Format,
+ SchResId( STR_OBJECT_DATAPOINT )),
+ m_xUndoManager );
+ uno::Reference< chart2::XDataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getModel() );
+ if( xSeries.is() )
+ {
+ sal_Int32 nPointIndex = ObjectIdentifier::getIndexFromParticleOrCID( m_aSelection.getSelectedCID() );
+ xSeries->resetDataPoint( nPointIndex );
+ }
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_InsertAxisTitle()
+{
+ try
+ {
+ uno::Reference< XTitle > xTitle;
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_TITLE )),
+ m_xUndoManager );
+
+ Reference< XAxis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getModel() );
+ sal_Int32 nDimensionIndex = -1;
+ sal_Int32 nCooSysIndex = -1;
+ sal_Int32 nAxisIndex = -1;
+ AxisHelper::getIndicesForAxis( xAxis, ChartModelHelper::findDiagram(getModel()), 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), getModel(), 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
+ {
+ Reference< XAxis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getModel() );
+ 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
+ {
+ Reference< XAxis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getModel() );
+ 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
+ {
+ Reference< XAxis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getModel() );
+ if( xAxis.is() )
+ {
+ AxisHelper::makeGridVisible( xAxis->getGridProperties() );
+ 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
+ {
+ Reference< XAxis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getModel() );
+ if( xAxis.is() )
+ {
+ AxisHelper::makeGridInvisible( xAxis->getGridProperties() );
+ 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
+ {
+ Reference< XAxis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getModel() );
+ if( xAxis.is() )
+ {
+ const Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() );
+ for( Reference< beans::XPropertySet > 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
+ {
+ Reference< XAxis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getModel() );
+ if( xAxis.is() )
+ {
+ const Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() );
+ for( Reference< beans::XPropertySet > 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 000000000..52664c356
--- /dev/null
+++ b/chart2/source/controller/main/ChartController_Position.cxx
@@ -0,0 +1,210 @@
+/* -*- 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 <DrawViewWrapper.hxx>
+#include <PositionAndSizeHelper.hxx>
+#include <ChartModel.hxx>
+#include <ChartModelHelper.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 <tools/diagnose_ex.h>
+#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 )
+{
+ long nPosX(0);
+ long nPosY(0);
+ long nSizX(0);
+ long nSizY(0);
+
+ RectPoint eRP = RectPoint::LT;
+
+ const SfxPoolItem* pPoolItem=nullptr;
+ //read position
+ if (rItemSet.GetItemState(SID_ATTR_TRANSFORM_POS_X,true,&pPoolItem)==SfxItemState::SET)
+ nPosX= static_cast<const SfxInt32Item*>(pPoolItem)->GetValue();
+ if (rItemSet.GetItemState(SID_ATTR_TRANSFORM_POS_Y,true,&pPoolItem)==SfxItemState::SET)
+ nPosY=static_cast<const SfxInt32Item*>(pPoolItem)->GetValue();
+ //read size
+ if (rItemSet.GetItemState(SID_ATTR_TRANSFORM_WIDTH,true,&pPoolItem)==SfxItemState::SET)
+ nSizX=static_cast<const SfxUInt32Item*>(pPoolItem)->GetValue();
+ if (rItemSet.GetItemState(SID_ATTR_TRANSFORM_HEIGHT,true,&pPoolItem)==SfxItemState::SET)
+ nSizY=static_cast<const SfxUInt32Item*>(pPoolItem)->GetValue();
+ if (rItemSet.GetItemState(SID_ATTR_TRANSFORM_SIZE_POINT,true,&pPoolItem)==SfxItemState::SET)
+ eRP=static_cast<RectPoint>(static_cast<const SfxUInt16Item*>(pPoolItem)->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;
+
+ sal_uInt16 nWhich;
+ for (const auto& aProp: *pArgs)
+ {
+ sal_Int32 nValue = 0;
+ aProp.Value >>= nValue;
+ if (aProp.Name == "TransformPosX") {
+ nWhich = pPool->GetWhich(SID_ATTR_TRANSFORM_POS_X);
+ aItemSet.Put(SfxInt32Item(nWhich, nValue));
+ }
+ else if (aProp.Name == "TransformPosY") {
+ nWhich = pPool->GetWhich(SID_ATTR_TRANSFORM_POS_Y);
+ aItemSet.Put(SfxInt32Item(nWhich, nValue));
+ }
+ else if (aProp.Name == "TransformWidth") {
+ nWhich = pPool->GetWhich(SID_ATTR_TRANSFORM_WIDTH);
+ aItemSet.Put(SfxUInt32Item(nWhich, static_cast<sal_uInt32>(nValue)));
+ }
+ else if (aProp.Name == "TransformHeight") {
+ nWhich = pPool->GetWhich(SID_ATTR_TRANSFORM_HEIGHT);
+ aItemSet.Put(SfxUInt32Item(nWhich, static_cast<sal_uInt32>(nValue)));
+ }
+ }
+ }
+
+ if(pOutItemSet || pArgs)
+ {
+ awt::Rectangle aOldObjectRect;
+ ExplicitValueProvider* pProvider(comphelper::getUnoTunnelImplementation<ExplicitValueProvider>( m_xChartView ));
+ if( pProvider )
+ aOldObjectRect = pProvider->getRectangleOfObject(aCID);
+
+ awt::Rectangle aNewObjectRect;
+ lcl_getPositionAndSizeFromItemSet( aItemSet, aNewObjectRect, ToSize(aOldObjectRect) );
+ awt::Size aPageSize( ChartModelHelper::getPageSize( getModel() ) );
+ awt::Rectangle aPageRect( 0,0,aPageSize.Width,aPageSize.Height );
+
+ bool bChanged = false;
+ if ( eObjectType == OBJECTTYPE_LEGEND )
+ {
+ ChartModel& rModel = dynamic_cast<ChartModel&>(*getModel());
+ bChanged = DiagramHelper::switchDiagramPositioningToExcludingPositioning(rModel, false , true);
+ }
+
+ bool bMoved = PositionAndSizeHelper::moveObject( m_aSelection.getSelectedCID(), getModel()
+ , 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 000000000..587cbbfc0
--- /dev/null
+++ b/chart2/source/controller/main/ChartController_Properties.cxx
@@ -0,0 +1,829 @@
+/* -*- 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 <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 <RegressionCurveItemConverter.hxx>
+#include <RegressionEquationItemConverter.hxx>
+#include <ErrorBarItemConverter.hxx>
+#include <ChartModelHelper.hxx>
+#include <AxisHelper.hxx>
+#include <TitleHelper.hxx>
+#include <ChartTypeHelper.hxx>
+#include <ColorPerPointHelper.hxx>
+#include <DiagramHelper.hxx>
+#include <ControllerLockGuard.hxx>
+#include "UndoGuard.hxx"
+#include <ObjectNameProvider.hxx>
+#include <ResId.hxx>
+#include <strings.hrc>
+#include <ReferenceSizeProvider.hxx>
+#include <RegressionCurveHelper.hxx>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
+#include <comphelper/servicehelper.hxx>
+
+#include <memory>
+
+#include <vcl/svapp.hxx>
+#include <svx/ActionDescriptionProvider.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace chart
+{
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::chart2;
+using ::com::sun::star::uno::Reference;
+
+namespace
+{
+
+wrapper::ItemConverter* createItemConverter(
+ const OUString & aObjectCID, const uno::Reference<frame::XModel>& 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;
+ }
+
+ OUString aParticleID = ObjectIdentifier::getParticleID( aObjectCID );
+ bool bAffectsMultipleObjects = aParticleID == "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, uno::Reference< lang::XMultiServiceFactory >( xChartModel, uno::UNO_QUERY ),
+ 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,
+ uno::Reference<lang::XMultiServiceFactory>(xChartModel, uno::UNO_QUERY),
+ 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,
+ uno::Reference<lang::XMultiServiceFactory>(xChartModel, uno::UNO_QUERY),
+ 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, uno::Reference< lang::XMultiServiceFactory >( xChartModel, uno::UNO_QUERY ),
+ wrapper::GraphicObjectType::LineAndFillProperties );
+ break;
+ case OBJECTTYPE_AXIS:
+ {
+ std::unique_ptr<awt::Size> pRefSize;
+ if (pRefSizeProvider)
+ pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize()));
+
+ uno::Reference< beans::XPropertySet > xDiaProp;
+ xDiaProp.set( ChartModelHelper::findDiagram( xChartModel ), uno::UNO_QUERY );
+
+ // 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(
+ uno::Reference< XAxis >( xObjectProperties, uno::UNO_QUERY ),
+ aExplicitScale, aExplicitIncrement );
+
+ pItemConverter = new wrapper::AxisItemConverter(
+ xObjectProperties, rDrawModel.GetItemPool(),
+ rDrawModel,
+ uno::Reference< chart2::XChartDocument >( xChartModel, uno::UNO_QUERY ),
+ &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()));
+
+ uno::Reference<XDataSeries> xSeries = ObjectIdentifier::getDataSeriesForCID(aObjectCID, xChartModel);
+
+ bool bDataSeries = eObjectType == OBJECTTYPE_DATA_LABELS;
+
+ sal_Int32 nNumberFormat = ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( xObjectProperties );
+ sal_Int32 nPercentNumberFormat = ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel(
+ xObjectProperties,uno::Reference<util::XNumberFormatsSupplier>(xChartModel, uno::UNO_QUERY));
+
+ 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;
+
+ uno::Reference< XDataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( aObjectCID, xChartModel );
+ uno::Reference< XChartType > xChartType = ChartModelHelper::getChartTypeOfSeries( xChartModel, xSeries );
+
+ uno::Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) );
+ sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram );
+ 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 = aParticleID.toInt32();
+ uno::Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY );
+ bool bVaryColorsByPoint = false;
+ if( xSeriesProp.is() &&
+ (xSeriesProp->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint) &&
+ bVaryColorsByPoint )
+ {
+ if( !ColorPerPointHelper::hasPointOwnColor( xSeriesProp, 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,uno::Reference< util::XNumberFormatsSupplier >(xChartModel, uno::UNO_QUERY));
+
+ pItemConverter = new wrapper::DataPointItemConverter( xChartModel, xContext,
+ xObjectProperties, xSeries, rDrawModel.GetItemPool(), rDrawModel,
+ uno::Reference< lang::XMultiServiceFactory >( xChartModel, uno::UNO_QUERY ),
+ 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, uno::Reference< lang::XMultiServiceFactory >( xChartModel, uno::UNO_QUERY ),
+ 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, uno::Reference< lang::XMultiServiceFactory >( xChartModel, uno::UNO_QUERY ));
+ break;
+
+ case OBJECTTYPE_DATA_CURVE:
+ pItemConverter = new wrapper::RegressionCurveItemConverter(
+ xObjectProperties, uno::Reference< chart2::XRegressionCurveContainer >(
+ ObjectIdentifier::getDataSeriesForCID( aObjectCID, xChartModel ), uno::UNO_QUERY ),
+ rDrawModel.GetItemPool(), rDrawModel,
+ uno::Reference< lang::XMultiServiceFactory >( xChartModel, uno::UNO_QUERY ));
+ 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,
+ uno::Reference< lang::XMultiServiceFactory >( xChartModel, uno::UNO_QUERY ),
+ 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, uno::Reference< lang::XMultiServiceFactory >( xChartModel, uno::UNO_QUERY ),
+ wrapper::GraphicObjectType::LineAndFillProperties );
+ 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, uno::Reference< lang::XMultiServiceFactory >( xChartModel, uno::UNO_QUERY ));
+ 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, uno::Reference< lang::XMultiServiceFactory >( xChartModel, uno::UNO_QUERY ));
+ break;
+ default: //for this type it is not supported to change all elements at once
+ break;
+ }
+
+ }
+ return pItemConverter;
+}
+
+OUString lcl_getTitleCIDForCommand( const OString& rDispatchCommand, const uno::Reference< frame::XModel > & xChartModel )
+{
+ if( rDispatchCommand == "AllTitles")
+ return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_TITLE, "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;
+
+ uno::Reference< XTitle > xTitle( TitleHelper::getTitle( nTitleType, xChartModel ) );
+ return ObjectIdentifier::createClassifiedIdentifierForObject( xTitle, xChartModel );
+}
+
+OUString lcl_getAxisCIDForCommand( const OString& rDispatchCommand, const uno::Reference< frame::XModel >& xChartModel )
+{
+ if( rDispatchCommand == "DiagramAxisAll")
+ return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_AXIS, "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;
+ }
+
+ uno::Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) );
+ uno::Reference< XAxis > xAxis( AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ) );
+ return ObjectIdentifier::createClassifiedIdentifierForObject( xAxis, xChartModel );
+}
+
+OUString lcl_getGridCIDForCommand( const OString& rDispatchCommand, const uno::Reference< frame::XModel >& xChartModel )
+{
+ uno::Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) );
+
+ if( rDispatchCommand == "DiagramGridAll")
+ return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_GRID, "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;
+ }
+
+ uno::Reference< XAxis > 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, OUString(), rSelectedCID );
+}
+
+OUString lcl_getObjectCIDForCommand( const OString& rDispatchCommand, const uno::Reference< XChartDocument > & xChartDocument, const OUString& rSelectedCID )
+{
+ ObjectType eObjectType = OBJECTTYPE_UNKNOWN;
+
+ uno::Reference< frame::XModel > xChartModel = xChartDocument;
+ const ObjectType eSelectedType = ObjectIdentifier::getObjectType( rSelectedCID );
+ uno::Reference< XDataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rSelectedCID, xChartModel );
+ uno::Reference< chart2::XRegressionCurveContainer > xRegCurveCnt( xSeries, uno::UNO_QUERY );
+
+ //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, xChartModel );
+ }
+ //axis
+ else if( rDispatchCommand == "DiagramAxisX"
+ || rDispatchCommand == "DiagramAxisY"
+ || rDispatchCommand == "DiagramAxisZ"
+ || rDispatchCommand == "DiagramAxisA"
+ || rDispatchCommand == "DiagramAxisB"
+ || rDispatchCommand == "DiagramAxisAll"
+ )
+ {
+ return lcl_getAxisCIDForCommand( rDispatchCommand, xChartModel );
+ }
+ //grid
+ else if( rDispatchCommand == "DiagramGridYMain"
+ || rDispatchCommand == "DiagramGridXMain"
+ || rDispatchCommand == "DiagramGridZMain"
+ || rDispatchCommand == "DiagramGridYHelp"
+ || rDispatchCommand == "DiagramGridXHelp"
+ || rDispatchCommand == "DiagramGridZHelp"
+ || rDispatchCommand == "DiagramGridAll"
+ )
+ {
+ return lcl_getGridCIDForCommand( rDispatchCommand, xChartModel );
+ }
+ //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, OUString(), rSelectedCID );
+ }
+ //data labels
+ else if( rDispatchCommand == "FormatDataLabel" )
+ {
+ if( eSelectedType == OBJECTTYPE_DATA_LABEL )
+ return rSelectedCID;
+ else
+ {
+ sal_Int32 nPointIndex = ObjectIdentifier::getParticleID( rSelectedCID ).toInt32();
+ 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, OUString(), 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( xRegCurveCnt,
+ RegressionCurveHelper::getMeanValueLine( xRegCurveCnt ) ), true );
+ }
+ //trend line
+ else if( rDispatchCommand == "FormatTrendline" )
+ {
+ if( eSelectedType == OBJECTTYPE_DATA_CURVE )
+ return rSelectedCID;
+ else
+ return ObjectIdentifier::createDataCurveCID(
+ ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ),
+ RegressionCurveHelper::getRegressionCurveIndex( xRegCurveCnt,
+ RegressionCurveHelper::getFirstCurveNotMeanValueLine( xRegCurveCnt ) ), 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( xRegCurveCnt,
+ RegressionCurveHelper::getFirstCurveNotMeanValueLine( xRegCurveCnt ) ) );
+ }
+ // 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
+ {
+ Reference< XAxis > xAxis = ObjectIdentifier::getAxisForCID( rSelectedCID, xChartModel );
+ return ObjectIdentifier::createClassifiedIdentifierForObject( xAxis , xChartModel );
+ }
+ }
+ // major grid
+ else if( rDispatchCommand == "FormatMajorGrid" )
+ {
+ if( eSelectedType == OBJECTTYPE_GRID )
+ return rSelectedCID;
+ else
+ {
+ Reference< XAxis > xAxis = ObjectIdentifier::getAxisForCID( rSelectedCID, xChartModel );
+ return ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartModel );
+ }
+
+ }
+ // minor grid
+ else if( rDispatchCommand == "FormatMinorGrid" )
+ {
+ if( eSelectedType == OBJECTTYPE_SUBGRID )
+ return rSelectedCID;
+ else
+ {
+ Reference< XAxis > xAxis = ObjectIdentifier::getAxisForCID( rSelectedCID, xChartModel );
+ return ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartModel, 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, OUString());
+ }
+ // stock gain
+ else if( rDispatchCommand == "FormatStockGain" )
+ {
+ if( eSelectedType == OBJECTTYPE_DATA_STOCK_GAIN )
+ return rSelectedCID;
+ else
+ return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DATA_STOCK_GAIN, OUString() );
+ }
+
+ return ObjectIdentifier::createClassifiedIdentifier(
+ eObjectType,
+ OUString() ); // aParticleID
+}
+
+}
+// anonymous namespace
+
+void ChartController::executeDispatch_FormatObject(const OUString& rDispatchCommand)
+{
+ uno::Reference< XChartDocument > xChartDocument( getModel(), uno::UNO_QUERY );
+ 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 )
+ {
+ OUString aParentParticle( ObjectIdentifier::getFullParentParticle( rSelectedCID ) );
+ aFormatCID = ObjectIdentifier::createClassifiedIdentifierForParticle( aParentParticle );
+ }
+
+ // treat diagram as wall
+ if( eObjectType==OBJECTTYPE_DIAGRAM )
+ aFormatCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, OUString() );
+
+ 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( !DiagramHelper::isSupportingFloorAndWall( ChartModelHelper::findDiagram( getModel() ) ) )
+ return bRet;
+ }
+
+ //convert properties to ItemSet
+
+ std::unique_ptr<ReferenceSizeProvider> pRefSizeProv(impl_createReferenceSizeProvider());
+
+ std::unique_ptr<wrapper::ItemConverter> pItemConverter(
+ createItemConverter( rObjectCID, getModel(), m_xCC,
+ m_pDrawModelWrapper->getSdrModel(),
+ comphelper::getUnoTunnelImplementation<ExplicitValueProvider>(m_xChartView),
+ 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( getModel() );
+ ViewElementListProvider aViewElementListProvider( m_pDrawModelWrapper.get() );
+
+ SolarMutexGuard aGuard;
+ SchAttribTabDlg aDlg(
+ GetChartFrame(), &aItemSet, &aDialogParameter,
+ &aViewElementListProvider,
+ uno::Reference< util::XNumberFormatsSupplier >(
+ getModel(), uno::UNO_QUERY ) );
+
+ if(aDialogParameter.HasSymbolProperties())
+ {
+ uno::Reference< beans::XPropertySet > xObjectProperties =
+ ObjectIdentifier::getObjectPropertySet( rObjectCID, getModel() );
+ wrapper::DataPointItemConverter aSymbolItemConverter( getModel(), m_xCC
+ , xObjectProperties, ObjectIdentifier::getDataSeriesForCID( rObjectCID, getModel() )
+ , m_pDrawModelWrapper->getSdrModel().GetItemPool()
+ , m_pDrawModelWrapper->getSdrModel()
+ , uno::Reference< lang::XMultiServiceFactory >( getModel(), uno::UNO_QUERY )
+ , wrapper::GraphicObjectType::FilledDataPoint );
+
+ std::unique_ptr<SfxItemSet> pSymbolShapeProperties(new SfxItemSet( aSymbolItemConverter.CreateEmptyItemSet() ));
+ aSymbolItemConverter.FillItemSet( *pSymbolShapeProperties );
+
+ sal_Int32 const nStandardSymbol=0;//@todo get from somewhere
+ std::unique_ptr<Graphic> pAutoSymbolGraphic(new Graphic( aViewElementListProvider.GetSymbolGraphic( nStandardSymbol, pSymbolShapeProperties.get() ) ));
+ // note: the dialog takes the ownership of pSymbolShapeProperties and pAutoSymbolGraphic
+ aDlg.setSymbolInformation( std::move(pSymbolShapeProperties), std::move(pAutoSymbolGraphic) );
+ }
+ if( aDialogParameter.HasStatisticProperties() )
+ {
+ aDlg.SetAxisMinorStepWidthForErrorBarDecimals(
+ InsertErrorBarsDialog::getAxisMinorStepWidthForErrorBarDecimals( getModel(), m_xChartView, rObjectCID ) );
+ }
+
+ //open the dialog
+ if (aDlg.run() == RET_OK || (bSuccessOnUnchanged && aDlg.DialogWasClosedWithOK()))
+ {
+ const SfxItemSet* pOutItemSet = aDlg.GetOutputItemSet();
+ if(pOutItemSet)
+ {
+ ControllerLockGuardUNO aCLGuard( getModel());
+ (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(), getModel());
+ 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 000000000..ae18162d8
--- /dev/null
+++ b/chart2/source/controller/main/ChartController_TextEdit.cxx
@@ -0,0 +1,220 @@
+/* -*- 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 <ResId.hxx>
+#include "UndoGuard.hxx"
+#include <DrawViewWrapper.hxx>
+#include <ChartWindow.hxx>
+#include <TitleHelper.hxx>
+#include <ObjectIdentifier.hxx>
+#include <ControllerLockGuard.hxx>
+#include <AccessibleTextHelper.hxx>
+#include <strings.hrc>
+#include <chartview/DrawModelWrapper.hxx>
+
+#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
+ uno::Reference< beans::XPropertySet > xChartViewProps( m_xChartView, uno::UNO_QUERY );
+ if( xChartViewProps.is() )
+ xChartViewProps->setPropertyValue( "SdrViewIsInEditMode", uno::Any(true) );
+
+ bool bEdit = m_pDrawViewWrapper->SdrBeginTextEdit( pTextObj
+ , m_pDrawViewWrapper->GetPageView()
+ , GetChartWindow()
+ , 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 );
+ }
+ }
+
+ //we invalidate the outliner region because the outliner has some
+ //paint problems (some characters are painted twice a little bit shifted)
+ GetChartWindow()->Invalidate( m_pDrawViewWrapper->GetMarkedObjBoundRect() );
+}
+
+bool ChartController::EndTextEdit()
+{
+ m_pDrawViewWrapper->SdrEndTextEdit();
+
+ //#i77362 change notification for changes on additional shapes are missing
+ uno::Reference< beans::XPropertySet > xChartViewProps( m_xChartView, uno::UNO_QUERY );
+ if( xChartViewProps.is() )
+ xChartViewProps->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 )
+ {
+ 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, getModel() );
+
+ // lock controllers till end of block
+ ControllerLockGuardUNO aCLGuard( getModel() );
+
+ TitleHelper::setCompleteString( aString, uno::Reference<
+ css::chart2::XTitle >::query( xPropSet ), 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();
+ const SfxPoolItem* pItem=nullptr;
+ OUString aString;
+ if (pSet && pSet->GetItemState(SID_CHARMAP, true, &pItem) == SfxItemState::SET)
+ if (auto pStringItem = dynamic_cast<const SfxStringItem*>(pItem))
+ aString = pStringItem->GetValue();
+
+ OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView();
+ SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner();
+
+ if(!pOutliner || !pOutlinerView)
+ return;
+
+ // insert string to outliner
+
+ // prevent flicker
+ pOutlinerView->HideCursor();
+ pOutliner->SetUpdateMode(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->SetUpdateMode(true);
+ pOutlinerView->ShowCursor();
+}
+
+uno::Reference< css::accessibility::XAccessibleContext >
+ ChartController::impl_createAccessibleTextContext()
+{
+ uno::Reference< css::accessibility::XAccessibleContext > xResult(
+ new AccessibleTextHelper( m_pDrawViewWrapper.get() ));
+
+ return xResult;
+}
+
+} //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 000000000..c60243504
--- /dev/null
+++ b/chart2/source/controller/main/ChartController_Tools.cxx
@@ -0,0 +1,990 @@
+/* -*- 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 <TitleHelper.hxx>
+#include <ThreeDHelper.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 <LegendHelper.hxx>
+#include <AxisHelper.hxx>
+#include <RegressionCurveHelper.hxx>
+#include "ShapeController.hxx"
+#include <DiagramHelper.hxx>
+#include <ObjectNameProvider.hxx>
+#include <unonames.hxx>
+
+#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/text/XTextRange.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 <com/sun/star/chart2/XChartDocument.hpp>
+
+#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 <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 <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+
+#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(
+ const OUString & rCID,
+ const Reference< frame::XModel > & xModel,
+ const Reference< document::XUndoManager > & xUndoManager )
+{
+ bool bResult = false;
+ uno::Reference< chart2::XDataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID( rCID, xModel ));
+ uno::Reference< chart2::XChartDocument > xChartDoc( xModel, uno::UNO_QUERY );
+ if( xSeries.is() && xChartDoc.is())
+ {
+ uno::Reference< chart2::XChartType > xChartType(
+ DataSeriesHelper::getChartTypeOfSeries( xSeries, xChartDoc->getFirstDiagram()));
+ if( xChartType.is())
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_DATASERIES )),
+ xUndoManager );
+
+ Reference< chart2::XDiagram > xDiagram( ChartModelHelper::findDiagram( xModel ) );
+ uno::Reference< chart2::XAxis > xAxis( DiagramHelper::getAttachedAxis( xSeries, xDiagram ) );
+
+ DataSeriesHelper::deleteSeries( xSeries, xChartType );
+
+ AxisHelper::hideAxisIfNoDataIsAttached( xAxis, xDiagram );
+
+ bResult = true;
+ aUndoGuard.commit();
+ }
+ }
+ return bResult;
+}
+
+bool lcl_deleteDataCurve(
+ const OUString & rCID,
+ const Reference< frame::XModel > & 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( getModel() ) );
+
+ return std::make_unique<ReferenceSizeProvider>(
+ aPageSize, Reference<chart2::XChartDocument>(getModel(), uno::UNO_QUERY));
+}
+
+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
+ {
+ Reference< frame::XModel > xModel( getModel() );
+ Reference< chart2::XDiagram > xDiagram( ChartModelHelper::findDiagram( xModel ));
+ if( xDiagram.is())
+ {
+ UndoGuard aUndoGuard(
+ SchResId( STR_ACTION_REARRANGE_CHART ),
+ m_xUndoManager );
+ ControllerLockGuardUNO aCtlLockGuard( xModel );
+
+ // diagram
+ Reference< beans::XPropertyState > xState( xDiagram, uno::UNO_QUERY_THROW );
+ xState->setPropertyToDefault( "RelativeSize");
+ xState->setPropertyToDefault( "RelativePosition");
+ xState->setPropertyToDefault( "PosSizeExcludeAxes");
+
+ // 3d rotation
+ ThreeDHelper::set3DSettingsToDefault( uno::Reference< beans::XPropertySet >( xDiagram, uno::UNO_QUERY ) );
+
+ // legend
+ Reference< beans::XPropertyState > xLegendState( xDiagram->getLegend(), uno::UNO_QUERY );
+ if( xLegendState.is())
+ {
+ xLegendState->setPropertyToDefault( "RelativePosition");
+ xLegendState->setPropertyToDefault( "RelativeSize");
+ xLegendState->setPropertyToDefault( "AnchorPosition");
+ }
+
+ // titles
+ for( sal_Int32 eType = TitleHelper::TITLE_BEGIN;
+ eType < TitleHelper::NORMAL_TITLE_END;
+ ++eType )
+ {
+ Reference< beans::XPropertyState > xTitleState(
+ TitleHelper::getTitle(
+ static_cast< TitleHelper::eTitleType >( eType ), xModel ), uno::UNO_QUERY );
+ if( xTitleState.is())
+ xTitleState->setPropertyToDefault( "RelativePosition");
+ }
+
+ // regression curve equations
+ std::vector< Reference< chart2::XRegressionCurve > > aRegressionCurves(
+ RegressionCurveHelper::getAllRegressionCurvesNotMeanValueLine( xDiagram ));
+
+ // 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( getModel() );
+
+ 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( {}, pChartWindow->GetSizePixel()).Center());
+
+ // handle different formats
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pChartWindow ));
+ if( aDataHelper.GetTransferable().is())
+ {
+ if ( aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ) )
+ {
+ tools::SvRef<SotStorageStream> 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<SotStorageStream> xStm;
+ if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::SVXB, xStm ))
+ ReadGraphic( *xStm, 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.
+ uno::Reference< beans::XPropertySet > xModelProp( getModel(), uno::UNO_QUERY );
+ DrawModelWrapper * pDrawModelWrapper( GetDrawModelWrapper());
+ if( ! (xGraphic.is() && xModelProp.is()))
+ return;
+ uno::Reference< lang::XMultiServiceFactory > xFact( pDrawModelWrapper->getShapeFactory());
+ uno::Reference< drawing::XShape > xGraphicShape(
+ xFact->createInstance( "com.sun.star.drawing.GraphicObjectShape" ), uno::UNO_QUERY );
+ uno::Reference< beans::XPropertySet > xGraphicShapeProp( xGraphicShape, uno::UNO_QUERY );
+ if( !(xGraphicShapeProp.is() && xGraphicShape.is()))
+ return;
+
+ uno::Reference< drawing::XShapes > xPage = pDrawModelWrapper->getMainDrawPage();
+ if( xPage.is())
+ {
+ xPage->add( xGraphicShape );
+ //need to change the model state manually
+ {
+ uno::Reference< util::XModifiable > xModifiable( getModel(), uno::UNO_QUERY );
+ if( xModifiable.is() )
+ xModifiable->setModified( true );
+ }
+ //select new shape
+ m_aSelection.setSelection( xGraphicShape );
+ m_aSelection.applySelection( m_pDrawViewWrapper.get() );
+ }
+ xGraphicShapeProp->setPropertyValue( "Graphic", uno::Any( xGraphic ));
+ uno::Reference< beans::XPropertySet > xGraphicProp( xGraphic, uno::UNO_QUERY );
+
+ awt::Size aGraphicSize( 1000, 1000 );
+ auto pChartWindow(GetChartWindow());
+ // first try size in 100th mm, then pixel size
+ if( ! ( xGraphicProp->getPropertyValue( "Size100thMM") >>= aGraphicSize ) &&
+ ( ( xGraphicProp->getPropertyValue( "SizePixel") >>= aGraphicSize ) && 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
+ SdrObject* pNewObj(pObj ? pObj->CloneSdrObject(pDrawModelWrapper->getSdrModel()) : nullptr);
+
+ 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 );
+ m_pDrawViewWrapper->AddUndo( std::make_unique<SdrUndoInsertObj>( *pNewObj ) );
+ xSelShape = xShape;
+ }
+ }
+ }
+
+ Reference< util::XModifiable > xModifiable( getModel(), uno::UNO_QUERY );
+ 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< lang::XMultiServiceFactory >& xShapeFactory( pDrawModelWrapper->getShapeFactory() );
+ const Reference< drawing::XDrawPage >& xDrawPage( pDrawModelWrapper->getMainDrawPage() );
+ OSL_ASSERT( xShapeFactory.is() && xDrawPage.is() );
+
+ if ( !(xShapeFactory.is() && xDrawPage.is()) )
+ return;
+
+ try
+ {
+ Reference< drawing::XShape > xTextShape(
+ xShapeFactory->createInstance( "com.sun.star.drawing.TextShape" ), uno::UNO_QUERY_THROW );
+ xDrawPage->add( xTextShape );
+
+ Reference< text::XTextRange > xRange( xTextShape, uno::UNO_QUERY_THROW );
+ xRange->setString( rString );
+
+ float fCharHeight = 10.0;
+ Reference< beans::XPropertySet > xProperties( xTextShape, uno::UNO_QUERY_THROW );
+ xProperties->setPropertyValue( "TextAutoGrowHeight", uno::Any( true ) );
+ xProperties->setPropertyValue( "TextAutoGrowWidth", uno::Any( true ) );
+ xProperties->setPropertyValue( "CharHeight", uno::Any( fCharHeight ) );
+ xProperties->setPropertyValue( "CharHeightAsian", uno::Any( fCharHeight ) );
+ xProperties->setPropertyValue( "CharHeightComplex", uno::Any( fCharHeight ) );
+ xProperties->setPropertyValue( "TextVerticalAdjust", uno::Any( drawing::TextVerticalAdjust_CENTER ) );
+ xProperties->setPropertyValue( "TextHorizontalAdjust", uno::Any( drawing::TextHorizontalAdjust_CENTER ) );
+ xProperties->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() == OBJ_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
+ uno::Reference< chart2::XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
+ 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 ), getModel() );
+ bReturn = true;
+ aUndoGuard.commit();
+ break;
+ }
+ case OBJECTTYPE_LEGEND:
+ {
+ uno::Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram());
+ if( xDiagram.is())
+ {
+ uno::Reference< beans::XPropertySet > xLegendProp( xDiagram->getLegend(), uno::UNO_QUERY );
+ if( xLegendProp.is())
+ {
+ UndoGuard aUndoGuard(
+ ActionDescriptionProvider::createDescription(
+ ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_LEGEND )),
+ m_xUndoManager );
+ xLegendProp->setPropertyValue( "Show", uno::Any( false ));
+ bReturn = true;
+ aUndoGuard.commit();
+ }
+ }
+ break;
+ }
+
+ case OBJECTTYPE_DATA_SERIES:
+ bReturn = lcl_deleteDataSeries( aCID, getModel(), m_xUndoManager );
+ break;
+
+ case OBJECTTYPE_LEGEND_ENTRY:
+ {
+ ObjectType eParentObjectType = ObjectIdentifier::getObjectType(
+ ObjectIdentifier::getFullParentParticle( aCID ));
+ if( eParentObjectType == OBJECTTYPE_DATA_SERIES )
+ {
+ bReturn = lcl_deleteDataSeries( aCID, getModel(), m_xUndoManager );
+ }
+ else if( eParentObjectType == OBJECTTYPE_DATA_CURVE )
+ {
+ sal_Int32 nEndPos = aCID.lastIndexOf(':');
+ OUString aParentCID = aCID.copy(0, nEndPos);
+
+ bReturn = lcl_deleteDataCurve(aParentCID, getModel(), 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 ), getModel()), 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, getModel(), m_xUndoManager );
+ }
+ break;
+
+ case OBJECTTYPE_DATA_CURVE_EQUATION:
+ {
+ uno::Reference< beans::XPropertySet > xEqProp(
+ ObjectIdentifier::getObjectPropertySet( aCID, getModel()));
+
+ if( xEqProp.is())
+ {
+ uno::Reference< frame::XModel > xModel( getModel() );
+ 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, getModel() ));
+ if( xErrorBarProp.is())
+ {
+ const char* 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;
+
+ uno::Reference< frame::XModel > xModel( getModel() );
+ 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, getModel() );
+ 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;
+ if( aObjectType == OBJECTTYPE_DATA_LABELS )
+ {
+ uno::Reference< chart2::XDataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID( aCID, getModel() ));
+ ::chart::DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, CHART_UNONAME_LABEL, uno::Any(aLabel) );
+ }
+ else
+ xObjectProperties->setPropertyValue( CHART_UNONAME_LABEL, uno::Any(aLabel) );
+ 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()
+{
+ Reference< frame::XModel > xModel( getModel() );
+ UndoGuard aUndoGuard(
+ SchResId( STR_ACTION_TOGGLE_LEGEND ), m_xUndoManager );
+ ChartModel& rModel = dynamic_cast<ChartModel&>(*xModel);
+ Reference< beans::XPropertySet > xLegendProp( LegendHelper::getLegend(rModel), uno::UNO_QUERY );
+ 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.set( LegendHelper::getLegend(rModel, m_xCC, true), uno::UNO_QUERY );
+ if( xLegendProp.is())
+ bChanged = true;
+ }
+
+ if( bChanged )
+ aUndoGuard.commit();
+}
+
+void ChartController::executeDispatch_ToggleGridHorizontal()
+{
+ UndoGuard aUndoGuard(
+ SchResId( STR_ACTION_TOGGLE_GRID_HORZ ), m_xUndoManager );
+ Reference< chart2::XDiagram > xDiagram( ChartModelHelper::findDiagram( getModel() ));
+ 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 );
+ Reference< chart2::XDiagram > xDiagram( ChartModelHelper::findDiagram( getModel() ));
+ 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_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() );
+ const uno::Reference< frame::XModel >& xChartModel = getModel();
+ 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 );
+ ChartModel& rModel = dynamic_cast<ChartModel&>(*m_aModel->getModel());
+ if (DiagramHelper::switchDiagramPositioningToExcludingPositioning(rModel, 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 000000000..cdf7e02aa
--- /dev/null
+++ b/chart2/source/controller/main/ChartController_Window.cxx
@@ -0,0 +1,2121 @@
+/* -*- 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 <PositionAndSizeHelper.hxx>
+#include <ObjectIdentifier.hxx>
+#include <ChartWindow.hxx>
+#include <ResId.hxx>
+#include <ChartModel.hxx>
+#include <ChartModelHelper.hxx>
+#include <DiagramHelper.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 <StatisticsHelper.hxx>
+#include <DataSeriesHelper.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/XRegressionCurveContainer.hpp>
+#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
+#include <com/sun/star/chart2/XChartDocument.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 <com/sun/star/qa/XDumper.hpp>
+
+#include <comphelper/lok.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <toolkit/awt/vclxmenu.hxx>
+
+#include <sfx2/viewsh.hxx>
+#include <sfx2/ipclient.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 <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+
+#include <sfx2/lokhelper.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 ::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( const OUString& 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( getModel() );
+ 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%
+ uno::Reference< beans::XPropertySet > xProp( m_xChartView, uno::UNO_QUERY );
+ if( xProp.is() )
+ {
+ auto aZoomFactors(::comphelper::InitPropertySequence({
+ { "ScaleXNumerator", uno::Any( nScaleXNumerator ) },
+ { "ScaleXDenominator", uno::Any( nScaleXDenominator ) },
+ { "ScaleYNumerator", uno::Any( nScaleYNumerator ) },
+ { "ScaleYDenominator", uno::Any( nScaleYDenominator ) }
+ }));
+ xProp->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->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
+ {
+ uno::Reference<frame::XModel> xModel(getModel());
+ //OSL_ENSURE( xModel.is(), "ChartController::execute_Paint: have no model to paint");
+ if (!xModel.is())
+ return;
+
+ //better performance for big data
+ uno::Reference<beans::XPropertySet> xProp(m_xChartView, uno::UNO_QUERY);
+ if (xProp.is())
+ {
+ awt::Size aResolution(1000, 1000);
+ {
+ SolarMutexGuard aGuard;
+ auto pChartWindow(GetChartWindow());
+ if (pChartWindow)
+ {
+ aResolution.Width = pChartWindow->GetSizePixel().Width();
+ aResolution.Height = pChartWindow->GetSizePixel().Height();
+ }
+ }
+ xProp->setPropertyValue( "Resolution", uno::Any( aResolution ));
+ }
+
+ uno::Reference< util::XUpdatable > xUpdatable( m_xChartView, uno::UNO_QUERY );
+ if (xUpdatable.is())
+ xUpdatable->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);
+ 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() == OBJ_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( getModel() ) )
+ {
+ 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(), getModel(), eRotationDirection );
+ }
+ }
+ else
+ {
+ OUString aDragMethodServiceName( ObjectIdentifier::getDragMethodServiceName( m_aSelection.getSelectedCID() ) );
+ if( aDragMethodServiceName == ObjectIdentifier::getPieSegmentDragMethodServiceName() )
+ pDragMethod = new DragMethod_PieSegment( *pDrawViewWrapper, m_aSelection.getSelectedCID(), getModel() );
+ }
+ 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) )
+ return;
+ }
+
+ if(pDrawViewWrapper->IsAction())
+ {
+ pDrawViewWrapper->MovAction( pChartWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+ }
+
+ impl_SetMousePointer( rMEvt );
+}
+
+void ChartController::execute_MouseButtonUp( const MouseEvent& rMEvt )
+{
+ ControllerLockGuardUNO aCLGuard( getModel() );
+ 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) )
+ 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() == OBJ_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( getModel() ) );
+ tools::Rectangle aPageRect( 0,0,aPageSize.Width,aPageSize.Height );
+
+ const E3dObject* pE3dObject(dynamic_cast< const E3dObject*>(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;
+ ChartModel* pModel = dynamic_cast<ChartModel*>(getModel().get());
+ assert(pModel);
+ if ( eObjectType == OBJECTTYPE_LEGEND )
+ bChanged = DiagramHelper::switchDiagramPositioningToExcludingPositioning( *pModel, false , true );
+
+ bool bMoved = PositionAndSizeHelper::moveObject( m_aSelection.getSelectedCID()
+ , getModel()
+ , awt::Rectangle(aObjectRect.getX(),aObjectRect.getY(),aObjectRect.getWidth(),aObjectRect.getHeight())
+ , awt::Rectangle(aOldObjectRect.getX(), aOldObjectRect.getY(), 0, 0)
+ , awt::Rectangle(aPageRect.getX(),aPageRect.getY(),aPageRect.getWidth(),aPageRect.getHeight()) );
+
+ 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( getModel() );
+
+ //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 ( dynamic_cast< const SdrTextObj* >(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();
+
+ css::uno::Reference< css::awt::XPopupMenu > xPopupMenu( m_xCC->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.awt.PopupMenu", m_xCC ), css::uno::UNO_QUERY );
+
+ 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() ? OUStringLiteral( "drawtext" ) : OUStringLiteral( "draw" );
+ else
+ {
+ // todo: the context menu should be specified by an xml file in uiconfig
+ if( xPopupMenu.is())
+ {
+ sal_Int16 nUniqueId = 1;
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:Cut" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:Copy" );
+ lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:Paste" );
+ xPopupMenu->insertSeparator( -1 );
+
+ ObjectType eObjectType = ObjectIdentifier::getObjectType( m_aSelection.getSelectedCID() );
+ Reference< XDiagram > xDiagram = ChartModelHelper::findDiagram( getModel() );
+
+ 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 );
+ uno::Reference< XDataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getModel() );
+ uno::Reference< chart2::XRegressionCurveContainer > xCurveCnt( xSeries, uno::UNO_QUERY );
+ Reference< chart2::XRegressionCurve > xTrendline( RegressionCurveHelper::getFirstCurveNotMeanValueLine( xCurveCnt ) );
+ bool bHasEquation = RegressionCurveHelper::hasEquation( xTrendline );
+ Reference< chart2::XRegressionCurve > xMeanValue( RegressionCurveHelper::getMeanValueLine( xCurveCnt ) );
+ 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;
+
+ Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY );
+ if( xSeriesProperties.is() )
+ {
+ uno::Sequence< sal_Int32 > aAttributedDataPointIndexList;
+ if( xSeriesProperties->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList )
+ {
+ if( aAttributedDataPointIndexList.hasElements() )
+ {
+ if( bIsPoint )
+ {
+ auto aIndices( comphelper::sequenceToContainer<std::vector< sal_Int32 >>( aAttributedDataPointIndexList ) );
+ std::vector< sal_Int32 >::iterator aIt = std::find( aIndices.begin(), aIndices.end(), nPointIndex );
+ if( aIt != aIndices.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" );
+ }
+
+ Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram, xSeries ) );
+ if( xChartType->getChartType() == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK )
+ {
+ try
+ {
+ Reference< beans::XPropertySet > xChartTypeProp( xChartType, uno::UNO_QUERY );
+ if( xChartTypeProp.is() )
+ {
+ bool bJapaneseStyle = false;
+ xChartTypeProp->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" );
+ uno::Reference< awt::XPopupMenu > xArrangePopupMenu(
+ m_xCC->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.awt.PopupMenu", m_xCC ), uno::UNO_QUERY );
+ if( xArrangePopupMenu.is() )
+ {
+ 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 )
+ {
+ Reference< XAxis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getModel() );
+ 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 = false;
+ uno::Reference< XTitled > xTitled( xAxis, uno::UNO_QUERY );
+ if( xTitled.is())
+ bHasTitle = !TitleHelper::getCompleteString( xTitled->getTitleObject() ).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( 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( 3 );
+ aArgs[0] <<= comphelper::makePropertyValue( "IsContextMenu", true );
+ aArgs[1] <<= comphelper::makePropertyValue( "Frame", m_xFrame );
+ aArgs[2] <<= 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())
+ {
+ PopupMenu* pPopupMenu = static_cast<PopupMenu*>(comphelper::getUnoTunnelImplementation<VCLXMenu>(xPopupMenu)->GetMenu());
+ ControllerCommandDispatch* pCommandDispatch = dynamic_cast<ControllerCommandDispatch*>(m_aDispatchContainer.getChartDispatcher().get());
+ if(pCommandDispatch)
+ {
+ for (sal_uInt16 nPos = 0; nPos < pPopupMenu->GetItemCount(); nPos++)
+ {
+ const sal_uInt16 nItemId = pPopupMenu->GetItemId(nPos);
+ OUString aCommandURL = pPopupMenu->GetItemCommand(nItemId);
+ if(!pCommandDispatch->commandAvailable(aCommandURL))
+ pPopupMenu->EnableItem(nItemId, false);
+ }
+ }
+
+ boost::property_tree::ptree aMenu = SfxDispatcher::fillPopupMenu(pPopupMenu);
+ 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, aStream.str().c_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
+ if( m_pDrawViewWrapper )
+ 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)
+ uno::Reference< XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
+ ObjectKeyNavigation aObjNav( m_aSelection.getSelectedOID(), xChartDoc, comphelper::getUnoTunnelImplementation<ExplicitValueProvider>( m_xChartView ));
+ 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(), getModel() ) )
+ {
+ 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;
+ OUString 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(getModel()));
+ if ((fShiftAmountX > 0.0 && (aRect.getX() + fShiftAmountX + aRect.getWidth() > aPageSize.Width)) ||
+ (fShiftAmountX < 0.0 && (aRect.getX() + fShiftAmountX < 0)) ||
+ (fShiftAmountY > 0.0 && (aRect.getY() + fShiftAmountY + aRect.getHeight() > aPageSize.Height)) ||
+ (fShiftAmountY < 0.0 && (aRect.getY() + fShiftAmountY < 0)))
+ bReturn = false;
+ else
+ bReturn = PositionAndSizeHelper::moveObject(
+ m_aSelection.getSelectedCID(), getModel(),
+ awt::Rectangle(aRect.getX() + fShiftAmountX, aRect.getY() + fShiftAmountY, aRect.getWidth(), aRect.getHeight()),
+ awt::Rectangle(aRect.getX(), aRect.getY(), 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( getModel() ) );
+ aPos.X = static_cast< long >( static_cast< double >( aPos.X ) + fShiftAmountX );
+ aPos.Y = static_cast< 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)
+ {
+ uno::Reference< qa::XDumper > xChartModel( getModel(), uno::UNO_QUERY );
+ if(xChartModel.is())
+ {
+ OUString aDump = xChartModel->dump();
+ 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 )
+{
+ uno::Reference< frame::XModel > xChartModel;
+ if( m_aModel.is())
+ xChartModel.set( getModel() );
+ 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
+ ExplicitValueProvider * pValueProvider(
+ comphelper::getUnoTunnelImplementation<ExplicitValueProvider>( m_xChartView ));
+ if( pValueProvider )
+ rOutEqualRect = pValueProvider->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
+ m_aLifeTimeManager.m_aListenerContainer.addInterface( cppu::UnoType<view::XSelectionChangeListener>::get(), 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
+ m_aLifeTimeManager.m_aListenerContainer.removeInterface( cppu::UnoType<view::XSelectionChangeListener>::get(), xListener );
+}
+
+void ChartController::impl_notifySelectionChangeListeners()
+{
+ ::cppu::OInterfaceContainerHelper* pIC = m_aLifeTimeManager.m_aListenerContainer
+ .getContainer( cppu::UnoType<view::XSelectionChangeListener>::get() );
+ if( pIC )
+ {
+ uno::Reference< view::XSelectionSupplier > xSelectionSupplier(this);
+ lang::EventObject aEvent( xSelectionSupplier );
+ ::cppu::OInterfaceIteratorHelper aIt( *pIC );
+ while( aIt.hasMoreElements() )
+ {
+ uno::Reference< view::XSelectionChangeListener > xListener( aIt.next(), uno::UNO_QUERY );
+ if( xListener.is() )
+ xListener->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 );
+
+ uno::Reference< frame::XModel > xChartModel( getModel() );
+ 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(
+ comphelper::getUnoTunnelImplementation<ExplicitValueProvider>( m_xChartView ));
+ 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( const OUString & rCID, double fAdditionalOffset )
+{
+ bool bResult = false;
+ if( fAdditionalOffset < -1.0 || fAdditionalOffset > 1.0 || fAdditionalOffset == 0.0 )
+ return bResult;
+
+ sal_Int32 nDataPointIndex = ObjectIdentifier::getIndexFromParticleOrCID( rCID );
+ uno::Reference< chart2::XDataSeries > xSeries(
+ ObjectIdentifier::getDataSeriesForCID( rCID, getModel() ));
+ 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, 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, 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 = static_cast< SdrObjKind >( m_pDrawViewWrapper->GetCurrentObjIdentifier() );
+ switch ( eKind )
+ {
+ case OBJ_LINE:
+ {
+ ePointerStyle = PointerStyle::DrawLine;
+ }
+ break;
+ case OBJ_RECT:
+ case OBJ_CUSTOMSHAPE:
+ {
+ ePointerStyle = PointerStyle::DrawRect;
+ }
+ break;
+ case OBJ_CIRC:
+ {
+ ePointerStyle = PointerStyle::DrawEllipse;
+ }
+ break;
+ case OBJ_FREELINE:
+ {
+ ePointerStyle = PointerStyle::DrawPolygon;
+ }
+ break;
+ case OBJ_TEXT:
+ {
+ ePointerStyle = PointerStyle::DrawText;
+ }
+ break;
+ case OBJ_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
+ , getModel() ) )
+ 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 );
+}
+
+css::uno::Reference<css::uno::XInterface> const & ChartController::getChartView() const
+{
+ return m_xChartView;
+}
+
+void ChartController::sendPopupRequest(OUString const & rCID, tools::Rectangle aRectangle)
+{
+ ChartModel* pChartModel = dynamic_cast<ChartModel*>(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();
+
+ PopupRequest* pPopupRequest = dynamic_cast<PopupRequest*>(pChartModel->getPopupRequest().get());
+ if (!pPopupRequest)
+ return;
+
+ // Get dimension index from CID
+ sal_Int32 nStartPos = rCID.lastIndexOf('.');
+ nStartPos++;
+ sal_Int32 nEndPos = rCID.getLength();
+ OUString sDimensionIndex = rCID.copy(nStartPos, nEndPos - nStartPos);
+ sal_Int32 nDimensionIndex = sDimensionIndex.toInt32();
+
+ 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::makeAny<awt::Rectangle>(xRectangle)},
+ {"DimensionIndex", uno::makeAny<sal_Int32>(nDimensionIndex)},
+ {"PivotTableName", uno::makeAny<OUString>(sPivotTableName)},
+ });
+
+ pPopupRequest->getCallback()->notify(uno::makeAny(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 000000000..15272dfc5
--- /dev/null
+++ b/chart2/source/controller/main/ChartDropTargetHelper.cxx
@@ -0,0 +1,176 @@
+/* -*- 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 <DataSourceHelper.hxx>
+
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/chart2/data/XDataProvider.hpp>
+#include <com/sun/star/container/XChild.hpp>
+
+#include <sot/formats.hxx>
+#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,
+ const Reference< chart2::XChartDocument > & xChartDocument ) :
+ DropTargetHelper( rxDropTarget ),
+ m_xChartDocument( 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] );
+ Reference< container::XChild > xChild( m_xChartDocument, uno::UNO_QUERY );
+ if( xChild.is())
+ {
+ Reference< frame::XModel > xParentModel( xChild->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)
+ Reference< chart2::XDiagram > xDiagram( m_xChartDocument->getFirstDiagram() );
+ Reference< chart2::data::XDataProvider > xDataProvider( m_xChartDocument->getDataProvider());
+ if( xDataProvider.is() && xDiagram.is() &&
+ DataSourceHelper::allArgumentsForRectRangeDetected( m_xChartDocument ))
+ {
+ Reference< chart2::data::XDataSource > xDataSource(
+ DataSourceHelper::pressUsedDataIntoRectangularFormat( m_xChartDocument ));
+ Sequence< beans::PropertyValue > aArguments(
+ xDataProvider->detectArguments( xDataSource ));
+
+ 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;
+ }
+
+ xDataSource.set( xDataProvider->createDataSource( aArguments ));
+ xDiagram->setDiagramData( xDataSource, 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 000000000..04c390a00
--- /dev/null
+++ b/chart2/source/controller/main/ChartDropTargetHelper.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_CHARTDROPTARGETHELPER_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_CHARTDROPTARGETHELPER_HXX
+
+#include <vcl/transfer.hxx>
+
+namespace com::sun::star {
+ namespace chart2 {
+ class XChartDocument;
+ }
+}
+
+namespace chart
+{
+
+class ChartDropTargetHelper : public DropTargetHelper
+{
+public:
+ ChartDropTargetHelper() = delete;
+ explicit ChartDropTargetHelper(
+ const css::uno::Reference< css::datatransfer::dnd::XDropTarget >& rxDropTarget,
+ const css::uno::Reference< css::chart2::XChartDocument > & 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;
+
+ css::uno::Reference< css::chart2::XChartDocument > m_xChartDocument;
+};
+
+} // namespace chart
+
+// INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_CHARTDROPTARGETHELPER_HXX
+#endif
+
+/* 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 000000000..c03a3f6b6
--- /dev/null
+++ b/chart2/source/controller/main/ChartFrameloader.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 "ChartFrameloader.hxx"
+#include <servicenames.hxx>
+#include <MediaDescriptorHelper.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/frame/XLoadable.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <tools/diagnose_ex.h>
+
+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.set(
+ m_xCC->getServiceManager()->createInstanceWithContext(
+ CHART_MODEL_SERVICE_IMPLEMENTATION_NAME, m_xCC )
+ , uno::UNO_QUERY );
+
+ if( impl_checkCancel() )
+ return false;
+ }
+
+ //create the controller(+XWindow)
+ uno::Reference< frame::XController > xController;
+ uno::Reference< awt::XWindow > xComponentWindow;
+ {
+ xController.set(
+ m_xCC->getServiceManager()->createInstanceWithContext(
+ CHART_CONTROLLER_SERVICE_IMPLEMENTATION_NAME,m_xCC )
+ , uno::UNO_QUERY );
+
+ //!!!it is a special characteristic of the example application
+ //that the controller simultaneously provides the XWindow controller functionality
+ xComponentWindow =
+ uno::Reference< awt::XWindow >( xController, uno::UNO_QUERY );
+
+ if( impl_checkCancel() )
+ return false;
+ }
+
+ //connect frame, controller and model one to each other:
+ if(xController.is()&&xModel.is())
+ {
+ xModel->connectController(xController);
+ xModel->setCurrentController(xController);
+ xController->attachModel(xModel);
+ if(xFrame.is())
+ xFrame->setComponent(xComponentWindow,xController);
+ //creates the view and menu
+ //for correct menu creation the initialized component must be already set into the frame
+ xController->attachFrame(xFrame);
+ }
+
+ // call initNew() or load() at XLoadable
+ if(!bHaveLoadedModel)
+ 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( xComponentWindow.is() && aMDHelper.ISSET_FilterName && aMDHelper.FilterName == "StarChart 5.0" )
+ {
+ 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 000000000..d1564b46e
--- /dev/null
+++ b/chart2/source/controller/main/ChartFrameloader.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_CHARTFRAMELOADER_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_CHARTFRAMELOADER_HXX
+
+#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
+
+#endif
+
+/* 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 000000000..6348aee6e
--- /dev/null
+++ b/chart2/source/controller/main/ChartModelClone.cxx
@@ -0,0 +1,249 @@
+/* -*- 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 <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/XDataSource.hpp>
+#include <com/sun/star/chart2/data/XLabeledDataSequence.hpp>
+
+#include <comphelper/property.hxx>
+#include <tools/diagnose_ex.h>
+
+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::lang::XComponent;
+ using ::com::sun::star::chart2::XTitled;
+ using ::com::sun::star::util::XModifiable;
+ using ::com::sun::star::chart2::data::XDataSource;
+ using ::com::sun::star::chart2::data::XLabeledDataSequence;
+
+ // = helper
+ namespace
+ {
+ Reference< XModel > lcl_cloneModel( const Reference< XModel > & xModel )
+ {
+ Reference< XModel > xResult;
+ try
+ {
+ const Reference< XCloneable > xCloneable( xModel, UNO_QUERY_THROW );
+ xResult.set( xCloneable->createClone(), UNO_QUERY_THROW );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ return xResult;
+ }
+
+ }
+
+ // = ChartModelClone
+ ChartModelClone::ChartModelClone( const Reference< XModel >& i_model, const ModelFacet i_facet )
+ {
+ m_xModelClone.set( lcl_cloneModel( i_model ) );
+
+ try
+ {
+ if ( i_facet == E_MODEL_WITH_DATA )
+ {
+ const Reference< XChartDocument > xChartDoc( m_xModelClone, UNO_QUERY_THROW );
+ ENSURE_OR_THROW( xChartDoc->hasInternalDataProvider(), "invalid chart model" );
+
+ const Reference< XCloneable > xCloneable( xChartDoc->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;
+
+ try
+ {
+ Reference< XComponent > xComp( m_xModelClone, UNO_QUERY_THROW );
+ xComp->dispose();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ 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 Reference< XModel >& 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 Reference< XModel >& i_model,
+ const Reference< XModel >& 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 );
+ Reference< XChartDocument > xSource( i_modelToCopyFrom, UNO_QUERY_THROW );
+ Reference< XChartDocument > xDestination( i_model, UNO_QUERY_THROW );
+
+ // propagate the correct flag for plotting of hidden values to the data provider and all used sequences
+ ChartModel& rModel = dynamic_cast<ChartModel&>(*i_model);
+ ChartModelHelper::setIncludeHiddenCells(ChartModelHelper::isIncludeHiddenCells( i_modelToCopyFrom ), rModel);
+
+ // diagram
+ xDestination->setFirstDiagram( xSource->getFirstDiagram() );
+
+ // main title
+ Reference< XTitled > xDestinationTitled( xDestination, UNO_QUERY_THROW );
+ Reference< XTitled > xSourceTitled( xSource, UNO_QUERY_THROW );
+ xDestinationTitled->setTitleObject( xSourceTitled->getTitleObject() );
+
+ // page background
+ ::comphelper::copyProperties(
+ xSource->getPageBackground(),
+ xDestination->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 ( xDestination->hasInternalDataProvider() )
+ {
+ Reference< XInternalDataProvider > xNewDataProvider( xDestination->getDataProvider(), UNO_QUERY );
+ Reference< XDataSource > 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
+ Reference< XModifiable > xSourceMod( xSource, UNO_QUERY );
+ Reference< XModifiable > xDestMod( xDestination, UNO_QUERY );
+ if ( xSourceMod.is() && xDestMod.is() && !xSourceMod->isModified() )
+ {
+ xDestMod->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 000000000..eb5a9b027
--- /dev/null
+++ b/chart2/source/controller/main/ChartModelClone.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_CHARTMODELCLONE_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_CHARTMODELCLONE_HXX
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.h>
+
+namespace com::sun::star::chart2 { class XInternalDataProvider; }
+namespace com::sun::star::frame { class XModel; }
+
+namespace chart
+{
+
+ enum ModelFacet
+ {
+ E_MODEL,
+ E_MODEL_WITH_DATA,
+ E_MODEL_WITH_SELECTION
+ };
+
+ class ChartModelClone
+ {
+ public:
+ ChartModelClone(
+ const css::uno::Reference< css::frame::XModel >& i_model,
+ const ModelFacet i_facet
+ );
+
+ ~ChartModelClone();
+
+ ChartModelClone(const ChartModelClone&) = delete;
+ const ChartModelClone& operator=(const ChartModelClone&) = delete;
+
+ ModelFacet getFacet() const;
+
+ void applyToModel( const css::uno::Reference< css::frame::XModel >& i_model ) const;
+
+ static void applyModelContentToModel(
+ const css::uno::Reference< css::frame::XModel > & i_model,
+ const css::uno::Reference< css::frame::XModel > & i_modelToCopyFrom,
+ const css::uno::Reference< css::chart2::XInternalDataProvider > & i_data );
+
+ void dispose();
+
+ private:
+ bool impl_isDisposed() const { return !m_xModelClone.is(); }
+
+ private:
+ css::uno::Reference< css::frame::XModel > m_xModelClone;
+ css::uno::Reference< css::chart2::XInternalDataProvider > m_xDataClone;
+ css::uno::Any m_aSelection;
+ };
+
+} // namespace chart
+
+#endif // INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_CHARTMODELCLONE_HXX
+
+/* 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 000000000..67db8d3e4
--- /dev/null
+++ b/chart2/source/controller/main/ChartTransferable.cxx
@@ -0,0 +1,164 @@
+/* -*- 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>
+
+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_pMarkedObjModel( nullptr )
+ ,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_pMarkedObjModel = pExchgView->CreateMarkedObjModel().release();
+ }
+}
+
+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_pMarkedObjModel, 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<SotStorageStream>& 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 ) );
+ if ( SvxDrawingLayerExport( pMarkedObjModel, xDocOut ) )
+ {
+ rxOStm->Commit();
+ }
+
+ 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 000000000..ebe6df966
--- /dev/null
+++ b/chart2/source/controller/main/ChartTransferable.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_CHARTTRANSFERABLE_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_CHARTTRANSFERABLE_HXX
+
+#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<SotStorageStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId,
+ const css::datatransfer::DataFlavor& rFlavor ) override;
+
+private:
+ css::uno::Reference< css::graphic::XGraphic > m_xMetaFileGraphic;
+ SdrModel* m_pMarkedObjModel;
+ bool m_bDrawing;
+};
+
+} // namespace chart
+
+// INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_CHARTTRANSFERABLE_HXX
+#endif
+
+/* 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 000000000..0971fd079
--- /dev/null
+++ b/chart2/source/controller/main/ChartWindow.cxx
@@ -0,0 +1,392 @@
+/* -*- 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 <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>
+
+#define TWIPS_PER_PIXEL 15
+
+using namespace ::com::sun::star;
+
+namespace
+{
+::tools::Rectangle lcl_AWTRectToVCLRect( const css::awt::Rectangle & rAWTRect )
+{
+ ::tools::Rectangle aResult;
+ aResult.setX( rAWTRect.X );
+ aResult.setY( 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
+ SetAntialiasing( AntialiasingFlags::EnableB2dDraw | 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( m_pWindowController )
+ return m_pWindowController->CreateAccessible();
+ else
+ return Window::CreateAccessible();
+}
+
+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( rHEvt.GetMousePosPixel()); // old chart: GetPointerPosPixel()
+ Point aLogicHitPos = PixelToLogic( GetPointerPosPixel());
+ OUString aQuickHelpText;
+ awt::Rectangle aHelpRect;
+ bool bIsBalloonHelp( Help::IsBalloonHelpEnabled() );
+ bHelpHandled = m_pWindowController->requestQuickHelp( aLogicHitPos, bIsBalloonHelp, aQuickHelpText, aHelpRect );
+
+ if( bHelpHandled )
+ {
+ if( bIsBalloonHelp )
+ Help::ShowBalloon(
+ this, rHEvt.GetMousePosPixel(), lcl_AWTRectToVCLRect( aHelpRect ), aQuickHelpText );
+ else
+ Help::ShowQuickHelp(
+ this, lcl_AWTRectToVCLRect( aHelpRect ), aQuickHelpText );
+ }
+ }
+
+ if( !bHelpHandled )
+ vcl::Window::RequestHelp( rHEvt );
+}
+
+void ChartWindow::LogicMouseButtonDown(const MouseEvent& rEvent)
+{
+ MouseButtonDown(rEvent);
+}
+
+void ChartWindow::LogicMouseButtonUp(const MouseEvent& rEvent)
+{
+ MouseButtonUp(rEvent);
+}
+
+void ChartWindow::LogicMouseMove(const MouseEvent& rEvent)
+{
+ MouseMove(rEvent);
+}
+
+void ChartWindow::adjustHighContrastMode()
+{
+ static const DrawModeFlags nContrastMode =
+ DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill |
+ DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient;
+
+ bool bUseContrast = GetSettings().GetStyleSettings().GetHighContrastMode();
+ SetDrawMode( bUseContrast ? nContrastMode : DrawModeFlags::Default );
+}
+
+void ChartWindow::ForceInvalidate()
+{
+ vcl::Window::Invalidate();
+}
+void ChartWindow::Invalidate( InvalidateFlags nFlags )
+{
+ if( m_bInPaint ) // #i101928# superfluous paint calls while entering and editing charts"
+ return;
+ vcl::Window::Invalidate( nFlags );
+}
+void ChartWindow::Invalidate( const tools::Rectangle& rRect, InvalidateFlags nFlags )
+{
+ if( m_bInPaint ) // #i101928# superfluous paint calls while entering and editing charts"
+ return;
+ vcl::Window::Invalidate( rRect, nFlags );
+}
+void ChartWindow::Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags )
+{
+ if( m_bInPaint ) // #i101928# superfluous paint calls while entering and editing charts"
+ return;
+ vcl::Window::Invalidate( rRegion, nFlags );
+}
+
+void ChartWindow::LogicInvalidate(const tools::Rectangle* pRectangle)
+{
+ SfxViewShell* pCurrentShell = SfxViewShell::Current();
+ if ( nullptr == pCurrentShell )
+ return;
+ OString sRectangle;
+ if (!pRectangle)
+ {
+ // we have to invalidate the whole chart area not the whole document
+ sRectangle = GetBoundingBox().toString();
+ }
+ else
+ {
+ tools::Rectangle aRectangle(*pRectangle);
+ // When dragging shapes the map mode is disabled.
+ if (IsMapModeEnabled())
+ {
+ if (GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+ aRectangle = OutputDevice::LogicToLogic(aRectangle, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip));
+ }
+ else
+ {
+ aRectangle = PixelToLogic(aRectangle, MapMode(MapUnit::MapTwip));
+ }
+
+ vcl::Window* pEditWin = GetParentEditWin();
+ if (pEditWin)
+ {
+ MapMode aCWMapMode = GetMapMode();
+ double fXScale( aCWMapMode.GetScaleX() );
+ double fYScale( aCWMapMode.GetScaleY() );
+
+ if (!IsMapModeEnabled())
+ {
+ aRectangle.SetLeft( aRectangle.Left() / fXScale );
+ aRectangle.SetRight( aRectangle.Right() / fXScale );
+ aRectangle.SetTop( aRectangle.Top() / fYScale );
+ aRectangle.SetBottom( aRectangle.Bottom() / fYScale );
+ }
+
+ Point aOffset = this->GetOffsetPixelFrom(*pEditWin);
+ aOffset.setX( aOffset.X() * (TWIPS_PER_PIXEL / fXScale) );
+ aOffset.setY( aOffset.Y() * (TWIPS_PER_PIXEL / fYScale) );
+
+ aRectangle = tools::Rectangle(aRectangle.TopLeft() + aOffset, aRectangle.GetSize());
+ }
+
+ sRectangle = aRectangle.toString();
+ }
+ SfxLokHelper::notifyInvalidation(pCurrentShell, sRectangle);
+}
+
+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();
+ double fXScale( aCWMapMode.GetScaleX() );
+ double fYScale( aCWMapMode.GetScaleY() );
+ Point aOffset = GetOffsetPixelFrom(*pRootWin);
+ aOffset.setX( aOffset.X() * (TWIPS_PER_PIXEL / fXScale) );
+ aOffset.setY( aOffset.Y() * (TWIPS_PER_PIXEL / fYScale) );
+ Size aSize = GetSizePixel();
+ aSize.setWidth( aSize.Width() * (TWIPS_PER_PIXEL / fXScale) );
+ aSize.setHeight( aSize.Height() * (TWIPS_PER_PIXEL / fYScale) );
+ 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 000000000..22e0a52c2
--- /dev/null
+++ b/chart2/source/controller/main/CommandDispatch.cxx
@@ -0,0 +1,170 @@
+/* -*- 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 <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace
+{
+template< class Map >
+ void lcl_DisposeAndClearAndDeleteAllMapElements(
+ Map & rMap,
+ const Reference< uno::XInterface > & xEventSource )
+{
+ for( const auto& rElement : rMap )
+ {
+ if( rElement.second )
+ {
+ rElement.second->disposeAndClear( xEventSource );
+ delete rElement.second;
+ }
+ }
+}
+
+} // anonymous namespace
+
+namespace chart
+{
+
+CommandDispatch::CommandDispatch(
+ const Reference< uno::XComponentContext > & xContext ) :
+ impl::CommandDispatch_Base( m_aMutex ),
+ m_xContext( xContext )
+{
+}
+
+CommandDispatch::~CommandDispatch()
+{}
+
+void CommandDispatch::initialize()
+{}
+
+// ____ WeakComponentImplHelperBase ____
+/// is called when this is disposed
+void SAL_CALL CommandDispatch::disposing()
+{
+ lcl_DisposeAndClearAndDeleteAllMapElements( m_aListeners, static_cast< cppu::OWeakObject* >( this ));
+ 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 )
+{
+ tListenerMap::iterator aIt( m_aListeners.find( URL.Complete ));
+ if( aIt == m_aListeners.end())
+ {
+ aIt = m_aListeners.insert(
+ m_aListeners.begin(),
+ tListenerMap::value_type( URL.Complete, new ::comphelper::OInterfaceContainerHelper2( m_aMutex )));
+ }
+ OSL_ASSERT( aIt != m_aListeners.end());
+
+ aIt->second->addInterface( Control );
+ fireStatusEvent( URL.Complete, Control );
+}
+
+void SAL_CALL CommandDispatch::removeStatusListener( const Reference< frame::XStatusListener >& Control, const util::URL& URL )
+{
+ tListenerMap::iterator aIt( m_aListeners.find( URL.Complete ));
+ if( aIt != m_aListeners.end())
+ (*aIt).second->removeInterface( 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())
+ {
+ if( aIt->second )
+ {
+ ::comphelper::OInterfaceIteratorHelper2 aIntfIt( *((*aIt).second) );
+
+ while( aIntfIt.hasMoreElements())
+ {
+ Reference< frame::XStatusListener > xListener( aIntfIt.next(), uno::UNO_QUERY );
+ try
+ {
+ if( xListener.is())
+ xListener->statusChanged( aEventToSend );
+ }
+ catch( const uno::Exception & )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ }
+ }
+ }
+ }
+}
+
+} // 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 000000000..00638a6c0
--- /dev/null
+++ b/chart2/source/controller/main/CommandDispatch.hxx
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_COMMANDDISPATCH_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_COMMANDDISPATCH_HXX
+
+#include <MutexContainer.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/interfacecontainer2.hxx>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/util/XModifyListener.hpp>
+
+#include <map>
+
+namespace com::sun::star::uno { class XComponentContext; }
+namespace com::sun::star::util { class XURLTransformer; }
+
+namespace chart
+{
+
+namespace impl
+{
+typedef ::cppu::WeakComponentImplHelper<
+ css::frame::XDispatch,
+ css::util::XModifyListener >
+ CommandDispatch_Base;
+}
+
+/** This is the base class for an XDispatch.
+ */
+class CommandDispatch :
+ public MutexContainer,
+ 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 SAL_CALL disposing() 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::OInterfaceContainerHelper2* >
+ tListenerMap;
+
+ tListenerMap m_aListeners;
+
+};
+
+} // namespace chart
+
+// INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_COMMANDDISPATCH_HXX
+#endif
+
+/* 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 000000000..b007ebe5c
--- /dev/null
+++ b/chart2/source/controller/main/CommandDispatchContainer.cxx
@@ -0,0 +1,198 @@
+/* -*- 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 <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+
+#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 Reference< frame::XModel > & xModel )
+{
+ // remove all existing dispatcher that base on the old model
+ m_aCachedDispatches.clear();
+ DisposeHelper::DisposeAllElements( m_aToBeDisposedDispatches );
+ m_aToBeDisposedDispatches.clear();
+ m_xModel = xModel;
+}
+
+void CommandDispatchContainer::setChartDispatch(
+ const Reference< frame::XDispatch >& rChartDispatch,
+ const o3tl::sorted_vector< OUString > & rChartCommands )
+{
+ OSL_ENSURE(rChartDispatch.is(),"Invalid fall back dispatcher!");
+ m_xChartDispatcher.set( rChartDispatch );
+ m_aChartCommands = 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
+ {
+ uno::Reference< frame::XModel > xModel( m_xModel );
+
+ if( xModel.is() && ( rURL.Path == "Undo" || rURL.Path == "Redo" ||
+ rURL.Path == "GetUndoStrings" || rURL.Path == "GetRedoStrings" ) )
+ {
+ 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 );
+ 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 );
+
+ for( sal_Int32 nPos = 0; nPos < nCount; ++nPos )
+ {
+ if ( aDescriptors[ nPos ].FrameName == "_self" )
+ aRet[ 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/ConfigurationAccess.cxx b/chart2/source/controller/main/ConfigurationAccess.cxx
new file mode 100644
index 000000000..2d1dcfcf9
--- /dev/null
+++ b/chart2/source/controller/main/ConfigurationAccess.cxx
@@ -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 .
+ */
+
+#include <ConfigurationAccess.hxx>
+
+#include <unotools/syslocale.hxx>
+#include <unotools/configitem.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <rtl/instance.hxx>
+
+namespace chart
+{
+using namespace ::com::sun::star;
+
+namespace
+{
+bool lcl_IsMetric()
+{
+ SvtSysLocale aSysLocale;
+ const LocaleDataWrapper* pLocWrapper = aSysLocale.GetLocaleDataPtr();
+ MeasurementSystem eSys = pLocWrapper->getMeasurementSystemEnum();
+
+ return ( eSys == MeasurementSystem::Metric );
+}
+
+class CalcConfigItem : public ::utl::ConfigItem
+{
+private:
+ virtual void ImplCommit() override;
+
+public:
+ CalcConfigItem();
+
+ FieldUnit getFieldUnit();
+ virtual void Notify( const uno::Sequence<OUString>& aPropertyNames) override;
+};
+
+}//end anonymous namespace
+
+CalcConfigItem::CalcConfigItem()
+ : ConfigItem( "Office.Calc/Layout" )
+{
+}
+
+void CalcConfigItem::ImplCommit() {}
+void CalcConfigItem::Notify( const uno::Sequence<OUString>& ) {}
+
+FieldUnit CalcConfigItem::getFieldUnit()
+{
+ FieldUnit eResult( FieldUnit::CM );
+
+ uno::Sequence< OUString > aNames( 1 );
+ if( lcl_IsMetric() )
+ aNames[ 0 ] = "Other/MeasureUnit/Metric";
+ else
+ aNames[ 0 ] = "Other/MeasureUnit/NonMetric";
+
+ uno::Sequence< uno::Any > aResult( GetProperties( aNames ));
+ sal_Int32 nValue = 0;
+ if( aResult[ 0 ] >>= nValue )
+ eResult = static_cast< FieldUnit >( nValue );
+
+ return eResult;
+}
+
+namespace
+{
+ //a CalcConfigItem Singleton
+ struct theCalcConfigItem : public rtl::Static< CalcConfigItem, theCalcConfigItem > {};
+}
+
+namespace ConfigurationAccess
+{
+ FieldUnit getFieldUnit()
+ {
+ FieldUnit aUnit( theCalcConfigItem::get().getFieldUnit() );
+ return aUnit;
+ }
+} //namespace ConfigurationAccess
+
+} //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 000000000..aa21b77fb
--- /dev/null
+++ b/chart2/source/controller/main/ControllerCommandDispatch.cxx
@@ -0,0 +1,837 @@
+/* -*- 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 <AxisHelper.hxx>
+#include <TitleHelper.hxx>
+#include <LegendHelper.hxx>
+#include <ObjectIdentifier.hxx>
+#include <ChartTypeHelper.hxx>
+#include <ChartController.hxx>
+#include <RegressionCurveHelper.hxx>
+#include <DataSeriesHelper.hxx>
+#include <StatisticsHelper.hxx>
+#include <ReferenceSizeProvider.hxx>
+#include "ShapeController.hxx"
+
+#include <vcl/svapp.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <comphelper/lok.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/objsh.hxx>
+
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/chart2/XRegressionCurve.hpp>
+#include <com/sun/star/chart2/XRegressionCurveContainer.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 {
+ static bool const MOVE_SERIES_FORWARD = true;
+ static 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 Reference< frame::XModel > & 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 Reference< frame::XModel > & 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;
+
+ uno::Reference< chart2::XDiagram > xDiagram( ChartModelHelper::findDiagram( xModel ));
+ bIsFormateableObjectSelected = bHasSelectedObject && aSelOID.isAutoGeneratedObject();
+ if( aObjectType==OBJECTTYPE_DIAGRAM || aObjectType==OBJECTTYPE_DIAGRAM_WALL || aObjectType==OBJECTTYPE_DIAGRAM_FLOOR )
+ bIsFormateableObjectSelected = DiagramHelper::isSupportingFloorAndWall( xDiagram );
+
+ uno::Reference< chart2::XDataSeries > xGivenDataSeries(
+ ObjectIdentifier::getDataSeriesForCID(
+ aSelObjCID, xModel ) );
+
+ bIsDeleteableObjectSelected = ChartController::isObjectDeleteable( aSelObj );
+
+ bMayMoveSeriesForward = (aObjectType!=OBJECTTYPE_DATA_POINT) && DiagramHelper::isSeriesMoveable(
+ ChartModelHelper::findDiagram( xModel ),
+ xGivenDataSeries,
+ MOVE_SERIES_FORWARD );
+
+ bMayMoveSeriesBackward = (aObjectType!=OBJECTTYPE_DATA_POINT) && DiagramHelper::isSeriesMoveable(
+ ChartModelHelper::findDiagram( xModel ),
+ 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 = DiagramHelper::getDimension( xDiagram );
+ uno::Reference< chart2::XChartType > xFirstChartType(
+ DataSeriesHelper::getChartTypeOfSeries( xGivenDataSeries, xDiagram ));
+
+ // trend lines/mean value line
+ if( (aObjectType == OBJECTTYPE_DATA_SERIES || aObjectType == OBJECTTYPE_DATA_POINT)
+ && ChartTypeHelper::isSupportingRegressionProperties( xFirstChartType, nDimensionCount ))
+ {
+ uno::Reference< chart2::XRegressionCurveContainer > xRegCurveCnt( xGivenDataSeries, uno::UNO_QUERY );
+ if( xRegCurveCnt.is())
+ {
+ // Trendline
+ bMayAddTrendline = true;
+
+ // Mean Value
+ bMayFormatMeanValue = bMayDeleteMeanValue = RegressionCurveHelper::hasMeanValueLine( xRegCurveCnt );
+ 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;
+ }
+ else if( aObjectType == OBJECTTYPE_DATA_CURVE_EQUATION )
+ {
+ bMayFormatTrendlineEquation = true;
+ bool bHasR2Value = false;
+ try
+ {
+ uno::Reference< beans::XPropertySet > xEquationProperties =
+ ObjectIdentifier::getObjectPropertySet( aSelObjCID, xModel );
+ if( xEquationProperties.is() )
+ xEquationProperties->getPropertyValue( "ShowCorrelationCoefficient" ) >>= bHasR2Value;
+ }
+ catch(const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+ bMayAddR2Value = !bHasR2Value;
+ 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 Reference< frame::XModel > & 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;
+};
+
+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 Reference< frame::XModel > & xModel )
+{
+ Reference< chart2::XChartDocument > xChartDoc( xModel, uno::UNO_QUERY );
+ Reference< chart2::XDiagram > xDiagram( ChartModelHelper::findDiagram( xModel ));
+
+ bIsReadOnly = true;
+ Reference< frame::XStorable > xStorable( xModel, uno::UNO_QUERY );
+ if( xStorable.is())
+ bIsReadOnly = xStorable->isReadonly();
+
+ sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram );
+
+ uno::Reference< chart2::XChartType > xFirstChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
+ bSupportsStatistics = ChartTypeHelper::isSupportingStatisticProperties( xFirstChartType, nDimensionCount );
+ bSupportsAxes = ChartTypeHelper::isSupportingMainAxis( xFirstChartType, nDimensionCount, 0 );
+
+ bIsThreeD = (nDimensionCount == 3);
+ if (xChartDoc.is())
+ {
+ ChartModel& rModel = dynamic_cast<ChartModel&>(*xChartDoc);
+ bHasOwnData = rModel.hasInternalDataProvider();
+ bHasDataFromPivotTable = !bHasOwnData && rModel.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( xChartDoc ) ==
+ ReferenceSizeProvider::AUTO_RESIZE_YES);
+
+ bHasLegend = LegendHelper::hasLegend( xDiagram );
+ bHasWall = DiagramHelper::isSupportingFloorAndWall( xDiagram );
+ bHasFloor = bHasWall && bIsThreeD;
+}
+
+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;
+
+ Reference< frame::XModel > xModel( m_xChartController->getModel());
+ Reference< util::XModifyBroadcaster > xModifyBroadcaster( xModel, uno::UNO_QUERY );
+ OSL_ASSERT( xModifyBroadcaster.is());
+ if( xModifyBroadcaster.is())
+ xModifyBroadcaster->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.get(), 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", "" );
+ }
+ }
+
+ Reference< chart2::XChartDocument > xChartDoc(m_xChartController->getModel(), uno::UNO_QUERY);
+ OSL_ENSURE(xChartDoc.is(), "Invalid XChartDocument");
+ if ( xChartDoc.is() )
+ {
+ ChartModel& rModel = dynamic_cast<ChartModel&>(*xChartDoc);
+ css::uno::Reference< com::sun::star::chart2::XDataProviderAccess > xCreatorDoc(rModel.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" ] <<= m_apModelState->bHasMainYGrid;
+ m_aCommandAvailability[ ".uno:ToggleGridVertical" ] = bIsWritable;
+ m_aCommandArguments[ ".uno:ToggleGridVertical" ] <<= m_apModelState->bHasMainXGrid;
+
+ m_aCommandAvailability[ ".uno:ToggleLegend" ] = bIsWritable;
+ m_aCommandArguments[ ".uno:ToggleLegend" ] <<= 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 && 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 && m_apControllerState->bIsTextObject;
+
+ // 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" ] <<= 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;
+ m_aCommandAvailability[ ".uno:InsertTrendlineEquation" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddTrendlineEquation;
+ m_aCommandAvailability[ ".uno:InsertTrendlineEquationAndR2" ] = m_aCommandAvailability[ ".uno:InsertTrendlineEquation" ];
+ m_aCommandAvailability[ ".uno:InsertR2Value" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddR2Value;
+ 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;
+}
+
+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.get());
+ 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.get() ));
+ 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 SAL_CALL ControllerCommandDispatch::disposing()
+{
+ 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->getModel());
+ bUpdateCommandAvailability = true;
+ }
+
+ // Update the "ControllerState" Struct.
+ if( m_apControllerState && m_xChartController.is())
+ {
+ m_apControllerState->update( m_xChartController.get(), m_xChartController->getModel());
+ 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.get(), m_xChartController->getModel());
+ 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 000000000..67a07514e
--- /dev/null
+++ b/chart2/source/controller/main/ControllerCommandDispatch.hxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_CONTROLLERCOMMANDDISPATCH_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_CONTROLLERCOMMANDDISPATCH_HXX
+
+#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 SAL_CALL disposing() 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
+
+// INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_CONTROLLERCOMMANDDISPATCH_HXX
+#endif
+
+/* 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 000000000..9e01d5c3b
--- /dev/null
+++ b/chart2/source/controller/main/DragMethod_Base.cxx
@@ -0,0 +1,77 @@
+/* -*- 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 <ObjectNameProvider.hxx>
+#include <ObjectIdentifier.hxx>
+
+#include <svx/ActionDescriptionProvider.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+#include <vcl/ptrstyle.hxx>
+
+namespace chart
+{
+
+using namespace ::com::sun::star;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::WeakReference;
+
+DragMethod_Base::DragMethod_Base( DrawViewWrapper& rDrawViewWrapper
+ , const OUString& rObjectCID
+ , const Reference< frame::XModel >& xChartModel
+ , ActionDescriptionProvider::ActionType eActionType )
+ : SdrDragMethod( rDrawViewWrapper )
+ , m_rDrawViewWrapper(rDrawViewWrapper)
+ , m_aObjectCID(rObjectCID)
+ , m_eActionType( eActionType )
+ , m_xChartModel( WeakReference< frame::XModel >(xChartModel) )
+{
+ setMoveOnly(true);
+}
+DragMethod_Base::~DragMethod_Base()
+{
+}
+
+Reference< frame::XModel > DragMethod_Base::getChartModel() const
+{
+ return Reference< frame::XModel >( m_xChartModel );
+}
+
+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 000000000..9ae8090fc
--- /dev/null
+++ b/chart2/source/controller/main/DragMethod_Base.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_DRAGMETHOD_BASE_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_DRAGMETHOD_BASE_HXX
+
+#include <svx/ActionDescriptionProvider.hxx>
+#include <svx/svddrgmt.hxx>
+#include <cppuhelper/weakref.hxx>
+
+namespace chart { class DrawViewWrapper; }
+namespace com::sun::star::frame { class XModel; }
+
+namespace chart
+{
+
+class DragMethod_Base : public SdrDragMethod
+{
+public:
+ DragMethod_Base( DrawViewWrapper& rDrawViewWrapper, const OUString& rObjectCID
+ , const css::uno::Reference< css::frame::XModel >& 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:
+ css::uno::Reference< css::frame::XModel > getChartModel() const;
+
+protected:
+ DrawViewWrapper& m_rDrawViewWrapper;
+ OUString m_aObjectCID;
+ ActionDescriptionProvider::ActionType m_eActionType;
+
+private:
+ css::uno::WeakReference< css::frame::XModel > m_xChartModel;
+};
+
+} // namespace chart
+
+// INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_DRAGMETHOD_BASE_HXX
+#endif
+
+/* 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 000000000..9814a5db6
--- /dev/null
+++ b/chart2/source/controller/main/DragMethod_PieSegment.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 "DragMethod_PieSegment.hxx"
+#include <DrawViewWrapper.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 <com/sun/star/frame/XModel.hpp>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <tools/diagnose_ex.h>
+
+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 Reference< frame::XModel >& 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 )
+{
+ OUString 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<long>(aNewPosVector.getX()), static_cast<long>(aNewPosVector.getY()) );
+ if( aNewPos != DragStat().GetNow() )
+ {
+ Hide();
+ DragStat().NextMove( aNewPos );
+ Show();
+ }
+}
+bool DragMethod_PieSegment::EndSdrDrag(bool /*bCopy*/)
+{
+ Hide();
+
+ try
+ {
+ Reference< frame::XModel > 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()
+{
+ 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 )
+ {
+ const basegfx::B2DPolyPolygon aNewPolyPolygon(pObj->TakeXorPoly());
+ addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(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 000000000..4a1264a01
--- /dev/null
+++ b/chart2/source/controller/main/DragMethod_PieSegment.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_DRAGMETHOD_PIESEGMENT_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_DRAGMETHOD_PIESEGMENT_HXX
+
+#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 css::uno::Reference< css::frame::XModel >& 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() 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
+
+// INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_DRAGMETHOD_PIESEGMENT_HXX
+#endif
+
+/* 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 000000000..7501f0bf7
--- /dev/null
+++ b/chart2/source/controller/main/DragMethod_RotateDiagram.cxx
@@ -0,0 +1,229 @@
+/* -*- 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 <DiagramHelper.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 <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <drawinglayer/geometry/viewinformation3d.hxx>
+
+namespace chart
+{
+
+using namespace ::com::sun::star;
+using ::com::sun::star::uno::Reference;
+
+DragMethod_RotateDiagram::DragMethod_RotateDiagram( DrawViewWrapper& rDrawViewWrapper
+ , const OUString& rObjectCID
+ , const Reference< frame::XModel >& 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_aWireframePolyPolygon()
+ , 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();
+
+ uno::Reference< chart2::XDiagram > xDiagram( ChartModelHelper::findDiagram(getChartModel()) );
+ uno::Reference< beans::XPropertySet > xDiagramProperties( xDiagram, uno::UNO_QUERY );
+ if( !xDiagramProperties.is() )
+ return;
+
+ ThreeDHelper::getRotationFromDiagram( xDiagramProperties
+ , m_nInitialHorizontalAngleDegree, m_nInitialVerticalAngleDegree );
+
+ ThreeDHelper::getRotationAngleFromDiagram( xDiagramProperties
+ , m_fInitialXAngleRad, m_fInitialYAngleRad, m_fInitialZAngleRad );
+
+ if( ChartTypeHelper::isSupportingRightAngledAxes(
+ DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) )
+ xDiagramProperties->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 = F_PI2 * static_cast<double>(rPnt.Y() - m_aStartPos.Y())
+ / (m_aReferenceRect.GetHeight() > 0 ? static_cast<double>(m_aReferenceRect.GetHeight()) : 1.0);
+ double fY = F_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 );
+
+ ThreeDHelper::setRotationAngleToDiagram( uno::Reference< beans::XPropertySet >( ChartModelHelper::findDiagram( getChartModel() ), uno::UNO_QUERY )
+ , fResultX, fResultY, fResultZ );
+ }
+ else
+ {
+ ThreeDHelper::setRotationToDiagram( ( uno::Reference< beans::XPropertySet >( ChartModelHelper::findDiagram( getChartModel() ), uno::UNO_QUERY ) )
+ , 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(
+ 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 000000000..a9401c923
--- /dev/null
+++ b/chart2/source/controller/main/DragMethod_RotateDiagram.hxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_DRAGMETHOD_ROTATEDIAGRAM_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_DRAGMETHOD_ROTATEDIAGRAM_HXX
+
+#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 css::uno::Reference< css::frame::XModel >& 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
+
+// INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_DRAGMETHOD_ROTATEDIAGRAM_HXX
+#endif
+
+/* 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 000000000..24ed70957
--- /dev/null
+++ b/chart2/source/controller/main/DrawCommandDispatch.cxx
@@ -0,0 +1,619 @@
+/* -*- 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 "DrawCommandDispatch.h"
+#include <ChartController.hxx>
+#include <DrawViewWrapper.hxx>
+#include <chartview/DrawModelWrapper.hxx>
+
+#include <com/sun/star/frame/CommandGroup.hpp>
+#include <o3tl/unsafe_downcast.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/itempool.hxx>
+#include <editeng/adjustitem.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 )
+{
+ sal_uInt16 nFeatureId = 0;
+ OUString aBaseCommand;
+ OUString aCustomShapeType;
+ return parseCommandURL( rCommandURL, &nFeatureId, &aBaseCommand, &aCustomShapeType );
+}
+
+static ::basegfx::B2DPolyPolygon getPolygon(const char* pResId, const SdrModel& rModel)
+{
+ ::basegfx::B2DPolyPolygon aReturn;
+ XLineEndListRef pLineEndList = rModel.GetLineEndList();
+ if ( pLineEndList.is() )
+ {
+ OUString aName(SvxResId(pResId));
+ long nCount = pLineEndList->Count();
+ for ( 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() == OBJ_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();
+ SfxItemSet aDest(
+ pObj->getSdrModelFromSdrObject().GetItemPool(),
+ svl::Items<
+ // 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.Set( rSource );
+ pObj->SetMergedItemSet( aDest );
+ sal_Int32 nAngle = pSourceObj->GetRotateAngle();
+ if ( nAngle )
+ {
+ double a = nAngle * F_PI18000;
+ pObj->NbcRotate( pObj->GetSnapRect().Center(), nAngle, sin( a ), cos( a ) );
+ }
+ 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 == COMMAND_ID_LINE_ARROW_END && 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 );
+
+ long nWidth = 300; // (1/100th mm)
+ if ( aSet.GetItemState( XATTR_LINEWIDTH ) != SfxItemState::DONTCARE )
+ {
+ 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()
+{
+}
+
+// XEventListener
+void DrawCommandDispatch::disposing( const lang::EventObject& /* Source */ )
+{
+}
+
+FeatureState DrawCommandDispatch::getState( const OUString& rCommand )
+{
+ FeatureState aReturn;
+ aReturn.bEnabled = false;
+ aReturn.aState <<= false;
+
+ sal_uInt16 nFeatureId = 0;
+ OUString aBaseCommand;
+ OUString aCustomShapeType;
+ if ( parseCommandURL( rCommand, &nFeatureId, &aBaseCommand, &aCustomShapeType ) )
+ {
+ switch ( nFeatureId )
+ {
+ case COMMAND_ID_OBJECT_SELECT:
+ case COMMAND_ID_DRAW_LINE:
+ case COMMAND_ID_LINE_ARROW_END:
+ case COMMAND_ID_DRAW_RECT:
+ case COMMAND_ID_DRAW_ELLIPSE:
+ case COMMAND_ID_DRAW_FREELINE_NOFILL:
+ case COMMAND_ID_DRAW_TEXT:
+ case COMMAND_ID_DRAW_CAPTION:
+ case COMMAND_ID_DRAWTBX_CS_BASIC:
+ case COMMAND_ID_DRAWTBX_CS_SYMBOL:
+ case COMMAND_ID_DRAWTBX_CS_ARROW:
+ case COMMAND_ID_DRAWTBX_CS_FLOWCHART:
+ case COMMAND_ID_DRAWTBX_CS_CALLOUT:
+ case COMMAND_ID_DRAWTBX_CS_STAR:
+ {
+ 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 = OBJ_NONE;
+
+ sal_uInt16 nFeatureId = 0;
+ OUString aBaseCommand;
+ OUString aCustomShapeType;
+ if ( !parseCommandURL( rCommand, &nFeatureId, &aBaseCommand, &aCustomShapeType ) )
+ return;
+
+ bool bCreate = false;
+ m_nFeatureId = nFeatureId;
+ m_aCustomShapeType = aCustomShapeType;
+
+ switch ( nFeatureId )
+ {
+ case COMMAND_ID_OBJECT_SELECT:
+ {
+ eDrawMode = CHARTDRAW_SELECT;
+ eKind = OBJ_NONE;
+ }
+ break;
+ case COMMAND_ID_DRAW_LINE:
+ case COMMAND_ID_LINE_ARROW_END:
+ {
+ eDrawMode = CHARTDRAW_INSERT;
+ eKind = OBJ_LINE;
+ }
+ break;
+ case COMMAND_ID_DRAW_RECT:
+ {
+ eDrawMode = CHARTDRAW_INSERT;
+ eKind = OBJ_RECT;
+ }
+ break;
+ case COMMAND_ID_DRAW_ELLIPSE:
+ {
+ eDrawMode = CHARTDRAW_INSERT;
+ eKind = OBJ_CIRC;
+ }
+ break;
+ case COMMAND_ID_DRAW_FREELINE_NOFILL:
+ {
+ eDrawMode = CHARTDRAW_INSERT;
+ eKind = OBJ_FREELINE;
+ }
+ break;
+ case COMMAND_ID_DRAW_TEXT:
+ {
+ eDrawMode = CHARTDRAW_INSERT;
+ eKind = OBJ_TEXT;
+ bCreate = true;
+ }
+ break;
+ case COMMAND_ID_DRAW_CAPTION:
+ {
+ eDrawMode = CHARTDRAW_INSERT;
+ eKind = OBJ_CAPTION;
+ }
+ break;
+ case COMMAND_ID_DRAWTBX_CS_BASIC:
+ case COMMAND_ID_DRAWTBX_CS_SYMBOL:
+ case COMMAND_ID_DRAWTBX_CS_ARROW:
+ case COMMAND_ID_DRAWTBX_CS_FLOWCHART:
+ case COMMAND_ID_DRAWTBX_CS_CALLOUT:
+ case COMMAND_ID_DRAWTBX_CS_STAR:
+ {
+ eDrawMode = CHARTDRAW_INSERT;
+ eKind = OBJ_CUSTOMSHAPE;
+ }
+ break;
+ default:
+ {
+ eDrawMode = CHARTDRAW_SELECT;
+ eKind = OBJ_NONE;
+ }
+ break;
+ }
+
+ if ( !m_pChartController )
+ return;
+
+ DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper();
+ if ( !pDrawViewWrapper )
+ return;
+
+ SolarMutexGuard aGuard;
+ m_pChartController->setDrawMode( eDrawMode );
+ setInsertObj( sal::static_int_cast< sal_uInt16 >( eKind ) );
+ if ( bCreate )
+ {
+ pDrawViewWrapper->SetCreateMode();
+ }
+
+ const OUString sKeyModifier( "KeyModifier" );
+ const beans::PropertyValue* pIter = rArgs.getConstArray();
+ const beans::PropertyValue* pEnd = pIter + rArgs.getLength();
+ const beans::PropertyValue* pKeyModifier = std::find_if(pIter, pEnd,
+ [&sKeyModifier](const beans::PropertyValue& lhs)
+ {return lhs.Name == sKeyModifier;} );
+ sal_Int16 nKeyModifier = 0;
+ if ( !(pKeyModifier != pEnd && ( pKeyModifier->Value >>= nKeyModifier ) && nKeyModifier == KEY_MOD1) )
+ return;
+
+ if ( eDrawMode != CHARTDRAW_INSERT )
+ return;
+
+ SdrObject* pObj = createDefaultObject( nFeatureId );
+ if ( pObj )
+ {
+ SdrPageView* pPageView = pDrawViewWrapper->GetSdrPageView();
+ if (pDrawViewWrapper->InsertObjectAtView(pObj, *pPageView))
+ m_pChartController->SetAndApplySelection(Reference<drawing::XShape>(pObj->getUnoShape(), uno::UNO_QUERY));
+ if ( nFeatureId == COMMAND_ID_DRAW_TEXT )
+ {
+ m_pChartController->StartTextEdit();
+ }
+ }
+}
+
+void DrawCommandDispatch::describeSupportedFeatures()
+{
+ implDescribeSupportedFeature( ".uno:SelectObject", COMMAND_ID_OBJECT_SELECT, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:Line", COMMAND_ID_DRAW_LINE, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:LineArrowEnd", COMMAND_ID_LINE_ARROW_END, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:Rect", COMMAND_ID_DRAW_RECT, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:Ellipse", COMMAND_ID_DRAW_ELLIPSE, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:Freeline_Unfilled", COMMAND_ID_DRAW_FREELINE_NOFILL, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DrawText", COMMAND_ID_DRAW_TEXT, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:DrawCaption", COMMAND_ID_DRAW_CAPTION, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:BasicShapes", COMMAND_ID_DRAWTBX_CS_BASIC, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:SymbolShapes", COMMAND_ID_DRAWTBX_CS_SYMBOL, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:ArrowShapes", COMMAND_ID_DRAWTBX_CS_ARROW, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:FlowChartShapes", COMMAND_ID_DRAWTBX_CS_FLOWCHART, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:CalloutShapes", COMMAND_ID_DRAWTBX_CS_CALLOUT, CommandGroup::INSERT );
+ implDescribeSupportedFeature( ".uno:StarShapes", COMMAND_ID_DRAWTBX_CS_STAR, CommandGroup::INSERT );
+}
+
+void DrawCommandDispatch::setInsertObj( sal_uInt16 eObj )
+{
+ DrawViewWrapper* pDrawViewWrapper = ( m_pChartController ? m_pChartController->GetDrawViewWrapper() : nullptr );
+ if ( pDrawViewWrapper )
+ {
+ pDrawViewWrapper->SetCurrentObj( eObj /*, Inventor */);
+ }
+}
+
+SdrObject* DrawCommandDispatch::createDefaultObject( const sal_uInt16 nID )
+{
+ SdrObject* pObj = nullptr;
+ 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 COMMAND_ID_DRAW_LINE:
+ case COMMAND_ID_LINE_ARROW_END:
+ {
+ if ( auto const pathObj = dynamic_cast<SdrPathObj*>( pObj) )
+ {
+ 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 COMMAND_ID_DRAW_FREELINE_NOFILL:
+ {
+ if ( auto const pathObj = dynamic_cast<SdrPathObj*>( pObj) )
+ {
+ 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 COMMAND_ID_DRAW_TEXT:
+ case COMMAND_ID_DRAW_TEXT_VERTICAL:
+ {
+ if ( SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>( pObj) )
+ {
+ pTextObj->SetLogicRect( aRect );
+ bool bVertical = ( nID == COMMAND_ID_DRAW_TEXT_VERTICAL );
+ 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 COMMAND_ID_DRAW_CAPTION:
+ case COMMAND_ID_DRAW_CAPTION_VERTICAL:
+ {
+ if ( SdrCaptionObj* pCaptionObj = dynamic_cast<SdrCaptionObj*>( pObj) )
+ {
+ bool bIsVertical( nID == COMMAND_ID_DRAW_CAPTION_VERTICAL );
+ 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 );
+ pObj->SetMergedItemSet( aSet );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return pObj;
+}
+
+bool DrawCommandDispatch::parseCommandURL( const OUString& rCommandURL, sal_uInt16* pnFeatureId,
+ OUString* pBaseCommand, OUString* pCustomShapeType )
+{
+ bool bFound = true;
+ sal_uInt16 nFeatureId = 0;
+ OUString aBaseCommand;
+ OUString aType;
+
+ sal_Int32 nIndex = 1;
+ OUString aToken = rCommandURL.getToken( 0, '.', nIndex );
+ if ( nIndex == -1 || aToken.isEmpty() )
+ {
+ aBaseCommand = rCommandURL;
+ SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( aBaseCommand );
+ if ( aIter != m_aSupportedFeatures.end() )
+ {
+ nFeatureId = aIter->second.nFeatureId;
+
+ switch ( nFeatureId )
+ {
+ case COMMAND_ID_DRAWTBX_CS_BASIC:
+ {
+ aType = "diamond";
+ }
+ break;
+ case COMMAND_ID_DRAWTBX_CS_SYMBOL:
+ {
+ aType = "smiley";
+ }
+ break;
+ case COMMAND_ID_DRAWTBX_CS_ARROW:
+ {
+ aType = "left-right-arrow";
+ }
+ break;
+ case COMMAND_ID_DRAWTBX_CS_FLOWCHART:
+ {
+ aType = "flowchart-internal-storage";
+ }
+ break;
+ case COMMAND_ID_DRAWTBX_CS_CALLOUT:
+ {
+ aType = "round-rectangular-callout";
+ }
+ break;
+ case COMMAND_ID_DRAWTBX_CS_STAR:
+ {
+ 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.h b/chart2/source/controller/main/DrawCommandDispatch.h
new file mode 100644
index 000000000..faf70bde1
--- /dev/null
+++ b/chart2/source/controller/main/DrawCommandDispatch.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef CHART_DRAWCOMMANDDISPATCH_HRC
+#define CHART_DRAWCOMMANDDISPATCH_HRC
+
+//Command Ids:
+#define COMMAND_ID_OBJECT_SELECT 1
+#define COMMAND_ID_DRAW_LINE 2
+#define COMMAND_ID_LINE_ARROW_END 3
+#define COMMAND_ID_DRAW_RECT 4
+#define COMMAND_ID_DRAW_ELLIPSE 5
+#define COMMAND_ID_DRAW_FREELINE_NOFILL 6
+#define COMMAND_ID_DRAW_TEXT 7
+#define COMMAND_ID_DRAW_TEXT_VERTICAL 8
+#define COMMAND_ID_DRAW_CAPTION 9
+#define COMMAND_ID_DRAW_CAPTION_VERTICAL 10
+#define COMMAND_ID_DRAWTBX_CS_BASIC 11
+#define COMMAND_ID_DRAWTBX_CS_SYMBOL 12
+#define COMMAND_ID_DRAWTBX_CS_ARROW 13
+#define COMMAND_ID_DRAWTBX_CS_FLOWCHART 14
+#define COMMAND_ID_DRAWTBX_CS_CALLOUT 15
+#define COMMAND_ID_DRAWTBX_CS_STAR 16
+
+#endif
+
+/* 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 000000000..7df47171a
--- /dev/null
+++ b/chart2/source/controller/main/DrawCommandDispatch.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_DRAWCOMMANDDISPATCH_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_DRAWCOMMANDDISPATCH_HXX
+
+#include "FeatureCommandDispatchBase.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 SAL_CALL disposing() 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( sal_uInt16 eObj );
+ SdrObject* createDefaultObject( const sal_uInt16 nID );
+
+ bool parseCommandURL( const OUString& rCommandURL, sal_uInt16* pnFeatureId, OUString* pBaseCommand, OUString* pCustomShapeType );
+
+ ChartController* m_pChartController;
+ OUString m_aCustomShapeType;
+};
+
+} // namespace chart
+
+// INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_DRAWCOMMANDDISPATCH_HXX
+#endif
+
+/* 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 000000000..46e601954
--- /dev/null
+++ b/chart2/source/controller/main/ElementSelector.cxx
@@ -0,0 +1,328 @@
+/* -*- 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 <cppuhelper/supportsservice.hxx>
+#include <o3tl/safeint.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+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
+{
+static const char lcl_aServiceName[] = "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)
+{
+ 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();
+}
+
+void SelectorListBox::GetFocus()
+{
+ if (m_xWidget)
+ m_xWidget->grab_focus();
+ InterimItemWindow::GetFocus();
+}
+
+SelectorListBox::~SelectorListBox()
+{
+ disposeOnce();
+}
+
+static void lcl_addObjectsToList( const ObjectHierarchy& rHierarchy, const ObjectIdentifier & rParent, std::vector< ListBoxEntryData >& rEntries
+ , const sal_Int32 nHierarchyDepth, const Reference< chart2::XChartDocument >& 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 Reference< frame::XController >& xChartController )
+{
+ m_xChartController = xChartController;
+}
+
+void SelectorListBox::UpdateChartElementsListAndSelection()
+{
+ m_xWidget->clear();
+ m_aEntries.clear();
+
+ Reference< frame::XController > xChartController( m_xChartController );
+ if( xChartController.is() )
+ {
+ Reference< view::XSelectionSupplier > xSelectionSupplier( xChartController, uno::UNO_QUERY);
+ ObjectIdentifier aSelectedOID;
+ OUString aSelectedCID;
+ if( xSelectionSupplier.is() )
+ {
+ aSelectedOID = ObjectIdentifier( xSelectionSupplier->getSelection() );
+ aSelectedCID = aSelectedOID.getObjectCID();
+ }
+
+ Reference< chart2::XChartDocument > xChartDoc( xChartController->getModel(), uno::UNO_QUERY );
+ 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;
+ Reference< lang::XMultiServiceFactory > xFact( xChartController->getModel(), uno::UNO_QUERY );
+ 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)
+ {
+ m_xWidget->append_text(entry.UIName);
+ 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;
+ }
+
+ Reference< frame::XController > xController( m_xChartController );
+ 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;
+ Reference< view::XSelectionSupplier > xSelectionSupplier( m_xChartController.get(), uno::UNO_QUERY );
+ if( xSelectionSupplier.is() )
+ xSelectionSupplier->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() throw ()
+{
+ ToolboxController::acquire();
+}
+void SAL_CALL ElementSelectorToolbarController::release() throw ()
+{
+ 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;
+ m_apSelectorListBox->SetChartController( xChartController );
+ 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 000000000..01cfd273c
--- /dev/null
+++ b/chart2/source/controller/main/ElementSelector.hxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_ELEMENTSELECTOR_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_ELEMENTSELECTOR_HXX
+
+#include <ObjectIdentifier.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <cppuhelper/implbase1.hxx>
+#include <svtools/toolboxcontroller.hxx>
+
+#include <vcl/InterimItemWindow.hxx>
+#include <cppuhelper/weakref.hxx>
+
+namespace chart
+{
+
+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;
+
+ virtual void GetFocus() override;
+
+ void ReleaseFocus_Impl();
+
+ void SetChartController( const css::uno::Reference< css::frame::XController >& xChartController );
+ void UpdateChartElementsListAndSelection();
+
+private:
+ css::uno::WeakReference<css::frame::XController> 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() throw () override;
+ virtual void SAL_CALL release() throw () 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
+
+#endif
+
+/* 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 000000000..90dcf77b2
--- /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( 0 )
+{
+}
+
+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,
+ sal_uInt16 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 000000000..e1125cd8e
--- /dev/null
+++ b/chart2/source/controller/main/FeatureCommandDispatchBase.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 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_FEATURECOMMANDDISPATCHBASE_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_FEATURECOMMANDDISPATCHBASE_HXX
+
+#include "CommandDispatch.hxx"
+
+#include <com/sun/star/frame/DispatchInformation.hpp>
+
+namespace chart
+{
+
+struct ControllerFeature: public css::frame::DispatchInformation
+{
+ sal_uInt16 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, sal_uInt16 nId,
+ sal_Int16 nGroup );
+
+ mutable SupportedFeatures m_aSupportedFeatures;
+
+ sal_uInt16 m_nFeatureId;
+};
+
+} // namespace chart
+
+// INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_FEATURECOMMANDDISPATCHBASE_HXX
+#endif
+
+/* 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 000000000..32762762e
--- /dev/null
+++ b/chart2/source/controller/main/ObjectHierarchy.cxx
@@ -0,0 +1,845 @@
+/* -*- 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 <RegressionCurveHelper.hxx>
+#include <AxisHelper.hxx>
+#include <chartview/ExplicitValueProvider.hxx>
+#include <ChartTypeHelper.hxx>
+#include <DataSeriesHelper.hxx>
+#include <LegendHelper.hxx>
+#include <chartview/DrawModelWrapper.hxx>
+#include <unonames.hxx>
+
+#include <map>
+#include <algorithm>
+#include <iterator>
+
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/chart2/XTitled.hpp>
+#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/chart2/XChartTypeContainer.hpp>
+#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
+#include <com/sun/star/chart2/XRegressionCurveContainer.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/KeyEvent.hpp>
+#include <com/sun/star/awt/KeyModifier.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::chart2;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+namespace
+{
+
+struct lcl_ObjectToOID
+{
+ explicit lcl_ObjectToOID( const Reference< chart2::XChartDocument > & xChartDoc ) :
+ m_xModel( xChartDoc )
+ {}
+
+ ::chart::ObjectIdentifier operator() ( const Reference< uno::XInterface > & xObj )
+ {
+ return ::chart::ObjectIdentifier( ::chart::ObjectIdentifier::createClassifiedIdentifierForObject( xObj, m_xModel ) );
+ }
+
+private:
+ Reference< frame::XModel > m_xModel;
+};
+
+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 Reference< XAxis >& xAxis, ::chart::ObjectHierarchy::tChildContainer& rContainer, const Reference< frame::XModel >& xChartModel )
+{
+ Reference< XTitled > xAxisTitled( xAxis, uno::UNO_QUERY );
+ if( xAxisTitled.is())
+ {
+ Reference< XTitle > xAxisTitle( xAxisTitled->getTitleObject());
+ if( xAxisTitle.is())
+ rContainer.emplace_back( ::chart::ObjectIdentifier::createClassifiedIdentifierForObject( xAxisTitle, xChartModel ) );
+ }
+}
+
+} // anonymous namespace
+
+namespace chart
+{
+
+namespace impl
+{
+
+class ImplObjectHierarchy
+{
+public:
+ explicit ImplObjectHierarchy(
+ const Reference< XChartDocument >& xChartDocument,
+ ExplicitValueProvider* pExplicitValueProvider,
+ bool bFlattenDiagram, bool bOrderingForElementSelector );
+
+ bool hasChildren( const ObjectIdentifier& rParent );
+ ObjectHierarchy::tChildContainer getChildren( const ObjectIdentifier& rParent );
+ ObjectHierarchy::tChildContainer getSiblings( const ObjectIdentifier& rNode );
+
+ ObjectIdentifier getParent( const ObjectIdentifier& rOID );
+
+private:
+ void createTree( const Reference< XChartDocument > & xChartDocument );
+ void createAxesTree(
+ ObjectHierarchy::tChildContainer & rContainer,
+ const Reference< XChartDocument > & xChartDoc,
+ const Reference< XDiagram > & xDiagram );
+ void createDiagramTree(
+ ObjectHierarchy::tChildContainer& rContainer,
+ const Reference< XChartDocument >& xChartDoc,
+ const Reference< XDiagram >& xDiagram );
+ void createDataSeriesTree(
+ ObjectHierarchy::tChildContainer & rOutDiagramSubContainer,
+ const Reference< XDiagram > & xDiagram );
+ static void createWallAndFloor(
+ ObjectHierarchy::tChildContainer & rContainer,
+ const Reference< XDiagram > & xDiagram );
+ void createLegendTree(
+ ObjectHierarchy::tChildContainer & rContainer,
+ const Reference< XChartDocument > & xChartDoc,
+ const Reference< XDiagram > & xDiagram );
+ void createAdditionalShapesTree( ObjectHierarchy::tChildContainer& rContainer );
+
+ ObjectIdentifier getParentImpl(
+ const ObjectIdentifier& rParentOID,
+ const ObjectIdentifier& rOID );
+
+ typedef std::map< ObjectIdentifier, ObjectHierarchy::tChildContainer >
+ tChildMap;
+ tChildMap m_aChildMap;
+ ExplicitValueProvider* m_pExplicitValueProvider;
+ bool m_bFlattenDiagram;
+ bool m_bOrderingForElementSelector;
+};
+
+ImplObjectHierarchy::ImplObjectHierarchy(
+ const Reference< XChartDocument >& xChartDocument,
+ ExplicitValueProvider* pExplicitValueProvider,
+ bool bFlattenDiagram,
+ bool bOrderingForElementSelector ) :
+ m_pExplicitValueProvider( pExplicitValueProvider ),
+ m_bFlattenDiagram( bFlattenDiagram ),
+ m_bOrderingForElementSelector( bOrderingForElementSelector )
+{
+ createTree( xChartDocument );
+ // don't remember this helper to avoid access after lifetime
+ m_pExplicitValueProvider = nullptr;
+}
+
+void ImplObjectHierarchy::createTree( const Reference< XChartDocument >& xChartDocument )
+{
+ m_aChildMap = tChildMap();//clear tree
+
+ if( !xChartDocument.is() )
+ return;
+
+ //@todo: change ObjectIdentifier to take an XChartDocument rather than XModel
+ Reference< frame::XModel > xModel = xChartDocument;
+ Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartDocument ) );
+ ObjectIdentifier aDiaOID;
+ if( xDiagram.is() )
+ aDiaOID = ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xDiagram, xModel ) );
+ ObjectHierarchy::tChildContainer aTopLevelContainer;
+
+ // First Level
+
+ // Chart Area
+ if( m_bOrderingForElementSelector )
+ {
+ aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) );
+ if( xDiagram.is() )
+ {
+ aTopLevelContainer.push_back( aDiaOID );
+ createWallAndFloor( aTopLevelContainer, xDiagram );
+ createLegendTree( aTopLevelContainer, xChartDocument, xDiagram );
+ }
+ }
+
+ // Main Title
+ Reference< XTitled > xDocTitled( xChartDocument, uno::UNO_QUERY );
+ if( xDocTitled.is())
+ {
+ Reference< XTitle > xMainTitle( xDocTitled->getTitleObject());
+ if( xMainTitle.is())
+ aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForObject( xMainTitle, xModel ) );
+ }
+
+ if( xDiagram.is())
+ {
+ // Sub Title. Note: This is interpreted of being top level
+ Reference< XTitled > xDiaTitled( xDiagram, uno::UNO_QUERY );
+ if( xDiaTitled.is())
+ {
+ Reference< XTitle > xSubTitle( xDiaTitled->getTitleObject());
+ if( xSubTitle.is())
+ aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForObject( xSubTitle, xModel ) );
+ }
+
+ if( !m_bOrderingForElementSelector )
+ {
+ // Axis Titles. Note: These are interpreted of being top level
+ const Sequence< Reference< XAxis > > aAxes( AxisHelper::getAllAxesOfDiagram( xDiagram ) );
+ for( Reference< XAxis > const & axis : aAxes )
+ lcl_addAxisTitle( axis, aTopLevelContainer, xModel );
+
+ // Diagram
+ aTopLevelContainer.push_back( aDiaOID );
+ }
+
+ if( m_bFlattenDiagram )
+ createDiagramTree( aTopLevelContainer, xChartDocument, xDiagram );
+ else
+ {
+ ObjectHierarchy::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, OUString() ) );
+
+ if( ! aTopLevelContainer.empty())
+ m_aChildMap[ ObjectHierarchy::getRootNodeOID() ] = aTopLevelContainer;
+}
+
+void ImplObjectHierarchy::createLegendTree(
+ ObjectHierarchy::tChildContainer & rContainer,
+ const Reference< XChartDocument > & xChartDoc,
+ const Reference< XDiagram > & 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 )
+ {
+ Reference< container::XIndexAccess > xLegendShapeContainer(
+ m_pExplicitValueProvider->getShapeForCID( aLegendOID.getObjectCID() ), uno::UNO_QUERY );
+ ObjectHierarchy::tChildContainer aLegendEntryOIDs;
+ lcl_getChildOIDs( aLegendEntryOIDs, xLegendShapeContainer );
+
+ m_aChildMap[ aLegendOID ] = aLegendEntryOIDs;
+ }
+}
+
+void ImplObjectHierarchy::createAxesTree(
+ ObjectHierarchy::tChildContainer & rContainer,
+ const Reference< XChartDocument > & xChartDoc,
+ const Reference< XDiagram > & xDiagram )
+{
+ Reference< XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW );
+ sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram );
+ uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
+ bool bSupportsAxesGrids = ChartTypeHelper::isSupportingMainAxis( xChartType, nDimensionCount, 0 );
+ if( !bSupportsAxesGrids )
+ return;
+
+ Sequence< Reference< XAxis > > aAxes( AxisHelper::getAllAxesOfDiagram( xDiagram, /* bOnlyVisible = */ true ) );
+ if( !m_bOrderingForElementSelector )
+ std::transform( aAxes.begin(), aAxes.end(),
+ std::back_inserter( rContainer ),
+ lcl_ObjectToOID( xChartDoc ));
+
+ // get all axes, also invisible ones
+ aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram );
+ // Grids
+ Reference< frame::XModel > xChartModel = xChartDoc;
+ for( Reference< XAxis > const & xAxis : std::as_const(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, xChartModel ) );
+
+ // axis title
+ lcl_addAxisTitle( xAxis, rContainer, xChartModel );
+ }
+
+ Reference< beans::XPropertySet > xGridProperties( xAxis->getGridProperties() );
+ if( AxisHelper::isGridVisible( xGridProperties ) )
+ {
+ //main grid
+ rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartModel ) );
+ }
+
+ Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() );
+ sal_Int32 nSubGrid = 0;
+ for( nSubGrid = 0; nSubGrid < aSubGrids.getLength(); ++nSubGrid )
+ {
+ Reference< beans::XPropertySet > xSubGridProperties( aSubGrids[nSubGrid] );
+ if( AxisHelper::isGridVisible( xSubGridProperties ) )
+ {
+ //sub grid
+ rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartModel, nSubGrid ) );
+ }
+ }
+ }
+}
+
+void ImplObjectHierarchy::createWallAndFloor(
+ ObjectHierarchy::tChildContainer & rContainer,
+ const Reference< XDiagram > & xDiagram )
+{
+ sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram );
+ bool bIsThreeD = ( nDimensionCount == 3 );
+ bool bHasWall = DiagramHelper::isSupportingFloorAndWall( xDiagram );
+ if( bHasWall && bIsThreeD )
+ {
+ rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, OUString() ) );
+
+ Reference< beans::XPropertySet > xFloor( xDiagram->getFloor());
+ if( xFloor.is())
+ rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_FLOOR, OUString() ) );
+ }
+
+}
+
+void ImplObjectHierarchy::createDiagramTree(
+ ObjectHierarchy::tChildContainer & rContainer,
+ const Reference< XChartDocument > & xChartDoc,
+ const Reference< XDiagram > & xDiagram )
+{
+ if( !m_bOrderingForElementSelector )
+ {
+ createDataSeriesTree( rContainer, xDiagram );
+ createAxesTree( rContainer, xChartDoc, xDiagram );
+ createWallAndFloor( rContainer, xDiagram );
+ }
+ else
+ {
+ createAxesTree( rContainer, xChartDoc, xDiagram );
+ createDataSeriesTree( rContainer, xDiagram );
+ }
+}
+
+void ImplObjectHierarchy::createDataSeriesTree(
+ ObjectHierarchy::tChildContainer & rOutDiagramSubContainer,
+ const Reference< XDiagram > & xDiagram )
+{
+ Reference< XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW );
+
+ try
+ {
+ sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram );
+ Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
+ xCooSysCnt->getCoordinateSystems());
+ for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx )
+ {
+ Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW );
+ Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
+ for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypeSeq.getLength(); ++nCTIdx )
+ {
+ Reference< XChartType > xChartType( aChartTypeSeq[nCTIdx] );
+ Reference< XDataSeriesContainer > xDSCnt( xChartType, uno::UNO_QUERY_THROW );
+ Sequence< Reference< XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries() );
+ const sal_Int32 nNumberOfSeries =
+ ChartTypeHelper::getNumberOfDisplayedSeries( xChartType, aSeriesSeq.getLength());
+
+ 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 );
+
+ ObjectHierarchy::tChildContainer aSeriesSubContainer;
+
+ Reference< chart2::XDataSeries > 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 ) )
+ {
+ Reference< chart2::XRegressionCurveContainer > xCurveCnt( xSeries, uno::UNO_QUERY );
+ if( xCurveCnt.is())
+ {
+ Sequence< Reference< chart2::XRegressionCurve > > aCurves( xCurveCnt->getRegressionCurves());
+ for( sal_Int32 nCurveIdx=0; nCurveIdx<aCurves.getLength(); ++nCurveIdx )
+ {
+ bool bIsAverageLine = RegressionCurveHelper::isMeanValueLine( aCurves[nCurveIdx] );
+ aSeriesSubContainer.emplace_back( ObjectIdentifier::createDataCurveCID( aSeriesParticle, nCurveIdx, bIsAverageLine ) );
+ if( RegressionCurveHelper::hasEquation( aCurves[nCurveIdx] ) )
+ {
+ aSeriesSubContainer.emplace_back( ObjectIdentifier::createDataCurveEquationCID( aSeriesParticle, nCurveIdx ) );
+ }
+ }
+ Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY );
+ Reference< beans::XPropertySet > xErrorBarProp;
+ if( xSeriesProp.is() &&
+ (xSeriesProp->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, OUString(), aSeriesParticle ) );
+ }
+ }
+
+ if( xSeriesProp.is() &&
+ (xSeriesProp->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, OUString(), aSeriesParticle ) );
+ }
+ }
+ }
+ }
+
+ // Data Points
+ // iterate over child shapes of legend and search for matching CIDs
+ if( m_pExplicitValueProvider )
+ {
+ Reference< container::XIndexAccess > xSeriesShapeContainer(
+ m_pExplicitValueProvider->getShapeForCID( aSeriesOID.getObjectCID() ), uno::UNO_QUERY );
+ lcl_getChildOIDs( aSeriesSubContainer, xSeriesShapeContainer );
+ }
+
+ if( ! aSeriesSubContainer.empty())
+ m_aChildMap[ aSeriesOID ] = aSeriesSubContainer;
+ }
+ }
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+}
+
+void ImplObjectHierarchy::createAdditionalShapesTree( ObjectHierarchy::tChildContainer& rContainer )
+{
+ try
+ {
+ if ( m_pExplicitValueProvider )
+ {
+ Reference< drawing::XDrawPage > xDrawPage( m_pExplicitValueProvider->getDrawModelWrapper()->getMainDrawPage() );
+ Reference< drawing::XShapes > xDrawPageShapes( xDrawPage, uno::UNO_QUERY_THROW );
+ Reference< drawing::XShapes > xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) );
+ sal_Int32 nCount = xDrawPageShapes->getCount();
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ Reference< drawing::XShape > xShape;
+ if ( xDrawPageShapes->getByIndex( i ) >>= xShape )
+ {
+ if ( xShape.is() && xShape != xChartRoot )
+ {
+ rContainer.emplace_back( xShape );
+ }
+ }
+ }
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+}
+
+bool ImplObjectHierarchy::hasChildren( const ObjectIdentifier& rParent )
+{
+ if ( rParent.isValid() )
+ {
+ tChildMap::const_iterator aIt( m_aChildMap.find( rParent ));
+ if( aIt != m_aChildMap.end())
+ return ! (aIt->second.empty());
+ }
+ return false;
+}
+
+ObjectHierarchy::tChildContainer ImplObjectHierarchy::getChildren( const ObjectIdentifier& rParent )
+{
+ if ( rParent.isValid() )
+ {
+ tChildMap::const_iterator aIt( m_aChildMap.find( rParent ));
+ if( aIt != m_aChildMap.end())
+ return aIt->second;
+ }
+ return ObjectHierarchy::tChildContainer();
+}
+
+ObjectHierarchy::tChildContainer ImplObjectHierarchy::getSiblings( const ObjectIdentifier& rNode )
+{
+ if ( rNode.isValid() && !ObjectHierarchy::isRootNode( rNode ) )
+ {
+ for (auto const& child : m_aChildMap)
+ {
+ ObjectHierarchy::tChildContainer::const_iterator aElemIt(
+ std::find( child.second.begin(), child.second.end(), rNode ));
+ if( aElemIt != child.second.end())
+ return child.second;
+ }
+ }
+ return ObjectHierarchy::tChildContainer();
+}
+
+ObjectIdentifier ImplObjectHierarchy::getParentImpl(
+ const ObjectIdentifier & rParentOID,
+ const ObjectIdentifier & rOID )
+{
+ // search children
+ ObjectHierarchy::tChildContainer aChildren( getChildren( rParentOID ));
+ ObjectHierarchy::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 ImplObjectHierarchy::getParent(
+ const ObjectIdentifier & rOID )
+{
+ return getParentImpl( ObjectHierarchy::getRootNodeOID(), rOID );
+}
+
+} // namespace impl
+
+ObjectHierarchy::ObjectHierarchy(
+ const Reference< XChartDocument > & xChartDocument,
+ ExplicitValueProvider * pExplicitValueProvider /* = 0 */,
+ bool bFlattenDiagram /* = false */,
+ bool bOrderingForElementSelector /* = false */) :
+ m_apImpl( new impl::ImplObjectHierarchy( xChartDocument, pExplicitValueProvider, bFlattenDiagram, bOrderingForElementSelector ))
+{}
+
+ObjectHierarchy::~ObjectHierarchy()
+{}
+
+ObjectIdentifier ObjectHierarchy::getRootNodeOID()
+{
+ return ObjectIdentifier( "ROOT" );
+}
+
+bool ObjectHierarchy::isRootNode( const ObjectIdentifier& rOID )
+{
+ return ( rOID == ObjectHierarchy::getRootNodeOID() );
+}
+
+ObjectHierarchy::tChildContainer ObjectHierarchy::getTopLevelChildren() const
+{
+ return m_apImpl->getChildren( ObjectHierarchy::getRootNodeOID());
+}
+
+bool ObjectHierarchy::hasChildren( const ObjectIdentifier& rParent ) const
+{
+ return m_apImpl->hasChildren( rParent );
+}
+
+ObjectHierarchy::tChildContainer ObjectHierarchy::getChildren(
+ const ObjectIdentifier& rParent ) const
+{
+ if ( rParent.isValid() )
+ return m_apImpl->getChildren( rParent );
+
+ return ObjectHierarchy::tChildContainer();
+}
+
+ObjectHierarchy::tChildContainer ObjectHierarchy::getSiblings(
+ const ObjectIdentifier& rNode ) const
+{
+ if ( rNode.isValid() && !isRootNode( rNode ) )
+ return m_apImpl->getSiblings( rNode );
+
+ return ObjectHierarchy::tChildContainer();
+}
+
+ObjectIdentifier ObjectHierarchy::getParent(
+ const ObjectIdentifier& rNode ) const
+{
+ return m_apImpl->getParent( rNode );
+}
+
+sal_Int32 ObjectHierarchy::getIndexInParent(
+ const ObjectIdentifier& rNode ) const
+{
+ ObjectIdentifier aParentOID( m_apImpl->getParent( rNode ));
+ tChildContainer aChildren( m_apImpl->getChildren( aParentOID ) );
+ sal_Int32 nIndex = 0;
+ for (auto const& child : aChildren)
+ {
+ if ( child == rNode )
+ return nIndex;
+ ++nIndex;
+ }
+ return -1;
+}
+
+ObjectKeyNavigation::ObjectKeyNavigation(
+ const ObjectIdentifier & rCurrentOID,
+ const Reference< chart2::XChartDocument > & xChartDocument,
+ ExplicitValueProvider * pExplicitValueProvider /* = 0 */ ) :
+ m_aCurrentOID( rCurrentOID ),
+ m_xChartDocument( 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 000000000..84e4325e3
--- /dev/null
+++ b/chart2/source/controller/main/PositionAndSizeHelper.cxx
@@ -0,0 +1,180 @@
+/* -*- 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/chart2/LegendPosition.hpp>
+#include <com/sun/star/chart/ChartLegendExpansion.hpp>
+#include <com/sun/star/chart2/XDiagram.hpp>
+#include <com/sun/star/chart2/RelativePosition.hpp>
+#include <com/sun/star/chart2/RelativeSize.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <tools/gen.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+
+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.getWidth() == 0 || aPageRect.getHeight() == 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.getWidth())/2.0)/double(aPageRect.getWidth());
+ aRelativePosition.Secondary = (double(aPos.Y())+double(aObjectRect.getHeight())/2.0)/double(aPageRect.getHeight());
+ xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) );
+ }
+ else if( eObjectType == OBJECTTYPE_DATA_LABEL )
+ {
+ RelativePosition aAbsolutePosition;
+ RelativePosition aCustomLabelPosition;
+ aAbsolutePosition.Primary = double(rOldPositionAndSize.X) / double(aPageRect.getWidth());
+ aAbsolutePosition.Secondary = double(rOldPositionAndSize.Y) / double(aPageRect.getHeight());
+
+ 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.getWidth()) - aAbsolutePosition.Primary;
+ aCustomLabelPosition.Secondary = double(aPos.Y()) / double(aPageRect.getHeight()) - 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.getWidth());
+ aRelativePosition.Secondary = double(aPos.Y())/double(aPageRect.getHeight());
+ 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.getWidth() );
+ aRelativePosition.Secondary =
+ static_cast< double >( aAnchor.Y()) /
+ static_cast< double >( aPageRect.getHeight());
+
+ xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) );
+
+ aRelativeSize.Primary =
+ static_cast< double >( aObjectRect.getWidth()) /
+ static_cast< double >( aPageRect.getWidth() );
+ if (aRelativeSize.Primary > 1.0)
+ aRelativeSize.Primary = 1.0;
+ aRelativeSize.Secondary =
+ static_cast< double >( aObjectRect.getHeight()) /
+ static_cast< double >( aPageRect.getHeight());
+ 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.getWidth());
+ aRelativePosition.Secondary = double(aPos.Y())/double(aPageRect.getHeight());
+ 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.getWidth())/double(aPageRect.getWidth());
+ aRelativeSize.Secondary = double(aObjectRect.getHeight())/double(aPageRect.getHeight());
+ xObjectProp->setPropertyValue( "RelativeSize", uno::Any(aRelativeSize) );
+ }
+ else
+ return false;
+ return true;
+}
+
+bool PositionAndSizeHelper::moveObject( const OUString& rObjectCID
+ , const uno::Reference< frame::XModel >& 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.set( ObjectIdentifier::getDiagramForCID( rObjectCID, xChartModel ), uno::UNO_QUERY );
+ 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 000000000..5475be204
--- /dev/null
+++ b/chart2/source/controller/main/SelectionHelper.cxx
@@ -0,0 +1,650 @@
+/* -*- 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 <ChartModelHelper.hxx>
+
+#include <com/sun/star/frame/XModel.hpp>
+#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>
+
+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, OUString() ) );//@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, OUString() ) );//@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 uno::Reference< frame::XModel >& 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, OUString() ) );//@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, OUString() ) );//@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( const OUString& rCID
+ , const uno::Reference< frame::XModel >& xChartModel )
+{
+ if( !ObjectIdentifier::isRotateableObject( rCID ) )
+ return false;
+
+ sal_Int32 nDimensionCount = DiagramHelper::getDimension( ChartModelHelper::findDiagram( xChartModel ) );
+
+ return nDimensionCount == 3;
+}
+
+SelectionHelper::SelectionHelper( SdrObject* pSelectedObj )
+ : m_pSelectedObj( pSelectedObj ), m_pMarkObj(nullptr)
+{
+
+}
+SelectionHelper::~SelectionHelper()
+{
+}
+
+bool SelectionHelper::getFrameDragSingles()
+{
+ //true == green == surrounding handles
+ return dynamic_cast<const E3dObject*>( 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 = dynamic_cast<E3dObject*>(pObj);
+ if( !pRotateable )
+ {
+ SolarMutexGuard aSolarGuard;
+ SdrObjList* pSubList = pObj->GetSubList();
+ if(pSubList)
+ {
+ SdrObjListIter aIterator(pSubList, SdrIterMode::DeepWithGroups);
+ while( aIterator.IsMore() && !pRotateable )
+ {
+ SdrObject* pSubObj = aIterator.Next();
+ pRotateable = dynamic_cast<E3dObject*>(pSubObj);
+ }
+ }
+ }
+ }
+
+ 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( dynamic_cast<const SdrPathObj*>( m_pMarkObj) != nullptr )
+ {
+ //if th object is a polygon
+ //from each point a handle is generated
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon = static_cast<SdrPathObj*>(m_pMarkObj)->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 000000000..8161717fe
--- /dev/null
+++ b/chart2/source/controller/main/ShapeController.cxx
@@ -0,0 +1,676 @@
+/* -*- 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 <ShapeController.h>
+#include <ChartController.hxx>
+#include <ViewElementListProvider.hxx>
+#include <dlg_ShapeFont.hxx>
+#include <dlg_ShapeParagraph.hxx>
+#include <chartview/DrawModelWrapper.hxx>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/frame/CommandGroup.hpp>
+#include <com/sun/star/frame/XStorable.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 <tools/diagnose_ex.h>
+
+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()
+{
+}
+
+// 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 )
+ {
+ Reference< frame::XStorable > xStorable( m_pChartController->getModel(), uno::UNO_QUERY );
+ if ( xStorable.is() )
+ {
+ bWritable = !xStorable->isReadonly();
+ }
+ }
+
+ SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( rCommand );
+ if ( aIter != m_aSupportedFeatures.end() )
+ {
+ sal_uInt16 nFeatureId = aIter->second.nFeatureId;
+ switch ( nFeatureId )
+ {
+ case COMMAND_ID_FORMAT_LINE:
+ case COMMAND_ID_FORMAT_AREA:
+ case COMMAND_ID_TEXT_ATTRIBUTES:
+ case COMMAND_ID_TRANSFORM_DIALOG:
+ case COMMAND_ID_OBJECT_TITLE_DESCRIPTION:
+ case COMMAND_ID_RENAME_OBJECT:
+ {
+ aReturn.bEnabled = bWritable;
+ aReturn.aState <<= false;
+ }
+ break;
+ case COMMAND_ID_BRING_TO_FRONT:
+ case COMMAND_ID_FORWARD:
+ {
+ aReturn.bEnabled = ( bWritable && isForwardPossible() );
+ aReturn.aState <<= false;
+ }
+ break;
+ case COMMAND_ID_BACKWARD:
+ case COMMAND_ID_SEND_TO_BACK:
+ {
+
+ aReturn.bEnabled = ( bWritable && isBackwardPossible() );
+ aReturn.aState <<= false;
+ }
+ break;
+ case COMMAND_ID_FONT_DIALOG:
+ case COMMAND_ID_PARAGRAPH_DIALOG:
+ {
+ 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;
+
+ sal_uInt16 nFeatureId = aIter->second.nFeatureId;
+ switch ( nFeatureId )
+ {
+ case COMMAND_ID_FORMAT_LINE:
+ {
+ executeDispatch_FormatLine();
+ }
+ break;
+ case COMMAND_ID_FORMAT_AREA:
+ {
+ executeDispatch_FormatArea();
+ }
+ break;
+ case COMMAND_ID_TEXT_ATTRIBUTES:
+ {
+ executeDispatch_TextAttributes();
+ }
+ break;
+ case COMMAND_ID_TRANSFORM_DIALOG:
+ {
+ executeDispatch_TransformDialog();
+ }
+ break;
+ case COMMAND_ID_OBJECT_TITLE_DESCRIPTION:
+ {
+ executeDispatch_ObjectTitleDescription();
+ }
+ break;
+ case COMMAND_ID_RENAME_OBJECT:
+ {
+ executeDispatch_RenameObject();
+ }
+ break;
+ case COMMAND_ID_BRING_TO_FRONT:
+ case COMMAND_ID_FORWARD:
+ case COMMAND_ID_BACKWARD:
+ case COMMAND_ID_SEND_TO_BACK:
+ {
+ executeDispatch_ChangeZOrder( nFeatureId );
+ }
+ break;
+ case COMMAND_ID_FONT_DIALOG:
+ {
+ executeDispatch_FontDialog();
+ }
+ break;
+ case COMMAND_ID_PARAGRAPH_DIALOG:
+ {
+ executeDispatch_ParagraphDialog();
+ }
+ break;
+ default:
+ {
+ }
+ break;
+ }
+}
+
+void ShapeController::describeSupportedFeatures()
+{
+ implDescribeSupportedFeature( ".uno:FormatLine", COMMAND_ID_FORMAT_LINE, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:FormatArea", COMMAND_ID_FORMAT_AREA, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:TextAttributes", COMMAND_ID_TEXT_ATTRIBUTES, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:TransformDialog", COMMAND_ID_TRANSFORM_DIALOG, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:ObjectTitleDescription", COMMAND_ID_OBJECT_TITLE_DESCRIPTION, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:RenameObject", COMMAND_ID_RENAME_OBJECT, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:BringToFront", COMMAND_ID_BRING_TO_FRONT, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:Forward", COMMAND_ID_FORWARD, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:Backward", COMMAND_ID_BACKWARD, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:SendToBack", COMMAND_ID_SEND_TO_BACK, CommandGroup::FORMAT );
+ implDescribeSupportedFeature( ".uno:FontDialog", COMMAND_ID_FONT_DIALOG, CommandGroup::EDIT );
+ implDescribeSupportedFeature( ".uno:ParagraphDialog", COMMAND_ID_PARAGRAPH_DIALOG, 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));
+ 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() == OBJ_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 sal_uInt16* 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() );
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ weld::Window* pChartWindow(m_pChartController->GetChartFrame());
+ ScopedVclPtr< AbstractSvxObjectTitleDescDialog > pDlg(
+ pFact->CreateSvxObjectTitleDescDialog(pChartWindow, aTitle, aDescription));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ pDlg->GetTitle( aTitle );
+ pDlg->GetDescription( aDescription );
+ pSelectedObj->SetTitle( aTitle );
+ pSelectedObj->SetDescription( aDescription );
+ }
+}
+
+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( sal_uInt16 nId )
+{
+ SolarMutexGuard aGuard;
+ DrawViewWrapper* pDrawViewWrapper = ( m_pChartController ? m_pChartController->GetDrawViewWrapper() : nullptr );
+ if ( !pDrawViewWrapper )
+ return;
+
+ switch ( nId )
+ {
+ case COMMAND_ID_BRING_TO_FRONT:
+ {
+ if ( isForwardPossible() )
+ {
+ pDrawViewWrapper->PutMarkedToTop();
+ }
+ }
+ break;
+ case COMMAND_ID_FORWARD:
+ {
+ if ( isForwardPossible() )
+ {
+ pDrawViewWrapper->MovMarkedToTop();
+ }
+ }
+ break;
+ case COMMAND_ID_BACKWARD:
+ {
+ if ( isBackwardPossible() )
+ {
+ pDrawViewWrapper->MovMarkedToBtm();
+ }
+ }
+ break;
+ case COMMAND_ID_SEND_TO_BACK:
+ {
+ 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 );
+
+ SfxItemSet aNewAttr(
+ rPool,
+ svl::Items<
+ EE_ITEMS_START, EE_ITEMS_END,
+ SID_ATTR_PARA_PAGEBREAK, SID_ATTR_PARA_WIDOWS>{});
+ 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;
+ Reference< drawing::XDrawPage > xDrawPage( pDrawModelWrapper->getMainDrawPage() );
+ Reference< drawing::XShapes > xDrawPageShapes( xDrawPage, uno::UNO_QUERY_THROW );
+ Reference< drawing::XShapes > xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) );
+ sal_Int32 nCount = xDrawPageShapes->getCount();
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ Reference< drawing::XShape > xShape;
+ if ( xDrawPageShapes->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;
+ Reference< drawing::XDrawPage > xDrawPage( pDrawModelWrapper->getMainDrawPage() );
+ Reference< drawing::XShapes > xDrawPageShapes( xDrawPage, uno::UNO_QUERY_THROW );
+ Reference< drawing::XShapes > xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) );
+ sal_Int32 nCount = xDrawPageShapes->getCount();
+ for ( sal_Int32 i = nCount - 1; i >= 0; --i )
+ {
+ Reference< drawing::XShape > xShape;
+ if ( xDrawPageShapes->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 000000000..70fcdecf9
--- /dev/null
+++ b/chart2/source/controller/main/ShapeController.hxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_SHAPECONTROLLER_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_SHAPECONTROLLER_HXX
+
+#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 SAL_CALL disposing() 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( sal_uInt16 nId );
+ void executeDispatch_FontDialog();
+ void executeDispatch_ParagraphDialog();
+
+ SdrObject* getFirstAdditionalShape();
+ SdrObject* getLastAdditionalShape();
+ bool isBackwardPossible();
+ bool isForwardPossible();
+
+ ChartController* m_pChartController;
+};
+
+} // namespace chart
+
+// INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_SHAPECONTROLLER_HXX
+#endif
+
+/* 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 000000000..1e6c06c35
--- /dev/null
+++ b/chart2/source/controller/main/StatusBarCommandDispatch.cxx
@@ -0,0 +1,128 @@
+/* -*- 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/chart2/XChartDocument.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+
+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,
+ const Reference< frame::XModel > & xModel,
+ const Reference< view::XSelectionSupplier > & xSelSupp ) :
+ impl::StatusBarCommandDispatch_Base( xContext ),
+ m_xModifiable( xModel, uno::UNO_QUERY ),
+ m_xSelectionSupplier( xSelSupp ),
+ m_bIsModified( false )
+{}
+
+StatusBarCommandDispatch::~StatusBarCommandDispatch()
+{}
+
+void StatusBarCommandDispatch::initialize()
+{
+ if( m_xModifiable.is())
+ {
+ m_xModifiable->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 )
+ {
+ uno::Any aArg;
+ Reference< chart2::XChartDocument > xDoc( m_xModifiable, uno::UNO_QUERY );
+ aArg <<= ObjectNameProvider::getSelectedObjectText( m_aSelectedOID.getObjectCID(), xDoc );
+ 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 SAL_CALL StatusBarCommandDispatch::disposing()
+{
+ m_xModifiable.clear();
+ m_xSelectionSupplier.clear();
+}
+
+// ____ XEventListener (base of XModifyListener) ____
+void SAL_CALL StatusBarCommandDispatch::disposing( const lang::EventObject& /* Source */ )
+{
+ m_xModifiable.clear();
+ m_xSelectionSupplier.clear();
+}
+
+// ____ XModifyListener ____
+void SAL_CALL StatusBarCommandDispatch::modified( const lang::EventObject& aEvent )
+{
+ if( m_xModifiable.is())
+ m_bIsModified = m_xModifiable->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 000000000..8ad9e62aa
--- /dev/null
+++ b/chart2/source/controller/main/StatusBarCommandDispatch.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_STATUSBARCOMMANDDISPATCH_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_STATUSBARCOMMANDDISPATCH_HXX
+
+#include "CommandDispatch.hxx"
+#include <ObjectIdentifier.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/view/XSelectionChangeListener.hpp>
+
+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,
+ const css::uno::Reference< css::frame::XModel > & 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 SAL_CALL disposing() 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:
+ css::uno::Reference< css::util::XModifiable > m_xModifiable;
+ css::uno::Reference< css::view::XSelectionSupplier > m_xSelectionSupplier;
+ bool m_bIsModified;
+ ObjectIdentifier m_aSelectedOID;
+};
+
+} // namespace chart
+
+// INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_STATUSBARCOMMANDDISPATCH_HXX
+#endif
+
+/* 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 000000000..b985558a3
--- /dev/null
+++ b/chart2/source/controller/main/ToolbarController.cxx
@@ -0,0 +1,124 @@
+/* -*- 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):
+ ChartToolbarControllerBase(m_aMutex)
+{
+ css::uno::Reference<css::frame::XFrame> xFrame;
+ sal_Int32 nLength = rProperties.getLength();
+ for (sal_Int32 i = 0; i < nLength; ++i)
+ {
+ css::beans::PropertyValue aPropValue;
+ rProperties[i] >>= aPropValue;
+ if (aPropValue.Name == "Frame")
+ aPropValue.Value >>= xFrame;
+ }
+
+ css::uno::Reference<css::frame::XFramesSupplier> xFramesSupplier(xFrame, css::uno::UNO_QUERY);
+ mxFramesSupplier = xFramesSupplier;
+}
+
+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 000000000..78bc1f6b0
--- /dev/null
+++ b/chart2/source/controller/main/UndoActions.cxx
@@ -0,0 +1,123 @@
+/* -*- 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 <com/sun/star/lang/DisposedException.hpp>
+
+#include <svx/svdundo.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+
+namespace chart::impl
+{
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::lang::DisposedException;
+
+UndoElement::UndoElement( const OUString& i_actionString, const Reference< XModel >& i_documentModel, const std::shared_ptr< ChartModelClone >& i_modelClone )
+ :UndoElement_MBase()
+ ,UndoElement_TBase( m_aMutex )
+ ,m_sActionString( i_actionString )
+ ,m_xDocumentModel( i_documentModel )
+ ,m_pModelClone( i_modelClone )
+{
+}
+
+UndoElement::~UndoElement()
+{
+}
+
+void SAL_CALL UndoElement::disposing()
+{
+ 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 )
+ :ShapeUndoElement_MBase()
+ ,ShapeUndoElement_TBase( m_aMutex )
+ ,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();
+}
+
+void SAL_CALL ShapeUndoElement::disposing()
+{
+}
+
+} // 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 000000000..770cb06cf
--- /dev/null
+++ b/chart2/source/controller/main/UndoActions.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 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_UNDOACTIONS_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_UNDOACTIONS_HXX
+
+#include <com/sun/star/document/XUndoAction.hpp>
+
+#include <rtl/ustring.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+#include <memory>
+
+namespace com::sun::star::frame { class XModel; }
+
+class SdrUndoAction;
+
+namespace chart
+{
+class ChartModelClone;
+
+namespace impl
+{
+
+typedef ::cppu::BaseMutex UndoElement_MBase;
+typedef ::cppu::WeakComponentImplHelper< css::document::XUndoAction > UndoElement_TBase;
+
+class UndoElement :public UndoElement_MBase
+ ,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( const OUString & i_actionString,
+ const css::uno::Reference< css::frame::XModel >& i_documentModel,
+ const std::shared_ptr< ChartModelClone >& i_modelClone
+ );
+
+ 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;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+protected:
+ virtual ~UndoElement() override;
+
+private:
+ void impl_toggleModelState();
+
+private:
+ OUString m_sActionString;
+ css::uno::Reference< css::frame::XModel > m_xDocumentModel;
+ std::shared_ptr< ChartModelClone > m_pModelClone;
+};
+
+typedef ::cppu::BaseMutex ShapeUndoElement_MBase;
+typedef ::cppu::WeakComponentImplHelper< css::document::XUndoAction > ShapeUndoElement_TBase;
+class ShapeUndoElement :public ShapeUndoElement_MBase
+ ,public ShapeUndoElement_TBase
+{
+public:
+ explicit ShapeUndoElement( std::unique_ptr<SdrUndoAction> xSdrUndoAction );
+
+ // XUndoAction
+ virtual OUString SAL_CALL getTitle() override;
+ virtual void SAL_CALL undo( ) override;
+ virtual void SAL_CALL redo( ) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+protected:
+ virtual ~ShapeUndoElement() override;
+
+private:
+ std::unique_ptr<SdrUndoAction> m_xAction;
+};
+
+} // namespace impl
+} // namespace chart
+
+// INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_UNDOACTIONS_HXX
+#endif
+
+/* 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 000000000..e4bd85a3b
--- /dev/null
+++ b/chart2/source/controller/main/UndoCommandDispatch.cxx
@@ -0,0 +1,147 @@
+/* -*- 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 <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+#include <com/sun/star/document/UndoFailedException.hpp>
+#include <com/sun/star/document/XUndoManagerSupplier.hpp>
+
+#include <vcl/svapp.hxx>
+#include <tools/diagnose_ex.h>
+
+#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,
+ const Reference< frame::XModel > & xModel ) :
+ CommandDispatch( xContext ),
+ m_xModel( xModel )
+{
+ uno::Reference< document::XUndoManagerSupplier > xSuppUndo( m_xModel, uno::UNO_QUERY_THROW );
+ m_xUndoManager.set( xSuppUndo->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 SAL_CALL UndoCommandDispatch::disposing()
+{
+ 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 000000000..aa5f5b2e3
--- /dev/null
+++ b/chart2/source/controller/main/UndoCommandDispatch.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_UNDOCOMMANDDISPATCH_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_UNDOCOMMANDDISPATCH_HXX
+
+#include "CommandDispatch.hxx"
+
+namespace com::sun::star::document { class XUndoManager; }
+namespace com::sun::star::frame { class XModel; }
+
+namespace chart
+{
+
+/** This is a CommandDispatch implementation for Undo and Redo.
+ */
+class UndoCommandDispatch : public CommandDispatch
+{
+public:
+ explicit UndoCommandDispatch(
+ const css::uno::Reference< css::uno::XComponentContext > & xContext,
+ const css::uno::Reference< css::frame::XModel > & 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 SAL_CALL disposing() 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:
+ css::uno::Reference< css::frame::XModel > m_xModel;
+ css::uno::Reference< css::document::XUndoManager > m_xUndoManager;
+};
+
+} // namespace chart
+
+// INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_UNDOCOMMANDDISPATCH_HXX
+#endif
+
+/* 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 000000000..91687aebd
--- /dev/null
+++ b/chart2/source/controller/main/UndoGuard.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 "UndoGuard.hxx"
+#include "ChartModelClone.hxx"
+#include "UndoActions.hxx"
+
+#include <com/sun/star/document/XUndoManager.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+
+namespace chart
+{
+
+UndoGuard::UndoGuard( const OUString& i_undoString, const uno::Reference< document::XUndoManager > & i_undoManager,
+ const ModelFacet i_facet )
+ :m_xChartModel( i_undoManager->getParent(), uno::UNO_QUERY_THROW )
+ ,m_xUndoManager( i_undoManager )
+ ,m_pDocumentSnapshot()
+ ,m_aUndoString( i_undoString )
+ ,m_bActionPosted( false )
+{
+ 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 000000000..0d9fa7538
--- /dev/null
+++ b/chart2/source/controller/main/UndoGuard.hxx
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_UNDOGUARD_HXX
+#define INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_UNDOGUARD_HXX
+
+#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(
+ const 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:
+ const css::uno::Reference< css::frame::XModel > 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;
+};
+
+}
+// INCLUDED_CHART2_SOURCE_CONTROLLER_MAIN_UNDOGUARD_HXX
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */