Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/unoobj/dapiuno.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 <algorithm>
21
#include <cmath>
22
23
#include <o3tl/safeint.hxx>
24
#include <svl/hint.hxx>
25
#include <utility>
26
#include <vcl/svapp.hxx>
27
#include <sal/log.hxx>
28
29
#include <dapiuno.hxx>
30
#include <datauno.hxx>
31
#include <miscuno.hxx>
32
#include <convuno.hxx>
33
#include <docsh.hxx>
34
#include <tabvwsh.hxx>
35
#include <rangeutl.hxx>
36
#include <dpobject.hxx>
37
#include <dpshttab.hxx>
38
#include <dpsdbtab.hxx>
39
#include <dpsave.hxx>
40
#include <dbdocfun.hxx>
41
#include <unonames.hxx>
42
#include <dpdimsave.hxx>
43
#include <hints.hxx>
44
#include <dputil.hxx>
45
#include <globstr.hrc>
46
#include <scresid.hxx>
47
#include <generalfunction.hxx>
48
49
#include <com/sun/star/container/XNameAccess.hpp>
50
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
51
#include <com/sun/star/lang/IllegalArgumentException.hpp>
52
#include <com/sun/star/lang/NullPointerException.hpp>
53
#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
54
#include <com/sun/star/sheet/XDimensionsSupplier.hpp>
55
#include <com/sun/star/sheet/XLevelsSupplier.hpp>
56
#include <com/sun/star/sheet/XMembersAccess.hpp>
57
#include <com/sun/star/beans/PropertyAttribute.hpp>
58
#include <com/sun/star/sheet/DataImportMode.hpp>
59
#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
60
#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
61
#include <com/sun/star/sheet/DataPilotOutputRangeType.hpp>
62
#include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
63
#include <com/sun/star/sheet/GeneralFunction2.hpp>
64
65
#include <comphelper/extract.hxx>
66
#include <comphelper/propertysequence.hxx>
67
#include <cppuhelper/queryinterface.hxx>
68
#include <comphelper/sequence.hxx>
69
#include <cppuhelper/exc_hlp.hxx>
70
71
using namespace com::sun::star;
72
using namespace com::sun::star::sheet;
73
74
using ::com::sun::star::uno::Any;
75
using ::com::sun::star::uno::Exception;
76
using ::com::sun::star::uno::Reference;
77
using ::com::sun::star::uno::RuntimeException;
78
using ::com::sun::star::uno::Sequence;
79
using ::com::sun::star::uno::UNO_QUERY;
80
using ::com::sun::star::uno::UNO_QUERY_THROW;
81
82
using ::com::sun::star::container::ElementExistException;
83
using ::com::sun::star::container::NoSuchElementException;
84
using ::com::sun::star::container::XEnumeration;
85
using ::com::sun::star::container::XIndexAccess;
86
using ::com::sun::star::container::XNameAccess;
87
using ::com::sun::star::container::XNamed;
88
89
using ::com::sun::star::beans::UnknownPropertyException;
90
using ::com::sun::star::beans::XPropertyChangeListener;
91
using ::com::sun::star::beans::XPropertySet;
92
using ::com::sun::star::beans::XPropertySetInfo;
93
using ::com::sun::star::beans::XVetoableChangeListener;
94
95
using ::com::sun::star::lang::IllegalArgumentException;
96
using ::com::sun::star::lang::IndexOutOfBoundsException;
97
using ::com::sun::star::lang::NullPointerException;
98
99
using ::com::sun::star::table::CellAddress;
100
using ::com::sun::star::table::CellRangeAddress;
101
102
namespace {
103
104
std::span<const SfxItemPropertyMapEntry> lcl_GetDataPilotDescriptorBaseMap()
105
320
{
106
320
    static const SfxItemPropertyMapEntry aDataPilotDescriptorBaseMap_Impl[] =
107
320
    {
108
320
        { SC_UNO_DP_COLGRAND,     0,  cppu::UnoType<bool>::get(),  0, 0 },
109
320
        { SC_UNO_DP_DRILLDOWN,    0,  cppu::UnoType<bool>::get(),  0, 0 },
110
320
        { SC_UNO_DP_GRANDTOTAL_NAME,0,cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0 },
111
320
        { SC_UNO_DP_IGNORE_EMPTYROWS,   0,  cppu::UnoType<bool>::get(),  0, 0 },
112
320
        { SC_UNO_DP_IMPORTDESC,   0,  cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get(), 0, 0 },
113
320
        { SC_UNO_DP_REPEATEMPTY,     0,  cppu::UnoType<bool>::get(),  0, 0 },
114
320
        { SC_UNO_DP_ROWGRAND,     0,  cppu::UnoType<bool>::get(),  0, 0 },
115
320
        { SC_UNO_DP_SERVICEARG,   0,  cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get(), 0, 0 },
116
320
        { SC_UNO_DP_SHOWFILTER,     0,  cppu::UnoType<bool>::get(),  0, 0 },
117
320
        { SC_UNO_DP_SOURCESERVICE,   0,  cppu::UnoType<OUString>::get(), 0, 0 },
118
320
    };
119
320
    return aDataPilotDescriptorBaseMap_Impl;
120
320
}
121
122
std::span<const SfxItemPropertyMapEntry> lcl_GetDataPilotFieldMap()
123
2.56k
{
124
2.56k
    using namespace ::com::sun::star::beans::PropertyAttribute;
125
2.56k
    static const SfxItemPropertyMapEntry aDataPilotFieldMap_Impl[] =
126
2.56k
    {
127
2.56k
        { SC_UNONAME_AUTOSHOW,     0,  cppu::UnoType<DataPilotFieldAutoShowInfo>::get(),   MAYBEVOID, 0 },
128
2.56k
        { SC_UNONAME_FUNCTION,     0,  cppu::UnoType<GeneralFunction>::get(),              0, 0 },
129
2.56k
        { SC_UNONAME_FUNCTION2,    0,  cppu::UnoType<sal_Int16>::get(),             0, 0 },
130
2.56k
        { SC_UNONAME_GROUPINFO,    0,  cppu::UnoType<DataPilotFieldGroupInfo>::get(),      MAYBEVOID, 0 },
131
2.56k
        { SC_UNONAME_HASAUTOSHOW,  0,  cppu::UnoType<bool>::get(),                          0, 0 },
132
2.56k
        { SC_UNONAME_HASLAYOUTINFO,0,  cppu::UnoType<bool>::get(),                          0, 0 },
133
2.56k
        { SC_UNONAME_HASREFERENCE, 0,  cppu::UnoType<bool>::get(),                          0, 0 },
134
2.56k
        { SC_UNONAME_HASSORTINFO,  0,  cppu::UnoType<bool>::get(),                          0, 0 },
135
2.56k
        { SC_UNONAME_ISGROUP,      0,  cppu::UnoType<bool>::get(),                          0, 0 },
136
2.56k
        { SC_UNONAME_LAYOUTINFO,   0,  cppu::UnoType<DataPilotFieldLayoutInfo>::get(),     MAYBEVOID, 0 },
137
2.56k
        { SC_UNONAME_ORIENT,       0,  cppu::UnoType<DataPilotFieldOrientation>::get(),    MAYBEVOID, 0 },
138
2.56k
        { SC_UNONAME_REFERENCE,    0,  cppu::UnoType<DataPilotFieldReference>::get(),      MAYBEVOID, 0 },
139
2.56k
        { SC_UNONAME_SELPAGE,      0,  cppu::UnoType<OUString>::get(),                     0, 0 },
140
2.56k
        { SC_UNONAME_SHOWEMPTY,    0,  cppu::UnoType<bool>::get(),                          0, 0 },
141
2.56k
        { SC_UNONAME_REPEATITEMLABELS,    0,  cppu::UnoType<bool>::get(),                          0, 0 },
142
2.56k
        { SC_UNONAME_SORTINFO,     0,  cppu::UnoType<DataPilotFieldSortInfo>::get(),       MAYBEVOID, 0 },
143
2.56k
        { SC_UNONAME_SUBTOTALS,    0,  cppu::UnoType<Sequence<GeneralFunction>>::get(),    0, 0 },
144
2.56k
        { SC_UNONAME_SUBTOTALS2,   0,  cppu::UnoType<Sequence<sal_Int16>>::get(),   0, 0 },
145
2.56k
        { SC_UNONAME_USESELPAGE,   0,  cppu::UnoType<bool>::get(),                          0, 0 },
146
2.56k
    };
147
2.56k
    return aDataPilotFieldMap_Impl;
148
2.56k
}
149
150
std::span<const SfxItemPropertyMapEntry> lcl_GetDataPilotItemMap()
151
0
{
152
0
    static const SfxItemPropertyMapEntry aDataPilotItemMap_Impl[] =
153
0
    {
154
0
        { SC_UNONAME_ISHIDDEN,     0,  cppu::UnoType<bool>::get(),          0, 0 },
155
0
        { SC_UNONAME_POS,          0,  cppu::UnoType<sal_Int32>::get(),    0, 0 },
156
0
        { SC_UNONAME_SHOWDETAIL,   0,  cppu::UnoType<bool>::get(),          0, 0 },
157
0
    };
158
0
    return aDataPilotItemMap_Impl;
159
0
}
160
161
bool lclCheckValidDouble( double fValue, bool bAuto )
162
51
{
163
51
    return bAuto || std::isfinite( fValue );
164
51
}
165
166
bool lclCheckMinMaxStep( const DataPilotFieldGroupInfo& rInfo )
167
17
{
168
17
    return
169
17
        lclCheckValidDouble( rInfo.Start, rInfo.HasAutoStart ) &&
170
17
        lclCheckValidDouble( rInfo.End, rInfo.HasAutoEnd ) &&
171
17
        (rInfo.HasAutoStart || rInfo.HasAutoEnd || (rInfo.Start <= rInfo.End)) &&
172
17
        lclCheckValidDouble( rInfo.Step, false ) &&
173
17
        (0.0 <= rInfo.Step);
174
17
}
175
176
} // namespace
177
178
SC_SIMPLE_SERVICE_INFO( ScDataPilotDescriptor, u"ScDataPilotDescriptor"_ustr, u"stardiv::one::sheet::DataPilotDescriptor"_ustr )
179
SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldObj, u"ScDataPilotFieldObj"_ustr, u"com.sun.star.sheet.DataPilotField"_ustr )
180
SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldsObj, u"ScDataPilotFieldsObj"_ustr, u"com.sun.star.sheet.DataPilotFields"_ustr )
181
SC_SIMPLE_SERVICE_INFO( ScDataPilotTableObj, u"ScDataPilotTableObj"_ustr, u"com.sun.star.sheet.DataPilotTable"_ustr )
182
SC_SIMPLE_SERVICE_INFO( ScDataPilotTablesObj, u"ScDataPilotTablesObj"_ustr, u"com.sun.star.sheet.DataPilotTables"_ustr )
183
SC_SIMPLE_SERVICE_INFO( ScDataPilotItemsObj, u"ScDataPilotItemsObj"_ustr, u"com.sun.star.sheet.DataPilotItems"_ustr )
184
SC_SIMPLE_SERVICE_INFO( ScDataPilotItemObj, u"ScDataPilotItemObj"_ustr, u"com.sun.star.sheet.DataPilotItem"_ustr )
185
186
SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldGroupsObj, u"ScDataPilotFieldGroupsObj"_ustr, u"com.sun.star.sheet.DataPilotFieldGroups"_ustr )
187
SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldGroupObj, u"ScDataPilotFieldGroupObj"_ustr, u"com.sun.star.sheet.DataPilotFieldGroup"_ustr )
188
SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldGroupItemObj, u"ScDataPilotFieldGroupItemObj"_ustr, u"com.sun.star.sheet.DataPilotFieldGroupItem"_ustr )
189
190
// name that is used in the API for the data layout field
191
constexpr OUString SC_DATALAYOUT_NAME = u"Data"_ustr;
192
193
ScGeneralFunction ScDataPilotConversion::FirstFunc( PivotFunc nBits )
194
0
{
195
0
    if ( nBits & PivotFunc::Sum )       return ScGeneralFunction::SUM;
196
0
    if ( nBits & PivotFunc::Count )     return ScGeneralFunction::COUNT;
197
0
    if ( nBits & PivotFunc::Average )   return ScGeneralFunction::AVERAGE;
198
0
    if ( nBits & PivotFunc::Median )    return ScGeneralFunction::MEDIAN;
199
0
    if ( nBits & PivotFunc::Max )       return ScGeneralFunction::MAX;
200
0
    if ( nBits & PivotFunc::Min )       return ScGeneralFunction::MIN;
201
0
    if ( nBits & PivotFunc::Product )   return ScGeneralFunction::PRODUCT;
202
0
    if ( nBits & PivotFunc::CountNum )  return ScGeneralFunction::COUNTNUMS;
203
0
    if ( nBits & PivotFunc::StdDev )    return ScGeneralFunction::STDEV;
204
0
    if ( nBits & PivotFunc::StdDevP )   return ScGeneralFunction::STDEVP;
205
0
    if ( nBits & PivotFunc::StdVar )    return ScGeneralFunction::VAR;
206
0
    if ( nBits & PivotFunc::StdVarP )   return ScGeneralFunction::VARP;
207
0
    if ( nBits & PivotFunc::Auto )      return ScGeneralFunction::AUTO;
208
0
    return ScGeneralFunction::NONE;
209
0
}
210
211
PivotFunc ScDataPilotConversion::FunctionBit( sal_Int16 eFunc )
212
0
{
213
0
    PivotFunc nRet = PivotFunc::NONE;  // 0
214
0
    switch (eFunc)
215
0
    {
216
0
        case GeneralFunction2::SUM:       nRet = PivotFunc::Sum;       break;
217
0
        case GeneralFunction2::COUNT:     nRet = PivotFunc::Count;     break;
218
0
        case GeneralFunction2::AVERAGE:   nRet = PivotFunc::Average;   break;
219
0
        case GeneralFunction2::MEDIAN:    nRet = PivotFunc::Median;    break;
220
0
        case GeneralFunction2::MAX:       nRet = PivotFunc::Max;       break;
221
0
        case GeneralFunction2::MIN:       nRet = PivotFunc::Min;       break;
222
0
        case GeneralFunction2::PRODUCT:   nRet = PivotFunc::Product;   break;
223
0
        case GeneralFunction2::COUNTNUMS: nRet = PivotFunc::CountNum; break;
224
0
        case GeneralFunction2::STDEV:     nRet = PivotFunc::StdDev;   break;
225
0
        case GeneralFunction2::STDEVP:    nRet = PivotFunc::StdDevP;  break;
226
0
        case GeneralFunction2::VAR:       nRet = PivotFunc::StdVar;   break;
227
0
        case GeneralFunction2::VARP:      nRet = PivotFunc::StdVarP;  break;
228
0
        case GeneralFunction2::AUTO:      nRet = PivotFunc::Auto;      break;
229
0
        default:
230
0
        {
231
0
            assert(false);
232
0
        }
233
0
    }
234
0
    return nRet;
235
0
}
236
237
void ScDataPilotConversion::FillGroupInfo( DataPilotFieldGroupInfo& rInfo, const ScDPNumGroupInfo& rGroupInfo )
238
17
{
239
17
    rInfo.HasDateValues = rGroupInfo.mbDateValues;
240
17
    rInfo.HasAutoStart  = rGroupInfo.mbAutoStart;
241
17
    rInfo.Start         = rGroupInfo.mfStart;
242
17
    rInfo.HasAutoEnd    = rGroupInfo.mbAutoEnd;
243
17
    rInfo.End           = rGroupInfo.mfEnd;
244
17
    rInfo.Step          = rGroupInfo.mfStep;
245
17
}
246
247
static ScDPObject* lcl_GetDPObject( ScDocShell* pDocShell, SCTAB nTab, std::u16string_view rName )
248
0
{
249
0
    if (pDocShell)
250
0
    {
251
0
        ScDocument& rDoc = pDocShell->GetDocument();
252
0
        ScDPCollection* pColl = rDoc.GetDPCollection();
253
0
        if ( pColl )
254
0
        {
255
0
            size_t nCount = pColl->GetCount();
256
0
            for (size_t i=0; i<nCount; ++i)
257
0
            {
258
0
                ScDPObject& rDPObj = (*pColl)[i];
259
0
                if ( rDPObj.GetOutRange().aStart.Tab() == nTab &&
260
0
                     rDPObj.GetName() == rName )
261
0
                    return &rDPObj;
262
0
            }
263
0
        }
264
0
    }
265
0
    return nullptr;    // not found
266
0
}
267
268
static OUString lcl_CreatePivotName( ScDocShell* pDocShell )
269
0
{
270
0
    if (pDocShell)
271
0
    {
272
0
        ScDocument& rDoc = pDocShell->GetDocument();
273
0
        ScDPCollection* pColl = rDoc.GetDPCollection();
274
0
        if ( pColl )
275
0
            return pColl->CreateNewName();
276
0
    }
277
0
    return OUString();                    // shouldn't happen
278
0
}
279
280
static sal_Int32 lcl_GetObjectIndex( ScDPObject* pDPObj, const ScFieldIdentifier& rFieldId )
281
26
{
282
    // used for items - nRepeat in identifier can be ignored
283
26
    if ( pDPObj )
284
26
    {
285
26
        sal_Int32 nCount = pDPObj->GetDimCount();
286
104
        for ( sal_Int32 nDim = 0; nDim < nCount; ++nDim )
287
104
        {
288
104
            bool bIsDataLayout = false;
289
104
            OUString aDimName( pDPObj->GetDimName( nDim, bIsDataLayout ) );
290
104
            if ( rFieldId.mbDataLayout ? bIsDataLayout : (aDimName == rFieldId.maFieldName) )
291
26
                return nDim;
292
104
        }
293
26
    }
294
0
    return -1;  // none
295
26
}
296
297
ScDataPilotTablesObj::ScDataPilotTablesObj(ScDocShell& rDocSh, SCTAB nT) :
298
320
    pDocShell( &rDocSh ),
299
320
    nTab( nT )
300
320
{
301
320
    pDocShell->GetDocument().AddUnoObject(*this);
302
320
}
303
304
ScDataPilotTablesObj::~ScDataPilotTablesObj()
305
320
{
306
320
    SolarMutexGuard g;
307
308
320
    if (pDocShell)
309
320
        pDocShell->GetDocument().RemoveUnoObject(*this);
310
320
}
311
312
void ScDataPilotTablesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
313
640
{
314
    //! update of references
315
316
640
    if ( rHint.GetId() == SfxHintId::Dying )
317
0
    {
318
0
        pDocShell = nullptr;       // became invalid
319
0
    }
320
640
}
321
322
// XDataPilotTables
323
324
rtl::Reference<ScDataPilotTableObj> ScDataPilotTablesObj::GetObjectByIndex_Impl( sal_Int32 nIndex )
325
0
{
326
0
    if (pDocShell)
327
0
    {
328
0
        ScDocument& rDoc = pDocShell->GetDocument();
329
0
        ScDPCollection* pColl = rDoc.GetDPCollection();
330
0
        if ( pColl )
331
0
        {
332
            //  count tables on this sheet
333
0
            sal_Int32 nFound = 0;
334
0
            size_t nCount = pColl->GetCount();
335
0
            for (size_t i=0; i<nCount; ++i)
336
0
            {
337
0
                ScDPObject& rDPObj = (*pColl)[i];
338
0
                if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
339
0
                {
340
0
                    if ( nFound == nIndex )
341
0
                    {
342
0
                        return new ScDataPilotTableObj(*pDocShell, nTab, rDPObj.GetName());
343
0
                    }
344
0
                    ++nFound;
345
0
                }
346
0
            }
347
0
        }
348
0
    }
349
0
    return nullptr;
350
0
}
351
352
rtl::Reference<ScDataPilotTableObj> ScDataPilotTablesObj::GetObjectByName_Impl(const OUString& rName)
353
0
{
354
0
    if (hasByName(rName))
355
0
        return new ScDataPilotTableObj(*pDocShell, nTab, rName);
356
0
    return nullptr;
357
0
}
358
359
Reference<XDataPilotDescriptor> SAL_CALL ScDataPilotTablesObj::createDataPilotDescriptor()
360
320
{
361
320
    SolarMutexGuard aGuard;
362
320
    if (pDocShell)
363
320
        return new ScDataPilotDescriptor(*pDocShell);
364
0
    return nullptr;
365
320
}
366
367
static bool lcl_IsDuplicated(const Reference<XPropertySet>& rDimProps)
368
4.88k
{
369
4.88k
    try
370
4.88k
    {
371
4.88k
        Any aAny = rDimProps->getPropertyValue( SC_UNO_DP_ORIGINAL );
372
4.88k
        Reference< XNamed > xOriginal( aAny, UNO_QUERY );
373
4.88k
        return xOriginal.is();
374
4.88k
    }
375
4.88k
    catch( Exception& )
376
4.88k
    {
377
0
    }
378
0
    return false;
379
4.88k
}
380
381
static OUString lcl_GetOriginalName(const Reference< XNamed >& rDim)
382
1.46k
{
383
1.46k
    Reference< XNamed > xOriginal;
384
385
1.46k
    Reference< XPropertySet > xDimProps(rDim, UNO_QUERY);
386
1.46k
    if ( xDimProps.is() )
387
1.46k
    {
388
1.46k
        try
389
1.46k
        {
390
1.46k
            Any aAny = xDimProps->getPropertyValue(SC_UNO_DP_ORIGINAL);
391
1.46k
            aAny >>= xOriginal;
392
1.46k
        }
393
1.46k
        catch( Exception& )
394
1.46k
        {
395
0
        }
396
1.46k
    }
397
398
1.46k
    if ( !xOriginal.is() )
399
1.46k
        xOriginal = rDim;
400
401
1.46k
    return xOriginal->getName();
402
1.46k
}
403
404
void SAL_CALL ScDataPilotTablesObj::insertNewByName( const OUString& aNewName,
405
    const CellAddress& aOutputAddress,
406
    const Reference<XDataPilotDescriptor>& xDescriptor )
407
320
{
408
320
    SolarMutexGuard aGuard;
409
320
    if (!xDescriptor.is()) return;
410
411
320
    if ( !aNewName.isEmpty() && hasByName( aNewName ) )
412
0
        throw IllegalArgumentException("Name \"" + aNewName + "\" already exists", getXWeak(), 0);
413
414
320
    if (!pDocShell)
415
0
        throw RuntimeException(u"DocShell is null"_ustr, getXWeak());
416
417
320
    auto pImp = dynamic_cast<ScDataPilotDescriptorBase*>( xDescriptor.get() );
418
320
    if (!pImp)
419
0
        throw RuntimeException(u"Failed to get ScDataPilotDescriptor"_ustr, getXWeak());
420
421
320
    ScDPObject* pNewObj = pImp->GetDPObject();
422
320
    if (!pNewObj)
423
0
        throw RuntimeException(u"Failed to get DPObject"_ustr, getXWeak());
424
425
320
    ScRange aOutputRange(static_cast<SCCOL>(aOutputAddress.Column), static_cast<SCROW>(aOutputAddress.Row), static_cast<SCTAB>(aOutputAddress.Sheet),
426
320
                        static_cast<SCCOL>(aOutputAddress.Column), static_cast<SCROW>(aOutputAddress.Row), static_cast<SCTAB>(aOutputAddress.Sheet));
427
320
    pNewObj->SetOutRange(aOutputRange);
428
320
    OUString aName = aNewName;
429
320
    if (aName.isEmpty())
430
0
        aName = lcl_CreatePivotName( pDocShell );
431
320
    pNewObj->SetName(aName);
432
320
    OUString aTag = xDescriptor->getTag();
433
320
    pNewObj->SetTag(aTag);
434
435
    // todo: handle double fields (for more information see ScDPObject)
436
437
320
    ScDBDocFunc aFunc(*pDocShell);
438
320
    if (!aFunc.CreatePivotTable(*pNewObj, true, true))
439
0
        throw RuntimeException(u"Failed to create pivot table"_ustr, getXWeak());
440
320
}
441
442
void SAL_CALL ScDataPilotTablesObj::removeByName( const OUString& aName )
443
0
{
444
0
    SolarMutexGuard aGuard;
445
0
    ScDPObject* pDPObj = lcl_GetDPObject( pDocShell, nTab, aName );
446
0
    if (!pDPObj || !pDocShell)
447
0
        throw RuntimeException();       // no other exceptions specified
448
449
0
    ScDBDocFunc aFunc(*pDocShell);
450
0
    aFunc.RemovePivotTable(*pDPObj, true, true);  // remove - incl. undo etc.
451
452
0
}
453
454
// XEnumerationAccess
455
456
Reference< XEnumeration > SAL_CALL ScDataPilotTablesObj::createEnumeration()
457
0
{
458
0
    SolarMutexGuard aGuard;
459
0
    return new ScIndexEnumeration(this, u"com.sun.star.sheet.DataPilotTablesEnumeration"_ustr);
460
0
}
461
462
// XIndexAccess
463
464
sal_Int32 SAL_CALL ScDataPilotTablesObj::getCount()
465
0
{
466
0
    SolarMutexGuard aGuard;
467
0
    if ( pDocShell )
468
0
    {
469
0
        ScDocument& rDoc = pDocShell->GetDocument();
470
0
        ScDPCollection* pColl = rDoc.GetDPCollection();
471
0
        if ( pColl )
472
0
        {
473
            //  count tables on this sheet
474
475
0
            sal_uInt16 nFound = 0;
476
0
            size_t nCount = pColl->GetCount();
477
0
            for (size_t i=0; i<nCount; ++i)
478
0
            {
479
0
                ScDPObject& rDPObj = (*pColl)[i];
480
0
                if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
481
0
                    ++nFound;
482
0
            }
483
0
            return nFound;
484
0
        }
485
0
    }
486
487
0
    return 0;
488
0
}
489
490
Any SAL_CALL ScDataPilotTablesObj::getByIndex( sal_Int32 nIndex )
491
0
{
492
0
    SolarMutexGuard aGuard;
493
0
    rtl::Reference<ScDataPilotTableObj> xTable(GetObjectByIndex_Impl(nIndex));
494
0
    if (!xTable.is())
495
0
        throw IndexOutOfBoundsException();
496
0
    return Any( Reference<XDataPilotTable2>(xTable) );
497
0
}
498
499
uno::Type SAL_CALL ScDataPilotTablesObj::getElementType()
500
0
{
501
0
    return cppu::UnoType<XDataPilotTable2>::get();
502
0
}
503
504
sal_Bool SAL_CALL ScDataPilotTablesObj::hasElements()
505
0
{
506
0
    SolarMutexGuard aGuard;
507
0
    return ( getCount() != 0 );
508
0
}
509
510
// XNameAccess
511
512
Any SAL_CALL ScDataPilotTablesObj::getByName( const OUString& aName )
513
0
{
514
0
    SolarMutexGuard aGuard;
515
0
    rtl::Reference<ScDataPilotTableObj> xTable(GetObjectByName_Impl(aName));
516
0
    if (!xTable.is())
517
0
        throw NoSuchElementException();
518
0
    return Any( Reference<XDataPilotTable2>(xTable) );
519
0
}
520
521
Sequence<OUString> SAL_CALL ScDataPilotTablesObj::getElementNames()
522
0
{
523
0
    SolarMutexGuard aGuard;
524
0
    if (pDocShell)
525
0
    {
526
0
        ScDocument& rDoc = pDocShell->GetDocument();
527
0
        ScDPCollection* pColl = rDoc.GetDPCollection();
528
0
        if ( pColl )
529
0
        {
530
            //  count tables on this sheet
531
532
0
            sal_uInt16 nFound = 0;
533
0
            size_t nCount = pColl->GetCount();
534
0
            size_t i;
535
0
            for (i=0; i<nCount; ++i)
536
0
            {
537
0
                ScDPObject& rDPObj = (*pColl)[i];
538
0
                if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
539
0
                    ++nFound;
540
0
            }
541
542
0
            sal_uInt16 nPos = 0;
543
0
            Sequence<OUString> aSeq(nFound);
544
0
            OUString* pAry = aSeq.getArray();
545
0
            for (i=0; i<nCount; ++i)
546
0
            {
547
0
                ScDPObject& rDPObj = (*pColl)[i];
548
0
                if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
549
0
                    pAry[nPos++] = rDPObj.GetName();
550
0
            }
551
552
0
            return aSeq;
553
0
        }
554
0
    }
555
0
    return {};
556
0
}
557
558
sal_Bool SAL_CALL ScDataPilotTablesObj::hasByName( const OUString& aName )
559
320
{
560
320
    SolarMutexGuard aGuard;
561
320
    if (pDocShell)
562
320
    {
563
320
        ScDocument& rDoc = pDocShell->GetDocument();
564
320
        ScDPCollection* pColl = rDoc.GetDPCollection();
565
320
        if ( pColl )
566
320
        {
567
320
            size_t nCount = pColl->GetCount();
568
425
            for (size_t i=0; i<nCount; ++i)
569
105
            {
570
105
                ScDPObject& rDPObj = (*pColl)[i];
571
105
                if ( rDPObj.GetOutRange().aStart.Tab() == nTab &&
572
54
                     rDPObj.GetName() == aName )
573
0
                    return true;
574
105
            }
575
320
        }
576
320
    }
577
320
    return false;
578
320
}
579
580
ScDataPilotDescriptorBase::ScDataPilotDescriptorBase(ScDocShell& rDocSh) :
581
320
    maPropSet( lcl_GetDataPilotDescriptorBaseMap() ),
582
320
    pDocShell( &rDocSh )
583
320
{
584
320
    pDocShell->GetDocument().AddUnoObject(*this);
585
320
}
586
587
ScDataPilotDescriptorBase::~ScDataPilotDescriptorBase()
588
320
{
589
320
    SolarMutexGuard g;
590
591
320
    if (pDocShell)
592
320
        pDocShell->GetDocument().RemoveUnoObject(*this);
593
320
}
594
595
void ScDataPilotDescriptorBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
596
1.91k
{
597
    //! update of references ?
598
599
1.91k
    if ( rHint.GetId() == SfxHintId::Dying )
600
0
    {
601
0
        pDocShell = nullptr;       // became invalid
602
0
    }
603
1.91k
}
604
605
// XDataPilotDescriptor
606
607
CellRangeAddress SAL_CALL ScDataPilotDescriptorBase::getSourceRange()
608
0
{
609
0
    SolarMutexGuard aGuard;
610
611
0
    ScDPObject* pDPObject(GetDPObject());
612
0
    if (!pDPObject)
613
0
        throw RuntimeException(u"Failed to get DPObject"_ustr, getXWeak());
614
615
0
    CellRangeAddress aRet;
616
0
    if (pDPObject->IsSheetData())
617
0
        ScUnoConversion::FillApiRange( aRet, pDPObject->GetSheetDesc()->GetSourceRange() );
618
0
    return aRet;
619
0
}
620
621
void SAL_CALL ScDataPilotDescriptorBase::setSourceRange( const CellRangeAddress& aSourceRange )
622
320
{
623
320
    SolarMutexGuard aGuard;
624
625
320
    ScDPObject* pDPObject = GetDPObject();
626
320
    if (!pDPObject)
627
0
        throw RuntimeException(u"Failed to get DPObject"_ustr, getXWeak());
628
629
320
    ScSheetSourceDesc aSheetDesc(&pDocShell->GetDocument());
630
320
    if (pDPObject->IsSheetData())
631
320
        aSheetDesc = *pDPObject->GetSheetDesc();
632
633
320
    ScRange aRange;
634
320
    ScUnoConversion::FillScRange(aRange, aSourceRange);
635
320
    aSheetDesc.SetSourceRange(aRange);
636
320
    pDPObject->SetSheetDesc( aSheetDesc );
637
320
    SetDPObject( pDPObject );
638
320
}
639
640
Reference<XSheetFilterDescriptor> SAL_CALL ScDataPilotDescriptorBase::getFilterDescriptor()
641
0
{
642
0
    SolarMutexGuard aGuard;
643
0
    return new ScDataPilotFilterDescriptor( pDocShell, this );
644
0
}
645
646
Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getDataPilotFields()
647
17
{
648
17
    SolarMutexGuard aGuard;
649
17
    return new ScDataPilotFieldsObj( *this );
650
17
}
651
652
rtl::Reference<ScDataPilotFieldsObj> ScDataPilotDescriptorBase::getScDataPilotFields()
653
3.21k
{
654
3.21k
    SolarMutexGuard aGuard;
655
3.21k
    return new ScDataPilotFieldsObj( *this );
656
3.21k
}
657
658
Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getColumnFields()
659
0
{
660
0
    SolarMutexGuard aGuard;
661
0
    return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_COLUMN );
662
0
}
663
664
Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getRowFields()
665
0
{
666
0
    SolarMutexGuard aGuard;
667
0
    return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_ROW );
668
0
}
669
670
Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getPageFields()
671
0
{
672
0
    SolarMutexGuard aGuard;
673
0
    return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_PAGE );
674
0
}
675
676
Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getDataFields()
677
0
{
678
0
    SolarMutexGuard aGuard;
679
0
    return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_DATA );
680
0
}
681
682
Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getHiddenFields()
683
0
{
684
0
    SolarMutexGuard aGuard;
685
0
    return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_HIDDEN );
686
0
}
687
688
// XPropertySet
689
Reference< XPropertySetInfo > SAL_CALL ScDataPilotDescriptorBase::getPropertySetInfo(  )
690
0
{
691
0
    SolarMutexGuard aGuard;
692
0
    static Reference<XPropertySetInfo> aRef =
693
0
        new SfxItemPropertySetInfo( maPropSet.getPropertyMap() );
694
0
    return aRef;
695
0
}
696
697
void SAL_CALL ScDataPilotDescriptorBase::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
698
0
{
699
0
    SolarMutexGuard aGuard;
700
0
    ScDPObject* pDPObject = GetDPObject();
701
0
    if (!pDPObject)
702
0
        return;
703
704
0
    ScDPSaveData* pOldData = pDPObject->GetSaveData();
705
0
    OSL_ENSURE(pOldData, "Here should be a SaveData");
706
0
    if ( pOldData )
707
0
    {
708
0
        ScDPSaveData aNewData( *pOldData );
709
710
0
        if ( aPropertyName == SC_UNO_DP_COLGRAND )
711
0
        {
712
0
            aNewData.SetColumnGrand(::cppu::any2bool( aValue ));
713
0
        }
714
0
        else if ( aPropertyName == SC_UNO_DP_IGNORE_EMPTYROWS )
715
0
        {
716
0
            aNewData.SetIgnoreEmptyRows(::cppu::any2bool( aValue ));
717
0
        }
718
0
        else if ( aPropertyName == SC_UNO_DP_REPEATEMPTY )
719
0
        {
720
0
            aNewData.SetRepeatIfEmpty(::cppu::any2bool( aValue ));
721
0
        }
722
0
        else if ( aPropertyName == SC_UNO_DP_ROWGRAND )
723
0
        {
724
0
            aNewData.SetRowGrand(::cppu::any2bool( aValue ));
725
0
        }
726
0
        else if ( aPropertyName == SC_UNO_DP_SHOWFILTER )
727
0
        {
728
0
            aNewData.SetFilterButton(::cppu::any2bool( aValue ));
729
0
        }
730
0
        else if ( aPropertyName == SC_UNO_DP_DRILLDOWN )
731
0
        {
732
0
            aNewData.SetDrillDown(::cppu::any2bool( aValue ));
733
0
        }
734
0
        else if ( aPropertyName == SC_UNO_DP_GRANDTOTAL_NAME )
735
0
        {
736
0
            OUString aStrVal;
737
0
            if ( aValue >>= aStrVal )
738
0
                aNewData.SetGrandTotalName(aStrVal);
739
0
        }
740
0
        else if ( aPropertyName == SC_UNO_DP_IMPORTDESC )
741
0
        {
742
0
            uno::Sequence<beans::PropertyValue> aArgSeq;
743
0
            if ( aValue >>= aArgSeq )
744
0
            {
745
0
                ScImportSourceDesc aImportDesc(&pDocShell->GetDocument());
746
747
0
                const ScImportSourceDesc* pOldDesc = pDPObject->GetImportSourceDesc();
748
0
                if (pOldDesc)
749
0
                    aImportDesc = *pOldDesc;
750
751
0
                ScImportParam aParam;
752
0
                ScImportDescriptor::FillImportParam( aParam, aArgSeq );
753
754
0
                sheet::DataImportMode nNewType = sheet::DataImportMode_NONE;
755
0
                if ( aParam.bImport )
756
0
                {
757
0
                    if ( aParam.bSql )
758
0
                        nNewType = sheet::DataImportMode_SQL;
759
0
                    else if ( aParam.nType == ScDbQuery )
760
0
                        nNewType = sheet::DataImportMode_QUERY;
761
0
                    else
762
0
                        nNewType = sheet::DataImportMode_TABLE;
763
0
                }
764
0
                aImportDesc.nType   = nNewType;
765
0
                aImportDesc.aDBName = aParam.aDBName;
766
0
                aImportDesc.aObject = aParam.aStatement;
767
0
                aImportDesc.bNative = aParam.bNative;
768
769
0
                pDPObject->SetImportDesc( aImportDesc );
770
0
            }
771
0
        }
772
0
        else if ( aPropertyName == SC_UNO_DP_SOURCESERVICE )
773
0
        {
774
0
            OUString aStrVal;
775
0
            if ( aValue >>= aStrVal )
776
0
            {
777
0
                ScDPServiceDesc aServiceDesc(u""_ustr, u""_ustr, u""_ustr, u""_ustr, u""_ustr);
778
779
0
                const ScDPServiceDesc* pOldDesc = pDPObject->GetDPServiceDesc();
780
0
                if (pOldDesc)
781
0
                    aServiceDesc = *pOldDesc;
782
783
0
                aServiceDesc.aServiceName = aStrVal;
784
785
0
                pDPObject->SetServiceData( aServiceDesc );
786
0
            }
787
0
        }
788
0
        else if ( aPropertyName == SC_UNO_DP_SERVICEARG )
789
0
        {
790
0
            uno::Sequence<beans::PropertyValue> aArgSeq;
791
0
            if ( aValue >>= aArgSeq )
792
0
            {
793
0
                ScDPServiceDesc aServiceDesc(u""_ustr, u""_ustr, u""_ustr, u""_ustr, u""_ustr);
794
795
0
                const ScDPServiceDesc* pOldDesc = pDPObject->GetDPServiceDesc();
796
0
                if (pOldDesc)
797
0
                    aServiceDesc = *pOldDesc;
798
799
0
                OUString aStrVal;
800
0
                for (const beans::PropertyValue& rProp : aArgSeq)
801
0
                {
802
0
                    OUString aPropName(rProp.Name);
803
804
0
                    if (aPropName == SC_UNO_DP_SOURCENAME)
805
0
                    {
806
0
                        if ( rProp.Value >>= aStrVal )
807
0
                            aServiceDesc.aParSource = aStrVal;
808
0
                    }
809
0
                    else if (aPropName == SC_UNO_DP_OBJECTNAME)
810
0
                    {
811
0
                        if ( rProp.Value >>= aStrVal )
812
0
                            aServiceDesc.aParName = aStrVal;
813
0
                    }
814
0
                    else if (aPropName == SC_UNO_DP_USERNAME)
815
0
                    {
816
0
                        if ( rProp.Value >>= aStrVal )
817
0
                            aServiceDesc.aParUser = aStrVal;
818
0
                    }
819
0
                    else if (aPropName == SC_UNO_DP_PASSWORD)
820
0
                    {
821
0
                        if ( rProp.Value >>= aStrVal )
822
0
                            aServiceDesc.aParPass = aStrVal;
823
0
                    }
824
0
                }
825
826
0
                pDPObject->SetServiceData( aServiceDesc );
827
0
            }
828
0
        }
829
0
        else
830
0
            throw UnknownPropertyException(aPropertyName);
831
832
0
        pDPObject->SetSaveData( aNewData );
833
0
    }
834
835
0
    SetDPObject(pDPObject);
836
0
}
837
838
Any SAL_CALL ScDataPilotDescriptorBase::getPropertyValue( const OUString& aPropertyName )
839
0
{
840
0
    SolarMutexGuard aGuard;
841
0
    Any aRet;
842
843
0
    ScDPObject* pDPObject(GetDPObject());
844
0
    if (pDPObject)
845
0
    {
846
0
        ScDPSaveData* pOldData = pDPObject->GetSaveData();
847
0
        OSL_ENSURE(pOldData, "Here should be a SaveData");
848
0
        if ( pOldData )
849
0
        {
850
0
            ScDPSaveData aNewData( *pOldData );
851
852
0
            if ( aPropertyName == SC_UNO_DP_COLGRAND )
853
0
            {
854
0
                aRet <<= aNewData.GetColumnGrand();
855
0
            }
856
0
            else if ( aPropertyName == SC_UNO_DP_IGNORE_EMPTYROWS )
857
0
            {
858
0
                aRet <<= aNewData.GetIgnoreEmptyRows();
859
0
            }
860
0
            else if ( aPropertyName == SC_UNO_DP_REPEATEMPTY )
861
0
            {
862
0
                aRet <<= aNewData.GetRepeatIfEmpty();
863
0
            }
864
0
            else if ( aPropertyName == SC_UNO_DP_ROWGRAND )
865
0
            {
866
0
                aRet <<= aNewData.GetRowGrand();
867
0
            }
868
0
            else if ( aPropertyName == SC_UNO_DP_SHOWFILTER )
869
0
            {
870
0
                aRet <<= aNewData.GetFilterButton();
871
0
            }
872
0
            else if ( aPropertyName == SC_UNO_DP_DRILLDOWN )
873
0
            {
874
0
                aRet <<= aNewData.GetDrillDown();
875
0
            }
876
0
            else if ( aPropertyName == SC_UNO_DP_GRANDTOTAL_NAME )
877
0
            {
878
0
                const std::optional<OUString> & pGrandTotalName = aNewData.GetGrandTotalName();
879
0
                if (pGrandTotalName)
880
0
                    aRet <<= *pGrandTotalName;      // same behavior as in ScDPSource
881
0
            }
882
0
            else if ( aPropertyName == SC_UNO_DP_IMPORTDESC )
883
0
            {
884
0
                const ScImportSourceDesc* pImportDesc = pDPObject->GetImportSourceDesc();
885
0
                if ( pImportDesc )
886
0
                {
887
                    // fill ScImportParam so ScImportDescriptor::FillProperties can be used
888
0
                    ScImportParam aParam;
889
0
                    aParam.bImport    = ( pImportDesc->nType != sheet::DataImportMode_NONE );
890
0
                    aParam.aDBName    = pImportDesc->aDBName;
891
0
                    aParam.aStatement = pImportDesc->aObject;
892
0
                    aParam.bNative    = pImportDesc->bNative;
893
0
                    aParam.bSql       = ( pImportDesc->nType == sheet::DataImportMode_SQL );
894
0
                    aParam.nType      = static_cast<sal_uInt8>(( pImportDesc->nType == sheet::DataImportMode_QUERY ) ? ScDbQuery : ScDbTable);
895
896
0
                    uno::Sequence<beans::PropertyValue> aSeq( ScImportDescriptor::GetPropertyCount() );
897
0
                    ScImportDescriptor::FillProperties( aSeq, aParam );
898
0
                    aRet <<= aSeq;
899
0
                }
900
0
                else
901
0
                {
902
                    // empty sequence
903
0
                    uno::Sequence<beans::PropertyValue> aEmpty(0);
904
0
                    aRet <<= aEmpty;
905
0
                }
906
0
            }
907
0
            else if ( aPropertyName == SC_UNO_DP_SOURCESERVICE )
908
0
            {
909
0
                OUString aServiceName;
910
0
                const ScDPServiceDesc* pServiceDesc = pDPObject->GetDPServiceDesc();
911
0
                if (pServiceDesc)
912
0
                    aServiceName = pServiceDesc->aServiceName;
913
0
                aRet <<= aServiceName;      // empty string if no ServiceDesc set
914
0
            }
915
0
            else if ( aPropertyName == SC_UNO_DP_SERVICEARG )
916
0
            {
917
0
                const ScDPServiceDesc* pServiceDesc = pDPObject->GetDPServiceDesc();
918
0
                if (pServiceDesc)
919
0
                {
920
0
                    uno::Sequence<beans::PropertyValue> aSeq( comphelper::InitPropertySequence({
921
0
                            { SC_UNO_DP_SOURCENAME, Any(pServiceDesc->aParSource) },
922
0
                            { SC_UNO_DP_OBJECTNAME, Any(pServiceDesc->aParName) },
923
0
                            { SC_UNO_DP_USERNAME, Any(pServiceDesc->aParUser) },
924
0
                            { SC_UNO_DP_PASSWORD, Any(pServiceDesc->aParPass) }
925
0
                        }));
926
0
                    aRet <<= aSeq;
927
0
                }
928
0
                else
929
0
                {
930
                    // empty sequence
931
0
                    uno::Sequence<beans::PropertyValue> aEmpty;
932
0
                    aRet <<= aEmpty;
933
0
                }
934
0
            }
935
0
            else
936
0
                throw UnknownPropertyException(aPropertyName);
937
0
        }
938
0
    }
939
940
0
    return aRet;
941
0
}
942
943
void SAL_CALL ScDataPilotDescriptorBase::addPropertyChangeListener(
944
        const OUString& /* aPropertyName */, const Reference<XPropertyChangeListener >& /* xListener */ )
945
0
{
946
0
}
947
948
void SAL_CALL ScDataPilotDescriptorBase::removePropertyChangeListener(
949
        const OUString& /* aPropertyName */, const Reference<XPropertyChangeListener >& /* aListener */ )
950
0
{
951
0
}
952
953
void SAL_CALL ScDataPilotDescriptorBase::addVetoableChangeListener(
954
        const OUString& /* PropertyName */, const Reference<XVetoableChangeListener >& /* aListener */ )
955
0
{
956
0
}
957
958
void SAL_CALL ScDataPilotDescriptorBase::removeVetoableChangeListener(
959
        const OUString& /* PropertyName */, const Reference<XVetoableChangeListener >& /* aListener */ )
960
0
{
961
0
}
962
963
// XDataPilotDataLayoutFieldSupplier
964
965
Reference< XDataPilotField > SAL_CALL ScDataPilotDescriptorBase::getDataLayoutField()
966
0
{
967
0
    return getScDataLayoutField();
968
0
}
969
970
rtl::Reference< ScDataPilotFieldObj > ScDataPilotDescriptorBase::getScDataLayoutField()
971
31
{
972
31
    SolarMutexGuard aGuard;
973
31
    if( ScDPObject* pDPObject = GetDPObject() )
974
31
    {
975
31
        if( ScDPSaveData* pSaveData = pDPObject->GetSaveData() )
976
31
        {
977
31
            if( pSaveData->GetDataLayoutDimension() )
978
31
            {
979
31
                ScFieldIdentifier aFieldId( SC_DATALAYOUT_NAME, true );
980
31
                return new ScDataPilotFieldObj( *this, aFieldId );
981
31
            }
982
31
        }
983
31
    }
984
0
    return nullptr;
985
31
}
986
987
ScDataPilotTableObj::ScDataPilotTableObj(ScDocShell& rDocSh, SCTAB nT, OUString aN) :
988
0
    ScDataPilotDescriptorBase( rDocSh ),
989
0
    nTab( nT ),
990
0
    aName(std::move( aN )),
991
0
    aModifyListeners( 0 )
992
0
{
993
0
}
994
995
ScDataPilotTableObj::~ScDataPilotTableObj()
996
0
{
997
0
}
998
999
Any SAL_CALL ScDataPilotTableObj::queryInterface( const uno::Type& rType )
1000
0
{
1001
    // since we manually do resolve the query for XDataPilotTable2
1002
    // we also need to do the same for XDataPilotTable
1003
0
    uno::Any aReturn = ::cppu::queryInterface(rType,
1004
0
                    static_cast<XDataPilotTable*>(this),
1005
0
                    static_cast<XDataPilotTable2*>(this),
1006
0
                    static_cast<XModifyBroadcaster*>(this));
1007
0
    if ( aReturn.hasValue() )
1008
0
        return aReturn;
1009
1010
0
    return ScDataPilotDescriptorBase::queryInterface( rType );
1011
0
}
1012
1013
void SAL_CALL ScDataPilotTableObj::acquire() noexcept
1014
0
{
1015
0
    ScDataPilotDescriptorBase::acquire();
1016
0
}
1017
1018
void SAL_CALL ScDataPilotTableObj::release() noexcept
1019
0
{
1020
0
    ScDataPilotDescriptorBase::release();
1021
0
}
1022
1023
Sequence< uno::Type > SAL_CALL ScDataPilotTableObj::getTypes()
1024
0
{
1025
0
    return comphelper::concatSequences(
1026
0
        ScDataPilotDescriptorBase::getTypes(),
1027
0
        Sequence< uno::Type >
1028
0
        {
1029
0
            cppu::UnoType<XDataPilotTable2>::get(),
1030
0
            cppu::UnoType<XModifyBroadcaster>::get()
1031
0
        } );
1032
0
}
1033
1034
Sequence<sal_Int8> SAL_CALL ScDataPilotTableObj::getImplementationId()
1035
0
{
1036
0
    return css::uno::Sequence<sal_Int8>();
1037
0
}
1038
1039
ScDPObject* ScDataPilotTableObj::GetDPObject() const
1040
0
{
1041
0
    return lcl_GetDPObject(GetDocShell(), nTab, aName);
1042
0
}
1043
1044
void ScDataPilotTableObj::SetDPObject( ScDPObject* pDPObject )
1045
0
{
1046
0
    ScDocShell* pDocSh = GetDocShell();
1047
0
    ScDPObject* pDPObj = lcl_GetDPObject(pDocSh, nTab, aName);
1048
0
    if ( pDPObj && pDocSh )
1049
0
    {
1050
0
        ScDBDocFunc aFunc(*pDocSh);
1051
0
        aFunc.DataPilotUpdate( pDPObj, pDPObject, true, true );
1052
0
    }
1053
0
}
1054
1055
// "rest of XDataPilotDescriptor"
1056
1057
OUString SAL_CALL ScDataPilotTableObj::getName()
1058
0
{
1059
0
    SolarMutexGuard aGuard;
1060
0
    ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
1061
0
    if (pDPObj)
1062
0
        return pDPObj->GetName();
1063
0
    return OUString();
1064
0
}
1065
1066
void SAL_CALL ScDataPilotTableObj::setName( const OUString& aNewName )
1067
0
{
1068
0
    SolarMutexGuard aGuard;
1069
0
    ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
1070
0
    if (pDPObj)
1071
0
    {
1072
        //! test for existing names !!!
1073
1074
0
        pDPObj->SetName( aNewName );     //! Undo - DBDocFunc ???
1075
0
        aName = aNewName;
1076
1077
        //  DataPilotUpdate would do too much (output table is not changed)
1078
0
        GetDocShell()->SetDocumentModified();
1079
0
    }
1080
0
}
1081
1082
OUString SAL_CALL ScDataPilotTableObj::getTag()
1083
0
{
1084
0
    SolarMutexGuard aGuard;
1085
0
    ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
1086
0
    if (pDPObj)
1087
0
        return pDPObj->GetTag();
1088
0
    return OUString();
1089
0
}
1090
1091
void SAL_CALL ScDataPilotTableObj::setTag( const OUString& aNewTag )
1092
0
{
1093
0
    SolarMutexGuard aGuard;
1094
0
    ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
1095
0
    if (pDPObj)
1096
0
    {
1097
0
        pDPObj->SetTag( aNewTag );      //! Undo - DBDocFunc ???
1098
1099
        //  DataPilotUpdate would do too much (output table is not changed)
1100
0
        GetDocShell()->SetDocumentModified();
1101
0
    }
1102
0
}
1103
1104
// XDataPilotTable
1105
1106
CellRangeAddress SAL_CALL ScDataPilotTableObj::getOutputRange()
1107
0
{
1108
0
    SolarMutexGuard aGuard;
1109
0
    CellRangeAddress aRet;
1110
0
    ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
1111
0
    if (pDPObj)
1112
0
    {
1113
0
        ScRange aRange(pDPObj->GetOutRange());
1114
0
        aRet.Sheet       = aRange.aStart.Tab();
1115
0
        aRet.StartColumn = aRange.aStart.Col();
1116
0
        aRet.StartRow    = aRange.aStart.Row();
1117
0
        aRet.EndColumn   = aRange.aEnd.Col();
1118
0
        aRet.EndRow      = aRange.aEnd.Row();
1119
0
    }
1120
0
    return aRet;
1121
0
}
1122
1123
void SAL_CALL ScDataPilotTableObj::refresh()
1124
0
{
1125
0
    SolarMutexGuard aGuard;
1126
0
    ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
1127
0
    if (pDPObj)
1128
0
    {
1129
0
        ScDBDocFunc aFunc(*GetDocShell());
1130
0
        aFunc.RefreshPivotTables(pDPObj, true);
1131
0
    }
1132
0
}
1133
1134
Sequence< Sequence<Any> > SAL_CALL ScDataPilotTableObj::getDrillDownData(const CellAddress& aAddr)
1135
0
{
1136
0
    SolarMutexGuard aGuard;
1137
0
    Sequence< Sequence<Any> > aTabData;
1138
0
    ScAddress aAddr2(static_cast<SCCOL>(aAddr.Column), static_cast<SCROW>(aAddr.Row), aAddr.Sheet);
1139
0
    ScDPObject* pObj = GetDPObject();
1140
0
    if (!pObj)
1141
0
        throw RuntimeException(u"Failed to get DPObject"_ustr, getXWeak());
1142
1143
0
    pObj->GetDrillDownData(aAddr2, aTabData);
1144
0
    return aTabData;
1145
0
}
1146
1147
DataPilotTablePositionData SAL_CALL ScDataPilotTableObj::getPositionData(const CellAddress& aAddr)
1148
0
{
1149
0
    SolarMutexGuard aGuard;
1150
0
    DataPilotTablePositionData aPosData;
1151
0
    ScAddress aAddr2(static_cast<SCCOL>(aAddr.Column), static_cast<SCROW>(aAddr.Row), aAddr.Sheet);
1152
0
    ScDPObject* pObj = GetDPObject();
1153
0
    if (!pObj)
1154
0
        throw RuntimeException(u"Failed to get DPObject"_ustr, getXWeak());
1155
1156
0
    pObj->GetPositionData(aAddr2, aPosData);
1157
0
    return aPosData;
1158
0
}
1159
1160
void SAL_CALL ScDataPilotTableObj::insertDrillDownSheet(const CellAddress& aAddr)
1161
0
{
1162
0
    SolarMutexGuard aGuard;
1163
0
    ScDPObject* pDPObj = GetDPObject();
1164
0
    if (!pDPObj)
1165
0
        throw RuntimeException(u"Failed to get DPObject"_ustr, getXWeak());
1166
0
    ScTabViewShell* pViewSh = GetDocShell()->GetBestViewShell();
1167
0
    if (!pViewSh)
1168
0
        throw RuntimeException(u"Failed to get ViewShell"_ustr, getXWeak());
1169
1170
0
    Sequence<DataPilotFieldFilter> aFilters;
1171
0
    pDPObj->GetDataFieldPositionData(
1172
0
        ScAddress(static_cast<SCCOL>(aAddr.Column), static_cast<SCROW>(aAddr.Row), aAddr.Sheet), aFilters);
1173
0
    pViewSh->ShowDataPilotSourceData(*pDPObj, aFilters);
1174
0
}
1175
1176
CellRangeAddress SAL_CALL ScDataPilotTableObj::getOutputRangeByType( sal_Int32 nType )
1177
0
{
1178
0
    SolarMutexGuard aGuard;
1179
0
    if (nType < 0 || nType > DataPilotOutputRangeType::RESULT)
1180
0
        throw IllegalArgumentException("nType must be between 0 and " +
1181
0
                OUString::number(DataPilotOutputRangeType::RESULT) + ", got " + OUString::number(nType),
1182
0
                getXWeak(), 0);
1183
1184
0
    CellRangeAddress aRet;
1185
0
    if (ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName))
1186
0
        ScUnoConversion::FillApiRange( aRet, pDPObj->GetOutputRangeByType( nType ) );
1187
0
    return aRet;
1188
0
}
1189
1190
void SAL_CALL ScDataPilotTableObj::addModifyListener( const uno::Reference<util::XModifyListener>& aListener )
1191
0
{
1192
0
    SolarMutexGuard aGuard;
1193
1194
0
    aModifyListeners.emplace_back( aListener );
1195
1196
0
    if ( aModifyListeners.size() == 1 )
1197
0
    {
1198
0
        acquire();  // don't lose this object (one ref for all listeners)
1199
0
    }
1200
0
}
1201
1202
void SAL_CALL ScDataPilotTableObj::removeModifyListener( const uno::Reference<util::XModifyListener>& aListener )
1203
0
{
1204
0
    SolarMutexGuard aGuard;
1205
1206
0
    rtl::Reference<ScDataPilotTableObj> xSelfHold(this); // in case the listeners have the last ref
1207
1208
0
    sal_uInt16 nCount = aModifyListeners.size();
1209
0
    for ( sal_uInt16 n=nCount; n--; )
1210
0
    {
1211
0
        uno::Reference<util::XModifyListener>& rObj = aModifyListeners[n];
1212
0
        if ( rObj == aListener )
1213
0
        {
1214
0
            aModifyListeners.erase( aModifyListeners.begin() + n );
1215
1216
0
            if ( aModifyListeners.empty() )
1217
0
            {
1218
0
                release();      // release the ref for the listeners
1219
0
            }
1220
1221
0
            break;
1222
0
        }
1223
0
    }
1224
0
}
1225
1226
void ScDataPilotTableObj::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
1227
0
{
1228
0
    if ( rHint.GetId() == SfxHintId::ScDataPilotModified )
1229
0
    {
1230
0
        auto pDataPilotHint = static_cast<const ScDataPilotModifiedHint*>(&rHint);
1231
0
        if (pDataPilotHint->GetName() == aName)
1232
0
            Refreshed_Impl();
1233
0
    }
1234
0
    else if ( rHint.GetId() == SfxHintId::ScUpdateRef )
1235
0
    {
1236
0
        auto pRefHint = static_cast<const ScUpdateRefHint*>(&rHint);
1237
0
        ScRange aRange( 0, 0, nTab );
1238
0
        ScRangeList aRanges( aRange );
1239
0
        if ( aRanges.UpdateReference( pRefHint->GetMode(), GetDocShell()->GetDocument(), pRefHint->GetRange(),
1240
0
                 pRefHint->GetDx(), pRefHint->GetDy(), pRefHint->GetDz() ) &&
1241
0
             aRanges.size() == 1 )
1242
0
        {
1243
0
            nTab = aRanges.front().aStart.Tab();
1244
0
        }
1245
0
    }
1246
1247
0
    ScDataPilotDescriptorBase::Notify( rBC, rHint );
1248
0
}
1249
1250
void ScDataPilotTableObj::Refreshed_Impl()
1251
0
{
1252
0
    lang::EventObject aEvent;
1253
0
    aEvent.Source = getXWeak();
1254
1255
    // the EventObject holds a Ref to this object until after the listener calls
1256
1257
0
    ScDocument& rDoc = GetDocShell()->GetDocument();
1258
0
    for (const uno::Reference<util::XModifyListener> & xModifyListener : aModifyListeners)
1259
0
        rDoc.AddUnoListenerCall( xModifyListener, aEvent );
1260
0
}
1261
1262
ScDataPilotDescriptor::ScDataPilotDescriptor(ScDocShell& rDocSh) :
1263
320
    ScDataPilotDescriptorBase( rDocSh ),
1264
320
    mpDPObject(new ScDPObject(&rDocSh.GetDocument()))
1265
320
{
1266
320
    ScDPSaveData aSaveData;
1267
    // set defaults like in ScPivotParam constructor
1268
320
    aSaveData.SetColumnGrand( true );
1269
320
    aSaveData.SetRowGrand( true );
1270
320
    aSaveData.SetIgnoreEmptyRows( false );
1271
320
    aSaveData.SetRepeatIfEmpty( false );
1272
320
    mpDPObject->SetSaveData(aSaveData);
1273
320
    ScSheetSourceDesc aSheetDesc(&rDocSh.GetDocument());
1274
320
    mpDPObject->SetSheetDesc(aSheetDesc);
1275
320
}
1276
1277
ScDataPilotDescriptor::~ScDataPilotDescriptor()
1278
320
{
1279
320
}
1280
1281
ScDPObject* ScDataPilotDescriptor::GetDPObject() const
1282
8.69k
{
1283
8.69k
    return mpDPObject.get();
1284
8.69k
}
1285
1286
void ScDataPilotDescriptor::SetDPObject( ScDPObject* pDPObject )
1287
4.68k
{
1288
4.68k
    if (mpDPObject.get() != pDPObject)
1289
0
    {
1290
0
        mpDPObject.reset( pDPObject );
1291
0
        OSL_FAIL("replace DPObject should not happen");
1292
0
    }
1293
4.68k
}
1294
1295
// "rest of XDataPilotDescriptor"
1296
1297
OUString SAL_CALL ScDataPilotDescriptor::getName()
1298
0
{
1299
0
    SolarMutexGuard aGuard;
1300
0
    return mpDPObject->GetName();
1301
0
}
1302
1303
void SAL_CALL ScDataPilotDescriptor::setName( const OUString& aNewName )
1304
0
{
1305
0
    SolarMutexGuard aGuard;
1306
0
    mpDPObject->SetName( aNewName );
1307
0
}
1308
1309
OUString SAL_CALL ScDataPilotDescriptor::getTag()
1310
320
{
1311
320
    SolarMutexGuard aGuard;
1312
320
    return mpDPObject->GetTag();
1313
320
}
1314
1315
void SAL_CALL ScDataPilotDescriptor::setTag( const OUString& aNewTag )
1316
320
{
1317
320
    SolarMutexGuard aGuard;
1318
320
    mpDPObject->SetTag( aNewTag );
1319
320
}
1320
1321
ScDataPilotChildObjBase::ScDataPilotChildObjBase( ScDataPilotDescriptorBase& rParent ) :
1322
3.23k
    mxParent( &rParent )
1323
3.23k
{
1324
3.23k
}
1325
1326
ScDataPilotChildObjBase::ScDataPilotChildObjBase( ScDataPilotDescriptorBase& rParent, ScFieldIdentifier aFieldId ) :
1327
2.56k
    mxParent( &rParent ),
1328
2.56k
    maFieldId(std::move( aFieldId ))
1329
2.56k
{
1330
2.56k
}
1331
1332
ScDataPilotChildObjBase::~ScDataPilotChildObjBase()
1333
5.79k
{
1334
5.79k
}
1335
1336
ScDPObject* ScDataPilotChildObjBase::GetDPObject() const
1337
7.69k
{
1338
7.69k
    return mxParent->GetDPObject();
1339
7.69k
}
1340
1341
void ScDataPilotChildObjBase::SetDPObject( ScDPObject* pDPObject )
1342
4.36k
{
1343
4.36k
    mxParent->SetDPObject( pDPObject );
1344
4.36k
}
1345
1346
ScDPSaveDimension* ScDataPilotChildObjBase::GetDPDimension( ScDPObject** ppDPObject ) const
1347
4.43k
{
1348
4.43k
    if( ScDPObject* pDPObj = GetDPObject() )
1349
4.43k
    {
1350
4.43k
        if( ppDPObject ) *ppDPObject = pDPObj;
1351
4.43k
        if( ScDPSaveData* pSaveData = pDPObj->GetSaveData() )
1352
4.43k
        {
1353
4.43k
            if( maFieldId.mbDataLayout )
1354
31
                return pSaveData->GetDataLayoutDimension();
1355
1356
4.40k
            if( maFieldId.mnFieldIdx == 0 )
1357
4.36k
                return pSaveData->GetDimensionByName( maFieldId.maFieldName );
1358
1359
            // find dimension with specified index (search in duplicated dimensions)
1360
42
            const ScDPSaveData::DimsType& rDims = pSaveData->GetDimensions();
1361
1362
42
            sal_Int32 nFoundIdx = 0;
1363
42
            for (auto const& it : rDims)
1364
296
            {
1365
296
                if (it->IsDataLayout())
1366
38
                    continue;
1367
1368
258
                OUString aSrcName = ScDPUtil::getSourceDimensionName(it->GetName());
1369
258
                if (aSrcName == maFieldId.maFieldName)
1370
102
                {
1371
102
                    if( nFoundIdx == maFieldId.mnFieldIdx )
1372
42
                        return it.get();
1373
60
                    ++nFoundIdx;
1374
60
                }
1375
258
            }
1376
42
        }
1377
4.43k
    }
1378
0
    return nullptr;
1379
4.43k
}
1380
1381
sal_Int32 ScDataPilotChildObjBase::GetMemberCount() const
1382
0
{
1383
0
    sal_Int32 nRet = 0;
1384
0
    Reference<XNameAccess> xMembersNA = GetMembers();
1385
0
    if (xMembersNA.is())
1386
0
    {
1387
0
        Reference< XIndexAccess > xMembersIA( new ScNameToIndexAccess( xMembersNA ) );
1388
0
        nRet = xMembersIA->getCount();
1389
0
    }
1390
0
    return nRet;
1391
0
}
1392
1393
Reference< XMembersAccess > ScDataPilotChildObjBase::GetMembers() const
1394
26
{
1395
26
    Reference< XMembersAccess > xMembersNA;
1396
26
    if( ScDPObject* pDPObj = GetDPObject() )
1397
26
        pDPObj->GetMembersNA( lcl_GetObjectIndex( pDPObj, maFieldId ), xMembersNA );
1398
26
    return xMembersNA;
1399
26
}
1400
1401
ScDocShell* ScDataPilotChildObjBase::GetDocShell() const
1402
17
{
1403
17
    return mxParent->GetDocShell();
1404
17
}
1405
1406
ScDataPilotFieldsObj::ScDataPilotFieldsObj( ScDataPilotDescriptorBase& rParent ) :
1407
3.23k
    ScDataPilotChildObjBase( rParent )
1408
3.23k
{
1409
3.23k
}
1410
1411
ScDataPilotFieldsObj::ScDataPilotFieldsObj( ScDataPilotDescriptorBase& rParent, DataPilotFieldOrientation eOrient ) :
1412
0
    ScDataPilotChildObjBase( rParent ),
1413
0
    maOrient( eOrient )
1414
0
{
1415
0
}
1416
1417
ScDataPilotFieldsObj::~ScDataPilotFieldsObj()
1418
3.23k
{
1419
3.23k
}
1420
1421
static sal_Int32 lcl_GetFieldCount( const Reference<XDimensionsSupplier>& rSource, const Any& rOrient )
1422
0
{
1423
0
    if (!rSource.is())
1424
0
        throw NullPointerException();
1425
1426
0
    sal_Int32 nRet = 0;
1427
1428
0
    Reference<XNameAccess> xDimsName(rSource->getDimensions());
1429
0
    Reference<XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
1430
0
    sal_Int32 nIntCount = xIntDims->getCount();
1431
0
    for (sal_Int32 i = 0; i < nIntCount; ++i)
1432
0
    {
1433
0
        Reference<XPropertySet> xDim(xIntDims->getByIndex(i), UNO_QUERY);
1434
0
        const bool bMatch = xDim
1435
0
                            && (rOrient.hasValue()
1436
                                    // all fields of the specified orientation, including duplicated
1437
0
                                    ? (xDim->getPropertyValue(SC_UNO_DP_ORIENTATION) == rOrient)
1438
                                    // count all non-duplicated fields
1439
0
                                    : !lcl_IsDuplicated(xDim));
1440
0
        if (bMatch)
1441
0
            ++nRet;
1442
0
    }
1443
1444
0
    return nRet;
1445
0
}
1446
1447
static bool lcl_GetFieldDataByIndex( const Reference<XDimensionsSupplier>& rSource,
1448
                                const Any& rOrient, SCSIZE nIndex, ScFieldIdentifier& rFieldId )
1449
1.46k
{
1450
1.46k
    if (!rSource.is())
1451
0
        throw NullPointerException();
1452
1453
1.46k
    bool bOk = false;
1454
1.46k
    SCSIZE nPos = 0;
1455
1.46k
    sal_Int32 nDimIndex = 0;
1456
1457
1.46k
    Reference<XNameAccess> xDimsName(rSource->getDimensions());
1458
1.46k
    Reference<XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
1459
1.46k
    sal_Int32 nIntCount = xIntDims->getCount();
1460
1.46k
    Reference<XPropertySet> xDim;
1461
4.88k
    for (sal_Int32 i = 0; i < nIntCount; ++i)
1462
4.88k
    {
1463
4.88k
        xDim.set(xIntDims->getByIndex(i), UNO_QUERY);
1464
4.88k
        const bool bMatch = xDim
1465
4.88k
                            && (rOrient.hasValue()
1466
4.88k
                                    ? (xDim->getPropertyValue(SC_UNO_DP_ORIENTATION) == rOrient)
1467
4.88k
                                    : !lcl_IsDuplicated(xDim));
1468
4.88k
        if (bMatch)
1469
4.88k
        {
1470
4.88k
            if (nPos == nIndex)
1471
1.46k
            {
1472
1.46k
                bOk = true;
1473
1.46k
                nDimIndex = i;
1474
1.46k
                break;
1475
1.46k
            }
1476
3.42k
            else
1477
3.42k
                ++nPos;
1478
4.88k
        }
1479
4.88k
    }
1480
1481
1.46k
    if ( bOk )
1482
1.46k
    {
1483
1.46k
        xDim.set( xIntDims->getByIndex(nDimIndex), UNO_QUERY );
1484
1.46k
        Reference<XNamed> xDimName( xDim, UNO_QUERY );
1485
1.46k
        if ( xDimName.is() )
1486
1.46k
        {
1487
1.46k
            OUString sOriginalName( lcl_GetOriginalName( xDimName ) );
1488
1.46k
            rFieldId.maFieldName = sOriginalName;
1489
1.46k
            rFieldId.mbDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDim,
1490
1.46k
                        SC_UNO_DP_ISDATALAYOUT );
1491
1492
1.46k
            sal_Int32 nRepeat = 0;
1493
1.46k
            if ( rOrient.hasValue() && lcl_IsDuplicated( xDim ) )
1494
0
            {
1495
                // find the repeat count
1496
                // (this relies on the original dimension always being before the duplicates)
1497
1498
0
                Reference<XNamed> xPrevName;
1499
0
                for (sal_Int32 i = 0; i < nDimIndex; ++i)
1500
0
                {
1501
0
                    xPrevName.set( xIntDims->getByIndex(i), UNO_QUERY );
1502
0
                    if ( xPrevName.is() && lcl_GetOriginalName( xPrevName ) == sOriginalName )
1503
0
                        ++nRepeat;
1504
0
                }
1505
0
            }
1506
1.46k
            rFieldId.mnFieldIdx = nRepeat;
1507
1.46k
        }
1508
0
        else
1509
0
            bOk = false;
1510
1.46k
    }
1511
1512
1.46k
    return bOk;
1513
1.46k
}
1514
1515
static bool lcl_GetFieldDataByName( ScDPObject* pDPObj, const OUString& rFieldName, ScFieldIdentifier& rFieldId )
1516
1.76k
{
1517
    // "By name" is always the first match.
1518
    // The name "Data" always refers to the data layout field.
1519
1.76k
    rFieldId.maFieldName = rFieldName;
1520
1.76k
    rFieldId.mnFieldIdx = 0;
1521
1.76k
    rFieldId.mbDataLayout = rFieldName == SC_DATALAYOUT_NAME;
1522
1523
    // check if the named field exists (not for data layout)
1524
1.76k
    return rFieldId.mbDataLayout || pDPObj->IsDimNameInUse( rFieldName );
1525
1.76k
}
1526
1527
// XDataPilotFields
1528
1529
rtl::Reference<ScDataPilotFieldObj>
1530
ScDataPilotFieldsObj::GetObjectByIndex_Impl(sal_Int32 nIndex, bool bCalculated,
1531
                                            const OUString& rFieldName,
1532
                                            const std::shared_ptr<ScTokenArray>& pArray) const
1533
1.46k
{
1534
1.46k
    if (ScDPObject* pObj = GetDPObject())
1535
1.46k
    {
1536
        // Register the calculated field dimension in the cache
1537
        // so that lcl_GetFieldDataByIndex can find it.
1538
1.46k
        if (bCalculated)
1539
0
            pObj->InsertCalculatedFieldToCache(nIndex, rFieldName, pArray);
1540
1541
1.46k
        ScFieldIdentifier aFieldId;
1542
1.46k
        if (lcl_GetFieldDataByIndex( pObj->GetSource(), maOrient, nIndex, aFieldId ))
1543
1.46k
            return new ScDataPilotFieldObj( *mxParent, aFieldId, maOrient );
1544
1.46k
    }
1545
2
    return nullptr;
1546
1.46k
}
1547
1548
rtl::Reference<ScDataPilotFieldObj> ScDataPilotFieldsObj::GetObjectByName_Impl(const OUString& aName) const
1549
1.76k
{
1550
1.76k
    if (ScDPObject* pDPObj = GetDPObject())
1551
1.76k
    {
1552
1.76k
        ScFieldIdentifier aFieldId;
1553
1.76k
        if (lcl_GetFieldDataByName( pDPObj, aName, aFieldId ))
1554
1.06k
            return new ScDataPilotFieldObj( *mxParent, aFieldId, maOrient );
1555
1.76k
    }
1556
704
    return nullptr;
1557
1.76k
}
1558
1559
// XEnumerationAccess
1560
1561
Reference<XEnumeration> SAL_CALL ScDataPilotFieldsObj::createEnumeration()
1562
0
{
1563
0
    SolarMutexGuard aGuard;
1564
0
    return new ScIndexEnumeration(this, u"com.sun.star.sheet.DataPilotFieldsEnumeration"_ustr);
1565
0
}
1566
1567
// XIndexAccess
1568
1569
sal_Int32 SAL_CALL ScDataPilotFieldsObj::getCount()
1570
0
{
1571
0
    SolarMutexGuard aGuard;
1572
0
    ScDPObject* pDPObj = GetDPObject();
1573
0
    return pDPObj ? lcl_GetFieldCount( pDPObj->GetSource(), maOrient ) : 0;
1574
0
}
1575
1576
Any SAL_CALL ScDataPilotFieldsObj::getByIndex( sal_Int32 nIndex )
1577
0
{
1578
0
    SolarMutexGuard aGuard;
1579
0
    rtl::Reference< ScDataPilotFieldObj > xField( GetObjectByIndex_Impl( nIndex ) );
1580
0
    if (!xField.is())
1581
0
        throw IndexOutOfBoundsException();
1582
0
    return Any( Reference< XPropertySet >(xField) );
1583
0
}
1584
1585
rtl::Reference<ScDataPilotFieldObj> ScDataPilotFieldsObj::getScDataPilotFieldObjByIndex(
1586
    sal_Int32 nIndex, bool bCalculated, const OUString& rFieldName,
1587
    const std::shared_ptr<ScTokenArray>& pArray)
1588
1.46k
{
1589
1.46k
    SolarMutexGuard aGuard;
1590
1.46k
    rtl::Reference< ScDataPilotFieldObj > xField( GetObjectByIndex_Impl( nIndex, bCalculated, rFieldName, pArray ) );
1591
1.46k
    if (!xField.is())
1592
2
        throw IndexOutOfBoundsException();
1593
1.46k
    return xField;
1594
1.46k
}
1595
1596
// XElementAccess
1597
1598
uno::Type SAL_CALL ScDataPilotFieldsObj::getElementType()
1599
0
{
1600
0
    return cppu::UnoType<XPropertySet>::get();
1601
0
}
1602
1603
sal_Bool SAL_CALL ScDataPilotFieldsObj::hasElements()
1604
0
{
1605
0
    SolarMutexGuard aGuard;
1606
0
    return ( getCount() != 0 );
1607
0
}
1608
1609
// XNameAccess
1610
1611
Any SAL_CALL ScDataPilotFieldsObj::getByName( const OUString& aName )
1612
17
{
1613
17
    SolarMutexGuard aGuard;
1614
17
    rtl::Reference<ScDataPilotFieldObj> xField(GetObjectByName_Impl(aName));
1615
17
    if (!xField.is())
1616
0
        throw NoSuchElementException();
1617
17
    return Any( Reference<XPropertySet>(xField) );
1618
17
}
1619
1620
rtl::Reference<ScDataPilotFieldObj> ScDataPilotFieldsObj::getScDataPilotFieldObjByName( const OUString& aName )
1621
1.75k
{
1622
1.75k
    SolarMutexGuard aGuard;
1623
1.75k
    rtl::Reference<ScDataPilotFieldObj> xField(GetObjectByName_Impl(aName));
1624
1.75k
    if (!xField.is())
1625
704
        throw NoSuchElementException();
1626
1.04k
    return xField;
1627
1.75k
}
1628
1629
Sequence<OUString> SAL_CALL ScDataPilotFieldsObj::getElementNames()
1630
0
{
1631
0
    SolarMutexGuard aGuard;
1632
0
    if (ScDPObject* pDPObj = GetDPObject())
1633
0
    {
1634
0
        Sequence< OUString > aSeq( lcl_GetFieldCount( pDPObj->GetSource(), maOrient ) );
1635
0
        OUString* pAry = aSeq.getArray();
1636
1637
0
        const ScDPSaveData::DimsType& rDimensions = pDPObj->GetSaveData()->GetDimensions();
1638
0
        for (auto const& it : rDimensions)
1639
0
        {
1640
0
            if(maOrient.hasValue() && (it->GetOrientation() == maOrient.get< DataPilotFieldOrientation >()))
1641
0
            {
1642
0
                *pAry = it->GetName();
1643
0
                ++pAry;
1644
0
            }
1645
0
        }
1646
0
        return aSeq;
1647
0
    }
1648
0
    return Sequence<OUString>();
1649
0
}
1650
1651
sal_Bool SAL_CALL ScDataPilotFieldsObj::hasByName( const OUString& aName )
1652
0
{
1653
0
    SolarMutexGuard aGuard;
1654
1655
0
    return GetObjectByName_Impl(aName) != nullptr;
1656
0
}
1657
1658
ScDataPilotFieldObj::ScDataPilotFieldObj(
1659
        ScDataPilotDescriptorBase& rParent, const ScFieldIdentifier& rFieldId ) :
1660
31
    ScDataPilotChildObjBase( rParent, rFieldId ),
1661
31
    maPropSet( lcl_GetDataPilotFieldMap() )
1662
31
{
1663
31
}
1664
1665
ScDataPilotFieldObj::ScDataPilotFieldObj( ScDataPilotDescriptorBase& rParent,
1666
        const ScFieldIdentifier& rFieldId, Any aOrient ) :
1667
2.52k
    ScDataPilotChildObjBase( rParent, rFieldId ),
1668
2.52k
    maPropSet( lcl_GetDataPilotFieldMap() ),
1669
2.52k
    maOrient(std::move( aOrient ))
