summaryrefslogtreecommitdiffstats
path: root/chart2/source/model/main/ChartModel.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /chart2/source/model/main/ChartModel.cxx
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'chart2/source/model/main/ChartModel.cxx')
-rw-r--r--chart2/source/model/main/ChartModel.cxx1306
1 files changed, 1306 insertions, 0 deletions
diff --git a/chart2/source/model/main/ChartModel.cxx b/chart2/source/model/main/ChartModel.cxx
new file mode 100644
index 000000000..712be3fdf
--- /dev/null
+++ b/chart2/source/model/main/ChartModel.cxx
@@ -0,0 +1,1306 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ChartModel.hxx>
+#include <ChartTypeManager.hxx>
+#include <ChartTypeTemplate.hxx>
+#include <servicenames.hxx>
+#include <DataSource.hxx>
+#include <DataSourceHelper.hxx>
+#include <ChartModelHelper.hxx>
+#include <DisposeHelper.hxx>
+#include <ControllerLockGuard.hxx>
+#include <InternalDataProvider.hxx>
+#include <ObjectIdentifier.hxx>
+#include "PageBackground.hxx"
+#include <CloneHelper.hxx>
+#include <NameContainer.hxx>
+#include "UndoManager.hxx"
+#include <ChartView.hxx>
+#include <PopupRequest.hxx>
+#include <ModifyListenerHelper.hxx>
+#include <Diagram.hxx>
+
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <svl/numformat.hxx>
+#include <svl/numuno.hxx>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/embed/EmbedMapUnits.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/document/DocumentProperties.hpp>
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <libxml/xmlwriter.h>
+
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Any;
+using ::osl::MutexGuard;
+
+using namespace ::com::sun::star;
+using namespace ::apphelper;
+using namespace ::chart::CloneHelper;
+
+namespace
+{
+constexpr OUStringLiteral lcl_aGDIMetaFileMIMEType(
+ u"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"");
+constexpr OUStringLiteral lcl_aGDIMetaFileMIMETypeHighContrast(
+ u"application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"");
+
+} // anonymous namespace
+
+// ChartModel Constructor and Destructor
+
+namespace chart
+{
+
+ChartModel::ChartModel(uno::Reference<uno::XComponentContext > const & xContext)
+ : m_aLifeTimeManager( this, this )
+ , m_bReadOnly( false )
+ , m_bModified( false )
+ , m_nInLoad(0)
+ , m_bUpdateNotificationsPending(false)
+ , mbTimeBased(false)
+ , m_aControllers( m_aModelMutex )
+ , m_nControllerLockCount(0)
+ , m_xContext( xContext )
+ , m_aVisualAreaSize( ChartModelHelper::getDefaultPageSize() )
+ , m_xPageBackground( new PageBackground )
+ , m_xXMLNamespaceMap( new NameContainer() )
+ , mnStart(0)
+ , mnEnd(0)
+{
+ osl_atomic_increment(&m_refCount);
+ {
+ m_xOldModelAgg.set(
+ m_xContext->getServiceManager()->createInstanceWithContext(
+ CHART_CHARTAPIWRAPPER_SERVICE_NAME,
+ m_xContext ), uno::UNO_QUERY_THROW );
+ m_xOldModelAgg->setDelegator( *this );
+ }
+
+ {
+ m_xPageBackground->addModifyListener( this );
+ m_xChartTypeManager = new ::chart::ChartTypeManager( m_xContext );
+ }
+ osl_atomic_decrement(&m_refCount);
+}
+
+ChartModel::ChartModel( const ChartModel & rOther )
+ : impl::ChartModel_Base(rOther)
+ , m_aLifeTimeManager( this, this )
+ , m_bReadOnly( rOther.m_bReadOnly )
+ , m_bModified( rOther.m_bModified )
+ , m_nInLoad(0)
+ , m_bUpdateNotificationsPending(false)
+ , mbTimeBased(rOther.mbTimeBased)
+ , m_aResource( rOther.m_aResource )
+ , m_aMediaDescriptor( rOther.m_aMediaDescriptor )
+ , m_aControllers( m_aModelMutex )
+ , m_nControllerLockCount(0)
+ , m_xContext( rOther.m_xContext )
+ // @note: the old model aggregate must not be shared with other models if it
+ // is, you get mutex deadlocks
+ //, m_xOldModelAgg( nullptr ) //rOther.m_xOldModelAgg )
+ // m_xStorage( nullptr ) //rOther.m_xStorage )
+ , m_aVisualAreaSize( rOther.m_aVisualAreaSize )
+ , m_aGraphicObjectVector( rOther.m_aGraphicObjectVector )
+ , m_xDataProvider( rOther.m_xDataProvider )
+ , m_xInternalDataProvider( rOther.m_xInternalDataProvider )
+ , mnStart(rOther.mnStart)
+ , mnEnd(rOther.mnEnd)
+{
+ osl_atomic_increment(&m_refCount);
+ {
+ m_xOldModelAgg.set(
+ m_xContext->getServiceManager()->createInstanceWithContext(
+ CHART_CHARTAPIWRAPPER_SERVICE_NAME,
+ m_xContext ), uno::UNO_QUERY_THROW );
+ m_xOldModelAgg->setDelegator( *this );
+
+ Reference< util::XModifyListener > xListener;
+ Reference< chart2::XTitle > xNewTitle = CreateRefClone< chart2::XTitle >()( rOther.m_xTitle );
+ rtl::Reference< ::chart::Diagram > xNewDiagram;
+ if (rOther.m_xDiagram.is())
+ xNewDiagram = new ::chart::Diagram( *rOther.m_xDiagram );
+ rtl::Reference< ::chart::PageBackground > xNewPageBackground = new PageBackground( *rOther.m_xPageBackground );
+ rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager; // does not implement XCloneable
+ rtl::Reference< ::chart::NameContainer > xXMLNamespaceMap = new NameContainer( *rOther.m_xXMLNamespaceMap );
+
+ {
+ MutexGuard aGuard( m_aModelMutex );
+ xListener = this;
+ m_xTitle = xNewTitle;
+ m_xDiagram = xNewDiagram;
+ m_xPageBackground = xNewPageBackground;
+ m_xChartTypeManager = xChartTypeManager;
+ m_xXMLNamespaceMap = xXMLNamespaceMap;
+ }
+
+ ModifyListenerHelper::addListener( xNewTitle, xListener );
+ if( xNewDiagram && xListener)
+ xNewDiagram->addModifyListener( xListener );
+ if( xNewPageBackground && xListener)
+ xNewPageBackground->addModifyListener( xListener );
+ xListener.clear();
+ }
+ osl_atomic_decrement(&m_refCount);
+}
+
+ChartModel::~ChartModel()
+{
+ if( m_xOldModelAgg.is())
+ m_xOldModelAgg->setDelegator( nullptr );
+}
+
+void SAL_CALL ChartModel::initialize( const Sequence< Any >& /*rArguments*/ )
+{
+ //#i113722# avoid duplicate creation
+
+ //maybe additional todo?:
+ //support argument "EmbeddedObject"?
+ //support argument "EmbeddedScriptSupport"?
+ //support argument "DocumentRecoverySupport"?
+}
+
+ChartView* ChartModel::getChartView() const
+{
+ return mxChartView.get();
+}
+
+// private methods
+
+OUString ChartModel::impl_g_getLocation()
+{
+
+ LifeTimeGuard aGuard(m_aLifeTimeManager);
+ if(!aGuard.startApiCall())
+ return OUString(); //behave passive if already disposed or closed or throw exception @todo?
+ //mutex is acquired
+ return m_aResource;
+}
+
+bool ChartModel::impl_isControllerConnected( const uno::Reference< frame::XController >& xController )
+{
+ try
+ {
+ std::vector< uno::Reference<uno::XInterface> > aSeq = m_aControllers.getElements();
+ for( const auto & r : aSeq )
+ {
+ if( r == xController )
+ return true;
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ return false;
+}
+
+uno::Reference< frame::XController > ChartModel::impl_getCurrentController()
+{
+ //@todo? hold only weak references to controllers
+
+ // get the last active controller of this model
+ if( m_xCurrentController.is() )
+ return m_xCurrentController;
+
+ // get the first controller of this model
+ if( m_aControllers.getLength() )
+ {
+ uno::Reference<uno::XInterface> xI = m_aControllers.getInterface(0);
+ return uno::Reference<frame::XController>( xI, uno::UNO_QUERY );
+ }
+
+ //return nothing if no controllers are connected at all
+ return uno::Reference< frame::XController > ();
+}
+
+void ChartModel::impl_notifyCloseListeners()
+{
+ ::comphelper::OInterfaceContainerHelper2* pIC = m_aLifeTimeManager.m_aListenerContainer
+ .getContainer( cppu::UnoType<util::XCloseListener>::get());
+ if( pIC )
+ {
+ lang::EventObject aEvent( static_cast< lang::XComponent*>(this) );
+ ::comphelper::OInterfaceIteratorHelper2 aIt( *pIC );
+ while( aIt.hasMoreElements() )
+ {
+ static_cast< util::XCloseListener* >( aIt.next() )->notifyClosing( aEvent );
+ }
+ }
+}
+
+void ChartModel::impl_adjustAdditionalShapesPositionAndSize( const awt::Size& aVisualAreaSize )
+{
+ uno::Reference< beans::XPropertySet > xProperties( static_cast< ::cppu::OWeakObject* >( this ), uno::UNO_QUERY );
+ if ( !xProperties.is() )
+ return;
+
+ uno::Reference< drawing::XShapes > xShapes;
+ xProperties->getPropertyValue( "AdditionalShapes" ) >>= xShapes;
+ if ( !xShapes.is() )
+ return;
+
+ sal_Int32 nCount = xShapes->getCount();
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ Reference< drawing::XShape > xShape;
+ if ( xShapes->getByIndex( i ) >>= xShape )
+ {
+ if ( xShape.is() )
+ {
+ awt::Point aPos( xShape->getPosition() );
+ awt::Size aSize( xShape->getSize() );
+
+ double fWidth = static_cast< double >( aVisualAreaSize.Width ) / m_aVisualAreaSize.Width;
+ double fHeight = static_cast< double >( aVisualAreaSize.Height ) / m_aVisualAreaSize.Height;
+
+ aPos.X = static_cast< tools::Long >( aPos.X * fWidth );
+ aPos.Y = static_cast< tools::Long >( aPos.Y * fHeight );
+ aSize.Width = static_cast< tools::Long >( aSize.Width * fWidth );
+ aSize.Height = static_cast< tools::Long >( aSize.Height * fHeight );
+
+ xShape->setPosition( aPos );
+ xShape->setSize( aSize );
+ }
+ }
+ }
+}
+
+// lang::XServiceInfo
+
+OUString SAL_CALL ChartModel::getImplementationName()
+{
+ return CHART_MODEL_SERVICE_IMPLEMENTATION_NAME;
+}
+
+sal_Bool SAL_CALL ChartModel::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL ChartModel::getSupportedServiceNames()
+{
+ return {
+ CHART_MODEL_SERVICE_NAME,
+ "com.sun.star.document.OfficeDocument",
+ "com.sun.star.chart.ChartDocument"
+ };
+}
+
+// frame::XModel (required interface)
+
+sal_Bool SAL_CALL ChartModel::attachResource( const OUString& rURL
+ , const uno::Sequence< beans::PropertyValue >& rMediaDescriptor )
+{
+ /*
+ The method attachResource() is used by the frame loader implementations
+ to inform the model about its URL and MediaDescriptor.
+ */
+
+ LifeTimeGuard aGuard(m_aLifeTimeManager);
+ if(!aGuard.startApiCall())
+ return false; //behave passive if already disposed or closed or throw exception @todo?
+ //mutex is acquired
+
+ if(!m_aResource.isEmpty())//we have a resource already //@todo? or is setting a new resource allowed?
+ return false;
+ m_aResource = rURL;
+ m_aMediaDescriptor = rMediaDescriptor;
+
+ //@todo ? check rURL ??
+ //@todo ? evaluate m_aMediaDescriptor;
+ //@todo ? ... ??? --> nothing, this method is only for setting information
+
+ return true;
+}
+
+OUString SAL_CALL ChartModel::getURL()
+{
+ return impl_g_getLocation();
+}
+
+uno::Sequence< beans::PropertyValue > SAL_CALL ChartModel::getArgs()
+{
+ /*
+ The method getArgs() returns a sequence of property values
+ that report the resource description according to com.sun.star.document.MediaDescriptor,
+ specified on loading or saving with storeAsURL.
+ */
+
+ LifeTimeGuard aGuard(m_aLifeTimeManager);
+ if(!aGuard.startApiCall())
+ return uno::Sequence< beans::PropertyValue >(); //behave passive if already disposed or closed or throw exception @todo?
+ //mutex is acquired
+
+ return m_aMediaDescriptor;
+}
+
+void SAL_CALL ChartModel::connectController( const uno::Reference< frame::XController >& xController )
+{
+ //@todo? this method is declared as oneway -> ...?
+
+ LifeTimeGuard aGuard(m_aLifeTimeManager);
+ if(!aGuard.startApiCall())
+ return ; //behave passive if already disposed or closed
+ //mutex is acquired
+
+ //--add controller
+ m_aControllers.addInterface(xController);
+}
+
+void SAL_CALL ChartModel::disconnectController( const uno::Reference< frame::XController >& xController )
+{
+ //@todo? this method is declared as oneway -> ...?
+
+ LifeTimeGuard aGuard(m_aLifeTimeManager);
+ if(!aGuard.startApiCall())
+ return; //behave passive if already disposed or closed
+
+ //--remove controller
+ m_aControllers.removeInterface(xController);
+
+ //case: current controller is disconnected:
+ if( m_xCurrentController == xController )
+ m_xCurrentController.clear();
+
+ DisposeHelper::DisposeAndClear( m_xRangeHighlighter );
+ DisposeHelper::DisposeAndClear(m_xPopupRequest);
+}
+
+void SAL_CALL ChartModel::lockControllers()
+{
+ /*
+ suspends some notifications to the controllers which are used for display updates.
+
+ The calls to lockControllers() and unlockControllers() may be nested
+ and even overlapping, but they must be in pairs. While there is at least one lock
+ remaining, some notifications for display updates are not broadcasted.
+ */
+
+ //@todo? this method is declared as oneway -> ...?
+
+ LifeTimeGuard aGuard(m_aLifeTimeManager);
+ if(!aGuard.startApiCall())
+ return; //behave passive if already disposed or closed or throw exception @todo?
+ ++m_nControllerLockCount;
+}
+
+void SAL_CALL ChartModel::unlockControllers()
+{
+ /*
+ resumes the notifications which were suspended by lockControllers() .
+
+ The calls to lockControllers() and unlockControllers() may be nested
+ and even overlapping, but they must be in pairs. While there is at least one lock
+ remaining, some notifications for display updates are not broadcasted.
+ */
+
+ //@todo? this method is declared as oneway -> ...?
+
+ LifeTimeGuard aGuard(m_aLifeTimeManager);
+ if(!aGuard.startApiCall())
+ return; //behave passive if already disposed or closed or throw exception @todo?
+ if( m_nControllerLockCount == 0 )
+ {
+ SAL_WARN("chart2", "ChartModel: unlockControllers called with m_nControllerLockCount == 0" );
+ return;
+ }
+ --m_nControllerLockCount;
+ if( m_nControllerLockCount == 0 && m_bUpdateNotificationsPending )
+ {
+ aGuard.clear();
+ impl_notifyModifiedListeners();
+ }
+}
+
+sal_Bool SAL_CALL ChartModel::hasControllersLocked()
+{
+ LifeTimeGuard aGuard(m_aLifeTimeManager);
+ if(!aGuard.startApiCall())
+ return false; //behave passive if already disposed or closed or throw exception @todo?
+ return ( m_nControllerLockCount != 0 ) ;
+}
+
+uno::Reference< frame::XController > SAL_CALL ChartModel::getCurrentController()
+{
+ LifeTimeGuard aGuard(m_aLifeTimeManager);
+ if(!aGuard.startApiCall())
+ throw lang::DisposedException(
+ "getCurrentController was called on an already disposed or closed model",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ return impl_getCurrentController();
+}
+
+void SAL_CALL ChartModel::setCurrentController( const uno::Reference< frame::XController >& xController )
+{
+ LifeTimeGuard aGuard(m_aLifeTimeManager);
+ if(!aGuard.startApiCall())
+ throw lang::DisposedException(
+ "setCurrentController was called on an already disposed or closed model",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ //OSL_ENSURE( impl_isControllerConnected(xController), "setCurrentController is called with a Controller which is not connected" );
+ if(!impl_isControllerConnected(xController))
+ throw container::NoSuchElementException(
+ "setCurrentController is called with a Controller which is not connected",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ m_xCurrentController = xController;
+
+ DisposeHelper::DisposeAndClear( m_xRangeHighlighter );
+ DisposeHelper::DisposeAndClear(m_xPopupRequest);
+}
+
+uno::Reference< uno::XInterface > SAL_CALL ChartModel::getCurrentSelection()
+{
+ LifeTimeGuard aGuard(m_aLifeTimeManager);
+ if(!aGuard.startApiCall())
+ throw lang::DisposedException(
+ "getCurrentSelection was called on an already disposed or closed model",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ uno::Reference< uno::XInterface > xReturn;
+ uno::Reference< frame::XController > xController = impl_getCurrentController();
+
+ aGuard.clear();
+ if( xController.is() )
+ {
+ uno::Reference< view::XSelectionSupplier > xSelectionSupl( xController, uno::UNO_QUERY );
+ if ( xSelectionSupl.is() )
+ {
+ uno::Any aSel = xSelectionSupl->getSelection();
+ OUString aObjectCID;
+ if( aSel >>= aObjectCID )
+ xReturn.set( ObjectIdentifier::getObjectPropertySet( aObjectCID, this));
+ }
+ }
+ return xReturn;
+}
+
+// lang::XComponent (base of XModel)
+void SAL_CALL ChartModel::dispose()
+{
+ Reference< XInterface > xKeepAlive( *this );
+
+ //This object should release all resources and references in the
+ //easiest possible manner
+ //This object must notify all registered listeners using the method
+ //<member>XEventListener::disposing</member>
+
+ //hold no mutex
+ if( !m_aLifeTimeManager.dispose() )
+ return;
+
+ //--release all resources and references
+ //// @todo
+
+ if ( m_xDiagram.is() )
+ m_xDiagram->removeModifyListener( this );
+
+ if ( m_xDataProvider.is() )
+ {
+ Reference<util::XModifyBroadcaster> xModifyBroadcaster( m_xDataProvider, uno::UNO_QUERY );
+ if ( xModifyBroadcaster.is() )
+ xModifyBroadcaster->removeModifyListener( this );
+ }
+
+ m_xDataProvider.clear();
+ m_xInternalDataProvider.clear();
+ m_xNumberFormatsSupplier.clear();
+ m_xOwnNumberFormatsSupplier.clear();
+ m_xChartTypeManager.clear();
+ m_xDiagram.clear();
+ DisposeHelper::DisposeAndClear( m_xTitle );
+ m_xPageBackground.clear();
+ m_xXMLNamespaceMap.clear();
+
+ m_xStorage.clear();
+ // just clear, don't dispose - we're not the owner
+
+ if ( m_pUndoManager.is() )
+ m_pUndoManager->disposing();
+ m_pUndoManager.clear();
+ // that's important, since the UndoManager implementation delegates its ref counting to ourself.
+
+ if( m_xOldModelAgg.is()) // #i120828#, to release cyclic reference to ChartModel object
+ m_xOldModelAgg->setDelegator( nullptr );
+
+ m_aControllers.disposeAndClear( lang::EventObject( static_cast< cppu::OWeakObject * >( this )));
+ m_xCurrentController.clear();
+
+ DisposeHelper::DisposeAndClear( m_xRangeHighlighter );
+ DisposeHelper::DisposeAndClear(m_xPopupRequest);
+
+ if( m_xOldModelAgg.is())
+ m_xOldModelAgg->setDelegator( nullptr );
+}
+
+void SAL_CALL ChartModel::addEventListener( const uno::Reference< lang::XEventListener > & xListener )
+{
+ if( m_aLifeTimeManager.impl_isDisposedOrClosed() )
+ return; //behave passive if already disposed or closed
+
+ m_aLifeTimeManager.m_aListenerContainer.addInterface( cppu::UnoType<lang::XEventListener>::get(), xListener );
+}
+
+void SAL_CALL ChartModel::removeEventListener( const uno::Reference< lang::XEventListener > & xListener )
+{
+ if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) )
+ return; //behave passive if already disposed or closed
+
+ m_aLifeTimeManager.m_aListenerContainer.removeInterface( cppu::UnoType<lang::XEventListener>::get(), xListener );
+}
+
+// util::XCloseBroadcaster (base of XCloseable)
+void SAL_CALL ChartModel::addCloseListener( const uno::Reference< util::XCloseListener > & xListener )
+{
+ m_aLifeTimeManager.g_addCloseListener( xListener );
+}
+
+void SAL_CALL ChartModel::removeCloseListener( const uno::Reference< util::XCloseListener > & xListener )
+{
+ if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) )
+ return; //behave passive if already disposed or closed
+
+ m_aLifeTimeManager.m_aListenerContainer.removeInterface( cppu::UnoType<util::XCloseListener>::get(), xListener );
+}
+
+// util::XCloseable
+void SAL_CALL ChartModel::close( sal_Bool bDeliverOwnership )
+{
+ //hold no mutex
+
+ if( !m_aLifeTimeManager.g_close_startTryClose( bDeliverOwnership ) )
+ return;
+ //no mutex is acquired
+
+ // At the end of this method may we must dispose ourself ...
+ // and may nobody from outside hold a reference to us ...
+ // then it's a good idea to do that by ourself.
+ uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) );
+
+ //the listeners have had no veto
+ //check whether we self can close
+ {
+ util::CloseVetoException aVetoException(
+ "the model itself could not be closed",
+ static_cast< ::cppu::OWeakObject* >(this) );
+
+ m_aLifeTimeManager.g_close_isNeedToCancelLongLastingCalls( bDeliverOwnership, aVetoException );
+ }
+ m_aLifeTimeManager.g_close_endTryClose_doClose();
+
+ // BM @todo: is it ok to call the listeners here?
+ impl_notifyCloseListeners();
+}
+
+// lang::XTypeProvider
+uno::Sequence< uno::Type > SAL_CALL ChartModel::getTypes()
+{
+ uno::Reference< lang::XTypeProvider > xAggTypeProvider;
+ if( (m_xOldModelAgg->queryAggregation( cppu::UnoType<decltype(xAggTypeProvider)>::get()) >>= xAggTypeProvider)
+ && xAggTypeProvider.is())
+ {
+ return comphelper::concatSequences(
+ impl::ChartModel_Base::getTypes(),
+ xAggTypeProvider->getTypes());
+ }
+
+ return impl::ChartModel_Base::getTypes();
+}
+
+// document::XDocumentPropertiesSupplier
+uno::Reference< document::XDocumentProperties > SAL_CALL
+ ChartModel::getDocumentProperties()
+{
+ ::osl::MutexGuard aGuard( m_aModelMutex );
+ if ( !m_xDocumentProperties.is() )
+ {
+ m_xDocumentProperties.set( document::DocumentProperties::create( ::comphelper::getProcessComponentContext() ) );
+ }
+ return m_xDocumentProperties;
+}
+
+// document::XDocumentPropertiesSupplier
+Reference< document::XUndoManager > SAL_CALL ChartModel::getUndoManager( )
+{
+ ::osl::MutexGuard aGuard( m_aModelMutex );
+ if ( !m_pUndoManager.is() )
+ m_pUndoManager.set( new UndoManager( *this, m_aModelMutex ) );
+ return m_pUndoManager;
+}
+
+// chart2::XChartDocument
+
+uno::Reference< chart2::XDiagram > SAL_CALL ChartModel::getFirstDiagram()
+{
+ MutexGuard aGuard( m_aModelMutex );
+ return m_xDiagram;
+}
+
+void SAL_CALL ChartModel::setFirstDiagram( const uno::Reference< chart2::XDiagram >& xDiagram )
+{
+ rtl::Reference< ::chart::Diagram > xOldDiagram;
+ Reference< util::XModifyListener > xListener;
+ {
+ MutexGuard aGuard( m_aModelMutex );
+ if( xDiagram.get() == m_xDiagram.get() )
+ return;
+ xOldDiagram = m_xDiagram;
+ assert(!xDiagram || dynamic_cast<::chart::Diagram*>(xDiagram.get()));
+ m_xDiagram = dynamic_cast<::chart::Diagram*>(xDiagram.get());
+ xListener = this;
+ }
+ //don't keep the mutex locked while calling out
+ if( xOldDiagram && xListener )
+ xOldDiagram->removeModifyListener( xListener );
+ ModifyListenerHelper::addListener( xDiagram, xListener );
+ setModified( true );
+}
+
+Reference< chart2::data::XDataSource > ChartModel::impl_createDefaultData()
+{
+ Reference< chart2::data::XDataSource > xDataSource;
+ if( hasInternalDataProvider() )
+ {
+ //init internal dataprovider
+ {
+ beans::NamedValue aParam( "CreateDefaultData" ,uno::Any(true) );
+ uno::Sequence< uno::Any > aArgs{ uno::Any(aParam) };
+ m_xInternalDataProvider->initialize(aArgs);
+ }
+ //create data
+ uno::Sequence<beans::PropertyValue> aArgs( comphelper::InitPropertySequence({
+ { "CellRangeRepresentation", uno::Any( OUString("all") ) },
+ { "HasCategories", uno::Any( true ) },
+ { "FirstCellAsLabel", uno::Any( true ) },
+ { "DataRowSource", uno::Any( css::chart::ChartDataRowSource_COLUMNS ) }
+ }));
+ xDataSource = m_xInternalDataProvider->createDataSource( aArgs );
+ }
+ return xDataSource;
+}
+
+void SAL_CALL ChartModel::createInternalDataProvider( sal_Bool bCloneExistingData )
+{
+ // don't lock the mutex, because this call calls out to code that tries to
+ // lock the solar mutex. On the other hand, a paint locks the solar mutex
+ // and calls to the model lock the model's mutex => deadlock
+ // @todo: lock a separate mutex in the InternalData class
+ if( !hasInternalDataProvider() )
+ {
+ if( bCloneExistingData )
+ m_xInternalDataProvider = ChartModelHelper::createInternalDataProvider( this, true );
+ else
+ m_xInternalDataProvider = ChartModelHelper::createInternalDataProvider( nullptr, true );
+ m_xDataProvider.set( m_xInternalDataProvider );
+ }
+ setModified( true );
+}
+
+void ChartModel::removeDataProviders()
+{
+ if (m_xInternalDataProvider.is())
+ m_xInternalDataProvider.clear();
+ if (m_xDataProvider.is())
+ m_xDataProvider.clear();
+}
+
+void ChartModel::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ChartModel"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+
+ if (mxChartView.is())
+ {
+ mxChartView->dumpAsXml(pWriter);
+ }
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+sal_Bool SAL_CALL ChartModel::hasInternalDataProvider()
+{
+ return m_xDataProvider.is() && m_xInternalDataProvider.is();
+}
+
+uno::Reference< chart2::data::XDataProvider > SAL_CALL ChartModel::getDataProvider()
+{
+ MutexGuard aGuard( m_aModelMutex );
+ return m_xDataProvider;
+}
+
+// ____ XDataReceiver ____
+
+void SAL_CALL ChartModel::attachDataProvider( const uno::Reference< chart2::data::XDataProvider >& xDataProvider )
+{
+ {
+ MutexGuard aGuard( m_aModelMutex );
+ uno::Reference< beans::XPropertySet > xProp( xDataProvider, uno::UNO_QUERY );
+ if( xProp.is() )
+ {
+ try
+ {
+ bool bIncludeHiddenCells = ChartModelHelper::isIncludeHiddenCells( this );
+ xProp->setPropertyValue("IncludeHiddenCells", uno::Any(bIncludeHiddenCells));
+ }
+ catch (const beans::UnknownPropertyException&)
+ {
+ }
+ }
+
+ uno::Reference<util::XModifyBroadcaster> xModifyBroadcaster(xDataProvider, uno::UNO_QUERY);
+ if (xModifyBroadcaster.is())
+ {
+ xModifyBroadcaster->addModifyListener(this);
+ }
+
+ m_xDataProvider.set( xDataProvider );
+ m_xInternalDataProvider.clear();
+
+ //the numberformatter is kept independent of the data provider!
+ }
+ setModified( true );
+}
+
+void SAL_CALL ChartModel::attachNumberFormatsSupplier( const uno::Reference< util::XNumberFormatsSupplier >& xNewSupplier )
+{
+ {
+ MutexGuard aGuard( m_aModelMutex );
+ if( xNewSupplier == m_xNumberFormatsSupplier )
+ return;
+ if( xNewSupplier == uno::Reference<XNumberFormatsSupplier>(m_xOwnNumberFormatsSupplier) )
+ return;
+ if( m_xOwnNumberFormatsSupplier.is() && xNewSupplier.is() )
+ {
+ //@todo
+ //merge missing numberformats from own to new formatter
+ }
+ else if( !xNewSupplier.is() )
+ {
+ if( m_xNumberFormatsSupplier.is() )
+ {
+ //@todo
+ //merge missing numberformats from old numberformatter to own numberformatter
+ //create own numberformatter if necessary
+ }
+ }
+
+ m_xNumberFormatsSupplier.set( xNewSupplier );
+ m_xOwnNumberFormatsSupplier.clear();
+ }
+ setModified( true );
+}
+
+void SAL_CALL ChartModel::setArguments( const Sequence< beans::PropertyValue >& aArguments )
+{
+ {
+ MutexGuard aGuard( m_aModelMutex );
+ if( !m_xDataProvider.is() )
+ return;
+ lockControllers();
+
+ try
+ {
+ Reference< chart2::data::XDataSource > xDataSource( m_xDataProvider->createDataSource( aArguments ) );
+ if( xDataSource.is() )
+ {
+ rtl::Reference< Diagram > xDia = getFirstChartDiagram();
+ if( !xDia.is() )
+ {
+ rtl::Reference< ::chart::ChartTypeTemplate > xTemplate( impl_createDefaultChartTypeTemplate() );
+ if( xTemplate.is())
+ setFirstDiagram( xTemplate->createDiagramByDataSource( xDataSource, aArguments ) );
+ }
+ else
+ xDia->setDiagramData( xDataSource, aArguments );
+ }
+ }
+ catch (const lang::IllegalArgumentException&)
+ {
+ throw;
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ unlockControllers();
+ }
+ setModified( true );
+}
+
+Sequence< OUString > SAL_CALL ChartModel::getUsedRangeRepresentations()
+{
+ return DataSourceHelper::getUsedDataRanges( this );
+}
+
+Reference< chart2::data::XDataSource > SAL_CALL ChartModel::getUsedData()
+{
+ return DataSourceHelper::getUsedData( *this );
+}
+
+Reference< chart2::data::XRangeHighlighter > SAL_CALL ChartModel::getRangeHighlighter()
+{
+ if( ! m_xRangeHighlighter.is())
+ m_xRangeHighlighter.set( ChartModelHelper::createRangeHighlighter( this ));
+ return m_xRangeHighlighter;
+}
+
+Reference<awt::XRequestCallback> SAL_CALL ChartModel::getPopupRequest()
+{
+ if (!m_xPopupRequest.is())
+ m_xPopupRequest.set(new PopupRequest);
+ return m_xPopupRequest;
+}
+
+rtl::Reference< ::chart::ChartTypeTemplate > ChartModel::impl_createDefaultChartTypeTemplate()
+{
+ rtl::Reference< ::chart::ChartTypeTemplate > xTemplate;
+ if( m_xChartTypeManager.is() )
+ xTemplate = m_xChartTypeManager->createTemplate( "com.sun.star.chart2.template.Column" );
+ return xTemplate;
+}
+
+void SAL_CALL ChartModel::setChartTypeManager( const uno::Reference< chart2::XChartTypeManager >& xNewManager )
+{
+ {
+ MutexGuard aGuard( m_aModelMutex );
+ m_xChartTypeManager = dynamic_cast<::chart::ChartTypeManager*>(xNewManager.get());
+ assert(!xNewManager || m_xChartTypeManager);
+ }
+ setModified( true );
+}
+
+uno::Reference< chart2::XChartTypeManager > SAL_CALL ChartModel::getChartTypeManager()
+{
+ MutexGuard aGuard( m_aModelMutex );
+ return m_xChartTypeManager;
+}
+
+uno::Reference< beans::XPropertySet > SAL_CALL ChartModel::getPageBackground()
+{
+ MutexGuard aGuard( m_aModelMutex );
+ return m_xPageBackground;
+}
+
+void SAL_CALL ChartModel::createDefaultChart()
+{
+ insertDefaultChart();
+}
+
+// ____ XTitled ____
+uno::Reference< chart2::XTitle > SAL_CALL ChartModel::getTitleObject()
+{
+ MutexGuard aGuard( m_aModelMutex );
+ return m_xTitle;
+}
+
+void SAL_CALL ChartModel::setTitleObject( const uno::Reference< chart2::XTitle >& xTitle )
+{
+ {
+ MutexGuard aGuard( m_aModelMutex );
+ if( m_xTitle.is() )
+ ModifyListenerHelper::removeListener( m_xTitle, this );
+ m_xTitle = xTitle;
+ ModifyListenerHelper::addListener( m_xTitle, this );
+ }
+ setModified( true );
+}
+
+// ____ XInterface (for old API wrapper) ____
+uno::Any SAL_CALL ChartModel::queryInterface( const uno::Type& aType )
+{
+ uno::Any aResult( impl::ChartModel_Base::queryInterface( aType ));
+
+ if( ! aResult.hasValue())
+ {
+ // try old API wrapper
+ try
+ {
+ if( m_xOldModelAgg.is())
+ aResult = m_xOldModelAgg->queryAggregation( aType );
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+ }
+
+ return aResult;
+}
+
+// ____ XCloneable ____
+Reference< util::XCloneable > SAL_CALL ChartModel::createClone()
+{
+ return Reference< util::XCloneable >( new ChartModel( *this ));
+}
+
+// ____ XVisualObject ____
+void SAL_CALL ChartModel::setVisualAreaSize( ::sal_Int64 nAspect, const awt::Size& aSize )
+{
+ if( nAspect == embed::Aspects::MSOLE_CONTENT )
+ {
+ ControllerLockGuard aLockGuard( *this );
+ bool bChanged =
+ (m_aVisualAreaSize.Width != aSize.Width ||
+ m_aVisualAreaSize.Height != aSize.Height);
+
+ // #i12587# support for shapes in chart
+ if ( bChanged )
+ {
+ impl_adjustAdditionalShapesPositionAndSize( aSize );
+ }
+
+ m_aVisualAreaSize = aSize;
+ if( bChanged )
+ setModified( true );
+ }
+ else
+ {
+ OSL_FAIL( "setVisualAreaSize: Aspect not implemented yet.");
+ }
+}
+
+awt::Size SAL_CALL ChartModel::getVisualAreaSize( ::sal_Int64 nAspect )
+{
+ OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT,
+ "No aspects other than content are supported" );
+ // other possible aspects are MSOLE_THUMBNAIL, MSOLE_ICON and MSOLE_DOCPRINT
+
+ return m_aVisualAreaSize;
+}
+
+embed::VisualRepresentation SAL_CALL ChartModel::getPreferredVisualRepresentation( ::sal_Int64 nAspect )
+{
+ OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT,
+ "No aspects other than content are supported" );
+
+ embed::VisualRepresentation aResult;
+
+ try
+ {
+ Sequence< sal_Int8 > aMetafile;
+
+ //get view from old api wrapper
+ Reference< datatransfer::XTransferable > xTransferable(
+ createInstance( CHART_VIEW_SERVICE_NAME ), uno::UNO_QUERY );
+ if( xTransferable.is() )
+ {
+ datatransfer::DataFlavor aDataFlavor( lcl_aGDIMetaFileMIMEType,
+ "GDIMetaFile",
+ cppu::UnoType<uno::Sequence< sal_Int8 >>::get() );
+
+ uno::Any aData( xTransferable->getTransferData( aDataFlavor ) );
+ aData >>= aMetafile;
+ }
+
+ aResult.Flavor.MimeType = lcl_aGDIMetaFileMIMEType;
+ aResult.Flavor.DataType = cppu::UnoType<decltype(aMetafile)>::get();
+
+ aResult.Data <<= aMetafile;
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+
+ return aResult;
+}
+
+::sal_Int32 SAL_CALL ChartModel::getMapUnit( ::sal_Int64 nAspect )
+{
+ OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT,
+ "No aspects other than content are supported" );
+ return embed::EmbedMapUnits::ONE_100TH_MM;
+}
+
+// ____ datatransfer::XTransferable ____
+uno::Any SAL_CALL ChartModel::getTransferData( const datatransfer::DataFlavor& aFlavor )
+{
+ uno::Any aResult;
+ if( !isDataFlavorSupported( aFlavor ) )
+ throw datatransfer::UnsupportedFlavorException(
+ aFlavor.MimeType, static_cast< ::cppu::OWeakObject* >( this ));
+
+ try
+ {
+ //get view from old api wrapper
+ Reference< datatransfer::XTransferable > xTransferable(
+ createInstance( CHART_VIEW_SERVICE_NAME ), uno::UNO_QUERY );
+ if( xTransferable.is() &&
+ xTransferable->isDataFlavorSupported( aFlavor ))
+ {
+ aResult = xTransferable->getTransferData( aFlavor );
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2");
+ }
+
+ return aResult;
+}
+
+Sequence< datatransfer::DataFlavor > SAL_CALL ChartModel::getTransferDataFlavors()
+{
+ return { datatransfer::DataFlavor( lcl_aGDIMetaFileMIMETypeHighContrast,
+ "GDIMetaFile",
+ cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ) };
+}
+
+sal_Bool SAL_CALL ChartModel::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor )
+{
+ return aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast;
+}
+
+namespace
+{
+enum eServiceType
+{
+ SERVICE_DASH_TABLE,
+ SERVICE_GRADIENT_TABLE,
+ SERVICE_HATCH_TABLE,
+ SERVICE_BITMAP_TABLE,
+ SERVICE_TRANSP_GRADIENT_TABLE,
+ SERVICE_MARKER_TABLE,
+ SERVICE_NAMESPACE_MAP
+};
+
+typedef std::map< OUString, enum eServiceType > tServiceNameMap;
+
+tServiceNameMap & lcl_getStaticServiceNameMap()
+{
+ static tServiceNameMap aServiceNameMap{
+ {"com.sun.star.drawing.DashTable", SERVICE_DASH_TABLE},
+ {"com.sun.star.drawing.GradientTable", SERVICE_GRADIENT_TABLE},
+ {"com.sun.star.drawing.HatchTable", SERVICE_HATCH_TABLE},
+ {"com.sun.star.drawing.BitmapTable", SERVICE_BITMAP_TABLE},
+ {"com.sun.star.drawing.TransparencyGradientTable", SERVICE_TRANSP_GRADIENT_TABLE},
+ {"com.sun.star.drawing.MarkerTable", SERVICE_MARKER_TABLE},
+ {"com.sun.star.xml.NamespaceMap", SERVICE_NAMESPACE_MAP}};
+ return aServiceNameMap;
+}
+}
+// ____ XMultiServiceFactory ____
+Reference< uno::XInterface > SAL_CALL ChartModel::createInstance( const OUString& rServiceSpecifier )
+{
+ tServiceNameMap & rMap = lcl_getStaticServiceNameMap();
+
+ tServiceNameMap::const_iterator aIt( rMap.find( rServiceSpecifier ));
+ if( aIt != rMap.end())
+ {
+ switch( (*aIt).second )
+ {
+ case SERVICE_DASH_TABLE:
+ case SERVICE_GRADIENT_TABLE:
+ case SERVICE_HATCH_TABLE:
+ case SERVICE_BITMAP_TABLE:
+ case SERVICE_TRANSP_GRADIENT_TABLE:
+ case SERVICE_MARKER_TABLE:
+ {
+ if(!mxChartView.is())
+ {
+ mxChartView = new ChartView( m_xContext, *this);
+ }
+ return mxChartView->createInstance( rServiceSpecifier );
+ }
+ break;
+ case SERVICE_NAMESPACE_MAP:
+ return static_cast<cppu::OWeakObject*>(m_xXMLNamespaceMap.get());
+ }
+ }
+ else if(rServiceSpecifier == CHART_VIEW_SERVICE_NAME)
+ {
+ if(!mxChartView.is())
+ {
+ mxChartView = new ChartView( m_xContext, *this);
+ }
+
+ return static_cast< ::cppu::OWeakObject* >( mxChartView.get() );
+ }
+ else
+ {
+ if( m_xOldModelAgg.is() )
+ {
+ Any aAny = m_xOldModelAgg->queryAggregation( cppu::UnoType<lang::XMultiServiceFactory>::get());
+ uno::Reference< lang::XMultiServiceFactory > xOldModelFactory;
+ if( (aAny >>= xOldModelFactory) && xOldModelFactory.is() )
+ {
+ return xOldModelFactory->createInstance( rServiceSpecifier );
+ }
+ }
+ }
+ return nullptr;
+}
+
+Reference< uno::XInterface > SAL_CALL ChartModel::createInstanceWithArguments(
+ const OUString& rServiceSpecifier , const Sequence< Any >& Arguments )
+{
+ OSL_ENSURE( Arguments.hasElements(), "createInstanceWithArguments: Warning: Arguments are ignored" );
+ return createInstance( rServiceSpecifier );
+}
+
+Sequence< OUString > SAL_CALL ChartModel::getAvailableServiceNames()
+{
+ uno::Sequence< OUString > aResult;
+
+ if( m_xOldModelAgg.is())
+ {
+ Any aAny = m_xOldModelAgg->queryAggregation( cppu::UnoType<lang::XMultiServiceFactory>::get());
+ uno::Reference< lang::XMultiServiceFactory > xOldModelFactory;
+ if( (aAny >>= xOldModelFactory) && xOldModelFactory.is() )
+ {
+ return xOldModelFactory->getAvailableServiceNames();
+ }
+ }
+ return aResult;
+}
+
+Reference< util::XNumberFormatsSupplier > const & ChartModel::getNumberFormatsSupplier()
+{
+ if( !m_xNumberFormatsSupplier.is() )
+ {
+ if( !m_xOwnNumberFormatsSupplier.is() )
+ {
+ m_apSvNumberFormatter.reset( new SvNumberFormatter( m_xContext, LANGUAGE_SYSTEM ) );
+ m_xOwnNumberFormatsSupplier = new SvNumberFormatsSupplierObj( m_apSvNumberFormatter.get() );
+ //pOwnNumberFormatter->ChangeStandardPrec( 15 ); todo?
+ }
+ m_xNumberFormatsSupplier = m_xOwnNumberFormatsSupplier;
+ }
+ return m_xNumberFormatsSupplier;
+}
+
+// ____ XUnoTunnel ___
+::sal_Int64 SAL_CALL ChartModel::getSomething( const Sequence< ::sal_Int8 >& aIdentifier )
+{
+ if( comphelper::isUnoTunnelId<SvNumberFormatsSupplierObj>(aIdentifier) )
+ {
+ Reference< lang::XUnoTunnel > xTunnel( getNumberFormatsSupplier(), uno::UNO_QUERY );
+ if( xTunnel.is() )
+ return xTunnel->getSomething( aIdentifier );
+ }
+ return 0;
+}
+
+// ____ XNumberFormatsSupplier ____
+uno::Reference< beans::XPropertySet > SAL_CALL ChartModel::getNumberFormatSettings()
+{
+ Reference< util::XNumberFormatsSupplier > xSupplier( getNumberFormatsSupplier() );
+ if( xSupplier.is() )
+ return xSupplier->getNumberFormatSettings();
+ return uno::Reference< beans::XPropertySet >();
+}
+
+uno::Reference< util::XNumberFormats > SAL_CALL ChartModel::getNumberFormats()
+{
+ Reference< util::XNumberFormatsSupplier > xSupplier( getNumberFormatsSupplier() );
+ if( xSupplier.is() )
+ return xSupplier->getNumberFormats();
+ return uno::Reference< util::XNumberFormats >();
+}
+
+// ____ XChild ____
+Reference< uno::XInterface > SAL_CALL ChartModel::getParent()
+{
+ return Reference< uno::XInterface >(m_xParent,uno::UNO_QUERY);
+}
+
+void SAL_CALL ChartModel::setParent( const Reference< uno::XInterface >& Parent )
+{
+ if( Parent != m_xParent )
+ m_xParent.set( Parent, uno::UNO_QUERY );
+}
+
+// ____ XDataSource ____
+uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > SAL_CALL ChartModel::getDataSequences()
+{
+ rtl::Reference< DataSource > xSource = DataSourceHelper::getUsedData( *this );
+ if( xSource.is())
+ return xSource->getDataSequences();
+
+ return uno::Sequence< Reference< chart2::data::XLabeledDataSequence > >();
+}
+
+//XDumper
+OUString SAL_CALL ChartModel::dump()
+{
+ uno::Reference< qa::XDumper > xDumper(
+ createInstance( CHART_VIEW_SERVICE_NAME ), uno::UNO_QUERY );
+ if (xDumper.is())
+ return xDumper->dump();
+
+ return OUString();
+}
+
+void ChartModel::setTimeBasedRange(sal_Int32 nStart, sal_Int32 nEnd)
+{
+ mnStart = nStart;
+ mnEnd = nEnd;
+ mbTimeBased = true;
+}
+
+void ChartModel::update()
+{
+ if(!mxChartView.is())
+ {
+ mxChartView = new ChartView( m_xContext, *this);
+ }
+ mxChartView->setViewDirty();
+ mxChartView->update();
+}
+
+bool ChartModel::isDataFromSpreadsheet()
+{
+ return !isDataFromPivotTable() && !hasInternalDataProvider();
+}
+
+bool ChartModel::isDataFromPivotTable() const
+{
+ uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(m_xDataProvider, uno::UNO_QUERY);
+ return xPivotTableDataProvider.is();
+}
+
+} // namespace chart
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_chart2_ChartModel_get_implementation(css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ::chart::ChartModel(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */