Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / chart2 / source / controller / main / ChartController.cxx
blob5e288da2a3bdb37a670c8cf8290f3ec8af5eaa46
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 <ChartModelHelper.hxx>
30 #include "ControllerCommandDispatch.hxx"
31 #include <strings.hrc>
32 #include <chartview/ExplicitValueProvider.hxx>
33 #include <ChartViewHelper.hxx>
35 #include <ChartWindow.hxx>
36 #include <chartview/DrawModelWrapper.hxx>
37 #include <DrawViewWrapper.hxx>
38 #include <ObjectIdentifier.hxx>
39 #include <DiagramHelper.hxx>
40 #include <ControllerLockGuard.hxx>
41 #include "UndoGuard.hxx"
42 #include "ChartDropTargetHelper.hxx"
44 #include <dlg_CreationWizard.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/awt/PosSize.hpp>
55 #include <com/sun/star/chart2/XChartDocument.hpp>
56 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
57 #include <com/sun/star/frame/XController2.hpp>
58 #include <com/sun/star/util/XCloneable.hpp>
59 #include <com/sun/star/embed/XEmbeddedClient.hpp>
60 #include <com/sun/star/util/XModeChangeBroadcaster.hpp>
61 #include <com/sun/star/util/XModifyBroadcaster.hpp>
62 #include <com/sun/star/frame/LayoutManagerEvents.hpp>
63 #include <com/sun/star/document/XUndoManagerSupplier.hpp>
64 #include <com/sun/star/document/XUndoAction.hpp>
65 #include <com/sun/star/ui/XSidebar.hpp>
66 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
67 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
68 #include <com/sun/star/drawing/XShape.hpp>
69 #include <com/sun/star/chart2/XDataProviderAccess.hpp>
71 #include <svx/sidebar/SelectionChangeHandler.hxx>
72 #include <toolkit/awt/vclxwindow.hxx>
73 #include <toolkit/helper/vclunohelper.hxx>
74 #include <vcl/svapp.hxx>
75 #include <vcl/weld.hxx>
76 #include <osl/mutex.hxx>
78 #include <sfx2/sidebar/SidebarController.hxx>
80 #include <com/sun/star/frame/XLayoutManager.hpp>
81 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
83 // this is needed to properly destroy the unique_ptr to the AcceleratorExecute
84 // object in the DTOR
85 #include <svtools/acceleratorexecute.hxx>
86 #include <svx/ActionDescriptionProvider.hxx>
87 #include <tools/diagnose_ex.h>
89 // enable the following define to let the controller listen to model changes and
90 // react on this by rebuilding the view
91 #define TEST_ENABLE_MODIFY_LISTENER
93 namespace chart
96 using namespace ::com::sun::star;
97 using namespace ::com::sun::star::accessibility;
98 using namespace ::com::sun::star::chart2;
99 using ::com::sun::star::uno::Reference;
100 using ::com::sun::star::uno::Sequence;
102 ChartController::ChartController(uno::Reference<uno::XComponentContext> const & xContext) :
103 m_aLifeTimeManager( nullptr ),
104 m_bSuspended( false ),
105 m_xCC(xContext), //@todo is it allowed to hold this context??
106 m_xFrame( nullptr ),
107 m_aModelMutex(),
108 m_aModel( nullptr, m_aModelMutex ),
109 m_xViewWindow(),
110 m_xChartView(),
111 m_pDrawModelWrapper(),
112 m_pDrawViewWrapper(nullptr),
113 m_eDragMode(SdrDragMode::Move),
114 m_bWaitingForDoubleClick(false),
115 m_bWaitingForMouseUp(false),
116 m_bFieldButtonDown(false),
117 m_bConnectingToView(false),
118 m_bDisposed(false),
119 m_xUndoManager( nullptr ),
120 m_aDispatchContainer( m_xCC ),
121 m_eDrawMode( CHARTDRAW_SELECT ),
122 mpSelectionChangeHandler(new svx::sidebar::SelectionChangeHandler(
123 [this]() { return this->GetContextName(); },
124 this, vcl::EnumContext::Context::Cell))
126 m_aDoubleClickTimer.SetInvokeHandler( LINK( this, ChartController, DoubleClickWaitingHdl ) );
129 ChartController::~ChartController()
131 stopDoubleClickWaiting();
134 ChartController::TheModel::TheModel( const uno::Reference< frame::XModel > & xModel ) :
135 m_xModel( xModel ),
136 m_xCloseable( nullptr ),
137 m_bOwnership( true )
139 m_xCloseable =
140 uno::Reference< util::XCloseable >( xModel, uno::UNO_QUERY );
143 ChartController::TheModel::~TheModel()
147 void ChartController::TheModel::addListener( ChartController* pController )
149 if(m_xCloseable.is())
151 //if you need to be able to veto against the destruction of the model
152 // you must add as a close listener
154 //otherwise you 'can' add as closelistener or 'must' add as dispose event listener
156 m_xCloseable->addCloseListener(
157 static_cast<util::XCloseListener*>(pController) );
159 else if( m_xModel.is() )
161 //we need to add as dispose event listener
162 m_xModel->addEventListener(
163 static_cast<util::XCloseListener*>(pController) );
168 void ChartController::TheModel::removeListener( ChartController* pController )
170 if(m_xCloseable.is())
171 m_xCloseable->removeCloseListener(
172 static_cast<util::XCloseListener*>(pController) );
174 else if( m_xModel.is() )
175 m_xModel->removeEventListener(
176 static_cast<util::XCloseListener*>(pController) );
179 void ChartController::TheModel::tryTermination()
181 if(!m_bOwnership)
182 return;
186 if(m_xCloseable.is())
190 //@todo ? are we allowed to use sal_True here if we have the explicit ownership?
191 //I think yes, because there might be other CloseListeners later in the list which might be interested still
192 //but make sure that we do not throw the CloseVetoException here ourselves
193 //so stop listening before trying to terminate or check the source of queryclosing event
194 m_xCloseable->close(true);
196 m_bOwnership = false;
198 catch( const util::CloseVetoException& )
200 //since we have indicated to give up the ownership with parameter true in close call
201 //the one who has thrown the CloseVetoException is the new owner
203 SAL_WARN_IF( m_bOwnership, "chart2.main", "a well known owner has caught a CloseVetoException after calling close(true)");
204 m_bOwnership = false;
205 return;
209 else if( m_xModel.is() )
211 //@todo correct??
212 m_xModel->dispose();
213 return;
216 catch(const uno::Exception&)
218 DBG_UNHANDLED_EXCEPTION( "chart2", "Termination of model failed" );
222 ChartController::TheModelRef::TheModelRef( TheModel* pTheModel, osl::Mutex& rMutex ) :
223 m_rModelMutex(rMutex)
225 osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
226 m_xTheModel = pTheModel;
228 ChartController::TheModelRef::TheModelRef( const TheModelRef& rTheModel, ::osl::Mutex& rMutex ) :
229 m_rModelMutex(rMutex)
231 osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
232 m_xTheModel = rTheModel.m_xTheModel;
234 ChartController::TheModelRef& ChartController::TheModelRef::operator=(TheModel* pTheModel)
236 osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
237 m_xTheModel = pTheModel;
238 return *this;
240 ChartController::TheModelRef& ChartController::TheModelRef::operator=(const TheModelRef& rTheModel)
242 osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
243 m_xTheModel = rTheModel.operator->();
244 return *this;
246 ChartController::TheModelRef::~TheModelRef()
248 osl::Guard< osl::Mutex > aGuard( m_rModelMutex );
249 m_xTheModel.clear();
251 bool ChartController::TheModelRef::is() const
253 return m_xTheModel.is();
256 namespace {
258 css::uno::Reference<css::chart2::XChartType> getChartType(
259 const css::uno::Reference<css::chart2::XChartDocument>& xChartDoc)
261 Reference <chart2::XDiagram > xDiagram = xChartDoc->getFirstDiagram();
262 if (!xDiagram.is()) {
263 return css::uno::Reference<css::chart2::XChartType>();
266 Reference< chart2::XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY_THROW );
268 Sequence< Reference< chart2::XCoordinateSystem > > xCooSysSequence( xCooSysContainer->getCoordinateSystems());
269 if (!xCooSysSequence.getLength()) {
270 return css::uno::Reference<css::chart2::XChartType>();
273 Reference< chart2::XChartTypeContainer > xChartTypeContainer( xCooSysSequence[0], uno::UNO_QUERY_THROW );
275 Sequence< Reference< chart2::XChartType > > xChartTypeSequence( xChartTypeContainer->getChartTypes() );
277 return xChartTypeSequence[0];
282 OUString ChartController::GetContextName()
284 if (m_bDisposed)
285 return OUString();
287 uno::Any aAny = getSelection();
288 if (!aAny.hasValue())
289 return OUString("Chart");
291 OUString aCID;
292 aAny >>= aCID;
294 if (aCID.isEmpty())
295 return OUString("Chart");
297 ObjectType eObjectID = ObjectIdentifier::getObjectType(aCID);
298 switch (eObjectID)
300 case OBJECTTYPE_DATA_SERIES:
301 return OUString("Series");
302 break;
303 case OBJECTTYPE_DATA_ERRORS_X:
304 case OBJECTTYPE_DATA_ERRORS_Y:
305 case OBJECTTYPE_DATA_ERRORS_Z:
306 return OUString("ErrorBar");
307 case OBJECTTYPE_AXIS:
308 return OUString("Axis");
309 case OBJECTTYPE_GRID:
310 return OUString("Grid");
311 case OBJECTTYPE_DIAGRAM:
313 css::uno::Reference<css::chart2::XChartType> xChartType = getChartType(css::uno::Reference<css::chart2::XChartDocument>(getModel(), uno::UNO_QUERY));
314 if (xChartType.is() && xChartType->getChartType() == "com.sun.star.chart2.PieChartType")
315 return OUString("ChartElements");
316 break;
318 case OBJECTTYPE_DATA_CURVE:
319 case OBJECTTYPE_DATA_AVERAGE_LINE:
320 return OUString("Trendline");
321 default:
322 break;
325 return OUString("Chart");
328 // private methods
330 bool ChartController::impl_isDisposedOrSuspended() const
332 if( m_aLifeTimeManager.impl_isDisposed() )
333 return true;
335 if( m_bSuspended )
337 OSL_FAIL( "This Controller is suspended" );
338 return true;
340 return false;
343 // lang::XServiceInfo
345 OUString SAL_CALL ChartController::getImplementationName()
347 return OUString(CHART_CONTROLLER_SERVICE_IMPLEMENTATION_NAME);
350 sal_Bool SAL_CALL ChartController::supportsService( const OUString& rServiceName )
352 return cppu::supportsService(this, rServiceName);
355 css::uno::Sequence< OUString > SAL_CALL ChartController::getSupportedServiceNames()
357 return {
358 CHART_CONTROLLER_SERVICE_NAME,
359 "com.sun.star.frame.Controller"
360 //// @todo : add additional services if you support any further
364 namespace {
366 uno::Reference<ui::XSidebar> getSidebarFromModel(const uno::Reference<frame::XModel>& xModel)
368 uno::Reference<container::XChild> xChild(xModel, uno::UNO_QUERY);
369 if (!xChild.is())
370 return nullptr;
372 uno::Reference<frame::XModel> xParent (xChild->getParent(), uno::UNO_QUERY);
373 if (!xParent.is())
374 return nullptr;
376 uno::Reference<frame::XController2> xController(xParent->getCurrentController(), uno::UNO_QUERY);
377 if (!xController.is())
378 return nullptr;
380 uno::Reference<ui::XSidebarProvider> xSidebarProvider (xController->getSidebar(), uno::UNO_QUERY);
381 if (!xSidebarProvider.is())
382 return nullptr;
384 uno::Reference<ui::XSidebar> xSidebar(xSidebarProvider->getSidebar(), uno::UNO_QUERY);
386 return xSidebar;
391 // XController
393 void SAL_CALL ChartController::attachFrame(
394 const uno::Reference<frame::XFrame>& xFrame )
396 SolarMutexGuard aGuard;
398 if( impl_isDisposedOrSuspended() ) //@todo? allow attaching the frame while suspended?
399 return; //behave passive if already disposed or suspended
401 mpSelectionChangeHandler->Connect();
403 uno::Reference<ui::XSidebar> xSidebar = getSidebarFromModel(getModel());
404 if (xSidebar.is())
406 sfx2::sidebar::SidebarController* pSidebar = dynamic_cast<sfx2::sidebar::SidebarController*>(xSidebar.get());
407 sfx2::sidebar::SidebarController::registerSidebarForFrame(pSidebar, this);
408 pSidebar->updateModel(getModel());
409 css::lang::EventObject aEvent;
410 mpSelectionChangeHandler->selectionChanged(aEvent);
413 if(m_xFrame.is()) //what happens, if we do have a Frame already??
415 //@todo? throw exception?
416 OSL_FAIL( "there is already a frame attached to the controller" );
417 return;
420 //--attach frame
421 m_xFrame = xFrame; //the frameloader is responsible to call xFrame->setComponent
423 //add as disposelistener to the frame (due to persistent reference) ??...:
425 //the frame is considered to be owner of this controller and will live longer than we do
426 //the frame or the disposer of the frame has the duty to call suspend and dispose on this object
427 //so we do not need to add as lang::XEventListener for DisposingEvents right?
429 //@todo nothing right???
431 //create view @todo is this the correct place here??
433 vcl::Window* pParent = nullptr;
434 //get the window parent from the frame to use as parent for our new window
435 if(xFrame.is())
437 uno::Reference< awt::XWindow > xContainerWindow = xFrame->getContainerWindow();
438 VCLXWindow* pParentComponent = VCLXWindow::GetImplementation(xContainerWindow);
439 assert(pParentComponent);
440 if (pParentComponent)
441 pParentComponent->setVisible(true);
443 pParent = VCLUnoHelper::GetWindow( xContainerWindow ).get();
447 // calls to VCL
448 SolarMutexGuard aSolarGuard;
449 auto pChartWindow = VclPtr<ChartWindow>::Create(this,pParent,pParent?pParent->GetStyle():0);
450 pChartWindow->SetBackground();//no Background
451 m_xViewWindow.set( pChartWindow->GetComponentInterface(), uno::UNO_QUERY );
452 pChartWindow->Show();
453 m_apDropTargetHelper.reset(
454 new ChartDropTargetHelper( pChartWindow->GetDropTarget(),
455 uno::Reference< chart2::XChartDocument >( getModel(), uno::UNO_QUERY )));
457 impl_createDrawViewController();
460 //create the menu
462 uno::Reference< beans::XPropertySet > xPropSet( xFrame, uno::UNO_QUERY );
463 if( xPropSet.is() )
467 uno::Reference< css::frame::XLayoutManager > xLayoutManager;
468 xPropSet->getPropertyValue( "LayoutManager" ) >>= xLayoutManager;
469 if ( xLayoutManager.is() )
471 xLayoutManager->lock();
472 xLayoutManager->requestElement( "private:resource/menubar/menubar" );
473 //@todo: createElement should become unnecessary, remove when #i79198# is fixed
474 xLayoutManager->createElement( "private:resource/toolbar/standardbar" );
475 xLayoutManager->requestElement( "private:resource/toolbar/standardbar" );
476 //@todo: createElement should become unnecessary, remove when #i79198# is fixed
477 xLayoutManager->createElement( "private:resource/toolbar/toolbar" );
478 xLayoutManager->requestElement( "private:resource/toolbar/toolbar" );
480 // #i12587# support for shapes in chart
481 xLayoutManager->createElement( "private:resource/toolbar/drawbar" );
482 xLayoutManager->requestElement( "private:resource/toolbar/drawbar" );
484 xLayoutManager->requestElement( "private:resource/statusbar/statusbar" );
485 xLayoutManager->unlock();
487 // add as listener to get notified when
488 m_xLayoutManagerEventBroadcaster.set( xLayoutManager, uno::UNO_QUERY );
489 if( m_xLayoutManagerEventBroadcaster.is())
490 m_xLayoutManagerEventBroadcaster->addLayoutManagerEventListener( this );
493 catch( const uno::Exception & )
495 DBG_UNHANDLED_EXCEPTION("chart2");
501 //XModeChangeListener
502 void SAL_CALL ChartController::modeChanged( const util::ModeChangeEvent& rEvent )
504 SolarMutexGuard aGuard;
505 auto pChartWindow(GetChartWindow());
506 //adjust controller to view status changes
508 if( rEvent.NewMode == "dirty" )
510 //the view has become dirty, we should repaint it if we have a window
511 if( pChartWindow )
512 pChartWindow->ForceInvalidate();
514 else if( rEvent.NewMode == "invalid" )
516 //the view is about to become invalid so end all actions on it
517 impl_invalidateAccessible();
518 if( m_pDrawViewWrapper && m_pDrawViewWrapper->IsTextEdit() )
519 this->EndTextEdit();
520 if( m_pDrawViewWrapper )
522 m_pDrawViewWrapper->UnmarkAll();
523 m_pDrawViewWrapper->HideSdrPage();
526 else
528 //the view was rebuild so we can start some actions on it again
529 if( !m_bConnectingToView )
531 if(pChartWindow && m_aModel.is() )
533 m_bConnectingToView = true;
535 GetDrawModelWrapper();
536 if(m_pDrawModelWrapper)
539 if( m_pDrawViewWrapper )
540 m_pDrawViewWrapper->ReInit();
543 //reselect object
544 if( m_aSelection.hasSelection() )
545 this->impl_selectObjectAndNotiy();
546 else
547 ChartModelHelper::triggerRangeHighlighting( getModel() );
549 impl_initializeAccessible();
552 if( pChartWindow )
553 pChartWindow->Invalidate();
557 m_bConnectingToView = false;
563 sal_Bool SAL_CALL ChartController::attachModel( const uno::Reference< frame::XModel > & xModel )
565 impl_invalidateAccessible();
567 //is called to attach the controller to a new model.
568 //return true if attach was successfully, false otherwise (e.g. if you do not work with a model)
570 SolarMutexResettableGuard aGuard;
571 if( impl_isDisposedOrSuspended() ) //@todo? allow attaching a new model while suspended?
572 return false; //behave passive if already disposed or suspended
573 aGuard.clear();
575 TheModelRef aNewModelRef( new TheModel( xModel), m_aModelMutex);
576 TheModelRef aOldModelRef(m_aModel,m_aModelMutex);
577 m_aModel = aNewModelRef;
579 //--handle relations to the old model if any
580 if( aOldModelRef.is() )
582 uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY );
583 if( xViewBroadcaster.is() )
584 xViewBroadcaster->removeModeChangeListener(this);
585 m_pDrawModelWrapper.reset();
587 aOldModelRef->removeListener( this );
588 #ifdef TEST_ENABLE_MODIFY_LISTENER
589 uno::Reference< util::XModifyBroadcaster > xMBroadcaster( aOldModelRef->getModel(),uno::UNO_QUERY );
590 if( xMBroadcaster.is())
591 xMBroadcaster->removeModifyListener( this );
592 #endif
595 //--handle relations to the new model
596 aNewModelRef->addListener( this );
598 aGuard.reset(); // lock for m_aDispatchContainer access
599 // set new model at dispatchers
600 m_aDispatchContainer.setModel( aNewModelRef->getModel());
601 ControllerCommandDispatch * pDispatch = new ControllerCommandDispatch( m_xCC, this, &m_aDispatchContainer );
602 pDispatch->initialize();
604 // the dispatch container will return "this" for all commands returned by
605 // impl_getAvailableCommands(). That means, for those commands dispatch()
606 // is called here at the ChartController.
607 m_aDispatchContainer.setChartDispatch( pDispatch, impl_getAvailableCommands() );
609 DrawCommandDispatch* pDrawDispatch = new DrawCommandDispatch( m_xCC, this );
610 pDrawDispatch->initialize();
611 m_aDispatchContainer.setDrawCommandDispatch( pDrawDispatch );
613 ShapeController* pShapeController = new ShapeController( m_xCC, this );
614 pShapeController->initialize();
615 m_aDispatchContainer.setShapeController( pShapeController );
616 aGuard.clear();
618 #ifdef TEST_ENABLE_MODIFY_LISTENER
619 uno::Reference< util::XModifyBroadcaster > xMBroadcaster( aNewModelRef->getModel(),uno::UNO_QUERY );
620 if( xMBroadcaster.is())
621 xMBroadcaster->addModifyListener( this );
622 #endif
624 // #i119999# Do not do this per default to allow the user to deselect the chart OLE with a single press to ESC
625 // select chart area per default:
626 // select( uno::Any( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) ) );
628 uno::Reference< lang::XMultiServiceFactory > xFact( getModel(), uno::UNO_QUERY );
629 if( xFact.is())
631 m_xChartView = xFact->createInstance( CHART_VIEW_SERVICE_NAME );
632 GetDrawModelWrapper();
633 uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY );
634 if( xViewBroadcaster.is() )
635 xViewBroadcaster->addModeChangeListener(this);
638 //the frameloader is responsible to call xModel->connectController
640 SolarMutexGuard aGuard2;
641 auto pChartWindow(GetChartWindow());
642 if( pChartWindow )
643 pChartWindow->Invalidate();
646 uno::Reference< document::XUndoManagerSupplier > xSuppUndo( getModel(), uno::UNO_QUERY_THROW );
647 m_xUndoManager.set( xSuppUndo->getUndoManager(), uno::UNO_QUERY_THROW );
649 return true;
652 uno::Reference< frame::XFrame > SAL_CALL ChartController::getFrame()
654 //provides access to owner frame of this controller
655 //return the frame containing this controller
657 return m_xFrame;
660 uno::Reference< frame::XModel > SAL_CALL ChartController::getModel()
662 //provides access to currently attached model
663 //returns the currently attached model
665 //return nothing, if you do not have a model
666 TheModelRef aModelRef( m_aModel, m_aModelMutex);
667 if(aModelRef.is())
668 return aModelRef->getModel();
670 return uno::Reference< frame::XModel > ();
673 uno::Any SAL_CALL ChartController::getViewData()
675 //provides access to current view status
676 //set of data that can be used to restore the current view status at later time
677 // by using XController::restoreViewData()
679 SolarMutexGuard aGuard;
680 if( impl_isDisposedOrSuspended() )
681 return uno::Any(); //behave passive if already disposed or suspended //@todo? or throw an exception??
683 //-- collect current view state
684 uno::Any aRet;
685 //// @todo integrate specialized implementation
687 return aRet;
690 void SAL_CALL ChartController::restoreViewData(
691 const uno::Any& /* Value */ )
693 //restores the view status using the data gotten from a previous call to XController::getViewData()
695 SolarMutexGuard aGuard;
696 if( impl_isDisposedOrSuspended() )
697 return; //behave passive if already disposed or suspended //@todo? or throw an exception??
699 //// @todo integrate specialized implementation
702 sal_Bool SAL_CALL ChartController::suspend( sal_Bool bSuspend )
704 //is called to prepare the controller for closing the view
705 //bSuspend==true: force the controller to suspend his work
706 //bSuspend==false try to reactivate the controller
707 //returns true if request was accepted and of course successfully finished, false otherwise
709 //we may show dialogs here to ask the user for saving changes ... @todo?
711 SolarMutexGuard aGuard;
712 if( m_aLifeTimeManager.impl_isDisposed() )
713 return false; //behave passive if already disposed, return false because request was not accepted //@todo? correct
715 if(bool(bSuspend) == m_bSuspended)
717 OSL_FAIL( "new suspend mode equals old suspend mode" );
718 return true;
721 //change suspend mode
722 m_bSuspended = bSuspend;
723 return true;
726 void ChartController::impl_createDrawViewController()
728 SolarMutexGuard aGuard;
729 if(!m_pDrawViewWrapper)
731 if( m_pDrawModelWrapper )
733 m_pDrawViewWrapper = new DrawViewWrapper(m_pDrawModelWrapper->getSdrModel(),GetChartWindow());
734 m_pDrawViewWrapper->attachParentReferenceDevice( getModel() );
739 void ChartController::impl_deleteDrawViewController()
741 if( m_pDrawViewWrapper )
743 SolarMutexGuard aGuard;
744 if( m_pDrawViewWrapper->IsTextEdit() )
745 this->EndTextEdit();
746 DELETEZ( m_pDrawViewWrapper );
750 // XComponent (base of XController)
752 void SAL_CALL ChartController::dispose()
754 m_bDisposed = true;
756 if (getModel().is())
758 uno::Reference<ui::XSidebar> xSidebar = getSidebarFromModel(getModel());
759 if (sfx2::sidebar::SidebarController* pSidebar = dynamic_cast<sfx2::sidebar::SidebarController*>(xSidebar.get()))
761 sfx2::sidebar::SidebarController::unregisterSidebarForFrame(pSidebar, this);
764 mpSelectionChangeHandler->selectionChanged(css::lang::EventObject());
765 mpSelectionChangeHandler->Disconnect();
769 //This object should release all resources and references in the
770 //easiest possible manner
771 //This object must notify all registered listeners using the method
772 //<member>XEventListener::disposing</member>
774 //hold no mutex
775 if( !m_aLifeTimeManager.dispose() )
776 return;
778 // OSL_ENSURE( m_bSuspended, "dispose was called but controller is not suspended" );
780 this->stopDoubleClickWaiting();
782 //end range highlighting
783 if( m_aModel.is())
785 uno::Reference< view::XSelectionChangeListener > xSelectionChangeListener;
786 uno::Reference< chart2::data::XDataReceiver > xDataReceiver( getModel(), uno::UNO_QUERY );
787 if( xDataReceiver.is() )
788 xSelectionChangeListener.set( xDataReceiver->getRangeHighlighter(), uno::UNO_QUERY );
789 if( xSelectionChangeListener.is() )
791 uno::Reference< frame::XController > xController( this );
792 uno::Reference< lang::XComponent > xComp( xController, uno::UNO_QUERY );
793 lang::EventObject aEvent( xComp );
794 xSelectionChangeListener->disposing( aEvent );
798 //--release all resources and references
800 uno::Reference< chart2::X3DChartWindowProvider > x3DWindowProvider(getModel(), uno::UNO_QUERY);
801 if(x3DWindowProvider.is())
802 x3DWindowProvider->setWindow(0);
804 uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY );
805 if( xViewBroadcaster.is() )
806 xViewBroadcaster->removeModeChangeListener(this);
808 impl_invalidateAccessible();
809 SolarMutexGuard aSolarGuard;
810 impl_deleteDrawViewController();
811 m_pDrawModelWrapper.reset();
813 m_apDropTargetHelper.reset();
815 //the accessible view is disposed within window destructor of m_pChartWindow
816 if(m_xViewWindow.is())
817 m_xViewWindow->dispose(); //ChartWindow is deleted via UNO due to dispose of m_xViewWindow (triggered by Framework (Controller pretends to be XWindow also))
818 m_xChartView.clear();
821 // remove as listener to layout manager events
822 if( m_xLayoutManagerEventBroadcaster.is())
824 m_xLayoutManagerEventBroadcaster->removeLayoutManagerEventListener( this );
825 m_xLayoutManagerEventBroadcaster.set( nullptr );
828 m_xFrame.clear();
829 m_xUndoManager.clear();
831 TheModelRef aModelRef( m_aModel, m_aModelMutex);
832 m_aModel = nullptr;
834 if( aModelRef.is())
836 uno::Reference< frame::XModel > xModel( aModelRef->getModel() );
837 if(xModel.is())
838 xModel->disconnectController( uno::Reference< frame::XController >( this ));
840 aModelRef->removeListener( this );
841 #ifdef TEST_ENABLE_MODIFY_LISTENER
844 uno::Reference< util::XModifyBroadcaster > xMBroadcaster( aModelRef->getModel(),uno::UNO_QUERY );
845 if( xMBroadcaster.is())
846 xMBroadcaster->removeModifyListener( this );
848 catch( const uno::Exception & )
850 DBG_UNHANDLED_EXCEPTION("chart2");
852 #endif
853 aModelRef->tryTermination();
856 //// @todo integrate specialized implementation
857 //e.g. release further resources and references
859 SolarMutexGuard g;
860 m_aDispatchContainer.DisposeAndClear();
862 catch( const uno::Exception & )
864 DBG_UNHANDLED_EXCEPTION("chart2");
865 assert(!m_xChartView.is());
869 void SAL_CALL ChartController::addEventListener(
870 const uno::Reference<lang::XEventListener>& xListener )
872 SolarMutexGuard aGuard;
873 if( impl_isDisposedOrSuspended() )//@todo? allow adding of listeners in suspend mode?
874 return; //behave passive if already disposed or suspended
876 //--add listener
877 m_aLifeTimeManager.m_aListenerContainer.addInterface( cppu::UnoType<lang::XEventListener>::get(), xListener );
880 void SAL_CALL ChartController::removeEventListener(
881 const uno::Reference<lang::XEventListener>& xListener )
883 SolarMutexGuard aGuard;
884 if( m_aLifeTimeManager.impl_isDisposed(false) )
885 return; //behave passive if already disposed or suspended
887 //--remove listener
888 m_aLifeTimeManager.m_aListenerContainer.removeInterface( cppu::UnoType<lang::XEventListener>::get(), xListener );
891 // util::XCloseListener
892 void SAL_CALL ChartController::queryClosing(
893 const lang::EventObject& rSource,
894 sal_Bool /*bGetsOwnership*/ )
896 //do not use the m_aControllerMutex here because this call is not allowed to block
898 TheModelRef aModelRef( m_aModel, m_aModelMutex);
900 if( !aModelRef.is() )
901 return;
903 if( !(aModelRef->getModel() == rSource.Source) )
905 OSL_FAIL( "queryClosing was called on a controller from an unknown source" );
906 return;
909 //@ todo prepare to closing model -> don't start any further hindering actions
912 void SAL_CALL ChartController::notifyClosing(
913 const lang::EventObject& rSource )
915 //Listener should deregister himself and release all references to the closing object.
917 TheModelRef aModelRef( m_aModel, m_aModelMutex);
918 if( impl_releaseThisModel( rSource.Source ) )
920 //--stop listening to the closing model
921 aModelRef->removeListener( this );
923 // #i79087# If the model using this controller is closed, the frame is
924 // expected to be closed as well
925 Reference< util::XCloseable > xFrameCloseable( m_xFrame, uno::UNO_QUERY );
926 if( xFrameCloseable.is())
930 xFrameCloseable->close( false /* DeliverOwnership */ );
931 m_xFrame.clear();
933 catch( const util::CloseVetoException & )
935 // closing was vetoed
941 bool ChartController::impl_releaseThisModel(
942 const uno::Reference< uno::XInterface > & xModel )
944 bool bReleaseModel = false;
946 ::osl::Guard< ::osl::Mutex > aGuard( m_aModelMutex );
947 if( m_aModel.is() && m_aModel->getModel() == xModel )
949 m_aModel = nullptr;
950 m_xUndoManager.clear();
951 bReleaseModel = true;
954 if( bReleaseModel )
956 SolarMutexGuard g;
957 m_aDispatchContainer.setModel( nullptr );
959 return bReleaseModel;
962 // util::XEventListener (base of XCloseListener)
963 void SAL_CALL ChartController::disposing(
964 const lang::EventObject& rSource )
966 if( !impl_releaseThisModel( rSource.Source ))
968 if( rSource.Source == m_xLayoutManagerEventBroadcaster )
969 m_xLayoutManagerEventBroadcaster.set( nullptr );
973 void SAL_CALL ChartController::layoutEvent(
974 const lang::EventObject& aSource,
975 sal_Int16 eLayoutEvent,
976 const uno::Any& /* aInfo */ )
978 if( eLayoutEvent == frame::LayoutManagerEvents::MERGEDMENUBAR )
980 Reference< frame::XLayoutManager > xLM( aSource.Source, uno::UNO_QUERY );
981 if( xLM.is())
983 xLM->createElement( "private:resource/statusbar/statusbar" );
984 xLM->requestElement( "private:resource/statusbar/statusbar" );
989 // XDispatchProvider (required interface)
991 namespace
994 bool lcl_isFormatObjectCommand( const OUString& aCommand )
996 if( aCommand == "MainTitle"
997 || aCommand == "SubTitle"
998 || aCommand == "XTitle"
999 || aCommand == "YTitle"
1000 || aCommand == "ZTitle"
1001 || aCommand == "SecondaryXTitle"
1002 || aCommand == "SecondaryYTitle"
1003 || aCommand == "AllTitles"
1004 || aCommand == "DiagramAxisX"
1005 || aCommand == "DiagramAxisY"
1006 || aCommand == "DiagramAxisZ"
1007 || aCommand == "DiagramAxisA"
1008 || aCommand == "DiagramAxisB"
1009 || aCommand == "DiagramAxisAll"
1010 || aCommand == "DiagramGridXMain"
1011 || aCommand == "DiagramGridYMain"
1012 || aCommand == "DiagramGridZMain"
1013 || aCommand == "DiagramGridXHelp"
1014 || aCommand == "DiagramGridYHelp"
1015 || aCommand == "DiagramGridZHelp"
1016 || aCommand == "DiagramGridAll"
1018 || aCommand == "DiagramWall"
1019 || aCommand == "DiagramFloor"
1020 || aCommand == "DiagramArea"
1021 || aCommand == "Legend"
1023 || aCommand == "FormatWall"
1024 || aCommand == "FormatFloor"
1025 || aCommand == "FormatChartArea"
1026 || aCommand == "FormatLegend"
1028 || aCommand == "FormatTitle"
1029 || aCommand == "FormatAxis"
1030 || aCommand == "FormatDataSeries"
1031 || aCommand == "FormatDataPoint"
1032 || aCommand == "FormatDataLabels"
1033 || aCommand == "FormatDataLabel"
1034 || aCommand == "FormatXErrorBars"
1035 || aCommand == "FormatYErrorBars"
1036 || aCommand == "FormatMeanValue"
1037 || aCommand == "FormatTrendline"
1038 || aCommand == "FormatTrendlineEquation"
1039 || aCommand == "FormatStockLoss"
1040 || aCommand == "FormatStockGain"
1041 || aCommand == "FormatMajorGrid"
1042 || aCommand == "FormatMinorGrid"
1044 return true;
1046 // else
1047 return false;
1050 } // anonymous namespace
1052 uno::Reference<frame::XDispatch> SAL_CALL
1053 ChartController::queryDispatch(
1054 const util::URL& rURL,
1055 const OUString& rTargetFrameName,
1056 sal_Int32 /* nSearchFlags */)
1058 SolarMutexGuard aGuard;
1060 if ( !m_aLifeTimeManager.impl_isDisposed() && getModel().is() )
1062 if( !rTargetFrameName.isEmpty() && rTargetFrameName == "_self" )
1063 return m_aDispatchContainer.getDispatchForURL( rURL );
1065 return uno::Reference< frame::XDispatch > ();
1068 uno::Sequence<uno::Reference<frame::XDispatch > >
1069 ChartController::queryDispatches(
1070 const uno::Sequence<frame::DispatchDescriptor>& xDescripts )
1072 SolarMutexGuard g;
1074 if ( !m_aLifeTimeManager.impl_isDisposed() )
1076 return m_aDispatchContainer.getDispatchesForURLs( xDescripts );
1078 return uno::Sequence<uno::Reference<frame::XDispatch > > ();
1081 // frame::XDispatch
1083 void SAL_CALL ChartController::dispatch(
1084 const util::URL& rURL,
1085 const uno::Sequence< beans::PropertyValue >& rArgs )
1087 OUString aCommand = rURL.Path;
1089 if(aCommand == "LOKSetTextSelection")
1091 if (rArgs.getLength() == 3)
1093 sal_Int32 nType = -1;
1094 rArgs[0].Value >>= nType;
1095 sal_Int32 nX = 0;
1096 rArgs[1].Value >>= nX;
1097 sal_Int32 nY = 0;
1098 rArgs[2].Value >>= nY;
1099 executeDispatch_LOKSetTextSelection(nType, nX, nY);
1102 else if(aCommand == "Paste")
1103 this->executeDispatch_Paste();
1104 else if(aCommand == "Copy" )
1105 this->executeDispatch_Copy();
1106 else if(aCommand == "Cut" )
1107 this->executeDispatch_Cut();
1108 else if(aCommand == "DataRanges" )
1109 this->executeDispatch_SourceData();
1110 else if(aCommand == "Update" ) //Update Chart
1112 ChartViewHelper::setViewToDirtyState( getModel() );
1113 SolarMutexGuard aGuard;
1114 auto pChartWindow(GetChartWindow());
1115 if( pChartWindow )
1116 pChartWindow->Invalidate();
1118 else if(aCommand == "DiagramData" )
1119 this->executeDispatch_EditData();
1120 //insert objects
1121 else if( aCommand == "InsertTitles"
1122 || aCommand == "InsertMenuTitles")
1123 this->executeDispatch_InsertTitles();
1124 else if( aCommand == "InsertMenuLegend" )
1125 this->executeDispatch_OpenLegendDialog();
1126 else if( aCommand == "InsertLegend" )
1127 this->executeDispatch_InsertLegend();
1128 else if( aCommand == "DeleteLegend" )
1129 this->executeDispatch_DeleteLegend();
1130 else if( aCommand == "InsertMenuDataLabels" )
1131 this->executeDispatch_InsertMenu_DataLabels();
1132 else if( aCommand == "InsertMenuAxes"
1133 || aCommand == "InsertRemoveAxes" )
1134 this->executeDispatch_InsertAxes();
1135 else if( aCommand == "InsertMenuGrids" )
1136 this->executeDispatch_InsertGrid();
1137 else if( aCommand == "InsertMenuTrendlines" )
1138 this->executeDispatch_InsertMenu_Trendlines();
1139 else if( aCommand == "InsertMenuMeanValues" )
1140 this->executeDispatch_InsertMenu_MeanValues();
1141 else if( aCommand == "InsertMenuXErrorBars" )
1142 this->executeDispatch_InsertErrorBars(false);
1143 else if( aCommand == "InsertMenuYErrorBars" )
1144 this->executeDispatch_InsertErrorBars(true);
1145 else if( aCommand == "InsertSymbol" )
1146 this->executeDispatch_InsertSpecialCharacter();
1147 else if( aCommand == "InsertTrendline" )
1148 this->executeDispatch_InsertTrendline();
1149 else if( aCommand == "DeleteTrendline" )
1150 this->executeDispatch_DeleteTrendline();
1151 else if( aCommand == "InsertMeanValue" )
1152 this->executeDispatch_InsertMeanValue();
1153 else if( aCommand == "DeleteMeanValue" )
1154 this->executeDispatch_DeleteMeanValue();
1155 else if( aCommand == "InsertXErrorBars" )
1156 this->executeDispatch_InsertErrorBars(false);
1157 else if( aCommand == "InsertYErrorBars" )
1158 this->executeDispatch_InsertErrorBars(true);
1159 else if( aCommand == "DeleteXErrorBars" )
1160 this->executeDispatch_DeleteErrorBars(false);
1161 else if( aCommand == "DeleteYErrorBars" )
1162 this->executeDispatch_DeleteErrorBars(true);
1163 else if( aCommand == "InsertTrendlineEquation" )
1164 this->executeDispatch_InsertTrendlineEquation();
1165 else if( aCommand == "DeleteTrendlineEquation" )
1166 this->executeDispatch_DeleteTrendlineEquation();
1167 else if( aCommand == "InsertTrendlineEquationAndR2" )
1168 this->executeDispatch_InsertTrendlineEquation( true );
1169 else if( aCommand == "InsertR2Value" )
1170 this->executeDispatch_InsertR2Value();
1171 else if( aCommand == "DeleteR2Value")
1172 this->executeDispatch_DeleteR2Value();
1173 else if( aCommand == "InsertDataLabels" )
1174 this->executeDispatch_InsertDataLabels();
1175 else if( aCommand == "InsertDataLabel" )
1176 this->executeDispatch_InsertDataLabel();
1177 else if( aCommand == "DeleteDataLabels")
1178 this->executeDispatch_DeleteDataLabels();
1179 else if( aCommand == "DeleteDataLabel" )
1180 this->executeDispatch_DeleteDataLabel();
1181 else if( aCommand == "ResetAllDataPoints" )
1182 this->executeDispatch_ResetAllDataPoints();
1183 else if( aCommand == "ResetDataPoint" )
1184 this->executeDispatch_ResetDataPoint();
1185 else if( aCommand == "InsertAxis" )
1186 this->executeDispatch_InsertAxis();
1187 else if( aCommand == "InsertMajorGrid" )
1188 this->executeDispatch_InsertMajorGrid();
1189 else if( aCommand == "InsertMinorGrid" )
1190 this->executeDispatch_InsertMinorGrid();
1191 else if( aCommand == "InsertAxisTitle" )
1192 this->executeDispatch_InsertAxisTitle();
1193 else if( aCommand == "DeleteAxis" )
1194 this->executeDispatch_DeleteAxis();
1195 else if( aCommand == "DeleteMajorGrid")
1196 this->executeDispatch_DeleteMajorGrid();
1197 else if( aCommand == "DeleteMinorGrid" )
1198 this->executeDispatch_DeleteMinorGrid();
1199 //format objects
1200 else if( aCommand == "FormatSelection" )
1201 this->executeDispatch_ObjectProperties();
1202 else if( aCommand == "TransformDialog" )
1204 if ( isShapeContext() )
1206 this->impl_ShapeControllerDispatch( rURL, rArgs );
1208 else
1210 this->executeDispatch_PositionAndSize();
1213 else if( lcl_isFormatObjectCommand(aCommand) )
1214 this->executeDispatch_FormatObject(rURL.Path);
1215 //more format
1216 else if( aCommand == "DiagramType" )
1217 this->executeDispatch_ChartType();
1218 else if( aCommand == "View3D" )
1219 this->executeDispatch_View3D();
1220 else if ( aCommand == "Forward" )
1222 if ( isShapeContext() )
1224 this->impl_ShapeControllerDispatch( rURL, rArgs );
1226 else
1228 this->executeDispatch_MoveSeries( true );
1231 else if ( aCommand == "Backward" )
1233 if ( isShapeContext() )
1235 this->impl_ShapeControllerDispatch( rURL, rArgs );
1237 else
1239 this->executeDispatch_MoveSeries( false );
1242 else if( aCommand == "NewArrangement")
1243 this->executeDispatch_NewArrangement();
1244 else if( aCommand == "ToggleLegend" )
1245 this->executeDispatch_ToggleLegend();
1246 else if( aCommand == "ToggleGridHorizontal" )
1247 this->executeDispatch_ToggleGridHorizontal();
1248 else if( aCommand == "ToggleGridVertical" )
1249 this->executeDispatch_ToggleGridVertical();
1250 else if( aCommand == "ScaleText" )
1251 this->executeDispatch_ScaleText();
1252 else if( aCommand == "StatusBarVisible" )
1254 // workaround: this should not be necessary.
1255 uno::Reference< beans::XPropertySet > xPropSet( m_xFrame, uno::UNO_QUERY );
1256 if( xPropSet.is() )
1258 uno::Reference< css::frame::XLayoutManager > xLayoutManager;
1259 xPropSet->getPropertyValue( "LayoutManager" ) >>= xLayoutManager;
1260 if ( xLayoutManager.is() )
1262 bool bIsVisible( xLayoutManager->isElementVisible( "private:resource/statusbar/statusbar" ));
1263 if( bIsVisible )
1265 xLayoutManager->hideElement( "private:resource/statusbar/statusbar" );
1266 xLayoutManager->destroyElement( "private:resource/statusbar/statusbar" );
1268 else
1270 xLayoutManager->createElement( "private:resource/statusbar/statusbar" );
1271 xLayoutManager->showElement( "private:resource/statusbar/statusbar" );
1273 // @todo: update menu state (checkmark next to "Statusbar").
1279 void SAL_CALL ChartController::addStatusListener(
1280 const uno::Reference<frame::XStatusListener >& /* xControl */,
1281 const util::URL& /* aURL */ )
1283 //@todo
1286 void SAL_CALL ChartController::removeStatusListener(
1287 const uno::Reference<frame::XStatusListener >& /* xControl */,
1288 const util::URL& /* aURL */ )
1290 //@todo
1293 // XContextMenuInterception (optional interface)
1294 void SAL_CALL ChartController::registerContextMenuInterceptor(
1295 const uno::Reference< ui::XContextMenuInterceptor >& /* xInterceptor */)
1297 //@todo
1300 void SAL_CALL ChartController::releaseContextMenuInterceptor(
1301 const uno::Reference< ui::XContextMenuInterceptor > & /* xInterceptor */)
1303 //@todo
1306 // ____ XEmbeddedClient ____
1307 // implementation see: ChartController_EditData.cxx
1309 void ChartController::executeDispatch_ChartType()
1311 UndoLiveUpdateGuard aUndoGuard(
1312 SchResId( STR_ACTION_EDIT_CHARTTYPE ), m_xUndoManager );
1314 SolarMutexGuard aSolarGuard;
1315 //prepare and open dialog
1316 ScopedVclPtrInstance< ChartTypeDialog > aDlg( GetChartWindow(), getModel() );
1317 if( aDlg->Execute() == RET_OK )
1319 impl_adaptDataSeriesAutoResize();
1320 aUndoGuard.commit();
1324 void ChartController::executeDispatch_SourceData()
1326 //convert properties to ItemSet
1327 uno::Reference< XChartDocument > xChartDoc( getModel(), uno::UNO_QUERY );
1328 OSL_ENSURE( xChartDoc.is(), "Invalid XChartDocument" );
1329 if( !xChartDoc.is() )
1330 return;
1332 // If there is a data table we should ask user if we really want to destroy it
1333 // and switch to data ranges.
1334 ChartModel& rModel = dynamic_cast<ChartModel&>(*xChartDoc.get());
1335 if ( rModel.hasInternalDataProvider() )
1337 // Check if we will able to create data provider later
1338 css::uno::Reference< com::sun::star::chart2::XDataProviderAccess > xCreatorDoc(
1339 rModel.getParent(), uno::UNO_QUERY);
1340 if (!xCreatorDoc.is())
1341 return;
1343 SolarMutexGuard aSolarGuard;
1345 VclPtr<ChartWindow> xChartWindow(GetChartWindow());
1346 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(xChartWindow ? xChartWindow->GetFrameWeld() : nullptr,
1347 VclMessageType::Question, VclButtonsType::YesNo, SchResId(STR_DLG_REMOVE_DATA_TABLE)));
1348 // If "No" then just return
1349 if (xQueryBox->run() == RET_NO)
1350 return;
1352 // Remove data table
1353 rModel.removeDataProviders();
1355 // Ask parent document to create new data provider
1357 uno::Reference< data::XDataProvider > xDataProvider = xCreatorDoc->createDataProvider();
1358 SAL_WARN_IF( !xDataProvider.is(), "chart2.main", "Data provider was not created" );
1359 if (xDataProvider.is())
1361 rModel.attachDataProvider(xDataProvider);
1365 UndoLiveUpdateGuard aUndoGuard(
1366 SchResId(STR_ACTION_EDIT_DATA_RANGES), m_xUndoManager);
1368 SolarMutexGuard aSolarGuard;
1369 ScopedVclPtrInstance< ::chart::DataSourceDialog > aDlg( GetChartWindow(), xChartDoc, m_xCC );
1370 if( aDlg->Execute() == RET_OK )
1372 impl_adaptDataSeriesAutoResize();
1373 aUndoGuard.commit();
1377 void ChartController::executeDispatch_MoveSeries( bool bForward )
1379 ControllerLockGuardUNO aCLGuard( getModel() );
1381 //get selected series
1382 OUString aObjectCID(m_aSelection.getSelectedCID());
1383 uno::Reference< XDataSeries > xGivenDataSeries( ObjectIdentifier::getDataSeriesForCID( //yyy todo also legend entries and labels?
1384 aObjectCID, getModel() ) );
1386 UndoGuardWithSelection aUndoGuard(
1387 ActionDescriptionProvider::createDescription(
1388 (bForward ? ActionDescriptionProvider::ActionType::MoveToTop : ActionDescriptionProvider::ActionType::MoveToBottom),
1389 SchResId(STR_OBJECT_DATASERIES)),
1390 m_xUndoManager );
1392 bool bChanged = DiagramHelper::moveSeries( ChartModelHelper::findDiagram( getModel() ), xGivenDataSeries, bForward );
1393 if( bChanged )
1395 m_aSelection.setSelection( ObjectIdentifier::getMovedSeriesCID( aObjectCID, bForward ) );
1396 aUndoGuard.commit();
1400 // ____ XMultiServiceFactory ____
1401 uno::Reference< uno::XInterface > SAL_CALL
1402 ChartController::createInstance( const OUString& aServiceSpecifier )
1404 uno::Reference< uno::XInterface > xResult;
1406 if( aServiceSpecifier == CHART_ACCESSIBLE_TEXT_SERVICE_NAME )
1407 xResult.set( impl_createAccessibleTextContext());
1408 return xResult;
1411 uno::Reference< uno::XInterface > SAL_CALL
1412 ChartController::createInstanceWithArguments(
1413 const OUString& ServiceSpecifier,
1414 const uno::Sequence< uno::Any >& /* Arguments */ )
1416 // ignore Arguments
1417 return createInstance( ServiceSpecifier );
1420 uno::Sequence< OUString > SAL_CALL
1421 ChartController::getAvailableServiceNames()
1423 uno::Sequence< OUString > aServiceNames { CHART_ACCESSIBLE_TEXT_SERVICE_NAME };
1424 return aServiceNames;
1427 // ____ XModifyListener ____
1428 void SAL_CALL ChartController::modified(
1429 const lang::EventObject& /* aEvent */ )
1431 // the source can also be a subobject of the ChartModel
1432 // @todo: change the source in ChartModel to always be the model itself ?
1433 //todo? update menu states ?
1436 IMPL_LINK( ChartController, NotifyUndoActionHdl, SdrUndoAction*, pUndoAction, void )
1438 ENSURE_OR_RETURN_VOID( pUndoAction, "invalid Undo action" );
1440 OUString aObjectCID = m_aSelection.getSelectedCID();
1441 if ( aObjectCID.isEmpty() )
1445 const Reference< document::XUndoManagerSupplier > xSuppUndo( getModel(), uno::UNO_QUERY_THROW );
1446 const Reference< document::XUndoManager > xUndoManager( xSuppUndo->getUndoManager(), uno::UNO_QUERY_THROW );
1447 const Reference< document::XUndoAction > xAction( new impl::ShapeUndoElement( *pUndoAction ) );
1448 xUndoManager->addUndoAction( xAction );
1450 catch( const uno::Exception& )
1452 DBG_UNHANDLED_EXCEPTION("chart2");
1457 DrawModelWrapper* ChartController::GetDrawModelWrapper()
1459 if( !m_pDrawModelWrapper.get() )
1461 ExplicitValueProvider* pProvider = ExplicitValueProvider::getExplicitValueProvider( m_xChartView );
1462 if( pProvider )
1463 m_pDrawModelWrapper = pProvider->getDrawModelWrapper();
1464 if ( m_pDrawModelWrapper.get() )
1466 m_pDrawModelWrapper->getSdrModel().SetNotifyUndoActionHdl( LINK( this, ChartController, NotifyUndoActionHdl ) );
1469 return m_pDrawModelWrapper.get();
1472 DrawViewWrapper* ChartController::GetDrawViewWrapper()
1474 if ( !m_pDrawViewWrapper )
1476 impl_createDrawViewController();
1478 return m_pDrawViewWrapper;
1482 VclPtr<ChartWindow> ChartController::GetChartWindow()
1484 // clients getting the naked VCL Window from UNO should always have the
1485 // solar mutex (and keep it over the lifetime of this ptr), as VCL might
1486 // might deinit otherwise
1487 DBG_TESTSOLARMUTEX();
1488 if(!m_xViewWindow.is())
1489 return nullptr;
1490 return dynamic_cast<ChartWindow*>(VCLUnoHelper::GetWindow(m_xViewWindow).get());
1493 weld::Window* ChartController::GetChartFrame()
1495 // clients getting the naked VCL Window from UNO should always have the
1496 // solar mutex (and keep it over the lifetime of this ptr), as VCL might
1497 // might deinit otherwise
1498 DBG_TESTSOLARMUTEX();
1499 return Application::GetFrameWeld(m_xViewWindow);
1502 bool ChartController::isAdditionalShapeSelected()
1504 return m_aSelection.isAdditionalShapeSelected();
1507 void ChartController::SetAndApplySelection(const Reference<drawing::XShape>& rxShape)
1509 if(rxShape.is())
1511 m_aSelection.setSelection(rxShape);
1512 m_aSelection.applySelection(GetDrawViewWrapper());
1518 uno::Reference< XAccessible > ChartController::CreateAccessible()
1520 uno::Reference< XAccessible > xResult = new AccessibleChartView( GetDrawViewWrapper() );
1521 impl_initializeAccessible( uno::Reference< lang::XInitialization >( xResult, uno::UNO_QUERY ) );
1522 return xResult;
1525 void ChartController::impl_invalidateAccessible()
1527 SolarMutexGuard aGuard;
1528 auto pChartWindow(GetChartWindow());
1529 if( pChartWindow )
1531 Reference< lang::XInitialization > xInit( pChartWindow->GetAccessible(false), uno::UNO_QUERY );
1532 if(xInit.is())
1534 uno::Sequence< uno::Any > aArguments(3);//empty arguments -> invalid accessible
1535 xInit->initialize(aArguments);
1539 void ChartController::impl_initializeAccessible()
1541 SolarMutexGuard aGuard;
1542 auto pChartWindow(GetChartWindow());
1543 if( pChartWindow )
1544 this->impl_initializeAccessible( Reference< lang::XInitialization >( pChartWindow->GetAccessible(false), uno::UNO_QUERY ) );
1546 void ChartController::impl_initializeAccessible( const uno::Reference< lang::XInitialization >& xInit )
1548 if(xInit.is())
1550 uno::Sequence< uno::Any > aArguments(5);
1551 aArguments[0] <<= uno::Reference<view::XSelectionSupplier>(this);
1552 aArguments[1] <<= getModel();
1553 aArguments[2] <<= m_xChartView;
1554 uno::Reference< XAccessible > xParent;
1556 SolarMutexGuard aGuard;
1557 auto pChartWindow(GetChartWindow());
1558 if( pChartWindow )
1560 vcl::Window* pParentWin( pChartWindow->GetAccessibleParentWindow());
1561 if( pParentWin )
1562 xParent.set( pParentWin->GetAccessible());
1565 aArguments[3] <<= xParent;
1566 aArguments[4] <<= m_xViewWindow;
1568 xInit->initialize(aArguments);
1572 const std::set< OUString >& ChartController::impl_getAvailableCommands()
1574 static std::set< OUString > s_AvailableCommands {
1575 // commands for container forward
1576 "AddDirect", "NewDoc", "Open",
1577 "Save", "SaveAs", "SendMail",
1578 "EditDoc", "ExportDirectToPDF", "PrintDefault",
1580 // own commands
1581 "Cut", "Copy", "Paste",
1582 "DataRanges", "DiagramData",
1583 // insert objects
1584 "InsertMenuTitles", "InsertTitles",
1585 "InsertMenuLegend", "InsertLegend", "DeleteLegend",
1586 "InsertMenuDataLabels",
1587 "InsertMenuAxes", "InsertRemoveAxes", "InsertMenuGrids",
1588 "InsertSymbol",
1589 "InsertTrendlineEquation", "InsertTrendlineEquationAndR2",
1590 "InsertR2Value", "DeleteR2Value",
1591 "InsertMenuTrendlines", "InsertTrendline",
1592 "InsertMenuMeanValues", "InsertMeanValue",
1593 "InsertMenuXErrorBars", "InsertXErrorBars",
1594 "InsertMenuYErrorBars", "InsertYErrorBars",
1595 "InsertDataLabels", "InsertDataLabel",
1596 "DeleteTrendline", "DeleteMeanValue", "DeleteTrendlineEquation",
1597 "DeleteXErrorBars", "DeleteYErrorBars",
1598 "DeleteDataLabels", "DeleteDataLabel",
1599 //format objects
1600 "FormatSelection", "TransformDialog",
1601 "DiagramType", "View3D",
1602 "Forward", "Backward",
1603 "MainTitle", "SubTitle",
1604 "XTitle", "YTitle", "ZTitle",
1605 "SecondaryXTitle", "SecondaryYTitle",
1606 "AllTitles", "Legend",
1607 "DiagramAxisX", "DiagramAxisY", "DiagramAxisZ",
1608 "DiagramAxisA", "DiagramAxisB", "DiagramAxisAll",
1609 "DiagramGridXMain", "DiagramGridYMain", "DiagramGridZMain",
1610 "DiagramGridXHelp", "DiagramGridYHelp", "DiagramGridZHelp",
1611 "DiagramGridAll",
1612 "DiagramWall", "DiagramFloor", "DiagramArea",
1614 //context menu - format objects entries
1615 "FormatWall", "FormatFloor", "FormatChartArea",
1616 "FormatLegend",
1618 "FormatAxis", "FormatTitle",
1619 "FormatDataSeries", "FormatDataPoint",
1620 "ResetAllDataPoints", "ResetDataPoint",
1621 "FormatDataLabels", "FormatDataLabel",
1622 "FormatMeanValue", "FormatTrendline", "FormatTrendlineEquation",
1623 "FormatXErrorBars", "FormatYErrorBars",
1624 "FormatStockLoss", "FormatStockGain",
1626 "FormatMajorGrid", "InsertMajorGrid", "DeleteMajorGrid",
1627 "FormatMinorGrid", "InsertMinorGrid", "DeleteMinorGrid",
1628 "InsertAxis", "DeleteAxis", "InsertAxisTitle",
1630 // toolbar commands
1631 "ToggleGridHorizontal", "ToggleGridVertical", "ToggleLegend", "ScaleText",
1632 "NewArrangement", "Update",
1633 "DefaultColors", "BarWidth", "NumberOfLines",
1634 "ArrangeRow",
1635 "StatusBarVisible",
1636 "ChartElementSelector"};
1637 return s_AvailableCommands;
1640 ViewElementListProvider ChartController::getViewElementListProvider()
1642 return ViewElementListProvider(m_pDrawModelWrapper.get());
1645 } //namespace chart
1647 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1648 com_sun_star_comp_chart2_ChartController_get_implementation(css::uno::XComponentContext *context,
1649 css::uno::Sequence<css::uno::Any> const &)
1651 return cppu::acquire(new chart::ChartController(context));
1654 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */