LibreOffice Module chart2 (master) 1
ChartModel_Persistence.cxx
Go to the documentation of this file.
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 <memory>
21#include <ChartModel.hxx>
23#include <ChartViewHelper.hxx>
24#include <ChartModelHelper.hxx>
25#include <ChartTypeManager.hxx>
26#include <ChartTypeTemplate.hxx>
27#include <DataSourceHelper.hxx>
28#include <AxisHelper.hxx>
29#include <ThreeDHelper.hxx>
30#include <Diagram.hxx>
31#include <DiagramHelper.hxx>
33#include <Legend.hxx>
34#include <XMLFilter.hxx>
35
36#include <com/sun/star/chart2/LegendPosition.hpp>
37#include <com/sun/star/container/XNameAccess.hpp>
38#include <com/sun/star/document/XExporter.hpp>
39#include <com/sun/star/document/XImporter.hpp>
40#include <com/sun/star/document/XFilter.hpp>
41#include <com/sun/star/drawing/FillStyle.hpp>
42#include <com/sun/star/drawing/LineStyle.hpp>
43#include <com/sun/star/drawing/ProjectionMode.hpp>
44#include <com/sun/star/embed/ElementModes.hpp>
45#include <com/sun/star/embed/XStorage.hpp>
46#include <com/sun/star/embed/StorageFactory.hpp>
47#include <com/sun/star/io/IOException.hpp>
48#include <com/sun/star/lang/XSingleServiceFactory.hpp>
49#include <com/sun/star/uno/XComponentContext.hpp>
50#include <com/sun/star/io/TempFile.hpp>
51#include <com/sun/star/io/XSeekable.hpp>
52#include <com/sun/star/ucb/CommandFailedException.hpp>
53#include <com/sun/star/ucb/ContentCreationException.hpp>
54
55#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
56
57#include <ucbhelper/content.hxx>
59#include <unotools/tempfile.hxx>
60#include <utility>
61#include <vcl/cvtgrf.hxx>
64#include <vcl/settings.hxx>
65#include <vcl/svapp.hxx>
67#include <sal/log.hxx>
68#include <sfx2/objsh.hxx>
69
70#include <algorithm>
71
72using namespace ::com::sun::star;
73
74using ::com::sun::star::uno::Reference;
75using ::com::sun::star::uno::Sequence;
76using ::osl::MutexGuard;
77
78namespace
79{
80struct lcl_PropNameEquals
81{
82 explicit lcl_PropNameEquals( OUString aStrToCompareWith ) :
83 m_aStr(std::move( aStrToCompareWith ))
84 {}
85 bool operator() ( const beans::PropertyValue & rProp )
86 {
87 return rProp.Name == m_aStr;
88 }
89private:
90 OUString m_aStr;
91};
92
93template< typename T >
94T lcl_getProperty(
95 const Sequence< beans::PropertyValue > & rMediaDescriptor,
96 const OUString & rPropName )
97{
98 T aResult;
99 if( rMediaDescriptor.hasElements())
100 {
101 const beans::PropertyValue * pIt = rMediaDescriptor.getConstArray();
102 const beans::PropertyValue * pEndIt = pIt + + rMediaDescriptor.getLength();
103 pIt = std::find_if( pIt, pEndIt, lcl_PropNameEquals( rPropName ));
104 if( pIt != pEndIt )
105 (*pIt).Value >>= aResult;
106 }
107 return aResult;
108}
109
110void lcl_addStorageToMediaDescriptor(
111 Sequence< beans::PropertyValue > & rOutMD,
112 const Reference< embed::XStorage > & xStorage )
113{
114 rOutMD.realloc( rOutMD.getLength() + 1 );
115 rOutMD.getArray()[rOutMD.getLength() - 1] = beans::PropertyValue(
116 "Storage", -1, uno::Any( xStorage ), beans::PropertyState_DIRECT_VALUE );
117}
118
119Reference< embed::XStorage > lcl_createStorage(
120 const OUString & rURL,
121 const Reference< uno::XComponentContext > & xContext,
122 const Sequence< beans::PropertyValue > & rMediaDescriptor )
123{
124 // create new storage
125 Reference< embed::XStorage > xStorage;
126 if( !xContext.is())
127 return xStorage;
128
129 try
130 {
131 Reference< io::XStream > xStream(
132 ::ucbhelper::Content( rURL, Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext()).openStream(),
133 uno::UNO_QUERY );
134
135 Reference< lang::XSingleServiceFactory > xStorageFact( embed::StorageFactory::create( xContext ) );
136 Sequence< uno::Any > aStorageArgs{ uno::Any(xStream),
137 uno::Any(embed::ElementModes::READWRITE),
138 uno::Any(rMediaDescriptor) };
139 xStorage.set(
140 xStorageFact->createInstanceWithArguments( aStorageArgs ), uno::UNO_QUERY_THROW );
141 }
142 catch(const css::ucb::ContentCreationException&)
143 {
144 DBG_UNHANDLED_EXCEPTION("chart2");
145 }
146 catch(const css::ucb::CommandFailedException&)
147 {
148 DBG_UNHANDLED_EXCEPTION("chart2");
149 }
150
151 return xStorage;
152}
153
154} // anonymous namespace
155
156namespace chart
157{
158
159Reference< document::XFilter > ChartModel::impl_createFilter(
160 const Sequence< beans::PropertyValue > & rMediaDescriptor )
161{
162 Reference< document::XFilter > xFilter;
163
164 // find FilterName in MediaDescriptor
165 OUString aFilterName(
166 lcl_getProperty< OUString >( rMediaDescriptor, "FilterName" ) );
167
168 // if FilterName was found, get Filter from factory
169 if( !aFilterName.isEmpty() )
170 {
171 try
172 {
173 Reference< container::XNameAccess > xFilterFact(
174 m_xContext->getServiceManager()->createInstanceWithContext(
175 "com.sun.star.document.FilterFactory", m_xContext ),
176 uno::UNO_QUERY_THROW );
177 uno::Any aFilterProps( xFilterFact->getByName( aFilterName ));
178 Sequence< beans::PropertyValue > aProps;
179
180 if( aFilterProps.hasValue() &&
181 (aFilterProps >>= aProps))
182 {
183 OUString aFilterServiceName(
184 lcl_getProperty< OUString >( aProps, "FilterService" ) );
185
186 if( !aFilterServiceName.isEmpty())
187 {
188 xFilter.set(
189 m_xContext->getServiceManager()->createInstanceWithContext(
190 aFilterServiceName, m_xContext ), uno::UNO_QUERY_THROW );
191 SAL_INFO("chart2", "Filter found for service " << aFilterServiceName );
192 }
193 }
194 }
195 catch( const uno::Exception & )
196 {
197 DBG_UNHANDLED_EXCEPTION("chart2");
198 }
199 OSL_ENSURE( xFilter.is(), "Filter not found via factory" );
200 }
201
202 // fall-back: create XML-Filter
203 if( ! xFilter.is())
204 {
205 SAL_WARN("chart2", "No FilterName passed in MediaDescriptor" );
206 xFilter = new XMLFilter(m_xContext);
207 }
208
209 return xFilter;
210}
211
212// frame::XStorable2
213
214void SAL_CALL ChartModel::storeSelf( const Sequence< beans::PropertyValue >& rMediaDescriptor )
215{
216 // only some parameters are allowed (see also SfxBaseModel)
217 // "VersionComment", "Author", "InteractionHandler", "StatusIndicator"
218 // However, they are ignored here. They would become interesting when
219 // charts support a standalone format again.
220 impl_store( rMediaDescriptor, m_xStorage );
221}
222
223// frame::XStorable (base of XStorable2)
224sal_Bool SAL_CALL ChartModel::hasLocation()
225{
226 //@todo guard
227 return !m_aResource.isEmpty();
228}
229
230OUString SAL_CALL ChartModel::getLocation()
231{
232 return impl_g_getLocation();
233}
234
235sal_Bool SAL_CALL ChartModel::isReadonly()
236{
237 //@todo guard
238 return m_bReadOnly;
239}
240
241void SAL_CALL ChartModel::store()
242{
243 apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager);
244 if(!aGuard.startApiCall(true)) //start LongLastingCall
245 return; //behave passive if already disposed or closed or throw exception @todo?
246
247 OUString aLocation = m_aResource;
248
249 if( aLocation.isEmpty() )
250 throw io::IOException( "no location specified", static_cast< ::cppu::OWeakObject* >(this));
251 //@todo check whether aLocation is something like private:factory...
252 if( m_bReadOnly )
253 throw io::IOException( "document is read only", static_cast< ::cppu::OWeakObject* >(this));
254
255 aGuard.clear();
256
257 // store
258 impl_store( m_aMediaDescriptor, m_xStorage );
259}
260
261void SAL_CALL ChartModel::storeAsURL(
262 const OUString& rURL,
263 const uno::Sequence< beans::PropertyValue >& rMediaDescriptor )
264{
265 apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager);
266 if(!aGuard.startApiCall(true)) //start LongLastingCall
267 return; //behave passive if already disposed or closed or throw exception @todo?
268
269 apphelper::MediaDescriptorHelper aMediaDescriptorHelper(rMediaDescriptor);
270 uno::Sequence< beans::PropertyValue > aReducedMediaDescriptor(
271 aMediaDescriptorHelper.getReducedForModel() );
272
273 m_bReadOnly = false;
274 aGuard.clear();
275
276 // create new storage
277 Reference< embed::XStorage > xStorage( lcl_createStorage( rURL, m_xContext, aReducedMediaDescriptor ));
278
279 if( xStorage.is())
280 {
281 impl_store( aReducedMediaDescriptor, xStorage );
282 attachResource( rURL, aReducedMediaDescriptor );
283 }
284}
285
286void SAL_CALL ChartModel::storeToURL(
287 const OUString& rURL,
288 const uno::Sequence< beans::PropertyValue >& rMediaDescriptor )
289{
290 apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager);
291 if(!aGuard.startApiCall(true)) //start LongLastingCall
292 return; //behave passive if already disposed or closed or throw exception @todo?
293 //do not change the internal state of the document here
294
295 aGuard.clear();
296
297 apphelper::MediaDescriptorHelper aMediaDescriptorHelper(rMediaDescriptor);
298 uno::Sequence< beans::PropertyValue > aReducedMediaDescriptor(
299 aMediaDescriptorHelper.getReducedForModel() );
300
301 if ( rURL == "private:stream" )
302 {
303 try
304 {
305 if( m_xContext.is() && aMediaDescriptorHelper.ISSET_OutputStream )
306 {
308 Reference< io::XInputStream > xInputStream( xStream->getInputStream());
309
310 Reference< embed::XStorage > xStorage(
311 ::comphelper::OStorageHelper::GetStorageFromStream( xStream, embed::ElementModes::READWRITE, m_xContext ));
312 if( xStorage.is())
313 {
314 impl_store( aReducedMediaDescriptor, xStorage );
315
316 xStream->seek( 0 );
317 ::comphelper::OStorageHelper::CopyInputToOutput( xInputStream, aMediaDescriptorHelper.OutputStream );
318 }
319 }
320 }
321 catch( const uno::Exception & )
322 {
323 DBG_UNHANDLED_EXCEPTION("chart2");
324 }
325 }
326 else
327 {
328 // create new storage
329 Reference< embed::XStorage > xStorage( lcl_createStorage( rURL, m_xContext, aReducedMediaDescriptor ));
330
331 if( xStorage.is())
332 impl_store( aReducedMediaDescriptor, xStorage );
333 }
334}
335
336void ChartModel::impl_store(
337 const Sequence< beans::PropertyValue >& rMediaDescriptor,
338 const Reference< embed::XStorage > & xStorage )
339{
340 Reference< document::XFilter > xFilter( impl_createFilter( rMediaDescriptor));
341 if( xFilter.is() && xStorage.is())
342 {
343 Sequence< beans::PropertyValue > aMD( rMediaDescriptor );
344 lcl_addStorageToMediaDescriptor( aMD, xStorage );
345 try
346 {
347 Reference< document::XExporter > xExporter( xFilter, uno::UNO_QUERY_THROW );
348 xExporter->setSourceDocument( Reference< lang::XComponent >( this ));
349 xFilter->filter( aMD );
350 }
351 catch( const uno::Exception & )
352 {
353 DBG_UNHANDLED_EXCEPTION("chart2");
354 }
355 }
356 else
357 {
358 OSL_FAIL( "No filter" );
359 }
360
361 setModified( false );
362
363 //#i66865#
364 //for data change notification during chart is not loaded:
365 //notify parent data provider after saving thus the parent document can store
366 //the ranges for which a load and update of the chart will be necessary
367 Reference< beans::XPropertySet > xPropSet( m_xParent, uno::UNO_QUERY );
368 if ( hasInternalDataProvider() || !xPropSet.is() )
369 return;
370
371 apphelper::MediaDescriptorHelper aMDHelper(rMediaDescriptor);
372 try
373 {
374 xPropSet->setPropertyValue(
375 "SavedObject",
376 uno::Any( aMDHelper.HierarchicalDocumentName ) );
377 }
378 catch ( const uno::Exception& )
379 {
380 }
381}
382
383void ChartModel::insertDefaultChart()
384{
385 lockControllers();
386 createInternalDataProvider( false );
387 try
388 {
389 // create default chart
390 rtl::Reference< ::chart::ChartTypeTemplate > xTemplate( impl_createDefaultChartTypeTemplate() );
391 if( xTemplate.is())
392 {
393 try
394 {
395 Reference< chart2::data::XDataSource > xDataSource( impl_createDefaultData() );
396 Sequence< beans::PropertyValue > aParam;
397
398 bool bSupportsCategories = xTemplate->supportsCategories();
399 if( bSupportsCategories )
400 {
401 aParam = { beans::PropertyValue( "HasCategories", -1, uno::Any( true ),
402 beans::PropertyState_DIRECT_VALUE ) };
403 }
404
405 rtl::Reference< Diagram > xDiagram( xTemplate->createDiagramByDataSource2( xDataSource, aParam ) );
406
407 setFirstDiagram( xDiagram );
408
409 bool bIsRTL = AllSettings::GetMathLayoutRTL();
410 //reverse x axis for rtl charts
411 if( bIsRTL )
413
414 // create and attach legend
415 rtl::Reference< Legend > xLegend = new Legend();
416 xLegend->setPropertyValue( "FillStyle", uno::Any( drawing::FillStyle_NONE ));
417 xLegend->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_NONE ));
418 xLegend->setPropertyValue( "LineColor", uno::Any( static_cast< sal_Int32 >( 0xb3b3b3 ) )); // gray30
419 xLegend->setPropertyValue( "FillColor", uno::Any( static_cast< sal_Int32 >( 0xe6e6e6 ) ) ); // gray10
420
421 if( bIsRTL )
422 xLegend->setPropertyValue( "AnchorPosition", uno::Any( chart2::LegendPosition_LINE_START ));
423 if(xDiagram.is())
424 xDiagram->setLegend( xLegend );
425
426 // set simple 3D look
427 if( xDiagram.is() )
428 {
429 xDiagram->setPropertyValue( "RightAngledAxes", uno::Any( true ));
430 xDiagram->setPropertyValue( "D3DScenePerspective", uno::Any( drawing::ProjectionMode_PARALLEL ));
432 }
433
434 //set some new 'defaults' for wall and floor
435 if( xDiagram.is() )
436 {
437 Reference< beans::XPropertySet > xWall( xDiagram->getWall() );
438 if( xWall.is() )
439 {
440 xWall->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_SOLID ) );
441 xWall->setPropertyValue( "FillStyle", uno::Any( drawing::FillStyle_NONE ) );
442 xWall->setPropertyValue( "LineColor", uno::Any( static_cast< sal_Int32 >( 0xb3b3b3 ) ) ); // gray30
443 xWall->setPropertyValue( "FillColor", uno::Any( static_cast< sal_Int32 >( 0xe6e6e6 ) ) ); // gray10
444 }
445 Reference< beans::XPropertySet > xFloor( xDiagram->getFloor() );
446 if( xFloor.is() )
447 {
448 xFloor->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_NONE ) );
449 xFloor->setPropertyValue( "FillStyle", uno::Any( drawing::FillStyle_SOLID ) );
450 xFloor->setPropertyValue( "LineColor", uno::Any( static_cast< sal_Int32 >( 0xb3b3b3 ) ) ); // gray30
451 xFloor->setPropertyValue( "FillColor", uno::Any( static_cast< sal_Int32 >( 0xcccccc ) ) ); // gray20
452 }
453
454 }
455 }
456 catch( const uno::Exception & )
457 {
458 DBG_UNHANDLED_EXCEPTION("chart2");
459 }
460 }
462 }
463 catch( const uno::Exception & )
464 {
465 DBG_UNHANDLED_EXCEPTION("chart2");
466 }
467 setModified( false );
468 unlockControllers();
469}
470
471// frame::XLoadable
472void SAL_CALL ChartModel::initNew()
473{
474}
475
476void SAL_CALL ChartModel::load(
477 const Sequence< beans::PropertyValue >& rMediaDescriptor )
478{
479 Reference< embed::XStorage > xStorage;
480 OUString aURL;
481 try
482 {
483 apphelper::MediaDescriptorHelper aMDHelper( rMediaDescriptor );
484 if( aMDHelper.ISSET_Storage )
485 {
486 xStorage = aMDHelper.Storage;
487 }
488 else if( aMDHelper.ISSET_Stream ||
489 aMDHelper.ISSET_InputStream )
490 {
491 if( aMDHelper.ISSET_FilterName &&
492 (aMDHelper.FilterName == "StarChart 5.0" ||
493 aMDHelper.FilterName == "StarChart 4.0" ||
494 aMDHelper.FilterName == "StarChart 3.0" ))
495 {
496 attachResource( aMDHelper.URL, rMediaDescriptor );
497 impl_load( rMediaDescriptor, nullptr ); // cannot create a storage from binary streams, but I do not need the storage here anyhow
498 m_bReadOnly = true;
499 return;
500 }
501
502 Reference< lang::XSingleServiceFactory > xStorageFact( embed::StorageFactory::create(m_xContext) );
503
504 if( aMDHelper.ISSET_Stream )
505 {
506 // convert XStream to XStorage via the storage factory
507 Sequence< uno::Any > aStorageArgs{ uno::Any(aMDHelper.Stream),
508 // todo: check if stream is read-only
509 uno::Any(embed::ElementModes::READ) }; //WRITE | embed::ElementModes::NOCREATE);
510
511 xStorage.set( xStorageFact->createInstanceWithArguments( aStorageArgs ),
512 uno::UNO_QUERY_THROW );
513 }
514 else
515 {
516 OSL_ASSERT( aMDHelper.ISSET_InputStream );
517 // convert XInputStream to XStorage via the storage factory
518 Sequence< uno::Any > aStorageArgs{ uno::Any(aMDHelper.InputStream),
519 uno::Any(embed::ElementModes::READ) };
520
521 xStorage.set( xStorageFact->createInstanceWithArguments( aStorageArgs ),
522 uno::UNO_QUERY_THROW );
523 }
524 }
525
526 if( aMDHelper.ISSET_URL )
527 aURL = aMDHelper.URL;
528 }
529 catch( const uno::Exception & )
530 {
531 DBG_UNHANDLED_EXCEPTION("chart2");
532 }
533
534 if( xStorage.is())
535 {
536 attachResource( aURL, rMediaDescriptor );
537 impl_load( rMediaDescriptor, xStorage );
538 }
539}
540
541void ChartModel::impl_load(
542 const Sequence< beans::PropertyValue >& rMediaDescriptor,
543 const Reference< embed::XStorage >& xStorage )
544{
545 {
546 MutexGuard aGuard( m_aModelMutex );
547 m_nInLoad++;
548 }
549
550 Reference< document::XFilter > xFilter( impl_createFilter( rMediaDescriptor ));
551
552 if( xFilter.is())
553 {
554 Reference< document::XImporter > xImporter( xFilter, uno::UNO_QUERY_THROW );
555 xImporter->setTargetDocument( this );
556 Sequence< beans::PropertyValue > aMD( rMediaDescriptor );
557 lcl_addStorageToMediaDescriptor( aMD, xStorage );
558
559 xFilter->filter( aMD );
560 xFilter.clear();
561 }
562 else
563 {
564 OSL_FAIL( "loadFromStorage cannot create filter" );
565 }
566
567 if( xStorage.is() )
568 impl_loadGraphics( xStorage );
569
570 setModified( false );
571
572 // switchToStorage without notifying listeners (which shouldn't exist at
573 // this time, anyway)
574 m_xStorage = xStorage;
575
576 {
577 MutexGuard aGuard( m_aModelMutex );
578 m_nInLoad--;
579 }
580}
581
582void ChartModel::impl_loadGraphics(
583 const Reference< embed::XStorage >& xStorage )
584{
585 try
586 {
587 const Reference< embed::XStorage >& xGraphicsStorage(
588 xStorage->openStorageElement( "Pictures",
589 embed::ElementModes::READ ) );
590
591 if( xGraphicsStorage.is() )
592 {
593 const uno::Sequence< OUString > aElementNames(
594 xGraphicsStorage->getElementNames() );
595
596 for( OUString const & streamName : aElementNames )
597 {
598 if( xGraphicsStorage->isStreamElement( streamName ) )
599 {
600 uno::Reference< io::XStream > xElementStream(
601 xGraphicsStorage->openStreamElement(
602 streamName,
603 embed::ElementModes::READ ) );
604
605 if( xElementStream.is() )
606 {
607 std::unique_ptr< SvStream > apIStm(
609 xElementStream, true ) );
610
611 if (apIStm)
612 {
613 SolarMutexGuard aGuard;
614 Graphic aGraphic;
615 if (!GraphicConverter::Import(*apIStm, aGraphic))
616 {
617 m_aGraphicObjectVector.emplace_back(aGraphic );
618 }
619 }
620 }
621 }
622 }
623 }
624 }
625 catch ( const uno::Exception& )
626 {
627 }
628}
629
630// util::XModifiable
631void ChartModel::impl_notifyModifiedListeners()
632{
633 {
634 MutexGuard aGuard( m_aModelMutex );
635 m_bUpdateNotificationsPending = false;
636 }
637
638 //always notify the view first!
640
641 std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
642 if( m_aLifeTimeManager.m_aModifyListeners.getLength(aGuard) )
643 {
644 lang::EventObject aEvent( static_cast< lang::XComponent*>(this) );
645 m_aLifeTimeManager.m_aModifyListeners.notifyEach(aGuard, &util::XModifyListener::modified, aEvent);
646 }
647}
648
649sal_Bool SAL_CALL ChartModel::isModified()
650{
651 //@todo guard
652 return m_bModified;
653}
654
655void SAL_CALL ChartModel::setModified( sal_Bool bModified )
656{
657 // tdf#141914: allow to set *unmodified* when parent does not allow to set modified
658 if (bModified)
659 {
660 // tdf#77007: honor parent's IsEnableSetModified
661 // Check it before LifeTimeGuard, to avoid deadlocking solar mutex and this guard
662 if (auto pParentShell = SfxObjectShell::GetShellFromComponent(getParent());
663 pParentShell && !pParentShell->IsEnableSetModified())
664 return;
665 }
666
667 apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager);
668 if(!aGuard.startApiCall())//@todo ? is this a long lasting call??
669 return; //behave passive if already disposed or closed or throw exception @todo?
670 m_bModified = bModified;
671
672 if( m_nControllerLockCount > 0 )
673 {
674 m_bUpdateNotificationsPending = true;
675 return;//don't call listeners if controllers are locked
676 }
677 aGuard.clear();
678
679 if(bModified)
680 impl_notifyModifiedListeners();
681}
682
683// util::XModifyBroadcaster (base of XModifiable)
684void SAL_CALL ChartModel::addModifyListener(
685 const uno::Reference< util::XModifyListener >& xListener )
686{
687 if( m_aLifeTimeManager.impl_isDisposedOrClosed() )
688 return; //behave passive if already disposed or closed
689
690 std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
691 m_aLifeTimeManager.m_aModifyListeners.addInterface( aGuard, xListener );
692}
693
694void SAL_CALL ChartModel::removeModifyListener(
695 const uno::Reference< util::XModifyListener >& xListener )
696{
697 if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) )
698 return; //behave passive if already disposed or closed
699
700 std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
701 m_aLifeTimeManager.m_aModifyListeners.removeInterface( aGuard, xListener );
702}
703
704// util::XModifyListener
705void SAL_CALL ChartModel::modified( const lang::EventObject& rEvenObject)
706{
707 uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(rEvenObject.Source, uno::UNO_QUERY);
708 if (xPivotTableDataProvider.is())
709 {
710 lockControllers();
711 uno::Reference<chart2::data::XDataProvider> xDataProvider(xPivotTableDataProvider, uno::UNO_QUERY);
712 try
713 {
714 uno::Sequence<beans::PropertyValue> aArguments =
715 DataSourceHelper::createArguments("PivotChart", uno::Sequence<sal_Int32>(), true, true, true);
716
717 Reference<chart2::data::XDataSource> xDataSource(xDataProvider->createDataSource(aArguments));
718 rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = getTypeManager();
719 rtl::Reference<Diagram> xDiagram(getFirstChartDiagram());
720
721 Diagram::tTemplateWithServiceName aTemplateAndService = xDiagram->getTemplate(xChartTypeManager);
722 aTemplateAndService.xChartTypeTemplate->changeDiagramData(xDiagram, xDataSource, aArguments);
723 }
724 catch (const uno::Exception &)
725 {
726 DBG_UNHANDLED_EXCEPTION("chart2");
727 }
728 unlockControllers();
729 }
730
731 if (m_nInLoad == 0)
732 setModified(true);
733}
734
735// lang::XEventListener (base of util::XModifyListener)
736void SAL_CALL ChartModel::disposing( const lang::EventObject& )
737{
738 // child was disposed -- should not happen from outside
739}
740
741// document::XStorageBasedDocument
742void SAL_CALL ChartModel::loadFromStorage(
743 const Reference< embed::XStorage >& xStorage,
744 const Sequence< beans::PropertyValue >& rMediaDescriptor )
745{
746 attachResource( OUString(), rMediaDescriptor );
747 impl_load( rMediaDescriptor, xStorage );
748}
749
750void SAL_CALL ChartModel::storeToStorage(
751 const Reference< embed::XStorage >& xStorage,
752 const Sequence< beans::PropertyValue >& rMediaDescriptor )
753{
754 impl_store( rMediaDescriptor, xStorage );
755}
756
757void SAL_CALL ChartModel::switchToStorage( const Reference< embed::XStorage >& xStorage )
758{
759 m_xStorage = xStorage;
760 impl_notifyStorageChangeListeners();
761}
762
763Reference< embed::XStorage > SAL_CALL ChartModel::getDocumentStorage()
764{
765 return m_xStorage;
766}
767
768void ChartModel::impl_notifyStorageChangeListeners()
769{
770 std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
771 if( m_aLifeTimeManager.m_aStorageChangeListeners.getLength(aGuard) )
772 {
773 m_aLifeTimeManager.m_aStorageChangeListeners.forEach(aGuard,
774 [this](const uno::Reference<document::XStorageChangeListener>& l)
775 {
776 l->notifyStorageChange( static_cast< ::cppu::OWeakObject* >( this ), m_xStorage );
777 });
778 }
779}
780
781void SAL_CALL ChartModel::addStorageChangeListener( const Reference< document::XStorageChangeListener >& xListener )
782{
783 if( m_aLifeTimeManager.impl_isDisposedOrClosed() )
784 return; //behave passive if already disposed or closed
785
786 std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
787 m_aLifeTimeManager.m_aStorageChangeListeners.addInterface( aGuard, xListener );
788}
789
790void SAL_CALL ChartModel::removeStorageChangeListener( const Reference< document::XStorageChangeListener >& xListener )
791{
792 if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) )
793 return; //behave passive if already disposed or closed
794
795 std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
796 m_aLifeTimeManager.m_aStorageChangeListeners.removeInterface(aGuard, xListener );
797}
798
799} // namespace chart
800
801/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< uno::XComponentContext > m_xContext
Reference< XInputStream > xStream
AnyEventRef aEvent
static bool GetMathLayoutRTL()
static ErrCode Import(SvStream &rIStm, Graphic &rGraphic, ConvertDataFormat nFormat=ConvertDataFormat::Unknown)
static SfxObjectShell * GetShellFromComponent(const css::uno::Reference< css::uno::XInterface > &xComp)
bool IsEnableSetModified() const
static rtl::Reference< ::chart::BaseCoordinateSystem > getCoordinateSystemByIndex(const rtl::Reference< ::chart::Diagram > &xDiagram, sal_Int32 nIndex)
Definition: AxisHelper.cxx:550
static void setRTLAxisLayout(const rtl::Reference< ::chart::BaseCoordinateSystem > &xCooSys)
static bool setIncludeHiddenCells(bool bIncludeHiddenCells, ChartModel &rModel)
static void setViewToDirtyState(const rtl::Reference<::chart::ChartModel > &xChartModel)
static css::uno::Sequence< css::beans::PropertyValue > createArguments(bool bUseColumns, bool bFirstCellAsLabel, bool bHasCategories)
static css::uno::Reference< css::embed::XStorage > GetStorageFromStream(const css::uno::Reference< css::io::XStream > &xStream, sal_Int32 nStorageMode=css::embed::ElementModes::READWRITE, const css::uno::Reference< css::uno::XComponentContext > &rxContext=css::uno::Reference< css::uno::XComponentContext >())
static void CopyInputToOutput(const css::uno::Reference< css::io::XInputStream > &xInput, const css::uno::Reference< css::io::XOutputStream > &xOutput)
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
#define DBG_UNHANDLED_EXCEPTION(...)
URL aURL
bool m_bReadOnly
Sequence< PropertyValue > aArguments
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
Reference< XComponentContext > getProcessComponentContext()
unsigned char sal_Bool