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