1670
2.52k
{
1671
2.52k
}
1672
1673
ScDataPilotFieldObj::~ScDataPilotFieldObj()
1674
2.56k
{
1675
2.56k
}
1676
1677
// XNamed
1678
1679
OUString SAL_CALL ScDataPilotFieldObj::getName()
1680
44
{
1681
44
    SolarMutexGuard aGuard;
1682
44
    OUString aName;
1683
44
    if( ScDPSaveDimension* pDim = GetDPDimension() )
1684
44
    {
1685
44
        if( pDim->IsDataLayout() )
1686
0
            aName = SC_DATALAYOUT_NAME;
1687
44
        else
1688
44
        {
1689
44
            const std::optional<OUString> & pLayoutName = pDim->GetLayoutName();
1690
44
            if (pLayoutName)
1691
0
                aName = *pLayoutName;
1692
44
            else
1693
44
                aName = pDim->GetName();
1694
44
        }
1695
44
    }
1696
44
    return aName;
1697
44
}
1698
1699
void SAL_CALL ScDataPilotFieldObj::setName(const OUString& rName)
1700
101
{
1701
101
    SolarMutexGuard aGuard;
1702
101
    ScDPObject* pDPObj = nullptr;
1703
101
    ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
1704
101
    if( pDim && !pDim->IsDataLayout() )
1705
101
    {
1706
101
        pDim->SetLayoutName(rName);
1707
101
        SetDPObject( pDPObj );
1708
101
    }
1709
101
}
1710
1711
// XPropertySet
1712
1713
Reference<XPropertySetInfo> SAL_CALL ScDataPilotFieldObj::getPropertySetInfo()
1714
1.22k
{
1715
1.22k
    SolarMutexGuard aGuard;
1716
1.22k
    static Reference<XPropertySetInfo> aRef(
1717
1.22k
        new SfxItemPropertySetInfo( maPropSet.getPropertyMap() ));
1718
1.22k
    return aRef;
1719
1.22k
}
1720
1721
void SAL_CALL ScDataPilotFieldObj::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
1722
4.36k
{
1723
4.36k
    SolarMutexGuard aGuard;
1724
4.36k
    if ( aPropertyName == SC_UNONAME_FUNCTION )
1725
165
    {
1726
        // #i109350# use GetEnumFromAny because it also allows sal_Int32
1727
165
        ScGeneralFunction eFunction = static_cast<ScGeneralFunction>(ScUnoHelpFunctions::GetEnumFromAny( aValue ));
1728
165
        setFunction( eFunction );
1729
165
    }
1730
4.19k
    else if ( aPropertyName == SC_UNONAME_FUNCTION2 )
1731
0
    {
1732
0
        ScGeneralFunction eFunction = static_cast<ScGeneralFunction>(ScUnoHelpFunctions::GetInt16FromAny( aValue ));
1733
0
        setFunction( eFunction );
1734
0
    }
1735
4.19k
    else if ( aPropertyName == SC_UNONAME_SUBTOTALS )
1736
862
    {
1737
862
        uno::Sequence<sheet::GeneralFunction> aSeq;
1738
862
        if( aValue >>= aSeq)
1739
862
        {
1740
862
            std::vector< ScGeneralFunction > aSubTotals(aSeq.getLength());
1741
862
            std::transform(std::cbegin(aSeq), std::cend(aSeq), aSubTotals.begin(),
1742
862
                [](const sheet::GeneralFunction& rValue) -> ScGeneralFunction {
1743
831
                    const int nValAsInt = static_cast<int>(rValue);
1744
831
                    return static_cast<ScGeneralFunction>(nValAsInt);
1745
831
                });
1746
862
            setSubtotals( aSubTotals );
1747
862
        }
1748
862
    }
1749
3.33k
    else if ( aPropertyName == SC_UNONAME_SUBTOTALS2 )
1750
0
    {
1751
0
        Sequence< sal_Int16 > aSeq;
1752
0
        if( aValue >>= aSeq )
1753
0
        {
1754
0
            std::vector< ScGeneralFunction > aSubTotals(aSeq.getLength());
1755
0
            std::transform(std::cbegin(aSeq), std::cend(aSeq), aSubTotals.begin(),
1756
0
                [](sal_Int16 nValue) -> ScGeneralFunction { return static_cast<ScGeneralFunction>(nValue); });
1757
0
            setSubtotals( aSubTotals );
1758
0
        }
1759
0
    }
1760
3.33k
    else if ( aPropertyName == SC_UNONAME_ORIENT )
1761
597
    {
1762
        //! test for correct enum type?
1763
597
        DataPilotFieldOrientation eOrient = static_cast<DataPilotFieldOrientation>(ScUnoHelpFunctions::GetEnumFromAny( aValue ));
1764
597
        setOrientation( eOrient );
1765
597
    }
1766
2.73k
    else if ( aPropertyName == SC_UNONAME_SELPAGE )
1767
26
    {
1768
26
        OUString sCurrentPage;
1769
26
        if (aValue >>= sCurrentPage)
1770
26
            setCurrentPage(sCurrentPage);
1771
26
    }
1772
2.71k
    else if ( aPropertyName == SC_UNONAME_USESELPAGE )
1773
0
    {
1774
0
        setUseCurrentPage(cppu::any2bool(aValue));
1775
0
    }
1776
2.71k
    else if ( aPropertyName == SC_UNONAME_HASAUTOSHOW )
1777
0
    {
1778
0
        if (!cppu::any2bool(aValue))
1779
0
            setAutoShowInfo(nullptr);
1780
0
    }
1781
2.71k
    else if ( aPropertyName == SC_UNONAME_AUTOSHOW )
1782
0
    {
1783
0
        DataPilotFieldAutoShowInfo aInfo;
1784
0
        if (aValue >>= aInfo)
1785
0
            setAutoShowInfo(&aInfo);
1786
0
    }
1787
2.71k
    else if ( aPropertyName == SC_UNONAME_HASLAYOUTINFO )
1788
0
    {
1789
0
        if (!cppu::any2bool(aValue))
1790
0
            setLayoutInfo(nullptr);
1791
0
    }
1792
2.71k
    else if ( aPropertyName == SC_UNONAME_LAYOUTINFO )
1793
862
    {
1794
862
        DataPilotFieldLayoutInfo aInfo;
1795
862
        if (aValue >>= aInfo)
1796
862
            setLayoutInfo(&aInfo);
1797
862
    }
1798
1.84k
    else if ( aPropertyName == SC_UNONAME_HASREFERENCE )
1799
0
    {
1800
0
        if (!cppu::any2bool(aValue))
1801
0
            setReference(nullptr);
1802
0
    }
1803
1.84k
    else if ( aPropertyName == SC_UNONAME_REFERENCE )
1804
6
    {
1805
6
        DataPilotFieldReference aRef;
1806
6
        if (aValue >>= aRef)
1807
6
            setReference(&aRef);
1808
6
    }
1809
1.84k
    else if ( aPropertyName == SC_UNONAME_HASSORTINFO )
1810
0
    {
1811
0
        if (!cppu::any2bool(aValue))
1812
0
            setSortInfo(nullptr);
1813
0
    }
1814
1.84k
    else if ( aPropertyName == SC_UNONAME_SORTINFO )
1815
862
    {
1816
862
        DataPilotFieldSortInfo aInfo;
1817
862
        if (aValue >>= aInfo)
1818
862
            setSortInfo(&aInfo);
1819
862
    }
1820
980
    else if ( aPropertyName == SC_UNONAME_ISGROUP )
1821
0
    {
1822
0
        if (!cppu::any2bool(aValue))
1823
0
            setGroupInfo(nullptr);
1824
0
    }
1825
980
    else if ( aPropertyName == SC_UNONAME_GROUPINFO )
1826
17
    {
1827
17
        DataPilotFieldGroupInfo aInfo;
1828
17
        if (aValue >>= aInfo)
1829
17
            setGroupInfo(&aInfo);
1830
17
    }
1831
963
    else if ( aPropertyName == SC_UNONAME_SHOWEMPTY )
1832
862
    {
1833
862
        setShowEmpty(cppu::any2bool(aValue));
1834
862
    }
1835
101
    else if ( aPropertyName == SC_UNONAME_REPEATITEMLABELS )
1836
0
    {
1837
0
        setRepeatItemLabels(cppu::any2bool(aValue));
1838
0
    }
1839
101
    else if (aPropertyName == SC_UNONAME_NAME)
1840
101
    {
1841
101
        OUString sName;
1842
101
        if (aValue >>= sName)
1843
101
            setName(sName);
1844
101
    }
1845
4.36k
}
1846
1847
Any SAL_CALL ScDataPilotFieldObj::getPropertyValue( const OUString& aPropertyName )
1848
17
{
1849
17
    SolarMutexGuard aGuard;
1850
17
    Any aRet;
1851
1852
17
    if ( aPropertyName == SC_UNONAME_FUNCTION )
1853
0
    {
1854
0
        sheet::GeneralFunction eVal;
1855
0
        sal_Int16 nFunction = getFunction();
1856
0
        if (nFunction == sheet::GeneralFunction2::MEDIAN)
1857
0
        {
1858
0
            eVal = sheet::GeneralFunction_NONE;
1859
0
        }
1860
0
        else
1861
0
        {
1862
0
            eVal = static_cast<sheet::GeneralFunction>(nFunction);
1863
0
        }
1864
0
        aRet <<= eVal;
1865
0
    }
1866
17
    else if ( aPropertyName == SC_UNONAME_FUNCTION2 )
1867
0
        aRet <<= getFunction();
1868
17
    else if ( aPropertyName == SC_UNONAME_SUBTOTALS )
1869
0
    {
1870
0
        const uno::Sequence<sal_Int16> aSeq = getSubtotals();
1871
0
        uno::Sequence<sheet::GeneralFunction>  aNewSeq(aSeq.getLength());
1872
0
        std::transform(aSeq.begin(), aSeq.end(), aNewSeq.getArray(),
1873
0
            [](sal_Int16 nFunc) -> sheet::GeneralFunction {
1874
0
                if (nFunc == sheet::GeneralFunction2::MEDIAN)
1875
0
                    return sheet::GeneralFunction_NONE;
1876
0
                return static_cast<sheet::GeneralFunction>(nFunc);
1877
0
            });
1878
0
        aRet <<= aNewSeq;
1879
0
    }
1880
17
    else if ( aPropertyName == SC_UNONAME_SUBTOTALS2 )
1881
0
    {
1882
0
        aRet <<= getSubtotals();
1883
0
    }
1884
17
    else if ( aPropertyName == SC_UNONAME_ORIENT )
1885
0
        aRet <<= getOrientation();
1886
17
    else if ( aPropertyName == SC_UNONAME_SELPAGE )
1887
0
        aRet <<= OUString();
1888
17
    else if ( aPropertyName == SC_UNONAME_USESELPAGE )
1889
0
        aRet <<= false;
1890
17
    else if ( aPropertyName == SC_UNONAME_HASAUTOSHOW )
1891
0
        aRet <<= (getAutoShowInfo() != nullptr);
1892
17
    else if ( aPropertyName == SC_UNONAME_AUTOSHOW )
1893
0
    {
1894
0
        const DataPilotFieldAutoShowInfo* pInfo = getAutoShowInfo();
1895
0
        if (pInfo)
1896
0
            aRet <<= *pInfo;
1897
0
    }
1898
17
    else if ( aPropertyName == SC_UNONAME_HASLAYOUTINFO )
1899
0
        aRet <<= (getLayoutInfo() != nullptr);
1900
17
    else if ( aPropertyName == SC_UNONAME_LAYOUTINFO )
1901
0
    {
1902
0
        const DataPilotFieldLayoutInfo* pInfo = getLayoutInfo();
1903
0
        if (pInfo)
1904
0
            aRet <<= *pInfo;
1905
0
    }
1906
17
    else if ( aPropertyName == SC_UNONAME_HASREFERENCE )
1907
0
        aRet <<= (getReference() != nullptr);
1908
17
    else if ( aPropertyName == SC_UNONAME_REFERENCE )
1909
0
    {
1910
0
        const DataPilotFieldReference* pRef = getReference();
1911
0
        if (pRef)
1912
0
            aRet <<= *pRef;
1913
0
    }
1914
17
    else if ( aPropertyName == SC_UNONAME_HASSORTINFO )
1915
0
        aRet <<= (getSortInfo() != nullptr);
1916
17
    else if ( aPropertyName == SC_UNONAME_SORTINFO )
1917
0
    {
1918
0
        const DataPilotFieldSortInfo* pInfo = getSortInfo();
1919
0
        if (pInfo)
1920
0
            aRet <<= *pInfo;
1921
0
    }
1922
17
    else if ( aPropertyName == SC_UNONAME_ISGROUP )
1923
0
        aRet <<= hasGroupInfo();
1924
17
    else if ( aPropertyName == SC_UNONAME_GROUPINFO )
1925
17
    {
1926
17
        aRet <<= getGroupInfo();
1927
17
    }
1928
0
    else if ( aPropertyName == SC_UNONAME_SHOWEMPTY )
1929
0
        aRet <<= getShowEmpty();
1930
0
    else if ( aPropertyName == SC_UNONAME_REPEATITEMLABELS )
1931
0
        aRet <<= getRepeatItemLabels();
1932
0
    else if (aPropertyName == SC_UNONAME_NAME)
1933
0
        aRet <<= getName();
1934
1935
17
    return aRet;
1936
17
}
1937
1938
// XDatePilotField
1939
1940
Reference<XIndexAccess> SAL_CALL ScDataPilotFieldObj::getItems()
1941
0
{
1942
0
    SolarMutexGuard aGuard;
1943
0
    if (!mxItems.is())
1944
0
        mxItems.set( new ScDataPilotItemsObj( *mxParent, maFieldId ) );
1945
0
    return mxItems;
1946
0
}
1947
1948
SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDataPilotFieldObj )
1949
1950
DataPilotFieldOrientation ScDataPilotFieldObj::getOrientation() const
1951
0
{
1952
0
    SolarMutexGuard aGuard;
1953
0
    ScDPSaveDimension* pDim = GetDPDimension();
1954
0
    return pDim ? pDim->GetOrientation() : DataPilotFieldOrientation_HIDDEN;
1955
0
}
1956
1957
void ScDataPilotFieldObj::setOrientation(DataPilotFieldOrientation eNew)
1958
597
{
1959
597
    SolarMutexGuard aGuard;
1960
597
    if (maOrient.hasValue() && (eNew == maOrient.get< DataPilotFieldOrientation >()))
1961
0
        return;
1962
1963
597
    ScDPObject* pDPObj = nullptr;
1964
597
    ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
1965
597
    if(!pDim)
1966
0
        return;
1967
1968
597
    ScDPSaveData* pSaveData = pDPObj->GetSaveData();
1969
1970
    /*  If the field was taken from getDataPilotFields(), don't reset the
1971
        orientation for an existing use, but create a duplicated field
1972
        instead (for "Data" orientation only). */
1973
597
    if ( !maOrient.hasValue() && !maFieldId.mbDataLayout &&
1974
566
         (pDim->GetOrientation() != DataPilotFieldOrientation_HIDDEN) &&
1975
18
         (eNew == DataPilotFieldOrientation_DATA) )
1976
18
    {
1977
1978
18
        ScDPSaveDimension* pNewDim = nullptr;
1979
1980
        // look for existing duplicate with orientation "hidden"
1981
1982
18
        sal_Int32 nFound = 0;
1983
18
        const ScDPSaveData::DimsType& rDimensions = pSaveData->GetDimensions();
1984
18
        for (auto const& it : rDimensions)
1985
106
        {
1986
106
            if ( !it->IsDataLayout() && (it->GetName() == maFieldId.maFieldName) )
1987
24
            {
1988
24
                if ( it->GetOrientation() == DataPilotFieldOrientation_HIDDEN )
1989
0
                {
1990
0
                    pNewDim = it.get();     // use this one
1991
0
                    break;
1992
0
                }
1993
24
                else
1994
24
                    ++nFound;               // count existing non-hidden occurrences
1995
24
            }
1996
106
        }
1997
1998
18
        if ( !pNewDim )     // if none found, create a new duplicated dimension
1999
18
            pNewDim = &pSaveData->DuplicateDimension( *pDim );
2000
2001
18
        maFieldId.mnFieldIdx = nFound;      // keep accessing the new one
2002
18
        pDim = pNewDim;
2003
18
    }
2004
2005
597
    pDim->SetOrientation(eNew);
2006
2007
    // move changed field behind all other fields (make it the last field in dimension)
2008
597
    pSaveData->SetPosition( pDim, pSaveData->GetDimensions().size() );
2009
2010
597
    SetDPObject( pDPObj );
2011
2012
597
    maOrient <<= eNew;   // modifying the same object's orientation again doesn't create another duplicate
2013
597
}
2014
2015
sal_Int16 ScDataPilotFieldObj::getFunction() const
2016
0
{
2017
0
    SolarMutexGuard aGuard;
2018
0
    sal_Int16 eRet = GeneralFunction2::NONE;
2019
0
    if( ScDPSaveDimension* pDim = GetDPDimension() )
2020
0
    {
2021
0
        if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
2022
0
        {
2023
            // for non-data fields, property Function is the subtotals
2024
0
            tools::Long nSubCount = pDim->GetSubTotalsCount();
2025
0
            if ( nSubCount > 0 )
2026
0
                eRet = static_cast<sal_Int16>(pDim->GetSubTotalFunc(0));    // always use the first one
2027
            // else keep NONE
2028
0
        }
2029
0
        else
2030
0
            eRet = static_cast<sal_Int16>(pDim->GetFunction());
2031
0
    }
2032
0
    return eRet;
2033
0
}
2034
2035
void ScDataPilotFieldObj::setFunction(ScGeneralFunction eNewFunc)
2036
165
{
2037
165
    SolarMutexGuard aGuard;
2038
165
    ScDPObject* pDPObj = nullptr;
2039
165
    ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
2040
165
    if(!pDim)
2041
0
        return;
2042
2043
165
    if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
2044
0
    {
2045
        // for non-data fields, property Function is the subtotals
2046
0
        std::vector<ScGeneralFunction> nSubTotalFuncs;
2047
0
        if ( eNewFunc != ScGeneralFunction::NONE )
2048
0
        {
2049
0
            nSubTotalFuncs.push_back( eNewFunc );
2050
0
        }
2051
0
        pDim->SetSubTotals( std::move(nSubTotalFuncs) );
2052
0
    }
2053
165
    else
2054
165
        pDim->SetFunction( eNewFunc );
2055
165
    SetDPObject( pDPObj );
2056
165
}
2057
2058
Sequence< sal_Int16 > ScDataPilotFieldObj::getSubtotals() const
2059
0
{
2060
0
    SolarMutexGuard aGuard;
2061
0
    Sequence< sal_Int16 > aRet;
2062
0
    if( ScDPSaveDimension* pDim = GetDPDimension() )
2063
0
    {
2064
0
        if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
2065
0
        {
2066
            // for non-data fields, property Functions is the sequence of subtotals
2067
0
            sal_Int32 nCount = static_cast< sal_Int32 >( pDim->GetSubTotalsCount() );
2068
0
            if ( nCount > 0 )
2069
0
            {
2070
0
                aRet.realloc( nCount );
2071
0
                auto pRet = aRet.getArray();
2072
0
                for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
2073
0
                    pRet[ nIdx ] = static_cast<sal_Int16>(pDim->GetSubTotalFunc( nIdx ));
2074
0
            }
2075
0
        }
2076
0
    }
2077
0
    return aRet;
2078
0
}
2079
2080
void ScDataPilotFieldObj::setSubtotals( const std::vector< ScGeneralFunction >& rSubtotals )
2081
862
{
2082
862
    SolarMutexGuard aGuard;
2083
862
    ScDPObject* pDPObj = nullptr;
2084
862
    ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
2085
862
    if(!pDim)
2086
0
        return;
2087
2088
862
    if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
2089
862
    {
2090
862
        sal_Int32 nCount = rSubtotals.size();
2091
862
        if( nCount == 1 )
2092
831
        {
2093
            // count 1: all values are allowed (including NONE and AUTO)
2094
831
            std::vector<ScGeneralFunction> nTmpFuncs;
2095
831
            if( rSubtotals[ 0 ] != ScGeneralFunction::NONE )
2096
831
            {
2097
831
                nTmpFuncs.push_back( rSubtotals[ 0 ] );
2098
831
            }
2099
831
            pDim->SetSubTotals( std::move(nTmpFuncs) );
2100
831
        }
2101
31
        else if( nCount > 1 )
2102
0
        {
2103
            // set multiple functions, ignore NONE and AUTO in this case
2104
0
            ::std::vector< ScGeneralFunction > aSubt;
2105
0
            for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
2106
0
            {
2107
0
                ScGeneralFunction eFunc = rSubtotals[ nIdx ];
2108
0
                if( (eFunc != ScGeneralFunction::NONE) && (eFunc != ScGeneralFunction::AUTO) )
2109
0
                {
2110
                    // do not insert functions twice
2111
0
                    if( ::std::find( aSubt.begin(), aSubt.end(), eFunc ) == aSubt.end() )
2112
0
                        aSubt.push_back( eFunc );
2113
0
                }
2114
0
            }
2115
            // set values from vector to ScDPSaveDimension
2116
0
            pDim->SetSubTotals( std::move(aSubt) );
2117
0
        }
2118
862
    }
2119
862
    SetDPObject( pDPObj );
2120
862
}
2121
2122
void ScDataPilotFieldObj::setCurrentPage( const OUString& rPage )
2123
26
{
2124
26
    SolarMutexGuard aGuard;
2125
26
    ScDPObject* pDPObj = nullptr;
2126
26
    if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2127
26
    {
2128
26
        pDim->SetCurrentPage( &rPage );
2129
26
        SetDPObject( pDPObj );
2130
26
    }
2131
26
}
2132
2133
void ScDataPilotFieldObj::setUseCurrentPage( bool bUse )
2134
0
{
2135
0
    SolarMutexGuard aGuard;
2136
0
    ScDPObject* pDPObj = nullptr;
2137
0
    ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
2138
0
    if(!pDim)
2139
0
        return;
2140
2141
0
    if( bUse )
2142
0
    {
2143
        /*  It is somehow useless to set the property "HasSelectedPage" to
2144
            true, because it is still needed to set an explicit page name. */
2145
0
        const OUString aPage;
2146
0
        pDim->SetCurrentPage( &aPage );
2147
0
    }
2148
0
    else
2149
0
        pDim->SetCurrentPage( nullptr );
2150
0
    SetDPObject( pDPObj );
2151
0
}
2152
2153
const DataPilotFieldAutoShowInfo* ScDataPilotFieldObj::getAutoShowInfo() const
2154
0
{
2155
0
    SolarMutexGuard aGuard;
2156
0
    ScDPSaveDimension* pDim = GetDPDimension();
2157
0
    return pDim ? pDim->GetAutoShowInfo() : nullptr;
2158
0
}
2159
2160
void ScDataPilotFieldObj::setAutoShowInfo( const DataPilotFieldAutoShowInfo* pInfo )
2161
0
{
2162
0
    SolarMutexGuard aGuard;
2163
0
    ScDPObject* pDPObj = nullptr;
2164
0
    if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2165
0
    {
2166
0
        pDim->SetAutoShowInfo( pInfo );
2167
0
        SetDPObject( pDPObj );
2168
0
    }
2169
0
}
2170
2171
const DataPilotFieldLayoutInfo* ScDataPilotFieldObj::getLayoutInfo() const
2172
0
{
2173
0
    SolarMutexGuard aGuard;
2174
0
    ScDPSaveDimension* pDim = GetDPDimension();
2175
0
    return pDim ? pDim->GetLayoutInfo() : nullptr;
2176
0
}
2177
2178
void ScDataPilotFieldObj::setLayoutInfo( const DataPilotFieldLayoutInfo* pInfo )
2179
862
{
2180
862
    SolarMutexGuard aGuard;
2181
862
    ScDPObject* pDPObj = nullptr;
2182
862
    if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2183
862
    {
2184
862
        pDim->SetLayoutInfo( pInfo );
2185
862
        SetDPObject( pDPObj );
2186
862
    }
2187
862
}
2188
2189
const DataPilotFieldReference* ScDataPilotFieldObj::getReference() const
2190
0
{
2191
0
    SolarMutexGuard aGuard;
2192
0
    ScDPSaveDimension* pDim = GetDPDimension();
2193
0
    return pDim ? pDim->GetReferenceValue() : nullptr;
2194
0
}
2195
2196
void ScDataPilotFieldObj::setReference( const DataPilotFieldReference* pInfo )
2197
6
{
2198
6
    SolarMutexGuard aGuard;
2199
6
    ScDPObject* pDPObj = nullptr;
2200
6
    if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2201
6
    {
2202
6
        pDim->SetReferenceValue( pInfo );
2203
6
        SetDPObject( pDPObj );
2204
6
    }
2205
6
}
2206
2207
const DataPilotFieldSortInfo* ScDataPilotFieldObj::getSortInfo() const
2208
0
{
2209
0
    SolarMutexGuard aGuard;
2210
0
    ScDPSaveDimension* pDim = GetDPDimension();
2211
0
    return pDim ? pDim->GetSortInfo() : nullptr;
2212
0
}
2213
2214
void ScDataPilotFieldObj::setSortInfo( const DataPilotFieldSortInfo* pInfo )
2215
862
{
2216
862
    SolarMutexGuard aGuard;
2217
862
    ScDPObject* pDPObj = nullptr;
2218
862
    if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2219
862
    {
2220
862
        pDim->SetSortInfo( pInfo );
2221
862
        SetDPObject( pDPObj );
2222
862
    }
2223
862
}
2224
2225
bool ScDataPilotFieldObj::getShowEmpty() const
2226
0
{
2227
0
    SolarMutexGuard aGuard;
2228
0
    ScDPSaveDimension* pDim = GetDPDimension();
2229
0
    return pDim && pDim->GetShowEmpty();
2230
0
}
2231
2232
void ScDataPilotFieldObj::setShowEmpty( bool bShow )
2233
862
{
2234
862
    SolarMutexGuard aGuard;
2235
862
    ScDPObject* pDPObj = nullptr;
2236
862
    if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2237
862
    {
2238
862
        pDim->SetShowEmpty( bShow );
2239
862
        SetDPObject( pDPObj );
2240
862
    }
2241
862
}
2242
2243
bool ScDataPilotFieldObj::getRepeatItemLabels() const
2244
0
{
2245
0
    SolarMutexGuard aGuard;
2246
0
    ScDPSaveDimension* pDim = GetDPDimension();
2247
0
    return pDim && pDim->GetRepeatItemLabels();
2248
0
}
2249
2250
void ScDataPilotFieldObj::setRepeatItemLabels( bool bShow )
2251
0
{
2252
0
    SolarMutexGuard aGuard;
2253
0
    ScDPObject* pDPObj = nullptr;
2254
0
    if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2255
0
    {
2256
0
        pDim->SetRepeatItemLabels( bShow );
2257
0
        SetDPObject( pDPObj );
2258
0
    }
2259
0
}
2260
2261
bool ScDataPilotFieldObj::hasGroupInfo() const
2262
0
{
2263
0
    SolarMutexGuard aGuard;
2264
0
    ScDPObject* pDPObj = nullptr;
2265
0
    if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2266
0
        if( const ScDPDimensionSaveData* pDimData = pDPObj->GetSaveData()->GetExistingDimensionData() )
2267
0
            return pDimData->GetNamedGroupDim( pDim->GetName() ) || pDimData->GetNumGroupDim( pDim->GetName() );
2268
0
    return false;
2269
0
}
2270
2271
DataPilotFieldGroupInfo ScDataPilotFieldObj::getGroupInfo()
2272
17
{
2273
17
    SolarMutexGuard aGuard;
2274
17
    DataPilotFieldGroupInfo aInfo;
2275
17
    ScDPObject* pDPObj = nullptr;
2276
17
    if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2277
17
    {
2278
17
        if( const ScDPDimensionSaveData* pDimData = pDPObj->GetSaveData()->GetExistingDimensionData() )
2279
17
        {
2280
17
            if( const ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDim( pDim->GetName() ) )
2281
17
            {
2282
                // grouped by ...
2283
17
                aInfo.GroupBy = pGroupDim->GetDatePart();
2284
2285
                // find source field
2286
17
                try
2287
17
                {
2288
17
                    Reference< XNameAccess > xFields( mxParent->getDataPilotFields(), UNO_QUERY_THROW );
2289
17
                    aInfo.SourceField.set( xFields->getByName( pGroupDim->GetSourceDimName() ), UNO_QUERY );
2290
17
                }
2291
17
                catch( Exception& )
2292
17
                {
2293
0
                }
2294
2295
17
                ScDataPilotConversion::FillGroupInfo( aInfo, pGroupDim->GetDateInfo() );
2296
17
                if( pGroupDim->GetDatePart() == 0 )
2297
17
                {
2298
                    // fill vector of group and group member information
2299
17
                    ScFieldGroups aGroups;
2300
41
                    for( sal_Int32 nIdx = 0, nCount = pGroupDim->GetGroupCount(); nIdx < nCount; ++nIdx )
2301
24
                    {
2302
24
                        const ScDPSaveGroupItem& rGroup = pGroupDim->GetGroupByIndex( nIdx );
2303
24
                        ScFieldGroup aGroup;
2304
24
                        aGroup.maName = rGroup.GetGroupName();
2305
55
                        for( sal_Int32 nMemIdx = 0, nMemCount = rGroup.GetElementCount(); nMemIdx < nMemCount; ++nMemIdx )
2306
31
                            if (const OUString* pMem = rGroup.GetElementByIndex(nMemIdx))
2307
31
                                aGroup.maMembers.push_back( *pMem );
2308
24
                        aGroups.push_back(std::move(aGroup));
2309
24
                    }
2310
17
                    aInfo.Groups = new ScDataPilotFieldGroupsObj( std::move(aGroups) );
2311
17
                }
2312
17
            }
2313
0
            else if( const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( pDim->GetName() ) )
2314
0
            {
2315
0
                if (pNumGroupDim->GetDatePart())
2316
0
                {
2317
0
                    ScDataPilotConversion::FillGroupInfo( aInfo, pNumGroupDim->GetDateInfo() );
2318
0
                    aInfo.GroupBy = pNumGroupDim->GetDatePart();
2319
0
                }
2320
0
                else
2321
0
                {
2322
0
                    ScDataPilotConversion::FillGroupInfo( aInfo, pNumGroupDim->GetInfo() );
2323
0
                }
2324
0
            }
2325
17
        }
2326
17
    }
2327
17
    return aInfo;
2328
17
}
2329
2330
void ScDataPilotFieldObj::setGroupInfo( const DataPilotFieldGroupInfo* pInfo )
2331
17
{
2332
17
    SolarMutexGuard aGuard;
2333
17
    ScDPObject* pDPObj = nullptr;
2334
17
    if( /*ScDPSaveDimension* pDim =*/ !GetDPDimension( &pDPObj ) )
2335
0
        return;
2336
2337
17
    ScDPSaveData* pSaveData = pDPObj->GetSaveData();
2338
17
    if( pInfo && lclCheckMinMaxStep( *pInfo ) )
2339
17
    {
2340
17
        ScDPNumGroupInfo aInfo;
2341
17
        aInfo.mbEnable = true;
2342
17
        aInfo.mbDateValues = pInfo->HasDateValues;
2343
17
        aInfo.mbAutoStart = pInfo->HasAutoStart;
2344
17
        aInfo.mbAutoEnd = pInfo->HasAutoEnd;
2345
17
        aInfo.mfStart = pInfo->Start;
2346
17
        aInfo.mfEnd = pInfo->End;
2347
17
        aInfo.mfStep = pInfo->Step;
2348
17
        Reference< XNamed > xNamed( pInfo->SourceField, UNO_QUERY );
2349
17
        if( xNamed.is() )
2350
17
        {
2351
17
            ScDPSaveGroupDimension aGroupDim( xNamed->getName(), getName() );
2352
17
            if( pInfo->GroupBy )
2353
0
                aGroupDim.SetDateInfo(aInfo, pInfo->GroupBy);
2354
17
            else
2355
17
            {
2356
17
                Reference<XIndexAccess> xIndex(pInfo->Groups, UNO_QUERY);
2357
17
                if (xIndex.is())
2358
17
                {
2359
17
                    sal_Int32 nCount(xIndex->getCount());
2360
41
                    for(sal_Int32 i = 0; i < nCount; i++)
2361
24
                    {
2362
24
                        Reference<XNamed> xGroupNamed(xIndex->getByIndex(i), UNO_QUERY);
2363
24
                        if (xGroupNamed.is())
2364
24
                        {
2365
24
                            ScDPSaveGroupItem aItem(xGroupNamed->getName());
2366
24
                            Reference<XIndexAccess> xGroupIndex(xGroupNamed, UNO_QUERY);
2367
24
                            if (xGroupIndex.is())
2368
24
                            {
2369
24
                                sal_Int32 nItemCount(xGroupIndex->getCount());
2370
55
                                for (sal_Int32 j = 0; j < nItemCount; ++j)
2371
31
                                {
2372
31
                                    Reference<XNamed> xItemNamed(xGroupIndex->getByIndex(j), UNO_QUERY);
2373
31
                                    if (xItemNamed.is())
2374
31
                                        aItem.AddElement(xItemNamed->getName());
2375
31
                                }
2376
24
                            }
2377
24
                            aGroupDim.AddGroupItem(aItem);
2378
24
                        }
2379
24
                    }
2380
17
                }
2381
17
            }
2382
2383
            // get dimension savedata or create new if none
2384
17
            ScDPDimensionSaveData& rDimSaveData = *pSaveData->GetDimensionData();
2385
17
            rDimSaveData.ReplaceGroupDimension( aGroupDim );
2386
17
        }
2387
0
        else    // no source field in group info -> numeric group
2388
0
        {
2389
0
            ScDPDimensionSaveData* pDimData = pSaveData->GetDimensionData();     // created if not there
2390
2391
0
            ScDPSaveNumGroupDimension* pExisting = pDimData->GetNumGroupDimAcc( getName() );
2392
0
            if ( pExisting )
2393
0
            {
2394
0
                if (pInfo->GroupBy)
2395
0
                    pExisting->SetDateInfo(aInfo, pInfo->GroupBy);
2396
                // modify existing group dimension
2397
0
                pExisting->SetGroupInfo( aInfo );
2398
0
            }
2399
0
            else if (pInfo->GroupBy)
2400
0
            {
2401
                // create new group dimension
2402
0
                ScDPSaveNumGroupDimension aNumGroupDim( getName(), aInfo, pInfo->GroupBy );
2403
0
                pDimData->AddNumGroupDimension( aNumGroupDim );
2404
0
            }
2405
0
            else
2406
0
            {
2407
                // create new group dimension
2408
0
                ScDPSaveNumGroupDimension aNumGroupDim( getName(), aInfo );
2409
0
                pDimData->AddNumGroupDimension( aNumGroupDim );
2410
0
            }
2411
0
        }
2412
17
    }
2413
0
    else    // null passed as argument
2414
0
    {
2415
0
        pSaveData->SetDimensionData( nullptr );
2416
0
    }
2417
2418
17
    pDPObj->SetSaveData( *pSaveData );
2419
17
    SetDPObject( pDPObj );
2420
17
}
2421
2422
// XDataPilotFieldGrouping
2423
Reference< XDataPilotField > SAL_CALL ScDataPilotFieldObj::createNameGroup( const Sequence< OUString >& rItems )
2424
0
{
2425
0
    return createNameGroup(comphelper::sequenceToContainer<std::vector<OUString>>(rItems));
2426
0
}
2427
2428
rtl::Reference< ScDataPilotFieldObj > ScDataPilotFieldObj::createNameGroup( const std::vector< OUString >& rItems )
2429
26
{
2430
26
    SolarMutexGuard aGuard;
2431
2432
26
    if( rItems.empty() )
2433
0
        throw IllegalArgumentException(u"rItems is empty"_ustr, getXWeak(), 0);
2434
2435
26
    Reference< XMembersAccess > xMembers = GetMembers();
2436
26
    if (!xMembers.is())
2437
0
    {
2438
0
        SAL_WARN("sc.ui", "Cannot access members of the field object.");
2439
0
        throw RuntimeException(u"Cannot access members of the field object"_ustr, getXWeak());
2440
0
    }
2441
2442
26
    for (const OUString& aEntryName : rItems)
2443
37
    {
2444
37
        if (!xMembers->hasByName(aEntryName))
2445
9
        {
2446
9
            SAL_WARN("sc.ui", "There is no member with that name: " + aEntryName + ".");
2447
9
            throw IllegalArgumentException("There is no member with name \"" + aEntryName + "\"", getXWeak(), 0);
2448
9
        }
2449
37
    }
2450
2451
17
    rtl::Reference< ScDataPilotFieldObj > xRet;
2452
17
    OUString sNewDim;
2453
17
    ScDPObject* pDPObj = nullptr;
2454
17
    if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2455
17
    {
2456
17
        const OUString& aDimName = pDim->GetName();
2457
2458
17
        ScDPSaveData aSaveData = *pDPObj->GetSaveData();
2459
17
        ScDPDimensionSaveData* pDimData = aSaveData.GetDimensionData();     // created if not there
2460
2461
        // find original base
2462
17
        OUString aBaseDimName( aDimName );
2463
17
        const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName );
2464
17
        if ( pBaseGroupDim )
2465
0
        {
2466
            // any entry's SourceDimName is the original base
2467
0
            aBaseDimName = pBaseGroupDim->GetSourceDimName();
2468
0
        }
2469
2470
        // find existing group dimension
2471
        // (using the selected dim, can be intermediate group dim)
2472
17
        ScDPSaveGroupDimension* pGroupDimension = pDimData->GetGroupDimAccForBase( aDimName );
2473
2474
        // remove the selected items from their groups
2475
        // (empty groups are removed, too)
2476
17
        if ( pGroupDimension )
2477
7
        {
2478
7
            for (const OUString& aEntryName : rItems)
2479
14
            {
2480
14
                if ( pBaseGroupDim )
2481
0
                {
2482
                    // for each selected (intermediate) group, remove all its items
2483
                    // (same logic as for adding, below)
2484
0
                    const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
2485
0
                    if ( pBaseGroup )
2486
0
                        pBaseGroup->RemoveElementsFromGroups( *pGroupDimension );   // remove all elements
2487
0
                    else
2488
0
                        pGroupDimension->RemoveFromGroups( aEntryName );
2489
0
                }
2490
14
                else
2491
14
                    pGroupDimension->RemoveFromGroups( aEntryName );
2492
14
            }
2493
7
        }
2494
2495
17
        std::unique_ptr<ScDPSaveGroupDimension> pNewGroupDim;
2496
17
        if ( !pGroupDimension )
2497
10
        {
2498
            // create a new group dimension
2499
10
            sNewDim = pDimData->CreateGroupDimName( aBaseDimName, *pDPObj, false, nullptr );
2500
10
            pNewGroupDim.reset(new ScDPSaveGroupDimension( aBaseDimName, sNewDim ));
2501
2502
10
            pGroupDimension = pNewGroupDim.get();     // make changes to the new dim if none existed
2503
2504
10
            if ( pBaseGroupDim )
2505
0
            {
2506
                // If it's a higher-order group dimension, pre-allocate groups for all
2507
                // non-selected original groups, so the individual base members aren't
2508
                // used for automatic groups (this would make the original groups hard
2509
                // to find).
2510
                //! Also do this when removing groups?
2511
                //! Handle this case dynamically with automatic groups?
2512
2513
0
                tools::Long nGroupCount = pBaseGroupDim->GetGroupCount();
2514
0
                for ( tools::Long nGroup = 0; nGroup < nGroupCount; nGroup++ )
2515
0
                {
2516
0
                    const ScDPSaveGroupItem& rBaseGroup = pBaseGroupDim->GetGroupByIndex( nGroup );
2517
2518
0
                    if (std::find(rItems.begin(), rItems.end(), rBaseGroup.GetGroupName()) == rItems.end())    //! ignore case?
2519
0
                    {
2520
                        // add an additional group for each item that is not in the selection
2521
0
                        ScDPSaveGroupItem aGroup( rBaseGroup.GetGroupName() );
2522
0
                        aGroup.AddElementsFromGroup( rBaseGroup );
2523
0
                        pGroupDimension->AddGroupItem( aGroup );
2524
0
                    }
2525
0
                }
2526
0
            }
2527
10
        }
2528
17
        OUString aGroupDimName = pGroupDimension->GetGroupDimName();
2529
2530
17
        ScDPSaveGroupItem aGroup(pGroupDimension->CreateGroupName(ScResId(STR_PIVOT_GROUP)));
2531
17
        for (const OUString& aEntryName : rItems)
2532
24
        {
2533
24
            if ( pBaseGroupDim )
2534
0
            {
2535
                // for each selected (intermediate) group, add all its items
2536
0
                const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
2537
0
                if ( pBaseGroup )
2538
0
                    aGroup.AddElementsFromGroup( *pBaseGroup );
2539
0
                else
2540
0
                    aGroup.AddElement( aEntryName );    // no group found -> automatic group, add the item itself
2541
0
            }
2542
24
            else
2543
24
                aGroup.AddElement( aEntryName );        // no group dimension, add all items directly
2544
24
        }
2545
2546
17
        pGroupDimension->AddGroupItem( aGroup );
2547
2548
17
        if ( pNewGroupDim )
2549
10
        {
2550
10
            pDimData->AddGroupDimension( *pNewGroupDim );
2551
10
            pNewGroupDim.reset();        // AddGroupDimension copies the object
2552
            // don't access pGroupDimension after here
2553
10
        }
2554
17
        pGroupDimension = nullptr;
2555
2556
        // set orientation
2557
17
        ScDPSaveDimension* pSaveDimension = aSaveData.GetDimensionByName( aGroupDimName );
2558
17
        if ( pSaveDimension->GetOrientation() == DataPilotFieldOrientation_HIDDEN )
2559
17
        {
2560
17
            ScDPSaveDimension* pOldDimension = aSaveData.GetDimensionByName( aDimName );
2561
17
            pSaveDimension->SetOrientation( pOldDimension->GetOrientation() );
2562
17
            aSaveData.SetPosition( pSaveDimension, 0 ); //! before (immediate) base
2563
17
        }
2564
2565
        // apply changes
2566
17
        pDPObj->SetSaveData( aSaveData );
2567
17
        ScDBDocFunc(*GetDocShell()).RefreshPivotTableGroups(pDPObj);
2568
17
    }
2569
2570
    // if new grouping field has been created (on first group), return it
2571
17
    if( !sNewDim.isEmpty() )
2572
10
    {
2573
10
        try
2574
10
        {
2575
10
            xRet = mxParent->getScDataPilotFields()->getScDataPilotFieldObjByName(sNewDim);
2576
10
            SAL_WARN_IF(!xRet.is(), "sc.ui", "there is a name, so there should be also a field");
2577
10
        }
2578
10
        catch (const container::NoSuchElementException&)
2579
10
        {
2580
0
            css::uno::Any anyEx = cppu::getCaughtException();
2581
0
            SAL_WARN("sc.ui", "Cannot find field with that name: " + sNewDim + ".");
2582
            // Avoid throwing exception that's not specified in the method signature.
2583
0
            throw css::lang::WrappedTargetRuntimeException(
2584
0
                    "Cannot find field with name \"" + sNewDim + "\"",
2585
0
                    getXWeak(), anyEx );
2586
0
        }
2587
10
    }
2588
17
    return xRet;
2589
17
}
2590
2591
Reference < XDataPilotField > SAL_CALL ScDataPilotFieldObj::createDateGroup( const DataPilotFieldGroupInfo& rInfo )
2592
0
{
2593
0
    return createScDateGroup(rInfo);
2594
0
}
2595
2596
rtl::Reference < ScDataPilotFieldObj > ScDataPilotFieldObj::createScDateGroup( const DataPilotFieldGroupInfo& rInfo )
2597
0
{
2598
0
    SolarMutexGuard aGuard;
2599
0
    using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
2600
2601
0
    if( !rInfo.HasDateValues )
2602
0
        throw IllegalArgumentException(u"HasDateValues is not set"_ustr, getXWeak(), 0);
2603
0
    if( !lclCheckMinMaxStep( rInfo ) )
2604
0
        throw IllegalArgumentException(u"min/max/step"_ustr, getXWeak(), 0);
2605
2606
    // only a single date flag is allowed
2607
0
    if( (rInfo.GroupBy == 0) || (rInfo.GroupBy > YEARS) || ((rInfo.GroupBy & (rInfo.GroupBy - 1)) != 0) )
2608
0
        throw IllegalArgumentException("Invalid GroupBy value: " + OUString::number(rInfo.GroupBy), getXWeak(), 0);
2609
2610
    // step must be zero, if something else than DAYS is specified
2611
0
    if( rInfo.Step >= ((rInfo.GroupBy == DAYS) ? 32768.0 : 1.0) )
2612
0
        throw IllegalArgumentException("Invalid step value: " + OUString::number(rInfo.Step), getXWeak(), 0);
2613
2614
0
    OUString aGroupDimName;
2615
0
    ScDPObject* pDPObj = nullptr;
2616
0
    if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
2617
0
    {
2618
0
        ScDPNumGroupInfo aInfo;
2619
0
        aInfo.mbEnable = true;
2620
0
        aInfo.mbDateValues = (rInfo.GroupBy == DAYS) && (rInfo.Step >= 1.0);
2621
0
        aInfo.mbAutoStart = rInfo.HasAutoStart;
2622
0
        aInfo.mbAutoEnd = rInfo.HasAutoEnd;
2623
0
        aInfo.mfStart = rInfo.Start;
2624
0
        aInfo.mfEnd = rInfo.End;
2625
0
        aInfo.mfStep = std::trunc( rInfo.Step );
2626
2627
        // create a local copy of the entire save data (will be written back below)
2628
0
        ScDPSaveData aSaveData = *pDPObj->GetSaveData();
2629
        // get or create dimension save data
2630
0
        ScDPDimensionSaveData& rDimData = *aSaveData.GetDimensionData();
2631
2632
        // find source dimension name
2633
0
        const OUString& rDimName = pDim->GetName();
2634
0
        const ScDPSaveGroupDimension* pGroupDim = rDimData.GetNamedGroupDim( rDimName );
2635
0
        OUString aSrcDimName = pGroupDim ? pGroupDim->GetSourceDimName() : rDimName;
2636
2637
        // find a group dimension for the base field, or get numeric grouping
2638
0
        pGroupDim = rDimData.GetFirstNamedGroupDim( aSrcDimName );
2639
0
        const ScDPSaveNumGroupDimension* pNumGroupDim = rDimData.GetNumGroupDim( aSrcDimName );
2640
2641
        // do not group by dates, if named groups or numeric grouping is present
2642
0
        bool bHasNamedGrouping = pGroupDim && !pGroupDim->GetDateInfo().mbEnable;
2643
0
        bool bHasNumGrouping = pNumGroupDim && pNumGroupDim->GetInfo().mbEnable && !pNumGroupDim->GetInfo().mbDateValues && !pNumGroupDim->GetDateInfo().mbEnable;
2644
0
        if( bHasNamedGrouping || bHasNumGrouping )
2645
0
            throw IllegalArgumentException();
2646
2647
0
        if( aInfo.mbDateValues )  // create day ranges grouping
2648
0
        {
2649
            // first remove all named group dimensions
2650
0
            while( pGroupDim )
2651
0
            {
2652
0
                OUString aGroupDimName2 = pGroupDim->GetGroupDimName();
2653
                // find next group dimension before deleting this group
2654
0
                pGroupDim = rDimData.GetNextNamedGroupDim( aGroupDimName2 );
2655
                // remove from dimension save data
2656
0
                rDimData.RemoveGroupDimension( aGroupDimName2 );
2657
                // also remove save data settings for the dimension that no longer exists
2658
0
                aSaveData.RemoveDimensionByName( aGroupDimName2 );
2659
0
            }
2660
            // create or replace the number grouping dimension
2661
0
            ScDPSaveNumGroupDimension aNumGroupDim( aSrcDimName, aInfo );
2662
0
            rDimData.ReplaceNumGroupDimension( aNumGroupDim );
2663
0
        }
2664
0
        else    // create date grouping
2665
0
        {
2666
            // collect all existing date flags
2667
0
            sal_Int32 nDateParts = rDimData.CollectDateParts( aSrcDimName );
2668
0
            if( nDateParts == 0 )
2669
0
            {
2670
                // insert numeric group dimension, if no date groups exist yet (or replace day range grouping)
2671
0
                ScDPSaveNumGroupDimension aNumGroupDim( aSrcDimName, aInfo, rInfo.GroupBy );
2672
0
                rDimData.ReplaceNumGroupDimension( aNumGroupDim );
2673
0
            }
2674
0
            else if( (nDateParts & rInfo.GroupBy) == 0 )    // do nothing if date field exists already
2675
0
            {
2676
                // create new named group dimension for additional date groups
2677
0
                aGroupDimName = rDimData.CreateDateGroupDimName( rInfo.GroupBy, *pDPObj, true, nullptr );
2678
0
                ScDPSaveGroupDimension aGroupDim( aSrcDimName, aGroupDimName, aInfo, rInfo.GroupBy );
2679
0
                rDimData.AddGroupDimension( aGroupDim );
2680
2681
                // set orientation of new named group dimension
2682
0
                ScDPSaveDimension& rSaveDim = *aSaveData.GetDimensionByName( aGroupDimName );
2683
0
                if( rSaveDim.GetOrientation() == DataPilotFieldOrientation_HIDDEN )
2684
0
                {
2685
0
                    ScDPSaveDimension& rOldDim = *aSaveData.GetDimensionByName( aSrcDimName );
2686
0
                    rSaveDim.SetOrientation( rOldDim.GetOrientation() );
2687
0
                    aSaveData.SetPosition( &rSaveDim, 0 );  //! before (immediate) base
2688
0
                }
2689
0
            }
2690
0
        }
2691
2692
        // apply changes
2693
0
        pDPObj->SetSaveData( aSaveData );
2694
0
        ScDBDocFunc(*GetDocShell()).RefreshPivotTableGroups(pDPObj);
2695
0
    }
2696
2697
    // return the UNO object of the new dimension, after writing back saved data
2698
0
    rtl::Reference< ScDataPilotFieldObj > xRet;
2699
0
    if( !aGroupDimName.isEmpty() )
2700
0
        try
2701
0
        {
2702
0
           xRet = mxParent->getScDataPilotFields()->getScDataPilotFieldObjByName( aGroupDimName );
2703
0
        }
2704
0
        catch( Exception& )
2705
0
        {
2706
0
        }
2707
0
    return xRet;
2708
0
}
2709
2710
namespace {
2711
2712
bool lclExtractGroupMembers( ScFieldGroupMembers& rMembers, const Any& rElement )
2713
0
{
2714
    // allow empty value to create a new group
2715
0
    if( !rElement.hasValue() )
2716
0
        return true;
2717
2718
    // try to extract a simple sequence of strings
2719
0
    Sequence< OUString > aSeq;
2720
0
    if( rElement >>= aSeq )
2721
0
    {
2722
0
        if( aSeq.hasElements() )
2723
0
            rMembers.insert( rMembers.end(), std::cbegin(aSeq), std::cend(aSeq) );
2724
0
        return true;
2725
0
    }
2726
2727
    // try to use XIndexAccess providing objects that support XNamed
2728
0
    Reference< XIndexAccess > xItemsIA( rElement, UNO_QUERY );
2729
0
    if( xItemsIA.is() )
2730
0
    {
2731
0
        for( sal_Int32 nIdx = 0, nCount = xItemsIA->getCount(); nIdx < nCount; ++nIdx )
2732
0
        {
2733
0
            try // getByIndex() should not throw, but we cannot be sure
2734
0
            {
2735
0
                Reference< XNamed > xItemName( xItemsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
2736
0
                rMembers.push_back( xItemName->getName() );
2737
0
            }
2738
0
            catch( Exception& )
2739
0
            {
2740
                // ignore exceptions, go ahead with next element in the array
2741
0
            }
2742
0
        }
2743
0
        return true;
2744
0
    }
2745
2746
    // nothing valid inside the Any -> return false
2747
0
    return false;
2748
0
}
2749
2750
} // namespace
2751
2752
ScDataPilotFieldGroupsObj::ScDataPilotFieldGroupsObj( ScFieldGroups&& rGroups ) :
2753
17
    maGroups( std::move(rGroups) )
2754
17
{
2755
17
}
2756
2757
ScDataPilotFieldGroupsObj::~ScDataPilotFieldGroupsObj()
2758
17
{
2759
17
}
2760
2761
// XNameAccess
2762
2763
Any SAL_CALL ScDataPilotFieldGroupsObj::getByName( const OUString& rName )
2764
0
{
2765
0
    SolarMutexGuard aGuard;
2766
0
    if( implFindByName( rName ) == maGroups.end() )
2767
0
        throw NoSuchElementException();
2768
0
    return Any( Reference< XNameAccess >( new ScDataPilotFieldGroupObj( *this, rName ) ) );
2769
0
}
2770
2771
Sequence< OUString > SAL_CALL ScDataPilotFieldGroupsObj::getElementNames()
2772
0
{
2773
0
    SolarMutexGuard aGuard;
2774
0
    Sequence< OUString > aSeq;
2775
0
    if( !maGroups.empty() )
2776
0
    {
2777
0
        aSeq.realloc( static_cast< sal_Int32 >( maGroups.size() ) );
2778
0
        OUString* pName = aSeq.getArray();
2779
0
        for( const auto& rGroup : maGroups )
2780
0
        {
2781
0
            *pName = rGroup.maName;
2782
0
            ++pName;
2783
0
        }
2784
0
    }
2785
0
    return aSeq;
2786
0
}
2787
2788
sal_Bool SAL_CALL ScDataPilotFieldGroupsObj::hasByName( const OUString& rName )
2789
0
{
2790
0
    SolarMutexGuard aGuard;
2791
0
    return implFindByName( rName ) != maGroups.end();
2792
0
}
2793
2794
// XNameReplace
2795
2796
void SAL_CALL ScDataPilotFieldGroupsObj::replaceByName( const OUString& rName, const Any& rElement )
2797
0
{
2798
0
    SolarMutexGuard aGuard;
2799
2800
0
    if( rName.isEmpty() )
2801
0
        throw IllegalArgumentException(u"Name is empty"_ustr, getXWeak(), 0);
2802
2803
0
    ScFieldGroups::iterator aIt = implFindByName( rName );
2804
0
    if( aIt == maGroups.end() )
2805
0
        throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
2806
2807
    // read all item names provided by the passed object
2808
0
    ScFieldGroupMembers aMembers;
2809
0
    if( !lclExtractGroupMembers( aMembers, rElement ) )
2810
0
        throw IllegalArgumentException(u"Invalid element object"_ustr, getXWeak(), 0);
2811
2812
    // copy and forget, faster than vector assignment
2813
0
    aIt->maMembers.swap( aMembers );
2814
0
}
2815
2816
// XNameContainer
2817
2818
void SAL_CALL ScDataPilotFieldGroupsObj::insertByName( const OUString& rName, const Any& rElement )
2819
0
{
2820
0
    SolarMutexGuard aGuard;
2821
2822
0
    if( rName.isEmpty() )
2823
0
        throw IllegalArgumentException(u"Name is empty"_ustr, getXWeak(), 0);
2824
2825
0
    ScFieldGroups::iterator aIt = implFindByName( rName );
2826
0
    if( aIt != maGroups.end() )
2827
0
        throw ElementExistException("Name \"" + rName + "\" already exists", getXWeak());
2828
2829
    // read all item names provided by the passed object
2830
0
    ScFieldGroupMembers aMembers;
2831
0
    if( !lclExtractGroupMembers( aMembers, rElement ) )
2832
0
        throw IllegalArgumentException(u"Invalid element object"_ustr, getXWeak(), 0);
2833
2834
    // create the new entry if no error has been occurred
2835
0
    maGroups.emplace_back();
2836
0
    ScFieldGroup& rGroup = maGroups.back();
2837
0
    rGroup.maName = rName;
2838
0
    rGroup.maMembers.swap( aMembers );
2839
0
}
2840
2841
void SAL_CALL ScDataPilotFieldGroupsObj::removeByName( const OUString& rName )
2842
0
{
2843
0
    SolarMutexGuard aGuard;
2844
2845
0
    if( rName.isEmpty() )
2846
0
        throw IllegalArgumentException(u"Name is empty"_ustr, getXWeak(), 0);
2847
2848
0
    ScFieldGroups::iterator aIt = implFindByName( rName );
2849
0
    if( aIt == maGroups.end() )
2850
0
        throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
2851
2852
0
    maGroups.erase( aIt );
2853
0
}
2854
2855
// XIndexAccess
2856
2857
sal_Int32 SAL_CALL ScDataPilotFieldGroupsObj::getCount()
2858
34
{
2859
34
    SolarMutexGuard aGuard;
2860
34
    return static_cast< sal_Int32 >( maGroups.size() );
2861
34
}
2862
2863
Any SAL_CALL ScDataPilotFieldGroupsObj::getByIndex( sal_Int32 nIndex )
2864
65
{
2865
65
    SolarMutexGuard aGuard;
2866
65
    if ((nIndex < 0) || (o3tl::make_unsigned(nIndex) >= maGroups.size()))
2867
0
        throw IndexOutOfBoundsException();
2868
65
    return Any( Reference< XNameAccess >( new ScDataPilotFieldGroupObj( *this, maGroups[ nIndex ].maName ) ) );
2869
65
}
2870
2871
// XEnumerationAccess
2872
2873
Reference<XEnumeration> SAL_CALL ScDataPilotFieldGroupsObj::createEnumeration()
2874
0
{
2875
0
    SolarMutexGuard aGuard;
2876
0
    return new ScIndexEnumeration( this, u"com.sun.star.sheet.DataPilotFieldGroupsEnumeration"_ustr );
2877
0
}
2878
2879
// XElementAccess
2880
2881
uno::Type SAL_CALL ScDataPilotFieldGroupsObj::getElementType()
2882
0
{
2883
0
    return cppu::UnoType<XNameAccess>::get();
2884
0
}
2885
2886
sal_Bool SAL_CALL ScDataPilotFieldGroupsObj::hasElements()
2887
0
{
2888
0
    SolarMutexGuard aGuard;
2889
0
    return !maGroups.empty();
2890
0
}
2891
2892
// implementation
2893
2894
ScFieldGroup& ScDataPilotFieldGroupsObj::getFieldGroup( const OUString& rName )
2895
79
{
2896
79
    SolarMutexGuard aGuard;
2897
79
    ScFieldGroups::iterator aIt = implFindByName( rName );
2898
79
    if( aIt == maGroups.end() )
2899
0
        throw RuntimeException("Field Group with name \"" + rName + "\" not found", getXWeak());
2900
79
    return *aIt;
2901
79
}
2902
2903
void ScDataPilotFieldGroupsObj::renameFieldGroup( const OUString& rOldName, const OUString& rNewName )
2904
17
{
2905
17
    SolarMutexGuard aGuard;
2906
17
    ScFieldGroups::iterator aOldIt = implFindByName( rOldName );
2907
17
    ScFieldGroups::iterator aNewIt = implFindByName( rNewName );
2908
17
    if( aOldIt == maGroups.end() )
2909
0
        throw RuntimeException("Field Group with name \"" + rOldName + "\" not found", getXWeak());
2910
    // new name must not exist yet
2911
17
    if( (aNewIt != maGroups.end()) && (aNewIt != aOldIt) )
2912
0
        throw RuntimeException("Field Group with name \"" + rOldName + "\" already exists", getXWeak());
2913
17
    aOldIt->maName = rNewName;
2914
17
}
2915
2916
ScFieldGroups::iterator ScDataPilotFieldGroupsObj::implFindByName( const OUString& rName )
2917
113
{
2918
113
    return std::find_if(maGroups.begin(), maGroups.end(),
2919
155
        [&rName](const ScFieldGroup& rGroup) { return rGroup.maName == rName; });
2920
113
}
2921
2922
namespace {
2923
2924
OUString lclExtractMember( const Any& rElement )
2925
0
{
2926
0
    if( rElement.has< OUString >() )
2927
0
        return rElement.get< OUString >();
2928
2929
0
    Reference< XNamed > xNamed( rElement, UNO_QUERY );
2930
0
    if( xNamed.is() )
2931
0
        return xNamed->getName();
2932
2933
0
    return OUString();
2934
0
}
2935
2936
} // namespace
2937
2938
ScDataPilotFieldGroupObj::ScDataPilotFieldGroupObj( ScDataPilotFieldGroupsObj& rParent, OUString aGroupName ) :
2939
65
    mxParent( &rParent ),
2940
65
    maGroupName(std::move( aGroupName ))
2941
65
{
2942
65
}
2943
2944
ScDataPilotFieldGroupObj::~ScDataPilotFieldGroupObj()
2945
65
{
2946
65
}
2947
2948
// XNameAccess
2949
2950
Any SAL_CALL ScDataPilotFieldGroupObj::getByName( const OUString& rName )
2951
0
{
2952
0
    SolarMutexGuard aGuard;
2953
0
    ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
2954
0
    ScFieldGroupMembers::iterator aIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
2955
0
    if( aIt == rMembers.end() )
2956
0
        throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
2957
0
    return Any( Reference< XNamed >( new ScDataPilotFieldGroupItemObj( *this, *aIt ) ) );
2958
0
}
2959
2960
Sequence< OUString > SAL_CALL ScDataPilotFieldGroupObj::getElementNames()
2961
0
{
2962
0
    SolarMutexGuard aGuard;
2963
0
    return ::comphelper::containerToSequence( mxParent->getFieldGroup( maGroupName ).maMembers );
2964
0
}
2965
2966
sal_Bool SAL_CALL ScDataPilotFieldGroupObj::hasByName( const OUString& rName )
2967
24
{
2968
24
    SolarMutexGuard aGuard;
2969
24
    ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
2970
24
    return ::std::find( rMembers.begin(), rMembers.end(), rName ) != rMembers.end();
2971
24
}
2972
2973
// XNameReplace
2974
2975
void SAL_CALL ScDataPilotFieldGroupObj::replaceByName( const OUString& rName, const Any& rElement )
2976
0
{
2977
0
    SolarMutexGuard aGuard;
2978
2979
    // it should be possible to quickly rename an item -> accept string or XNamed
2980
0
    OUString aNewName = lclExtractMember( rElement );
2981
0
    if( rName.isEmpty() || aNewName.isEmpty() )
2982
0
        throw IllegalArgumentException(u"Name is empty"_ustr, getXWeak(), 0);
2983
0
    if( rName == aNewName )
2984
0
        return;
2985
2986
0
    ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
2987
0
    ScFieldGroupMembers::iterator aOldIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
2988
0
    ScFieldGroupMembers::iterator aNewIt = ::std::find( rMembers.begin(), rMembers.end(), aNewName );
2989
0
    if( aOldIt == rMembers.end() )
2990
0
        throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
2991
0
    if( aNewIt != rMembers.end() )
2992
0
        throw IllegalArgumentException("Name \"" + rName + "\" already exists", getXWeak(), 0);
2993
0
    *aOldIt = aNewName;
2994
0
}
2995
2996
// XNameContainer
2997
2998
void SAL_CALL ScDataPilotFieldGroupObj::insertByName( const OUString& rName, const Any& /*rElement*/ )
2999
0
{
3000
0
    SolarMutexGuard aGuard;
3001
3002
    // we will ignore the passed element and just try to insert the name
3003
0
    if( rName.isEmpty() )
3004
0
        throw IllegalArgumentException(u"Name is empty"_ustr, getXWeak(), 0);
3005
3006
0
    ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
3007
0
    ScFieldGroupMembers::iterator aIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
3008
0
    if( aIt != rMembers.end() )
3009
0
        throw IllegalArgumentException("Name \"" + rName + "\" already exists", getXWeak(), 0);
3010
0
    rMembers.push_back( rName );
3011
0
}
3012
3013
void SAL_CALL ScDataPilotFieldGroupObj::removeByName( const OUString& rName )
3014
0
{
3015
0
    SolarMutexGuard aGuard;
3016
3017
0
    if( rName.isEmpty() )
3018
0
        throw IllegalArgumentException(u"Name is empty"_ustr, getXWeak(), 0);
3019
0
    ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
3020
0
    ScFieldGroupMembers::iterator aIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
3021
0
    if( aIt == rMembers.end() )
3022
0
        throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
3023
0
    rMembers.erase( aIt );
3024
0
}
3025
3026
// XIndexAccess
3027
3028
sal_Int32 SAL_CALL ScDataPilotFieldGroupObj::getCount()
3029
24
{
3030
24
    SolarMutexGuard aGuard;
3031
24
    return static_cast< sal_Int32 >( mxParent->getFieldGroup( maGroupName ).maMembers.size() );
3032
24
}
3033
3034
Any SAL_CALL ScDataPilotFieldGroupObj::getByIndex( sal_Int32 nIndex )
3035
31
{
3036
31
    SolarMutexGuard aGuard;
3037
31
    ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
3038
31
    if ((nIndex < 0) || (o3tl::make_unsigned(nIndex) >= rMembers.size()))
3039
0
        throw IndexOutOfBoundsException();
3040
31
    return Any( Reference< XNamed >( new ScDataPilotFieldGroupItemObj( *this, rMembers[ nIndex ] ) ) );
3041
31
}
3042
3043
// XEnumerationAccess
3044
3045
Reference< XEnumeration > SAL_CALL ScDataPilotFieldGroupObj::createEnumeration()
3046
0
{
3047
0
    SolarMutexGuard aGuard;
3048
0
    return new ScIndexEnumeration( this, u"com.sun.star.sheet.DataPilotFieldGroupEnumeration"_ustr );
3049
0
}
3050
3051
// XElementAccess
3052
3053
uno::Type SAL_CALL ScDataPilotFieldGroupObj::getElementType()
3054
0
{
3055
0
    return cppu::UnoType<XNamed>::get();
3056
0
}
3057
3058
sal_Bool SAL_CALL ScDataPilotFieldGroupObj::hasElements()
3059
0
{
3060
0
    SolarMutexGuard aGuard;
3061
0
    return !mxParent->getFieldGroup( maGroupName ).maMembers.empty();
3062
0
}
3063
3064
// XNamed
3065
3066
OUString SAL_CALL ScDataPilotFieldGroupObj::getName()
3067
41
{
3068
41
    SolarMutexGuard aGuard;
3069
41
    return maGroupName;
3070
41
}
3071
3072
void SAL_CALL ScDataPilotFieldGroupObj::setName( const OUString& rName )
3073
17
{
3074
17
    SolarMutexGuard aGuard;
3075
17
    mxParent->renameFieldGroup( maGroupName, rName );
3076
    // if call to renameFieldGroup() did not throw, remember the new name
3077
17
    maGroupName = rName;
3078
17
}
3079
3080
ScDataPilotFieldGroupItemObj::ScDataPilotFieldGroupItemObj( ScDataPilotFieldGroupObj& rParent, OUString aName ) :
3081
31
    mxParent( &rParent ),
3082
31
    maName(std::move( aName ))
3083
31
{
3084
31
}
3085
3086
ScDataPilotFieldGroupItemObj::~ScDataPilotFieldGroupItemObj()
3087
31
{
3088
31
}
3089
3090
// XNamed
3091
3092
OUString SAL_CALL ScDataPilotFieldGroupItemObj::getName()
3093
31
{
3094
31
    SolarMutexGuard aGuard;
3095
31
    return maName;
3096
31
}
3097
3098
void SAL_CALL ScDataPilotFieldGroupItemObj::setName( const OUString& rName )
3099
0
{
3100
0
    SolarMutexGuard aGuard;
3101
0
    mxParent->replaceByName( maName, Any( rName ) );
3102
    // if call to replaceByName() did not throw, remember the new name
3103
0
    maName = rName;
3104
0
}
3105
3106
ScDataPilotItemsObj::ScDataPilotItemsObj( ScDataPilotDescriptorBase& rParent, const ScFieldIdentifier& rFieldId ) :
3107
0
    ScDataPilotChildObjBase( rParent, rFieldId )
3108
0
{
3109
0
}
3110
3111
ScDataPilotItemsObj::~ScDataPilotItemsObj()
3112
0
{
3113
0
}
3114
3115
// XDataPilotItems
3116
3117
ScDataPilotItemObj* ScDataPilotItemsObj::GetObjectByIndex_Impl( sal_Int32 nIndex ) const
3118
0
{
3119
0
    return ((0 <= nIndex) && (nIndex < GetMemberCount())) ?
3120
0
        new ScDataPilotItemObj( *mxParent, maFieldId, nIndex ) : nullptr;
3121
0
}
3122
3123
// XNameAccess
3124
3125
Any SAL_CALL ScDataPilotItemsObj::getByName( const OUString& aName )
3126
0
{
3127
0
    SolarMutexGuard aGuard;
3128
0
    Reference<XNameAccess> xMembers = GetMembers();
3129
0
    if (xMembers.is())
3130
0
    {
3131
0
        Reference<XIndexAccess> xMembersIndex(new ScNameToIndexAccess( xMembers ));
3132
0
        sal_Int32 nCount = xMembersIndex->getCount();
3133
0
        sal_Int32 nItem = 0;
3134
0
        while (nItem < nCount)
3135
0
        {
3136
0
            Reference<XNamed> xMember(xMembersIndex->getByIndex(nItem), UNO_QUERY);
3137
0
            if (xMember.is() && (aName == xMember->getName()))
3138
0
            {
3139
0
                return Any( Reference< XPropertySet >( GetObjectByIndex_Impl( nItem ) ) );
3140
0
            }
3141
0
            ++nItem;
3142
0
        }
3143
0
        throw NoSuchElementException("Name \"" + aName + "\" not found", getXWeak());
3144
0
    }
3145
0
    return Any();
3146
0
}
3147
3148
Sequence<OUString> SAL_CALL ScDataPilotItemsObj::getElementNames()
3149
0
{
3150
0
    SolarMutexGuard aGuard;
3151
0
    Sequence< OUString > aSeq;
3152
0
    if( ScDPObject* pDPObj = GetDPObject() )
3153
0
        pDPObj->GetMemberNames( lcl_GetObjectIndex( pDPObj, maFieldId ), aSeq );
3154
0
    return aSeq;
3155
0
}
3156
3157
sal_Bool SAL_CALL ScDataPilotItemsObj::hasByName( const OUString& aName )
3158
0
{
3159
0
    SolarMutexGuard aGuard;
3160
0
    bool bFound = false;
3161
0
    Reference<XNameAccess> xMembers = GetMembers();
3162
0
    if (xMembers.is())
3163
0
    {
3164
0
        Reference<XIndexAccess> xMembersIndex(new ScNameToIndexAccess( xMembers ));
3165
0
        sal_Int32 nCount = xMembersIndex->getCount();
3166
0
        sal_Int32 nItem = 0;
3167
0
        while (nItem < nCount && !bFound )
3168
0
        {
3169
0
            Reference<XNamed> xMember(xMembersIndex->getByIndex(nItem), UNO_QUERY);
3170
0
            if (xMember.is() && aName == xMember->getName())
3171
0
                bFound = true;
3172
0
            else
3173
0
                nItem++;
3174
0
        }
3175
0
    }
3176
0
    return bFound;
3177
0
}
3178
3179
// XEnumerationAccess
3180
3181
Reference<XEnumeration> SAL_CALL ScDataPilotItemsObj::createEnumeration()
3182
0
{
3183
0
    SolarMutexGuard aGuard;
3184
0
    return new ScIndexEnumeration(this, u"com.sun.star.sheet.DataPilotItemsEnumeration"_ustr);
3185
0
}
3186
3187
// XIndexAccess
3188
3189
sal_Int32 SAL_CALL ScDataPilotItemsObj::getCount()
3190
0
{
3191
0
    SolarMutexGuard aGuard;
3192
0
    return GetMemberCount();
3193
0
}
3194
3195
Any SAL_CALL ScDataPilotItemsObj::getByIndex( sal_Int32 nIndex )
3196
0
{
3197
0
    SolarMutexGuard aGuard;
3198
0
    Reference< XPropertySet > xItem( GetObjectByIndex_Impl( nIndex ) );
3199
0
    if (!xItem.is())
3200
0
        throw IndexOutOfBoundsException();
3201
0
    return Any( xItem );
3202
0
}
3203
3204
uno::Type SAL_CALL ScDataPilotItemsObj::getElementType()
3205
0
{
3206
0
    return cppu::UnoType<XPropertySet>::get();
3207
0
}
3208
3209
sal_Bool SAL_CALL ScDataPilotItemsObj::hasElements()
3210
0
{
3211
0
    SolarMutexGuard aGuard;
3212
0
    return ( getCount() != 0 );
3213
0
}
3214
3215
ScDataPilotItemObj::ScDataPilotItemObj( ScDataPilotDescriptorBase& rParent, const ScFieldIdentifier& rFieldId, sal_Int32 nIndex ) :
3216
0
    ScDataPilotChildObjBase( rParent, rFieldId ),
3217
0
    maPropSet( lcl_GetDataPilotItemMap() ),
3218
0
    mnIndex( nIndex )
3219
0
{
3220
0
}
3221
3222
ScDataPilotItemObj::~ScDataPilotItemObj()
3223
0
{
3224
0
}
3225
3226
                            // XNamed
3227
OUString SAL_CALL ScDataPilotItemObj::getName()
3228
0
{
3229
0
    SolarMutexGuard aGuard;
3230
0
    OUString sRet;
3231
0
    Reference<XNameAccess> xMembers = GetMembers();
3232
0
    if (xMembers.is())
3233
0
    {
3234
0
        Reference<XIndexAccess> xMembersIndex(new ScNameToIndexAccess( xMembers ));
3235
0
        sal_Int32 nCount = xMembersIndex->getCount();
3236
0
        if (mnIndex < nCount)
3237
0
        {
3238
0
            Reference<XNamed> xMember(xMembersIndex->getByIndex(mnIndex), UNO_QUERY);
3239
0
            sRet = xMember->getName();
3240
0
        }
3241
0
    }
3242
0
    return sRet;
3243
0
}
3244
3245
void SAL_CALL ScDataPilotItemObj::setName( const OUString& /* aName */ )
3246
0
{
3247
0
}
3248
3249
                            // XPropertySet
3250
Reference< XPropertySetInfo >
3251
                            SAL_CALL ScDataPilotItemObj::getPropertySetInfo(  )
3252
0
{
3253
0
    SolarMutexGuard aGuard;
3254
0
    static Reference<XPropertySetInfo> aRef =
3255
0
        new SfxItemPropertySetInfo( maPropSet.getPropertyMap() );
3256
0
    return aRef;
3257
0
}
3258
3259
void SAL_CALL ScDataPilotItemObj::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
3260
0
{
3261
0
    SolarMutexGuard aGuard;
3262
0
    ScDPObject* pDPObj = nullptr;
3263
0
    ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
3264
0
    if(!pDim)
3265
0
        return;
3266
3267
0
    Reference<XNameAccess> xMembers = GetMembers();
3268
0
    if( !xMembers.is() )
3269
0
        return;
3270
3271
0
    Reference<XIndexAccess> xMembersIndex( new ScNameToIndexAccess( xMembers ) );
3272
0
    sal_Int32 nCount = xMembersIndex->getCount();
3273
0
    if( mnIndex >= nCount )
3274
0
        return;
3275
3276
0
    Reference<XNamed> xMember(xMembersIndex->getByIndex(mnIndex), UNO_QUERY);
3277
0
    OUString sName(xMember->getName());
3278
0
    ScDPSaveMember* pMember = pDim->GetMemberByName(sName);
3279
0
    if (!pMember)
3280
0
        return;
3281
3282
0
    bool bGetNewIndex = false;
3283
0
    if ( aPropertyName == SC_UNONAME_SHOWDETAIL )
3284
0
        pMember->SetShowDetails(cppu::any2bool(aValue));
3285
0
    else if ( aPropertyName == SC_UNONAME_ISHIDDEN )
3286
0
        pMember->SetIsVisible(!cppu::any2bool(aValue));
3287
0
    else if ( aPropertyName == SC_UNONAME_POS )
3288
0
    {
3289
0
        sal_Int32 nNewPos = 0;
3290
0
        if ( !( aValue >>= nNewPos ) || nNewPos < 0 || nNewPos >= nCount )
3291
0
            throw IllegalArgumentException();
3292
3293
0
        pDim->SetMemberPosition( sName, nNewPos );
3294
        // get new effective index (depends on sorting mode, which isn't modified)
3295
0
        bGetNewIndex = true;
3296
3297
0
    }
3298
0
    SetDPObject( pDPObj );
3299
3300
0
    if ( bGetNewIndex )     // after SetDPObject, get the new index
3301
0
    {
3302
0
        Sequence< OUString > aItemNames = xMembers->getElementNames();
3303
0
        sal_Int32 nItemCount = aItemNames.getLength();
3304
0
        for (sal_Int32 nItem=0; nItem<nItemCount; ++nItem)
3305
0
            if (aItemNames[nItem] == sName)
3306
0
                mnIndex = nItem;
3307
0
    }
3308
0
}
3309
3310
Any SAL_CALL ScDataPilotItemObj::getPropertyValue( const OUString& aPropertyName )
3311
0
{
3312
0
    SolarMutexGuard aGuard;
3313
0
    Any aRet;
3314
0
    if( ScDPSaveDimension* pDim = GetDPDimension() )
3315
0
    {
3316
0
        Reference< XNameAccess > xMembers = GetMembers();
3317
0
        if( xMembers.is() )
3318
0
        {
3319
0
            Reference< XIndexAccess > xMembersIndex( new ScNameToIndexAccess( xMembers ) );
3320
0
            sal_Int32 nCount = xMembersIndex->getCount();
3321
0
            if( mnIndex < nCount )
3322
0
            {
3323
0
                Reference< XNamed > xMember( xMembersIndex->getByIndex( mnIndex ), UNO_QUERY );
3324
0
                OUString sName( xMember->getName() );
3325
0
                ScDPSaveMember* pMember = pDim->GetExistingMemberByName( sName );
3326
0
                if ( aPropertyName == SC_UNONAME_SHOWDETAIL )
3327
0
                {
3328
0
                    if (pMember && pMember->HasShowDetails())
3329
0
                    {
3330
0
                        aRet <<= pMember->GetShowDetails();
3331
0
                    }
3332
0
                    else
3333
0
                    {
3334
0
                        Reference< XPropertySet > xMemberProps( xMember, UNO_QUERY );
3335
0
                        if( xMemberProps.is() )
3336
0
                            aRet = xMemberProps->getPropertyValue( SC_UNO_DP_SHOWDETAILS );
3337
0
                        else
3338
0
                            aRet <<= true;
3339
0
                    }
3340
0
                }
3341
0
                else if ( aPropertyName == SC_UNONAME_ISHIDDEN )
3342
0
                {
3343
0
                    if (pMember && pMember->HasIsVisible())
3344
0
                    {
3345
0
                        aRet <<= !pMember->GetIsVisible();
3346
0
                    }
3347
0
                    else
3348
0
                    {
3349
0
                        Reference< XPropertySet > xMemberProps( xMember, UNO_QUERY );
3350
0
                        if( xMemberProps.is() )
3351
0
                            aRet <<= !cppu::any2bool( xMemberProps->getPropertyValue( SC_UNO_DP_ISVISIBLE ) );
3352
0
                        else
3353
0
                            aRet <<= false;
3354
0
                    }
3355
0
                }
3356
0
                else if ( aPropertyName == SC_UNONAME_POS )
3357
0
                {
3358
0
                    aRet <<= mnIndex;
3359
0
                }
3360
0
            }
3361
0
        }
3362
0
    }
3363
0
    return aRet;
3364
0
}
3365
3366
void SAL_CALL ScDataPilotItemObj::addPropertyChangeListener(
3367
        const OUString& /* aPropertyName */, const Reference< XPropertyChangeListener >& /* xListener */ )
3368
0
{
3369
0
}
3370
3371
void SAL_CALL ScDataPilotItemObj::removePropertyChangeListener(
3372
        const OUString& /* aPropertyName */, const Reference< XPropertyChangeListener >& /* aListener */ )
3373
0
{
3374
0
}
3375
3376
void SAL_CALL ScDataPilotItemObj::addVetoableChangeListener(
3377
        const OUString& /* PropertyName */, const Reference< XVetoableChangeListener >& /* aListener */ )
3378
0
{
3379
0
}
3380
3381
void SAL_CALL ScDataPilotItemObj::removeVetoableChangeListener(
3382
        const OUString& /* PropertyName */, const Reference< XVetoableChangeListener >& /* aListener */ )
3383
0
{
3384
0
}
3385
3386
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */