1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sal/config.h>
23 #include <config_wasm_strip.h>
24 #include <ChartController.hxx>
25 #include <ChartView.hxx>
26 #include <servicenames.hxx>
28 #include <dlg_DataSource.hxx>
29 #include <ChartModel.hxx>
30 #include <ChartModelHelper.hxx>
31 #include <ChartType.hxx>
32 #include "ControllerCommandDispatch.hxx"
33 #include <DataSeries.hxx>
34 #include <Diagram.hxx>
35 #include <strings.hrc>
36 #include <ChartViewHelper.hxx>
38 #include <ChartWindow.hxx>
39 #include <chartview/DrawModelWrapper.hxx>
40 #include <DrawViewWrapper.hxx>
41 #include <ObjectIdentifier.hxx>
42 #include <ControllerLockGuard.hxx>
43 #include "UndoGuard.hxx"
44 #include "ChartDropTargetHelper.hxx"
46 #include <dlg_ChartType.hxx>
47 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
48 #include <AccessibleChartView.hxx>
50 #include "DrawCommandDispatch.hxx"
51 #include "ShapeController.hxx"
52 #include "UndoActions.hxx"
53 #include <ViewElementListProvider.hxx>
55 #include <comphelper/dispatchcommand.hxx>
56 #include <BaseCoordinateSystem.hxx>
58 #include <com/sun/star/frame/XController2.hpp>
59 #include <com/sun/star/util/CloseVetoException.hpp>
60 #include <com/sun/star/frame/LayoutManagerEvents.hpp>
61 #include <com/sun/star/frame/XLayoutManagerEventBroadcaster.hpp>
62 #include <com/sun/star/ui/XSidebar.hpp>
63 #include <com/sun/star/chart2/XDataProviderAccess.hpp>
64 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
66 #include <sal/log.hxx>
67 #include <tools/debug.hxx>
68 #include <svx/sidebar/SelectionChangeHandler.hxx>
69 #include <toolkit/helper/vclunohelper.hxx>
71 #include <vcl/svapp.hxx>
72 #include <vcl/weld.hxx>
73 #include <osl/mutex.hxx>
74 #include <comphelper/lok.hxx>
76 #include <sfx2/sidebar/SidebarController.hxx>
77 #include <com/sun/star/awt/XVclWindowPeer.hpp>
78 #include <com/sun/star/frame/XLayoutManager.hpp>
80 // this is needed to properly destroy the unique_ptr to the AcceleratorExecute
82 #include <svtools/acceleratorexecute.hxx>
83 #include <svx/ActionDescriptionProvider.hxx>
84 #include <comphelper/diagnose_ex.hxx>
86 // enable the following define to let the controller listen to model changes and
87 // react on this by rebuilding the view
88 #define TEST_ENABLE_MODIFY_LISTENER
93 using namespace ::com::sun::star
;
94 using namespace ::com::sun::star::accessibility
;
95 using namespace ::com::sun::star::chart2
;
96 using ::com::sun::star::uno::Reference
;
97 using ::com::sun::star::uno::Sequence
;
99 ChartController::ChartController(uno::Reference
<uno::XComponentContext
> xContext
) :
100 m_aLifeTimeManager( nullptr ),
101 m_bSuspended( false ),
102 m_xCC(std::move(xContext
)),
103 m_aModel( nullptr, m_aModelMutex
),
104 m_eDragMode(SdrDragMode::Move
),
105 m_aDoubleClickTimer("chart2 ChartController m_aDoubleClickTimer"),
106 m_bWaitingForDoubleClick(false),
107 m_bWaitingForMouseUp(false),
108 m_bFieldButtonDown(false),
109 m_bConnectingToView(false),
111 m_aDispatchContainer( m_xCC
),
112 m_eDrawMode( CHARTDRAW_SELECT
),
113 mpSelectionChangeHandler(new svx::sidebar::SelectionChangeHandler(
114 [this]() { return this->GetContextName(); },
115 this, vcl::EnumContext::Context::Cell
))
117 m_aDoubleClickTimer
.SetInvokeHandler( LINK( this, ChartController
, DoubleClickWaitingHdl
) );
120 ChartController::~ChartController()
122 stopDoubleClickWaiting();
125 ChartController::TheModel::TheModel( rtl::Reference
<::chart::ChartModel
> xModel
) :
126 m_xModel(std::move( xModel
)),
131 ChartController::TheModel::~TheModel()
135 void ChartController::TheModel::addListener( ChartController
* pController
)
139 //if you need to be able to veto against the destruction of the model
140 // you must add as a close listener
142 //otherwise you 'can' add as closelistener or 'must' add as dispose event listener
144 m_xModel
->addCloseListener(
145 static_cast<util::XCloseListener
*>(pController
) );
149 void ChartController::TheModel::removeListener( ChartController
* pController
)
152 m_xModel
->removeCloseListener(
153 static_cast<util::XCloseListener
*>(pController
) );
156 void ChartController::TheModel::tryTermination()
167 //@todo ? are we allowed to use sal_True here if we have the explicit ownership?
168 //I think yes, because there might be other CloseListeners later in the list which might be interested still
169 //but make sure that we do not throw the CloseVetoException here ourselves
170 //so stop listening before trying to terminate or check the source of queryclosing event
171 m_xModel
->close(true);
173 m_bOwnership
= false;
175 catch( const util::CloseVetoException
& )
177 //since we have indicated to give up the ownership with parameter true in close call
178 //the one who has thrown the CloseVetoException is the new owner
180 SAL_WARN_IF( m_bOwnership
, "chart2.main", "a well known owner has caught a CloseVetoException after calling close(true)");
181 m_bOwnership
= false;
187 catch(const uno::Exception
&)
189 DBG_UNHANDLED_EXCEPTION( "chart2", "Termination of model failed" );
193 ChartController::TheModelRef::TheModelRef( TheModel
* pTheModel
, osl::Mutex
& rMutex
) :
194 m_rModelMutex(rMutex
)
196 osl::Guard
< osl::Mutex
> aGuard( m_rModelMutex
);
197 m_xTheModel
= pTheModel
;
199 ChartController::TheModelRef::TheModelRef( const TheModelRef
& rTheModel
, ::osl::Mutex
& rMutex
) :
200 m_rModelMutex(rMutex
)
202 osl::Guard
< osl::Mutex
> aGuard( m_rModelMutex
);
203 m_xTheModel
= rTheModel
.m_xTheModel
;
205 ChartController::TheModelRef
& ChartController::TheModelRef::operator=(TheModel
* pTheModel
)
207 osl::Guard
< osl::Mutex
> aGuard( m_rModelMutex
);
208 m_xTheModel
= pTheModel
;
211 ChartController::TheModelRef
& ChartController::TheModelRef::operator=(const TheModelRef
& rTheModel
)
213 osl::Guard
< osl::Mutex
> aGuard( m_rModelMutex
);
214 m_xTheModel
= rTheModel
.operator->();
217 ChartController::TheModelRef::~TheModelRef()
219 osl::Guard
< osl::Mutex
> aGuard( m_rModelMutex
);
222 bool ChartController::TheModelRef::is() const
224 return m_xTheModel
.is();
229 rtl::Reference
<ChartType
> getChartType(const rtl::Reference
<ChartModel
>& xChartDoc
)
231 rtl::Reference
<Diagram
> xDiagram
= xChartDoc
->getFirstChartDiagram();
235 const std::vector
< rtl::Reference
< BaseCoordinateSystem
> > xCooSysSequence( xDiagram
->getBaseCoordinateSystems());
236 if (xCooSysSequence
.empty())
239 return xCooSysSequence
[0]->getChartTypes2()[0];
244 OUString
ChartController::GetContextName()
249 uno::Any aAny
= getSelection();
250 if (!aAny
.hasValue())
251 return u
"Chart"_ustr
;
257 return u
"Chart"_ustr
;
259 ObjectType eObjectID
= ObjectIdentifier::getObjectType(aCID
);
262 case OBJECTTYPE_DATA_SERIES
:
263 return u
"Series"_ustr
;
264 case OBJECTTYPE_DATA_ERRORS_X
:
265 case OBJECTTYPE_DATA_ERRORS_Y
:
266 case OBJECTTYPE_DATA_ERRORS_Z
:
267 return u
"ErrorBar"_ustr
;
268 case OBJECTTYPE_AXIS
:
270 case OBJECTTYPE_GRID
:
272 case OBJECTTYPE_DIAGRAM
:
274 rtl::Reference
<ChartType
> xChartType
= getChartType(getChartModel());
275 if (xChartType
.is() && xChartType
->getChartType() == "com.sun.star.chart2.PieChartType")
276 return u
"ChartElements"_ustr
;
279 case OBJECTTYPE_DATA_CURVE
:
280 case OBJECTTYPE_DATA_AVERAGE_LINE
:
281 return u
"Trendline"_ustr
;
286 return u
"Chart"_ustr
;
291 bool ChartController::impl_isDisposedOrSuspended() const
293 if( m_aLifeTimeManager
.impl_isDisposed() )
298 OSL_FAIL( "This Controller is suspended" );
306 uno::Reference
<ui::XSidebar
> getSidebarFromModel(const uno::Reference
<frame::XModel
>& xModel
)
308 uno::Reference
<container::XChild
> xChild(xModel
, uno::UNO_QUERY
);
312 uno::Reference
<frame::XModel
> xParent (xChild
->getParent(), uno::UNO_QUERY
);
316 uno::Reference
<frame::XController2
> xController(xParent
->getCurrentController(), uno::UNO_QUERY
);
317 if (!xController
.is())
320 uno::Reference
<ui::XSidebarProvider
> xSidebarProvider
= xController
->getSidebar();
321 if (!xSidebarProvider
.is())
324 return xSidebarProvider
->getSidebar();
331 void SAL_CALL
ChartController::attachFrame(
332 const uno::Reference
<frame::XFrame
>& xFrame
)
334 SolarMutexGuard aGuard
;
336 if( impl_isDisposedOrSuspended() ) //@todo? allow attaching the frame while suspended?
337 return; //behave passive if already disposed or suspended
339 if(m_xFrame
.is()) //what happens, if we do have a Frame already??
341 //@todo? throw exception?
342 OSL_FAIL( "there is already a frame attached to the controller" );
347 m_xFrame
= xFrame
; //the frameloader is responsible to call xFrame->setComponent
349 // Only notify after setting the frame, otherwise notification will fail
350 mpSelectionChangeHandler
->Connect();
352 uno::Reference
<ui::XSidebar
> xSidebar
= getSidebarFromModel(getChartModel());
355 auto pSidebar
= dynamic_cast<sfx2::sidebar::SidebarController
*>(xSidebar
.get());
357 pSidebar
->registerSidebarForFrame(this);
358 pSidebar
->updateModel(getChartModel());
359 css::lang::EventObject aEvent
;
360 mpSelectionChangeHandler
->selectionChanged(aEvent
);
363 //add as disposelistener to the frame (due to persistent reference) ??...:
365 //the frame is considered to be owner of this controller and will live longer than we do
366 //the frame or the disposer of the frame has the duty to call suspend and dispose on this object
367 //so we do not need to add as lang::XEventListener for DisposingEvents right?
369 //@todo nothing right???
371 //create view @todo is this the correct place here??
373 vcl::Window
* pParent
= nullptr;
374 //get the window parent from the frame to use as parent for our new window
377 uno::Reference
<awt::XWindow
> xContainerWindow
= xFrame
->getContainerWindow();
378 if (xContainerWindow
)
379 xContainerWindow
->setVisible(true);
380 pParent
= VCLUnoHelper::GetWindow( xContainerWindow
);
385 SolarMutexGuard aSolarGuard
;
386 auto pChartWindow
= VclPtr
<ChartWindow
>::Create(this,pParent
,pParent
?pParent
->GetStyle():0);
387 pChartWindow
->SetBackground();//no Background
388 m_xViewWindow
.set( pChartWindow
->GetComponentInterface(), uno::UNO_QUERY
);
389 pChartWindow
->Show();
390 m_apDropTargetHelper
.reset(
391 new ChartDropTargetHelper( pChartWindow
->GetDropTarget(), getChartModel()));
393 impl_createDrawViewController();
398 uno::Reference
< beans::XPropertySet
> xPropSet( xFrame
, uno::UNO_QUERY
);
403 uno::Reference
< css::frame::XLayoutManager
> xLayoutManager
;
404 xPropSet
->getPropertyValue( u
"LayoutManager"_ustr
) >>= xLayoutManager
;
405 if ( xLayoutManager
.is() )
407 xLayoutManager
->lock();
408 xLayoutManager
->requestElement( u
"private:resource/menubar/menubar"_ustr
);
409 //@todo: createElement should become unnecessary, remove when #i79198# is fixed
410 xLayoutManager
->createElement( u
"private:resource/toolbar/standardbar"_ustr
);
411 xLayoutManager
->requestElement( u
"private:resource/toolbar/standardbar"_ustr
);
412 //@todo: createElement should become unnecessary, remove when #i79198# is fixed
413 xLayoutManager
->createElement( u
"private:resource/toolbar/toolbar"_ustr
);
414 xLayoutManager
->requestElement( u
"private:resource/toolbar/toolbar"_ustr
);
416 // #i12587# support for shapes in chart
417 xLayoutManager
->createElement( u
"private:resource/toolbar/drawbar"_ustr
);
418 xLayoutManager
->requestElement( u
"private:resource/toolbar/drawbar"_ustr
);
420 xLayoutManager
->requestElement( u
"private:resource/statusbar/statusbar"_ustr
);
421 xLayoutManager
->unlock();
423 // add as listener to get notified when
424 m_xLayoutManagerEventBroadcaster
.set( xLayoutManager
, uno::UNO_QUERY
);
425 if( m_xLayoutManagerEventBroadcaster
.is())
426 m_xLayoutManagerEventBroadcaster
->addLayoutManagerEventListener( this );
429 catch( const uno::Exception
& )
431 DBG_UNHANDLED_EXCEPTION("chart2");
437 //XModeChangeListener
438 void SAL_CALL
ChartController::modeChanged( const util::ModeChangeEvent
& rEvent
)
440 SolarMutexGuard aGuard
;
441 auto pChartWindow(GetChartWindow());
442 //adjust controller to view status changes
444 if( rEvent
.NewMode
== "dirty" )
446 //the view has become dirty, we should repaint it if we have a window
448 pChartWindow
->ForceInvalidate();
450 else if( rEvent
.NewMode
== "invalid" )
452 //the view is about to become invalid so end all actions on it
453 impl_invalidateAccessible();
454 if( m_pDrawViewWrapper
&& m_pDrawViewWrapper
->IsTextEdit() )
456 if( m_pDrawViewWrapper
)
458 m_pDrawViewWrapper
->UnmarkAll();
459 m_pDrawViewWrapper
->HideSdrPage();
464 //the view was rebuild so we can start some actions on it again
465 if( !m_bConnectingToView
)
467 if(pChartWindow
&& m_aModel
.is() )
469 m_bConnectingToView
= true;
471 GetDrawModelWrapper();
472 if(m_pDrawModelWrapper
)
475 if( m_pDrawViewWrapper
)
476 m_pDrawViewWrapper
->ReInit();
480 if( m_aSelection
.hasSelection() )
481 this->impl_selectObjectAndNotiy();
483 ChartModelHelper::triggerRangeHighlighting( getChartModel() );
485 impl_initializeAccessible();
487 pChartWindow
->Invalidate();
490 m_bConnectingToView
= false;
496 sal_Bool SAL_CALL
ChartController::attachModel( const uno::Reference
< frame::XModel
> & xModel
)
498 impl_invalidateAccessible();
500 //is called to attach the controller to a new model.
501 //return true if attach was successfully, false otherwise (e.g. if you do not work with a model)
503 SolarMutexResettableGuard aGuard
;
504 if( impl_isDisposedOrSuspended() ) //@todo? allow attaching a new model while suspended?
505 return false; //behave passive if already disposed or suspended
508 ::chart::ChartModel
* pChartModel
= dynamic_cast<::chart::ChartModel
*>(xModel
.get());
509 assert(!xModel
|| pChartModel
);
511 TheModelRef
aNewModelRef( new TheModel(pChartModel
), m_aModelMutex
);
512 TheModelRef
aOldModelRef(m_aModel
,m_aModelMutex
);
513 m_aModel
= aNewModelRef
;
515 //--handle relations to the old model if any
516 if( aOldModelRef
.is() )
518 if( m_xChartView
.is() )
519 m_xChartView
->removeModeChangeListener(this);
520 m_pDrawModelWrapper
.reset();
522 aOldModelRef
->removeListener( this );
523 #ifdef TEST_ENABLE_MODIFY_LISTENER
524 if( aOldModelRef
->getModel().is())
525 aOldModelRef
->getModel()->removeModifyListener( this );
529 //--handle relations to the new model
530 aNewModelRef
->addListener( this );
532 aGuard
.reset(); // lock for m_aDispatchContainer access
533 // set new model at dispatchers
534 m_aDispatchContainer
.setModel( aNewModelRef
->getModel());
535 rtl::Reference
<ControllerCommandDispatch
> pDispatch
= new ControllerCommandDispatch( m_xCC
, this, &m_aDispatchContainer
);
536 pDispatch
->initialize();
538 // the dispatch container will return "this" for all commands returned by
539 // impl_getAvailableCommands(). That means, for those commands dispatch()
540 // is called here at the ChartController.
541 m_aDispatchContainer
.setChartDispatch( pDispatch
, impl_getAvailableCommands() );
543 rtl::Reference
<DrawCommandDispatch
> pDrawDispatch
= new DrawCommandDispatch( m_xCC
, this );
544 pDrawDispatch
->initialize();
545 m_aDispatchContainer
.setDrawCommandDispatch( pDrawDispatch
.get() );
547 rtl::Reference
<ShapeController
> pShapeController
= new ShapeController( m_xCC
, this );
548 pShapeController
->initialize();
549 m_aDispatchContainer
.setShapeController( pShapeController
.get() );
552 #ifdef TEST_ENABLE_MODIFY_LISTENER
553 if( aNewModelRef
->getModel().is())
554 aNewModelRef
->getModel()->addModifyListener( this );
557 // #i119999# Do not do this per default to allow the user to deselect the chart OLE with a single press to ESC
558 // select chart area per default:
559 // select( uno::Any( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) ) );
561 rtl::Reference
< ChartModel
> xFact
= getChartModel();
564 m_xChartView
= dynamic_cast<::chart::ChartView
*>(xFact
->createInstance( CHART_VIEW_SERVICE_NAME
).get());
565 GetDrawModelWrapper();
566 m_xChartView
->addModeChangeListener(this);
569 //the frameloader is responsible to call xModel->connectController
571 SolarMutexGuard aGuard2
;
572 auto pChartWindow(GetChartWindow());
574 pChartWindow
->Invalidate();
577 m_xUndoManager
.set( getChartModel()->getUndoManager(), uno::UNO_SET_THROW
);
582 uno::Reference
< frame::XFrame
> SAL_CALL
ChartController::getFrame()
584 //provides access to owner frame of this controller
585 //return the frame containing this controller
590 uno::Reference
< frame::XModel
> SAL_CALL
ChartController::getModel()
592 return getChartModel();
595 rtl::Reference
<::chart::ChartModel
> ChartController::getChartModel()
597 //provides access to currently attached model
598 //returns the currently attached model
600 //return nothing, if you do not have a model
601 TheModelRef
aModelRef( m_aModel
, m_aModelMutex
);
603 return aModelRef
->getModel();
608 rtl::Reference
<::chart::Diagram
> ChartController::getFirstDiagram()
610 return getChartModel()->getFirstChartDiagram();
613 uno::Any SAL_CALL
ChartController::getViewData()
615 //provides access to current view status
616 //set of data that can be used to restore the current view status at later time
617 // by using XController::restoreViewData()
619 SolarMutexGuard aGuard
;
620 if( impl_isDisposedOrSuspended() )
621 return uno::Any(); //behave passive if already disposed or suspended //@todo? or throw an exception??
623 //-- collect current view state
625 //// @todo integrate specialized implementation
630 void SAL_CALL
ChartController::restoreViewData(
631 const uno::Any
& /* Value */ )
633 //restores the view status using the data gotten from a previous call to XController::getViewData()
635 SolarMutexGuard aGuard
;
636 if( impl_isDisposedOrSuspended() )
637 return; //behave passive if already disposed or suspended //@todo? or throw an exception??
639 //// @todo integrate specialized implementation
642 sal_Bool SAL_CALL
ChartController::suspend( sal_Bool bSuspend
)
644 //is called to prepare the controller for closing the view
645 //bSuspend==true: force the controller to suspend his work
646 //bSuspend==false try to reactivate the controller
647 //returns true if request was accepted and of course successfully finished, false otherwise
649 //we may show dialogs here to ask the user for saving changes ... @todo?
651 SolarMutexGuard aGuard
;
652 if( m_aLifeTimeManager
.impl_isDisposed() )
653 return false; //behave passive if already disposed, return false because request was not accepted //@todo? correct
655 if(bool(bSuspend
) == m_bSuspended
)
657 OSL_FAIL( "new suspend mode equals old suspend mode" );
661 //change suspend mode
662 m_bSuspended
= bSuspend
;
666 // css::frame::XController2
668 css::uno::Reference
<css::awt::XWindow
> SAL_CALL
ChartController::getComponentWindow()
670 // it is a special characteristic of ChartController
671 // that it simultaneously provides the XWindow functionality
675 OUString SAL_CALL
ChartController::getViewControllerName() { return {}; }
677 css::uno::Sequence
<css::beans::PropertyValue
> SAL_CALL
ChartController::getCreationArguments()
682 css::uno::Reference
<css::ui::XSidebarProvider
> SAL_CALL
ChartController::getSidebar() { return {}; }
684 void ChartController::impl_createDrawViewController()
686 SolarMutexGuard aGuard
;
687 if(!m_pDrawViewWrapper
)
689 if( m_pDrawModelWrapper
)
691 bool bLokCalcGlobalRTL
= false;
692 if(comphelper::LibreOfficeKit::isActive() && AllSettings::GetLayoutRTL())
694 rtl::Reference
< ChartModel
> xChartModel
= getChartModel();
695 if (xChartModel
.is())
697 uno::Reference
<css::sheet::XSpreadsheetDocument
> xSSDoc(xChartModel
->getParent(), uno::UNO_QUERY
);
699 bLokCalcGlobalRTL
= true;
703 m_pDrawViewWrapper
.reset( new DrawViewWrapper(m_pDrawModelWrapper
->getSdrModel(),GetChartWindow()->GetOutDev()) );
704 m_pDrawViewWrapper
->SetNegativeX(bLokCalcGlobalRTL
);
705 m_pDrawViewWrapper
->attachParentReferenceDevice( getChartModel() );
710 void ChartController::impl_deleteDrawViewController()
712 if( m_pDrawViewWrapper
)
714 SolarMutexGuard aGuard
;
715 if( m_pDrawViewWrapper
->IsTextEdit() )
717 m_pDrawViewWrapper
.reset();
721 // XComponent (base of XController)
723 void SAL_CALL
ChartController::dispose()
727 mpSelectionChangeHandler
->selectionChanged(css::lang::EventObject());
728 mpSelectionChangeHandler
->Disconnect();
732 uno::Reference
<ui::XSidebar
> xSidebar
= getSidebarFromModel(getChartModel());
733 if (sfx2::sidebar::SidebarController
* pSidebar
= dynamic_cast<sfx2::sidebar::SidebarController
*>(xSidebar
.get()))
735 pSidebar
->unregisterSidebarForFrame(this);
741 //This object should release all resources and references in the
742 //easiest possible manner
743 //This object must notify all registered listeners using the method
744 //<member>XEventListener::disposing</member>
747 if( !m_aLifeTimeManager
.dispose() )
750 // OSL_ENSURE( m_bSuspended, "dispose was called but controller is not suspended" );
752 this->stopDoubleClickWaiting();
754 //end range highlighting
757 uno::Reference
< view::XSelectionChangeListener
> xSelectionChangeListener
;
758 rtl::Reference
< ChartModel
> xDataReceiver
= getChartModel();
759 if( xDataReceiver
.is() )
760 xSelectionChangeListener
.set( xDataReceiver
->getRangeHighlighter(), uno::UNO_QUERY
);
761 if( xSelectionChangeListener
.is() )
763 uno::Reference
< frame::XController
> xController( this );
764 lang::EventObject
aEvent( xController
);
765 xSelectionChangeListener
->disposing( aEvent
);
769 //--release all resources and references
771 if( m_xChartView
.is() )
772 m_xChartView
->removeModeChangeListener(this);
774 impl_invalidateAccessible();
775 SolarMutexGuard aSolarGuard
;
776 impl_deleteDrawViewController();
777 m_pDrawModelWrapper
.reset();
779 m_apDropTargetHelper
.reset();
781 //the accessible view is disposed within window destructor of m_pChartWindow
782 if(m_xViewWindow
.is())
783 m_xViewWindow
->dispose(); //ChartWindow is deleted via UNO due to dispose of m_xViewWindow (triggered by Framework (Controller pretends to be XWindow also))
784 m_xChartView
.clear();
787 // remove as listener to layout manager events
788 if( m_xLayoutManagerEventBroadcaster
.is())
790 m_xLayoutManagerEventBroadcaster
->removeLayoutManagerEventListener( this );
791 m_xLayoutManagerEventBroadcaster
.clear();
795 m_xUndoManager
.clear();
797 TheModelRef
aModelRef( m_aModel
, m_aModelMutex
);
802 uno::Reference
< frame::XModel
> xModel( aModelRef
->getModel() );
804 xModel
->disconnectController( uno::Reference
< frame::XController
>( this ));
806 aModelRef
->removeListener( this );
807 #ifdef TEST_ENABLE_MODIFY_LISTENER
810 if( aModelRef
->getModel().is())
811 aModelRef
->getModel()->removeModifyListener( this );
813 catch( const uno::Exception
& )
815 DBG_UNHANDLED_EXCEPTION("chart2");
818 aModelRef
->tryTermination();
821 //// @todo integrate specialized implementation
822 //e.g. release further resources and references
825 m_aDispatchContainer
.DisposeAndClear();
827 catch( const uno::Exception
& )
829 DBG_UNHANDLED_EXCEPTION("chart2");
830 assert(!m_xChartView
.is());
834 void SAL_CALL
ChartController::addEventListener(
835 const uno::Reference
<lang::XEventListener
>& xListener
)
837 if( impl_isDisposedOrSuspended() )//@todo? allow adding of listeners in suspend mode?
838 return; //behave passive if already disposed or suspended
841 std::unique_lock
aGuard2(m_aLifeTimeManager
.m_aAccessMutex
);
842 m_aLifeTimeManager
.m_aEventListeners
.addInterface( aGuard2
, xListener
);
845 void SAL_CALL
ChartController::removeEventListener(
846 const uno::Reference
<lang::XEventListener
>& xListener
)
848 SolarMutexGuard aGuard
;
849 if( m_aLifeTimeManager
.impl_isDisposed(false) )
850 return; //behave passive if already disposed or suspended
853 std::unique_lock
aGuard2(m_aLifeTimeManager
.m_aAccessMutex
);
854 m_aLifeTimeManager
.m_aEventListeners
.removeInterface( aGuard2
, xListener
);
857 // util::XCloseListener
858 void SAL_CALL
ChartController::queryClosing(
859 const lang::EventObject
& rSource
,
860 sal_Bool
/*bGetsOwnership*/ )
862 //do not use the m_aControllerMutex here because this call is not allowed to block
864 TheModelRef
aModelRef( m_aModel
, m_aModelMutex
);
866 if( !aModelRef
.is() )
869 if( uno::Reference
<XInterface
>(static_cast<cppu::OWeakObject
*>(aModelRef
->getModel().get())) != rSource
.Source
)
871 OSL_FAIL( "queryClosing was called on a controller from an unknown source" );
875 //@ todo prepare to closing model -> don't start any further hindering actions
878 void SAL_CALL
ChartController::notifyClosing(
879 const lang::EventObject
& rSource
)
881 //Listener should deregister himself and release all references to the closing object.
883 TheModelRef
aModelRef( m_aModel
, m_aModelMutex
);
884 if( !impl_releaseThisModel( rSource
.Source
) )
887 //--stop listening to the closing model
888 aModelRef
->removeListener( this );
890 // #i79087# If the model using this controller is closed, the frame is
891 // expected to be closed as well
892 Reference
< util::XCloseable
> xFrameCloseable( m_xFrame
, uno::UNO_QUERY
);
893 if( xFrameCloseable
.is())
897 xFrameCloseable
->close( false /* DeliverOwnership */ );
900 catch( const util::CloseVetoException
& )
902 // closing was vetoed
907 bool ChartController::impl_releaseThisModel(
908 const uno::Reference
< uno::XInterface
> & xModel
)
910 bool bReleaseModel
= false;
912 ::osl::Guard
< ::osl::Mutex
> aGuard( m_aModelMutex
);
913 if( m_aModel
.is() && uno::Reference
< uno::XInterface
>(static_cast<cppu::OWeakObject
*>(m_aModel
->getModel().get())) == xModel
)
916 m_xUndoManager
.clear();
917 bReleaseModel
= true;
923 m_aDispatchContainer
.setModel( nullptr );
925 return bReleaseModel
;
928 // util::XEventListener (base of XCloseListener)
929 void SAL_CALL
ChartController::disposing(
930 const lang::EventObject
& rSource
)
932 if( !impl_releaseThisModel( rSource
.Source
))
934 if( rSource
.Source
== m_xLayoutManagerEventBroadcaster
)
935 m_xLayoutManagerEventBroadcaster
.clear();
939 void SAL_CALL
ChartController::layoutEvent(
940 const lang::EventObject
& aSource
,
941 sal_Int16 eLayoutEvent
,
942 const uno::Any
& /* aInfo */ )
944 if( eLayoutEvent
== frame::LayoutManagerEvents::MERGEDMENUBAR
)
946 Reference
< frame::XLayoutManager
> xLM( aSource
.Source
, uno::UNO_QUERY
);
949 xLM
->createElement( u
"private:resource/statusbar/statusbar"_ustr
);
950 xLM
->requestElement( u
"private:resource/statusbar/statusbar"_ustr
);
955 // XDispatchProvider (required interface)
960 bool lcl_isFormatObjectCommand( std::u16string_view aCommand
)
962 return aCommand
== u
"MainTitle"
963 || aCommand
== u
"SubTitle"
964 || aCommand
== u
"XTitle"
965 || aCommand
== u
"YTitle"
966 || aCommand
== u
"ZTitle"
967 || aCommand
== u
"SecondaryXTitle"
968 || aCommand
== u
"SecondaryYTitle"
969 || aCommand
== u
"AllTitles"
970 || aCommand
== u
"DiagramAxisX"
971 || aCommand
== u
"DiagramAxisY"
972 || aCommand
== u
"DiagramAxisZ"
973 || aCommand
== u
"DiagramAxisA"
974 || aCommand
== u
"DiagramAxisB"
975 || aCommand
== u
"DiagramAxisAll"
976 || aCommand
== u
"DiagramGridXMain"
977 || aCommand
== u
"DiagramGridYMain"
978 || aCommand
== u
"DiagramGridZMain"
979 || aCommand
== u
"DiagramGridXHelp"
980 || aCommand
== u
"DiagramGridYHelp"
981 || aCommand
== u
"DiagramGridZHelp"
982 || aCommand
== u
"DiagramGridAll"
984 || aCommand
== u
"DiagramWall"
985 || aCommand
== u
"DiagramFloor"
986 || aCommand
== u
"DiagramArea"
987 || aCommand
== u
"Legend"
989 || aCommand
== u
"FormatWall"
990 || aCommand
== u
"FormatFloor"
991 || aCommand
== u
"FormatChartArea"
992 || aCommand
== u
"FormatLegend"
994 || aCommand
== u
"FormatTitle"
995 || aCommand
== u
"FormatAxis"
996 || aCommand
== u
"FormatDataSeries"
997 || aCommand
== u
"FormatDataPoint"
998 || aCommand
== u
"FormatDataLabels"
999 || aCommand
== u
"FormatDataLabel"
1000 || aCommand
== u
"FormatXErrorBars"
1001 || aCommand
== u
"FormatYErrorBars"
1002 || aCommand
== u
"FormatMeanValue"
1003 || aCommand
== u
"FormatTrendline"
1004 || aCommand
== u
"FormatTrendlineEquation"
1005 || aCommand
== u
"FormatStockLoss"
1006 || aCommand
== u
"FormatStockGain"
1007 || aCommand
== u
"FormatMajorGrid"
1008 || aCommand
== u
"FormatMinorGrid";
1011 } // anonymous namespace
1013 uno::Reference
<frame::XDispatch
> SAL_CALL
1014 ChartController::queryDispatch(
1015 const util::URL
& rURL
,
1016 const OUString
& rTargetFrameName
,
1017 sal_Int32
/* nSearchFlags */)
1019 SolarMutexGuard aGuard
;
1021 if ( !m_aLifeTimeManager
.impl_isDisposed() && getModel().is() )
1023 if( !rTargetFrameName
.isEmpty() && rTargetFrameName
== "_self" )
1024 return m_aDispatchContainer
.getDispatchForURL( rURL
);
1026 return uno::Reference
< frame::XDispatch
> ();
1029 uno::Sequence
<uno::Reference
<frame::XDispatch
> >
1030 ChartController::queryDispatches(
1031 const uno::Sequence
<frame::DispatchDescriptor
>& xDescripts
)
1035 if ( !m_aLifeTimeManager
.impl_isDisposed() )
1037 return m_aDispatchContainer
.getDispatchesForURLs( xDescripts
);
1039 return uno::Sequence
<uno::Reference
<frame::XDispatch
> > ();
1044 void SAL_CALL
ChartController::dispatch(
1045 const util::URL
& rURL
,
1046 const uno::Sequence
< beans::PropertyValue
>& rArgs
)
1048 OUString aCommand
= rURL
.Path
;
1050 if(aCommand
== "LOKSetTextSelection")
1052 if (rArgs
.getLength() == 3)
1054 sal_Int32 nType
= -1;
1055 rArgs
[0].Value
>>= nType
;
1057 rArgs
[1].Value
>>= nX
;
1059 rArgs
[2].Value
>>= nY
;
1060 executeDispatch_LOKSetTextSelection(nType
, nX
, nY
);
1063 else if (aCommand
== "LOKTransform")
1065 if (rArgs
[0].Name
== "Action")
1068 if ((rArgs
[0].Value
>>= sAction
) && sAction
== "PieSegmentDragging")
1070 if (rArgs
[1].Name
== "Offset")
1073 if (rArgs
[1].Value
>>= nOffset
)
1075 this->executeDispatch_LOKPieSegmentDragging(nOffset
);
1082 this->executeDispatch_PositionAndSize(&rArgs
);
1085 else if(aCommand
== "FillColor")
1087 if (rArgs
.getLength() > 0)
1090 if (rArgs
[0].Value
>>= nColor
)
1091 this->executeDispatch_FillColor(nColor
);
1094 else if(aCommand
== "XLineColor")
1096 if (rArgs
.getLength() > 0)
1098 sal_Int32 nColor
= -1;
1099 rArgs
[0].Value
>>= nColor
;
1100 this->executeDispatch_LineColor(nColor
);
1103 else if(aCommand
== "LineWidth")
1105 if (rArgs
.getLength() > 0)
1107 sal_Int32 nWidth
= -1;
1108 rArgs
[0].Value
>>= nWidth
;
1109 this->executeDispatch_LineWidth(nWidth
);
1112 else if(aCommand
.startsWith("FillGradient"))
1114 this->executeDispatch_FillGradient(aCommand
.subView(aCommand
.indexOf('=') + 1));
1116 else if(aCommand
== "Paste")
1117 this->executeDispatch_Paste();
1118 else if(aCommand
== "Copy" )
1119 this->executeDispatch_Copy();
1120 else if(aCommand
== "Cut" )
1121 this->executeDispatch_Cut();
1122 else if(aCommand
== "DataRanges" )
1123 this->executeDispatch_SourceData();
1124 else if(aCommand
== "Update" ) //Update Chart
1126 ChartViewHelper::setViewToDirtyState( getChartModel() );
1127 SolarMutexGuard aGuard
;
1128 auto pChartWindow(GetChartWindow());
1130 pChartWindow
->Invalidate();
1132 else if(aCommand
== "DiagramData" )
1133 this->executeDispatch_EditData();
1135 else if( aCommand
== "InsertTitles"
1136 || aCommand
== "InsertMenuTitles")
1137 this->executeDispatch_InsertTitles();
1138 else if( aCommand
== "InsertMenuLegend" )
1139 this->executeDispatch_OpenLegendDialog();
1140 else if( aCommand
== "InsertLegend" )
1141 this->executeDispatch_InsertLegend();
1142 else if( aCommand
== "DeleteLegend" )
1143 this->executeDispatch_DeleteLegend();
1144 else if( aCommand
== "InsertMenuDataLabels" )
1145 this->executeDispatch_InsertMenu_DataLabels();
1146 else if( aCommand
== "InsertMenuAxes"
1147 || aCommand
== "InsertRemoveAxes" )
1148 this->executeDispatch_InsertAxes();
1149 else if( aCommand
== "InsertMenuGrids" )
1150 this->executeDispatch_InsertGrid();
1151 else if( aCommand
== "InsertMenuTrendlines" )
1152 this->executeDispatch_InsertMenu_Trendlines();
1153 else if( aCommand
== "InsertMenuMeanValues" )
1154 this->executeDispatch_InsertMenu_MeanValues();
1155 else if( aCommand
== "InsertMenuXErrorBars" )
1156 this->executeDispatch_InsertErrorBars(false);
1157 else if( aCommand
== "InsertMenuYErrorBars" )
1158 this->executeDispatch_InsertErrorBars(true);
1159 else if( aCommand
== "InsertMenuDataTable" )
1160 this->executeDispatch_OpenInsertDataTableDialog();
1161 else if( aCommand
== "InsertSymbol" )
1162 this->executeDispatch_InsertSpecialCharacter();
1163 else if( aCommand
== "InsertTrendline" )
1164 this->executeDispatch_InsertTrendline();
1165 else if( aCommand
== "DeleteTrendline" )
1166 this->executeDispatch_DeleteTrendline();
1167 else if( aCommand
== "InsertMeanValue" )
1168 this->executeDispatch_InsertMeanValue();
1169 else if( aCommand
== "DeleteMeanValue" )
1170 this->executeDispatch_DeleteMeanValue();
1171 else if( aCommand
== "InsertXErrorBars" )
1172 this->executeDispatch_InsertErrorBars(false);
1173 else if( aCommand
== "InsertYErrorBars" )
1174 this->executeDispatch_InsertErrorBars(true);
1175 else if( aCommand
== "DeleteXErrorBars" )
1176 this->executeDispatch_DeleteErrorBars(false);
1177 else if( aCommand
== "DeleteYErrorBars" )
1178 this->executeDispatch_DeleteErrorBars(true);
1179 else if( aCommand
== "InsertTrendlineEquation" )
1180 this->executeDispatch_InsertTrendlineEquation();
1181 else if( aCommand
== "DeleteTrendlineEquation" )
1182 this->executeDispatch_DeleteTrendlineEquation();
1183 else if( aCommand
== "InsertTrendlineEquationAndR2" )
1184 this->executeDispatch_InsertTrendlineEquation( true );
1185 else if( aCommand
== "InsertR2Value" )
1186 this->executeDispatch_InsertR2Value();
1187 else if( aCommand
== "DeleteR2Value")
1188 this->executeDispatch_DeleteR2Value();
1189 else if( aCommand
== "InsertDataLabels" )
1190 this->executeDispatch_InsertDataLabels();
1191 else if( aCommand
== "InsertDataLabel" )
1192 this->executeDispatch_InsertDataLabel();
1193 else if( aCommand
== "DeleteDataLabels")
1194 this->executeDispatch_DeleteDataLabels();
1195 else if( aCommand
== "DeleteDataLabel" )
1196 this->executeDispatch_DeleteDataLabel();
1197 else if( aCommand
== "ResetAllDataPoints" )
1198 this->executeDispatch_ResetAllDataPoints();
1199 else if( aCommand
== "ResetDataPoint" )
1200 this->executeDispatch_ResetDataPoint();
1201 else if( aCommand
== "InsertAxis" )
1202 this->executeDispatch_InsertAxis();
1203 else if( aCommand
== "InsertMajorGrid" )
1204 this->executeDispatch_InsertMajorGrid();
1205 else if( aCommand
== "InsertMinorGrid" )
1206 this->executeDispatch_InsertMinorGrid();
1207 else if( aCommand
== "InsertAxisTitle" )
1208 this->executeDispatch_InsertAxisTitle();
1209 else if( aCommand
== "DeleteAxis" )
1210 this->executeDispatch_DeleteAxis();
1211 else if( aCommand
== "DeleteMajorGrid")
1212 this->executeDispatch_DeleteMajorGrid();
1213 else if( aCommand
== "DeleteMinorGrid" )
1214 this->executeDispatch_DeleteMinorGrid();
1215 else if( aCommand
== "InsertDataTable" )
1216 this->executeDispatch_InsertDataTable();
1217 else if( aCommand
== "DeleteDataTable" )
1218 this->executeDispatch_DeleteDataTable();
1220 else if( aCommand
== "FormatSelection" )
1221 this->executeDispatch_ObjectProperties();
1222 else if( aCommand
== "TransformDialog" )
1224 if ( isShapeContext() )
1226 this->impl_ShapeControllerDispatch( rURL
, rArgs
);
1230 this->executeDispatch_PositionAndSize();
1233 else if ( aCommand
== "FontDialog" )
1234 this->impl_ShapeControllerDispatch(rURL
, rArgs
);
1235 else if (lcl_isFormatObjectCommand(aCommand
))
1236 this->executeDispatch_FormatObject(rURL
.Path
);
1238 else if( aCommand
== "DiagramType" )
1239 this->executeDispatch_ChartType();
1240 else if( aCommand
== "View3D" )
1241 this->executeDispatch_View3D();
1242 else if ( aCommand
== "Forward" )
1244 if ( isShapeContext() )
1246 this->impl_ShapeControllerDispatch( rURL
, rArgs
);
1250 this->executeDispatch_MoveSeries( true );
1253 else if ( aCommand
== "Backward" )
1255 if ( isShapeContext() )
1257 this->impl_ShapeControllerDispatch( rURL
, rArgs
);
1261 this->executeDispatch_MoveSeries( false );
1264 else if( aCommand
== "NewArrangement")
1265 this->executeDispatch_NewArrangement();
1266 else if( aCommand
== "ToggleLegend" )
1267 this->executeDispatch_ToggleLegend();
1268 else if( aCommand
== "ToggleGridHorizontal" )
1269 this->executeDispatch_ToggleGridHorizontal();
1270 else if( aCommand
== "ToggleGridVertical" )
1271 this->executeDispatch_ToggleGridVertical();
1272 else if( aCommand
== "ScaleText" )
1273 this->executeDispatch_ScaleText();
1274 else if( aCommand
== "StatusBarVisible" )
1276 // workaround: this should not be necessary.
1277 uno::Reference
< beans::XPropertySet
> xPropSet( m_xFrame
, uno::UNO_QUERY
);
1280 uno::Reference
< css::frame::XLayoutManager
> xLayoutManager
;
1281 xPropSet
->getPropertyValue( u
"LayoutManager"_ustr
) >>= xLayoutManager
;
1282 if ( xLayoutManager
.is() )
1284 bool bIsVisible( xLayoutManager
->isElementVisible( u
"private:resource/statusbar/statusbar"_ustr
));
1287 xLayoutManager
->hideElement( u
"private:resource/statusbar/statusbar"_ustr
);
1288 xLayoutManager
->destroyElement( u
"private:resource/statusbar/statusbar"_ustr
);
1292 xLayoutManager
->createElement( u
"private:resource/statusbar/statusbar"_ustr
);
1293 xLayoutManager
->showElement( u
"private:resource/statusbar/statusbar"_ustr
);
1295 // @todo: update menu state (checkmark next to "Statusbar").
1299 else if( aCommand
== "ChangeTheme" )
1300 comphelper::dispatchCommand(u
".uno:ChangeTheme"_ustr
, getFrame(), rArgs
);
1303 void SAL_CALL
ChartController::addStatusListener(
1304 const uno::Reference
<frame::XStatusListener
>& /* xControl */,
1305 const util::URL
& /* aURL */ )
1310 void SAL_CALL
ChartController::removeStatusListener(
1311 const uno::Reference
<frame::XStatusListener
>& /* xControl */,
1312 const util::URL
& /* aURL */ )
1317 // XContextMenuInterception (optional interface)
1318 void SAL_CALL
ChartController::registerContextMenuInterceptor(
1319 const uno::Reference
< ui::XContextMenuInterceptor
>& /* xInterceptor */)
1324 void SAL_CALL
ChartController::releaseContextMenuInterceptor(
1325 const uno::Reference
< ui::XContextMenuInterceptor
> & /* xInterceptor */)
1330 // ____ XEmbeddedClient ____
1331 // implementation see: ChartController_EditData.cxx
1333 void ChartController::executeDispatch_ChartType()
1335 auto xUndoGuard
= std::make_shared
<UndoLiveUpdateGuard
>(SchResId(STR_ACTION_EDIT_CHARTTYPE
),
1338 SolarMutexGuard aSolarGuard
;
1339 //prepare and open dialog
1340 auto aDlg
= std::make_shared
<ChartTypeDialog
>(GetChartFrame(), getChartModel());
1341 weld::DialogController::runAsync(aDlg
, [this, xUndoGuard
=std::move(xUndoGuard
)](int nResult
) {
1342 if (nResult
== RET_OK
)
1344 impl_adaptDataSeriesAutoResize();
1345 xUndoGuard
->commit();
1350 void ChartController::executeDispatch_SourceData()
1352 //convert properties to ItemSet
1353 rtl::Reference
< ::chart::ChartModel
> xChartDoc
= getChartModel();
1354 OSL_ENSURE( xChartDoc
.is(), "Invalid XChartDocument" );
1355 if( !xChartDoc
.is() )
1358 // If there is a data table we should ask user if we really want to destroy it
1359 // and switch to data ranges.
1360 ChartModel
& rModel
= *xChartDoc
;
1361 if ( rModel
.hasInternalDataProvider() )
1363 // Check if we will able to create data provider later
1364 css::uno::Reference
< css::chart2::XDataProviderAccess
> xCreatorDoc(
1365 rModel
.getParent(), uno::UNO_QUERY
);
1366 if (!xCreatorDoc
.is())
1369 SolarMutexGuard aSolarGuard
;
1371 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(GetChartFrame(),
1372 VclMessageType::Question
, VclButtonsType::YesNo
, SchResId(STR_DLG_REMOVE_DATA_TABLE
)));
1373 // If "No" then just return
1374 if (xQueryBox
->run() == RET_NO
)
1377 // Remove data table
1378 rModel
.removeDataProviders();
1380 // Ask parent document to create new data provider
1382 uno::Reference
< data::XDataProvider
> xDataProvider
= xCreatorDoc
->createDataProvider();
1383 SAL_WARN_IF( !xDataProvider
.is(), "chart2.main", "Data provider was not created" );
1384 if (xDataProvider
.is())
1386 rModel
.attachDataProvider(xDataProvider
);
1389 auto xUndoGuard
= std::make_shared
<UndoLiveUpdateGuard
>(SchResId(STR_ACTION_EDIT_DATA_RANGES
),
1391 SolarMutexGuard aSolarGuard
;
1392 auto aDlg
= std::make_shared
<DataSourceDialog
>(GetChartFrame(), xChartDoc
);
1393 weld::DialogController::runAsync(aDlg
, [this, xUndoGuard
=std::move(xUndoGuard
)](int nResult
) {
1394 if (nResult
== RET_OK
)
1396 impl_adaptDataSeriesAutoResize();
1397 xUndoGuard
->commit();
1402 void ChartController::executeDispatch_MoveSeries( bool bForward
)
1404 ControllerLockGuardUNO
aCLGuard( getChartModel() );
1406 //get selected series
1407 OUString
aObjectCID(m_aSelection
.getSelectedCID());
1408 rtl::Reference
< DataSeries
> xGivenDataSeries
= ObjectIdentifier::getDataSeriesForCID( //yyy todo also legend entries and labels?
1409 aObjectCID
, getChartModel() );
1411 UndoGuardWithSelection
aUndoGuard(
1412 ActionDescriptionProvider::createDescription(
1413 (bForward
? ActionDescriptionProvider::ActionType::MoveToTop
: ActionDescriptionProvider::ActionType::MoveToBottom
),
1414 SchResId(STR_OBJECT_DATASERIES
)),
1417 bool bChanged
= getFirstDiagram()->moveSeries( xGivenDataSeries
, bForward
);
1420 m_aSelection
.setSelection( ObjectIdentifier::getMovedSeriesCID( aObjectCID
, bForward
) );
1421 aUndoGuard
.commit();
1425 // ____ XModifyListener ____
1426 void SAL_CALL
ChartController::modified(
1427 const lang::EventObject
& /* aEvent */ )
1429 // the source can also be a subobject of the ChartModel
1430 // @todo: change the source in ChartModel to always be the model itself ?
1431 //todo? update menu states ?
1434 void ChartController::NotifyUndoActionHdl( std::unique_ptr
<SdrUndoAction
> pUndoAction
)
1436 ENSURE_OR_RETURN_VOID( pUndoAction
, "invalid Undo action" );
1438 OUString aObjectCID
= m_aSelection
.getSelectedCID();
1439 if ( !aObjectCID
.isEmpty() )
1444 rtl::Reference
< ChartModel
> xSuppUndo
= getChartModel();
1445 const Reference
< document::XUndoManager
> xUndoManager( xSuppUndo
->getUndoManager(), uno::UNO_SET_THROW
);
1446 const Reference
< document::XUndoAction
> xAction( new impl::ShapeUndoElement( std::move(pUndoAction
) ) );
1447 xUndoManager
->addUndoAction( xAction
);
1449 catch( const uno::Exception
& )
1451 DBG_UNHANDLED_EXCEPTION("chart2");
1455 DrawModelWrapper
* ChartController::GetDrawModelWrapper()
1457 if( !m_pDrawModelWrapper
)
1460 m_pDrawModelWrapper
= m_xChartView
->getDrawModelWrapper();
1461 if ( m_pDrawModelWrapper
)
1463 m_pDrawModelWrapper
->getSdrModel().SetNotifyUndoActionHdl(
1464 std::bind(&ChartController::NotifyUndoActionHdl
, this, std::placeholders::_1
) );
1467 return m_pDrawModelWrapper
.get();
1470 DrawViewWrapper
* ChartController::GetDrawViewWrapper()
1472 if ( !m_pDrawViewWrapper
)
1474 impl_createDrawViewController();
1476 return m_pDrawViewWrapper
.get();
1480 ChartWindow
* ChartController::GetChartWindow() const
1482 // clients getting the naked VCL Window from UNO should always have the
1483 // solar mutex (and keep it over the lifetime of this ptr), as VCL might
1484 // might deinit otherwise
1485 DBG_TESTSOLARMUTEX();
1486 if(!m_xViewWindow
.is())
1488 return dynamic_cast<ChartWindow
*>(VCLUnoHelper::GetWindow(m_xViewWindow
));
1491 weld::Window
* ChartController::GetChartFrame()
1493 // clients getting the naked VCL Window from UNO should always have the
1494 // solar mutex (and keep it over the lifetime of this ptr), as VCL might
1495 // might deinit otherwise
1496 DBG_TESTSOLARMUTEX();
1497 return Application::GetFrameWeld(m_xViewWindow
);
1500 bool ChartController::isAdditionalShapeSelected() const
1502 return m_aSelection
.isAdditionalShapeSelected();
1505 void ChartController::SetAndApplySelection(const Reference
<drawing::XShape
>& rxShape
)
1509 m_aSelection
.setSelection(rxShape
);
1510 m_aSelection
.applySelection(GetDrawViewWrapper());
1516 uno::Reference
< XAccessible
> ChartController::CreateAccessible()
1518 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1519 rtl::Reference
< AccessibleChartView
> xResult
= new AccessibleChartView( GetDrawViewWrapper() );
1520 impl_initializeAccessible( *xResult
);
1523 return uno::Reference
< XAccessible
>();
1527 void ChartController::impl_invalidateAccessible()
1529 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1530 SolarMutexGuard aGuard
;
1531 auto pChartWindow(GetChartWindow());
1534 Reference
< XInterface
> xInit( pChartWindow
->GetAccessible(false) );
1537 //empty arguments -> invalid accessible
1538 dynamic_cast<AccessibleChartView
&>(*xInit
).initialize();
1543 void ChartController::impl_initializeAccessible()
1545 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1546 SolarMutexGuard aGuard
;
1547 auto pChartWindow(GetChartWindow());
1550 Reference
<XAccessible
> xInit
= pChartWindow
->GetAccessible(false);
1552 impl_initializeAccessible( dynamic_cast<AccessibleChartView
&>(*xInit
) );
1555 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1556 void ChartController::impl_initializeAccessible( AccessibleChartView
& rAccChartView
)
1558 uno::Reference
< XAccessible
> xParent
;
1560 SolarMutexGuard aGuard
;
1561 auto pChartWindow(GetChartWindow());
1564 vcl::Window
* pParentWin( pChartWindow
->GetAccessibleParentWindow());
1566 xParent
.set( pParentWin
->GetAccessible());
1570 rAccChartView
.initialize(*this, getChartModel(), m_xChartView
, xParent
, m_xViewWindow
);
1573 void ChartController::impl_initializeAccessible( AccessibleChartView
& /* rAccChartView */) {}
1576 const o3tl::sorted_vector
< std::u16string_view
>& ChartController::impl_getAvailableCommands()
1578 static const o3tl::sorted_vector
< std::u16string_view
> s_AvailableCommands
{
1579 // commands for container forward
1580 u
"AddDirect", u
"NewDoc", u
"Open",
1581 u
"Save", u
"SaveAs", u
"SendMail",
1582 u
"EditDoc", u
"ExportDirectToPDF", u
"PrintDefault",
1585 u
"Cut", u
"Copy", u
"Paste",
1586 u
"DataRanges", u
"DiagramData",
1588 u
"InsertMenuTitles", u
"InsertTitles",
1589 u
"InsertMenuLegend", u
"InsertLegend", u
"DeleteLegend",
1590 u
"InsertMenuDataLabels",
1591 u
"InsertMenuAxes", u
"InsertRemoveAxes", u
"InsertMenuGrids",
1593 u
"InsertTrendlineEquation", u
"InsertTrendlineEquationAndR2",
1594 u
"InsertR2Value", u
"DeleteR2Value",
1595 u
"InsertMenuTrendlines", u
"InsertTrendline",
1596 u
"InsertMenuMeanValues", u
"InsertMeanValue",
1597 u
"InsertMenuXErrorBars", u
"InsertXErrorBars",
1598 u
"InsertMenuYErrorBars", u
"InsertYErrorBars",
1599 u
"InsertDataLabels", u
"InsertDataLabel",
1600 u
"DeleteTrendline", u
"DeleteMeanValue", u
"DeleteTrendlineEquation",
1601 u
"DeleteXErrorBars", u
"DeleteYErrorBars",
1602 u
"DeleteDataLabels", u
"DeleteDataLabel",
1603 u
"InsertMenuDataTable",
1604 u
"InsertDataTable", u
"DeleteDataTable",
1606 u
"FormatSelection", u
"FontDialog", u
"TransformDialog",
1607 u
"DiagramType", u
"View3D",
1608 u
"Forward", u
"Backward",
1609 u
"MainTitle", u
"SubTitle",
1610 u
"XTitle", u
"YTitle", u
"ZTitle",
1611 u
"SecondaryXTitle", u
"SecondaryYTitle",
1612 u
"AllTitles", u
"Legend",
1613 u
"DiagramAxisX", u
"DiagramAxisY", u
"DiagramAxisZ",
1614 u
"DiagramAxisA", u
"DiagramAxisB", u
"DiagramAxisAll",
1615 u
"DiagramGridXMain", u
"DiagramGridYMain", u
"DiagramGridZMain",
1616 u
"DiagramGridXHelp", u
"DiagramGridYHelp", u
"DiagramGridZHelp",
1618 u
"DiagramWall", u
"DiagramFloor", u
"DiagramArea",
1620 //context menu - format objects entries
1621 u
"FormatWall", u
"FormatFloor", u
"FormatChartArea",
1624 u
"FormatAxis", u
"FormatTitle",
1625 u
"FormatDataSeries", u
"FormatDataPoint",
1626 u
"ResetAllDataPoints", u
"ResetDataPoint",
1627 u
"FormatDataLabels", u
"FormatDataLabel",
1628 u
"FormatMeanValue", u
"FormatTrendline", u
"FormatTrendlineEquation",
1629 u
"FormatXErrorBars", u
"FormatYErrorBars",
1630 u
"FormatStockLoss", u
"FormatStockGain",
1632 u
"FormatMajorGrid", u
"InsertMajorGrid", u
"DeleteMajorGrid",
1633 u
"FormatMinorGrid", u
"InsertMinorGrid", u
"DeleteMinorGrid",
1634 u
"InsertAxis", u
"DeleteAxis", u
"InsertAxisTitle",
1637 u
"ToggleGridHorizontal", u
"ToggleGridVertical", u
"ToggleLegend", u
"ScaleText",
1638 u
"NewArrangement", u
"Update",
1639 u
"DefaultColors", u
"BarWidth", u
"NumberOfLines",
1641 u
"StatusBarVisible",
1642 u
"ChartElementSelector"};
1643 return s_AvailableCommands
;
1646 ViewElementListProvider
ChartController::getViewElementListProvider()
1648 return ViewElementListProvider(m_pDrawModelWrapper
.get());
1653 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */