Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / chart2 / source / controller / main / ChartController.cxx
blob96ec317defa64ac2921e5507eda098f7790c0f61
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <memory>
21 #include <sal/config.h>
23 #include <set>
25 #include <ChartController.hxx>
26 #include <servicenames.hxx>
27 #include <ResId.hxx>
28 #include <dlg_DataSource.hxx>
29 #include <ChartModel.hxx>
30 #include <ChartModelHelper.hxx>
31 #include "ControllerCommandDispatch.hxx"
32 #include <strings.hrc>
33 #include <chartview/ExplicitValueProvider.hxx>
34 #include <ChartViewHelper.hxx>
36 #include <ChartWindow.hxx>
37 #include <chartview/DrawModelWrapper.hxx>
38 #include <DrawViewWrapper.hxx>
39 #include <ObjectIdentifier.hxx>
40 #include <DiagramHelper.hxx>
41 #include <ControllerLockGuard.hxx>
42 #include "UndoGuard.hxx"
43 #include "ChartDropTargetHelper.hxx"
45 #include <dlg_ChartType.hxx>
46 #include <AccessibleChartView.hxx>
47 #include "DrawCommandDispatch.hxx"
48 #include "ShapeController.hxx"
49 #include "UndoActions.hxx"
50 #include <ViewElementListProvider.hxx>
52 #include <cppuhelper/supportsservice.hxx>
54 #include <com/sun/star/chart2/XChartDocument.hpp>
55 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
56 #include <com/sun/star/frame/XController2.hpp>
57 #include <com/sun/star/util/CloseVetoException.hpp>
58 #include <com/sun/star/util/XModeChangeBroadcaster.hpp>
59 #include <com/sun/star/util/XModifyBroadcaster.hpp>
60 #include <com/sun/star/frame/LayoutManagerEvents.hpp>
61 #include <com/sun/star/frame/XLayoutManagerEventBroadcaster.hpp>
62 #include <com/sun/star/document/XUndoManagerSupplier.hpp>
63 #include <com/sun/star/ui/XSidebar.hpp>
64 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
65 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
66 #include <com/sun/star/chart2/XDataProviderAccess.hpp>
68 #include <sal/log.hxx>
69 #include <tools/debug.hxx>
70 #include <svx/sidebar/SelectionChangeHandler.hxx>
71 #include <toolkit/awt/vclxwindow.hxx>
72 #include <toolkit/helper/vclunohelper.hxx>
73 #include <vcl/svapp.hxx>
74 #include <vcl/weld.hxx>
75 #include <osl/mutex.hxx>
77 #include <sfx2/sidebar/SidebarController.hxx>
79 #include <com/sun/star/frame/XLayoutManager.hpp>
81 // this is needed to properly destroy the unique_ptr to the AcceleratorExecute
82 // object in the DTOR
83 #include <svtools/acceleratorexecute.hxx>
84 #include <svx/ActionDescriptionProvider.hxx>
85 #include <tools/diagnose_ex.h>
87 // enable the following define to let the controller listen to model changes and
88 // react on this by rebuilding the view
89 #define TEST_ENABLE_MODIFY_LISTENER
91 namespace chart
94 using namespace ::com::sun::star;
95 using namespace ::com::sun::star::accessibility;
96 using namespace ::com::sun::star::chart2;
97 using ::com::sun::star::uno::Reference;
98 using ::com::sun::star::uno::Sequence;
100 ChartController::ChartController(uno::Reference<uno::XComponentContext> const & xContext) :
101 m_aLifeTimeManager( nullptr ),
102 m_bSuspended( false ),
103 m_xCC(xContext), //@todo is it allowed to hold this context??
104 m_aModelMutex(),
105 m_aModel( nullptr, m_aModelMutex ),
106 m_xViewWindow(),
107 m_xChartView(),
108 m_pDrawModelWrapper(),
109 m_eDragMode(SdrDragMode::Move),
110 m_bWaitingForDoubleClick(false),
111 m_bWaitingForMouseUp(false),
112 m_bFieldButtonDown(false),
113 m_bConnectingToView(false),
114 m_bDisposed(false),
115 m_aDispatchContainer( m_xCC ),
116 m_eDrawMode( CHARTDRAW_SELECT ),
117 mpSelectionChangeHandler(new svx::sidebar::SelectionChangeHandler(
118 [this]() { return this->GetContextName(); },
119 this, vcl::EnumContext::Context::Cell))
121 m_aDoubleClickTimer.SetInvokeHandler( LINK( this, ChartController, DoubleClickWaitingHdl ) );
124 ChartController::~ChartController()
126 stopDoubleClickWaiting();
129 ChartController::TheModel::TheModel( const uno::Reference< frame::XModel > & xModel ) :
130 m_xModel( xModel ),
131 m_bOwnership( true )
133 m_xCloseable =
134 uno::Reference< util::XCloseable >( xModel, uno::UNO_QUERY );
137 ChartController::TheModel::~TheModel()
141 void ChartController::TheModel::addListener( ChartController* pController )
143 if(m_xCloseable.is())
145 //if you need to be able to veto against the destruction of the model
146 // you must add as a close listener
148 //otherwise you 'can' add as closelistener or 'must' add as dispose event listener
150 m_xCloseable->addCloseListener(
151 static_cast<util::XCloseListener*>(pController) );
153 else if( m_xModel.is() )
155 //we need to add as dispose event listener
156 m_xModel->addEventListener(
157 static_cast<util::XCloseListener*>(pController) );
162 void ChartController::TheModel::removeListener( ChartController* pController )
164 if(m_xCloseable.is())
165 m_xCloseable->removeCloseListener(
166 static_cast<util::XCloseListener*>(pController) );
168 else if( m_xModel.is() )
169 m_xModel->removeEventListener(
170 static_cast<util::XCloseListener*>(pController) );
173 void ChartController::TheModel::tryTermination()
175 if(!m_bOwnership)
176 return;
180 if(m_xCloseable.is())
184 //@todo ? are we allowed to use sal_True here if we have the explicit ownership?
185 //I think yes, because there might be other CloseListeners later in the list which might be interested still
186 //but make sure that we do not throw the CloseVetoException here ourselves
187 //so stop listening before trying to terminate or check the source of queryclosing event
188 m_xCloseable->close(true);
190 m_bOwnership = false;
192 catch( const util::CloseVetoException& )
194 //since we have indicated to give up the ownership with parameter true in close call
195 //the one who has thrown the CloseVetoException is the new owner
197 SAL_WARN_IF( m_bOwnership, "chart2.main", "a well known owner has caught a CloseVetoException after calling close(true)");
198 m_bOwnership = false;
199 return;
203 else if( m_xModel.is() )
205 //@todo correct??
206 m_xModel->dispose();
207 return;
210 catch(const uno::Exception&)
212 DBG_UNHANDLED_EXCEPTION( "chart2", "Termination of model failed" );
216 ChartController::TheModelRef::TheModelRef( TheModel* pTheModel, osl::Mutex& rMutex ) :
217 m_rModelMutex(rMutex)
219 osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
220 m_xTheModel = pTheModel;
222 ChartController::TheModelRef::TheModelRef( const TheModelRef& rTheModel, ::osl::Mutex& rMutex ) :
223 m_rModelMutex(rMutex)
225 osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
226 m_xTheModel = rTheModel.m_xTheModel;
228 ChartController::TheModelRef& ChartController::TheModelRef::operator=(TheModel* pTheModel)
230 osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
231 m_xTheModel = pTheModel;
232 return *this;
234 ChartController::TheModelRef& ChartController::TheModelRef::operator=(const TheModelRef& rTheModel)
236 osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
237 m_xTheModel = rTheModel.operator->();
238 return *this;
240 ChartController::TheModelRef::~TheModelRef()
242 osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
243 m_xTheModel.clear();
245 bool ChartController::TheModelRef::is() const
247 return m_xTheModel.is();
250 namespace {
252 css::uno::Reference<css::chart2::XChartType> getChartType(
253 const css::uno::Reference<css::chart2::XChartDocument>& xChartDoc)
255 Reference <chart2::XDiagram > xDiagram = xChartDoc->getFirstDiagram();
256 if (!xDiagram.is()) {
257 return css::uno::Reference<css::chart2::XChartType>();
260 Reference< chart2::XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY_THROW );
262 Sequence< Reference< chart2::XCoordinateSystem > > xCooSysSequence( xCooSysContainer->getCoordinateSystems());
263 if (!xCooSysSequence.hasElements()) {
264 return css::uno::Reference<css::chart2::XChartType>();
267 Reference< chart2::XChartTypeContainer > xChartTypeContainer( xCooSysSequence[0], uno::UNO_QUERY_THROW );
269 Sequence< Reference< chart2::XChartType > > xChartTypeSequence( xChartTypeContainer->getChartTypes() );
271 return xChartTypeSequence[0];
276 OUString ChartController::GetContextName()
278 if (m_bDisposed)
279 return OUString();
281 uno::Any aAny = getSelection();
282 if (!aAny.hasValue())
283 return "Chart";
285 OUString aCID;
286 aAny >>= aCID;
288 if (aCID.isEmpty())
289 return "Chart";
291 ObjectType eObjectID = ObjectIdentifier::getObjectType(aCID);
292 switch (eObjectID)
294 case OBJECTTYPE_DATA_SERIES:
295 return "Series";
296 break;
297 case OBJECTTYPE_DATA_ERRORS_X:
298 case OBJECTTYPE_DATA_ERRORS_Y:
299 case OBJECTTYPE_DATA_ERRORS_Z:
300 return "ErrorBar";
301 case OBJECTTYPE_AXIS:
302 return "Axis";
303 case OBJECTTYPE_GRID:
304 return "Grid";
305 case OBJECTTYPE_DIAGRAM:
307 css::uno::Reference<css::chart2::XChartType> xChartType = getChartType(css::uno::Reference<css::chart2::XChartDocument>(getModel(), uno::UNO_QUERY));
308 if (xChartType.is() && xChartType->getChartType() == "com.sun.star.chart2.PieChartType")
309 return "ChartElements";
310 break;
312 case OBJECTTYPE_DATA_CURVE:
313 case OBJECTTYPE_DATA_AVERAGE_LINE:
314 return "Trendline";
315 default:
316 break;
319 return "Chart";
322 // private methods
324 bool ChartController::impl_isDisposedOrSuspended() const
326 if( m_aLifeTimeManager.impl_isDisposed() )
327 return true;
329 if( m_bSuspended )
331 OSL_FAIL( "This Controller is suspended" );
332 return true;
334 return false;
337 // lang::XServiceInfo
339 OUString SAL_CALL ChartController::getImplementationName()
341 return CHART_CONTROLLER_SERVICE_IMPLEMENTATION_NAME;
344 sal_Bool SAL_CALL ChartController::supportsService( const OUString& rServiceName )
346 return cppu::supportsService(this, rServiceName);
349 css::uno::Sequence< OUString > SAL_CALL ChartController::getSupportedServiceNames()
351 return {
352 CHART_CONTROLLER_SERVICE_NAME,
353 "com.sun.star.frame.Controller"
354 //// @todo : add additional services if you support any further
358 namespace {
360 uno::Reference<ui::XSidebar> getSidebarFromModel(const uno::Reference<frame::XModel>& xModel)
362 uno::Reference<container::XChild> xChild(xModel, uno::UNO_QUERY);
363 if (!xChild.is())
364 return nullptr;
366 uno::Reference<frame::XModel> xParent (xChild->getParent(), uno::UNO_QUERY);
367 if (!xParent.is())
368 return nullptr;
370 uno::Reference<frame::XController2> xController(xParent->getCurrentController(), uno::UNO_QUERY);
371 if (!xController.is())
372 return nullptr;
374 uno::Reference<ui::XSidebarProvider> xSidebarProvider = xController->getSidebar();
375 if (!xSidebarProvider.is())
376 return nullptr;
378 return xSidebarProvider->getSidebar();
383 // XController
385 void SAL_CALL ChartController::attachFrame(
386 const uno::Reference<frame::XFrame>& xFrame )
388 SolarMutexGuard aGuard;
390 if( impl_isDisposedOrSuspended() ) //@todo? allow attaching the frame while suspended?
391 return; //behave passive if already disposed or suspended
393 mpSelectionChangeHandler->Connect();
395 uno::Reference<ui::XSidebar> xSidebar = getSidebarFromModel(getModel());
396 if (xSidebar.is())
398 auto pSidebar = dynamic_cast<sfx2::sidebar::SidebarController*>(xSidebar.get());
399 assert(pSidebar);
400 sfx2::sidebar::SidebarController::registerSidebarForFrame(pSidebar, this);
401 pSidebar->updateModel(getModel());
402 css::lang::EventObject aEvent;
403 mpSelectionChangeHandler->selectionChanged(aEvent);
406 if(m_xFrame.is()) //what happens, if we do have a Frame already??
408 //@todo? throw exception?
409 OSL_FAIL( "there is already a frame attached to the controller" );
410 return;
413 //--attach frame
414 m_xFrame = xFrame; //the frameloader is responsible to call xFrame->setComponent
416 //add as disposelistener to the frame (due to persistent reference) ??...:
418 //the frame is considered to be owner of this controller and will live longer than we do
419 //the frame or the disposer of the frame has the duty to call suspend and dispose on this object
420 //so we do not need to add as lang::XEventListener for DisposingEvents right?
422 //@todo nothing right???
424 //create view @todo is this the correct place here??
426 vcl::Window* pParent = nullptr;
427 //get the window parent from the frame to use as parent for our new window
428 if(xFrame.is())
430 uno::Reference< awt::XWindow > xContainerWindow = xFrame->getContainerWindow();
431 VCLXWindow* pParentComponent = comphelper::getUnoTunnelImplementation<VCLXWindow>(xContainerWindow);
432 assert(pParentComponent);
433 if (pParentComponent)
434 pParentComponent->setVisible(true);
436 pParent = VCLUnoHelper::GetWindow( xContainerWindow ).get();
440 // calls to VCL
441 SolarMutexGuard aSolarGuard;
442 auto pChartWindow = VclPtr<ChartWindow>::Create(this,pParent,pParent?pParent->GetStyle():0);
443 pChartWindow->SetBackground();//no Background
444 m_xViewWindow.set( pChartWindow->GetComponentInterface(), uno::UNO_QUERY );
445 pChartWindow->Show();
446 m_apDropTargetHelper.reset(
447 new ChartDropTargetHelper( pChartWindow->GetDropTarget(),
448 uno::Reference< chart2::XChartDocument >( getModel(), uno::UNO_QUERY )));
450 impl_createDrawViewController();
453 //create the menu
455 uno::Reference< beans::XPropertySet > xPropSet( xFrame, uno::UNO_QUERY );
456 if( xPropSet.is() )
460 uno::Reference< css::frame::XLayoutManager > xLayoutManager;
461 xPropSet->getPropertyValue( "LayoutManager" ) >>= xLayoutManager;
462 if ( xLayoutManager.is() )
464 xLayoutManager->lock();
465 xLayoutManager->requestElement( "private:resource/menubar/menubar" );
466 //@todo: createElement should become unnecessary, remove when #i79198# is fixed
467 xLayoutManager->createElement( "private:resource/toolbar/standardbar" );
468 xLayoutManager->requestElement( "private:resource/toolbar/standardbar" );
469 //@todo: createElement should become unnecessary, remove when #i79198# is fixed
470 xLayoutManager->createElement( "private:resource/toolbar/toolbar" );
471 xLayoutManager->requestElement( "private:resource/toolbar/toolbar" );
473 // #i12587# support for shapes in chart
474 xLayoutManager->createElement( "private:resource/toolbar/drawbar" );
475 xLayoutManager->requestElement( "private:resource/toolbar/drawbar" );
477 xLayoutManager->requestElement( "private:resource/statusbar/statusbar" );
478 xLayoutManager->unlock();
480 // add as listener to get notified when
481 m_xLayoutManagerEventBroadcaster.set( xLayoutManager, uno::UNO_QUERY );
482 if( m_xLayoutManagerEventBroadcaster.is())
483 m_xLayoutManagerEventBroadcaster->addLayoutManagerEventListener( this );
486 catch( const uno::Exception & )
488 DBG_UNHANDLED_EXCEPTION("chart2");
494 //XModeChangeListener
495 void SAL_CALL ChartController::modeChanged( const util::ModeChangeEvent& rEvent )
497 SolarMutexGuard aGuard;
498 auto pChartWindow(GetChartWindow());
499 //adjust controller to view status changes
501 if( rEvent.NewMode == "dirty" )
503 //the view has become dirty, we should repaint it if we have a window
504 if( pChartWindow )
505 pChartWindow->ForceInvalidate();
507 else if( rEvent.NewMode == "invalid" )
509 //the view is about to become invalid so end all actions on it
510 impl_invalidateAccessible();
511 if( m_pDrawViewWrapper && m_pDrawViewWrapper->IsTextEdit() )
512 this->EndTextEdit();
513 if( m_pDrawViewWrapper )
515 m_pDrawViewWrapper->UnmarkAll();
516 m_pDrawViewWrapper->HideSdrPage();
519 else
521 //the view was rebuild so we can start some actions on it again
522 if( !m_bConnectingToView )
524 if(pChartWindow && m_aModel.is() )
526 m_bConnectingToView = true;
528 GetDrawModelWrapper();
529 if(m_pDrawModelWrapper)
532 if( m_pDrawViewWrapper )
533 m_pDrawViewWrapper->ReInit();
536 //reselect object
537 if( m_aSelection.hasSelection() )
538 this->impl_selectObjectAndNotiy();
539 else
540 ChartModelHelper::triggerRangeHighlighting( getModel() );
542 impl_initializeAccessible();
545 if( pChartWindow )
546 pChartWindow->Invalidate();
550 m_bConnectingToView = false;
556 sal_Bool SAL_CALL ChartController::attachModel( const uno::Reference< frame::XModel > & xModel )
558 impl_invalidateAccessible();
560 //is called to attach the controller to a new model.
561 //return true if attach was successfully, false otherwise (e.g. if you do not work with a model)
563 SolarMutexResettableGuard aGuard;
564 if( impl_isDisposedOrSuspended() ) //@todo? allow attaching a new model while suspended?
565 return false; //behave passive if already disposed or suspended
566 aGuard.clear();
568 TheModelRef aNewModelRef( new TheModel( xModel), m_aModelMutex);
569 TheModelRef aOldModelRef(m_aModel,m_aModelMutex);
570 m_aModel = aNewModelRef;
572 //--handle relations to the old model if any
573 if( aOldModelRef.is() )
575 uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY );
576 if( xViewBroadcaster.is() )
577 xViewBroadcaster->removeModeChangeListener(this);
578 m_pDrawModelWrapper.reset();
580 aOldModelRef->removeListener( this );
581 #ifdef TEST_ENABLE_MODIFY_LISTENER
582 uno::Reference< util::XModifyBroadcaster > xMBroadcaster( aOldModelRef->getModel(),uno::UNO_QUERY );
583 if( xMBroadcaster.is())
584 xMBroadcaster->removeModifyListener( this );
585 #endif
588 //--handle relations to the new model
589 aNewModelRef->addListener( this );
591 aGuard.reset(); // lock for m_aDispatchContainer access
592 // set new model at dispatchers
593 m_aDispatchContainer.setModel( aNewModelRef->getModel());
594 ControllerCommandDispatch * pDispatch = new ControllerCommandDispatch( m_xCC, this, &m_aDispatchContainer );
595 pDispatch->initialize();
597 // the dispatch container will return "this" for all commands returned by
598 // impl_getAvailableCommands(). That means, for those commands dispatch()
599 // is called here at the ChartController.
600 m_aDispatchContainer.setChartDispatch( pDispatch, impl_getAvailableCommands() );
602 DrawCommandDispatch* pDrawDispatch = new DrawCommandDispatch( m_xCC, this );
603 pDrawDispatch->initialize();
604 m_aDispatchContainer.setDrawCommandDispatch( pDrawDispatch );
606 ShapeController* pShapeController = new ShapeController( m_xCC, this );
607 pShapeController->initialize();
608 m_aDispatchContainer.setShapeController( pShapeController );
609 aGuard.clear();
611 #ifdef TEST_ENABLE_MODIFY_LISTENER
612 uno::Reference< util::XModifyBroadcaster > xMBroadcaster( aNewModelRef->getModel(),uno::UNO_QUERY );
613 if( xMBroadcaster.is())
614 xMBroadcaster->addModifyListener( this );
615 #endif
617 // #i119999# Do not do this per default to allow the user to deselect the chart OLE with a single press to ESC
618 // select chart area per default:
619 // select( uno::Any( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) ) );
621 uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
622 if( xFact.is())
624 m_xChartView = xFact->createInstance( CHART_VIEW_SERVICE_NAME );
625 GetDrawModelWrapper();
626 uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY );
627 if( xViewBroadcaster.is() )
628 xViewBroadcaster->addModeChangeListener(this);
631 //the frameloader is responsible to call xModel->connectController
633 SolarMutexGuard aGuard2;
634 auto pChartWindow(GetChartWindow());
635 if( pChartWindow )
636 pChartWindow->Invalidate();
639 uno::Reference< document::XUndoManagerSupplier > xSuppUndo( getModel(), uno::UNO_QUERY_THROW );
640 m_xUndoManager.set( xSuppUndo->getUndoManager(), uno::UNO_SET_THROW );
642 return true;
645 uno::Reference< frame::XFrame > SAL_CALL ChartController::getFrame()
647 //provides access to owner frame of this controller
648 //return the frame containing this controller
650 return m_xFrame;
653 uno::Reference< frame::XModel > SAL_CALL ChartController::getModel()
655 //provides access to currently attached model
656 //returns the currently attached model
658 //return nothing, if you do not have a model
659 TheModelRef aModelRef( m_aModel, m_aModelMutex);
660 if(aModelRef.is())
661 return aModelRef->getModel();
663 return uno::Reference< frame::XModel > ();
666 uno::Any SAL_CALL ChartController::getViewData()
668 //provides access to current view status
669 //set of data that can be used to restore the current view status at later time
670 // by using XController::restoreViewData()
672 SolarMutexGuard aGuard;
673 if( impl_isDisposedOrSuspended() )
674 return uno::Any(); //behave passive if already disposed or suspended //@todo? or throw an exception??
676 //-- collect current view state
677 uno::Any aRet;
678 //// @todo integrate specialized implementation
680 return aRet;
683 void SAL_CALL ChartController::restoreViewData(
684 const uno::Any& /* Value */ )
686 //restores the view status using the data gotten from a previous call to XController::getViewData()
688 SolarMutexGuard aGuard;
689 if( impl_isDisposedOrSuspended() )
690 return; //behave passive if already disposed or suspended //@todo? or throw an exception??
692 //// @todo integrate specialized implementation
695 sal_Bool SAL_CALL ChartController::suspend( sal_Bool bSuspend )
697 //is called to prepare the controller for closing the view
698 //bSuspend==true: force the controller to suspend his work
699 //bSuspend==false try to reactivate the controller
700 //returns true if request was accepted and of course successfully finished, false otherwise
702 //we may show dialogs here to ask the user for saving changes ... @todo?
704 SolarMutexGuard aGuard;
705 if( m_aLifeTimeManager.impl_isDisposed() )
706 return false; //behave passive if already disposed, return false because request was not accepted //@todo? correct
708 if(bool(bSuspend) == m_bSuspended)
710 OSL_FAIL( "new suspend mode equals old suspend mode" );
711 return true;
714 //change suspend mode
715 m_bSuspended = bSuspend;
716 return true;
719 void ChartController::impl_createDrawViewController()
721 SolarMutexGuard aGuard;
722 if(!m_pDrawViewWrapper)
724 if( m_pDrawModelWrapper )
726 m_pDrawViewWrapper.reset( new DrawViewWrapper(m_pDrawModelWrapper->getSdrModel(),GetChartWindow()) );
727 m_pDrawViewWrapper->attachParentReferenceDevice( getModel() );
732 void ChartController::impl_deleteDrawViewController()
734 if( m_pDrawViewWrapper )
736 SolarMutexGuard aGuard;
737 if( m_pDrawViewWrapper->IsTextEdit() )
738 this->EndTextEdit();
739 m_pDrawViewWrapper.reset();
743 // XComponent (base of XController)
745 void SAL_CALL ChartController::dispose()
747 m_bDisposed = true;
749 if (getModel().is())
751 uno::Reference<ui::XSidebar> xSidebar = getSidebarFromModel(getModel());
752 if (sfx2::sidebar::SidebarController* pSidebar = dynamic_cast<sfx2::sidebar::SidebarController*>(xSidebar.get()))
754 sfx2::sidebar::SidebarController::unregisterSidebarForFrame(pSidebar, this);
757 mpSelectionChangeHandler->selectionChanged(css::lang::EventObject());
758 mpSelectionChangeHandler->Disconnect();
762 //This object should release all resources and references in the
763 //easiest possible manner
764 //This object must notify all registered listeners using the method
765 //<member>XEventListener::disposing</member>
767 //hold no mutex
768 if( !m_aLifeTimeManager.dispose() )
769 return;
771 // OSL_ENSURE( m_bSuspended, "dispose was called but controller is not suspended" );
773 this->stopDoubleClickWaiting();
775 //end range highlighting
776 if( m_aModel.is())
778 uno::Reference< view::XSelectionChangeListener > xSelectionChangeListener;
779 uno::Reference< chart2::data::XDataReceiver > xDataReceiver( getModel(), uno::UNO_QUERY );
780 if( xDataReceiver.is() )
781 xSelectionChangeListener.set( xDataReceiver->getRangeHighlighter(), uno::UNO_QUERY );
782 if( xSelectionChangeListener.is() )
784 uno::Reference< frame::XController > xController( this );
785 lang::EventObject aEvent( xController );
786 xSelectionChangeListener->disposing( aEvent );
790 //--release all resources and references
792 uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY );
793 if( xViewBroadcaster.is() )
794 xViewBroadcaster->removeModeChangeListener(this);
796 impl_invalidateAccessible();
797 SolarMutexGuard aSolarGuard;
798 impl_deleteDrawViewController();
799 m_pDrawModelWrapper.reset();
801 m_apDropTargetHelper.reset();
803 //the accessible view is disposed within window destructor of m_pChartWindow
804 if(m_xViewWindow.is())
805 m_xViewWindow->dispose(); //ChartWindow is deleted via UNO due to dispose of m_xViewWindow (triggered by Framework (Controller pretends to be XWindow also))
806 m_xChartView.clear();
809 // remove as listener to layout manager events
810 if( m_xLayoutManagerEventBroadcaster.is())
812 m_xLayoutManagerEventBroadcaster->removeLayoutManagerEventListener( this );
813 m_xLayoutManagerEventBroadcaster.set( nullptr );
816 m_xFrame.clear();
817 m_xUndoManager.clear();
819 TheModelRef aModelRef( m_aModel, m_aModelMutex);
820 m_aModel = nullptr;
822 if( aModelRef.is())
824 uno::Reference< frame::XModel > xModel( aModelRef->getModel() );
825 if(xModel.is())
826 xModel->disconnectController( uno::Reference< frame::XController >( this ));
828 aModelRef->removeListener( this );
829 #ifdef TEST_ENABLE_MODIFY_LISTENER
832 uno::Reference< util::XModifyBroadcaster > xMBroadcaster( aModelRef->getModel(),uno::UNO_QUERY );
833 if( xMBroadcaster.is())
834 xMBroadcaster->removeModifyListener( this );
836 catch( const uno::Exception & )
838 DBG_UNHANDLED_EXCEPTION("chart2");
840 #endif
841 aModelRef->tryTermination();
844 //// @todo integrate specialized implementation
845 //e.g. release further resources and references
847 SolarMutexGuard g;
848 m_aDispatchContainer.DisposeAndClear();
850 catch( const uno::Exception & )
852 DBG_UNHANDLED_EXCEPTION("chart2");
853 assert(!m_xChartView.is());
857 void SAL_CALL ChartController::addEventListener(
858 const uno::Reference<lang::XEventListener>& xListener )
860 SolarMutexGuard aGuard;
861 if( impl_isDisposedOrSuspended() )//@todo? allow adding of listeners in suspend mode?
862 return; //behave passive if already disposed or suspended
864 //--add listener
865 m_aLifeTimeManager.m_aListenerContainer.addInterface( cppu::UnoType<lang::XEventListener>::get(), xListener );
868 void SAL_CALL ChartController::removeEventListener(
869 const uno::Reference<lang::XEventListener>& xListener )
871 SolarMutexGuard aGuard;
872 if( m_aLifeTimeManager.impl_isDisposed(false) )
873 return; //behave passive if already disposed or suspended
875 //--remove listener
876 m_aLifeTimeManager.m_aListenerContainer.removeInterface( cppu::UnoType<lang::XEventListener>::get(), xListener );
879 // util::XCloseListener
880 void SAL_CALL ChartController::queryClosing(
881 const lang::EventObject& rSource,
882 sal_Bool /*bGetsOwnership*/ )
884 //do not use the m_aControllerMutex here because this call is not allowed to block
886 TheModelRef aModelRef( m_aModel, m_aModelMutex);
888 if( !aModelRef.is() )
889 return;
891 if( aModelRef->getModel() != rSource.Source )
893 OSL_FAIL( "queryClosing was called on a controller from an unknown source" );
894 return;
897 //@ todo prepare to closing model -> don't start any further hindering actions
900 void SAL_CALL ChartController::notifyClosing(
901 const lang::EventObject& rSource )
903 //Listener should deregister himself and release all references to the closing object.
905 TheModelRef aModelRef( m_aModel, m_aModelMutex);
906 if( impl_releaseThisModel( rSource.Source ) )
908 //--stop listening to the closing model
909 aModelRef->removeListener( this );
911 // #i79087# If the model using this controller is closed, the frame is
912 // expected to be closed as well
913 Reference< util::XCloseable > xFrameCloseable( m_xFrame, uno::UNO_QUERY );
914 if( xFrameCloseable.is())
918 xFrameCloseable->close( false /* DeliverOwnership */ );
919 m_xFrame.clear();
921 catch( const util::CloseVetoException & )
923 // closing was vetoed
929 bool ChartController::impl_releaseThisModel(
930 const uno::Reference< uno::XInterface > & xModel )
932 bool bReleaseModel = false;
934 ::osl::Guard< ::osl::Mutex > aGuard( m_aModelMutex );
935 if( m_aModel.is() && m_aModel->getModel() == xModel )
937 m_aModel = nullptr;
938 m_xUndoManager.clear();
939 bReleaseModel = true;
942 if( bReleaseModel )
944 SolarMutexGuard g;
945 m_aDispatchContainer.setModel( nullptr );
947 return bReleaseModel;
950 // util::XEventListener (base of XCloseListener)
951 void SAL_CALL ChartController::disposing(
952 const lang::EventObject& rSource )
954 if( !impl_releaseThisModel( rSource.Source ))
956 if( rSource.Source == m_xLayoutManagerEventBroadcaster )
957 m_xLayoutManagerEventBroadcaster.set( nullptr );
961 void SAL_CALL ChartController::layoutEvent(
962 const lang::EventObject& aSource,
963 sal_Int16 eLayoutEvent,
964 const uno::Any& /* aInfo */ )
966 if( eLayoutEvent == frame::LayoutManagerEvents::MERGEDMENUBAR )
968 Reference< frame::XLayoutManager > xLM( aSource.Source, uno::UNO_QUERY );
969 if( xLM.is())
971 xLM->createElement( "private:resource/statusbar/statusbar" );
972 xLM->requestElement( "private:resource/statusbar/statusbar" );
977 // XDispatchProvider (required interface)
979 namespace
982 bool lcl_isFormatObjectCommand( const OUString& aCommand )
984 return aCommand == "MainTitle"
985 || aCommand == "SubTitle"
986 || aCommand == "XTitle"
987 || aCommand == "YTitle"
988 || aCommand == "ZTitle"
989 || aCommand == "SecondaryXTitle"
990 || aCommand == "SecondaryYTitle"
991 || aCommand == "AllTitles"
992 || aCommand == "DiagramAxisX"
993 || aCommand == "DiagramAxisY"
994 || aCommand == "DiagramAxisZ"
995 || aCommand == "DiagramAxisA"
996 || aCommand == "DiagramAxisB"
997 || aCommand == "DiagramAxisAll"
998 || aCommand == "DiagramGridXMain"
999 || aCommand == "DiagramGridYMain"
1000 || aCommand == "DiagramGridZMain"
1001 || aCommand == "DiagramGridXHelp"
1002 || aCommand == "DiagramGridYHelp"
1003 || aCommand == "DiagramGridZHelp"
1004 || aCommand == "DiagramGridAll"
1006 || aCommand == "DiagramWall"
1007 || aCommand == "DiagramFloor"
1008 || aCommand == "DiagramArea"
1009 || aCommand == "Legend"
1011 || aCommand == "FormatWall"
1012 || aCommand == "FormatFloor"
1013 || aCommand == "FormatChartArea"
1014 || aCommand == "FormatLegend"
1016 || aCommand == "FormatTitle"
1017 || aCommand == "FormatAxis"
1018 || aCommand == "FormatDataSeries"
1019 || aCommand == "FormatDataPoint"
1020 || aCommand == "FormatDataLabels"
1021 || aCommand == "FormatDataLabel"
1022 || aCommand == "FormatXErrorBars"
1023 || aCommand == "FormatYErrorBars"
1024 || aCommand == "FormatMeanValue"
1025 || aCommand == "FormatTrendline"
1026 || aCommand == "FormatTrendlineEquation"
1027 || aCommand == "FormatStockLoss"
1028 || aCommand == "FormatStockGain"
1029 || aCommand == "FormatMajorGrid"
1030 || aCommand == "FormatMinorGrid";
1033 } // anonymous namespace
1035 uno::Reference<frame::XDispatch> SAL_CALL
1036 ChartController::queryDispatch(
1037 const util::URL& rURL,
1038 const OUString& rTargetFrameName,
1039 sal_Int32 /* nSearchFlags */)
1041 SolarMutexGuard aGuard;
1043 if ( !m_aLifeTimeManager.impl_isDisposed() && getModel().is() )
1045 if( !rTargetFrameName.isEmpty() && rTargetFrameName == "_self" )
1046 return m_aDispatchContainer.getDispatchForURL( rURL );
1048 return uno::Reference< frame::XDispatch > ();
1051 uno::Sequence<uno::Reference<frame::XDispatch > >
1052 ChartController::queryDispatches(
1053 const uno::Sequence<frame::DispatchDescriptor>& xDescripts )
1055 SolarMutexGuard g;
1057 if ( !m_aLifeTimeManager.impl_isDisposed() )
1059 return m_aDispatchContainer.getDispatchesForURLs( xDescripts );
1061 return uno::Sequence<uno::Reference<frame::XDispatch > > ();
1064 // frame::XDispatch
1066 void SAL_CALL ChartController::dispatch(
1067 const util::URL& rURL,
1068 const uno::Sequence< beans::PropertyValue >& rArgs )
1070 OUString aCommand = rURL.Path;
1072 if(aCommand == "LOKSetTextSelection")
1074 if (rArgs.getLength() == 3)
1076 sal_Int32 nType = -1;
1077 rArgs[0].Value >>= nType;
1078 sal_Int32 nX = 0;
1079 rArgs[1].Value >>= nX;
1080 sal_Int32 nY = 0;
1081 rArgs[2].Value >>= nY;
1082 executeDispatch_LOKSetTextSelection(nType, nX, nY);
1085 else if (aCommand == "LOKTransform")
1087 if (rArgs[0].Name == "Action")
1089 OUString sAction;
1090 if ((rArgs[0].Value >>= sAction) && sAction == "PieSegmentDragging")
1092 if (rArgs[1].Name == "Offset")
1094 sal_Int32 nOffset;
1095 if (rArgs[1].Value >>= nOffset)
1097 this->executeDispatch_LOKPieSegmentDragging(nOffset);
1102 else
1104 this->executeDispatch_PositionAndSize(&rArgs);
1107 else if(aCommand == "Paste")
1108 this->executeDispatch_Paste();
1109 else if(aCommand == "Copy" )
1110 this->executeDispatch_Copy();
1111 else if(aCommand == "Cut" )
1112 this->executeDispatch_Cut();
1113 else if(aCommand == "DataRanges" )
1114 this->executeDispatch_SourceData();
1115 else if(aCommand == "Update" ) //Update Chart
1117 ChartViewHelper::setViewToDirtyState( getModel() );
1118 SolarMutexGuard aGuard;
1119 auto pChartWindow(GetChartWindow());
1120 if( pChartWindow )
1121 pChartWindow->Invalidate();
1123 else if(aCommand == "DiagramData" )
1124 this->executeDispatch_EditData();
1125 //insert objects
1126 else if( aCommand == "InsertTitles"
1127 || aCommand == "InsertMenuTitles")
1128 this->executeDispatch_InsertTitles();
1129 else if( aCommand == "InsertMenuLegend" )
1130 this->executeDispatch_OpenLegendDialog();
1131 else if( aCommand == "InsertLegend" )
1132 this->executeDispatch_InsertLegend();
1133 else if( aCommand == "DeleteLegend" )
1134 this->executeDispatch_DeleteLegend();
1135 else if( aCommand == "InsertMenuDataLabels" )
1136 this->executeDispatch_InsertMenu_DataLabels();
1137 else if( aCommand == "InsertMenuAxes"
1138 || aCommand == "InsertRemoveAxes" )
1139 this->executeDispatch_InsertAxes();
1140 else if( aCommand == "InsertMenuGrids" )
1141 this->executeDispatch_InsertGrid();
1142 else if( aCommand == "InsertMenuTrendlines" )
1143 this->executeDispatch_InsertMenu_Trendlines();
1144 else if( aCommand == "InsertMenuMeanValues" )
1145 this->executeDispatch_InsertMenu_MeanValues();
1146 else if( aCommand == "InsertMenuXErrorBars" )
1147 this->executeDispatch_InsertErrorBars(false);
1148 else if( aCommand == "InsertMenuYErrorBars" )
1149 this->executeDispatch_InsertErrorBars(true);
1150 else if( aCommand == "InsertSymbol" )
1151 this->executeDispatch_InsertSpecialCharacter();
1152 else if( aCommand == "InsertTrendline" )
1153 this->executeDispatch_InsertTrendline();
1154 else if( aCommand == "DeleteTrendline" )
1155 this->executeDispatch_DeleteTrendline();
1156 else if( aCommand == "InsertMeanValue" )
1157 this->executeDispatch_InsertMeanValue();
1158 else if( aCommand == "DeleteMeanValue" )
1159 this->executeDispatch_DeleteMeanValue();
1160 else if( aCommand == "InsertXErrorBars" )
1161 this->executeDispatch_InsertErrorBars(false);
1162 else if( aCommand == "InsertYErrorBars" )
1163 this->executeDispatch_InsertErrorBars(true);
1164 else if( aCommand == "DeleteXErrorBars" )
1165 this->executeDispatch_DeleteErrorBars(false);
1166 else if( aCommand == "DeleteYErrorBars" )
1167 this->executeDispatch_DeleteErrorBars(true);
1168 else if( aCommand == "InsertTrendlineEquation" )
1169 this->executeDispatch_InsertTrendlineEquation();
1170 else if( aCommand == "DeleteTrendlineEquation" )
1171 this->executeDispatch_DeleteTrendlineEquation();
1172 else if( aCommand == "InsertTrendlineEquationAndR2" )
1173 this->executeDispatch_InsertTrendlineEquation( true );
1174 else if( aCommand == "InsertR2Value" )
1175 this->executeDispatch_InsertR2Value();
1176 else if( aCommand == "DeleteR2Value")
1177 this->executeDispatch_DeleteR2Value();
1178 else if( aCommand == "InsertDataLabels" )
1179 this->executeDispatch_InsertDataLabels();
1180 else if( aCommand == "InsertDataLabel" )
1181 this->executeDispatch_InsertDataLabel();
1182 else if( aCommand == "DeleteDataLabels")
1183 this->executeDispatch_DeleteDataLabels();
1184 else if( aCommand == "DeleteDataLabel" )
1185 this->executeDispatch_DeleteDataLabel();
1186 else if( aCommand == "ResetAllDataPoints" )
1187 this->executeDispatch_ResetAllDataPoints();
1188 else if( aCommand == "ResetDataPoint" )
1189 this->executeDispatch_ResetDataPoint();
1190 else if( aCommand == "InsertAxis" )
1191 this->executeDispatch_InsertAxis();
1192 else if( aCommand == "InsertMajorGrid" )
1193 this->executeDispatch_InsertMajorGrid();
1194 else if( aCommand == "InsertMinorGrid" )
1195 this->executeDispatch_InsertMinorGrid();
1196 else if( aCommand == "InsertAxisTitle" )
1197 this->executeDispatch_InsertAxisTitle();
1198 else if( aCommand == "DeleteAxis" )
1199 this->executeDispatch_DeleteAxis();
1200 else if( aCommand == "DeleteMajorGrid")
1201 this->executeDispatch_DeleteMajorGrid();
1202 else if( aCommand == "DeleteMinorGrid" )
1203 this->executeDispatch_DeleteMinorGrid();
1204 //format objects
1205 else if( aCommand == "FormatSelection" )
1206 this->executeDispatch_ObjectProperties();
1207 else if( aCommand == "TransformDialog" )
1209 if ( isShapeContext() )
1211 this->impl_ShapeControllerDispatch( rURL, rArgs );
1213 else
1215 this->executeDispatch_PositionAndSize();
1218 else if( lcl_isFormatObjectCommand(aCommand) )
1219 this->executeDispatch_FormatObject(rURL.Path);
1220 //more format
1221 else if( aCommand == "DiagramType" )
1222 this->executeDispatch_ChartType();
1223 else if( aCommand == "View3D" )
1224 this->executeDispatch_View3D();
1225 else if ( aCommand == "Forward" )
1227 if ( isShapeContext() )
1229 this->impl_ShapeControllerDispatch( rURL, rArgs );
1231 else
1233 this->executeDispatch_MoveSeries( true );
1236 else if ( aCommand == "Backward" )
1238 if ( isShapeContext() )
1240 this->impl_ShapeControllerDispatch( rURL, rArgs );
1242 else
1244 this->executeDispatch_MoveSeries( false );
1247 else if( aCommand == "NewArrangement")
1248 this->executeDispatch_NewArrangement();
1249 else if( aCommand == "ToggleLegend" )
1250 this->executeDispatch_ToggleLegend();
1251 else if( aCommand == "ToggleGridHorizontal" )
1252 this->executeDispatch_ToggleGridHorizontal();
1253 else if( aCommand == "ToggleGridVertical" )
1254 this->executeDispatch_ToggleGridVertical();
1255 else if( aCommand == "ScaleText" )
1256 this->executeDispatch_ScaleText();
1257 else if( aCommand == "StatusBarVisible" )
1259 // workaround: this should not be necessary.
1260 uno::Reference< beans::XPropertySet > xPropSet( m_xFrame, uno::UNO_QUERY );
1261 if( xPropSet.is() )
1263 uno::Reference< css::frame::XLayoutManager > xLayoutManager;
1264 xPropSet->getPropertyValue( "LayoutManager" ) >>= xLayoutManager;
1265 if ( xLayoutManager.is() )
1267 bool bIsVisible( xLayoutManager->isElementVisible( "private:resource/statusbar/statusbar" ));
1268 if( bIsVisible )
1270 xLayoutManager->hideElement( "private:resource/statusbar/statusbar" );
1271 xLayoutManager->destroyElement( "private:resource/statusbar/statusbar" );
1273 else
1275 xLayoutManager->createElement( "private:resource/statusbar/statusbar" );
1276 xLayoutManager->showElement( "private:resource/statusbar/statusbar" );
1278 // @todo: update menu state (checkmark next to "Statusbar").
1284 void SAL_CALL ChartController::addStatusListener(
1285 const uno::Reference<frame::XStatusListener >& /* xControl */,
1286 const util::URL& /* aURL */ )
1288 //@todo
1291 void SAL_CALL ChartController::removeStatusListener(
1292 const uno::Reference<frame::XStatusListener >& /* xControl */,
1293 const util::URL& /* aURL */ )
1295 //@todo
1298 // XContextMenuInterception (optional interface)
1299 void SAL_CALL ChartController::registerContextMenuInterceptor(
1300 const uno::Reference< ui::XContextMenuInterceptor >& /* xInterceptor */)
1302 //@todo
1305 void SAL_CALL ChartController::releaseContextMenuInterceptor(
1306 const uno::Reference< ui::XContextMenuInterceptor > & /* xInterceptor */)
1308 //@todo
1311 // ____ XEmbeddedClient ____
1312 // implementation see: ChartController_EditData.cxx
1314 void ChartController::executeDispatch_ChartType()
1316 UndoLiveUpdateGuard aUndoGuard(
1317 SchResId( STR_ACTION_EDIT_CHARTTYPE ), m_xUndoManager );
1319 SolarMutexGuard aSolarGuard;
1320 //prepare and open dialog
1321 ChartTypeDialog aDlg(GetChartFrame(), getModel());
1322 if (aDlg.run() == RET_OK)
1324 impl_adaptDataSeriesAutoResize();
1325 aUndoGuard.commit();
1329 void ChartController::executeDispatch_SourceData()
1331 //convert properties to ItemSet
1332 uno::Reference< XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
1333 OSL_ENSURE( xChartDoc.is(), "Invalid XChartDocument" );
1334 if( !xChartDoc.is() )
1335 return;
1337 // If there is a data table we should ask user if we really want to destroy it
1338 // and switch to data ranges.
1339 ChartModel& rModel = dynamic_cast<ChartModel&>(*xChartDoc);
1340 if ( rModel.hasInternalDataProvider() )
1342 // Check if we will able to create data provider later
1343 css::uno::Reference< com::sun::star::chart2::XDataProviderAccess > xCreatorDoc(
1344 rModel.getParent(), uno::UNO_QUERY);
1345 if (!xCreatorDoc.is())
1346 return;
1348 SolarMutexGuard aSolarGuard;
1350 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetChartFrame(),
1351 VclMessageType::Question, VclButtonsType::YesNo, SchResId(STR_DLG_REMOVE_DATA_TABLE)));
1352 // If "No" then just return
1353 if (xQueryBox->run() == RET_NO)
1354 return;
1356 // Remove data table
1357 rModel.removeDataProviders();
1359 // Ask parent document to create new data provider
1361 uno::Reference< data::XDataProvider > xDataProvider = xCreatorDoc->createDataProvider();
1362 SAL_WARN_IF( !xDataProvider.is(), "chart2.main", "Data provider was not created" );
1363 if (xDataProvider.is())
1365 rModel.attachDataProvider(xDataProvider);
1369 UndoLiveUpdateGuard aUndoGuard(
1370 SchResId(STR_ACTION_EDIT_DATA_RANGES), m_xUndoManager);
1372 SolarMutexGuard aSolarGuard;
1373 ::chart::DataSourceDialog aDlg(GetChartFrame(), xChartDoc, m_xCC);
1374 if (aDlg.run() == RET_OK)
1376 impl_adaptDataSeriesAutoResize();
1377 aUndoGuard.commit();
1381 void ChartController::executeDispatch_MoveSeries( bool bForward )
1383 ControllerLockGuardUNO aCLGuard( getModel() );
1385 //get selected series
1386 OUString aObjectCID(m_aSelection.getSelectedCID());
1387 uno::Reference< XDataSeries > xGivenDataSeries( ObjectIdentifier::getDataSeriesForCID( //yyy todo also legend entries and labels?
1388 aObjectCID, getModel() ) );
1390 UndoGuardWithSelection aUndoGuard(
1391 ActionDescriptionProvider::createDescription(
1392 (bForward ? ActionDescriptionProvider::ActionType::MoveToTop : ActionDescriptionProvider::ActionType::MoveToBottom),
1393 SchResId(STR_OBJECT_DATASERIES)),
1394 m_xUndoManager );
1396 bool bChanged = DiagramHelper::moveSeries( ChartModelHelper::findDiagram( getModel() ), xGivenDataSeries, bForward );
1397 if( bChanged )
1399 m_aSelection.setSelection( ObjectIdentifier::getMovedSeriesCID( aObjectCID, bForward ) );
1400 aUndoGuard.commit();
1404 // ____ XMultiServiceFactory ____
1405 uno::Reference< uno::XInterface > SAL_CALL
1406 ChartController::createInstance( const OUString& aServiceSpecifier )
1408 uno::Reference< uno::XInterface > xResult;
1410 if( aServiceSpecifier == CHART_ACCESSIBLE_TEXT_SERVICE_NAME )
1411 xResult.set( impl_createAccessibleTextContext());
1412 return xResult;
1415 uno::Reference< uno::XInterface > SAL_CALL
1416 ChartController::createInstanceWithArguments(
1417 const OUString& ServiceSpecifier,
1418 const uno::Sequence< uno::Any >& /* Arguments */ )
1420 // ignore Arguments
1421 return createInstance( ServiceSpecifier );
1424 uno::Sequence< OUString > SAL_CALL
1425 ChartController::getAvailableServiceNames()
1427 uno::Sequence< OUString > aServiceNames { CHART_ACCESSIBLE_TEXT_SERVICE_NAME };
1428 return aServiceNames;
1431 // ____ XModifyListener ____
1432 void SAL_CALL ChartController::modified(
1433 const lang::EventObject& /* aEvent */ )
1435 // the source can also be a subobject of the ChartModel
1436 // @todo: change the source in ChartModel to always be the model itself ?
1437 //todo? update menu states ?
1440 void ChartController::NotifyUndoActionHdl( std::unique_ptr<SdrUndoAction> pUndoAction )
1442 ENSURE_OR_RETURN_VOID( pUndoAction, "invalid Undo action" );
1444 OUString aObjectCID = m_aSelection.getSelectedCID();
1445 if ( aObjectCID.isEmpty() )
1449 const Reference< document::XUndoManagerSupplier > xSuppUndo( getModel(), uno::UNO_QUERY_THROW );
1450 const Reference< document::XUndoManager > xUndoManager( xSuppUndo->getUndoManager(), uno::UNO_SET_THROW );
1451 const Reference< document::XUndoAction > xAction( new impl::ShapeUndoElement( std::move(pUndoAction) ) );
1452 xUndoManager->addUndoAction( xAction );
1454 catch( const uno::Exception& )
1456 DBG_UNHANDLED_EXCEPTION("chart2");
1461 DrawModelWrapper* ChartController::GetDrawModelWrapper()
1463 if( !m_pDrawModelWrapper.get() )
1465 ExplicitValueProvider* pProvider = comphelper::getUnoTunnelImplementation<ExplicitValueProvider>( m_xChartView );
1466 if( pProvider )
1467 m_pDrawModelWrapper = pProvider->getDrawModelWrapper();
1468 if ( m_pDrawModelWrapper.get() )
1470 m_pDrawModelWrapper->getSdrModel().SetNotifyUndoActionHdl(
1471 std::bind(&ChartController::NotifyUndoActionHdl, this, std::placeholders::_1) );
1474 return m_pDrawModelWrapper.get();
1477 DrawViewWrapper* ChartController::GetDrawViewWrapper()
1479 if ( !m_pDrawViewWrapper )
1481 impl_createDrawViewController();
1483 return m_pDrawViewWrapper.get();
1487 VclPtr<ChartWindow> ChartController::GetChartWindow() const
1489 // clients getting the naked VCL Window from UNO should always have the
1490 // solar mutex (and keep it over the lifetime of this ptr), as VCL might
1491 // might deinit otherwise
1492 DBG_TESTSOLARMUTEX();
1493 if(!m_xViewWindow.is())
1494 return nullptr;
1495 return dynamic_cast<ChartWindow*>(VCLUnoHelper::GetWindow(m_xViewWindow).get());
1498 weld::Window* ChartController::GetChartFrame()
1500 // clients getting the naked VCL Window from UNO should always have the
1501 // solar mutex (and keep it over the lifetime of this ptr), as VCL might
1502 // might deinit otherwise
1503 DBG_TESTSOLARMUTEX();
1504 return Application::GetFrameWeld(m_xViewWindow);
1507 bool ChartController::isAdditionalShapeSelected() const
1509 return m_aSelection.isAdditionalShapeSelected();
1512 void ChartController::SetAndApplySelection(const Reference<drawing::XShape>& rxShape)
1514 if(rxShape.is())
1516 m_aSelection.setSelection(rxShape);
1517 m_aSelection.applySelection(GetDrawViewWrapper());
1523 uno::Reference< XAccessible > ChartController::CreateAccessible()
1525 uno::Reference< XAccessible > xResult = new AccessibleChartView( GetDrawViewWrapper() );
1526 impl_initializeAccessible( uno::Reference< lang::XInitialization >( xResult, uno::UNO_QUERY ) );
1527 return xResult;
1530 void ChartController::impl_invalidateAccessible()
1532 SolarMutexGuard aGuard;
1533 auto pChartWindow(GetChartWindow());
1534 if( pChartWindow )
1536 Reference< lang::XInitialization > xInit( pChartWindow->GetAccessible(false), uno::UNO_QUERY );
1537 if(xInit.is())
1539 uno::Sequence< uno::Any > aArguments(3);//empty arguments -> invalid accessible
1540 xInit->initialize(aArguments);
1544 void ChartController::impl_initializeAccessible()
1546 SolarMutexGuard aGuard;
1547 auto pChartWindow(GetChartWindow());
1548 if( pChartWindow )
1549 this->impl_initializeAccessible( Reference< lang::XInitialization >( pChartWindow->GetAccessible(false), uno::UNO_QUERY ) );
1551 void ChartController::impl_initializeAccessible( const uno::Reference< lang::XInitialization >& xInit )
1553 if(xInit.is())
1555 uno::Sequence< uno::Any > aArguments(5);
1556 aArguments[0] <<= uno::Reference<view::XSelectionSupplier>(this);
1557 aArguments[1] <<= getModel();
1558 aArguments[2] <<= m_xChartView;
1559 uno::Reference< XAccessible > xParent;
1561 SolarMutexGuard aGuard;
1562 auto pChartWindow(GetChartWindow());
1563 if( pChartWindow )
1565 vcl::Window* pParentWin( pChartWindow->GetAccessibleParentWindow());
1566 if( pParentWin )
1567 xParent.set( pParentWin->GetAccessible());
1570 aArguments[3] <<= xParent;
1571 aArguments[4] <<= m_xViewWindow;
1573 xInit->initialize(aArguments);
1577 const std::set< OUString >& ChartController::impl_getAvailableCommands()
1579 static std::set< OUString > s_AvailableCommands {
1580 // commands for container forward
1581 "AddDirect", "NewDoc", "Open",
1582 "Save", "SaveAs", "SendMail",
1583 "EditDoc", "ExportDirectToPDF", "PrintDefault",
1585 // own commands
1586 "Cut", "Copy", "Paste",
1587 "DataRanges", "DiagramData",
1588 // insert objects
1589 "InsertMenuTitles", "InsertTitles",
1590 "InsertMenuLegend", "InsertLegend", "DeleteLegend",
1591 "InsertMenuDataLabels",
1592 "InsertMenuAxes", "InsertRemoveAxes", "InsertMenuGrids",
1593 "InsertSymbol",
1594 "InsertTrendlineEquation", "InsertTrendlineEquationAndR2",
1595 "InsertR2Value", "DeleteR2Value",
1596 "InsertMenuTrendlines", "InsertTrendline",
1597 "InsertMenuMeanValues", "InsertMeanValue",
1598 "InsertMenuXErrorBars", "InsertXErrorBars",
1599 "InsertMenuYErrorBars", "InsertYErrorBars",
1600 "InsertDataLabels", "InsertDataLabel",
1601 "DeleteTrendline", "DeleteMeanValue", "DeleteTrendlineEquation",
1602 "DeleteXErrorBars", "DeleteYErrorBars",
1603 "DeleteDataLabels", "DeleteDataLabel",
1604 //format objects
1605 "FormatSelection", "TransformDialog",
1606 "DiagramType", "View3D",
1607 "Forward", "Backward",
1608 "MainTitle", "SubTitle",
1609 "XTitle", "YTitle", "ZTitle",
1610 "SecondaryXTitle", "SecondaryYTitle",
1611 "AllTitles", "Legend",
1612 "DiagramAxisX", "DiagramAxisY", "DiagramAxisZ",
1613 "DiagramAxisA", "DiagramAxisB", "DiagramAxisAll",
1614 "DiagramGridXMain", "DiagramGridYMain", "DiagramGridZMain",
1615 "DiagramGridXHelp", "DiagramGridYHelp", "DiagramGridZHelp",
1616 "DiagramGridAll",
1617 "DiagramWall", "DiagramFloor", "DiagramArea",
1619 //context menu - format objects entries
1620 "FormatWall", "FormatFloor", "FormatChartArea",
1621 "FormatLegend",
1623 "FormatAxis", "FormatTitle",
1624 "FormatDataSeries", "FormatDataPoint",
1625 "ResetAllDataPoints", "ResetDataPoint",
1626 "FormatDataLabels", "FormatDataLabel",
1627 "FormatMeanValue", "FormatTrendline", "FormatTrendlineEquation",
1628 "FormatXErrorBars", "FormatYErrorBars",
1629 "FormatStockLoss", "FormatStockGain",
1631 "FormatMajorGrid", "InsertMajorGrid", "DeleteMajorGrid",
1632 "FormatMinorGrid", "InsertMinorGrid", "DeleteMinorGrid",
1633 "InsertAxis", "DeleteAxis", "InsertAxisTitle",
1635 // toolbar commands
1636 "ToggleGridHorizontal", "ToggleGridVertical", "ToggleLegend", "ScaleText",
1637 "NewArrangement", "Update",
1638 "DefaultColors", "BarWidth", "NumberOfLines",
1639 "ArrangeRow",
1640 "StatusBarVisible",
1641 "ChartElementSelector"};
1642 return s_AvailableCommands;
1645 ViewElementListProvider ChartController::getViewElementListProvider()
1647 return ViewElementListProvider(m_pDrawModelWrapper.get());
1650 } //namespace chart
1652 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1653 com_sun_star_comp_chart2_ChartController_get_implementation(css::uno::XComponentContext *context,
1654 css::uno::Sequence<css::uno::Any> const &)
1656 return cppu::acquire(new chart::ChartController(context));
1659 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */