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