Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/chart2/source/model/main/ChartModel.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 <ChartModel.hxx>
21
#include <ChartTypeManager.hxx>
22
#include <ChartTypeTemplate.hxx>
23
#include <servicenames.hxx>
24
#include <DataSource.hxx>
25
#include <DataSourceHelper.hxx>
26
#include <ChartType.hxx>
27
#include <DisposeHelper.hxx>
28
#include <ControllerLockGuard.hxx>
29
#include <InternalDataProvider.hxx>
30
#include <ObjectIdentifier.hxx>
31
#include <BaseCoordinateSystem.hxx>
32
#include "PageBackground.hxx"
33
#include <CloneHelper.hxx>
34
#include <NameContainer.hxx>
35
#include "UndoManager.hxx"
36
37
#include <ChartColorPaletteHelper.hxx>
38
#include <ChartView.hxx>
39
#include <PopupRequest.hxx>
40
#include <ModifyListenerHelper.hxx>
41
#include <RangeHighlighter.hxx>
42
#include <Diagram.hxx>
43
#include <ChartDocumentWrapper.hxx>
44
#include <comphelper/dumpxmltostring.hxx>
45
46
#include <com/sun/star/chart/ChartDataRowSource.hpp>
47
#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
48
49
#include <comphelper/processfactory.hxx>
50
#include <comphelper/propertysequence.hxx>
51
#include <cppuhelper/supportsservice.hxx>
52
53
#include <svl/numformat.hxx>
54
#include <svl/numuno.hxx>
55
#include <com/sun/star/lang/DisposedException.hpp>
56
#include <com/sun/star/view/XSelectionSupplier.hpp>
57
#include <com/sun/star/embed/EmbedMapUnits.hpp>
58
#include <com/sun/star/embed/Aspects.hpp>
59
#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
60
#include <com/sun/star/datatransfer/XTransferable.hpp>
61
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
62
#include <com/sun/star/drawing/XDrawPage.hpp>
63
#include <com/sun/star/drawing/FillStyle.hpp>
64
#include <com/sun/star/drawing/XShapes.hpp>
65
#include <com/sun/star/document/DocumentProperties.hpp>
66
#include <com/sun/star/text/XTextDocument.hpp>
67
#include <com/sun/star/util/CloseVetoException.hpp>
68
#include <com/sun/star/util/XModifyBroadcaster.hpp>
69
70
#include <sal/log.hxx>
71
#include <utility>
72
#include <comphelper/diagnose_ex.hxx>
73
#include <libxml/xmlwriter.h>
74
75
#include <sfx2/objsh.hxx>
76
#include <sfx2/viewsh.hxx>
77
#include <com/sun/star/util/XTheme.hpp>
78
#include <docmodel/uno/UnoTheme.hxx>
79
#include <docmodel/theme/Theme.hxx>
80
#include <docmodel/uno/UnoChartStyle.hxx>
81
82
using ::com::sun::star::uno::Sequence;
83
using ::com::sun::star::uno::Reference;
84
using ::com::sun::star::uno::Any;
85
using ::osl::MutexGuard;
86
87
using namespace ::com::sun::star;
88
using namespace ::apphelper;
89
90
namespace
91
{
92
constexpr OUString lcl_aGDIMetaFileMIMEType(
93
    u"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\""_ustr);
94
constexpr OUString lcl_aGDIMetaFileMIMETypeHighContrast(
95
    u"application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\""_ustr);
96
97
} // anonymous namespace
98
99
// ChartModel Constructor and Destructor
100
101
namespace chart
102
{
103
104
namespace
105
{
106
SfxObjectShell* getParentShell(const uno::Reference<frame::XModel>& xDocModel)
107
0
{
108
0
    uno::Reference<lang::XUnoTunnel> xUnoTunnel(xDocModel, uno::UNO_QUERY);
109
0
    if (xUnoTunnel.is())
110
0
    {
111
0
        return comphelper::getFromUnoTunnel<SfxObjectShell>(xUnoTunnel);
112
0
    }
113
0
    return nullptr;
114
0
}
115
}
116
117
ChartModel::ChartModel(uno::Reference<uno::XComponentContext > xContext)
118
0
    : m_aLifeTimeManager( this, this )
119
0
    , m_bReadOnly( false )
120
0
    , m_bModified( false )
121
0
    , m_nInLoad(0)
122
0
    , m_bUpdateNotificationsPending(false)
123
0
    , mbTimeBased(false)
124
0
    , m_aControllers( m_aModelMutex )
125
0
    , m_nControllerLockCount(0)
126
0
    , m_xContext(std::move( xContext ))
127
0
    , m_aVisualAreaSize( ChartModel::getDefaultPageSize() )
128
0
    , m_xPageBackground( new PageBackground )
129
0
    , m_xXMLNamespaceMap( new NameContainer() )
130
0
    , m_eColorPaletteType(ChartColorPaletteType::Unknown)
131
0
    , m_nColorPaletteIndex(0)
132
0
    , m_aStyles(new UnoChartStyle)
133
0
    , mnStart(0)
134
0
    , mnEnd(0)
135
0
{
136
0
    osl_atomic_increment(&m_refCount);
137
0
    {
138
0
        m_xOldModelAgg = new wrapper::ChartDocumentWrapper(m_xContext);
139
0
        m_xOldModelAgg->setDelegator( *this );
140
0
    }
141
142
0
    {
143
0
        m_xPageBackground->addModifyListener( this );
144
#if 0 // TODO
145
        m_aStyles->addModifyListener( this );
146
#endif
147
0
        m_xChartTypeManager = new ::chart::ChartTypeManager( m_xContext );
148
0
    }
149
0
    osl_atomic_decrement(&m_refCount);
150
0
}
151
152
ChartModel::ChartModel( const ChartModel & rOther )
153
0
    : impl::ChartModel_Base(rOther)
154
    // not copy the listener
155
0
    , SfxListener()
156
0
    , m_aLifeTimeManager( this, this )
157
0
    , m_bReadOnly( rOther.m_bReadOnly )
158
0
    , m_bModified( rOther.m_bModified )
159
0
    , m_nInLoad(0)
160
0
    , m_bUpdateNotificationsPending(false)
161
0
    , mbTimeBased(rOther.mbTimeBased)
162
0
    , m_aResource( rOther.m_aResource )
163
0
    , m_aMediaDescriptor( rOther.m_aMediaDescriptor )
164
0
    , m_aControllers( m_aModelMutex )
165
0
    , m_nControllerLockCount(0)
166
0
    , m_xContext( rOther.m_xContext )
167
    // @note: the old model aggregate must not be shared with other models if it
168
    // is, you get mutex deadlocks
169
    //, m_xOldModelAgg( nullptr ) //rOther.m_xOldModelAgg )
170
    // m_xStorage( nullptr ) //rOther.m_xStorage )
171
0
    , m_aVisualAreaSize( rOther.m_aVisualAreaSize )
172
0
    , m_aGraphicObjectVector( rOther.m_aGraphicObjectVector )
173
0
    , m_xDataProvider( rOther.m_xDataProvider )
174
0
    , m_xInternalDataProvider( rOther.m_xInternalDataProvider )
175
0
    , m_eColorPaletteType(ChartColorPaletteType::Unknown)
176
0
    , m_nColorPaletteIndex(0)
177
0
    , mnStart(rOther.mnStart)
178
0
    , mnEnd(rOther.mnEnd)
179
0
{
180
0
    osl_atomic_increment(&m_refCount);
181
0
    {
182
0
        m_xOldModelAgg = new wrapper::ChartDocumentWrapper(m_xContext);
183
0
        m_xOldModelAgg->setDelegator( *this );
184
185
0
        Reference< util::XModifyListener > xListener;
186
0
        rtl::Reference< Title > xNewTitle;
187
0
        if ( rOther.m_xTitle )
188
0
            xNewTitle = new Title(*rOther.m_xTitle);
189
0
        rtl::Reference< ::chart::Diagram > xNewDiagram;
190
0
        if (rOther.m_xDiagram.is())
191
0
            xNewDiagram = new ::chart::Diagram( *rOther.m_xDiagram );
192
0
        rtl::Reference< ::chart::PageBackground > xNewPageBackground = new PageBackground( *rOther.m_xPageBackground );
193
0
        rtl::Reference<UnoChartStyle> xNewChartStyle = new UnoChartStyle(*rOther.m_aStyles);
194
195
0
        {
196
0
            rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager; // does not implement XCloneable
197
0
            rtl::Reference< ::chart::NameContainer > xXMLNamespaceMap = new NameContainer( *rOther.m_xXMLNamespaceMap );
198
199
0
            {
200
0
                MutexGuard aGuard( m_aModelMutex );
201
0
                xListener = this;
202
0
                m_xTitle = xNewTitle;
203
0
                m_xDiagram = xNewDiagram;
204
0
                m_xPageBackground = xNewPageBackground;
205
0
                m_aStyles = xNewChartStyle;
206
0
                m_xChartTypeManager = std::move(xChartTypeManager);
207
0
                m_xXMLNamespaceMap = std::move(xXMLNamespaceMap);
208
0
            }
209
0
        }
210
211
0
        ModifyListenerHelper::addListener( xNewTitle, xListener );
212
0
        if( xNewDiagram && xListener)
213
0
            xNewDiagram->addModifyListener( xListener );
214
0
        if( xNewPageBackground && xListener)
215
0
            xNewPageBackground->addModifyListener( xListener );
216
#if 0 // TODO
217
        if( xNewChartStyle && xListener) {
218
            xNewChartStyle->addModifyListener( xListener );
219
        }
220
#endif
221
0
        xListener.clear();
222
0
    }
223
0
    osl_atomic_decrement(&m_refCount);
224
0
}
225
226
ChartModel::~ChartModel()
227
0
{
228
0
    if (SfxObjectShell* pShell = getParentShell(m_xParent))
229
0
        EndListening(*pShell);
230
0
    if( m_xOldModelAgg.is())
231
0
        m_xOldModelAgg->setDelegator( nullptr );
232
0
}
233
234
void SAL_CALL ChartModel::initialize( const Sequence< Any >& /*rArguments*/ )
235
0
{
236
    //#i113722# avoid duplicate creation
237
238
    //maybe additional todo?:
239
    //support argument "EmbeddedObject"?
240
    //support argument "EmbeddedScriptSupport"?
241
    //support argument "DocumentRecoverySupport"?
242
0
}
243
244
ChartView* ChartModel::getChartView() const
245
0
{
246
0
    return mxChartView.get();
247
0
}
248
249
// private methods
250
251
OUString ChartModel::impl_g_getLocation()
252
0
{
253
254
0
    LifeTimeGuard aGuard(m_aLifeTimeManager);
255
0
    if(!aGuard.startApiCall())
256
0
        return OUString(); //behave passive if already disposed or closed or throw exception @todo?
257
    //mutex is acquired
258
0
    return m_aResource;
259
0
}
260
261
bool ChartModel::impl_isControllerConnected( const uno::Reference< frame::XController >& xController )
262
0
{
263
0
    try
264
0
    {
265
0
        std::vector< uno::Reference<uno::XInterface> > aSeq = m_aControllers.getElements();
266
0
        for( const auto & r : aSeq )
267
0
        {
268
0
            if( r == xController )
269
0
                return true;
270
0
        }
271
0
    }
272
0
    catch (const uno::Exception&)
273
0
    {
274
0
    }
275
0
    return false;
276
0
}
277
278
uno::Reference< frame::XController > ChartModel::impl_getCurrentController()
279
0
{
280
        //@todo? hold only weak references to controllers
281
282
    // get the last active controller of this model
283
0
    if( m_xCurrentController.is() )
284
0
        return m_xCurrentController;
285
286
    // get the first controller of this model
287
0
    if( m_aControllers.getLength() )
288
0
    {
289
0
        uno::Reference<uno::XInterface> xI = m_aControllers.getInterface(0);
290
0
        return uno::Reference<frame::XController>( xI, uno::UNO_QUERY );
291
0
    }
292
293
    //return nothing if no controllers are connected at all
294
0
    return uno::Reference< frame::XController > ();
295
0
}
296
297
void ChartModel::impl_notifyCloseListeners()
298
0
{
299
0
    std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
300
0
    if( m_aLifeTimeManager.m_aCloseListeners.getLength(aGuard) )
301
0
    {
302
0
        lang::EventObject aEvent( static_cast< lang::XComponent*>(this) );
303
0
        m_aLifeTimeManager.m_aCloseListeners.notifyEach(aGuard, &util::XCloseListener::notifyClosing, aEvent);
304
0
    }
305
0
}
306
307
void ChartModel::impl_adjustAdditionalShapesPositionAndSize( const awt::Size& aVisualAreaSize )
308
0
{
309
0
    uno::Reference< beans::XPropertySet > xProperties( static_cast< ::cppu::OWeakObject* >( this ), uno::UNO_QUERY );
310
0
    if ( !xProperties.is() )
311
0
        return;
312
313
0
    uno::Reference< drawing::XShapes > xShapes;
314
0
    xProperties->getPropertyValue( u"AdditionalShapes"_ustr ) >>= xShapes;
315
0
    if ( !xShapes.is() )
316
0
        return;
317
318
0
    sal_Int32 nCount = xShapes->getCount();
319
0
    for ( sal_Int32 i = 0; i < nCount; ++i )
320
0
    {
321
0
        Reference< drawing::XShape > xShape;
322
0
        if ( xShapes->getByIndex( i ) >>= xShape )
323
0
        {
324
0
            if ( xShape.is() )
325
0
            {
326
0
                awt::Point aPos( xShape->getPosition() );
327
0
                awt::Size aSize( xShape->getSize() );
328
329
0
                double fWidth = static_cast< double >( aVisualAreaSize.Width ) / m_aVisualAreaSize.Width;
330
0
                double fHeight = static_cast< double >( aVisualAreaSize.Height ) / m_aVisualAreaSize.Height;
331
332
0
                aPos.X = static_cast< tools::Long >( aPos.X * fWidth );
333
0
                aPos.Y = static_cast< tools::Long >( aPos.Y * fHeight );
334
0
                aSize.Width = static_cast< tools::Long >( aSize.Width * fWidth );
335
0
                aSize.Height = static_cast< tools::Long >( aSize.Height * fHeight );
336
337
0
                xShape->setPosition( aPos );
338
0
                xShape->setSize( aSize );
339
0
            }
340
0
        }
341
0
    }
342
0
}
343
344
// lang::XServiceInfo
345
346
OUString SAL_CALL ChartModel::getImplementationName()
347
0
{
348
0
    return u"com.sun.star.comp.chart2.ChartModel"_ustr;
349
0
}
350
351
sal_Bool SAL_CALL ChartModel::supportsService( const OUString& rServiceName )
352
0
{
353
0
    return cppu::supportsService(this, rServiceName);
354
0
}
355
356
css::uno::Sequence< OUString > SAL_CALL ChartModel::getSupportedServiceNames()
357
0
{
358
0
    return {
359
0
        u"com.sun.star.chart2.ChartDocument"_ustr,
360
0
        u"com.sun.star.document.OfficeDocument"_ustr,
361
0
        u"com.sun.star.chart.ChartDocument"_ustr
362
0
    };
363
0
}
364
365
// frame::XModel (required interface)
366
367
sal_Bool SAL_CALL ChartModel::attachResource( const OUString& rURL
368
        , const uno::Sequence< beans::PropertyValue >& rMediaDescriptor )
369
0
{
370
    /*
371
    The method attachResource() is used by the frame loader implementations
372
    to inform the model about its URL and MediaDescriptor.
373
    */
374
375
0
    LifeTimeGuard aGuard(m_aLifeTimeManager);
376
0
    if(!aGuard.startApiCall())
377
0
        return false; //behave passive if already disposed or closed or throw exception @todo?
378
    //mutex is acquired
379
380
0
    if(!m_aResource.isEmpty())//we have a resource already //@todo? or is setting a new resource allowed?
381
0
        return false;
382
0
    m_aResource = rURL;
383
0
    m_aMediaDescriptor = rMediaDescriptor;
384
385
    //@todo ? check rURL ??
386
    //@todo ? evaluate m_aMediaDescriptor;
387
    //@todo ? ... ??? --> nothing, this method is only for setting information
388
389
0
    return true;
390
0
}
391
392
OUString SAL_CALL ChartModel::getURL()
393
0
{
394
0
    return impl_g_getLocation();
395
0
}
396
397
uno::Sequence< beans::PropertyValue > SAL_CALL ChartModel::getArgs()
398
0
{
399
    /*
400
    The method getArgs() returns a sequence of property values
401
    that report the resource description according to com.sun.star.document.MediaDescriptor,
402
    specified on loading or saving with storeAsURL.
403
    */
404
405
0
    LifeTimeGuard aGuard(m_aLifeTimeManager);
406
0
    if(!aGuard.startApiCall())
407
0
        return uno::Sequence< beans::PropertyValue >(); //behave passive if already disposed or closed or throw exception @todo?
408
    //mutex is acquired
409
410
0
    return m_aMediaDescriptor;
411
0
}
412
413
void SAL_CALL ChartModel::connectController( const uno::Reference< frame::XController >& xController )
414
0
{
415
    //@todo? this method is declared as oneway -> ...?
416
417
0
    LifeTimeGuard aGuard(m_aLifeTimeManager);
418
0
    if(!aGuard.startApiCall())
419
0
        return ; //behave passive if already disposed or closed
420
    //mutex is acquired
421
422
    //--add controller
423
0
    m_aControllers.addInterface(xController);
424
0
}
425
426
void SAL_CALL ChartModel::disconnectController( const uno::Reference< frame::XController >& xController )
427
0
{
428
    //@todo? this method is declared as oneway -> ...?
429
430
0
    LifeTimeGuard aGuard(m_aLifeTimeManager);
431
0
    if(!aGuard.startApiCall())
432
0
        return; //behave passive if already disposed or closed
433
434
    //--remove controller
435
0
    m_aControllers.removeInterface(xController);
436
437
    //case: current controller is disconnected:
438
0
    if( m_xCurrentController == xController )
439
0
        m_xCurrentController.clear();
440
441
0
    if (m_xRangeHighlighter)
442
0
    {
443
0
        m_xRangeHighlighter->dispose();
444
0
        m_xRangeHighlighter.clear();
445
0
    }
446
0
    DisposeHelper::DisposeAndClear(m_xPopupRequest);
447
0
}
448
449
void SAL_CALL ChartModel::lockControllers()
450
0
{
451
    /*
452
    suspends some notifications to the controllers which are used for display updates.
453
454
    The calls to lockControllers() and unlockControllers() may be nested
455
    and even overlapping, but they must be in pairs. While there is at least one lock
456
    remaining, some notifications for display updates are not broadcasted.
457
    */
458
459
    //@todo? this method is declared as oneway -> ...?
460
461
0
    LifeTimeGuard aGuard(m_aLifeTimeManager);
462
0
    if(!aGuard.startApiCall())
463
0
        return; //behave passive if already disposed or closed or throw exception @todo?
464
0
    ++m_nControllerLockCount;
465
0
}
466
467
void SAL_CALL ChartModel::unlockControllers()
468
0
{
469
    /*
470
    resumes the notifications which were suspended by lockControllers() .
471
472
    The calls to lockControllers() and unlockControllers() may be nested
473
    and even overlapping, but they must be in pairs. While there is at least one lock
474
    remaining, some notifications for display updates are not broadcasted.
475
    */
476
477
    //@todo? this method is declared as oneway -> ...?
478
479
0
    LifeTimeGuard aGuard(m_aLifeTimeManager);
480
0
    if(!aGuard.startApiCall())
481
0
        return; //behave passive if already disposed or closed or throw exception @todo?
482
0
    if( m_nControllerLockCount == 0 )
483
0
    {
484
0
        SAL_WARN("chart2",  "ChartModel: unlockControllers called with m_nControllerLockCount == 0" );
485
0
        return;
486
0
    }
487
0
    --m_nControllerLockCount;
488
0
    if( m_nControllerLockCount == 0 && m_bUpdateNotificationsPending  )
489
0
    {
490
0
        aGuard.clear();
491
0
        impl_notifyModifiedListeners();
492
0
    }
493
0
}
494
495
sal_Bool SAL_CALL ChartModel::hasControllersLocked()
496
0
{
497
0
    LifeTimeGuard aGuard(m_aLifeTimeManager);
498
0
    if(!aGuard.startApiCall())
499
0
        return false; //behave passive if already disposed or closed or throw exception @todo?
500
0
    return ( m_nControllerLockCount != 0 ) ;
501
0
}
502
503
uno::Reference< frame::XController > SAL_CALL ChartModel::getCurrentController()
504
0
{
505
0
    LifeTimeGuard aGuard(m_aLifeTimeManager);
506
0
    if(!aGuard.startApiCall())
507
0
        throw lang::DisposedException(
508
0
                u"getCurrentController was called on an already disposed or closed model"_ustr,
509
0
                static_cast< ::cppu::OWeakObject* >(this) );
510
511
0
    return impl_getCurrentController();
512
0
}
513
514
void SAL_CALL ChartModel::setCurrentController( const uno::Reference< frame::XController >& xController )
515
0
{
516
0
    LifeTimeGuard aGuard(m_aLifeTimeManager);
517
0
    if(!aGuard.startApiCall())
518
0
        throw lang::DisposedException(
519
0
                u"setCurrentController was called on an already disposed or closed model"_ustr,
520
0
                static_cast< ::cppu::OWeakObject* >(this) );
521
522
    //OSL_ENSURE( impl_isControllerConnected(xController), "setCurrentController is called with a Controller which is not connected" );
523
0
    if(!impl_isControllerConnected(xController))
524
0
        throw container::NoSuchElementException(
525
0
                u"setCurrentController is called with a Controller which is not connected"_ustr,
526
0
                static_cast< ::cppu::OWeakObject* >(this) );
527
528
0
    m_xCurrentController = xController;
529
530
0
    if (m_xRangeHighlighter)
531
0
    {
532
0
        m_xRangeHighlighter->dispose();
533
0
        m_xRangeHighlighter.clear();
534
0
    }
535
0
    DisposeHelper::DisposeAndClear(m_xPopupRequest);
536
0
}
537
538
uno::Reference< uno::XInterface > SAL_CALL ChartModel::getCurrentSelection()
539
0
{
540
0
    LifeTimeGuard aGuard(m_aLifeTimeManager);
541
0
    if(!aGuard.startApiCall())
542
0
        throw lang::DisposedException(
543
0
                u"getCurrentSelection was called on an already disposed or closed model"_ustr,
544
0
                static_cast< ::cppu::OWeakObject* >(this) );
545
546
0
    uno::Reference< uno::XInterface > xReturn;
547
0
    uno::Reference< frame::XController > xController = impl_getCurrentController();
548
549
0
    aGuard.clear();
550
0
    if( xController.is() )
551
0
    {
552
0
        uno::Reference< view::XSelectionSupplier >  xSelectionSupl( xController, uno::UNO_QUERY );
553
0
        if ( xSelectionSupl.is() )
554
0
        {
555
0
            uno::Any aSel = xSelectionSupl->getSelection();
556
0
            OUString aObjectCID;
557
0
            if( aSel >>= aObjectCID )
558
0
                xReturn.set( ObjectIdentifier::getObjectPropertySet( aObjectCID, this));
559
0
        }
560
0
    }
561
0
    return xReturn;
562
0
}
563
564
// lang::XComponent (base of XModel)
565
void SAL_CALL ChartModel::dispose()
566
0
{
567
0
    Reference< XInterface > xKeepAlive( *this );
568
569
    //This object should release all resources and references in the
570
    //easiest possible manner
571
    //This object must notify all registered listeners using the method
572
    //<member>XEventListener::disposing</member>
573
574
    //hold no mutex
575
0
    if( !m_aLifeTimeManager.dispose() )
576
0
        return;
577
578
    //--release all resources and references
579
    //// @todo
580
581
0
    if ( m_xDiagram.is() )
582
0
        m_xDiagram->removeModifyListener( this );
583
584
0
    if ( m_xDataProvider.is() )
585
0
    {
586
0
        Reference<util::XModifyBroadcaster> xModifyBroadcaster( m_xDataProvider, uno::UNO_QUERY );
587
0
        if ( xModifyBroadcaster.is() )
588
0
            xModifyBroadcaster->removeModifyListener( this );
589
0
    }
590
591
0
    m_xDataProvider.clear();
592
0
    m_xInternalDataProvider.clear();
593
0
    m_xNumberFormatsSupplier.clear();
594
0
    m_xOwnNumberFormatsSupplier.clear();
595
0
    m_xChartTypeManager.clear();
596
0
    m_xDiagram.clear();
597
0
    m_xTitle.clear();
598
0
    m_xPageBackground.clear();
599
0
    m_xXMLNamespaceMap.clear();
600
0
    m_aStyles.clear();
601
602
0
    m_xStorage.clear();
603
        // just clear, don't dispose - we're not the owner
604
605
0
    if ( m_pUndoManager.is() )
606
0
        m_pUndoManager->disposing();
607
0
    m_pUndoManager.clear();
608
        // that's important, since the UndoManager implementation delegates its ref counting to ourself.
609
610
0
    if( m_xOldModelAgg.is())  // #i120828#, to release cyclic reference to ChartModel object
611
0
        m_xOldModelAgg->setDelegator( nullptr );
612
613
0
    m_aControllers.disposeAndClear( lang::EventObject( static_cast< cppu::OWeakObject * >( this )));
614
0
    m_xCurrentController.clear();
615
616
0
    if (m_xRangeHighlighter)
617
0
    {
618
0
        m_xRangeHighlighter->dispose();
619
0
        m_xRangeHighlighter.clear();
620
0
    }
621
0
    DisposeHelper::DisposeAndClear(m_xPopupRequest);
622
623
0
    if( m_xOldModelAgg.is())
624
0
        m_xOldModelAgg->setDelegator( nullptr );
625
0
}
626
627
void SAL_CALL ChartModel::addEventListener( const uno::Reference< lang::XEventListener > & xListener )
628
0
{
629
0
    if( m_aLifeTimeManager.impl_isDisposedOrClosed() )
630
0
        return; //behave passive if already disposed or closed
631
632
0
    std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
633
0
    m_aLifeTimeManager.m_aEventListeners.addInterface( aGuard, xListener );
634
0
}
635
636
void SAL_CALL ChartModel::removeEventListener( const uno::Reference< lang::XEventListener > & xListener )
637
0
{
638
0
    if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) )
639
0
        return; //behave passive if already disposed or closed
640
641
0
    std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
642
0
    m_aLifeTimeManager.m_aEventListeners.removeInterface( aGuard, xListener );
643
0
}
644
645
// util::XCloseBroadcaster (base of XCloseable)
646
void SAL_CALL ChartModel::addCloseListener( const uno::Reference<   util::XCloseListener > & xListener )
647
0
{
648
0
    m_aLifeTimeManager.g_addCloseListener( xListener );
649
0
}
650
651
void SAL_CALL ChartModel::removeCloseListener( const uno::Reference< util::XCloseListener > & xListener )
652
0
{
653
0
    if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) )
654
0
        return; //behave passive if already disposed or closed
655
656
0
    std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
657
0
    m_aLifeTimeManager.m_aCloseListeners.removeInterface( aGuard, xListener );
658
0
}
659
660
// util::XCloseable
661
void SAL_CALL ChartModel::close( sal_Bool bDeliverOwnership )
662
0
{
663
    //hold no mutex
664
665
0
    if( !m_aLifeTimeManager.g_close_startTryClose( bDeliverOwnership ) )
666
0
        return;
667
    //no mutex is acquired
668
669
    // At the end of this method may we must dispose ourself ...
670
    // and may nobody from outside hold a reference to us ...
671
    // then it's a good idea to do that by ourself.
672
0
    uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) );
673
674
    //the listeners have had no veto
675
    //check whether we self can close
676
0
    {
677
0
        util::CloseVetoException aVetoException(
678
0
                        u"the model itself could not be closed"_ustr,
679
0
                        static_cast< ::cppu::OWeakObject* >(this) );
680
681
0
        m_aLifeTimeManager.g_close_isNeedToCancelLongLastingCalls( bDeliverOwnership, aVetoException );
682
0
    }
683
0
    m_aLifeTimeManager.g_close_endTryClose_doClose();
684
685
    // BM @todo: is it ok to call the listeners here?
686
0
    impl_notifyCloseListeners();
687
0
}
688
689
// lang::XTypeProvider
690
uno::Sequence< uno::Type > SAL_CALL ChartModel::getTypes()
691
0
{
692
0
    uno::Reference< lang::XTypeProvider > xAggTypeProvider;
693
0
    if( (m_xOldModelAgg->queryAggregation( cppu::UnoType<decltype(xAggTypeProvider)>::get()) >>= xAggTypeProvider)
694
0
        && xAggTypeProvider.is())
695
0
    {
696
0
        return comphelper::concatSequences(
697
0
            impl::ChartModel_Base::getTypes(),
698
0
            xAggTypeProvider->getTypes());
699
0
    }
700
701
0
    return impl::ChartModel_Base::getTypes();
702
0
}
703
704
// document::XDocumentPropertiesSupplier
705
uno::Reference< document::XDocumentProperties > SAL_CALL
706
        ChartModel::getDocumentProperties()
707
0
{
708
0
    ::osl::MutexGuard aGuard( m_aModelMutex );
709
0
    if ( !m_xDocumentProperties.is() )
710
0
    {
711
0
        m_xDocumentProperties.set( document::DocumentProperties::create( ::comphelper::getProcessComponentContext() ) );
712
0
    }
713
0
    return m_xDocumentProperties;
714
0
}
715
716
// document::XDocumentPropertiesSupplier
717
Reference< document::XUndoManager > SAL_CALL ChartModel::getUndoManager(  )
718
0
{
719
0
    ::osl::MutexGuard aGuard( m_aModelMutex );
720
0
    if ( !m_pUndoManager.is() )
721
0
        m_pUndoManager.set( new UndoManager( *this, m_aModelMutex ) );
722
0
    return m_pUndoManager;
723
0
}
724
725
// chart2::XChartDocument
726
727
uno::Reference< chart2::XDiagram > SAL_CALL ChartModel::getFirstDiagram()
728
0
{
729
0
    MutexGuard aGuard( m_aModelMutex );
730
0
    return m_xDiagram;
731
0
}
732
733
void SAL_CALL ChartModel::setFirstDiagram( const uno::Reference< chart2::XDiagram >& xDiagram )
734
0
{
735
0
    rtl::Reference< ::chart::Diagram > xOldDiagram;
736
0
    Reference< util::XModifyListener > xListener;
737
0
    {
738
0
        MutexGuard aGuard( m_aModelMutex );
739
0
        if( xDiagram.get() == m_xDiagram.get() )
740
0
            return;
741
0
        xOldDiagram = m_xDiagram;
742
0
        assert(!xDiagram || dynamic_cast<::chart::Diagram*>(xDiagram.get()));
743
0
        m_xDiagram = dynamic_cast<::chart::Diagram*>(xDiagram.get());
744
0
        xListener = this;
745
0
    }
746
    //don't keep the mutex locked while calling out
747
0
    if( xOldDiagram && xListener )
748
0
        xOldDiagram->removeModifyListener( xListener );
749
0
    ModifyListenerHelper::addListener( xDiagram, xListener );
750
0
    setModified( true );
751
0
}
752
753
Reference< chart2::data::XDataSource > ChartModel::impl_createDefaultData()
754
0
{
755
0
    Reference< chart2::data::XDataSource > xDataSource;
756
0
    if( hasInternalDataProvider() )
757
0
    {
758
        //init internal dataprovider
759
0
        {
760
0
            beans::NamedValue aParam( u"CreateDefaultData"_ustr ,uno::Any(true) );
761
0
            uno::Sequence< uno::Any > aArgs{ uno::Any(aParam) };
762
0
            m_xInternalDataProvider->initialize(aArgs);
763
0
        }
764
        //create data
765
0
        uno::Sequence<beans::PropertyValue> aArgs( comphelper::InitPropertySequence({
766
0
            { "CellRangeRepresentation", uno::Any( u"all"_ustr ) },
767
0
            { "HasCategories", uno::Any( true ) },
768
0
            { "FirstCellAsLabel", uno::Any( true ) },
769
0
            { "DataRowSource", uno::Any( css::chart::ChartDataRowSource_COLUMNS ) }
770
0
            }));
771
0
        xDataSource = m_xInternalDataProvider->createDataSource( aArgs );
772
0
    }
773
0
    return xDataSource;
774
0
}
775
776
void SAL_CALL ChartModel::createInternalDataProvider( sal_Bool bCloneExistingData )
777
0
{
778
    // don't lock the mutex, because this call calls out to code that tries to
779
    // lock the solar mutex. On the other hand, a paint locks the solar mutex
780
    // and calls to the model lock the model's mutex => deadlock
781
    // @todo: lock a separate mutex in the InternalData class
782
0
    if( !hasInternalDataProvider() )
783
0
    {
784
0
        if( bCloneExistingData )
785
0
            m_xInternalDataProvider = new InternalDataProvider( this, /*bConnectToModel*/true, /*bDefaultDataInColumns*/ true );
786
0
        else
787
0
        {
788
0
            m_xInternalDataProvider = new InternalDataProvider( nullptr, /*bConnectToModel*/true, /*bDefaultDataInColumns*/ true );
789
0
            m_xInternalDataProvider->setChartModel(this);
790
0
        }
791
0
        m_xDataProvider.set( m_xInternalDataProvider );
792
0
    }
793
0
    setModified( true );
794
0
}
795
796
void ChartModel::removeDataProviders()
797
0
{
798
0
    if (m_xInternalDataProvider.is())
799
0
        m_xInternalDataProvider.clear();
800
0
    if (m_xDataProvider.is())
801
0
        m_xDataProvider.clear();
802
0
}
803
804
void ChartModel::dumpAsXml(xmlTextWriterPtr pWriter) const
805
0
{
806
0
    (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ChartModel"));
807
0
    (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
808
809
0
    if (mxChartView.is())
810
0
    {
811
0
        mxChartView->dumpAsXml(pWriter);
812
0
    }
813
814
0
    (void)xmlTextWriterEndElement(pWriter);
815
0
}
816
817
sal_Bool SAL_CALL ChartModel::hasInternalDataProvider()
818
0
{
819
0
    return m_xDataProvider.is() && m_xInternalDataProvider.is();
820
0
}
821
822
uno::Reference< chart2::data::XDataProvider > SAL_CALL ChartModel::getDataProvider()
823
0
{
824
0
    MutexGuard aGuard( m_aModelMutex );
825
0
    return m_xDataProvider;
826
0
}
827
828
uno::Reference< chart2::XChartStyle > SAL_CALL ChartModel::getStyles()
829
0
{
830
0
    MutexGuard aGuard( m_aModelMutex );
831
0
    return m_aStyles;
832
0
}
833
834
// ____ XDataReceiver ____
835
836
void SAL_CALL ChartModel::attachDataProvider( const uno::Reference< chart2::data::XDataProvider >& xDataProvider )
837
0
{
838
0
    {
839
0
        MutexGuard aGuard( m_aModelMutex );
840
0
        uno::Reference< beans::XPropertySet > xProp( xDataProvider, uno::UNO_QUERY );
841
0
        if( xProp.is() )
842
0
        {
843
0
            try
844
0
            {
845
0
                bool bIncludeHiddenCells = isIncludeHiddenCells();
846
0
                xProp->setPropertyValue(u"IncludeHiddenCells"_ustr, uno::Any(bIncludeHiddenCells));
847
0
            }
848
0
            catch (const beans::UnknownPropertyException&)
849
0
            {
850
0
            }
851
0
        }
852
853
0
        uno::Reference<util::XModifyBroadcaster> xModifyBroadcaster(xDataProvider, uno::UNO_QUERY);
854
0
        if (xModifyBroadcaster.is())
855
0
        {
856
0
            xModifyBroadcaster->addModifyListener(this);
857
0
        }
858
859
0
        m_xDataProvider.set( xDataProvider );
860
0
        m_xInternalDataProvider.clear();
861
862
        //the numberformatter is kept independent of the data provider!
863
0
    }
864
0
    setModified( true );
865
0
}
866
867
void SAL_CALL ChartModel::attachNumberFormatsSupplier( const uno::Reference< util::XNumberFormatsSupplier >& xNewSupplier )
868
0
{
869
0
    {
870
        // Mostly the supplier is SvNumberFormatsSupplierObj, but sometimes it is reportdesign::OReportDefinition
871
0
        MutexGuard aGuard( m_aModelMutex );
872
0
        if( xNewSupplier == m_xNumberFormatsSupplier )
873
0
            return;
874
0
        if( xNewSupplier == uno::Reference<XNumberFormatsSupplier>(m_xOwnNumberFormatsSupplier) )
875
0
            return;
876
0
        if( m_xOwnNumberFormatsSupplier.is() && xNewSupplier.is() )
877
0
        {
878
            //@todo
879
            //merge missing numberformats from own to new formatter
880
0
        }
881
0
        else if( !xNewSupplier.is() )
882
0
        {
883
0
            if( m_xNumberFormatsSupplier.is() )
884
0
            {
885
                //@todo
886
                //merge missing numberformats from old numberformatter to own numberformatter
887
                //create own numberformatter if necessary
888
0
            }
889
0
        }
890
891
0
        m_xNumberFormatsSupplier.set( xNewSupplier );
892
0
        m_xOwnNumberFormatsSupplier.clear();
893
0
    }
894
0
    setModified( true );
895
0
}
896
897
void SAL_CALL ChartModel::setArguments( const Sequence< beans::PropertyValue >& aArguments )
898
0
{
899
0
    {
900
0
        MutexGuard aGuard( m_aModelMutex );
901
0
        if( !m_xDataProvider.is() )
902
0
            return;
903
0
        lockControllers();
904
905
0
        try
906
0
        {
907
0
            Reference< chart2::data::XDataSource > xDataSource( m_xDataProvider->createDataSource( aArguments ) );
908
0
            if( xDataSource.is() )
909
0
            {
910
0
                rtl::Reference< Diagram > xDia = getFirstChartDiagram();
911
0
                if( !xDia.is() )
912
0
                {
913
0
                    rtl::Reference< ::chart::ChartTypeTemplate > xTemplate( impl_createDefaultChartTypeTemplate() );
914
0
                    if( xTemplate.is())
915
0
                        setFirstDiagram( xTemplate->createDiagramByDataSource( xDataSource, aArguments ) );
916
0
                }
917
0
                else
918
0
                    xDia->setDiagramData( xDataSource, aArguments );
919
0
            }
920
0
        }
921
0
        catch (const lang::IllegalArgumentException&)
922
0
        {
923
0
            throw;
924
0
        }
925
0
        catch (const uno::Exception&)
926
0
        {
927
0
            DBG_UNHANDLED_EXCEPTION("chart2");
928
0
        }
929
0
        unlockControllers();
930
0
    }
931
0
    setModified( true );
932
0
}
933
934
Sequence< OUString > SAL_CALL ChartModel::getUsedRangeRepresentations()
935
0
{
936
0
    return comphelper::containerToSequence(DataSourceHelper::getUsedDataRanges( this ));
937
0
}
938
939
Reference< chart2::data::XDataSource > SAL_CALL ChartModel::getUsedData()
940
0
{
941
0
    return DataSourceHelper::getUsedData( *this );
942
0
}
943
944
Reference< chart2::data::XRangeHighlighter > SAL_CALL ChartModel::getRangeHighlighter()
945
0
{
946
0
    if( ! m_xRangeHighlighter.is())
947
0
        m_xRangeHighlighter = new RangeHighlighter( this );
948
0
    return m_xRangeHighlighter;
949
0
}
950
951
Reference<awt::XRequestCallback> SAL_CALL ChartModel::getPopupRequest()
952
0
{
953
0
    if (!m_xPopupRequest.is())
954
0
        m_xPopupRequest.set(new PopupRequest);
955
0
    return m_xPopupRequest;
956
0
}
957
958
rtl::Reference< ::chart::ChartTypeTemplate > ChartModel::impl_createDefaultChartTypeTemplate()
959
0
{
960
0
    rtl::Reference< ::chart::ChartTypeTemplate > xTemplate;
961
0
    if( m_xChartTypeManager.is() )
962
0
        xTemplate = m_xChartTypeManager->createTemplate( u"com.sun.star.chart2.template.Column"_ustr );
963
0
    return xTemplate;
964
0
}
965
966
void SAL_CALL ChartModel::setChartTypeManager( const uno::Reference< chart2::XChartTypeManager >& xNewManager )
967
0
{
968
0
    {
969
0
        MutexGuard aGuard( m_aModelMutex );
970
0
        m_xChartTypeManager = dynamic_cast<::chart::ChartTypeManager*>(xNewManager.get());
971
0
        assert(!xNewManager || m_xChartTypeManager);
972
0
    }
973
0
    setModified( true );
974
0
}
975
976
uno::Reference< chart2::XChartTypeManager > SAL_CALL ChartModel::getChartTypeManager()
977
0
{
978
0
    MutexGuard aGuard( m_aModelMutex );
979
0
    return m_xChartTypeManager;
980
0
}
981
982
uno::Reference< beans::XPropertySet > SAL_CALL ChartModel::getPageBackground()
983
0
{
984
0
    MutexGuard aGuard( m_aModelMutex );
985
0
    return m_xPageBackground;
986
0
}
987
988
void SAL_CALL ChartModel::createDefaultChart()
989
0
{
990
0
    insertDefaultChart();
991
0
}
992
993
// ____ XTitled ____
994
uno::Reference< chart2::XTitle > SAL_CALL ChartModel::getTitleObject()
995
0
{
996
0
    MutexGuard aGuard( m_aModelMutex );
997
0
    return m_xTitle;
998
0
}
999
1000
rtl::Reference< Title > ChartModel::getTitleObject2() const
1001
0
{
1002
0
    MutexGuard aGuard( m_aModelMutex );
1003
0
    return m_xTitle;
1004
0
}
1005
1006
void SAL_CALL ChartModel::setTitleObject( const uno::Reference< chart2::XTitle >& xNewTitle )
1007
0
{
1008
0
    rtl::Reference<Title> xTitle = dynamic_cast<Title*>(xNewTitle.get());
1009
0
    assert(!xNewTitle || xTitle);
1010
0
    setTitleObject(xTitle);
1011
0
}
1012
1013
void ChartModel::setTitleObject( const rtl::Reference< Title >& xTitle )
1014
0
{
1015
0
    {
1016
0
        MutexGuard aGuard( m_aModelMutex );
1017
0
        if( m_xTitle.is() )
1018
0
            ModifyListenerHelper::removeListener( m_xTitle, this );
1019
0
        m_xTitle = xTitle;
1020
0
        ModifyListenerHelper::addListener( m_xTitle, this );
1021
0
    }
1022
0
    setModified( true );
1023
0
}
1024
1025
// ____ XInterface (for old API wrapper) ____
1026
uno::Any SAL_CALL ChartModel::queryInterface( const uno::Type& aType )
1027
0
{
1028
0
    uno::Any aResult( impl::ChartModel_Base::queryInterface( aType ));
1029
1030
0
    if( ! aResult.hasValue())
1031
0
    {
1032
        // try old API wrapper
1033
0
        try
1034
0
        {
1035
0
            if( m_xOldModelAgg.is())
1036
0
                aResult = m_xOldModelAgg->queryAggregation( aType );
1037
0
        }
1038
0
        catch (const uno::Exception&)
1039
0
        {
1040
0
            DBG_UNHANDLED_EXCEPTION("chart2");
1041
0
        }
1042
0
    }
1043
1044
0
    return aResult;
1045
0
}
1046
1047
// ____ XCloneable ____
1048
Reference< util::XCloneable > SAL_CALL ChartModel::createClone()
1049
0
{
1050
0
    std::unique_lock aGuard(m_aLifeTimeManager.m_aAccessMutex);
1051
0
    return Reference< util::XCloneable >( new ChartModel( *this ));
1052
0
}
1053
1054
// ____ XVisualObject ____
1055
void SAL_CALL ChartModel::setVisualAreaSize( ::sal_Int64 nAspect, const awt::Size& aSize )
1056
0
{
1057
0
    if( nAspect == embed::Aspects::MSOLE_CONTENT )
1058
0
    {
1059
0
        ControllerLockGuard aLockGuard( *this );
1060
0
        bool bChanged =
1061
0
            (m_aVisualAreaSize.Width != aSize.Width ||
1062
0
             m_aVisualAreaSize.Height != aSize.Height);
1063
1064
        // #i12587# support for shapes in chart
1065
0
        if ( bChanged )
1066
0
        {
1067
0
            impl_adjustAdditionalShapesPositionAndSize( aSize );
1068
0
        }
1069
1070
0
        m_aVisualAreaSize = aSize;
1071
0
        if( bChanged )
1072
0
            setModified( true );
1073
0
    }
1074
0
    else
1075
0
    {
1076
0
        OSL_FAIL( "setVisualAreaSize: Aspect not implemented yet.");
1077
0
    }
1078
0
}
1079
1080
awt::Size SAL_CALL ChartModel::getVisualAreaSize( ::sal_Int64 nAspect )
1081
0
{
1082
0
    OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT,
1083
0
                "No aspects other than content are supported" );
1084
    // other possible aspects are MSOLE_THUMBNAIL, MSOLE_ICON and MSOLE_DOCPRINT
1085
1086
0
    return m_aVisualAreaSize;
1087
0
}
1088
1089
embed::VisualRepresentation SAL_CALL ChartModel::getPreferredVisualRepresentation( ::sal_Int64 nAspect )
1090
0
{
1091
0
    OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT,
1092
0
                "No aspects other than content are supported" );
1093
1094
0
    embed::VisualRepresentation aResult;
1095
1096
0
    try
1097
0
    {
1098
0
        Sequence< sal_Int8 > aMetafile;
1099
1100
        //get view from old api wrapper
1101
0
        Reference< datatransfer::XTransferable > xTransferable( createChartView() );
1102
0
        if( xTransferable.is() )
1103
0
        {
1104
0
            datatransfer::DataFlavor aDataFlavor( lcl_aGDIMetaFileMIMEType,
1105
0
                    u"GDIMetaFile"_ustr,
1106
0
                    cppu::UnoType<uno::Sequence< sal_Int8 >>::get() );
1107
1108
0
            uno::Any aData( xTransferable->getTransferData( aDataFlavor ) );
1109
0
            aData >>= aMetafile;
1110
0
        }
1111
1112
0
        aResult.Flavor.MimeType = lcl_aGDIMetaFileMIMEType;
1113
0
        aResult.Flavor.DataType = cppu::UnoType<decltype(aMetafile)>::get();
1114
1115
0
        aResult.Data <<= aMetafile;
1116
0
    }
1117
0
    catch (const uno::Exception&)
1118
0
    {
1119
0
        DBG_UNHANDLED_EXCEPTION("chart2");
1120
0
    }
1121
1122
0
    return aResult;
1123
0
}
1124
1125
::sal_Int32 SAL_CALL ChartModel::getMapUnit( ::sal_Int64 nAspect )
1126
0
{
1127
0
    OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT,
1128
0
                "No aspects other than content are supported" );
1129
0
    return embed::EmbedMapUnits::ONE_100TH_MM;
1130
0
}
1131
1132
// ____ datatransfer::XTransferable ____
1133
uno::Any SAL_CALL ChartModel::getTransferData( const datatransfer::DataFlavor& aFlavor )
1134
0
{
1135
0
    uno::Any aResult;
1136
0
    if( !isDataFlavorSupported( aFlavor ) )
1137
0
        throw datatransfer::UnsupportedFlavorException(
1138
0
            aFlavor.MimeType, static_cast< ::cppu::OWeakObject* >( this ));
1139
1140
0
    try
1141
0
    {
1142
        //get view from old api wrapper
1143
0
        Reference< datatransfer::XTransferable > xTransferable( createChartView() );
1144
0
        if( xTransferable.is() &&
1145
0
            xTransferable->isDataFlavorSupported( aFlavor ))
1146
0
        {
1147
0
            aResult = xTransferable->getTransferData( aFlavor );
1148
0
        }
1149
0
    }
1150
0
    catch (const uno::Exception&)
1151
0
    {
1152
0
        DBG_UNHANDLED_EXCEPTION("chart2");
1153
0
    }
1154
1155
0
    return aResult;
1156
0
}
1157
1158
Sequence< datatransfer::DataFlavor > SAL_CALL ChartModel::getTransferDataFlavors()
1159
0
{
1160
0
    return { datatransfer::DataFlavor( lcl_aGDIMetaFileMIMETypeHighContrast,
1161
0
        u"GDIMetaFile"_ustr,
1162
0
        cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ) };
1163
0
}
1164
1165
sal_Bool SAL_CALL ChartModel::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor )
1166
0
{
1167
0
    return aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast;
1168
0
}
1169
1170
namespace
1171
{
1172
enum eServiceType
1173
{
1174
    SERVICE_DASH_TABLE,
1175
    SERVICE_GRADIENT_TABLE,
1176
    SERVICE_HATCH_TABLE,
1177
    SERVICE_BITMAP_TABLE,
1178
    SERVICE_TRANSP_GRADIENT_TABLE,
1179
    SERVICE_MARKER_TABLE,
1180
    SERVICE_NAMESPACE_MAP
1181
};
1182
1183
typedef std::map< OUString, enum eServiceType > tServiceNameMap;
1184
1185
tServiceNameMap & lcl_getStaticServiceNameMap()
1186
0
{
1187
0
    static tServiceNameMap aServiceNameMap{
1188
0
        {"com.sun.star.drawing.DashTable",                    SERVICE_DASH_TABLE},
1189
0
        {"com.sun.star.drawing.GradientTable",                SERVICE_GRADIENT_TABLE},
1190
0
        {"com.sun.star.drawing.HatchTable",                   SERVICE_HATCH_TABLE},
1191
0
        {"com.sun.star.drawing.BitmapTable",                  SERVICE_BITMAP_TABLE},
1192
0
        {"com.sun.star.drawing.TransparencyGradientTable",    SERVICE_TRANSP_GRADIENT_TABLE},
1193
0
        {"com.sun.star.drawing.MarkerTable",                  SERVICE_MARKER_TABLE},
1194
0
        {"com.sun.star.xml.NamespaceMap",                     SERVICE_NAMESPACE_MAP}};
1195
0
    return aServiceNameMap;
1196
0
}
1197
}
1198
// ____ XMultiServiceFactory ____
1199
Reference< uno::XInterface > SAL_CALL ChartModel::createInstance( const OUString& rServiceSpecifier )
1200
0
{
1201
0
    tServiceNameMap & rMap = lcl_getStaticServiceNameMap();
1202
1203
0
    tServiceNameMap::const_iterator aIt( rMap.find( rServiceSpecifier ));
1204
0
    if( aIt != rMap.end())
1205
0
    {
1206
0
        switch( (*aIt).second )
1207
0
        {
1208
0
            case SERVICE_DASH_TABLE:
1209
0
            case SERVICE_GRADIENT_TABLE:
1210
0
            case SERVICE_HATCH_TABLE:
1211
0
            case SERVICE_BITMAP_TABLE:
1212
0
            case SERVICE_TRANSP_GRADIENT_TABLE:
1213
0
            case SERVICE_MARKER_TABLE:
1214
0
                {
1215
0
                    if(!mxChartView.is())
1216
0
                    {
1217
0
                        mxChartView = new ChartView( m_xContext, *this);
1218
0
                    }
1219
0
                    return mxChartView->createInstance( rServiceSpecifier );
1220
0
                }
1221
0
                break;
1222
0
            case SERVICE_NAMESPACE_MAP:
1223
0
                return static_cast<cppu::OWeakObject*>(m_xXMLNamespaceMap.get());
1224
0
        }
1225
0
    }
1226
0
    else if(rServiceSpecifier == CHART_VIEW_SERVICE_NAME)
1227
0
    {
1228
0
        return static_cast< ::cppu::OWeakObject* >( createChartView().get() );
1229
0
    }
1230
0
    else
1231
0
    {
1232
0
        if( m_xOldModelAgg.is() )
1233
0
        {
1234
0
            Any aAny = m_xOldModelAgg->queryAggregation( cppu::UnoType<lang::XMultiServiceFactory>::get());
1235
0
            uno::Reference< lang::XMultiServiceFactory > xOldModelFactory;
1236
0
            if( (aAny >>= xOldModelFactory) && xOldModelFactory.is() )
1237
0
            {
1238
0
                return xOldModelFactory->createInstance( rServiceSpecifier );
1239
0
            }
1240
0
        }
1241
0
    }
1242
0
    return nullptr;
1243
0
}
1244
1245
const rtl::Reference<ChartView>& ChartModel::createChartView()
1246
0
{
1247
0
    if(!mxChartView.is())
1248
0
        mxChartView = new ChartView( m_xContext, *this);
1249
0
    return mxChartView;
1250
0
}
1251
1252
Reference< uno::XInterface > SAL_CALL ChartModel::createInstanceWithArguments(
1253
            const OUString& rServiceSpecifier , const Sequence< Any >& Arguments )
1254
0
{
1255
0
    OSL_ENSURE( Arguments.hasElements(), "createInstanceWithArguments: Warning: Arguments are ignored" );
1256
0
    return createInstance( rServiceSpecifier );
1257
0
}
1258
1259
Sequence< OUString > SAL_CALL ChartModel::getAvailableServiceNames()
1260
0
{
1261
0
    uno::Sequence< OUString > aResult;
1262
1263
0
    if( m_xOldModelAgg.is())
1264
0
    {
1265
0
        Any aAny = m_xOldModelAgg->queryAggregation( cppu::UnoType<lang::XMultiServiceFactory>::get());
1266
0
        uno::Reference< lang::XMultiServiceFactory > xOldModelFactory;
1267
0
        if( (aAny >>= xOldModelFactory) && xOldModelFactory.is() )
1268
0
        {
1269
0
            return xOldModelFactory->getAvailableServiceNames();
1270
0
        }
1271
0
    }
1272
0
    return aResult;
1273
0
}
1274
1275
Reference< util::XNumberFormatsSupplier > const & ChartModel::getNumberFormatsSupplier()
1276
0
{
1277
0
    if( !m_xNumberFormatsSupplier.is() )
1278
0
    {
1279
0
        if( !m_xOwnNumberFormatsSupplier.is() )
1280
0
        {
1281
0
            m_apSvNumberFormatter.reset( new SvNumberFormatter( m_xContext, LANGUAGE_SYSTEM ) );
1282
0
            if (m_aNullDate)
1283
0
            {
1284
0
                m_apSvNumberFormatter->ChangeNullDate(m_aNullDate->Day, m_aNullDate->Month, m_aNullDate->Year);
1285
0
            }
1286
0
            m_xOwnNumberFormatsSupplier = new SvNumberFormatsSupplierObj( m_apSvNumberFormatter.get() );
1287
            //pOwnNumberFormatter->ChangeStandardPrec( 15 ); todo?
1288
0
        }
1289
0
        m_xNumberFormatsSupplier = m_xOwnNumberFormatsSupplier;
1290
0
    }
1291
0
    return m_xNumberFormatsSupplier;
1292
0
}
1293
1294
// ____ XUnoTunnel ___
1295
::sal_Int64 SAL_CALL ChartModel::getSomething( const Sequence< ::sal_Int8 >& aIdentifier )
1296
0
{
1297
0
    if( comphelper::isUnoTunnelId<SvNumberFormatsSupplierObj>(aIdentifier) )
1298
0
    {
1299
0
        Reference< lang::XUnoTunnel > xTunnel( getNumberFormatsSupplier(), uno::UNO_QUERY );
1300
0
        if( xTunnel.is() )
1301
0
            return xTunnel->getSomething( aIdentifier );
1302
0
    }
1303
0
    return 0;
1304
0
}
1305
1306
// ____ XNumberFormatsSupplier ____
1307
uno::Reference< beans::XPropertySet > SAL_CALL ChartModel::getNumberFormatSettings()
1308
0
{
1309
0
    Reference< util::XNumberFormatsSupplier > xSupplier( getNumberFormatsSupplier() );
1310
0
    if( xSupplier.is() )
1311
0
        return xSupplier->getNumberFormatSettings();
1312
0
    return uno::Reference< beans::XPropertySet >();
1313
0
}
1314
1315
uno::Reference< util::XNumberFormats > SAL_CALL ChartModel::getNumberFormats()
1316
0
{
1317
0
    Reference< util::XNumberFormatsSupplier > xSupplier( getNumberFormatsSupplier() );
1318
0
    if( xSupplier.is() )
1319
0
        return xSupplier->getNumberFormats();
1320
0
    return uno::Reference< util::XNumberFormats >();
1321
0
}
1322
1323
// ____ XChild ____
1324
Reference< uno::XInterface > SAL_CALL ChartModel::getParent()
1325
0
{
1326
0
    return Reference< uno::XInterface >(m_xParent,uno::UNO_QUERY);
1327
0
}
1328
1329
void SAL_CALL ChartModel::setParent( const Reference< uno::XInterface >& Parent )
1330
0
{
1331
0
    if( Parent != m_xParent )
1332
0
    {
1333
0
        if (SfxObjectShell* pShell = getParentShell(m_xParent))
1334
0
            EndListening(*pShell);
1335
0
        m_xParent.set( Parent, uno::UNO_QUERY );
1336
0
        if (SfxObjectShell* pShell = getParentShell(m_xParent))
1337
0
            StartListening(*pShell);
1338
0
    }
1339
0
}
1340
1341
// ____ XDataSource ____
1342
uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > SAL_CALL ChartModel::getDataSequences()
1343
0
{
1344
0
    rtl::Reference< DataSource > xSource = DataSourceHelper::getUsedData( *this );
1345
0
    if( xSource.is())
1346
0
        return xSource->getDataSequences();
1347
1348
0
    return uno::Sequence< Reference< chart2::data::XLabeledDataSequence > >();
1349
0
}
1350
1351
//XDumper
1352
OUString SAL_CALL ChartModel::dump(OUString const & kind)
1353
0
{
1354
0
    if (kind.isEmpty()) {
1355
0
        return comphelper::dumpXmlToString([this](auto writer) { return dumpAsXml(writer); });
1356
0
    }
1357
1358
    // kind == "shapes":
1359
0
    uno::Reference< qa::XDumper > xDumper( createChartView() );
1360
0
    if (xDumper.is())
1361
0
        return xDumper->dump(kind);
1362
1363
0
    return OUString();
1364
0
}
1365
1366
void ChartModel::setTimeBasedRange(sal_Int32 nStart, sal_Int32 nEnd)
1367
0
{
1368
0
    mnStart = nStart;
1369
0
    mnEnd = nEnd;
1370
0
    mbTimeBased = true;
1371
0
}
1372
1373
void ChartModel::update()
1374
0
{
1375
0
    if(!mxChartView.is())
1376
0
    {
1377
0
        mxChartView = new ChartView( m_xContext, *this);
1378
0
    }
1379
0
    mxChartView->setViewDirty();
1380
0
    mxChartView->update();
1381
0
}
1382
1383
bool ChartModel::isDataFromSpreadsheet()
1384
0
{
1385
0
    return !isDataFromPivotTable() && !hasInternalDataProvider();
1386
0
}
1387
1388
bool ChartModel::isDataFromPivotTable() const
1389
0
{
1390
0
    uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(m_xDataProvider, uno::UNO_QUERY);
1391
0
    return xPivotTableDataProvider.is();
1392
0
}
1393
1394
rtl::Reference< BaseCoordinateSystem > ChartModel::getFirstCoordinateSystem()
1395
0
{
1396
0
    if( m_xDiagram )
1397
0
    {
1398
0
        auto aCooSysSeq( m_xDiagram->getBaseCoordinateSystems() );
1399
0
        if( !aCooSysSeq.empty() )
1400
0
            return aCooSysSeq[0];
1401
0
    }
1402
0
    return nullptr;
1403
0
}
1404
1405
std::vector< rtl::Reference< DataSeries > > ChartModel::getDataSeries()
1406
0
{
1407
0
    if( m_xDiagram)
1408
0
        return m_xDiagram->getDataSeries();
1409
1410
0
    return {};
1411
0
}
1412
1413
rtl::Reference< ChartType > ChartModel::getChartTypeOfSeries( const rtl::Reference< DataSeries >& xGivenDataSeries )
1414
0
{
1415
0
    return m_xDiagram ? m_xDiagram->getChartTypeOfSeries( xGivenDataSeries ) : nullptr;
1416
0
}
1417
1418
// static
1419
awt::Size ChartModel::getDefaultPageSize()
1420
0
{
1421
0
    return awt::Size( 16000, 9000 );
1422
0
}
1423
1424
awt::Size ChartModel::getPageSize()
1425
0
{
1426
0
    return getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
1427
0
}
1428
1429
void ChartModel::triggerRangeHighlighting()
1430
0
{
1431
0
    getRangeHighlighter();
1432
0
    uno::Reference< view::XSelectionChangeListener > xSelectionChangeListener( m_xRangeHighlighter );
1433
    //trigger selection of cell range
1434
0
    lang::EventObject aEvent( xSelectionChangeListener );
1435
0
    xSelectionChangeListener->selectionChanged( aEvent );
1436
0
}
1437
1438
bool ChartModel::isIncludeHiddenCells()
1439
0
{
1440
0
    bool bIncluded = true;  // hidden cells are included by default.
1441
1442
0
    if (!m_xDiagram)
1443
0
        return bIncluded;
1444
1445
0
    try
1446
0
    {
1447
0
        m_xDiagram->getPropertyValue(u"IncludeHiddenCells"_ustr) >>= bIncluded;
1448
0
    }
1449
0
    catch( const beans::UnknownPropertyException& )
1450
0
    {
1451
0
    }
1452
1453
0
    return bIncluded;
1454
0
}
1455
1456
bool ChartModel::setIncludeHiddenCells( bool bIncludeHiddenCells )
1457
0
{
1458
0
    bool bChanged = false;
1459
0
    try
1460
0
    {
1461
0
        ControllerLockGuard aLockedControllers( *this );
1462
1463
0
        uno::Reference< beans::XPropertySet > xDiagramProperties( getFirstDiagram(), uno::UNO_QUERY );
1464
0
        if (!xDiagramProperties)
1465
0
            return false;
1466
1467
0
        bool bOldValue = bIncludeHiddenCells;
1468
0
        xDiagramProperties->getPropertyValue( u"IncludeHiddenCells"_ustr ) >>= bOldValue;
1469
0
        if( bOldValue == bIncludeHiddenCells )
1470
0
            bChanged = true;
1471
1472
        //set the property on all instances in all cases to get the different objects in sync!
1473
1474
0
        uno::Any aNewValue(bIncludeHiddenCells);
1475
1476
0
        try
1477
0
        {
1478
0
            uno::Reference< beans::XPropertySet > xDataProviderProperties( getDataProvider(), uno::UNO_QUERY );
1479
0
            if( xDataProviderProperties.is() )
1480
0
                xDataProviderProperties->setPropertyValue(u"IncludeHiddenCells"_ustr, aNewValue );
1481
0
        }
1482
0
        catch( const beans::UnknownPropertyException& )
1483
0
        {
1484
            //the property is optional!
1485
0
        }
1486
1487
0
        try
1488
0
        {
1489
0
            rtl::Reference< DataSource > xUsedData = DataSourceHelper::getUsedData( *this );
1490
0
            if( xUsedData.is() )
1491
0
            {
1492
0
                uno::Reference< beans::XPropertySet > xProp;
1493
0
                const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aData( xUsedData->getDataSequences());
1494
0
                for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledData : aData )
1495
0
                {
1496
0
                    xProp.set( uno::Reference< beans::XPropertySet >( labeledData->getValues(), uno::UNO_QUERY ) );
1497
0
                    if(xProp.is())
1498
0
                        xProp->setPropertyValue(u"IncludeHiddenCells"_ustr, aNewValue );
1499
0
                    xProp.set( uno::Reference< beans::XPropertySet >( labeledData->getLabel(), uno::UNO_QUERY ) );
1500
0
                    if(xProp.is())
1501
0
                        xProp->setPropertyValue(u"IncludeHiddenCells"_ustr, aNewValue );
1502
0
                }
1503
0
            }
1504
0
        }
1505
0
        catch( const beans::UnknownPropertyException& )
1506
0
        {
1507
            //the property is optional!
1508
0
        }
1509
1510
0
        xDiagramProperties->setPropertyValue( u"IncludeHiddenCells"_ustr, aNewValue);
1511
0
    }
1512
0
    catch (const uno::Exception&)
1513
0
    {
1514
0
        TOOLS_WARN_EXCEPTION("chart2", "" );
1515
0
    }
1516
0
    return bChanged;
1517
0
}
1518
1519
void ChartModel::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
1520
0
{
1521
0
    if (rHint.GetId() == SfxHintId::ThemeColorsChanged)
1522
0
    {
1523
0
        onDocumentThemeChanged();
1524
0
    }
1525
0
}
1526
1527
std::shared_ptr<model::Theme> ChartModel::getDocumentTheme() const
1528
0
{
1529
0
    std::shared_ptr<model::Theme> pTheme;
1530
0
    uno::Any aThemeValue;
1531
1532
0
    auto pParent = const_cast<ChartModel*>(this)->getParent();
1533
0
    uno::Reference<frame::XModel> xDocModel(pParent, uno::UNO_QUERY);
1534
0
    uno::Reference<text::XTextDocument> xTextDoc(xDocModel, uno::UNO_QUERY);
1535
1536
0
    if (!xTextDoc.is()) // Calc, Impress
1537
0
    {
1538
0
        uno::Reference<beans::XPropertySet> xPropSet(xDocModel, uno::UNO_QUERY);
1539
0
        if (xPropSet.is())
1540
0
        {
1541
0
            aThemeValue = xPropSet->getPropertyValue("Theme");
1542
0
        }
1543
0
    }
1544
0
    else // Writer
1545
0
    {
1546
0
        uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xDocModel, uno::UNO_QUERY);
1547
0
        if (xDrawPageSupplier.is())
1548
0
        {
1549
0
            uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
1550
0
            if (xDrawPage.is())
1551
0
            {
1552
0
                uno::Reference<beans::XPropertySet> xPropSet(xDrawPage, uno::UNO_QUERY);
1553
0
                if (xPropSet.is())
1554
0
                {
1555
0
                    aThemeValue = xPropSet->getPropertyValue("Theme");
1556
0
                }
1557
0
            }
1558
0
        }
1559
0
    }
