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