/src/libreoffice/chart2/source/model/main/ChartModel.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | |
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 <ChartType.hxx> |
27 | | #include <DisposeHelper.hxx> |
28 | | #include <ControllerLockGuard.hxx> |
29 | | #include <InternalDataProvider.hxx> |
30 | | #include <ObjectIdentifier.hxx> |
31 | | #include <BaseCoordinateSystem.hxx> |
32 | | #include "PageBackground.hxx" |
33 | | #include <CloneHelper.hxx> |
34 | | #include <NameContainer.hxx> |
35 | | #include "UndoManager.hxx" |
36 | | |
37 | | #include <ChartColorPaletteHelper.hxx> |
38 | | #include <ChartView.hxx> |
39 | | #include <PopupRequest.hxx> |
40 | | #include <ModifyListenerHelper.hxx> |
41 | | #include <RangeHighlighter.hxx> |
42 | | #include <Diagram.hxx> |
43 | | #include <ChartDocumentWrapper.hxx> |
44 | | #include <comphelper/dumpxmltostring.hxx> |
45 | | |
46 | | #include <com/sun/star/chart/ChartDataRowSource.hpp> |
47 | | #include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp> |
48 | | |
49 | | #include <comphelper/processfactory.hxx> |
50 | | #include <comphelper/propertysequence.hxx> |
51 | | #include <cppuhelper/supportsservice.hxx> |
52 | | |
53 | | #include <svl/numformat.hxx> |
54 | | #include <svl/numuno.hxx> |
55 | | #include <com/sun/star/lang/DisposedException.hpp> |
56 | | #include <com/sun/star/view/XSelectionSupplier.hpp> |
57 | | #include <com/sun/star/embed/EmbedMapUnits.hpp> |
58 | | #include <com/sun/star/embed/Aspects.hpp> |
59 | | #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp> |
60 | | #include <com/sun/star/datatransfer/XTransferable.hpp> |
61 | | #include <com/sun/star/drawing/XDrawPageSupplier.hpp> |
62 | | #include <com/sun/star/drawing/XDrawPage.hpp> |
63 | | #include <com/sun/star/drawing/FillStyle.hpp> |
64 | | #include <com/sun/star/drawing/XShapes.hpp> |
65 | | #include <com/sun/star/document/DocumentProperties.hpp> |
66 | | #include <com/sun/star/text/XTextDocument.hpp> |
67 | | #include <com/sun/star/util/CloseVetoException.hpp> |
68 | | #include <com/sun/star/util/XModifyBroadcaster.hpp> |
69 | | |
70 | | #include <sal/log.hxx> |
71 | | #include <utility> |
72 | | #include <comphelper/diagnose_ex.hxx> |
73 | | #include <libxml/xmlwriter.h> |
74 | | |
75 | | #include <sfx2/objsh.hxx> |
76 | | #include <sfx2/viewsh.hxx> |
77 | | #include <com/sun/star/util/XTheme.hpp> |
78 | | #include <docmodel/uno/UnoTheme.hxx> |
79 | | #include <docmodel/theme/Theme.hxx> |
80 | | #include <docmodel/uno/UnoChartStyle.hxx> |
81 | | |
82 | | using ::com::sun::star::uno::Sequence; |
83 | | using ::com::sun::star::uno::Reference; |
84 | | using ::com::sun::star::uno::Any; |
85 | | using ::osl::MutexGuard; |
86 | | |
87 | | using namespace ::com::sun::star; |
88 | | using namespace ::apphelper; |
89 | | |
90 | | namespace |
91 | | { |
92 | | constexpr OUString lcl_aGDIMetaFileMIMEType( |
93 | | u"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\""_ustr); |
94 | | constexpr OUString lcl_aGDIMetaFileMIMETypeHighContrast( |
95 | | u"application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\""_ustr); |
96 | | |
97 | | } // anonymous namespace |
98 | | |
99 | | // ChartModel Constructor and Destructor |
100 | | |
101 | | namespace chart |
102 | | { |
103 | | |
104 | | namespace |
105 | | { |
106 | | SfxObjectShell* getParentShell(const uno::Reference<frame::XModel>& xDocModel) |
107 | 0 | { |
108 | 0 | uno::Reference<lang::XUnoTunnel> xUnoTunnel(xDocModel, uno::UNO_QUERY); |
109 | 0 | if (xUnoTunnel.is()) |
110 | 0 | { |
111 | 0 | return comphelper::getFromUnoTunnel<SfxObjectShell>(xUnoTunnel); |
112 | 0 | } |
113 | 0 | return nullptr; |
114 | 0 | } |
115 | | } |
116 | | |
117 | | ChartModel::ChartModel(uno::Reference<uno::XComponentContext > xContext) |
118 | 0 | : m_aLifeTimeManager( this, this ) |
119 | 0 | , m_bReadOnly( false ) |
120 | 0 | , m_bModified( false ) |
121 | 0 | , m_nInLoad(0) |
122 | 0 | , m_bUpdateNotificationsPending(false) |
123 | 0 | , mbTimeBased(false) |
124 | 0 | , m_aControllers( m_aModelMutex ) |
125 | 0 | , m_nControllerLockCount(0) |
126 | 0 | , m_xContext(std::move( xContext )) |
127 | 0 | , m_aVisualAreaSize( ChartModel::getDefaultPageSize() ) |
128 | 0 | , m_xPageBackground( new PageBackground ) |
129 | 0 | , m_xXMLNamespaceMap( new NameContainer() ) |
130 | 0 | , m_eColorPaletteType(ChartColorPaletteType::Unknown) |
131 | 0 | , m_nColorPaletteIndex(0) |
132 | 0 | , m_aStyles(new UnoChartStyle) |
133 | 0 | , mnStart(0) |
134 | 0 | , mnEnd(0) |
135 | 0 | { |
136 | 0 | osl_atomic_increment(&m_refCount); |
137 | 0 | { |
138 | 0 | m_xOldModelAgg = new wrapper::ChartDocumentWrapper(m_xContext); |
139 | 0 | m_xOldModelAgg->setDelegator( *this ); |
140 | 0 | } |
141 | |
|
142 | 0 | { |
143 | 0 | m_xPageBackground->addModifyListener( this ); |
144 | | #if 0 // TODO |
145 | | m_aStyles->addModifyListener( this ); |
146 | | #endif |
147 | 0 | m_xChartTypeManager = new ::chart::ChartTypeManager( m_xContext ); |
148 | 0 | } |
149 | 0 | osl_atomic_decrement(&m_refCount); |
150 | 0 | } |
151 | | |
152 | | ChartModel::ChartModel( const ChartModel & rOther ) |
153 | 0 | : impl::ChartModel_Base(rOther) |
154 | | // not copy the listener |
155 | 0 | , SfxListener() |
156 | 0 | , m_aLifeTimeManager( this, this ) |
157 | 0 | , m_bReadOnly( rOther.m_bReadOnly ) |
158 | 0 | , m_bModified( rOther.m_bModified ) |
159 | 0 | , m_nInLoad(0) |
160 | 0 | , m_bUpdateNotificationsPending(false) |
161 | 0 | , mbTimeBased(rOther.mbTimeBased) |
162 | 0 | , m_aResource( rOther.m_aResource ) |
163 | 0 | , m_aMediaDescriptor( rOther.m_aMediaDescriptor ) |
164 | 0 | , m_aControllers( m_aModelMutex ) |
165 | 0 | , m_nControllerLockCount(0) |
166 | 0 | , m_xContext( rOther.m_xContext ) |
167 | | // @note: the old model aggregate must not be shared with other models if it |
168 | | // is, you get mutex deadlocks |
169 | | //, m_xOldModelAgg( nullptr ) //rOther.m_xOldModelAgg ) |
170 | | // m_xStorage( nullptr ) //rOther.m_xStorage ) |
171 | 0 | , m_aVisualAreaSize( rOther.m_aVisualAreaSize ) |
172 | 0 | , m_aGraphicObjectVector( rOther.m_aGraphicObjectVector ) |
173 | 0 | , m_xDataProvider( rOther.m_xDataProvider ) |
174 | 0 | , m_xInternalDataProvider( rOther.m_xInternalDataProvider ) |
175 | 0 | , m_eColorPaletteType(ChartColorPaletteType::Unknown) |
176 | 0 | , m_nColorPaletteIndex(0) |
177 | 0 | , mnStart(rOther.mnStart) |
178 | 0 | , mnEnd(rOther.mnEnd) |
179 | 0 | { |
180 | 0 | osl_atomic_increment(&m_refCount); |
181 | 0 | { |
182 | 0 | m_xOldModelAgg = new wrapper::ChartDocumentWrapper(m_xContext); |
183 | 0 | m_xOldModelAgg->setDelegator( *this ); |
184 | |
|
185 | 0 | Reference< util::XModifyListener > xListener; |
186 | 0 | rtl::Reference< Title > xNewTitle; |
187 | 0 | if ( rOther.m_xTitle ) |
188 | 0 | xNewTitle = new Title(*rOther.m_xTitle); |
189 | 0 | rtl::Reference< ::chart::Diagram > xNewDiagram; |
190 | 0 | if (rOther.m_xDiagram.is()) |
191 | 0 | xNewDiagram = new ::chart::Diagram( *rOther.m_xDiagram ); |
192 | 0 | rtl::Reference< ::chart::PageBackground > xNewPageBackground = new PageBackground( *rOther.m_xPageBackground ); |
193 | 0 | rtl::Reference<UnoChartStyle> xNewChartStyle = new UnoChartStyle(*rOther.m_aStyles); |
194 | |
|
195 | 0 | { |
196 | 0 | rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager; // does not implement XCloneable |
197 | 0 | rtl::Reference< ::chart::NameContainer > xXMLNamespaceMap = new NameContainer( *rOther.m_xXMLNamespaceMap ); |
198 | |
|
199 | 0 | { |
200 | 0 | MutexGuard aGuard( m_aModelMutex ); |
201 | 0 | xListener = this; |
202 | 0 | m_xTitle = xNewTitle; |
203 | 0 | m_xDiagram = xNewDiagram; |
204 | 0 | m_xPageBackground = xNewPageBackground; |
205 | 0 | m_aStyles = xNewChartStyle; |
206 | 0 | m_xChartTypeManager = std::move(xChartTypeManager); |
207 | 0 | m_xXMLNamespaceMap = std::move(xXMLNamespaceMap); |
208 | 0 | } |
209 | 0 | } |
210 | |
|
211 | 0 | ModifyListenerHelper::addListener( xNewTitle, xListener ); |
212 | 0 | if( xNewDiagram && xListener) |
213 | 0 | xNewDiagram->addModifyListener( xListener ); |
214 | 0 | if( xNewPageBackground && xListener) |
215 | 0 | xNewPageBackground->addModifyListener( xListener ); |
216 | | #if 0 // TODO |
217 | | if( xNewChartStyle && xListener) { |
218 | | xNewChartStyle->addModifyListener( xListener ); |
219 | | } |
220 | | #endif |
221 | 0 | xListener.clear(); |
222 | 0 | } |
223 | 0 | osl_atomic_decrement(&m_refCount); |
224 | 0 | } |
225 | | |
226 | | ChartModel::~ChartModel() |
227 | 0 | { |
228 | 0 | if (SfxObjectShell* pShell = getParentShell(m_xParent)) |
229 | 0 | EndListening(*pShell); |
230 | 0 | if( m_xOldModelAgg.is()) |
231 | 0 | m_xOldModelAgg->setDelegator( nullptr ); |
232 | 0 | } |
233 | | |
234 | | void SAL_CALL ChartModel::initialize( const Sequence< Any >& /*rArguments*/ ) |
235 | 0 | { |
236 | | //#i113722# avoid duplicate creation |
237 | | |
238 | | //maybe additional todo?: |
239 | | //support argument "EmbeddedObject"? |
240 | | //support argument "EmbeddedScriptSupport"? |
241 | | //support argument "DocumentRecoverySupport"? |
242 | 0 | } |
243 | | |
244 | | ChartView* ChartModel::getChartView() const |
245 | 0 | { |
246 | 0 | return mxChartView.get(); |
247 | 0 | } |
248 | | |
249 | | // private methods |
250 | | |
251 | | OUString ChartModel::impl_g_getLocation() |
252 | 0 | { |
253 | |
|
254 | 0 | LifeTimeGuard aGuard(m_aLifeTimeManager); |
255 | 0 | if(!aGuard.startApiCall()) |
256 | 0 | return OUString(); //behave passive if already disposed or closed or throw exception @todo? |
257 | | //mutex is acquired |
258 | 0 | return m_aResource; |
259 | 0 | } |
260 | | |
261 | | bool ChartModel::impl_isControllerConnected( const uno::Reference< frame::XController >& xController ) |
262 | 0 | { |
263 | 0 | try |
264 | 0 | { |
265 | 0 | std::vector< uno::Reference<uno::XInterface> > aSeq = m_aControllers.getElements(); |
266 | 0 | for( const auto & r : aSeq ) |
267 | 0 | { |
268 | 0 | if( r == xController ) |
269 | 0 | return true; |
270 | 0 | } |
271 | 0 | } |
272 | 0 | catch (const uno::Exception&) |
273 | 0 | { |
274 | 0 | } |
275 | 0 | return false; |
276 | 0 | } |
277 | | |
278 | | uno::Reference< frame::XController > ChartModel::impl_getCurrentController() |
279 | 0 | { |
280 | | //@todo? hold only weak references to controllers |
281 | | |
282 | | // get the last active controller of this model |
283 | 0 | if( m_xCurrentController.is() ) |
284 | 0 | return m_xCurrentController; |
285 | | |
286 | | // get the first controller of this model |
287 | 0 | if( m_aControllers.getLength() ) |
288 | 0 | { |
289 | 0 | uno::Reference<uno::XInterface> xI = m_aControllers.getInterface(0); |
290 | 0 | return uno::Reference<frame::XController>( xI, uno::UNO_QUERY ); |
291 | 0 | } |
292 | | |
293 | | //return nothing if no controllers are connected at all |
294 | 0 | return uno::Reference< frame::XController > (); |
295 | 0 | } |
296 | | |
297 | | void ChartModel::impl_notifyCloseListeners() |
298 | 0 | { |
299 | 0 | std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); |
300 | 0 | if( m_aLifeTimeManager.m_aCloseListeners.getLength(aGuard) ) |
301 | 0 | { |
302 | 0 | lang::EventObject aEvent( static_cast< lang::XComponent*>(this) ); |
303 | 0 | m_aLifeTimeManager.m_aCloseListeners.notifyEach(aGuard, &util::XCloseListener::notifyClosing, aEvent); |
304 | 0 | } |
305 | 0 | } |
306 | | |
307 | | void ChartModel::impl_adjustAdditionalShapesPositionAndSize( const awt::Size& aVisualAreaSize ) |
308 | 0 | { |
309 | 0 | uno::Reference< beans::XPropertySet > xProperties( static_cast< ::cppu::OWeakObject* >( this ), uno::UNO_QUERY ); |
310 | 0 | if ( !xProperties.is() ) |
311 | 0 | return; |
312 | | |
313 | 0 | uno::Reference< drawing::XShapes > xShapes; |
314 | 0 | xProperties->getPropertyValue( u"AdditionalShapes"_ustr ) >>= xShapes; |
315 | 0 | if ( !xShapes.is() ) |
316 | 0 | return; |
317 | | |
318 | 0 | sal_Int32 nCount = xShapes->getCount(); |
319 | 0 | for ( sal_Int32 i = 0; i < nCount; ++i ) |
320 | 0 | { |
321 | 0 | Reference< drawing::XShape > xShape; |
322 | 0 | if ( xShapes->getByIndex( i ) >>= xShape ) |
323 | 0 | { |
324 | 0 | if ( xShape.is() ) |
325 | 0 | { |
326 | 0 | awt::Point aPos( xShape->getPosition() ); |
327 | 0 | awt::Size aSize( xShape->getSize() ); |
328 | |
|
329 | 0 | double fWidth = static_cast< double >( aVisualAreaSize.Width ) / m_aVisualAreaSize.Width; |
330 | 0 | double fHeight = static_cast< double >( aVisualAreaSize.Height ) / m_aVisualAreaSize.Height; |
331 | |
|
332 | 0 | aPos.X = static_cast< tools::Long >( aPos.X * fWidth ); |
333 | 0 | aPos.Y = static_cast< tools::Long >( aPos.Y * fHeight ); |
334 | 0 | aSize.Width = static_cast< tools::Long >( aSize.Width * fWidth ); |
335 | 0 | aSize.Height = static_cast< tools::Long >( aSize.Height * fHeight ); |
336 | |
|
337 | 0 | xShape->setPosition( aPos ); |
338 | 0 | xShape->setSize( aSize ); |
339 | 0 | } |
340 | 0 | } |
341 | 0 | } |
342 | 0 | } |
343 | | |
344 | | // lang::XServiceInfo |
345 | | |
346 | | OUString SAL_CALL ChartModel::getImplementationName() |
347 | 0 | { |
348 | 0 | return u"com.sun.star.comp.chart2.ChartModel"_ustr; |
349 | 0 | } |
350 | | |
351 | | sal_Bool SAL_CALL ChartModel::supportsService( const OUString& rServiceName ) |
352 | 0 | { |
353 | 0 | return cppu::supportsService(this, rServiceName); |
354 | 0 | } |
355 | | |
356 | | css::uno::Sequence< OUString > SAL_CALL ChartModel::getSupportedServiceNames() |
357 | 0 | { |
358 | 0 | return { |
359 | 0 | u"com.sun.star.chart2.ChartDocument"_ustr, |
360 | 0 | u"com.sun.star.document.OfficeDocument"_ustr, |
361 | 0 | u"com.sun.star.chart.ChartDocument"_ustr |
362 | 0 | }; |
363 | 0 | } |
364 | | |
365 | | // frame::XModel (required interface) |
366 | | |
367 | | sal_Bool SAL_CALL ChartModel::attachResource( const OUString& rURL |
368 | | , const uno::Sequence< beans::PropertyValue >& rMediaDescriptor ) |
369 | 0 | { |
370 | | /* |
371 | | The method attachResource() is used by the frame loader implementations |
372 | | to inform the model about its URL and MediaDescriptor. |
373 | | */ |
374 | |
|
375 | 0 | LifeTimeGuard aGuard(m_aLifeTimeManager); |
376 | 0 | if(!aGuard.startApiCall()) |
377 | 0 | return false; //behave passive if already disposed or closed or throw exception @todo? |
378 | | //mutex is acquired |
379 | | |
380 | 0 | if(!m_aResource.isEmpty())//we have a resource already //@todo? or is setting a new resource allowed? |
381 | 0 | return false; |
382 | 0 | m_aResource = rURL; |
383 | 0 | m_aMediaDescriptor = rMediaDescriptor; |
384 | | |
385 | | //@todo ? check rURL ?? |
386 | | //@todo ? evaluate m_aMediaDescriptor; |
387 | | //@todo ? ... ??? --> nothing, this method is only for setting information |
388 | |
|
389 | 0 | return true; |
390 | 0 | } |
391 | | |
392 | | OUString SAL_CALL ChartModel::getURL() |
393 | 0 | { |
394 | 0 | return impl_g_getLocation(); |
395 | 0 | } |
396 | | |
397 | | uno::Sequence< beans::PropertyValue > SAL_CALL ChartModel::getArgs() |
398 | 0 | { |
399 | | /* |
400 | | The method getArgs() returns a sequence of property values |
401 | | that report the resource description according to com.sun.star.document.MediaDescriptor, |
402 | | specified on loading or saving with storeAsURL. |
403 | | */ |
404 | |
|
405 | 0 | LifeTimeGuard aGuard(m_aLifeTimeManager); |
406 | 0 | if(!aGuard.startApiCall()) |
407 | 0 | return uno::Sequence< beans::PropertyValue >(); //behave passive if already disposed or closed or throw exception @todo? |
408 | | //mutex is acquired |
409 | | |
410 | 0 | return m_aMediaDescriptor; |
411 | 0 | } |
412 | | |
413 | | void SAL_CALL ChartModel::connectController( const uno::Reference< frame::XController >& xController ) |
414 | 0 | { |
415 | | //@todo? this method is declared as oneway -> ...? |
416 | |
|
417 | 0 | LifeTimeGuard aGuard(m_aLifeTimeManager); |
418 | 0 | if(!aGuard.startApiCall()) |
419 | 0 | return ; //behave passive if already disposed or closed |
420 | | //mutex is acquired |
421 | | |
422 | | //--add controller |
423 | 0 | m_aControllers.addInterface(xController); |
424 | 0 | } |
425 | | |
426 | | void SAL_CALL ChartModel::disconnectController( const uno::Reference< frame::XController >& xController ) |
427 | 0 | { |
428 | | //@todo? this method is declared as oneway -> ...? |
429 | |
|
430 | 0 | LifeTimeGuard aGuard(m_aLifeTimeManager); |
431 | 0 | if(!aGuard.startApiCall()) |
432 | 0 | return; //behave passive if already disposed or closed |
433 | | |
434 | | //--remove controller |
435 | 0 | m_aControllers.removeInterface(xController); |
436 | | |
437 | | //case: current controller is disconnected: |
438 | 0 | if( m_xCurrentController == xController ) |
439 | 0 | m_xCurrentController.clear(); |
440 | |
|
441 | 0 | if (m_xRangeHighlighter) |
442 | 0 | { |
443 | 0 | m_xRangeHighlighter->dispose(); |
444 | 0 | m_xRangeHighlighter.clear(); |
445 | 0 | } |
446 | 0 | DisposeHelper::DisposeAndClear(m_xPopupRequest); |
447 | 0 | } |
448 | | |
449 | | void SAL_CALL ChartModel::lockControllers() |
450 | 0 | { |
451 | | /* |
452 | | suspends some notifications to the controllers which are used for display updates. |
453 | | |
454 | | The calls to lockControllers() and unlockControllers() may be nested |
455 | | and even overlapping, but they must be in pairs. While there is at least one lock |
456 | | remaining, some notifications for display updates are not broadcasted. |
457 | | */ |
458 | | |
459 | | //@todo? this method is declared as oneway -> ...? |
460 | |
|
461 | 0 | LifeTimeGuard aGuard(m_aLifeTimeManager); |
462 | 0 | if(!aGuard.startApiCall()) |
463 | 0 | return; //behave passive if already disposed or closed or throw exception @todo? |
464 | 0 | ++m_nControllerLockCount; |
465 | 0 | } |
466 | | |
467 | | void SAL_CALL ChartModel::unlockControllers() |
468 | 0 | { |
469 | | /* |
470 | | resumes the notifications which were suspended by lockControllers() . |
471 | | |
472 | | The calls to lockControllers() and unlockControllers() may be nested |
473 | | and even overlapping, but they must be in pairs. While there is at least one lock |
474 | | remaining, some notifications for display updates are not broadcasted. |
475 | | */ |
476 | | |
477 | | //@todo? this method is declared as oneway -> ...? |
478 | |
|
479 | 0 | LifeTimeGuard aGuard(m_aLifeTimeManager); |
480 | 0 | if(!aGuard.startApiCall()) |
481 | 0 | return; //behave passive if already disposed or closed or throw exception @todo? |
482 | 0 | if( m_nControllerLockCount == 0 ) |
483 | 0 | { |
484 | 0 | SAL_WARN("chart2", "ChartModel: unlockControllers called with m_nControllerLockCount == 0" ); |
485 | 0 | return; |
486 | 0 | } |
487 | 0 | --m_nControllerLockCount; |
488 | 0 | if( m_nControllerLockCount == 0 && m_bUpdateNotificationsPending ) |
489 | 0 | { |
490 | 0 | aGuard.clear(); |
491 | 0 | impl_notifyModifiedListeners(); |
492 | 0 | } |
493 | 0 | } |
494 | | |
495 | | sal_Bool SAL_CALL ChartModel::hasControllersLocked() |
496 | 0 | { |
497 | 0 | LifeTimeGuard aGuard(m_aLifeTimeManager); |
498 | 0 | if(!aGuard.startApiCall()) |
499 | 0 | return false; //behave passive if already disposed or closed or throw exception @todo? |
500 | 0 | return ( m_nControllerLockCount != 0 ) ; |
501 | 0 | } |
502 | | |
503 | | uno::Reference< frame::XController > SAL_CALL ChartModel::getCurrentController() |
504 | 0 | { |
505 | 0 | LifeTimeGuard aGuard(m_aLifeTimeManager); |
506 | 0 | if(!aGuard.startApiCall()) |
507 | 0 | throw lang::DisposedException( |
508 | 0 | u"getCurrentController was called on an already disposed or closed model"_ustr, |
509 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
510 | | |
511 | 0 | return impl_getCurrentController(); |
512 | 0 | } |
513 | | |
514 | | void SAL_CALL ChartModel::setCurrentController( const uno::Reference< frame::XController >& xController ) |
515 | 0 | { |
516 | 0 | LifeTimeGuard aGuard(m_aLifeTimeManager); |
517 | 0 | if(!aGuard.startApiCall()) |
518 | 0 | throw lang::DisposedException( |
519 | 0 | u"setCurrentController was called on an already disposed or closed model"_ustr, |
520 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
521 | | |
522 | | //OSL_ENSURE( impl_isControllerConnected(xController), "setCurrentController is called with a Controller which is not connected" ); |
523 | 0 | if(!impl_isControllerConnected(xController)) |
524 | 0 | throw container::NoSuchElementException( |
525 | 0 | u"setCurrentController is called with a Controller which is not connected"_ustr, |
526 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
527 | | |
528 | 0 | m_xCurrentController = xController; |
529 | |
|
530 | 0 | if (m_xRangeHighlighter) |
531 | 0 | { |
532 | 0 | m_xRangeHighlighter->dispose(); |
533 | 0 | m_xRangeHighlighter.clear(); |
534 | 0 | } |
535 | 0 | DisposeHelper::DisposeAndClear(m_xPopupRequest); |
536 | 0 | } |
537 | | |
538 | | uno::Reference< uno::XInterface > SAL_CALL ChartModel::getCurrentSelection() |
539 | 0 | { |
540 | 0 | LifeTimeGuard aGuard(m_aLifeTimeManager); |
541 | 0 | if(!aGuard.startApiCall()) |
542 | 0 | throw lang::DisposedException( |
543 | 0 | u"getCurrentSelection was called on an already disposed or closed model"_ustr, |
544 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
545 | | |
546 | 0 | uno::Reference< uno::XInterface > xReturn; |
547 | 0 | uno::Reference< frame::XController > xController = impl_getCurrentController(); |
548 | |
|
549 | 0 | aGuard.clear(); |
550 | 0 | if( xController.is() ) |
551 | 0 | { |
552 | 0 | uno::Reference< view::XSelectionSupplier > xSelectionSupl( xController, uno::UNO_QUERY ); |
553 | 0 | if ( xSelectionSupl.is() ) |
554 | 0 | { |
555 | 0 | uno::Any aSel = xSelectionSupl->getSelection(); |
556 | 0 | OUString aObjectCID; |
557 | 0 | if( aSel >>= aObjectCID ) |
558 | 0 | xReturn.set( ObjectIdentifier::getObjectPropertySet( aObjectCID, this)); |
559 | 0 | } |
560 | 0 | } |
561 | 0 | return xReturn; |
562 | 0 | } |
563 | | |
564 | | // lang::XComponent (base of XModel) |
565 | | void SAL_CALL ChartModel::dispose() |
566 | 0 | { |
567 | 0 | Reference< XInterface > xKeepAlive( *this ); |
568 | | |
569 | | //This object should release all resources and references in the |
570 | | //easiest possible manner |
571 | | //This object must notify all registered listeners using the method |
572 | | //<member>XEventListener::disposing</member> |
573 | | |
574 | | //hold no mutex |
575 | 0 | if( !m_aLifeTimeManager.dispose() ) |
576 | 0 | return; |
577 | | |
578 | | //--release all resources and references |
579 | | //// @todo |
580 | | |
581 | 0 | if ( m_xDiagram.is() ) |
582 | 0 | m_xDiagram->removeModifyListener( this ); |
583 | |
|
584 | 0 | if ( m_xDataProvider.is() ) |
585 | 0 | { |
586 | 0 | Reference<util::XModifyBroadcaster> xModifyBroadcaster( m_xDataProvider, uno::UNO_QUERY ); |
587 | 0 | if ( xModifyBroadcaster.is() ) |
588 | 0 | xModifyBroadcaster->removeModifyListener( this ); |
589 | 0 | } |
590 | |
|
591 | 0 | m_xDataProvider.clear(); |
592 | 0 | m_xInternalDataProvider.clear(); |
593 | 0 | m_xNumberFormatsSupplier.clear(); |
594 | 0 | m_xOwnNumberFormatsSupplier.clear(); |
595 | 0 | m_xChartTypeManager.clear(); |
596 | 0 | m_xDiagram.clear(); |
597 | 0 | m_xTitle.clear(); |
598 | 0 | m_xPageBackground.clear(); |
599 | 0 | m_xXMLNamespaceMap.clear(); |
600 | 0 | m_aStyles.clear(); |
601 | |
|
602 | 0 | m_xStorage.clear(); |
603 | | // just clear, don't dispose - we're not the owner |
604 | |
|
605 | 0 | if ( m_pUndoManager.is() ) |
606 | 0 | m_pUndoManager->disposing(); |
607 | 0 | m_pUndoManager.clear(); |
608 | | // that's important, since the UndoManager implementation delegates its ref counting to ourself. |
609 | |
|
610 | 0 | if( m_xOldModelAgg.is()) // #i120828#, to release cyclic reference to ChartModel object |
611 | 0 | m_xOldModelAgg->setDelegator( nullptr ); |
612 | |
|
613 | 0 | m_aControllers.disposeAndClear( lang::EventObject( static_cast< cppu::OWeakObject * >( this ))); |
614 | 0 | m_xCurrentController.clear(); |
615 | |
|
616 | 0 | if (m_xRangeHighlighter) |
617 | 0 | { |
618 | 0 | m_xRangeHighlighter->dispose(); |
619 | 0 | m_xRangeHighlighter.clear(); |
620 | 0 | } |
621 | 0 | DisposeHelper::DisposeAndClear(m_xPopupRequest); |
622 | |
|
623 | 0 | if( m_xOldModelAgg.is()) |
624 | 0 | m_xOldModelAgg->setDelegator( nullptr ); |
625 | 0 | } |
626 | | |
627 | | void SAL_CALL ChartModel::addEventListener( const uno::Reference< lang::XEventListener > & xListener ) |
628 | 0 | { |
629 | 0 | if( m_aLifeTimeManager.impl_isDisposedOrClosed() ) |
630 | 0 | return; //behave passive if already disposed or closed |
631 | | |
632 | 0 | std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); |
633 | 0 | m_aLifeTimeManager.m_aEventListeners.addInterface( aGuard, xListener ); |
634 | 0 | } |
635 | | |
636 | | void SAL_CALL ChartModel::removeEventListener( const uno::Reference< lang::XEventListener > & xListener ) |
637 | 0 | { |
638 | 0 | if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) ) |
639 | 0 | return; //behave passive if already disposed or closed |
640 | | |
641 | 0 | std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); |
642 | 0 | m_aLifeTimeManager.m_aEventListeners.removeInterface( aGuard, xListener ); |
643 | 0 | } |
644 | | |
645 | | // util::XCloseBroadcaster (base of XCloseable) |
646 | | void SAL_CALL ChartModel::addCloseListener( const uno::Reference< util::XCloseListener > & xListener ) |
647 | 0 | { |
648 | 0 | m_aLifeTimeManager.g_addCloseListener( xListener ); |
649 | 0 | } |
650 | | |
651 | | void SAL_CALL ChartModel::removeCloseListener( const uno::Reference< util::XCloseListener > & xListener ) |
652 | 0 | { |
653 | 0 | if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) ) |
654 | 0 | return; //behave passive if already disposed or closed |
655 | | |
656 | 0 | std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); |
657 | 0 | m_aLifeTimeManager.m_aCloseListeners.removeInterface( aGuard, xListener ); |
658 | 0 | } |
659 | | |
660 | | // util::XCloseable |
661 | | void SAL_CALL ChartModel::close( sal_Bool bDeliverOwnership ) |
662 | 0 | { |
663 | | //hold no mutex |
664 | |
|
665 | 0 | if( !m_aLifeTimeManager.g_close_startTryClose( bDeliverOwnership ) ) |
666 | 0 | return; |
667 | | //no mutex is acquired |
668 | | |
669 | | // At the end of this method may we must dispose ourself ... |
670 | | // and may nobody from outside hold a reference to us ... |
671 | | // then it's a good idea to do that by ourself. |
672 | 0 | uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) ); |
673 | | |
674 | | //the listeners have had no veto |
675 | | //check whether we self can close |
676 | 0 | { |
677 | 0 | util::CloseVetoException aVetoException( |
678 | 0 | u"the model itself could not be closed"_ustr, |
679 | 0 | static_cast< ::cppu::OWeakObject* >(this) ); |
680 | |
|
681 | 0 | m_aLifeTimeManager.g_close_isNeedToCancelLongLastingCalls( bDeliverOwnership, aVetoException ); |
682 | 0 | } |
683 | 0 | m_aLifeTimeManager.g_close_endTryClose_doClose(); |
684 | | |
685 | | // BM @todo: is it ok to call the listeners here? |
686 | 0 | impl_notifyCloseListeners(); |
687 | 0 | } |
688 | | |
689 | | // lang::XTypeProvider |
690 | | uno::Sequence< uno::Type > SAL_CALL ChartModel::getTypes() |
691 | 0 | { |
692 | 0 | uno::Reference< lang::XTypeProvider > xAggTypeProvider; |
693 | 0 | if( (m_xOldModelAgg->queryAggregation( cppu::UnoType<decltype(xAggTypeProvider)>::get()) >>= xAggTypeProvider) |
694 | 0 | && xAggTypeProvider.is()) |
695 | 0 | { |
696 | 0 | return comphelper::concatSequences( |
697 | 0 | impl::ChartModel_Base::getTypes(), |
698 | 0 | xAggTypeProvider->getTypes()); |
699 | 0 | } |
700 | | |
701 | 0 | return impl::ChartModel_Base::getTypes(); |
702 | 0 | } |
703 | | |
704 | | // document::XDocumentPropertiesSupplier |
705 | | uno::Reference< document::XDocumentProperties > SAL_CALL |
706 | | ChartModel::getDocumentProperties() |
707 | 0 | { |
708 | 0 | ::osl::MutexGuard aGuard( m_aModelMutex ); |
709 | 0 | if ( !m_xDocumentProperties.is() ) |
710 | 0 | { |
711 | 0 | m_xDocumentProperties.set( document::DocumentProperties::create( ::comphelper::getProcessComponentContext() ) ); |
712 | 0 | } |
713 | 0 | return m_xDocumentProperties; |
714 | 0 | } |
715 | | |
716 | | // document::XDocumentPropertiesSupplier |
717 | | Reference< document::XUndoManager > SAL_CALL ChartModel::getUndoManager( ) |
718 | 0 | { |
719 | 0 | ::osl::MutexGuard aGuard( m_aModelMutex ); |
720 | 0 | if ( !m_pUndoManager.is() ) |
721 | 0 | m_pUndoManager.set( new UndoManager( *this, m_aModelMutex ) ); |
722 | 0 | return m_pUndoManager; |
723 | 0 | } |
724 | | |
725 | | // chart2::XChartDocument |
726 | | |
727 | | uno::Reference< chart2::XDiagram > SAL_CALL ChartModel::getFirstDiagram() |
728 | 0 | { |
729 | 0 | MutexGuard aGuard( m_aModelMutex ); |
730 | 0 | return m_xDiagram; |
731 | 0 | } |
732 | | |
733 | | void SAL_CALL ChartModel::setFirstDiagram( const uno::Reference< chart2::XDiagram >& xDiagram ) |
734 | 0 | { |
735 | 0 | rtl::Reference< ::chart::Diagram > xOldDiagram; |
736 | 0 | Reference< util::XModifyListener > xListener; |
737 | 0 | { |
738 | 0 | MutexGuard aGuard( m_aModelMutex ); |
739 | 0 | if( xDiagram.get() == m_xDiagram.get() ) |
740 | 0 | return; |
741 | 0 | xOldDiagram = m_xDiagram; |
742 | 0 | assert(!xDiagram || dynamic_cast<::chart::Diagram*>(xDiagram.get())); |
743 | 0 | m_xDiagram = dynamic_cast<::chart::Diagram*>(xDiagram.get()); |
744 | 0 | xListener = this; |
745 | 0 | } |
746 | | //don't keep the mutex locked while calling out |
747 | 0 | if( xOldDiagram && xListener ) |
748 | 0 | xOldDiagram->removeModifyListener( xListener ); |
749 | 0 | ModifyListenerHelper::addListener( xDiagram, xListener ); |
750 | 0 | setModified( true ); |
751 | 0 | } |
752 | | |
753 | | Reference< chart2::data::XDataSource > ChartModel::impl_createDefaultData() |
754 | 0 | { |
755 | 0 | Reference< chart2::data::XDataSource > xDataSource; |
756 | 0 | if( hasInternalDataProvider() ) |
757 | 0 | { |
758 | | //init internal dataprovider |
759 | 0 | { |
760 | 0 | beans::NamedValue aParam( u"CreateDefaultData"_ustr ,uno::Any(true) ); |
761 | 0 | uno::Sequence< uno::Any > aArgs{ uno::Any(aParam) }; |
762 | 0 | m_xInternalDataProvider->initialize(aArgs); |
763 | 0 | } |
764 | | //create data |
765 | 0 | uno::Sequence<beans::PropertyValue> aArgs( comphelper::InitPropertySequence({ |
766 | 0 | { "CellRangeRepresentation", uno::Any( u"all"_ustr ) }, |
767 | 0 | { "HasCategories", uno::Any( true ) }, |
768 | 0 | { "FirstCellAsLabel", uno::Any( true ) }, |
769 | 0 | { "DataRowSource", uno::Any( css::chart::ChartDataRowSource_COLUMNS ) } |
770 | 0 | })); |
771 | 0 | xDataSource = m_xInternalDataProvider->createDataSource( aArgs ); |
772 | 0 | } |
773 | 0 | return xDataSource; |
774 | 0 | } |
775 | | |
776 | | void SAL_CALL ChartModel::createInternalDataProvider( sal_Bool bCloneExistingData ) |
777 | 0 | { |
778 | | // don't lock the mutex, because this call calls out to code that tries to |
779 | | // lock the solar mutex. On the other hand, a paint locks the solar mutex |
780 | | // and calls to the model lock the model's mutex => deadlock |
781 | | // @todo: lock a separate mutex in the InternalData class |
782 | 0 | if( !hasInternalDataProvider() ) |
783 | 0 | { |
784 | 0 | if( bCloneExistingData ) |
785 | 0 | m_xInternalDataProvider = new InternalDataProvider( this, /*bConnectToModel*/true, /*bDefaultDataInColumns*/ true ); |
786 | 0 | else |
787 | 0 | { |
788 | 0 | m_xInternalDataProvider = new InternalDataProvider( nullptr, /*bConnectToModel*/true, /*bDefaultDataInColumns*/ true ); |
789 | 0 | m_xInternalDataProvider->setChartModel(this); |
790 | 0 | } |
791 | 0 | m_xDataProvider.set( m_xInternalDataProvider ); |
792 | 0 | } |
793 | 0 | setModified( true ); |
794 | 0 | } |
795 | | |
796 | | void ChartModel::removeDataProviders() |
797 | 0 | { |
798 | 0 | if (m_xInternalDataProvider.is()) |
799 | 0 | m_xInternalDataProvider.clear(); |
800 | 0 | if (m_xDataProvider.is()) |
801 | 0 | m_xDataProvider.clear(); |
802 | 0 | } |
803 | | |
804 | | void ChartModel::dumpAsXml(xmlTextWriterPtr pWriter) const |
805 | 0 | { |
806 | 0 | (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ChartModel")); |
807 | 0 | (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); |
808 | |
|
809 | 0 | if (mxChartView.is()) |
810 | 0 | { |
811 | 0 | mxChartView->dumpAsXml(pWriter); |
812 | 0 | } |
813 | |
|
814 | 0 | (void)xmlTextWriterEndElement(pWriter); |
815 | 0 | } |
816 | | |
817 | | sal_Bool SAL_CALL ChartModel::hasInternalDataProvider() |
818 | 0 | { |
819 | 0 | return m_xDataProvider.is() && m_xInternalDataProvider.is(); |
820 | 0 | } |
821 | | |
822 | | uno::Reference< chart2::data::XDataProvider > SAL_CALL ChartModel::getDataProvider() |
823 | 0 | { |
824 | 0 | MutexGuard aGuard( m_aModelMutex ); |
825 | 0 | return m_xDataProvider; |
826 | 0 | } |
827 | | |
828 | | uno::Reference< chart2::XChartStyle > SAL_CALL ChartModel::getStyles() |
829 | 0 | { |
830 | 0 | MutexGuard aGuard( m_aModelMutex ); |
831 | 0 | return m_aStyles; |
832 | 0 | } |
833 | | |
834 | | // ____ XDataReceiver ____ |
835 | | |
836 | | void SAL_CALL ChartModel::attachDataProvider( const uno::Reference< chart2::data::XDataProvider >& xDataProvider ) |
837 | 0 | { |
838 | 0 | { |
839 | 0 | MutexGuard aGuard( m_aModelMutex ); |
840 | 0 | uno::Reference< beans::XPropertySet > xProp( xDataProvider, uno::UNO_QUERY ); |
841 | 0 | if( xProp.is() ) |
842 | 0 | { |
843 | 0 | try |
844 | 0 | { |
845 | 0 | bool bIncludeHiddenCells = isIncludeHiddenCells(); |
846 | 0 | xProp->setPropertyValue(u"IncludeHiddenCells"_ustr, uno::Any(bIncludeHiddenCells)); |
847 | 0 | } |
848 | 0 | catch (const beans::UnknownPropertyException&) |
849 | 0 | { |
850 | 0 | } |
851 | 0 | } |
852 | |
|
853 | 0 | uno::Reference<util::XModifyBroadcaster> xModifyBroadcaster(xDataProvider, uno::UNO_QUERY); |
854 | 0 | if (xModifyBroadcaster.is()) |
855 | 0 | { |
856 | 0 | xModifyBroadcaster->addModifyListener(this); |
857 | 0 | } |
858 | |
|
859 | 0 | m_xDataProvider.set( xDataProvider ); |
860 | 0 | m_xInternalDataProvider.clear(); |
861 | | |
862 | | //the numberformatter is kept independent of the data provider! |
863 | 0 | } |
864 | 0 | setModified( true ); |
865 | 0 | } |
866 | | |
867 | | void SAL_CALL ChartModel::attachNumberFormatsSupplier( const uno::Reference< util::XNumberFormatsSupplier >& xNewSupplier ) |
868 | 0 | { |
869 | 0 | { |
870 | | // Mostly the supplier is SvNumberFormatsSupplierObj, but sometimes it is reportdesign::OReportDefinition |
871 | 0 | MutexGuard aGuard( m_aModelMutex ); |
872 | 0 | if( xNewSupplier == m_xNumberFormatsSupplier ) |
873 | 0 | return; |
874 | 0 | if( xNewSupplier == uno::Reference<XNumberFormatsSupplier>(m_xOwnNumberFormatsSupplier) ) |
875 | 0 | return; |
876 | 0 | if( m_xOwnNumberFormatsSupplier.is() && xNewSupplier.is() ) |
877 | 0 | { |
878 | | //@todo |
879 | | //merge missing numberformats from own to new formatter |
880 | 0 | } |
881 | 0 | else if( !xNewSupplier.is() ) |
882 | 0 | { |
883 | 0 | if( m_xNumberFormatsSupplier.is() ) |
884 | 0 | { |
885 | | //@todo |
886 | | //merge missing numberformats from old numberformatter to own numberformatter |
887 | | //create own numberformatter if necessary |
888 | 0 | } |
889 | 0 | } |
890 | |
|
891 | 0 | m_xNumberFormatsSupplier.set( xNewSupplier ); |
892 | 0 | m_xOwnNumberFormatsSupplier.clear(); |
893 | 0 | } |
894 | 0 | setModified( true ); |
895 | 0 | } |
896 | | |
897 | | void SAL_CALL ChartModel::setArguments( const Sequence< beans::PropertyValue >& aArguments ) |
898 | 0 | { |
899 | 0 | { |
900 | 0 | MutexGuard aGuard( m_aModelMutex ); |
901 | 0 | if( !m_xDataProvider.is() ) |
902 | 0 | return; |
903 | 0 | lockControllers(); |
904 | |
|
905 | 0 | try |
906 | 0 | { |
907 | 0 | Reference< chart2::data::XDataSource > xDataSource( m_xDataProvider->createDataSource( aArguments ) ); |
908 | 0 | if( xDataSource.is() ) |
909 | 0 | { |
910 | 0 | rtl::Reference< Diagram > xDia = getFirstChartDiagram(); |
911 | 0 | if( !xDia.is() ) |
912 | 0 | { |
913 | 0 | rtl::Reference< ::chart::ChartTypeTemplate > xTemplate( impl_createDefaultChartTypeTemplate() ); |
914 | 0 | if( xTemplate.is()) |
915 | 0 | setFirstDiagram( xTemplate->createDiagramByDataSource( xDataSource, aArguments ) ); |
916 | 0 | } |
917 | 0 | else |
918 | 0 | xDia->setDiagramData( xDataSource, aArguments ); |
919 | 0 | } |
920 | 0 | } |
921 | 0 | catch (const lang::IllegalArgumentException&) |
922 | 0 | { |
923 | 0 | throw; |
924 | 0 | } |
925 | 0 | catch (const uno::Exception&) |
926 | 0 | { |
927 | 0 | DBG_UNHANDLED_EXCEPTION("chart2"); |
928 | 0 | } |
929 | 0 | unlockControllers(); |
930 | 0 | } |
931 | 0 | setModified( true ); |
932 | 0 | } |
933 | | |
934 | | Sequence< OUString > SAL_CALL ChartModel::getUsedRangeRepresentations() |
935 | 0 | { |
936 | 0 | return comphelper::containerToSequence(DataSourceHelper::getUsedDataRanges( this )); |
937 | 0 | } |
938 | | |
939 | | Reference< chart2::data::XDataSource > SAL_CALL ChartModel::getUsedData() |
940 | 0 | { |
941 | 0 | return DataSourceHelper::getUsedData( *this ); |
942 | 0 | } |
943 | | |
944 | | Reference< chart2::data::XRangeHighlighter > SAL_CALL ChartModel::getRangeHighlighter() |
945 | 0 | { |
946 | 0 | if( ! m_xRangeHighlighter.is()) |
947 | 0 | m_xRangeHighlighter = new RangeHighlighter( this ); |
948 | 0 | return m_xRangeHighlighter; |
949 | 0 | } |
950 | | |
951 | | Reference<awt::XRequestCallback> SAL_CALL ChartModel::getPopupRequest() |
952 | 0 | { |
953 | 0 | if (!m_xPopupRequest.is()) |
954 | 0 | m_xPopupRequest.set(new PopupRequest); |
955 | 0 | return m_xPopupRequest; |
956 | 0 | } |
957 | | |
958 | | rtl::Reference< ::chart::ChartTypeTemplate > ChartModel::impl_createDefaultChartTypeTemplate() |
959 | 0 | { |
960 | 0 | rtl::Reference< ::chart::ChartTypeTemplate > xTemplate; |
961 | 0 | if( m_xChartTypeManager.is() ) |
962 | 0 | xTemplate = m_xChartTypeManager->createTemplate( u"com.sun.star.chart2.template.Column"_ustr ); |
963 | 0 | return xTemplate; |
964 | 0 | } |
965 | | |
966 | | void SAL_CALL ChartModel::setChartTypeManager( const uno::Reference< chart2::XChartTypeManager >& xNewManager ) |
967 | 0 | { |
968 | 0 | { |
969 | 0 | MutexGuard aGuard( m_aModelMutex ); |
970 | 0 | m_xChartTypeManager = dynamic_cast<::chart::ChartTypeManager*>(xNewManager.get()); |
971 | 0 | assert(!xNewManager || m_xChartTypeManager); |
972 | 0 | } |
973 | 0 | setModified( true ); |
974 | 0 | } |
975 | | |
976 | | uno::Reference< chart2::XChartTypeManager > SAL_CALL ChartModel::getChartTypeManager() |
977 | 0 | { |
978 | 0 | MutexGuard aGuard( m_aModelMutex ); |
979 | 0 | return m_xChartTypeManager; |
980 | 0 | } |
981 | | |
982 | | uno::Reference< beans::XPropertySet > SAL_CALL ChartModel::getPageBackground() |
983 | 0 | { |
984 | 0 | MutexGuard aGuard( m_aModelMutex ); |
985 | 0 | return m_xPageBackground; |
986 | 0 | } |
987 | | |
988 | | void SAL_CALL ChartModel::createDefaultChart() |
989 | 0 | { |
990 | 0 | insertDefaultChart(); |
991 | 0 | } |
992 | | |
993 | | // ____ XTitled ____ |
994 | | uno::Reference< chart2::XTitle > SAL_CALL ChartModel::getTitleObject() |
995 | 0 | { |
996 | 0 | MutexGuard aGuard( m_aModelMutex ); |
997 | 0 | return m_xTitle; |
998 | 0 | } |
999 | | |
1000 | | rtl::Reference< Title > ChartModel::getTitleObject2() const |
1001 | 0 | { |
1002 | 0 | MutexGuard aGuard( m_aModelMutex ); |
1003 | 0 | return m_xTitle; |
1004 | 0 | } |
1005 | | |
1006 | | void SAL_CALL ChartModel::setTitleObject( const uno::Reference< chart2::XTitle >& xNewTitle ) |
1007 | 0 | { |
1008 | 0 | rtl::Reference<Title> xTitle = dynamic_cast<Title*>(xNewTitle.get()); |
1009 | 0 | assert(!xNewTitle || xTitle); |
1010 | 0 | setTitleObject(xTitle); |
1011 | 0 | } |
1012 | | |
1013 | | void ChartModel::setTitleObject( const rtl::Reference< Title >& xTitle ) |
1014 | 0 | { |
1015 | 0 | { |
1016 | 0 | MutexGuard aGuard( m_aModelMutex ); |
1017 | 0 | if( m_xTitle.is() ) |
1018 | 0 | ModifyListenerHelper::removeListener( m_xTitle, this ); |
1019 | 0 | m_xTitle = xTitle; |
1020 | 0 | ModifyListenerHelper::addListener( m_xTitle, this ); |
1021 | 0 | } |
1022 | 0 | setModified( true ); |
1023 | 0 | } |
1024 | | |
1025 | | // ____ XInterface (for old API wrapper) ____ |
1026 | | uno::Any SAL_CALL ChartModel::queryInterface( const uno::Type& aType ) |
1027 | 0 | { |
1028 | 0 | uno::Any aResult( impl::ChartModel_Base::queryInterface( aType )); |
1029 | |
|
1030 | 0 | if( ! aResult.hasValue()) |
1031 | 0 | { |
1032 | | // try old API wrapper |
1033 | 0 | try |
1034 | 0 | { |
1035 | 0 | if( m_xOldModelAgg.is()) |
1036 | 0 | aResult = m_xOldModelAgg->queryAggregation( aType ); |
1037 | 0 | } |
1038 | 0 | catch (const uno::Exception&) |
1039 | 0 | { |
1040 | 0 | DBG_UNHANDLED_EXCEPTION("chart2"); |
1041 | 0 | } |
1042 | 0 | } |
1043 | |
|
1044 | 0 | return aResult; |
1045 | 0 | } |
1046 | | |
1047 | | // ____ XCloneable ____ |
1048 | | Reference< util::XCloneable > SAL_CALL ChartModel::createClone() |
1049 | 0 | { |
1050 | 0 | std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex); |
1051 | 0 | return Reference< util::XCloneable >( new ChartModel( *this )); |
1052 | 0 | } |
1053 | | |
1054 | | // ____ XVisualObject ____ |
1055 | | void SAL_CALL ChartModel::setVisualAreaSize( ::sal_Int64 nAspect, const awt::Size& aSize ) |
1056 | 0 | { |
1057 | 0 | if( nAspect == embed::Aspects::MSOLE_CONTENT ) |
1058 | 0 | { |
1059 | 0 | ControllerLockGuard aLockGuard( *this ); |
1060 | 0 | bool bChanged = |
1061 | 0 | (m_aVisualAreaSize.Width != aSize.Width || |
1062 | 0 | m_aVisualAreaSize.Height != aSize.Height); |
1063 | | |
1064 | | // #i12587# support for shapes in chart |
1065 | 0 | if ( bChanged ) |
1066 | 0 | { |
1067 | 0 | impl_adjustAdditionalShapesPositionAndSize( aSize ); |
1068 | 0 | } |
1069 | |
|
1070 | 0 | m_aVisualAreaSize = aSize; |
1071 | 0 | if( bChanged ) |
1072 | 0 | setModified( true ); |
1073 | 0 | } |
1074 | 0 | else |
1075 | 0 | { |
1076 | 0 | OSL_FAIL( "setVisualAreaSize: Aspect not implemented yet."); |
1077 | 0 | } |
1078 | 0 | } |
1079 | | |
1080 | | awt::Size SAL_CALL ChartModel::getVisualAreaSize( ::sal_Int64 nAspect ) |
1081 | 0 | { |
1082 | 0 | OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT, |
1083 | 0 | "No aspects other than content are supported" ); |
1084 | | // other possible aspects are MSOLE_THUMBNAIL, MSOLE_ICON and MSOLE_DOCPRINT |
1085 | |
|
1086 | 0 | return m_aVisualAreaSize; |
1087 | 0 | } |
1088 | | |
1089 | | embed::VisualRepresentation SAL_CALL ChartModel::getPreferredVisualRepresentation( ::sal_Int64 nAspect ) |
1090 | 0 | { |
1091 | 0 | OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT, |
1092 | 0 | "No aspects other than content are supported" ); |
1093 | |
|
1094 | 0 | embed::VisualRepresentation aResult; |
1095 | |
|
1096 | 0 | try |
1097 | 0 | { |
1098 | 0 | Sequence< sal_Int8 > aMetafile; |
1099 | | |
1100 | | //get view from old api wrapper |
1101 | 0 | Reference< datatransfer::XTransferable > xTransferable( createChartView() ); |
1102 | 0 | if( xTransferable.is() ) |
1103 | 0 | { |
1104 | 0 | datatransfer::DataFlavor aDataFlavor( lcl_aGDIMetaFileMIMEType, |
1105 | 0 | u"GDIMetaFile"_ustr, |
1106 | 0 | cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ); |
1107 | |
|
1108 | 0 | uno::Any aData( xTransferable->getTransferData( aDataFlavor ) ); |
1109 | 0 | aData >>= aMetafile; |
1110 | 0 | } |
1111 | |
|
1112 | 0 | aResult.Flavor.MimeType = lcl_aGDIMetaFileMIMEType; |
1113 | 0 | aResult.Flavor.DataType = cppu::UnoType<decltype(aMetafile)>::get(); |
1114 | |
|
1115 | 0 | aResult.Data <<= aMetafile; |
1116 | 0 | } |
1117 | 0 | catch (const uno::Exception&) |
1118 | 0 | { |
1119 | 0 | DBG_UNHANDLED_EXCEPTION("chart2"); |
1120 | 0 | } |
1121 | |
|
1122 | 0 | return aResult; |
1123 | 0 | } |
1124 | | |
1125 | | ::sal_Int32 SAL_CALL ChartModel::getMapUnit( ::sal_Int64 nAspect ) |
1126 | 0 | { |
1127 | 0 | OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT, |
1128 | 0 | "No aspects other than content are supported" ); |
1129 | 0 | return embed::EmbedMapUnits::ONE_100TH_MM; |
1130 | 0 | } |
1131 | | |
1132 | | // ____ datatransfer::XTransferable ____ |
1133 | | uno::Any SAL_CALL ChartModel::getTransferData( const datatransfer::DataFlavor& aFlavor ) |
1134 | 0 | { |
1135 | 0 | uno::Any aResult; |
1136 | 0 | if( !isDataFlavorSupported( aFlavor ) ) |
1137 | 0 | throw datatransfer::UnsupportedFlavorException( |
1138 | 0 | aFlavor.MimeType, static_cast< ::cppu::OWeakObject* >( this )); |
1139 | | |
1140 | 0 | try |
1141 | 0 | { |
1142 | | //get view from old api wrapper |
1143 | 0 | Reference< datatransfer::XTransferable > xTransferable( createChartView() ); |
1144 | 0 | if( xTransferable.is() && |
1145 | 0 | xTransferable->isDataFlavorSupported( aFlavor )) |
1146 | 0 | { |
1147 | 0 | aResult = xTransferable->getTransferData( aFlavor ); |
1148 | 0 | } |
1149 | 0 | } |
1150 | 0 | catch (const uno::Exception&) |
1151 | 0 | { |
1152 | 0 | DBG_UNHANDLED_EXCEPTION("chart2"); |
1153 | 0 | } |
1154 | |
|
1155 | 0 | return aResult; |
1156 | 0 | } |
1157 | | |
1158 | | Sequence< datatransfer::DataFlavor > SAL_CALL ChartModel::getTransferDataFlavors() |
1159 | 0 | { |
1160 | 0 | return { datatransfer::DataFlavor( lcl_aGDIMetaFileMIMETypeHighContrast, |
1161 | 0 | u"GDIMetaFile"_ustr, |
1162 | 0 | cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ) }; |
1163 | 0 | } |
1164 | | |
1165 | | sal_Bool SAL_CALL ChartModel::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor ) |
1166 | 0 | { |
1167 | 0 | return aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast; |
1168 | 0 | } |
1169 | | |
1170 | | namespace |
1171 | | { |
1172 | | enum eServiceType |
1173 | | { |
1174 | | SERVICE_DASH_TABLE, |
1175 | | SERVICE_GRADIENT_TABLE, |
1176 | | SERVICE_HATCH_TABLE, |
1177 | | SERVICE_BITMAP_TABLE, |
1178 | | SERVICE_TRANSP_GRADIENT_TABLE, |
1179 | | SERVICE_MARKER_TABLE, |
1180 | | SERVICE_NAMESPACE_MAP |
1181 | | }; |
1182 | | |
1183 | | typedef std::map< OUString, enum eServiceType > tServiceNameMap; |
1184 | | |
1185 | | tServiceNameMap & lcl_getStaticServiceNameMap() |
1186 | 0 | { |
1187 | 0 | static tServiceNameMap aServiceNameMap{ |
1188 | 0 | {"com.sun.star.drawing.DashTable", SERVICE_DASH_TABLE}, |
1189 | 0 | {"com.sun.star.drawing.GradientTable", SERVICE_GRADIENT_TABLE}, |
1190 | 0 | {"com.sun.star.drawing.HatchTable", SERVICE_HATCH_TABLE}, |
1191 | 0 | {"com.sun.star.drawing.BitmapTable", SERVICE_BITMAP_TABLE}, |
1192 | 0 | {"com.sun.star.drawing.TransparencyGradientTable", SERVICE_TRANSP_GRADIENT_TABLE}, |
1193 | 0 | {"com.sun.star.drawing.MarkerTable", SERVICE_MARKER_TABLE}, |
1194 | 0 | {"com.sun.star.xml.NamespaceMap", SERVICE_NAMESPACE_MAP}}; |
1195 | 0 | return aServiceNameMap; |
1196 | 0 | } |
1197 | | } |
1198 | | // ____ XMultiServiceFactory ____ |
1199 | | Reference< uno::XInterface > SAL_CALL ChartModel::createInstance( const OUString& rServiceSpecifier ) |
1200 | 0 | { |
1201 | 0 | tServiceNameMap & rMap = lcl_getStaticServiceNameMap(); |
1202 | |
|
1203 | 0 | tServiceNameMap::const_iterator aIt( rMap.find( rServiceSpecifier )); |
1204 | 0 | if( aIt != rMap.end()) |
1205 | 0 | { |
1206 | 0 | switch( (*aIt).second ) |
1207 | 0 | { |
1208 | 0 | case SERVICE_DASH_TABLE: |
1209 | 0 | case SERVICE_GRADIENT_TABLE: |
1210 | 0 | case SERVICE_HATCH_TABLE: |
1211 | 0 | case SERVICE_BITMAP_TABLE: |
1212 | 0 | case SERVICE_TRANSP_GRADIENT_TABLE: |
1213 | 0 | case SERVICE_MARKER_TABLE: |
1214 | 0 | { |
1215 | 0 | if(!mxChartView.is()) |
1216 | 0 | { |
1217 | 0 | mxChartView = new ChartView( m_xContext, *this); |
1218 | 0 | } |
1219 | 0 | return mxChartView->createInstance( rServiceSpecifier ); |
1220 | 0 | } |
1221 | 0 | break; |
1222 | 0 | case SERVICE_NAMESPACE_MAP: |
1223 | 0 | return static_cast<cppu::OWeakObject*>(m_xXMLNamespaceMap.get()); |
1224 | 0 | } |
1225 | 0 | } |
1226 | 0 | else if(rServiceSpecifier == CHART_VIEW_SERVICE_NAME) |
1227 | 0 | { |
1228 | 0 | return static_cast< ::cppu::OWeakObject* >( createChartView().get() ); |
1229 | 0 | } |
1230 | 0 | else |
1231 | 0 | { |
1232 | 0 | if( m_xOldModelAgg.is() ) |
1233 | 0 | { |
1234 | 0 | Any aAny = m_xOldModelAgg->queryAggregation( cppu::UnoType<lang::XMultiServiceFactory>::get()); |
1235 | 0 | uno::Reference< lang::XMultiServiceFactory > xOldModelFactory; |
1236 | 0 | if( (aAny >>= xOldModelFactory) && xOldModelFactory.is() ) |
1237 | 0 | { |
1238 | 0 | return xOldModelFactory->createInstance( rServiceSpecifier ); |
1239 | 0 | } |
1240 | 0 | } |
1241 | 0 | } |
1242 | 0 | return nullptr; |
1243 | 0 | } |
1244 | | |
1245 | | const rtl::Reference<ChartView>& ChartModel::createChartView() |
1246 | 0 | { |
1247 | 0 | if(!mxChartView.is()) |
1248 | 0 | mxChartView = new ChartView( m_xContext, *this); |
1249 | 0 | return mxChartView; |
1250 | 0 | } |
1251 | | |
1252 | | Reference< uno::XInterface > SAL_CALL ChartModel::createInstanceWithArguments( |
1253 | | const OUString& rServiceSpecifier , const Sequence< Any >& Arguments ) |
1254 | 0 | { |
1255 | 0 | OSL_ENSURE( Arguments.hasElements(), "createInstanceWithArguments: Warning: Arguments are ignored" ); |
1256 | 0 | return createInstance( rServiceSpecifier ); |
1257 | 0 | } |
1258 | | |
1259 | | Sequence< OUString > SAL_CALL ChartModel::getAvailableServiceNames() |
1260 | 0 | { |
1261 | 0 | uno::Sequence< OUString > aResult; |
1262 | |
|
1263 | 0 | if( m_xOldModelAgg.is()) |
1264 | 0 | { |
1265 | 0 | Any aAny = m_xOldModelAgg->queryAggregation( cppu::UnoType<lang::XMultiServiceFactory>::get()); |
1266 | 0 | uno::Reference< lang::XMultiServiceFactory > xOldModelFactory; |
1267 | 0 | if( (aAny >>= xOldModelFactory) && xOldModelFactory.is() ) |
1268 | 0 | { |
1269 | 0 | return xOldModelFactory->getAvailableServiceNames(); |
1270 | 0 | } |
1271 | 0 | } |
1272 | 0 | return aResult; |
1273 | 0 | } |
1274 | | |
1275 | | Reference< util::XNumberFormatsSupplier > const & ChartModel::getNumberFormatsSupplier() |
1276 | 0 | { |
1277 | 0 | if( !m_xNumberFormatsSupplier.is() ) |
1278 | 0 | { |
1279 | 0 | if( !m_xOwnNumberFormatsSupplier.is() ) |
1280 | 0 | { |
1281 | 0 | m_apSvNumberFormatter.reset( new SvNumberFormatter( m_xContext, LANGUAGE_SYSTEM ) ); |
1282 | 0 | if (m_aNullDate) |
1283 | 0 | { |
1284 | 0 | m_apSvNumberFormatter->ChangeNullDate(m_aNullDate->Day, m_aNullDate->Month, m_aNullDate->Year); |
1285 | 0 | } |
1286 | 0 | m_xOwnNumberFormatsSupplier = new SvNumberFormatsSupplierObj( m_apSvNumberFormatter.get() ); |
1287 | | //pOwnNumberFormatter->ChangeStandardPrec( 15 ); todo? |
1288 | 0 | } |
1289 | 0 | m_xNumberFormatsSupplier = m_xOwnNumberFormatsSupplier; |
1290 | 0 | } |
1291 | 0 | return m_xNumberFormatsSupplier; |
1292 | 0 | } |
1293 | | |
1294 | | // ____ XUnoTunnel ___ |
1295 | | ::sal_Int64 SAL_CALL ChartModel::getSomething( const Sequence< ::sal_Int8 >& aIdentifier ) |
1296 | 0 | { |
1297 | 0 | if( comphelper::isUnoTunnelId<SvNumberFormatsSupplierObj>(aIdentifier) ) |
1298 | 0 | { |
1299 | 0 | Reference< lang::XUnoTunnel > xTunnel( getNumberFormatsSupplier(), uno::UNO_QUERY ); |
1300 | 0 | if( xTunnel.is() ) |
1301 | 0 | return xTunnel->getSomething( aIdentifier ); |
1302 | 0 | } |
1303 | 0 | return 0; |
1304 | 0 | } |
1305 | | |
1306 | | // ____ XNumberFormatsSupplier ____ |
1307 | | uno::Reference< beans::XPropertySet > SAL_CALL ChartModel::getNumberFormatSettings() |
1308 | 0 | { |
1309 | 0 | Reference< util::XNumberFormatsSupplier > xSupplier( getNumberFormatsSupplier() ); |
1310 | 0 | if( xSupplier.is() ) |
1311 | 0 | return xSupplier->getNumberFormatSettings(); |
1312 | 0 | return uno::Reference< beans::XPropertySet >(); |
1313 | 0 | } |
1314 | | |
1315 | | uno::Reference< util::XNumberFormats > SAL_CALL ChartModel::getNumberFormats() |
1316 | 0 | { |
1317 | 0 | Reference< util::XNumberFormatsSupplier > xSupplier( getNumberFormatsSupplier() ); |
1318 | 0 | if( xSupplier.is() ) |
1319 | 0 | return xSupplier->getNumberFormats(); |
1320 | 0 | return uno::Reference< util::XNumberFormats >(); |
1321 | 0 | } |
1322 | | |
1323 | | // ____ XChild ____ |
1324 | | Reference< uno::XInterface > SAL_CALL ChartModel::getParent() |
1325 | 0 | { |
1326 | 0 | return Reference< uno::XInterface >(m_xParent,uno::UNO_QUERY); |
1327 | 0 | } |
1328 | | |
1329 | | void SAL_CALL ChartModel::setParent( const Reference< uno::XInterface >& Parent ) |
1330 | 0 | { |
1331 | 0 | if( Parent != m_xParent ) |
1332 | 0 | { |
1333 | 0 | if (SfxObjectShell* pShell = getParentShell(m_xParent)) |
1334 | 0 | EndListening(*pShell); |
1335 | 0 | m_xParent.set( Parent, uno::UNO_QUERY ); |
1336 | 0 | if (SfxObjectShell* pShell = getParentShell(m_xParent)) |
1337 | 0 | StartListening(*pShell); |
1338 | 0 | } |
1339 | 0 | } |
1340 | | |
1341 | | // ____ XDataSource ____ |
1342 | | uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > SAL_CALL ChartModel::getDataSequences() |
1343 | 0 | { |
1344 | 0 | rtl::Reference< DataSource > xSource = DataSourceHelper::getUsedData( *this ); |
1345 | 0 | if( xSource.is()) |
1346 | 0 | return xSource->getDataSequences(); |
1347 | | |
1348 | 0 | return uno::Sequence< Reference< chart2::data::XLabeledDataSequence > >(); |
1349 | 0 | } |
1350 | | |
1351 | | //XDumper |
1352 | | OUString SAL_CALL ChartModel::dump(OUString const & kind) |
1353 | 0 | { |
1354 | 0 | if (kind.isEmpty()) { |
1355 | 0 | return comphelper::dumpXmlToString([this](auto writer) { return dumpAsXml(writer); }); |
1356 | 0 | } |
1357 | | |
1358 | | // kind == "shapes": |
1359 | 0 | uno::Reference< qa::XDumper > xDumper( createChartView() ); |
1360 | 0 | if (xDumper.is()) |
1361 | 0 | return xDumper->dump(kind); |
1362 | | |
1363 | 0 | return OUString(); |
1364 | 0 | } |
1365 | | |
1366 | | void ChartModel::setTimeBasedRange(sal_Int32 nStart, sal_Int32 nEnd) |
1367 | 0 | { |
1368 | 0 | mnStart = nStart; |
1369 | 0 | mnEnd = nEnd; |
1370 | 0 | mbTimeBased = true; |
1371 | 0 | } |
1372 | | |
1373 | | void ChartModel::update() |
1374 | 0 | { |
1375 | 0 | if(!mxChartView.is()) |
1376 | 0 | { |
1377 | 0 | mxChartView = new ChartView( m_xContext, *this); |
1378 | 0 | } |
1379 | 0 | mxChartView->setViewDirty(); |
1380 | 0 | mxChartView->update(); |
1381 | 0 | } |
1382 | | |
1383 | | bool ChartModel::isDataFromSpreadsheet() |
1384 | 0 | { |
1385 | 0 | return !isDataFromPivotTable() && !hasInternalDataProvider(); |
1386 | 0 | } |
1387 | | |
1388 | | bool ChartModel::isDataFromPivotTable() const |
1389 | 0 | { |
1390 | 0 | uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(m_xDataProvider, uno::UNO_QUERY); |
1391 | 0 | return xPivotTableDataProvider.is(); |
1392 | 0 | } |
1393 | | |
1394 | | rtl::Reference< BaseCoordinateSystem > ChartModel::getFirstCoordinateSystem() |
1395 | 0 | { |
1396 | 0 | if( m_xDiagram ) |
1397 | 0 | { |
1398 | 0 | auto aCooSysSeq( m_xDiagram->getBaseCoordinateSystems() ); |
1399 | 0 | if( !aCooSysSeq.empty() ) |
1400 | 0 | return aCooSysSeq[0]; |
1401 | 0 | } |
1402 | 0 | return nullptr; |
1403 | 0 | } |
1404 | | |
1405 | | std::vector< rtl::Reference< DataSeries > > ChartModel::getDataSeries() |
1406 | 0 | { |
1407 | 0 | if( m_xDiagram) |
1408 | 0 | return m_xDiagram->getDataSeries(); |
1409 | | |
1410 | 0 | return {}; |
1411 | 0 | } |
1412 | | |
1413 | | rtl::Reference< ChartType > ChartModel::getChartTypeOfSeries( const rtl::Reference< DataSeries >& xGivenDataSeries ) |
1414 | 0 | { |
1415 | 0 | return m_xDiagram ? m_xDiagram->getChartTypeOfSeries( xGivenDataSeries ) : nullptr; |
1416 | 0 | } |
1417 | | |
1418 | | // static |
1419 | | awt::Size ChartModel::getDefaultPageSize() |
1420 | 0 | { |
1421 | 0 | return awt::Size( 16000, 9000 ); |
1422 | 0 | } |
1423 | | |
1424 | | awt::Size ChartModel::getPageSize() |
1425 | 0 | { |
1426 | 0 | return getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); |
1427 | 0 | } |
1428 | | |
1429 | | void ChartModel::triggerRangeHighlighting() |
1430 | 0 | { |
1431 | 0 | getRangeHighlighter(); |
1432 | 0 | uno::Reference< view::XSelectionChangeListener > xSelectionChangeListener( m_xRangeHighlighter ); |
1433 | | //trigger selection of cell range |
1434 | 0 | lang::EventObject aEvent( xSelectionChangeListener ); |
1435 | 0 | xSelectionChangeListener->selectionChanged( aEvent ); |
1436 | 0 | } |
1437 | | |
1438 | | bool ChartModel::isIncludeHiddenCells() |
1439 | 0 | { |
1440 | 0 | bool bIncluded = true; // hidden cells are included by default. |
1441 | |
|
1442 | 0 | if (!m_xDiagram) |
1443 | 0 | return bIncluded; |
1444 | | |
1445 | 0 | try |
1446 | 0 | { |
1447 | 0 | m_xDiagram->getPropertyValue(u"IncludeHiddenCells"_ustr) >>= bIncluded; |
1448 | 0 | } |
1449 | 0 | catch( const beans::UnknownPropertyException& ) |
1450 | 0 | { |
1451 | 0 | } |
1452 | |
|
1453 | 0 | return bIncluded; |
1454 | 0 | } |
1455 | | |
1456 | | bool ChartModel::setIncludeHiddenCells( bool bIncludeHiddenCells ) |
1457 | 0 | { |
1458 | 0 | bool bChanged = false; |
1459 | 0 | try |
1460 | 0 | { |
1461 | 0 | ControllerLockGuard aLockedControllers( *this ); |
1462 | |
|
1463 | 0 | uno::Reference< beans::XPropertySet > xDiagramProperties( getFirstDiagram(), uno::UNO_QUERY ); |
1464 | 0 | if (!xDiagramProperties) |
1465 | 0 | return false; |
1466 | | |
1467 | 0 | bool bOldValue = bIncludeHiddenCells; |
1468 | 0 | xDiagramProperties->getPropertyValue( u"IncludeHiddenCells"_ustr ) >>= bOldValue; |
1469 | 0 | if( bOldValue == bIncludeHiddenCells ) |
1470 | 0 | bChanged = true; |
1471 | | |
1472 | | //set the property on all instances in all cases to get the different objects in sync! |
1473 | |
|
1474 | 0 | uno::Any aNewValue(bIncludeHiddenCells); |
1475 | |
|
1476 | 0 | try |
1477 | 0 | { |
1478 | 0 | uno::Reference< beans::XPropertySet > xDataProviderProperties( getDataProvider(), uno::UNO_QUERY ); |
1479 | 0 | if( xDataProviderProperties.is() ) |
1480 | 0 | xDataProviderProperties->setPropertyValue(u"IncludeHiddenCells"_ustr, aNewValue ); |
1481 | 0 | } |
1482 | 0 | catch( const beans::UnknownPropertyException& ) |
1483 | 0 | { |
1484 | | //the property is optional! |
1485 | 0 | } |
1486 | |
|
1487 | 0 | try |
1488 | 0 | { |
1489 | 0 | rtl::Reference< DataSource > xUsedData = DataSourceHelper::getUsedData( *this ); |
1490 | 0 | if( xUsedData.is() ) |
1491 | 0 | { |
1492 | 0 | uno::Reference< beans::XPropertySet > xProp; |
1493 | 0 | const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aData( xUsedData->getDataSequences()); |
1494 | 0 | for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledData : aData ) |
1495 | 0 | { |
1496 | 0 | xProp.set( uno::Reference< beans::XPropertySet >( labeledData->getValues(), uno::UNO_QUERY ) ); |
1497 | 0 | if(xProp.is()) |
1498 | 0 | xProp->setPropertyValue(u"IncludeHiddenCells"_ustr, aNewValue ); |
1499 | 0 | xProp.set( uno::Reference< beans::XPropertySet >( labeledData->getLabel(), uno::UNO_QUERY ) ); |
1500 | 0 | if(xProp.is()) |
1501 | 0 | xProp->setPropertyValue(u"IncludeHiddenCells"_ustr, aNewValue ); |
1502 | 0 | } |
1503 | 0 | } |
1504 | 0 | } |
1505 | 0 | catch( const beans::UnknownPropertyException& ) |
1506 | 0 | { |
1507 | | //the property is optional! |
1508 | 0 | } |
1509 | |
|
1510 | 0 | xDiagramProperties->setPropertyValue( u"IncludeHiddenCells"_ustr, aNewValue); |
1511 | 0 | } |
1512 | 0 | catch (const uno::Exception&) |
1513 | 0 | { |
1514 | 0 | TOOLS_WARN_EXCEPTION("chart2", "" ); |
1515 | 0 | } |
1516 | 0 | return bChanged; |
1517 | 0 | } |
1518 | | |
1519 | | void ChartModel::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint) |
1520 | 0 | { |
1521 | 0 | if (rHint.GetId() == SfxHintId::ThemeColorsChanged) |
1522 | 0 | { |
1523 | 0 | onDocumentThemeChanged(); |
1524 | 0 | } |
1525 | 0 | } |
1526 | | |
1527 | | std::shared_ptr<model::Theme> ChartModel::getDocumentTheme() const |
1528 | 0 | { |
1529 | 0 | std::shared_ptr<model::Theme> pTheme; |
1530 | 0 | uno::Any aThemeValue; |
1531 | |
|
1532 | 0 | auto pParent = const_cast<ChartModel*>(this)->getParent(); |
1533 | 0 | uno::Reference<frame::XModel> xDocModel(pParent, uno::UNO_QUERY); |
1534 | 0 | uno::Reference<text::XTextDocument> xTextDoc(xDocModel, uno::UNO_QUERY); |
1535 | |
|
1536 | 0 | if (!xTextDoc.is()) // Calc, Impress |
1537 | 0 | { |
1538 | 0 | uno::Reference<beans::XPropertySet> xPropSet(xDocModel, uno::UNO_QUERY); |
1539 | 0 | if (xPropSet.is()) |
1540 | 0 | { |
1541 | 0 | aThemeValue = xPropSet->getPropertyValue("Theme"); |
1542 | 0 | } |
1543 | 0 | } |
1544 | 0 | else // Writer |
1545 | 0 | { |
1546 | 0 | uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xDocModel, uno::UNO_QUERY); |
1547 | 0 | if (xDrawPageSupplier.is()) |
1548 | 0 | { |
1549 | 0 | uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage(); |
1550 | 0 | if (xDrawPage.is()) |
1551 | 0 | { |
1552 | 0 | uno::Reference<beans::XPropertySet> xPropSet(xDrawPage, uno::UNO_QUERY); |
1553 | 0 | if (xPropSet.is()) |
1554 | 0 | { |
1555 | 0 | aThemeValue = xPropSet->getPropertyValue("Theme"); |
1556 | 0 | } |
1557 | 0 | } |
1558 | 0 | } |
1559 | 0 | } |
1560 | |
|
1561 | 0 | uno::Reference<util::XTheme> xTheme(aThemeValue, uno::UNO_QUERY); |
1562 | 0 | if (xTheme.is()) |
1563 | 0 | { |
1564 | 0 | if (auto* pUnoTheme = dynamic_cast<UnoTheme*>(xTheme.get())) |
1565 | 0 | { |
1566 | 0 | pTheme = pUnoTheme->getTheme(); |
1567 | 0 | } |
1568 | 0 | } |
1569 | 0 | else |
1570 | 0 | { |
1571 | 0 | pTheme = model::Theme::FromAny(aThemeValue); |
1572 | 0 | } |
1573 | |
|
1574 | 0 | return pTheme; |
1575 | 0 | } |
1576 | | |
1577 | | void ChartModel::setColorPalette(ChartColorPaletteType eType, sal_uInt32 nIndex) |
1578 | 0 | { |
1579 | 0 | m_eColorPaletteType = eType; |
1580 | 0 | m_nColorPaletteIndex = nIndex; |
1581 | 0 | } |
1582 | | |
1583 | | void ChartModel::clearColorPalette() |
1584 | 0 | { |
1585 | | // Not reset the selected palette if user is just previewing a color |
1586 | | // for a data series or a data point |
1587 | 0 | SfxViewShell* pCurrentShell = SfxViewShell::Current(); |
1588 | 0 | if (pCurrentShell && pCurrentShell->IsLOKColorPreviewEnabled()) |
1589 | 0 | return; |
1590 | | |
1591 | 0 | setColorPalette(ChartColorPaletteType::Unknown, 0); |
1592 | 0 | } |
1593 | | |
1594 | | bool ChartModel::usesColorPalette() const |
1595 | 0 | { |
1596 | 0 | return m_eColorPaletteType != ChartColorPaletteType::Unknown; |
1597 | 0 | } |
1598 | | |
1599 | | std::optional<ChartColorPalette> ChartModel::getCurrentColorPalette() const |
1600 | 0 | { |
1601 | 0 | if (!usesColorPalette()) |
1602 | 0 | { |
1603 | 0 | SAL_WARN("chart2", "ChartModel::getCurrentColorPalette: no palette is in use"); |
1604 | 0 | return std::nullopt; |
1605 | 0 | } |
1606 | | |
1607 | 0 | const std::shared_ptr<model::Theme> pTheme = getDocumentTheme(); |
1608 | | // when pTheme is null, ChartColorPaletteHelper uses a default theme |
1609 | 0 | const ChartColorPaletteHelper aColorPaletteHelper(pTheme); |
1610 | 0 | return aColorPaletteHelper.getColorPalette(getColorPaletteType(), getColorPaletteIndex()); |
1611 | 0 | } |
1612 | | |
1613 | | void ChartModel::applyColorPaletteToDataSeries(const ChartColorPalette& rColorPalette) |
1614 | 0 | { |
1615 | 0 | const rtl::Reference<Diagram> xDiagram = getFirstChartDiagram(); |
1616 | 0 | const auto xDataSeriesArray = xDiagram->getDataSeries(); |
1617 | 0 | for (size_t i = 0; i < xDataSeriesArray.size(); ++i) |
1618 | 0 | { |
1619 | 0 | const uno::Reference<beans::XPropertySet> xPropSet = xDataSeriesArray[i]; |
1620 | 0 | const size_t nPaletteIndex = i % rColorPalette.size(); |
1621 | 0 | xPropSet->setPropertyValue("FillStyle", uno::Any(drawing::FillStyle_SOLID)); |
1622 | 0 | xPropSet->setPropertyValue("FillColor", uno::Any(rColorPalette[nPaletteIndex])); |
1623 | 0 | } |
1624 | 0 | } |
1625 | | |
1626 | | void ChartModel::onDocumentThemeChanged() |
1627 | 0 | { |
1628 | 0 | if (const auto oColorPalette = getCurrentColorPalette()) |
1629 | 0 | { |
1630 | 0 | applyColorPaletteToDataSeries(*oColorPalette); |
1631 | 0 | setModified(true); |
1632 | 0 | } |
1633 | 0 | } |
1634 | | |
1635 | | void ChartModel::changeNullDate(const css::util::DateTime& aNullDate) |
1636 | 0 | { |
1637 | 0 | if (m_aNullDate == aNullDate) |
1638 | 0 | return; |
1639 | | |
1640 | 0 | m_aNullDate = aNullDate; |
1641 | 0 | if (m_apSvNumberFormatter) |
1642 | 0 | { |
1643 | 0 | m_apSvNumberFormatter->ChangeNullDate(aNullDate.Day, aNullDate.Month, aNullDate.Year); |
1644 | 0 | } |
1645 | 0 | } |
1646 | | |
1647 | | std::optional<css::util::DateTime> ChartModel::getNullDate() const |
1648 | 0 | { |
1649 | 0 | return m_aNullDate; |
1650 | 0 | } |
1651 | | |
1652 | | } // namespace chart |
1653 | | |
1654 | | extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * |
1655 | | com_sun_star_comp_chart2_ChartModel_get_implementation(css::uno::XComponentContext *context, |
1656 | | css::uno::Sequence<css::uno::Any> const &) |
1657 | 0 | { |
1658 | 0 | return cppu::acquire(new ::chart::ChartModel(context)); |
1659 | 0 | } |
1660 | | |
1661 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |