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_chart2.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__anona22cd80e0111::lcl_PropNameEquals73     lcl_PropNameEquals( const OUString & rStrToCompareWith ) :
74             m_aStr( rStrToCompareWith )
75     {}
operator ()__anona22cd80e0111::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     throw (lang::IllegalArgumentException,
215            io::IOException,
216            uno::RuntimeException)
217 {
218     // only some parameters are allowed (see also SfxBaseModel)
219     // "VersionComment", "Author", "InteractionHandler", "StatusIndicator"
220     // However, they are ignored here.  They would become interesting when
221     // charts support a standalone format again.
222     impl_store( rMediaDescriptor, m_xStorage );
223 }
224 
225 //-----------------------------------------------------------------
226 // frame::XStorable (base of XStorable2)
227 //-----------------------------------------------------------------
hasLocation()228 sal_Bool SAL_CALL ChartModel::hasLocation()
229     throw(uno::RuntimeException)
230 {
231 	//@todo guard
232 	return !m_aResource.isEmpty();
233 }
234 
getLocation()235 ::rtl::OUString SAL_CALL ChartModel::getLocation()
236     throw(uno::RuntimeException)
237 {
238 	return impl_g_getLocation();
239 }
240 
isReadonly()241 sal_Bool SAL_CALL ChartModel::isReadonly()
242     throw(uno::RuntimeException)
243 {
244 	//@todo guard
245 	return m_bReadOnly;
246 }
247 
store()248 void SAL_CALL ChartModel::store()
249     throw(io::IOException,
250           uno::RuntimeException)
251 {
252 	apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager);
253 	if(!aGuard.startApiCall(sal_True)) //start LongLastingCall
254 		return; //behave passive if already disposed or closed or throw exception @todo?
255 
256 	::rtl::OUString aLocation = m_aResource;
257 
258 	if( aLocation.isEmpty() )
259 		throw io::IOException( C2U( "no location specified" ), static_cast< ::cppu::OWeakObject* >(this));
260 	//@todo check wether aLocation is something like private:factory...
261 	if( m_bReadOnly )
262 		throw io::IOException( C2U( "document is read only" ), static_cast< ::cppu::OWeakObject* >(this));
263 
264     aGuard.clear();
265 
266     // store
267     impl_store( m_aMediaDescriptor, m_xStorage );
268 }
269 
storeAsURL(const::rtl::OUString & rURL,const uno::Sequence<beans::PropertyValue> & rMediaDescriptor)270 void SAL_CALL ChartModel::storeAsURL(
271     const ::rtl::OUString& rURL,
272     const uno::Sequence< beans::PropertyValue >& rMediaDescriptor )
273     throw(io::IOException, uno::RuntimeException)
274 {
275 	apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager);
276 	if(!aGuard.startApiCall(sal_True)) //start LongLastingCall
277 		return; //behave passive if already disposed or closed or throw exception @todo?
278 
279 	apphelper::MediaDescriptorHelper aMediaDescriptorHelper(rMediaDescriptor);
280     uno::Sequence< beans::PropertyValue > aReducedMediaDescriptor(
281         aMediaDescriptorHelper.getReducedForModel() );
282 
283 	m_bReadOnly = sal_False;
284     aGuard.clear();
285 
286     // create new storage
287     Reference< embed::XStorage > xStorage( lcl_createStorage( rURL, m_xContext, aReducedMediaDescriptor ));
288 
289     if( xStorage.is())
290     {
291         impl_store( aReducedMediaDescriptor, xStorage );
292         attachResource( rURL, aReducedMediaDescriptor );
293     }
294 }
295 
storeToURL(const::rtl::OUString & rURL,const uno::Sequence<beans::PropertyValue> & rMediaDescriptor)296 void SAL_CALL ChartModel::storeToURL(
297     const ::rtl::OUString& rURL,
298     const uno::Sequence< beans::PropertyValue >& rMediaDescriptor )
299     throw(io::IOException,
300           uno::RuntimeException)
301 {
302 	apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager);
303 	if(!aGuard.startApiCall(sal_True)) //start LongLastingCall
304 		return; //behave passive if already disposed or closed or throw exception @todo?
305 	//do not change the internal state of the document here
306 	//...
307 
308     aGuard.clear();
309 
310     apphelper::MediaDescriptorHelper aMediaDescriptorHelper(rMediaDescriptor);
311     uno::Sequence< beans::PropertyValue > aReducedMediaDescriptor(
312         aMediaDescriptorHelper.getReducedForModel() );
313 
314     if( rURL.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("private:stream")))
315     {
316         try
317         {
318             if( m_xContext.is() && aMediaDescriptorHelper.ISSET_OutputStream )
319             {
320                 Reference< lang::XMultiServiceFactory > xFact( m_xContext->getServiceManager(), uno::UNO_QUERY_THROW );
321                 Reference< io::XStream > xStream(
322                     xFact->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.io.TempFile"))), uno::UNO_QUERY_THROW );
323                 Reference< io::XInputStream > xInputStream( xStream->getInputStream());
324 
325                 Reference< embed::XStorage > xStorage(
326                     ::comphelper::OStorageHelper::GetStorageFromStream( xStream, embed::ElementModes::READWRITE, xFact ));
327                 if( xStorage.is())
328                 {
329                     impl_store( aReducedMediaDescriptor, xStorage );
330 
331                     Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY_THROW );
332                     xSeekable->seek( 0 );
333                     ::comphelper::OStorageHelper::CopyInputToOutput( xInputStream, aMediaDescriptorHelper.OutputStream );
334                 }
335             }
336         }
337         catch( const uno::Exception & ex )
338         {
339             ASSERT_EXCEPTION( ex );
340         }
341     }
342     else
343     {
344         // create new storage
345         Reference< embed::XStorage > xStorage( lcl_createStorage( rURL, m_xContext, aReducedMediaDescriptor ));
346 
347         if( xStorage.is())
348             impl_store( aReducedMediaDescriptor, xStorage );
349     }
350 }
351 
impl_store(const Sequence<beans::PropertyValue> & rMediaDescriptor,const Reference<embed::XStorage> & xStorage)352 void ChartModel::impl_store(
353     const Sequence< beans::PropertyValue >& rMediaDescriptor,
354     const Reference< embed::XStorage > & xStorage )
355 {
356     Reference< document::XFilter > xFilter( impl_createFilter( rMediaDescriptor));
357     if( xFilter.is() && xStorage.is())
358     {
359         Sequence< beans::PropertyValue > aMD( rMediaDescriptor );
360         lcl_addStorageToMediaDescriptor( aMD, xStorage );
361         try
362         {
363             Reference< document::XExporter > xExporter( xFilter, uno::UNO_QUERY_THROW );
364             xExporter->setSourceDocument( Reference< lang::XComponent >( this ));
365             xFilter->filter( aMD );
366         }
367         catch( uno::Exception & ex )
368         {
369             ASSERT_EXCEPTION( ex );
370         }
371     }
372     else
373     {
374         OSL_ENSURE( false, "No filter" );
375     }
376 
377     setModified( sal_False );
378 
379     //#i66865#
380     //for data change notification during chart is not loaded:
381     //notify parent data provider after saving thus the parent document can store
382     //the ranges for which a load and update of the chart will be necessary
383     Reference< beans::XPropertySet > xPropSet( m_xParent, uno::UNO_QUERY );
384     if ( !hasInternalDataProvider() && xPropSet.is() )
385     {
386         apphelper::MediaDescriptorHelper aMDHelper(rMediaDescriptor);
387         try
388         {
389             xPropSet->setPropertyValue( OUString::createFromAscii("SavedObject"),
390                 uno::makeAny( aMDHelper.HierarchicalDocumentName ) );
391         }
392         catch ( uno::Exception& )
393         {
394         }
395     }
396 }
397 
398 //-----------------------------------------------------------------
399 // frame::XLoadable
400 //-----------------------------------------------------------------
initNew()401 void SAL_CALL ChartModel::initNew()
402     throw (frame::DoubleInitializationException,
403            io::IOException,
404            uno::Exception,
405            uno::RuntimeException)
406 {
407     lockControllers();
408     createInternalDataProvider( sal_False );
409     try
410     {
411         // create default chart
412         Reference< chart2::XChartTypeTemplate > xTemplate( impl_createDefaultChartTypeTemplate() );
413         if( xTemplate.is())
414         {
415             try
416             {
417                 Reference< chart2::data::XDataSource > xDataSource( impl_createDefaultData() );
418                 Sequence< beans::PropertyValue > aParam;
419 
420                 bool bSupportsCategories = xTemplate->supportsCategories();
421                 if( bSupportsCategories )
422                 {
423                     aParam.realloc( 1 );
424                     aParam[0] = beans::PropertyValue( C2U("HasCategories"), -1, uno::makeAny( true ),
425                                                       beans::PropertyState_DIRECT_VALUE );
426                 }
427 
428                 Reference< chart2::XDiagram > xDiagram( xTemplate->createDiagramByDataSource( xDataSource, aParam ) );
429 
430                 setFirstDiagram( xDiagram );
431 
432                 bool bIsRTL = Application::GetSettings().GetLayoutRTL();
433                 //reverse x axis for rtl charts
434                 if( bIsRTL )
435                     AxisHelper::setRTLAxisLayout( AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 ) );
436 
437                 // create and attach legend
438                 Reference< chart2::XLegend > xLegend(
439                     m_xContext->getServiceManager()->createInstanceWithContext(
440                         C2U( "com.sun.star.chart2.Legend" ), m_xContext ), uno::UNO_QUERY_THROW );
441                 Reference< beans::XPropertySet > xLegendProperties( xLegend, uno::UNO_QUERY );
442                 if( xLegendProperties.is() )
443                 {
444                     xLegendProperties->setPropertyValue( C2U( "FillStyle" ), uno::makeAny( drawing::FillStyle_NONE ));
445                     xLegendProperties->setPropertyValue( C2U( "LineStyle" ), uno::makeAny( drawing::LineStyle_NONE ));
446                     xLegendProperties->setPropertyValue( C2U( "LineColor" ), uno::makeAny( static_cast< sal_Int32 >( 0xb3b3b3 ) ));  // gray30
447                     xLegendProperties->setPropertyValue( C2U( "FillColor" ), uno::makeAny( static_cast< sal_Int32 >( 0xe6e6e6 ) ) ); // gray10
448 
449                     if( bIsRTL )
450                         xLegendProperties->setPropertyValue( C2U( "AnchorPosition" ), uno::makeAny( chart2::LegendPosition_LINE_START ));
451                 }
452                 if(xDiagram.is())
453                     xDiagram->setLegend( xLegend );
454 
455                 // set simple 3D look
456                 Reference< beans::XPropertySet > xDiagramProperties( xDiagram, uno::UNO_QUERY );
457                 if( xDiagramProperties.is() )
458                 {
459                     xDiagramProperties->setPropertyValue( C2U("RightAngledAxes"), uno::makeAny( sal_True ));
460                     xDiagramProperties->setPropertyValue( C2U("D3DScenePerspective"), uno::makeAny( drawing::ProjectionMode_PARALLEL ));
461                     ThreeDHelper::setScheme( xDiagram, ThreeDLookScheme_Realistic );
462                 }
463 
464                 //set some new 'defaults' for wall and floor
465                 if( xDiagram.is() )
466                 {
467                     Reference< beans::XPropertySet > xWall( xDiagram->getWall() );
468                     if( xWall.is() )
469                     {
470                         xWall->setPropertyValue( C2U( "LineStyle" ), uno::makeAny( drawing::LineStyle_SOLID ) );
471                         xWall->setPropertyValue( C2U( "FillStyle" ), uno::makeAny( drawing::FillStyle_NONE ) );
472                         xWall->setPropertyValue( C2U( "LineColor" ), uno::makeAny( static_cast< sal_Int32 >( 0xb3b3b3 ) ) ); // gray30
473                         xWall->setPropertyValue( C2U( "FillColor" ), uno::makeAny( static_cast< sal_Int32 >( 0xe6e6e6 ) ) ); // gray10
474                     }
475                     Reference< beans::XPropertySet > xFloor( xDiagram->getFloor() );
476                     if( xFloor.is() )
477                     {
478                         xFloor->setPropertyValue( C2U( "LineStyle" ), uno::makeAny( drawing::LineStyle_NONE ) );
479                         xFloor->setPropertyValue( C2U( "FillStyle" ), uno::makeAny( drawing::FillStyle_SOLID ) );
480                         xFloor->setPropertyValue( C2U( "LineColor" ), uno::makeAny( static_cast< sal_Int32 >( 0xb3b3b3 ) ) ); // gray30
481                         xFloor->setPropertyValue( C2U( "FillColor" ), uno::makeAny( static_cast< sal_Int32 >( 0xcccccc ) ) ); // gray20
482                     }
483 
484                 }
485             }
486             catch( uno::Exception & ex )
487             {
488                 ASSERT_EXCEPTION( ex );
489             }
490         }
491         ChartModelHelper::setIncludeHiddenCells( false, this );
492     }
493     catch( uno::Exception & ex )
494     {
495         ASSERT_EXCEPTION( ex );
496     }
497     setModified( sal_False );
498     unlockControllers();
499 
500 #if OSL_DEBUG_LEVEL >= CHART_TRACE_OSL_DEBUG_LEVEL
501     OSL_TRACE( "ChartModel::initNew: Showing ChartDocument structure" );
502     OSL_TRACE( "----------------------------------------------------" );
503     debug::ChartDebugTraceDocument( Reference< chart2::XChartDocument >( this ));
504 #endif
505 }
506 
load(const Sequence<beans::PropertyValue> & rMediaDescriptor)507 void SAL_CALL ChartModel::load(
508     const Sequence< beans::PropertyValue >& rMediaDescriptor )
509     throw (frame::DoubleInitializationException,
510            io::IOException,
511            uno::Exception,
512            uno::RuntimeException)
513 {
514     Reference< embed::XStorage > xStorage;
515     OUString aURL;
516     try
517     {
518         apphelper::MediaDescriptorHelper aMDHelper( rMediaDescriptor );
519         if( aMDHelper.ISSET_Storage )
520         {
521             xStorage = aMDHelper.Storage;
522         }
523         else if( aMDHelper.ISSET_Stream ||
524                  aMDHelper.ISSET_InputStream )
525         {
526             if( aMDHelper.ISSET_FilterName &&
527                 (aMDHelper.FilterName.equals( C2U("StarChart 5.0")) ||
528                  aMDHelper.FilterName.equals( C2U("StarChart 4.0")) ||
529                  aMDHelper.FilterName.equals( C2U("StarChart 3.0")) ))
530             {
531                 attachResource( aMDHelper.URL, rMediaDescriptor );
532                 impl_load( rMediaDescriptor, 0 ); // cannot create a storage from binary streams, but I do not need the storage here anyhow
533                 m_bReadOnly = sal_True;
534                 return;
535             }
536 
537             Reference< lang::XSingleServiceFactory > xStorageFact(
538                 m_xContext->getServiceManager()->createInstanceWithContext(
539                     C2U("com.sun.star.embed.StorageFactory"),
540                     m_xContext ),
541                 uno::UNO_QUERY_THROW );
542 
543             if( aMDHelper.ISSET_Stream )
544             {
545                 // convert XStream to XStorage via the storage factory
546                 Sequence< uno::Any > aStorageArgs( 2 );
547                 aStorageArgs[0] <<= aMDHelper.Stream;
548                 // todo: check if stream is read-only
549                 aStorageArgs[1] <<= (embed::ElementModes::READ); //WRITE | embed::ElementModes::NOCREATE);
550 
551                 xStorage.set( xStorageFact->createInstanceWithArguments( aStorageArgs ),
552                     uno::UNO_QUERY_THROW );
553             }
554             else
555             {
556                 OSL_ASSERT( aMDHelper.ISSET_InputStream );
557                 // convert XInputStream to XStorage via the storage factory
558                 Sequence< uno::Any > aStorageArgs( 2 );
559                 aStorageArgs[0] <<= aMDHelper.InputStream;
560                 aStorageArgs[1] <<= (embed::ElementModes::READ);
561 
562                 xStorage.set( xStorageFact->createInstanceWithArguments( aStorageArgs ),
563                     uno::UNO_QUERY_THROW );
564             }
565         }
566 
567         if( aMDHelper.ISSET_URL )
568             aURL = aMDHelper.URL;
569     }
570     catch( uno::Exception & ex )
571     {
572         ASSERT_EXCEPTION( ex );
573     }
574 
575     if( xStorage.is())
576     {
577         attachResource( aURL, rMediaDescriptor );
578         impl_load( rMediaDescriptor, xStorage );
579     }
580 }
581 
impl_load(const Sequence<beans::PropertyValue> & rMediaDescriptor,const Reference<embed::XStorage> & xStorage)582 void ChartModel::impl_load(
583     const Sequence< beans::PropertyValue >& rMediaDescriptor,
584     const Reference< embed::XStorage >& xStorage )
585 {
586     {
587         MutexGuard aGuard( m_aModelMutex );
588         m_nInLoad++;
589     }
590 
591     Reference< document::XFilter > xFilter( impl_createFilter( rMediaDescriptor ));
592 
593     if( xFilter.is())
594     {
595         Reference< document::XImporter > xImporter( xFilter, uno::UNO_QUERY_THROW );
596         xImporter->setTargetDocument( this );
597         Sequence< beans::PropertyValue > aMD( rMediaDescriptor );
598         lcl_addStorageToMediaDescriptor( aMD, xStorage );
599 
600         xFilter->filter( aMD );
601         xFilter.clear();
602     }
603     else
604     {
605         OSL_ENSURE( false, "loadFromStorage cannot create filter" );
606     }
607 
608     if( xStorage.is() )
609         impl_loadGraphics( xStorage );
610 
611     setModified( sal_False );
612 
613     // switchToStorage without notifying listeners (which shouldn't exist at
614     // this time, anyway)
615     m_xStorage = xStorage;
616 
617     {
618         MutexGuard aGuard( m_aModelMutex );
619         m_nInLoad--;
620     }
621 }
622 
impl_loadGraphics(const Reference<embed::XStorage> & xStorage)623 void ChartModel::impl_loadGraphics(
624     const Reference< embed::XStorage >& xStorage )
625 {
626     try
627     {
628         const Reference< embed::XStorage >& xGraphicsStorage(
629             xStorage->openStorageElement( C2U( "Pictures" ),
630                                           embed::ElementModes::READ ) );
631 
632         if( xGraphicsStorage.is() )
633         {
634             const uno::Sequence< ::rtl::OUString > aElementNames(
635                 xGraphicsStorage->getElementNames() );
636 
637             for( int i = 0; i < aElementNames.getLength(); ++i )
638             {
639                 if( xGraphicsStorage->isStreamElement( aElementNames[ i ] ) )
640                 {
641                     uno::Reference< io::XStream > xElementStream(
642                         xGraphicsStorage->openStreamElement(
643                             aElementNames[ i ],
644                             embed::ElementModes::READ ) );
645 
646                     if( xElementStream.is() )
647                     {
648                         std::auto_ptr< SvStream > apIStm(
649                             ::utl::UcbStreamHelper::CreateStream(
650                                 xElementStream, true ) );
651 
652                         if( apIStm.get() )
653                         {
654                             Graphic aGraphic;
655 
656                             if( !GraphicConverter::Import(
657                                     *apIStm.get(),
658                                     aGraphic ) )
659                             {
660                                 m_aGraphicObjectVector.push_back( aGraphic );
661                             }
662                         }
663                     }
664                 }
665             }
666         }
667     }
668     catch ( uno::Exception& )
669     {
670     }
671 }
672 
673 //-----------------------------------------------------------------
674 // util::XModifiable
675 //-----------------------------------------------------------------
impl_notifyModifiedListeners()676 void SAL_CALL ChartModel::impl_notifyModifiedListeners()
677     throw( uno::RuntimeException)
678 {
679     {
680         MutexGuard aGuard( m_aModelMutex );
681         m_bUpdateNotificationsPending = false;
682     }
683 
684     //always notify the view first!
685     ChartViewHelper::setViewToDirtyState( this );
686 
687 	::cppu::OInterfaceContainerHelper* pIC = m_aLifeTimeManager.m_aListenerContainer
688 		.getContainer( ::getCppuType((const uno::Reference< util::XModifyListener >*)0) );
689 	if( pIC )
690 	{
691 		lang::EventObject aEvent( static_cast< lang::XComponent*>(this) );
692 		::cppu::OInterfaceIteratorHelper aIt( *pIC );
693 		while( aIt.hasMoreElements() )
694         {
695             uno::Reference< util::XModifyListener > xListener( aIt.next(), uno::UNO_QUERY );
696             if( xListener.is() )
697                 xListener->modified( aEvent );
698         }
699 	}
700 }
701 
isModified()702 sal_Bool SAL_CALL ChartModel::isModified()
703     throw(uno::RuntimeException)
704 {
705 	//@todo guard
706 	return m_bModified;
707 }
708 
setModified(sal_Bool bModified)709 void SAL_CALL ChartModel::setModified( sal_Bool bModified )
710     throw(beans::PropertyVetoException,
711           uno::RuntimeException)
712 {
713     apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager);
714 	if(!aGuard.startApiCall())//@todo ? is this a long lasting call??
715 		return; //behave passive if already disposed or closed or throw exception @todo?
716 	m_bModified = bModified;
717 
718     if( m_nControllerLockCount > 0 )
719     {
720         m_bUpdateNotificationsPending = true;
721         return;//don't call listeners if controllers are locked
722     }
723     aGuard.clear();
724 
725 	if(bModified)
726 		impl_notifyModifiedListeners();
727 }
728 
729 //-----------------------------------------------------------------
730 // util::XModifyBroadcaster (base of XModifiable)
731 //-----------------------------------------------------------------
addModifyListener(const uno::Reference<util::XModifyListener> & xListener)732 void SAL_CALL ChartModel::addModifyListener(
733     const uno::Reference< util::XModifyListener >& xListener )
734     throw(uno::RuntimeException)
735 {
736 	if( m_aLifeTimeManager.impl_isDisposedOrClosed() )
737 		return; //behave passive if already disposed or closed
738 
739 	m_aLifeTimeManager.m_aListenerContainer.addInterface(
740         ::getCppuType((const uno::Reference< util::XModifyListener >*)0), xListener );
741 }
742 
removeModifyListener(const uno::Reference<util::XModifyListener> & xListener)743 void SAL_CALL ChartModel::removeModifyListener(
744     const uno::Reference< util::XModifyListener >& xListener )
745     throw(uno::RuntimeException)
746 {
747 	if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) )
748 		return; //behave passive if already disposed or closed
749 
750 	m_aLifeTimeManager.m_aListenerContainer.removeInterface(
751         ::getCppuType((const uno::Reference< util::XModifyListener >*)0), xListener );
752 }
753 
754 //-----------------------------------------------------------------
755 // util::XModifyListener
756 //-----------------------------------------------------------------
modified(const lang::EventObject &)757 void SAL_CALL ChartModel::modified( const lang::EventObject& )
758     throw (uno::RuntimeException)
759 {
760     if( m_nInLoad == 0 )
761         setModified( sal_True );
762 }
763 
764 //-----------------------------------------------------------------
765 // lang::XEventListener (base of util::XModifyListener)
766 //-----------------------------------------------------------------
disposing(const lang::EventObject &)767 void SAL_CALL ChartModel::disposing( const lang::EventObject& )
768     throw (uno::RuntimeException)
769 {
770     // child was disposed -- should not happen from outside
771 }
772 
773 
774 //-----------------------------------------------------------------
775 // document::XStorageBasedDocument
776 //-----------------------------------------------------------------
loadFromStorage(const Reference<embed::XStorage> & xStorage,const Sequence<beans::PropertyValue> & rMediaDescriptor)777 void SAL_CALL ChartModel::loadFromStorage(
778     const Reference< embed::XStorage >& xStorage,
779     const Sequence< beans::PropertyValue >& rMediaDescriptor )
780     throw (lang::IllegalArgumentException,
781            frame::DoubleInitializationException,
782            io::IOException,
783            uno::Exception,
784            uno::RuntimeException)
785 {
786     attachResource( OUString(), rMediaDescriptor );
787     impl_load( rMediaDescriptor, xStorage );
788 }
789 
storeToStorage(const Reference<embed::XStorage> & xStorage,const Sequence<beans::PropertyValue> & rMediaDescriptor)790 void SAL_CALL ChartModel::storeToStorage(
791     const Reference< embed::XStorage >& xStorage,
792     const Sequence< beans::PropertyValue >& rMediaDescriptor )
793     throw (lang::IllegalArgumentException,
794            io::IOException,
795            uno::Exception,
796            uno::RuntimeException)
797 {
798     impl_store( rMediaDescriptor, xStorage );
799 }
800 
switchToStorage(const Reference<embed::XStorage> & xStorage)801 void SAL_CALL ChartModel::switchToStorage( const Reference< embed::XStorage >& xStorage )
802     throw (lang::IllegalArgumentException,
803            io::IOException,
804            uno::Exception,
805            uno::RuntimeException)
806 {
807     m_xStorage = xStorage;
808     impl_notifyStorageChangeListeners();
809 }
810 
getDocumentStorage()811 Reference< embed::XStorage > SAL_CALL ChartModel::getDocumentStorage()
812     throw (io::IOException,
813            uno::Exception,
814            uno::RuntimeException)
815 {
816     return m_xStorage;
817 }
818 
impl_notifyStorageChangeListeners()819 void SAL_CALL ChartModel::impl_notifyStorageChangeListeners()
820     throw( uno::RuntimeException)
821 {
822     ::cppu::OInterfaceContainerHelper* pIC = m_aLifeTimeManager.m_aListenerContainer
823           .getContainer( ::getCppuType((const uno::Reference< document::XStorageChangeListener >*)0) );
824 	if( pIC )
825 	{
826 		::cppu::OInterfaceIteratorHelper aIt( *pIC );
827 		while( aIt.hasMoreElements() )
828         {
829             uno::Reference< document::XStorageChangeListener > xListener( aIt.next(), uno::UNO_QUERY );
830             if( xListener.is() )
831                 xListener->notifyStorageChange( static_cast< ::cppu::OWeakObject* >( this ), m_xStorage );
832         }
833     }
834 }
835 
addStorageChangeListener(const Reference<document::XStorageChangeListener> & xListener)836 void SAL_CALL ChartModel::addStorageChangeListener( const Reference< document::XStorageChangeListener >& xListener )
837     throw (uno::RuntimeException)
838 {
839 	if( m_aLifeTimeManager.impl_isDisposedOrClosed() )
840 		return; //behave passive if already disposed or closed
841 
842 	m_aLifeTimeManager.m_aListenerContainer.addInterface(
843         ::getCppuType((const uno::Reference< document::XStorageChangeListener >*)0), xListener );
844 }
845 
removeStorageChangeListener(const Reference<document::XStorageChangeListener> & xListener)846 void SAL_CALL ChartModel::removeStorageChangeListener( const Reference< document::XStorageChangeListener >& xListener )
847     throw (uno::RuntimeException)
848 {
849 	if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) )
850 		return; //behave passive if already disposed or closed
851 
852 	m_aLifeTimeManager.m_aListenerContainer.removeInterface(
853         ::getCppuType((const uno::Reference< document::XStorageChangeListener >*)0), xListener );
854 }
855 
856 } //  namespace chart
857