1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <servicenames.hxx>
22 #include <DataSourceHelper.hxx>
23 #include <ChartModelHelper.hxx>
24 #include <DisposeHelper.hxx>
25 #include <ControllerLockGuard.hxx>
26 #include <ObjectIdentifier.hxx>
27 #include "PageBackground.hxx"
28 #include <CloneHelper.hxx>
29 #include <NameContainer.hxx>
30 #include "UndoManager.hxx"
31 #include <ChartView.hxx>
32 #include <PopupRequest.hxx>
33 #include <ModifyListenerHelper.hxx>
35 #include <com/sun/star/chart/ChartDataRowSource.hpp>
36 #include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
38 #include <comphelper/processfactory.hxx>
39 #include <comphelper/propertysequence.hxx>
40 #include <cppuhelper/supportsservice.hxx>
42 #include <svl/numuno.hxx>
43 #include <com/sun/star/lang/DisposedException.hpp>
44 #include <com/sun/star/lang/XInitialization.hpp>
45 #include <com/sun/star/view/XSelectionSupplier.hpp>
46 #include <com/sun/star/embed/EmbedMapUnits.hpp>
47 #include <com/sun/star/embed/Aspects.hpp>
48 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
49 #include <com/sun/star/datatransfer/XTransferable.hpp>
50 #include <com/sun/star/drawing/XShapes.hpp>
51 #include <com/sun/star/document/DocumentProperties.hpp>
52 #include <com/sun/star/util/CloseVetoException.hpp>
53 #include <com/sun/star/util/XModifyBroadcaster.hpp>
54 #include <com/sun/star/chart2/XChartTypeTemplate.hpp>
56 #include <sal/log.hxx>
57 #include <svl/zforlist.hxx>
58 #include <tools/diagnose_ex.h>
59 #include <libxml/xmlwriter.h>
61 using ::com::sun::star::uno::Sequence
;
62 using ::com::sun::star::uno::Reference
;
63 using ::com::sun::star::uno::Any
;
64 using ::osl::MutexGuard
;
66 using namespace ::com::sun::star
;
67 using namespace ::apphelper
;
68 using namespace ::chart::CloneHelper
;
72 constexpr OUStringLiteral
lcl_aGDIMetaFileMIMEType(
73 u
"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"");
74 constexpr OUStringLiteral
lcl_aGDIMetaFileMIMETypeHighContrast(
75 u
"application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"");
77 } // anonymous namespace
79 // ChartModel Constructor and Destructor
84 ChartModel::ChartModel(uno::Reference
<uno::XComponentContext
> const & xContext
)
85 : m_aLifeTimeManager( this, this )
86 , m_bReadOnly( false )
87 , m_bModified( false )
89 , m_bUpdateNotificationsPending(false)
91 , m_aControllers( m_aModelMutex
)
92 , m_nControllerLockCount(0)
93 , m_xContext( xContext
)
94 , m_aVisualAreaSize( ChartModelHelper::getDefaultPageSize() )
95 , m_xPageBackground( new PageBackground
)
96 , m_xXMLNamespaceMap( createNameContainer( ::cppu::UnoType
<OUString
>::get(),
97 "com.sun.star.xml.NamespaceMap", "com.sun.star.comp.chart.XMLNameSpaceMap" ) )
101 osl_atomic_increment(&m_refCount
);
104 m_xContext
->getServiceManager()->createInstanceWithContext(
105 CHART_CHARTAPIWRAPPER_SERVICE_NAME
,
106 m_xContext
), uno::UNO_QUERY_THROW
);
107 m_xOldModelAgg
->setDelegator( *this );
111 ModifyListenerHelper::addListener( m_xPageBackground
, this );
112 m_xChartTypeManager
.set( xContext
->getServiceManager()->createInstanceWithContext(
113 "com.sun.star.chart2.ChartTypeManager", m_xContext
), uno::UNO_QUERY
);
115 osl_atomic_decrement(&m_refCount
);
118 ChartModel::ChartModel( const ChartModel
& rOther
)
119 : impl::ChartModel_Base(rOther
)
120 , m_aLifeTimeManager( this, this )
121 , m_bReadOnly( rOther
.m_bReadOnly
)
122 , m_bModified( rOther
.m_bModified
)
124 , m_bUpdateNotificationsPending(false)
125 , mbTimeBased(rOther
.mbTimeBased
)
126 , m_aResource( rOther
.m_aResource
)
127 , m_aMediaDescriptor( rOther
.m_aMediaDescriptor
)
128 , m_aControllers( m_aModelMutex
)
129 , m_nControllerLockCount(0)
130 , m_xContext( rOther
.m_xContext
)
131 // @note: the old model aggregate must not be shared with other models if it
132 // is, you get mutex deadlocks
133 //, m_xOldModelAgg( nullptr ) //rOther.m_xOldModelAgg )
134 // m_xStorage( nullptr ) //rOther.m_xStorage )
135 , m_aVisualAreaSize( rOther
.m_aVisualAreaSize
)
136 , m_aGraphicObjectVector( rOther
.m_aGraphicObjectVector
)
137 , m_xDataProvider( rOther
.m_xDataProvider
)
138 , m_xInternalDataProvider( rOther
.m_xInternalDataProvider
)
139 , mnStart(rOther
.mnStart
)
140 , mnEnd(rOther
.mnEnd
)
142 osl_atomic_increment(&m_refCount
);
145 m_xContext
->getServiceManager()->createInstanceWithContext(
146 CHART_CHARTAPIWRAPPER_SERVICE_NAME
,
147 m_xContext
), uno::UNO_QUERY_THROW
);
148 m_xOldModelAgg
->setDelegator( *this );
150 Reference
< util::XModifyListener
> xListener
;
151 Reference
< chart2::XTitle
> xNewTitle
= CreateRefClone
< chart2::XTitle
>()( rOther
.m_xTitle
);
152 Reference
< chart2::XDiagram
> xNewDiagram
= CreateRefClone
< chart2::XDiagram
>()( rOther
.m_xDiagram
);
153 Reference
< beans::XPropertySet
> xNewPageBackground
= CreateRefClone
< beans::XPropertySet
>()( rOther
.m_xPageBackground
);
154 Reference
< chart2::XChartTypeManager
> xChartTypeManager
= CreateRefClone
< chart2::XChartTypeManager
>()( rOther
.m_xChartTypeManager
);
155 Reference
< container::XNameAccess
> xXMLNamespaceMap
= CreateRefClone
< container::XNameAccess
>()( rOther
.m_xXMLNamespaceMap
);
158 MutexGuard
aGuard( m_aModelMutex
);
160 m_xTitle
= xNewTitle
;
161 m_xDiagram
= xNewDiagram
;
162 m_xPageBackground
= xNewPageBackground
;
163 m_xChartTypeManager
= xChartTypeManager
;
164 m_xXMLNamespaceMap
= xXMLNamespaceMap
;
167 ModifyListenerHelper::addListener( xNewTitle
, xListener
);
168 ModifyListenerHelper::addListener( xNewDiagram
, xListener
);
169 ModifyListenerHelper::addListener( xNewPageBackground
, xListener
);
172 osl_atomic_decrement(&m_refCount
);
175 ChartModel::~ChartModel()
177 if( m_xOldModelAgg
.is())
178 m_xOldModelAgg
->setDelegator( nullptr );
181 void SAL_CALL
ChartModel::initialize( const Sequence
< Any
>& /*rArguments*/ )
183 //#i113722# avoid duplicate creation
185 //maybe additional todo?:
186 //support argument "EmbeddedObject"?
187 //support argument "EmbeddedScriptSupport"?
188 //support argument "DocumentRecoverySupport"?
191 css::uno::Reference
< css::uno::XInterface
> ChartModel::getChartView() const
193 return static_cast< ::cppu::OWeakObject
* >( mxChartView
.get() );
198 OUString
ChartModel::impl_g_getLocation()
201 LifeTimeGuard
aGuard(m_aLifeTimeManager
);
202 if(!aGuard
.startApiCall())
203 return OUString(); //behave passive if already disposed or closed or throw exception @todo?
208 bool ChartModel::impl_isControllerConnected( const uno::Reference
< frame::XController
>& xController
)
212 std::vector
< uno::Reference
<uno::XInterface
> > aSeq
= m_aControllers
.getElements();
213 for( const auto & r
: aSeq
)
215 if( r
== xController
)
219 catch (const uno::Exception
&)
225 uno::Reference
< frame::XController
> ChartModel::impl_getCurrentController()
227 //@todo? hold only weak references to controllers
229 // get the last active controller of this model
230 if( m_xCurrentController
.is() )
231 return m_xCurrentController
;
233 // get the first controller of this model
234 if( m_aControllers
.getLength() )
236 uno::Reference
<uno::XInterface
> xI
= m_aControllers
.getElements()[0];
237 return uno::Reference
<frame::XController
>( xI
, uno::UNO_QUERY
);
240 //return nothing if no controllers are connected at all
241 return uno::Reference
< frame::XController
> ();
244 void ChartModel::impl_notifyCloseListeners()
246 ::cppu::OInterfaceContainerHelper
* pIC
= m_aLifeTimeManager
.m_aListenerContainer
247 .getContainer( cppu::UnoType
<util::XCloseListener
>::get());
250 lang::EventObject
aEvent( static_cast< lang::XComponent
*>(this) );
251 ::cppu::OInterfaceIteratorHelper
aIt( *pIC
);
252 while( aIt
.hasMoreElements() )
254 uno::Reference
< util::XCloseListener
> xListener( aIt
.next(), uno::UNO_QUERY
);
256 xListener
->notifyClosing( aEvent
);
261 void ChartModel::impl_adjustAdditionalShapesPositionAndSize( const awt::Size
& aVisualAreaSize
)
263 uno::Reference
< beans::XPropertySet
> xProperties( static_cast< ::cppu::OWeakObject
* >( this ), uno::UNO_QUERY
);
264 if ( !xProperties
.is() )
267 uno::Reference
< drawing::XShapes
> xShapes
;
268 xProperties
->getPropertyValue( "AdditionalShapes" ) >>= xShapes
;
272 sal_Int32 nCount
= xShapes
->getCount();
273 for ( sal_Int32 i
= 0; i
< nCount
; ++i
)
275 Reference
< drawing::XShape
> xShape
;
276 if ( xShapes
->getByIndex( i
) >>= xShape
)
280 awt::Point
aPos( xShape
->getPosition() );
281 awt::Size
aSize( xShape
->getSize() );
283 double fWidth
= static_cast< double >( aVisualAreaSize
.Width
) / m_aVisualAreaSize
.Width
;
284 double fHeight
= static_cast< double >( aVisualAreaSize
.Height
) / m_aVisualAreaSize
.Height
;
286 aPos
.X
= static_cast< tools::Long
>( aPos
.X
* fWidth
);
287 aPos
.Y
= static_cast< tools::Long
>( aPos
.Y
* fHeight
);
288 aSize
.Width
= static_cast< tools::Long
>( aSize
.Width
* fWidth
);
289 aSize
.Height
= static_cast< tools::Long
>( aSize
.Height
* fHeight
);
291 xShape
->setPosition( aPos
);
292 xShape
->setSize( aSize
);
298 // lang::XServiceInfo
300 OUString SAL_CALL
ChartModel::getImplementationName()
302 return CHART_MODEL_SERVICE_IMPLEMENTATION_NAME
;
305 sal_Bool SAL_CALL
ChartModel::supportsService( const OUString
& rServiceName
)
307 return cppu::supportsService(this, rServiceName
);
310 css::uno::Sequence
< OUString
> SAL_CALL
ChartModel::getSupportedServiceNames()
313 CHART_MODEL_SERVICE_NAME
,
314 "com.sun.star.document.OfficeDocument",
315 "com.sun.star.chart.ChartDocument"
319 // frame::XModel (required interface)
321 sal_Bool SAL_CALL
ChartModel::attachResource( const OUString
& rURL
322 , const uno::Sequence
< beans::PropertyValue
>& rMediaDescriptor
)
325 The method attachResource() is used by the frame loader implementations
326 to inform the model about its URL and MediaDescriptor.
329 LifeTimeGuard
aGuard(m_aLifeTimeManager
);
330 if(!aGuard
.startApiCall())
331 return false; //behave passive if already disposed or closed or throw exception @todo?
334 if(!m_aResource
.isEmpty())//we have a resource already //@todo? or is setting a new resource allowed?
337 m_aMediaDescriptor
= rMediaDescriptor
;
339 //@todo ? check rURL ??
340 //@todo ? evaluate m_aMediaDescriptor;
341 //@todo ? ... ??? --> nothing, this method is only for setting information
346 OUString SAL_CALL
ChartModel::getURL()
348 return impl_g_getLocation();
351 uno::Sequence
< beans::PropertyValue
> SAL_CALL
ChartModel::getArgs()
354 The method getArgs() returns a sequence of property values
355 that report the resource description according to com.sun.star.document.MediaDescriptor,
356 specified on loading or saving with storeAsURL.
359 LifeTimeGuard
aGuard(m_aLifeTimeManager
);
360 if(!aGuard
.startApiCall())
361 return uno::Sequence
< beans::PropertyValue
>(); //behave passive if already disposed or closed or throw exception @todo?
364 return m_aMediaDescriptor
;
367 void SAL_CALL
ChartModel::connectController( const uno::Reference
< frame::XController
>& xController
)
369 //@todo? this method is declared as oneway -> ...?
371 LifeTimeGuard
aGuard(m_aLifeTimeManager
);
372 if(!aGuard
.startApiCall())
373 return ; //behave passive if already disposed or closed
377 m_aControllers
.addInterface(xController
);
380 void SAL_CALL
ChartModel::disconnectController( const uno::Reference
< frame::XController
>& xController
)
382 //@todo? this method is declared as oneway -> ...?
384 LifeTimeGuard
aGuard(m_aLifeTimeManager
);
385 if(!aGuard
.startApiCall())
386 return; //behave passive if already disposed or closed
388 //--remove controller
389 m_aControllers
.removeInterface(xController
);
391 //case: current controller is disconnected:
392 if( m_xCurrentController
== xController
)
393 m_xCurrentController
.clear();
395 DisposeHelper::DisposeAndClear( m_xRangeHighlighter
);
396 DisposeHelper::DisposeAndClear(m_xPopupRequest
);
399 void SAL_CALL
ChartModel::lockControllers()
402 suspends some notifications to the controllers which are used for display updates.
404 The calls to lockControllers() and unlockControllers() may be nested
405 and even overlapping, but they must be in pairs. While there is at least one lock
406 remaining, some notifications for display updates are not broadcasted.
409 //@todo? this method is declared as oneway -> ...?
411 LifeTimeGuard
aGuard(m_aLifeTimeManager
);
412 if(!aGuard
.startApiCall())
413 return; //behave passive if already disposed or closed or throw exception @todo?
414 ++m_nControllerLockCount
;
417 void SAL_CALL
ChartModel::unlockControllers()
420 resumes the notifications which were suspended by lockControllers() .
422 The calls to lockControllers() and unlockControllers() may be nested
423 and even overlapping, but they must be in pairs. While there is at least one lock
424 remaining, some notifications for display updates are not broadcasted.
427 //@todo? this method is declared as oneway -> ...?
429 LifeTimeGuard
aGuard(m_aLifeTimeManager
);
430 if(!aGuard
.startApiCall())
431 return; //behave passive if already disposed or closed or throw exception @todo?
432 if( m_nControllerLockCount
== 0 )
434 SAL_WARN("chart2", "ChartModel: unlockControllers called with m_nControllerLockCount == 0" );
437 --m_nControllerLockCount
;
438 if( m_nControllerLockCount
== 0 && m_bUpdateNotificationsPending
)
441 impl_notifyModifiedListeners();
445 sal_Bool SAL_CALL
ChartModel::hasControllersLocked()
447 LifeTimeGuard
aGuard(m_aLifeTimeManager
);
448 if(!aGuard
.startApiCall())
449 return false; //behave passive if already disposed or closed or throw exception @todo?
450 return ( m_nControllerLockCount
!= 0 ) ;
453 uno::Reference
< frame::XController
> SAL_CALL
ChartModel::getCurrentController()
455 LifeTimeGuard
aGuard(m_aLifeTimeManager
);
456 if(!aGuard
.startApiCall())
457 throw lang::DisposedException(
458 "getCurrentController was called on an already disposed or closed model",
459 static_cast< ::cppu::OWeakObject
* >(this) );
461 return impl_getCurrentController();
464 void SAL_CALL
ChartModel::setCurrentController( const uno::Reference
< frame::XController
>& xController
)
466 LifeTimeGuard
aGuard(m_aLifeTimeManager
);
467 if(!aGuard
.startApiCall())
468 throw lang::DisposedException(
469 "setCurrentController was called on an already disposed or closed model",
470 static_cast< ::cppu::OWeakObject
* >(this) );
472 //OSL_ENSURE( impl_isControllerConnected(xController), "setCurrentController is called with a Controller which is not connected" );
473 if(!impl_isControllerConnected(xController
))
474 throw container::NoSuchElementException(
475 "setCurrentController is called with a Controller which is not connected",
476 static_cast< ::cppu::OWeakObject
* >(this) );
478 m_xCurrentController
= xController
;
480 DisposeHelper::DisposeAndClear( m_xRangeHighlighter
);
481 DisposeHelper::DisposeAndClear(m_xPopupRequest
);
484 uno::Reference
< uno::XInterface
> SAL_CALL
ChartModel::getCurrentSelection()
486 LifeTimeGuard
aGuard(m_aLifeTimeManager
);
487 if(!aGuard
.startApiCall())
488 throw lang::DisposedException(
489 "getCurrentSelection was called on an already disposed or closed model",
490 static_cast< ::cppu::OWeakObject
* >(this) );
492 uno::Reference
< uno::XInterface
> xReturn
;
493 uno::Reference
< frame::XController
> xController
= impl_getCurrentController();
496 if( xController
.is() )
498 uno::Reference
< view::XSelectionSupplier
> xSelectionSupl( xController
, uno::UNO_QUERY
);
499 if ( xSelectionSupl
.is() )
501 uno::Any aSel
= xSelectionSupl
->getSelection();
503 if( aSel
>>= aObjectCID
)
504 xReturn
.set( ObjectIdentifier::getObjectPropertySet( aObjectCID
, Reference
< XChartDocument
>(this)));
510 // lang::XComponent (base of XModel)
511 void SAL_CALL
ChartModel::dispose()
513 Reference
< XInterface
> xKeepAlive( *this );
515 //This object should release all resources and references in the
516 //easiest possible manner
517 //This object must notify all registered listeners using the method
518 //<member>XEventListener::disposing</member>
521 if( !m_aLifeTimeManager
.dispose() )
524 //--release all resources and references
527 if ( m_xDiagram
.is() )
528 ModifyListenerHelper::removeListener( m_xDiagram
, this );
530 if ( m_xDataProvider
.is() )
532 Reference
<util::XModifyBroadcaster
> xModifyBroadcaster( m_xDataProvider
, uno::UNO_QUERY
);
533 if ( xModifyBroadcaster
.is() )
534 xModifyBroadcaster
->removeModifyListener( this );
537 m_xDataProvider
.clear();
538 m_xInternalDataProvider
.clear();
539 m_xNumberFormatsSupplier
.clear();
540 DisposeHelper::DisposeAndClear( m_xOwnNumberFormatsSupplier
);
541 DisposeHelper::DisposeAndClear( m_xChartTypeManager
);
542 DisposeHelper::DisposeAndClear( m_xDiagram
);
543 DisposeHelper::DisposeAndClear( m_xTitle
);
544 DisposeHelper::DisposeAndClear( m_xPageBackground
);
545 DisposeHelper::DisposeAndClear( m_xXMLNamespaceMap
);
548 // just clear, don't dispose - we're not the owner
550 if ( m_pUndoManager
.is() )
551 m_pUndoManager
->disposing();
552 m_pUndoManager
.clear();
553 // that's important, since the UndoManager implementation delegates its ref counting to ourself.
555 if( m_xOldModelAgg
.is()) // #i120828#, to release cyclic reference to ChartModel object
556 m_xOldModelAgg
->setDelegator( nullptr );
558 m_aControllers
.disposeAndClear( lang::EventObject( static_cast< cppu::OWeakObject
* >( this )));
559 m_xCurrentController
.clear();
561 DisposeHelper::DisposeAndClear( m_xRangeHighlighter
);
562 DisposeHelper::DisposeAndClear(m_xPopupRequest
);
564 if( m_xOldModelAgg
.is())
565 m_xOldModelAgg
->setDelegator( nullptr );
568 void SAL_CALL
ChartModel::addEventListener( const uno::Reference
< lang::XEventListener
> & xListener
)
570 if( m_aLifeTimeManager
.impl_isDisposedOrClosed() )
571 return; //behave passive if already disposed or closed
573 m_aLifeTimeManager
.m_aListenerContainer
.addInterface( cppu::UnoType
<lang::XEventListener
>::get(), xListener
);
576 void SAL_CALL
ChartModel::removeEventListener( const uno::Reference
< lang::XEventListener
> & xListener
)
578 if( m_aLifeTimeManager
.impl_isDisposedOrClosed(false) )
579 return; //behave passive if already disposed or closed
581 m_aLifeTimeManager
.m_aListenerContainer
.removeInterface( cppu::UnoType
<lang::XEventListener
>::get(), xListener
);
584 // util::XCloseBroadcaster (base of XCloseable)
585 void SAL_CALL
ChartModel::addCloseListener( const uno::Reference
< util::XCloseListener
> & xListener
)
587 m_aLifeTimeManager
.g_addCloseListener( xListener
);
590 void SAL_CALL
ChartModel::removeCloseListener( const uno::Reference
< util::XCloseListener
> & xListener
)
592 if( m_aLifeTimeManager
.impl_isDisposedOrClosed(false) )
593 return; //behave passive if already disposed or closed
595 m_aLifeTimeManager
.m_aListenerContainer
.removeInterface( cppu::UnoType
<util::XCloseListener
>::get(), xListener
);
599 void SAL_CALL
ChartModel::close( sal_Bool bDeliverOwnership
)
603 if( !m_aLifeTimeManager
.g_close_startTryClose( bDeliverOwnership
) )
605 //no mutex is acquired
607 // At the end of this method may we must dispose ourself ...
608 // and may nobody from outside hold a reference to us ...
609 // then it's a good idea to do that by ourself.
610 uno::Reference
< uno::XInterface
> xSelfHold( static_cast< ::cppu::OWeakObject
* >(this) );
612 //the listeners have had no veto
613 //check whether we self can close
615 util::CloseVetoException
aVetoException(
616 "the model itself could not be closed",
617 static_cast< ::cppu::OWeakObject
* >(this) );
619 m_aLifeTimeManager
.g_close_isNeedToCancelLongLastingCalls( bDeliverOwnership
, aVetoException
);
621 m_aLifeTimeManager
.g_close_endTryClose_doClose();
623 // BM @todo: is it ok to call the listeners here?
624 impl_notifyCloseListeners();
627 // lang::XTypeProvider
628 uno::Sequence
< uno::Type
> SAL_CALL
ChartModel::getTypes()
630 uno::Reference
< lang::XTypeProvider
> xAggTypeProvider
;
631 if( (m_xOldModelAgg
->queryAggregation( cppu::UnoType
<decltype(xAggTypeProvider
)>::get()) >>= xAggTypeProvider
)
632 && xAggTypeProvider
.is())
634 return comphelper::concatSequences(
635 impl::ChartModel_Base::getTypes(),
636 xAggTypeProvider
->getTypes());
639 return impl::ChartModel_Base::getTypes();
642 // document::XDocumentPropertiesSupplier
643 uno::Reference
< document::XDocumentProperties
> SAL_CALL
644 ChartModel::getDocumentProperties()
646 ::osl::MutexGuard
aGuard( m_aModelMutex
);
647 if ( !m_xDocumentProperties
.is() )
649 m_xDocumentProperties
.set( document::DocumentProperties::create( ::comphelper::getProcessComponentContext() ) );
651 return m_xDocumentProperties
;
654 // document::XDocumentPropertiesSupplier
655 Reference
< document::XUndoManager
> SAL_CALL
ChartModel::getUndoManager( )
657 ::osl::MutexGuard
aGuard( m_aModelMutex
);
658 if ( !m_pUndoManager
.is() )
659 m_pUndoManager
.set( new UndoManager( *this, m_aModelMutex
) );
660 return m_pUndoManager
.get();
663 // chart2::XChartDocument
665 uno::Reference
< chart2::XDiagram
> SAL_CALL
ChartModel::getFirstDiagram()
667 MutexGuard
aGuard( m_aModelMutex
);
671 void SAL_CALL
ChartModel::setFirstDiagram( const uno::Reference
< chart2::XDiagram
>& xDiagram
)
673 Reference
< chart2::XDiagram
> xOldDiagram
;
674 Reference
< util::XModifyListener
> xListener
;
676 MutexGuard
aGuard( m_aModelMutex
);
677 if( xDiagram
== m_xDiagram
)
679 xOldDiagram
= m_xDiagram
;
680 m_xDiagram
= xDiagram
;
683 //don't keep the mutex locked while calling out
684 ModifyListenerHelper::removeListener( xOldDiagram
, xListener
);
685 ModifyListenerHelper::addListener( xDiagram
, xListener
);
689 Reference
< chart2::data::XDataSource
> ChartModel::impl_createDefaultData()
691 Reference
< chart2::data::XDataSource
> xDataSource
;
692 if( hasInternalDataProvider() )
694 uno::Reference
< lang::XInitialization
> xIni(m_xInternalDataProvider
,uno::UNO_QUERY
);
697 //init internal dataprovider
699 uno::Sequence
< uno::Any
> aArgs(1);
700 beans::NamedValue
aParam( "CreateDefaultData" ,uno::Any(true) );
702 xIni
->initialize(aArgs
);
705 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
706 { "CellRangeRepresentation", uno::Any( OUString("all") ) },
707 { "HasCategories", uno::Any( true ) },
708 { "FirstCellAsLabel", uno::Any( true ) },
709 { "DataRowSource", uno::Any( css::chart::ChartDataRowSource_COLUMNS
) }
711 xDataSource
= m_xInternalDataProvider
->createDataSource( aArgs
);
717 void SAL_CALL
ChartModel::createInternalDataProvider( sal_Bool bCloneExistingData
)
719 // don't lock the mutex, because this call calls out to code that tries to
720 // lock the solar mutex. On the other hand, a paint locks the solar mutex
721 // and calls to the model lock the model's mutex => deadlock
722 // @todo: lock a separate mutex in the InternalData class
723 if( !hasInternalDataProvider() )
725 if( bCloneExistingData
)
726 m_xInternalDataProvider
= ChartModelHelper::createInternalDataProvider( this, true );
728 m_xInternalDataProvider
= ChartModelHelper::createInternalDataProvider( Reference
<XChartDocument
>(), true );
729 m_xDataProvider
.set( m_xInternalDataProvider
);
734 void ChartModel::removeDataProviders()
736 if (m_xInternalDataProvider
.is())
737 m_xInternalDataProvider
.clear();
738 if (m_xDataProvider
.is())
739 m_xDataProvider
.clear();
742 void ChartModel::dumpAsXml(xmlTextWriterPtr pWriter
) const
744 xmlTextWriterStartElement(pWriter
, BAD_CAST("ChartModel"));
745 xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
747 if (mxChartView
.is())
749 mxChartView
->dumpAsXml(pWriter
);
752 xmlTextWriterEndElement(pWriter
);
755 sal_Bool SAL_CALL
ChartModel::hasInternalDataProvider()
757 return m_xDataProvider
.is() && m_xInternalDataProvider
.is();
760 uno::Reference
< chart2::data::XDataProvider
> SAL_CALL
ChartModel::getDataProvider()
762 MutexGuard
aGuard( m_aModelMutex
);
763 return m_xDataProvider
;
766 // ____ XDataReceiver ____
768 void SAL_CALL
ChartModel::attachDataProvider( const uno::Reference
< chart2::data::XDataProvider
>& xDataProvider
)
771 MutexGuard
aGuard( m_aModelMutex
);
772 uno::Reference
< beans::XPropertySet
> xProp( xDataProvider
, uno::UNO_QUERY
);
777 bool bIncludeHiddenCells
= ChartModelHelper::isIncludeHiddenCells( Reference
< frame::XModel
>(this) );
778 xProp
->setPropertyValue("IncludeHiddenCells", uno::Any(bIncludeHiddenCells
));
780 catch (const beans::UnknownPropertyException
&)
785 uno::Reference
<util::XModifyBroadcaster
> xModifyBroadcaster(xDataProvider
, uno::UNO_QUERY
);
786 if (xModifyBroadcaster
.is())
788 xModifyBroadcaster
->addModifyListener(this);
791 m_xDataProvider
.set( xDataProvider
);
792 m_xInternalDataProvider
.clear();
794 //the numberformatter is kept independent of the data provider!
799 void SAL_CALL
ChartModel::attachNumberFormatsSupplier( const uno::Reference
< util::XNumberFormatsSupplier
>& xNewSupplier
)
802 MutexGuard
aGuard( m_aModelMutex
);
803 if( xNewSupplier
==m_xNumberFormatsSupplier
)
805 if( xNewSupplier
==m_xOwnNumberFormatsSupplier
)
807 if( m_xOwnNumberFormatsSupplier
.is() && xNewSupplier
.is() )
810 //merge missing numberformats from own to new formatter
812 else if( !xNewSupplier
.is() )
814 if( m_xNumberFormatsSupplier
.is() )
817 //merge missing numberformats from old numberformatter to own numberformatter
818 //create own numberformatter if necessary
822 m_xNumberFormatsSupplier
.set( xNewSupplier
);
823 m_xOwnNumberFormatsSupplier
.clear();
828 void SAL_CALL
ChartModel::setArguments( const Sequence
< beans::PropertyValue
>& aArguments
)
831 MutexGuard
aGuard( m_aModelMutex
);
832 if( !m_xDataProvider
.is() )
838 Reference
< chart2::data::XDataSource
> xDataSource( m_xDataProvider
->createDataSource( aArguments
) );
839 if( xDataSource
.is() )
841 Reference
< chart2::XDiagram
> xDia( getFirstDiagram() );
844 Reference
< chart2::XChartTypeTemplate
> xTemplate( impl_createDefaultChartTypeTemplate() );
846 setFirstDiagram( xTemplate
->createDiagramByDataSource( xDataSource
, aArguments
) );
849 xDia
->setDiagramData( xDataSource
, aArguments
);
852 catch (const lang::IllegalArgumentException
&)
856 catch (const uno::Exception
&)
858 DBG_UNHANDLED_EXCEPTION("chart2");
865 Sequence
< OUString
> SAL_CALL
ChartModel::getUsedRangeRepresentations()
867 return DataSourceHelper::getUsedDataRanges( Reference
< frame::XModel
>(this));
870 Reference
< chart2::data::XDataSource
> SAL_CALL
ChartModel::getUsedData()
872 return DataSourceHelper::getUsedData( Reference
< chart2::XChartDocument
>(this));
875 Reference
< chart2::data::XRangeHighlighter
> SAL_CALL
ChartModel::getRangeHighlighter()
877 if( ! m_xRangeHighlighter
.is())
879 uno::Reference
< view::XSelectionSupplier
> xSelSupp( getCurrentController(), uno::UNO_QUERY
);
881 m_xRangeHighlighter
.set( ChartModelHelper::createRangeHighlighter( xSelSupp
));
883 return m_xRangeHighlighter
;
886 Reference
<awt::XRequestCallback
> SAL_CALL
ChartModel::getPopupRequest()
888 if (!m_xPopupRequest
.is())
889 m_xPopupRequest
.set(new PopupRequest
);
890 return m_xPopupRequest
;
893 Reference
< chart2::XChartTypeTemplate
> ChartModel::impl_createDefaultChartTypeTemplate()
895 Reference
< chart2::XChartTypeTemplate
> xTemplate
;
896 Reference
< lang::XMultiServiceFactory
> xFact( m_xChartTypeManager
, uno::UNO_QUERY
);
898 xTemplate
.set( xFact
->createInstance( "com.sun.star.chart2.template.Column" ), uno::UNO_QUERY
);
902 void SAL_CALL
ChartModel::setChartTypeManager( const uno::Reference
< chart2::XChartTypeManager
>& xNewManager
)
905 MutexGuard
aGuard( m_aModelMutex
);
906 m_xChartTypeManager
= xNewManager
;
911 uno::Reference
< chart2::XChartTypeManager
> SAL_CALL
ChartModel::getChartTypeManager()
913 MutexGuard
aGuard( m_aModelMutex
);
914 return m_xChartTypeManager
;
917 uno::Reference
< beans::XPropertySet
> SAL_CALL
ChartModel::getPageBackground()
919 MutexGuard
aGuard( m_aModelMutex
);
920 return m_xPageBackground
;
923 void SAL_CALL
ChartModel::createDefaultChart()
925 insertDefaultChart();
929 uno::Reference
< chart2::XTitle
> SAL_CALL
ChartModel::getTitleObject()
931 MutexGuard
aGuard( m_aModelMutex
);
935 void SAL_CALL
ChartModel::setTitleObject( const uno::Reference
< chart2::XTitle
>& xTitle
)
938 MutexGuard
aGuard( m_aModelMutex
);
940 ModifyListenerHelper::removeListener( m_xTitle
, this );
942 ModifyListenerHelper::addListener( m_xTitle
, this );
947 // ____ XInterface (for old API wrapper) ____
948 uno::Any SAL_CALL
ChartModel::queryInterface( const uno::Type
& aType
)
950 uno::Any
aResult( impl::ChartModel_Base::queryInterface( aType
));
952 if( ! aResult
.hasValue())
954 // try old API wrapper
957 if( m_xOldModelAgg
.is())
958 aResult
= m_xOldModelAgg
->queryAggregation( aType
);
960 catch (const uno::Exception
&)
962 DBG_UNHANDLED_EXCEPTION("chart2");
969 // ____ XCloneable ____
970 Reference
< util::XCloneable
> SAL_CALL
ChartModel::createClone()
972 return Reference
< util::XCloneable
>( new ChartModel( *this ));
975 // ____ XVisualObject ____
976 void SAL_CALL
ChartModel::setVisualAreaSize( ::sal_Int64 nAspect
, const awt::Size
& aSize
)
978 if( nAspect
== embed::Aspects::MSOLE_CONTENT
)
980 ControllerLockGuard
aLockGuard( *this );
982 (m_aVisualAreaSize
.Width
!= aSize
.Width
||
983 m_aVisualAreaSize
.Height
!= aSize
.Height
);
985 // #i12587# support for shapes in chart
988 impl_adjustAdditionalShapesPositionAndSize( aSize
);
991 m_aVisualAreaSize
= aSize
;
997 OSL_FAIL( "setVisualAreaSize: Aspect not implemented yet.");
1001 awt::Size SAL_CALL
ChartModel::getVisualAreaSize( ::sal_Int64 nAspect
)
1003 OSL_ENSURE( nAspect
== embed::Aspects::MSOLE_CONTENT
,
1004 "No aspects other than content are supported" );
1005 // other possible aspects are MSOLE_THUMBNAIL, MSOLE_ICON and MSOLE_DOCPRINT
1007 return m_aVisualAreaSize
;
1010 embed::VisualRepresentation SAL_CALL
ChartModel::getPreferredVisualRepresentation( ::sal_Int64 nAspect
)
1012 OSL_ENSURE( nAspect
== embed::Aspects::MSOLE_CONTENT
,
1013 "No aspects other than content are supported" );
1015 embed::VisualRepresentation aResult
;
1019 Sequence
< sal_Int8
> aMetafile
;
1021 //get view from old api wrapper
1022 Reference
< datatransfer::XTransferable
> xTransferable(
1023 createInstance( CHART_VIEW_SERVICE_NAME
), uno::UNO_QUERY
);
1024 if( xTransferable
.is() )
1026 datatransfer::DataFlavor
aDataFlavor( lcl_aGDIMetaFileMIMEType
,
1028 cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() );
1030 uno::Any
aData( xTransferable
->getTransferData( aDataFlavor
) );
1031 aData
>>= aMetafile
;
1034 aResult
.Flavor
.MimeType
= lcl_aGDIMetaFileMIMEType
;
1035 aResult
.Flavor
.DataType
= cppu::UnoType
<decltype(aMetafile
)>::get();
1037 aResult
.Data
<<= aMetafile
;
1039 catch (const uno::Exception
&)
1041 DBG_UNHANDLED_EXCEPTION("chart2");
1047 ::sal_Int32 SAL_CALL
ChartModel::getMapUnit( ::sal_Int64 nAspect
)
1049 OSL_ENSURE( nAspect
== embed::Aspects::MSOLE_CONTENT
,
1050 "No aspects other than content are supported" );
1051 return embed::EmbedMapUnits::ONE_100TH_MM
;
1054 // ____ datatransfer::XTransferable ____
1055 uno::Any SAL_CALL
ChartModel::getTransferData( const datatransfer::DataFlavor
& aFlavor
)
1058 if( !isDataFlavorSupported( aFlavor
) )
1059 throw datatransfer::UnsupportedFlavorException(
1060 aFlavor
.MimeType
, static_cast< ::cppu::OWeakObject
* >( this ));
1064 //get view from old api wrapper
1065 Reference
< datatransfer::XTransferable
> xTransferable(
1066 createInstance( CHART_VIEW_SERVICE_NAME
), uno::UNO_QUERY
);
1067 if( xTransferable
.is() &&
1068 xTransferable
->isDataFlavorSupported( aFlavor
))
1070 aResult
= xTransferable
->getTransferData( aFlavor
);
1073 catch (const uno::Exception
&)
1075 DBG_UNHANDLED_EXCEPTION("chart2");
1081 Sequence
< datatransfer::DataFlavor
> SAL_CALL
ChartModel::getTransferDataFlavors()
1083 uno::Sequence
< datatransfer::DataFlavor
> aRet(1);
1085 aRet
[0] = datatransfer::DataFlavor( lcl_aGDIMetaFileMIMETypeHighContrast
,
1087 cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() );
1092 sal_Bool SAL_CALL
ChartModel::isDataFlavorSupported( const datatransfer::DataFlavor
& aFlavor
)
1094 return aFlavor
.MimeType
== lcl_aGDIMetaFileMIMETypeHighContrast
;
1102 SERVICE_GRADIENT_TABLE
,
1103 SERVICE_HATCH_TABLE
,
1104 SERVICE_BITMAP_TABLE
,
1105 SERVICE_TRANSP_GRADIENT_TABLE
,
1106 SERVICE_MARKER_TABLE
,
1107 SERVICE_NAMESPACE_MAP
1110 typedef std::map
< OUString
, enum eServiceType
> tServiceNameMap
;
1112 tServiceNameMap
& lcl_getStaticServiceNameMap()
1114 static tServiceNameMap aServiceNameMap
{
1115 {"com.sun.star.drawing.DashTable", SERVICE_DASH_TABLE
},
1116 {"com.sun.star.drawing.GradientTable", SERVICE_GRADIENT_TABLE
},
1117 {"com.sun.star.drawing.HatchTable", SERVICE_HATCH_TABLE
},
1118 {"com.sun.star.drawing.BitmapTable", SERVICE_BITMAP_TABLE
},
1119 {"com.sun.star.drawing.TransparencyGradientTable", SERVICE_TRANSP_GRADIENT_TABLE
},
1120 {"com.sun.star.drawing.MarkerTable", SERVICE_MARKER_TABLE
},
1121 {"com.sun.star.xml.NamespaceMap", SERVICE_NAMESPACE_MAP
}};
1122 return aServiceNameMap
;
1125 // ____ XMultiServiceFactory ____
1126 Reference
< uno::XInterface
> SAL_CALL
ChartModel::createInstance( const OUString
& rServiceSpecifier
)
1128 tServiceNameMap
& rMap
= lcl_getStaticServiceNameMap();
1130 tServiceNameMap::const_iterator
aIt( rMap
.find( rServiceSpecifier
));
1131 if( aIt
!= rMap
.end())
1133 switch( (*aIt
).second
)
1135 case SERVICE_DASH_TABLE
:
1136 case SERVICE_GRADIENT_TABLE
:
1137 case SERVICE_HATCH_TABLE
:
1138 case SERVICE_BITMAP_TABLE
:
1139 case SERVICE_TRANSP_GRADIENT_TABLE
:
1140 case SERVICE_MARKER_TABLE
:
1142 if(!mxChartView
.is())
1144 mxChartView
= new ChartView( m_xContext
, *this);
1146 return mxChartView
->createInstance( rServiceSpecifier
);
1149 case SERVICE_NAMESPACE_MAP
:
1150 return Reference
< uno::XInterface
>( m_xXMLNamespaceMap
);
1153 else if(rServiceSpecifier
== CHART_VIEW_SERVICE_NAME
)
1155 if(!mxChartView
.is())
1157 mxChartView
= new ChartView( m_xContext
, *this);
1160 return static_cast< ::cppu::OWeakObject
* >( mxChartView
.get() );
1164 if( m_xOldModelAgg
.is() )
1166 Any aAny
= m_xOldModelAgg
->queryAggregation( cppu::UnoType
<lang::XMultiServiceFactory
>::get());
1167 uno::Reference
< lang::XMultiServiceFactory
> xOldModelFactory
;
1168 if( (aAny
>>= xOldModelFactory
) && xOldModelFactory
.is() )
1170 return xOldModelFactory
->createInstance( rServiceSpecifier
);
1177 Reference
< uno::XInterface
> SAL_CALL
ChartModel::createInstanceWithArguments(
1178 const OUString
& rServiceSpecifier
, const Sequence
< Any
>& Arguments
)
1180 OSL_ENSURE( Arguments
.hasElements(), "createInstanceWithArguments: Warning: Arguments are ignored" );
1181 return createInstance( rServiceSpecifier
);
1184 Sequence
< OUString
> SAL_CALL
ChartModel::getAvailableServiceNames()
1186 uno::Sequence
< OUString
> aResult
;
1188 if( m_xOldModelAgg
.is())
1190 Any aAny
= m_xOldModelAgg
->queryAggregation( cppu::UnoType
<lang::XMultiServiceFactory
>::get());
1191 uno::Reference
< lang::XMultiServiceFactory
> xOldModelFactory
;
1192 if( (aAny
>>= xOldModelFactory
) && xOldModelFactory
.is() )
1194 return xOldModelFactory
->getAvailableServiceNames();
1200 Reference
< util::XNumberFormatsSupplier
> const & ChartModel::getNumberFormatsSupplier()
1202 if( !m_xNumberFormatsSupplier
.is() )
1204 if( !m_xOwnNumberFormatsSupplier
.is() )
1206 m_apSvNumberFormatter
.reset( new SvNumberFormatter( m_xContext
, LANGUAGE_SYSTEM
) );
1207 m_xOwnNumberFormatsSupplier
= new SvNumberFormatsSupplierObj( m_apSvNumberFormatter
.get() );
1208 //pOwnNumberFormatter->ChangeStandardPrec( 15 ); todo?
1210 m_xNumberFormatsSupplier
= m_xOwnNumberFormatsSupplier
;
1212 return m_xNumberFormatsSupplier
;
1215 // ____ XUnoTunnel ___
1216 ::sal_Int64 SAL_CALL
ChartModel::getSomething( const Sequence
< ::sal_Int8
>& aIdentifier
)
1218 if( isUnoTunnelId
<SvNumberFormatsSupplierObj
>(aIdentifier
) )
1220 Reference
< lang::XUnoTunnel
> xTunnel( getNumberFormatsSupplier(), uno::UNO_QUERY
);
1222 return xTunnel
->getSomething( aIdentifier
);
1227 // ____ XNumberFormatsSupplier ____
1228 uno::Reference
< beans::XPropertySet
> SAL_CALL
ChartModel::getNumberFormatSettings()
1230 Reference
< util::XNumberFormatsSupplier
> xSupplier( getNumberFormatsSupplier() );
1231 if( xSupplier
.is() )
1232 return xSupplier
->getNumberFormatSettings();
1233 return uno::Reference
< beans::XPropertySet
>();
1236 uno::Reference
< util::XNumberFormats
> SAL_CALL
ChartModel::getNumberFormats()
1238 Reference
< util::XNumberFormatsSupplier
> xSupplier( getNumberFormatsSupplier() );
1239 if( xSupplier
.is() )
1240 return xSupplier
->getNumberFormats();
1241 return uno::Reference
< util::XNumberFormats
>();
1245 Reference
< uno::XInterface
> SAL_CALL
ChartModel::getParent()
1247 return Reference
< uno::XInterface
>(m_xParent
,uno::UNO_QUERY
);
1250 void SAL_CALL
ChartModel::setParent( const Reference
< uno::XInterface
>& Parent
)
1252 if( Parent
!= m_xParent
)
1253 m_xParent
.set( Parent
, uno::UNO_QUERY
);
1256 // ____ XDataSource ____
1257 uno::Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > SAL_CALL
ChartModel::getDataSequences()
1259 Reference
< chart2::data::XDataSource
> xSource(
1260 DataSourceHelper::getUsedData( uno::Reference
< frame::XModel
>(this) ) );
1262 return xSource
->getDataSequences();
1264 return uno::Sequence
< Reference
< chart2::data::XLabeledDataSequence
> >();
1268 OUString SAL_CALL
ChartModel::dump()
1270 uno::Reference
< qa::XDumper
> xDumper(
1271 createInstance( CHART_VIEW_SERVICE_NAME
), uno::UNO_QUERY
);
1273 return xDumper
->dump();
1278 void ChartModel::setTimeBasedRange(sal_Int32 nStart
, sal_Int32 nEnd
)
1285 void ChartModel::update()
1287 if(!mxChartView
.is())
1289 mxChartView
= new ChartView( m_xContext
, *this);
1291 mxChartView
->setViewDirty();
1292 mxChartView
->update();
1295 bool ChartModel::isDataFromSpreadsheet()
1297 return !isDataFromPivotTable() && !hasInternalDataProvider();
1300 bool ChartModel::isDataFromPivotTable() const
1302 uno::Reference
<chart2::data::XPivotTableDataProvider
> xPivotTableDataProvider(m_xDataProvider
, uno::UNO_QUERY
);
1303 return xPivotTableDataProvider
.is();
1306 } // namespace chart
1308 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
1309 com_sun_star_comp_chart2_ChartModel_get_implementation(css::uno::XComponentContext
*context
,
1310 css::uno::Sequence
<css::uno::Any
> const &)
1312 return cppu::acquire(new ::chart::ChartModel(context
));
1315 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */