tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / chart2 / source / model / main / ChartModel.cxx
blobbc718c89878d352caaf136f34524f0015fed548f
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 <ChartModel.hxx>
21 #include <ChartTypeManager.hxx>
22 #include <ChartTypeTemplate.hxx>
23 #include <servicenames.hxx>
24 #include <DataSource.hxx>
25 #include <DataSourceHelper.hxx>
26 #include <ChartModelHelper.hxx>
27 #include <DisposeHelper.hxx>
28 #include <ControllerLockGuard.hxx>
29 #include <InternalDataProvider.hxx>
30 #include <ObjectIdentifier.hxx>
31 #include "PageBackground.hxx"
32 #include <CloneHelper.hxx>
33 #include <NameContainer.hxx>
34 #include "UndoManager.hxx"
35 #include <ChartView.hxx>
36 #include <PopupRequest.hxx>
37 #include <ModifyListenerHelper.hxx>
38 #include <RangeHighlighter.hxx>
39 #include <Diagram.hxx>
40 #include <comphelper/dumpxmltostring.hxx>
42 #include <com/sun/star/chart/ChartDataRowSource.hpp>
43 #include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
45 #include <comphelper/processfactory.hxx>
46 #include <comphelper/propertysequence.hxx>
47 #include <cppuhelper/supportsservice.hxx>
49 #include <svl/numformat.hxx>
50 #include <svl/numuno.hxx>
51 #include <com/sun/star/lang/DisposedException.hpp>
52 #include <com/sun/star/view/XSelectionSupplier.hpp>
53 #include <com/sun/star/embed/EmbedMapUnits.hpp>
54 #include <com/sun/star/embed/Aspects.hpp>
55 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
56 #include <com/sun/star/datatransfer/XTransferable.hpp>
57 #include <com/sun/star/drawing/XShapes.hpp>
58 #include <com/sun/star/document/DocumentProperties.hpp>
59 #include <com/sun/star/util/CloseVetoException.hpp>
60 #include <com/sun/star/util/XModifyBroadcaster.hpp>
62 #include <sal/log.hxx>
63 #include <utility>
64 #include <comphelper/diagnose_ex.hxx>
65 #include <libxml/xmlwriter.h>
67 using ::com::sun::star::uno::Sequence;
68 using ::com::sun::star::uno::Reference;
69 using ::com::sun::star::uno::Any;
70 using ::osl::MutexGuard;
72 using namespace ::com::sun::star;
73 using namespace ::apphelper;
75 namespace
77 constexpr OUString lcl_aGDIMetaFileMIMEType(
78 u"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\""_ustr);
79 constexpr OUString lcl_aGDIMetaFileMIMETypeHighContrast(
80 u"application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\""_ustr);
82 } // anonymous namespace
84 // ChartModel Constructor and Destructor
86 namespace chart
89 ChartModel::ChartModel(uno::Reference<uno::XComponentContext > xContext)
90 : m_aLifeTimeManager( this, this )
91 , m_bReadOnly( false )
92 , m_bModified( false )
93 , m_nInLoad(0)
94 , m_bUpdateNotificationsPending(false)
95 , mbTimeBased(false)
96 , m_aControllers( m_aModelMutex )
97 , m_nControllerLockCount(0)
98 , m_xContext(std::move( xContext ))
99 , m_aVisualAreaSize( ChartModelHelper::getDefaultPageSize() )
100 , m_xPageBackground( new PageBackground )
101 , m_xXMLNamespaceMap( new NameContainer() )
102 , mnStart(0)
103 , mnEnd(0)
105 osl_atomic_increment(&m_refCount);
107 m_xOldModelAgg.set(
108 m_xContext->getServiceManager()->createInstanceWithContext(
109 CHART_CHARTAPIWRAPPER_SERVICE_NAME,
110 m_xContext ), uno::UNO_QUERY_THROW );
111 m_xOldModelAgg->setDelegator( *this );
115 m_xPageBackground->addModifyListener( this );
116 m_xChartTypeManager = new ::chart::ChartTypeManager( m_xContext );
118 osl_atomic_decrement(&m_refCount);
121 ChartModel::ChartModel( const ChartModel & rOther )
122 : impl::ChartModel_Base(rOther)
123 , m_aLifeTimeManager( this, this )
124 , m_bReadOnly( rOther.m_bReadOnly )
125 , m_bModified( rOther.m_bModified )
126 , m_nInLoad(0)
127 , m_bUpdateNotificationsPending(false)
128 , mbTimeBased(rOther.mbTimeBased)
129 , m_aResource( rOther.m_aResource )
130 , m_aMediaDescriptor( rOther.m_aMediaDescriptor )
131 , m_aControllers( m_aModelMutex )
132 , m_nControllerLockCount(0)
133 , m_xContext( rOther.m_xContext )
134 // @note: the old model aggregate must not be shared with other models if it
135 // is, you get mutex deadlocks
136 //, m_xOldModelAgg( nullptr ) //rOther.m_xOldModelAgg )
137 // m_xStorage( nullptr ) //rOther.m_xStorage )
138 , m_aVisualAreaSize( rOther.m_aVisualAreaSize )
139 , m_aGraphicObjectVector( rOther.m_aGraphicObjectVector )
140 , m_xDataProvider( rOther.m_xDataProvider )
141 , m_xInternalDataProvider( rOther.m_xInternalDataProvider )
142 , mnStart(rOther.mnStart)
143 , mnEnd(rOther.mnEnd)
145 osl_atomic_increment(&m_refCount);
147 m_xOldModelAgg.set(
148 m_xContext->getServiceManager()->createInstanceWithContext(
149 CHART_CHARTAPIWRAPPER_SERVICE_NAME,
150 m_xContext ), uno::UNO_QUERY_THROW );
151 m_xOldModelAgg->setDelegator( *this );
153 Reference< util::XModifyListener > xListener;
154 rtl::Reference< Title > xNewTitle;
155 if ( rOther.m_xTitle )
156 xNewTitle = new Title(*rOther.m_xTitle);
157 rtl::Reference< ::chart::Diagram > xNewDiagram;
158 if (rOther.m_xDiagram.is())
159 xNewDiagram = new ::chart::Diagram( *rOther.m_xDiagram );
160 rtl::Reference< ::chart::PageBackground > xNewPageBackground = new PageBackground( *rOther.m_xPageBackground );
163 rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager; // does not implement XCloneable
164 rtl::Reference< ::chart::NameContainer > xXMLNamespaceMap = new NameContainer( *rOther.m_xXMLNamespaceMap );
167 MutexGuard aGuard( m_aModelMutex );
168 xListener = this;
169 m_xTitle = xNewTitle;
170 m_xDiagram = xNewDiagram;
171 m_xPageBackground = xNewPageBackground;
172 m_xChartTypeManager = std::move(xChartTypeManager);
173 m_xXMLNamespaceMap = std::move(xXMLNamespaceMap);
177 ModifyListenerHelper::addListener( xNewTitle, xListener );
178 if( xNewDiagram && xListener)
179 xNewDiagram->addModifyListener( xListener );
180 if( xNewPageBackground && xListener)
181 xNewPageBackground->addModifyListener( xListener );
182 xListener.clear();
184 osl_atomic_decrement(&m_refCount);
187 ChartModel::~ChartModel()
189 if( m_xOldModelAgg.is())
190 m_xOldModelAgg->setDelegator( nullptr );
193 void SAL_CALL ChartModel::initialize( const Sequence< Any >& /*rArguments*/ )
195 //#i113722# avoid duplicate creation
197 //maybe additional todo?:
198 //support argument "EmbeddedObject"?
199 //support argument "EmbeddedScriptSupport"?
200 //support argument "DocumentRecoverySupport"?
203 ChartView* ChartModel::getChartView() const
205 return mxChartView.get();
208 // private methods
210 OUString ChartModel::impl_g_getLocation()
213 LifeTimeGuard aGuard(m_aLifeTimeManager);
214 if(!aGuard.startApiCall())
215 return OUString(); //behave passive if already disposed or closed or throw exception @todo?
216 //mutex is acquired
217 return m_aResource;
220 bool ChartModel::impl_isControllerConnected( const uno::Reference< frame::XController >& xController )
224 std::vector< uno::Reference<uno::XInterface> > aSeq = m_aControllers.getElements();
225 for( const auto & r : aSeq )
227 if( r == xController )
228 return true;
231 catch (const uno::Exception&)
234 return false;
237 uno::Reference< frame::XController > ChartModel::impl_getCurrentController()
239 //@todo? hold only weak references to controllers
241 // get the last active controller of this model
242 if( m_xCurrentController.is() )
243 return m_xCurrentController;
245 // get the first controller of this model
246 if( m_aControllers.getLength() )
248 uno::Reference<uno::XInterface> xI = m_aControllers.getInterface(0);
249 return uno::Reference<frame::XController>( xI, uno::UNO_QUERY );
252 //return nothing if no controllers are connected at all
253 return uno::Reference< frame::XController > ();
256 void ChartModel::impl_notifyCloseListeners()
258 std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
259 if( m_aLifeTimeManager.m_aCloseListeners.getLength(aGuard) )
261 lang::EventObject aEvent( static_cast< lang::XComponent*>(this) );
262 m_aLifeTimeManager.m_aCloseListeners.notifyEach(aGuard, &util::XCloseListener::notifyClosing, aEvent);
266 void ChartModel::impl_adjustAdditionalShapesPositionAndSize( const awt::Size& aVisualAreaSize )
268 uno::Reference< beans::XPropertySet > xProperties( static_cast< ::cppu::OWeakObject* >( this ), uno::UNO_QUERY );
269 if ( !xProperties.is() )
270 return;
272 uno::Reference< drawing::XShapes > xShapes;
273 xProperties->getPropertyValue( u"AdditionalShapes"_ustr ) >>= xShapes;
274 if ( !xShapes.is() )
275 return;
277 sal_Int32 nCount = xShapes->getCount();
278 for ( sal_Int32 i = 0; i < nCount; ++i )
280 Reference< drawing::XShape > xShape;
281 if ( xShapes->getByIndex( i ) >>= xShape )
283 if ( xShape.is() )
285 awt::Point aPos( xShape->getPosition() );
286 awt::Size aSize( xShape->getSize() );
288 double fWidth = static_cast< double >( aVisualAreaSize.Width ) / m_aVisualAreaSize.Width;
289 double fHeight = static_cast< double >( aVisualAreaSize.Height ) / m_aVisualAreaSize.Height;
291 aPos.X = static_cast< tools::Long >( aPos.X * fWidth );
292 aPos.Y = static_cast< tools::Long >( aPos.Y * fHeight );
293 aSize.Width = static_cast< tools::Long >( aSize.Width * fWidth );
294 aSize.Height = static_cast< tools::Long >( aSize.Height * fHeight );
296 xShape->setPosition( aPos );
297 xShape->setSize( aSize );
303 // lang::XServiceInfo
305 OUString SAL_CALL ChartModel::getImplementationName()
307 return CHART_MODEL_SERVICE_IMPLEMENTATION_NAME;
310 sal_Bool SAL_CALL ChartModel::supportsService( const OUString& rServiceName )
312 return cppu::supportsService(this, rServiceName);
315 css::uno::Sequence< OUString > SAL_CALL ChartModel::getSupportedServiceNames()
317 return {
318 CHART_MODEL_SERVICE_NAME,
319 u"com.sun.star.document.OfficeDocument"_ustr,
320 u"com.sun.star.chart.ChartDocument"_ustr
324 // frame::XModel (required interface)
326 sal_Bool SAL_CALL ChartModel::attachResource( const OUString& rURL
327 , const uno::Sequence< beans::PropertyValue >& rMediaDescriptor )
330 The method attachResource() is used by the frame loader implementations
331 to inform the model about its URL and MediaDescriptor.
334 LifeTimeGuard aGuard(m_aLifeTimeManager);
335 if(!aGuard.startApiCall())
336 return false; //behave passive if already disposed or closed or throw exception @todo?
337 //mutex is acquired
339 if(!m_aResource.isEmpty())//we have a resource already //@todo? or is setting a new resource allowed?
340 return false;
341 m_aResource = rURL;
342 m_aMediaDescriptor = rMediaDescriptor;
344 //@todo ? check rURL ??
345 //@todo ? evaluate m_aMediaDescriptor;
346 //@todo ? ... ??? --> nothing, this method is only for setting information
348 return true;
351 OUString SAL_CALL ChartModel::getURL()
353 return impl_g_getLocation();
356 uno::Sequence< beans::PropertyValue > SAL_CALL ChartModel::getArgs()
359 The method getArgs() returns a sequence of property values
360 that report the resource description according to com.sun.star.document.MediaDescriptor,
361 specified on loading or saving with storeAsURL.
364 LifeTimeGuard aGuard(m_aLifeTimeManager);
365 if(!aGuard.startApiCall())
366 return uno::Sequence< beans::PropertyValue >(); //behave passive if already disposed or closed or throw exception @todo?
367 //mutex is acquired
369 return m_aMediaDescriptor;
372 void SAL_CALL ChartModel::connectController( const uno::Reference< frame::XController >& xController )
374 //@todo? this method is declared as oneway -> ...?
376 LifeTimeGuard aGuard(m_aLifeTimeManager);
377 if(!aGuard.startApiCall())
378 return ; //behave passive if already disposed or closed
379 //mutex is acquired
381 //--add controller
382 m_aControllers.addInterface(xController);
385 void SAL_CALL ChartModel::disconnectController( const uno::Reference< frame::XController >& xController )
387 //@todo? this method is declared as oneway -> ...?
389 LifeTimeGuard aGuard(m_aLifeTimeManager);
390 if(!aGuard.startApiCall())
391 return; //behave passive if already disposed or closed
393 //--remove controller
394 m_aControllers.removeInterface(xController);
396 //case: current controller is disconnected:
397 if( m_xCurrentController == xController )
398 m_xCurrentController.clear();
400 if (m_xRangeHighlighter)
402 m_xRangeHighlighter->dispose();
403 m_xRangeHighlighter.clear();
405 DisposeHelper::DisposeAndClear(m_xPopupRequest);
408 void SAL_CALL ChartModel::lockControllers()
411 suspends some notifications to the controllers which are used for display updates.
413 The calls to lockControllers() and unlockControllers() may be nested
414 and even overlapping, but they must be in pairs. While there is at least one lock
415 remaining, some notifications for display updates are not broadcasted.
418 //@todo? this method is declared as oneway -> ...?
420 LifeTimeGuard aGuard(m_aLifeTimeManager);
421 if(!aGuard.startApiCall())
422 return; //behave passive if already disposed or closed or throw exception @todo?
423 ++m_nControllerLockCount;
426 void SAL_CALL ChartModel::unlockControllers()
429 resumes the notifications which were suspended by lockControllers() .
431 The calls to lockControllers() and unlockControllers() may be nested
432 and even overlapping, but they must be in pairs. While there is at least one lock
433 remaining, some notifications for display updates are not broadcasted.
436 //@todo? this method is declared as oneway -> ...?
438 LifeTimeGuard aGuard(m_aLifeTimeManager);
439 if(!aGuard.startApiCall())
440 return; //behave passive if already disposed or closed or throw exception @todo?
441 if( m_nControllerLockCount == 0 )
443 SAL_WARN("chart2", "ChartModel: unlockControllers called with m_nControllerLockCount == 0" );
444 return;
446 --m_nControllerLockCount;
447 if( m_nControllerLockCount == 0 && m_bUpdateNotificationsPending )
449 aGuard.clear();
450 impl_notifyModifiedListeners();
454 sal_Bool SAL_CALL ChartModel::hasControllersLocked()
456 LifeTimeGuard aGuard(m_aLifeTimeManager);
457 if(!aGuard.startApiCall())
458 return false; //behave passive if already disposed or closed or throw exception @todo?
459 return ( m_nControllerLockCount != 0 ) ;
462 uno::Reference< frame::XController > SAL_CALL ChartModel::getCurrentController()
464 LifeTimeGuard aGuard(m_aLifeTimeManager);
465 if(!aGuard.startApiCall())
466 throw lang::DisposedException(
467 u"getCurrentController was called on an already disposed or closed model"_ustr,
468 static_cast< ::cppu::OWeakObject* >(this) );
470 return impl_getCurrentController();
473 void SAL_CALL ChartModel::setCurrentController( const uno::Reference< frame::XController >& xController )
475 LifeTimeGuard aGuard(m_aLifeTimeManager);
476 if(!aGuard.startApiCall())
477 throw lang::DisposedException(
478 u"setCurrentController was called on an already disposed or closed model"_ustr,
479 static_cast< ::cppu::OWeakObject* >(this) );
481 //OSL_ENSURE( impl_isControllerConnected(xController), "setCurrentController is called with a Controller which is not connected" );
482 if(!impl_isControllerConnected(xController))
483 throw container::NoSuchElementException(
484 u"setCurrentController is called with a Controller which is not connected"_ustr,
485 static_cast< ::cppu::OWeakObject* >(this) );
487 m_xCurrentController = xController;
489 if (m_xRangeHighlighter)
491 m_xRangeHighlighter->dispose();
492 m_xRangeHighlighter.clear();
494 DisposeHelper::DisposeAndClear(m_xPopupRequest);
497 uno::Reference< uno::XInterface > SAL_CALL ChartModel::getCurrentSelection()
499 LifeTimeGuard aGuard(m_aLifeTimeManager);
500 if(!aGuard.startApiCall())
501 throw lang::DisposedException(
502 u"getCurrentSelection was called on an already disposed or closed model"_ustr,
503 static_cast< ::cppu::OWeakObject* >(this) );
505 uno::Reference< uno::XInterface > xReturn;
506 uno::Reference< frame::XController > xController = impl_getCurrentController();
508 aGuard.clear();
509 if( xController.is() )
511 uno::Reference< view::XSelectionSupplier > xSelectionSupl( xController, uno::UNO_QUERY );
512 if ( xSelectionSupl.is() )
514 uno::Any aSel = xSelectionSupl->getSelection();
515 OUString aObjectCID;
516 if( aSel >>= aObjectCID )
517 xReturn.set( ObjectIdentifier::getObjectPropertySet( aObjectCID, this));
520 return xReturn;
523 // lang::XComponent (base of XModel)
524 void SAL_CALL ChartModel::dispose()
526 Reference< XInterface > xKeepAlive( *this );
528 //This object should release all resources and references in the
529 //easiest possible manner
530 //This object must notify all registered listeners using the method
531 //<member>XEventListener::disposing</member>
533 //hold no mutex
534 if( !m_aLifeTimeManager.dispose() )
535 return;
537 //--release all resources and references
538 //// @todo
540 if ( m_xDiagram.is() )
541 m_xDiagram->removeModifyListener( this );
543 if ( m_xDataProvider.is() )
545 Reference<util::XModifyBroadcaster> xModifyBroadcaster( m_xDataProvider, uno::UNO_QUERY );
546 if ( xModifyBroadcaster.is() )
547 xModifyBroadcaster->removeModifyListener( this );
550 m_xDataProvider.clear();
551 m_xInternalDataProvider.clear();
552 m_xNumberFormatsSupplier.clear();
553 m_xOwnNumberFormatsSupplier.clear();
554 m_xChartTypeManager.clear();
555 m_xDiagram.clear();
556 m_xTitle.clear();
557 m_xPageBackground.clear();
558 m_xXMLNamespaceMap.clear();
560 m_xStorage.clear();
561 // just clear, don't dispose - we're not the owner
563 if ( m_pUndoManager.is() )
564 m_pUndoManager->disposing();
565 m_pUndoManager.clear();
566 // that's important, since the UndoManager implementation delegates its ref counting to ourself.
568 if( m_xOldModelAgg.is()) // #i120828#, to release cyclic reference to ChartModel object
569 m_xOldModelAgg->setDelegator( nullptr );
571 m_aControllers.disposeAndClear( lang::EventObject( static_cast< cppu::OWeakObject * >( this )));
572 m_xCurrentController.clear();
574 if (m_xRangeHighlighter)
576 m_xRangeHighlighter->dispose();
577 m_xRangeHighlighter.clear();
579 DisposeHelper::DisposeAndClear(m_xPopupRequest);
581 if( m_xOldModelAgg.is())
582 m_xOldModelAgg->setDelegator( nullptr );
585 void SAL_CALL ChartModel::addEventListener( const uno::Reference< lang::XEventListener > & xListener )
587 if( m_aLifeTimeManager.impl_isDisposedOrClosed() )
588 return; //behave passive if already disposed or closed
590 std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
591 m_aLifeTimeManager.m_aEventListeners.addInterface( aGuard, xListener );
594 void SAL_CALL ChartModel::removeEventListener( const uno::Reference< lang::XEventListener > & xListener )
596 if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) )
597 return; //behave passive if already disposed or closed
599 std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
600 m_aLifeTimeManager.m_aEventListeners.removeInterface( aGuard, xListener );
603 // util::XCloseBroadcaster (base of XCloseable)
604 void SAL_CALL ChartModel::addCloseListener( const uno::Reference< util::XCloseListener > & xListener )
606 m_aLifeTimeManager.g_addCloseListener( xListener );
609 void SAL_CALL ChartModel::removeCloseListener( const uno::Reference< util::XCloseListener > & xListener )
611 if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) )
612 return; //behave passive if already disposed or closed
614 std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
615 m_aLifeTimeManager.m_aCloseListeners.removeInterface( aGuard, xListener );
618 // util::XCloseable
619 void SAL_CALL ChartModel::close( sal_Bool bDeliverOwnership )
621 //hold no mutex
623 if( !m_aLifeTimeManager.g_close_startTryClose( bDeliverOwnership ) )
624 return;
625 //no mutex is acquired
627 // At the end of this method may we must dispose ourself ...
628 // and may nobody from outside hold a reference to us ...
629 // then it's a good idea to do that by ourself.
630 uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) );
632 //the listeners have had no veto
633 //check whether we self can close
635 util::CloseVetoException aVetoException(
636 u"the model itself could not be closed"_ustr,
637 static_cast< ::cppu::OWeakObject* >(this) );
639 m_aLifeTimeManager.g_close_isNeedToCancelLongLastingCalls( bDeliverOwnership, aVetoException );
641 m_aLifeTimeManager.g_close_endTryClose_doClose();
643 // BM @todo: is it ok to call the listeners here?
644 impl_notifyCloseListeners();
647 // lang::XTypeProvider
648 uno::Sequence< uno::Type > SAL_CALL ChartModel::getTypes()
650 uno::Reference< lang::XTypeProvider > xAggTypeProvider;
651 if( (m_xOldModelAgg->queryAggregation( cppu::UnoType<decltype(xAggTypeProvider)>::get()) >>= xAggTypeProvider)
652 && xAggTypeProvider.is())
654 return comphelper::concatSequences(
655 impl::ChartModel_Base::getTypes(),
656 xAggTypeProvider->getTypes());
659 return impl::ChartModel_Base::getTypes();
662 // document::XDocumentPropertiesSupplier
663 uno::Reference< document::XDocumentProperties > SAL_CALL
664 ChartModel::getDocumentProperties()
666 ::osl::MutexGuard aGuard( m_aModelMutex );
667 if ( !m_xDocumentProperties.is() )
669 m_xDocumentProperties.set( document::DocumentProperties::create( ::comphelper::getProcessComponentContext() ) );
671 return m_xDocumentProperties;
674 // document::XDocumentPropertiesSupplier
675 Reference< document::XUndoManager > SAL_CALL ChartModel::getUndoManager( )
677 ::osl::MutexGuard aGuard( m_aModelMutex );
678 if ( !m_pUndoManager.is() )
679 m_pUndoManager.set( new UndoManager( *this, m_aModelMutex ) );
680 return m_pUndoManager;
683 // chart2::XChartDocument
685 uno::Reference< chart2::XDiagram > SAL_CALL ChartModel::getFirstDiagram()
687 MutexGuard aGuard( m_aModelMutex );
688 return m_xDiagram;
691 void SAL_CALL ChartModel::setFirstDiagram( const uno::Reference< chart2::XDiagram >& xDiagram )
693 rtl::Reference< ::chart::Diagram > xOldDiagram;
694 Reference< util::XModifyListener > xListener;
696 MutexGuard aGuard( m_aModelMutex );
697 if( xDiagram.get() == m_xDiagram.get() )
698 return;
699 xOldDiagram = m_xDiagram;
700 assert(!xDiagram || dynamic_cast<::chart::Diagram*>(xDiagram.get()));
701 m_xDiagram = dynamic_cast<::chart::Diagram*>(xDiagram.get());
702 xListener = this;
704 //don't keep the mutex locked while calling out
705 if( xOldDiagram && xListener )
706 xOldDiagram->removeModifyListener( xListener );
707 ModifyListenerHelper::addListener( xDiagram, xListener );
708 setModified( true );
711 Reference< chart2::data::XDataSource > ChartModel::impl_createDefaultData()
713 Reference< chart2::data::XDataSource > xDataSource;
714 if( hasInternalDataProvider() )
716 //init internal dataprovider
718 beans::NamedValue aParam( u"CreateDefaultData"_ustr ,uno::Any(true) );
719 uno::Sequence< uno::Any > aArgs{ uno::Any(aParam) };
720 m_xInternalDataProvider->initialize(aArgs);
722 //create data
723 uno::Sequence<beans::PropertyValue> aArgs( comphelper::InitPropertySequence({
724 { "CellRangeRepresentation", uno::Any( u"all"_ustr ) },
725 { "HasCategories", uno::Any( true ) },
726 { "FirstCellAsLabel", uno::Any( true ) },
727 { "DataRowSource", uno::Any( css::chart::ChartDataRowSource_COLUMNS ) }
728 }));
729 xDataSource = m_xInternalDataProvider->createDataSource( aArgs );
731 return xDataSource;
734 void SAL_CALL ChartModel::createInternalDataProvider( sal_Bool bCloneExistingData )
736 // don't lock the mutex, because this call calls out to code that tries to
737 // lock the solar mutex. On the other hand, a paint locks the solar mutex
738 // and calls to the model lock the model's mutex => deadlock
739 // @todo: lock a separate mutex in the InternalData class
740 if( !hasInternalDataProvider() )
742 if( bCloneExistingData )
743 m_xInternalDataProvider = ChartModelHelper::createInternalDataProvider( this, true );
744 else
746 m_xInternalDataProvider = ChartModelHelper::createInternalDataProvider( nullptr, true );
747 m_xInternalDataProvider->setChartModel(this);
749 m_xDataProvider.set( m_xInternalDataProvider );
751 setModified( true );
754 void ChartModel::removeDataProviders()
756 if (m_xInternalDataProvider.is())
757 m_xInternalDataProvider.clear();
758 if (m_xDataProvider.is())
759 m_xDataProvider.clear();
762 void ChartModel::dumpAsXml(xmlTextWriterPtr pWriter) const
764 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ChartModel"));
765 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
767 if (mxChartView.is())
769 mxChartView->dumpAsXml(pWriter);
772 (void)xmlTextWriterEndElement(pWriter);
775 sal_Bool SAL_CALL ChartModel::hasInternalDataProvider()
777 return m_xDataProvider.is() && m_xInternalDataProvider.is();
780 uno::Reference< chart2::data::XDataProvider > SAL_CALL ChartModel::getDataProvider()
782 MutexGuard aGuard( m_aModelMutex );
783 return m_xDataProvider;
786 // ____ XDataReceiver ____
788 void SAL_CALL ChartModel::attachDataProvider( const uno::Reference< chart2::data::XDataProvider >& xDataProvider )
791 MutexGuard aGuard( m_aModelMutex );
792 uno::Reference< beans::XPropertySet > xProp( xDataProvider, uno::UNO_QUERY );
793 if( xProp.is() )
797 bool bIncludeHiddenCells = ChartModelHelper::isIncludeHiddenCells( this );
798 xProp->setPropertyValue(u"IncludeHiddenCells"_ustr, uno::Any(bIncludeHiddenCells));
800 catch (const beans::UnknownPropertyException&)
805 uno::Reference<util::XModifyBroadcaster> xModifyBroadcaster(xDataProvider, uno::UNO_QUERY);
806 if (xModifyBroadcaster.is())
808 xModifyBroadcaster->addModifyListener(this);
811 m_xDataProvider.set( xDataProvider );
812 m_xInternalDataProvider.clear();
814 //the numberformatter is kept independent of the data provider!
816 setModified( true );
819 void SAL_CALL ChartModel::attachNumberFormatsSupplier( const uno::Reference< util::XNumberFormatsSupplier >& xNewSupplier )
822 MutexGuard aGuard( m_aModelMutex );
823 if( xNewSupplier == m_xNumberFormatsSupplier )
824 return;
825 if( xNewSupplier == uno::Reference<XNumberFormatsSupplier>(m_xOwnNumberFormatsSupplier) )
826 return;
827 if( m_xOwnNumberFormatsSupplier.is() && xNewSupplier.is() )
829 //@todo
830 //merge missing numberformats from own to new formatter
832 else if( !xNewSupplier.is() )
834 if( m_xNumberFormatsSupplier.is() )
836 //@todo
837 //merge missing numberformats from old numberformatter to own numberformatter
838 //create own numberformatter if necessary
842 m_xNumberFormatsSupplier.set( xNewSupplier );
843 m_xOwnNumberFormatsSupplier.clear();
845 setModified( true );
848 void SAL_CALL ChartModel::setArguments( const Sequence< beans::PropertyValue >& aArguments )
851 MutexGuard aGuard( m_aModelMutex );
852 if( !m_xDataProvider.is() )
853 return;
854 lockControllers();
858 Reference< chart2::data::XDataSource > xDataSource( m_xDataProvider->createDataSource( aArguments ) );
859 if( xDataSource.is() )
861 rtl::Reference< Diagram > xDia = getFirstChartDiagram();
862 if( !xDia.is() )
864 rtl::Reference< ::chart::ChartTypeTemplate > xTemplate( impl_createDefaultChartTypeTemplate() );
865 if( xTemplate.is())
866 setFirstDiagram( xTemplate->createDiagramByDataSource( xDataSource, aArguments ) );
868 else
869 xDia->setDiagramData( xDataSource, aArguments );
872 catch (const lang::IllegalArgumentException&)
874 throw;
876 catch (const uno::Exception&)
878 DBG_UNHANDLED_EXCEPTION("chart2");
880 unlockControllers();
882 setModified( true );
885 Sequence< OUString > SAL_CALL ChartModel::getUsedRangeRepresentations()
887 return DataSourceHelper::getUsedDataRanges( this );
890 Reference< chart2::data::XDataSource > SAL_CALL ChartModel::getUsedData()
892 return DataSourceHelper::getUsedData( *this );
895 Reference< chart2::data::XRangeHighlighter > SAL_CALL ChartModel::getRangeHighlighter()
897 if( ! m_xRangeHighlighter.is())
898 m_xRangeHighlighter = new RangeHighlighter( this );
899 return m_xRangeHighlighter;
902 Reference<awt::XRequestCallback> SAL_CALL ChartModel::getPopupRequest()
904 if (!m_xPopupRequest.is())
905 m_xPopupRequest.set(new PopupRequest);
906 return m_xPopupRequest;
909 rtl::Reference< ::chart::ChartTypeTemplate > ChartModel::impl_createDefaultChartTypeTemplate()
911 rtl::Reference< ::chart::ChartTypeTemplate > xTemplate;
912 if( m_xChartTypeManager.is() )
913 xTemplate = m_xChartTypeManager->createTemplate( u"com.sun.star.chart2.template.Column"_ustr );
914 return xTemplate;
917 void SAL_CALL ChartModel::setChartTypeManager( const uno::Reference< chart2::XChartTypeManager >& xNewManager )
920 MutexGuard aGuard( m_aModelMutex );
921 m_xChartTypeManager = dynamic_cast<::chart::ChartTypeManager*>(xNewManager.get());
922 assert(!xNewManager || m_xChartTypeManager);
924 setModified( true );
927 uno::Reference< chart2::XChartTypeManager > SAL_CALL ChartModel::getChartTypeManager()
929 MutexGuard aGuard( m_aModelMutex );
930 return m_xChartTypeManager;
933 uno::Reference< beans::XPropertySet > SAL_CALL ChartModel::getPageBackground()
935 MutexGuard aGuard( m_aModelMutex );
936 return m_xPageBackground;
939 void SAL_CALL ChartModel::createDefaultChart()
941 insertDefaultChart();
944 // ____ XTitled ____
945 uno::Reference< chart2::XTitle > SAL_CALL ChartModel::getTitleObject()
947 MutexGuard aGuard( m_aModelMutex );
948 return m_xTitle;
951 rtl::Reference< Title > ChartModel::getTitleObject2() const
953 MutexGuard aGuard( m_aModelMutex );
954 return m_xTitle;
957 void SAL_CALL ChartModel::setTitleObject( const uno::Reference< chart2::XTitle >& xNewTitle )
959 rtl::Reference<Title> xTitle = dynamic_cast<Title*>(xNewTitle.get());
960 assert(!xNewTitle || xTitle);
961 setTitleObject(xTitle);
964 void ChartModel::setTitleObject( const rtl::Reference< Title >& xTitle )
967 MutexGuard aGuard( m_aModelMutex );
968 if( m_xTitle.is() )
969 ModifyListenerHelper::removeListener( m_xTitle, this );
970 m_xTitle = xTitle;
971 ModifyListenerHelper::addListener( m_xTitle, this );
973 setModified( true );
976 // ____ XInterface (for old API wrapper) ____
977 uno::Any SAL_CALL ChartModel::queryInterface( const uno::Type& aType )
979 uno::Any aResult( impl::ChartModel_Base::queryInterface( aType ));
981 if( ! aResult.hasValue())
983 // try old API wrapper
986 if( m_xOldModelAgg.is())
987 aResult = m_xOldModelAgg->queryAggregation( aType );
989 catch (const uno::Exception&)
991 DBG_UNHANDLED_EXCEPTION("chart2");
995 return aResult;
998 // ____ XCloneable ____
999 Reference< util::XCloneable > SAL_CALL ChartModel::createClone()
1001 std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
1002 return Reference< util::XCloneable >( new ChartModel( *this ));
1005 // ____ XVisualObject ____
1006 void SAL_CALL ChartModel::setVisualAreaSize( ::sal_Int64 nAspect, const awt::Size& aSize )
1008 if( nAspect == embed::Aspects::MSOLE_CONTENT )
1010 ControllerLockGuard aLockGuard( *this );
1011 bool bChanged =
1012 (m_aVisualAreaSize.Width != aSize.Width ||
1013 m_aVisualAreaSize.Height != aSize.Height);
1015 // #i12587# support for shapes in chart
1016 if ( bChanged )
1018 impl_adjustAdditionalShapesPositionAndSize( aSize );
1021 m_aVisualAreaSize = aSize;
1022 if( bChanged )
1023 setModified( true );
1025 else
1027 OSL_FAIL( "setVisualAreaSize: Aspect not implemented yet.");
1031 awt::Size SAL_CALL ChartModel::getVisualAreaSize( ::sal_Int64 nAspect )
1033 OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT,
1034 "No aspects other than content are supported" );
1035 // other possible aspects are MSOLE_THUMBNAIL, MSOLE_ICON and MSOLE_DOCPRINT
1037 return m_aVisualAreaSize;
1040 embed::VisualRepresentation SAL_CALL ChartModel::getPreferredVisualRepresentation( ::sal_Int64 nAspect )
1042 OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT,
1043 "No aspects other than content are supported" );
1045 embed::VisualRepresentation aResult;
1049 Sequence< sal_Int8 > aMetafile;
1051 //get view from old api wrapper
1052 Reference< datatransfer::XTransferable > xTransferable(
1053 createInstance( CHART_VIEW_SERVICE_NAME ), uno::UNO_QUERY );
1054 if( xTransferable.is() )
1056 datatransfer::DataFlavor aDataFlavor( lcl_aGDIMetaFileMIMEType,
1057 u"GDIMetaFile"_ustr,
1058 cppu::UnoType<uno::Sequence< sal_Int8 >>::get() );
1060 uno::Any aData( xTransferable->getTransferData( aDataFlavor ) );
1061 aData >>= aMetafile;
1064 aResult.Flavor.MimeType = lcl_aGDIMetaFileMIMEType;
1065 aResult.Flavor.DataType = cppu::UnoType<decltype(aMetafile)>::get();
1067 aResult.Data <<= aMetafile;
1069 catch (const uno::Exception&)
1071 DBG_UNHANDLED_EXCEPTION("chart2");
1074 return aResult;
1077 ::sal_Int32 SAL_CALL ChartModel::getMapUnit( ::sal_Int64 nAspect )
1079 OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT,
1080 "No aspects other than content are supported" );
1081 return embed::EmbedMapUnits::ONE_100TH_MM;
1084 // ____ datatransfer::XTransferable ____
1085 uno::Any SAL_CALL ChartModel::getTransferData( const datatransfer::DataFlavor& aFlavor )
1087 uno::Any aResult;
1088 if( !isDataFlavorSupported( aFlavor ) )
1089 throw datatransfer::UnsupportedFlavorException(
1090 aFlavor.MimeType, static_cast< ::cppu::OWeakObject* >( this ));
1094 //get view from old api wrapper
1095 Reference< datatransfer::XTransferable > xTransferable(
1096 createInstance( CHART_VIEW_SERVICE_NAME ), uno::UNO_QUERY );
1097 if( xTransferable.is() &&
1098 xTransferable->isDataFlavorSupported( aFlavor ))
1100 aResult = xTransferable->getTransferData( aFlavor );
1103 catch (const uno::Exception&)
1105 DBG_UNHANDLED_EXCEPTION("chart2");
1108 return aResult;
1111 Sequence< datatransfer::DataFlavor > SAL_CALL ChartModel::getTransferDataFlavors()
1113 return { datatransfer::DataFlavor( lcl_aGDIMetaFileMIMETypeHighContrast,
1114 u"GDIMetaFile"_ustr,
1115 cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ) };
1118 sal_Bool SAL_CALL ChartModel::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor )
1120 return aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast;
1123 namespace
1125 enum eServiceType
1127 SERVICE_DASH_TABLE,
1128 SERVICE_GRADIENT_TABLE,
1129 SERVICE_HATCH_TABLE,
1130 SERVICE_BITMAP_TABLE,
1131 SERVICE_TRANSP_GRADIENT_TABLE,
1132 SERVICE_MARKER_TABLE,
1133 SERVICE_NAMESPACE_MAP
1136 typedef std::map< OUString, enum eServiceType > tServiceNameMap;
1138 tServiceNameMap & lcl_getStaticServiceNameMap()
1140 static tServiceNameMap aServiceNameMap{
1141 {"com.sun.star.drawing.DashTable", SERVICE_DASH_TABLE},
1142 {"com.sun.star.drawing.GradientTable", SERVICE_GRADIENT_TABLE},
1143 {"com.sun.star.drawing.HatchTable", SERVICE_HATCH_TABLE},
1144 {"com.sun.star.drawing.BitmapTable", SERVICE_BITMAP_TABLE},
1145 {"com.sun.star.drawing.TransparencyGradientTable", SERVICE_TRANSP_GRADIENT_TABLE},
1146 {"com.sun.star.drawing.MarkerTable", SERVICE_MARKER_TABLE},
1147 {"com.sun.star.xml.NamespaceMap", SERVICE_NAMESPACE_MAP}};
1148 return aServiceNameMap;
1151 // ____ XMultiServiceFactory ____
1152 Reference< uno::XInterface > SAL_CALL ChartModel::createInstance( const OUString& rServiceSpecifier )
1154 tServiceNameMap & rMap = lcl_getStaticServiceNameMap();
1156 tServiceNameMap::const_iterator aIt( rMap.find( rServiceSpecifier ));
1157 if( aIt != rMap.end())
1159 switch( (*aIt).second )
1161 case SERVICE_DASH_TABLE:
1162 case SERVICE_GRADIENT_TABLE:
1163 case SERVICE_HATCH_TABLE:
1164 case SERVICE_BITMAP_TABLE:
1165 case SERVICE_TRANSP_GRADIENT_TABLE:
1166 case SERVICE_MARKER_TABLE:
1168 if(!mxChartView.is())
1170 mxChartView = new ChartView( m_xContext, *this);
1172 return mxChartView->createInstance( rServiceSpecifier );
1174 break;
1175 case SERVICE_NAMESPACE_MAP:
1176 return static_cast<cppu::OWeakObject*>(m_xXMLNamespaceMap.get());
1179 else if(rServiceSpecifier == CHART_VIEW_SERVICE_NAME)
1181 if(!mxChartView.is())
1183 mxChartView = new ChartView( m_xContext, *this);
1186 return static_cast< ::cppu::OWeakObject* >( mxChartView.get() );
1188 else
1190 if( m_xOldModelAgg.is() )
1192 Any aAny = m_xOldModelAgg->queryAggregation( cppu::UnoType<lang::XMultiServiceFactory>::get());
1193 uno::Reference< lang::XMultiServiceFactory > xOldModelFactory;
1194 if( (aAny >>= xOldModelFactory) && xOldModelFactory.is() )
1196 return xOldModelFactory->createInstance( rServiceSpecifier );
1200 return nullptr;
1203 Reference< uno::XInterface > SAL_CALL ChartModel::createInstanceWithArguments(
1204 const OUString& rServiceSpecifier , const Sequence< Any >& Arguments )
1206 OSL_ENSURE( Arguments.hasElements(), "createInstanceWithArguments: Warning: Arguments are ignored" );
1207 return createInstance( rServiceSpecifier );
1210 Sequence< OUString > SAL_CALL ChartModel::getAvailableServiceNames()
1212 uno::Sequence< OUString > aResult;
1214 if( m_xOldModelAgg.is())
1216 Any aAny = m_xOldModelAgg->queryAggregation( cppu::UnoType<lang::XMultiServiceFactory>::get());
1217 uno::Reference< lang::XMultiServiceFactory > xOldModelFactory;
1218 if( (aAny >>= xOldModelFactory) && xOldModelFactory.is() )
1220 return xOldModelFactory->getAvailableServiceNames();
1223 return aResult;
1226 Reference< util::XNumberFormatsSupplier > const & ChartModel::getNumberFormatsSupplier()
1228 if( !m_xNumberFormatsSupplier.is() )
1230 if( !m_xOwnNumberFormatsSupplier.is() )
1232 m_apSvNumberFormatter.reset( new SvNumberFormatter( m_xContext, LANGUAGE_SYSTEM ) );
1233 m_xOwnNumberFormatsSupplier = new SvNumberFormatsSupplierObj( m_apSvNumberFormatter.get() );
1234 //pOwnNumberFormatter->ChangeStandardPrec( 15 ); todo?
1236 m_xNumberFormatsSupplier = m_xOwnNumberFormatsSupplier;
1238 return m_xNumberFormatsSupplier;
1241 // ____ XUnoTunnel ___
1242 ::sal_Int64 SAL_CALL ChartModel::getSomething( const Sequence< ::sal_Int8 >& aIdentifier )
1244 if( comphelper::isUnoTunnelId<SvNumberFormatsSupplierObj>(aIdentifier) )
1246 Reference< lang::XUnoTunnel > xTunnel( getNumberFormatsSupplier(), uno::UNO_QUERY );
1247 if( xTunnel.is() )
1248 return xTunnel->getSomething( aIdentifier );
1250 return 0;
1253 // ____ XNumberFormatsSupplier ____
1254 uno::Reference< beans::XPropertySet > SAL_CALL ChartModel::getNumberFormatSettings()
1256 Reference< util::XNumberFormatsSupplier > xSupplier( getNumberFormatsSupplier() );
1257 if( xSupplier.is() )
1258 return xSupplier->getNumberFormatSettings();
1259 return uno::Reference< beans::XPropertySet >();
1262 uno::Reference< util::XNumberFormats > SAL_CALL ChartModel::getNumberFormats()
1264 Reference< util::XNumberFormatsSupplier > xSupplier( getNumberFormatsSupplier() );
1265 if( xSupplier.is() )
1266 return xSupplier->getNumberFormats();
1267 return uno::Reference< util::XNumberFormats >();
1270 // ____ XChild ____
1271 Reference< uno::XInterface > SAL_CALL ChartModel::getParent()
1273 return Reference< uno::XInterface >(m_xParent,uno::UNO_QUERY);
1276 void SAL_CALL ChartModel::setParent( const Reference< uno::XInterface >& Parent )
1278 if( Parent != m_xParent )
1279 m_xParent.set( Parent, uno::UNO_QUERY );
1282 // ____ XDataSource ____
1283 uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > SAL_CALL ChartModel::getDataSequences()
1285 rtl::Reference< DataSource > xSource = DataSourceHelper::getUsedData( *this );
1286 if( xSource.is())
1287 return xSource->getDataSequences();
1289 return uno::Sequence< Reference< chart2::data::XLabeledDataSequence > >();
1292 //XDumper
1293 OUString SAL_CALL ChartModel::dump(OUString const & kind)
1295 if (kind.isEmpty()) {
1296 return comphelper::dumpXmlToString([this](auto writer) { return dumpAsXml(writer); });
1299 // kind == "shapes":
1300 uno::Reference< qa::XDumper > xDumper(
1301 createInstance( CHART_VIEW_SERVICE_NAME ), uno::UNO_QUERY );
1302 if (xDumper.is())
1303 return xDumper->dump(kind);
1305 return OUString();
1308 void ChartModel::setTimeBasedRange(sal_Int32 nStart, sal_Int32 nEnd)
1310 mnStart = nStart;
1311 mnEnd = nEnd;
1312 mbTimeBased = true;
1315 void ChartModel::update()
1317 if(!mxChartView.is())
1319 mxChartView = new ChartView( m_xContext, *this);
1321 mxChartView->setViewDirty();
1322 mxChartView->update();
1325 bool ChartModel::isDataFromSpreadsheet()
1327 return !isDataFromPivotTable() && !hasInternalDataProvider();
1330 bool ChartModel::isDataFromPivotTable() const
1332 uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(m_xDataProvider, uno::UNO_QUERY);
1333 return xPivotTableDataProvider.is();
1336 } // namespace chart
1338 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1339 com_sun_star_comp_chart2_ChartModel_get_implementation(css::uno::XComponentContext *context,
1340 css::uno::Sequence<css::uno::Any> const &)
1342 return cppu::acquire(new ::chart::ChartModel(context));
1345 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */