Coverage Report

Created: 2026-02-14 09:37

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