1560
1561
0
    uno::Reference<util::XTheme> xTheme(aThemeValue, uno::UNO_QUERY);
1562
0
    if (xTheme.is())
1563
0
    {
1564
0
        if (auto* pUnoTheme = dynamic_cast<UnoTheme*>(xTheme.get()))
1565
0
        {
1566
0
            pTheme = pUnoTheme->getTheme();
1567
0
        }
1568
0
    }
1569
0
    else
1570
0
    {
1571
0
        pTheme = model::Theme::FromAny(aThemeValue);
1572
0
    }
1573
1574
0
    return pTheme;
1575
0
}
1576
1577
void ChartModel::setColorPalette(ChartColorPaletteType eType, sal_uInt32 nIndex)
1578
0
{
1579
0
    m_eColorPaletteType = eType;
1580
0
    m_nColorPaletteIndex = nIndex;
1581
0
}
1582
1583
void ChartModel::clearColorPalette()
1584
0
{
1585
    // Not reset the selected palette if user is just previewing a color
1586
    // for a data series or a data point
1587
0
    SfxViewShell* pCurrentShell = SfxViewShell::Current();
1588
0
    if (pCurrentShell && pCurrentShell->IsLOKColorPreviewEnabled())
1589
0
        return;
1590
1591
0
    setColorPalette(ChartColorPaletteType::Unknown, 0);
1592
0
}
1593
1594
bool ChartModel::usesColorPalette() const
1595
0
{
1596
0
    return m_eColorPaletteType != ChartColorPaletteType::Unknown;
1597
0
}
1598
1599
std::optional<ChartColorPalette> ChartModel::getCurrentColorPalette() const
1600
0
{
1601
0
    if (!usesColorPalette())
1602
0
    {
1603
0
        SAL_WARN("chart2", "ChartModel::getCurrentColorPalette: no palette is in use");
1604
0
        return std::nullopt;
1605
0
    }
1606
1607
0
    const std::shared_ptr<model::Theme> pTheme = getDocumentTheme();
1608
    // when pTheme is null, ChartColorPaletteHelper uses a default theme
1609
0
    const ChartColorPaletteHelper aColorPaletteHelper(pTheme);
1610
0
    return aColorPaletteHelper.getColorPalette(getColorPaletteType(), getColorPaletteIndex());
1611
0
}
1612
1613
void ChartModel::applyColorPaletteToDataSeries(const ChartColorPalette& rColorPalette)
1614
0
{
1615
0
    const rtl::Reference<Diagram> xDiagram = getFirstChartDiagram();
1616
0
    const auto xDataSeriesArray = xDiagram->getDataSeries();
1617
0
    for (size_t i = 0; i < xDataSeriesArray.size(); ++i)
1618
0
    {
1619
0
        const uno::Reference<beans::XPropertySet> xPropSet = xDataSeriesArray[i];
1620
0
        const size_t nPaletteIndex = i % rColorPalette.size();
1621
0
        xPropSet->setPropertyValue("FillStyle", uno::Any(drawing::FillStyle_SOLID));
1622
0
        xPropSet->setPropertyValue("FillColor", uno::Any(rColorPalette[nPaletteIndex]));
1623
0
    }
1624
0
}
1625
1626
void ChartModel::onDocumentThemeChanged()
1627
0
{
1628
0
    if (const auto oColorPalette = getCurrentColorPalette())
1629
0
    {
1630
0
        applyColorPaletteToDataSeries(*oColorPalette);
1631
0
        setModified(true);
1632
0
    }
1633
0
}
1634
1635
void ChartModel::changeNullDate(const css::util::DateTime& aNullDate)
1636
0
{
1637
0
    if (m_aNullDate == aNullDate)
1638
0
        return;
1639
1640
0
    m_aNullDate = aNullDate;
1641
0
    if (m_apSvNumberFormatter)
1642
0
    {
1643
0
        m_apSvNumberFormatter->ChangeNullDate(aNullDate.Day, aNullDate.Month, aNullDate.Year);
1644
0
    }
1645
0
}
1646
1647
std::optional<css::util::DateTime> ChartModel::getNullDate() const
1648
0
{
1649
0
    return m_aNullDate;
1650
0
}
1651
1652
}  // namespace chart
1653
1654
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1655
com_sun_star_comp_chart2_ChartModel_get_implementation(css::uno::XComponentContext *context,
1656
        css::uno::Sequence<css::uno::Any> const &)
1657
0
{
1658
0
    return cppu::acquire(new ::chart::ChartModel(context));
1659
0
}
1660
1661
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */