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 #pragma once
21 
22 #include <com/sun/star/util/DateTime.hpp>
23 #include <oox/helper/containerhelper.hxx>
24 #include <oox/helper/refvector.hxx>
25 #include "workbookhelper.hxx"
26 
27 namespace oox { class AttributeList; }
28 namespace oox { class SequenceInputStream; }
29 
30 namespace com::sun::star {
31     namespace sheet { class XDataPilotField; }
32 }
33 
34 namespace oox::core { class Relations; }
35 
36 class ScDPSaveDimension;
37 class ScDPObject;
38 class DateTime;
39 
40 namespace oox::xls {
41 
42 class WorksheetHelper;
43 
44 typedef ::std::pair< sal_Int32, OUString > IdCaptionPair;
45 typedef ::std::vector< IdCaptionPair > IdCaptionPairList;
46 
47 class PivotCacheItem
48 {
49 public:
50     explicit            PivotCacheItem();
51 
52     /** Reads the string value from a pivot cache item. */
53     void                readString( const AttributeList& rAttribs );
54     /** Reads the double value from a pivot cache item. */
55     void                readNumeric( const AttributeList& rAttribs );
56     /** Reads the date/time value from a pivot cache item. */
57     void                readDate( const AttributeList& rAttribs );
58     /** Reads the boolean value from a pivot cache item. */
59     void                readBool( const AttributeList& rAttribs );
60     /** Reads the error code value from a pivot cache item. */
61     void                readError( const AttributeList& rAttribs );
62     /** Reads the index of a shared item. */
63     void                readIndex( const AttributeList& rAttribs );
64 
65     /** Reads the string value from a pivot cache item. */
66     void                readString( SequenceInputStream& rStrm );
67     /** Reads the double value from a pivot cache item. */
68     void                readDouble( SequenceInputStream& rStrm );
69     /** Reads the date/time value from a pivot cache item. */
70     void                readDate( SequenceInputStream& rStrm );
71     /** Reads the boolean value from a pivot cache item. */
72     void                readBool( SequenceInputStream& rStrm );
73     /** Reads the error code value from a pivot cache item. */
74     void                readError( SequenceInputStream& rStrm );
75     /** Reads the index of a shared item. */
76     void                readIndex( SequenceInputStream& rStrm );
77 
78     /** Returns the type of the item. */
getType() const79     sal_Int32    getType() const { return mnType; }
80     /** Returns the value of the item. */
getValue() const81     const css::uno::Any& getValue() const { return maValue; }
82     /** Returns the string representation of the item. */
83     OUString     getName() const;
84 
85     /** Returns the string representation of the item, using the actual formatting. */
86     OUString     getFormattedName(const ScDPSaveDimension& rSaveDim, ScDPObject* pObj, const DateTime& rNullDate) const;
87     /** Returns true if the item is unused. */
isUnused() const88     bool         isUnused() const { return mbUnused; }
89 
90 private:
91 friend class PivotCacheItemList;
92     // #FIXME hack Sets the value of this item to the given string ( and overwrites type if necessary
93     void                setStringValue( const OUString& sName );
94     css::uno::Any       maValue;     /// Value of the item.
95     sal_Int32           mnType;             /// Value type (OOXML token identifier).
96     bool                mbUnused;
97 };
98 
99 class PivotCacheItemList : public WorkbookHelper
100 {
101 public:
102     explicit            PivotCacheItemList( const WorkbookHelper& rHelper );
103 
104     /** Imports the item from the passed attribute list. */
105     void                importItem( sal_Int32 nElement, const AttributeList& rAttribs );
106     /** Imports the item from the passed stream and record. */
107     void                importItem( sal_Int32 nRecId, SequenceInputStream& rStrm );
108 
109     /** Returns true, if this item list is empty. */
empty() const110     bool         empty() const { return maItems.empty(); }
111     /** Returns the size of the item list. */
size() const112     size_t       size() const { return maItems.size(); }
113 
114     /** Returns the specified item. */
115     const PivotCacheItem* getCacheItem( sal_Int32 nItemIdx ) const;
116     /** Returns the names of all items. */
117     void                getCacheItemNames( ::std::vector< OUString >& orItemNames ) const;
118     void                applyItemCaptions( const IdCaptionPairList& vCaptions );
119 
120 private:
121     /** Creates and returns a new item at the end of the items list. */
122     PivotCacheItem&     createItem();
123     /** Imports an array of items from the PCITEM_ARRAY record */
124     void                importArray( SequenceInputStream& rStrm );
125 
126 private:
127     std::vector< PivotCacheItem >  maItems;            /// All items of this list.
128 };
129 
130 struct PCFieldModel
131 {
132     OUString     maName;             /// Fixed name of the cache field.
133     OUString     maCaption;          /// Caption of the cache field.
134     OUString     maPropertyName;     /// OLAP property name.
135     OUString     maFormula;          /// Formula of a calculated field.
136     sal_Int32           mnNumFmtId;         /// Number format for all items.
137     sal_Int32           mnSqlType;          /// Data type from ODBC data source.
138     sal_Int32           mnHierarchy;        /// Hierarchy this field is part of.
139     sal_Int32           mnLevel;            /// Hierarchy level this field is part of.
140     sal_Int32           mnMappingCount;     /// Number of property mappings.
141     bool                mbDatabaseField;    /// True = field from source data; false = calculated field.
142     bool                mbServerField;      /// True = ODBC server-based page field.
143     bool                mbUniqueList;       /// True = list of unique ODBC items exists.
144     bool                mbMemberPropField;  /// True = contains OLAP member properties.
145 
146     explicit            PCFieldModel();
147 };
148 
149 struct PCSharedItemsModel
150 {
151     bool                mbHasSemiMixed;     /// True = has (blank|string|bool|error) item(s), maybe other types.
152     bool                mbHasNonDate;       /// True = has non-date item(s), maybe date items.
153     bool                mbHasDate;          /// True = has date item(s), maybe other types.
154     bool                mbHasString;        /// True = has (string|bool|error) item(s), maybe other types.
155     bool                mbHasBlank;         /// True = has blank item(s), maybe other types.
156     bool                mbHasMixed;         /// True = has [(string|bool|error) and (number|date)] or (number and date).
157     bool                mbIsNumeric;        /// True = has numeric item(s), maybe other types except date.
158     bool                mbIsInteger;        /// True = has numeric item(s) with only integers, maybe other types except date.
159     bool                mbHasLongText;      /// True = contains strings with >255 characters.
160 
161     explicit            PCSharedItemsModel();
162 };
163 
164 struct PCFieldGroupModel
165 {
166     css::util::DateTime maStartDate;   /// Manual or calculated start date for range grouping.
167     css::util::DateTime maEndDate;     /// Manual or calculated end date for range grouping.
168     double              mfStartValue;       /// Manual or calculated start value for range grouping.
169     double              mfEndValue;         /// Manual or calculated end value for range grouping.
170     double              mfInterval;         /// Interval for numeric range grouping.
171     sal_Int32           mnParentField;      /// Index of cache field that contains item groups based on this field.
172     sal_Int32           mnBaseField;        /// Index of cache field this grouped field is based on.
173     sal_Int32           mnGroupBy;          /// Type of numeric or date range grouping.
174     bool                mbRangeGroup;       /// True = items are grouped by numeric ranges or date ranges.
175     bool                mbDateGroup;        /// True = items are grouped by date ranges or by item names.
176     bool                mbAutoStart;        /// True = start value for range groups is calculated from source data.
177     bool                mbAutoEnd;          /// True = end value for range groups is calculated from source data.
178     OUString            msFinalGroupName ;  /// Finalized group name of this field used in internal pivot table collection.
179 
180 
181     explicit            PCFieldGroupModel();
182 
183     /** Sets the group-by value for BIFF import. */
184     void                setBiffGroupBy( sal_uInt8 nGroupBy );
185 };
186 
187 /** Helper struct for mapping original item names from/to group item names. */
188 struct PivotCacheGroupItem
189 {
190     OUString     maOrigName;
191     OUString     maGroupName;
192 
PivotCacheGroupItemoox::xls::PivotCacheGroupItem193     explicit     PivotCacheGroupItem( const OUString& rItemName ) :
194                             maOrigName( rItemName ), maGroupName( rItemName ) {}
195 };
196 
197 typedef ::std::vector< PivotCacheGroupItem > PivotCacheGroupItemVector;
198 
199 class PivotCacheField : public WorkbookHelper
200 {
201 public:
202     explicit            PivotCacheField( const WorkbookHelper& rHelper, bool bIsDatabaseField );
203 
204     /** Imports pivot cache field settings from the cacheField element. */
205     void                importCacheField( const AttributeList& rAttribs );
206     /** Imports shared items settings from the sharedItems element. */
207     void                importSharedItems( const AttributeList& rAttribs );
208     /** Imports a shared item from the passed element. */
209     void                importSharedItem( sal_Int32 nElement, const AttributeList& rAttribs );
210     /** Imports grouping settings from the fieldGroup element. */
211     void                importFieldGroup( const AttributeList& rAttribs );
212     /** Imports numeric grouping settings from the rangePr element. */
213     void                importRangePr( const AttributeList& rAttribs );
214     /** Imports an item of the mapping between group items and base items from the passed element. */
215     void                importDiscretePrItem( sal_Int32 nElement, const AttributeList& rAttribs );
216     /** Imports a group item from the passed element. */
217     void                importGroupItem( sal_Int32 nElement, const AttributeList& rAttribs );
218 
219     /** Imports pivot cache field settings from the PCDFIELD record. */
220     void                importPCDField( SequenceInputStream& rStrm );
221     /** Imports shared items settings from the PCDFSHAREDITEMS record. */
222     void                importPCDFSharedItems( SequenceInputStream& rStrm );
223     /** Imports one or more shared items from the passed record. */
224     void                importPCDFSharedItem( sal_Int32 nRecId, SequenceInputStream& rStrm );
225     /** Imports grouping settings from the PCDFIELDGROUP record. */
226     void                importPCDFieldGroup( SequenceInputStream& rStrm );
227     /** Imports numeric grouping settings from the PCDFRANGEPR record. */
228     void                importPCDFRangePr( SequenceInputStream& rStrm );
229     /** Imports an item of the mapping between group items and base items from the passed record. */
230     void                importPCDFDiscretePrItem( sal_Int32 nRecId, SequenceInputStream& rStrm );
231     /** Imports one or more group items from the passed record. */
232     void                importPCDFGroupItem( sal_Int32 nRecId, SequenceInputStream& rStrm );
233 
234     /** Apply user Captions to imported group data */
235     void                applyItemCaptions( const IdCaptionPairList& vCaptions );
236 
237     /** Returns true, if the field is based on source data, or false if it is grouped or calculated. */
isDatabaseField() const238     bool         isDatabaseField() const { return maFieldModel.mbDatabaseField; }
239 
240     /** Returns true, if the field contains a list of shared items. */
hasSharedItems() const241     bool         hasSharedItems() const { return !maSharedItems.empty(); }
242     /** Returns true, if the field contains a list of grouping items. */
hasGroupItems() const243     bool         hasGroupItems() const { return !maGroupItems.empty(); }
244     /** Returns true, if the field has inplace numeric grouping settings. */
hasNumericGrouping() const245     bool         hasNumericGrouping() const { return maFieldGroupModel.mbRangeGroup && !maFieldGroupModel.mbDateGroup; }
246     /** Returns true, if the field has inplace date grouping settings. */
hasDateGrouping() const247     bool         hasDateGrouping() const { return maFieldGroupModel.mbRangeGroup && maFieldGroupModel.mbDateGroup; }
248     /** Returns true, if the field has a parent group field that groups the items of this field. */
hasParentGrouping() const249     bool         hasParentGrouping() const { return maFieldGroupModel.mnParentField >= 0; }
250 
251     /** Returns the name of the cache field. */
getName() const252     const OUString& getName() const { return maFieldModel.maName; }
253     /** Returns the index of the parent group field that groups the items of this field. */
getParentGroupField() const254     sal_Int32    getParentGroupField() const { return maFieldGroupModel.mnParentField; }
255     /** Returns the index of the base field grouping is based on. */
getGroupBaseField() const256     sal_Int32    getGroupBaseField() const { return maFieldGroupModel.mnBaseField; }
257     /** Returns the finalized group name of this field.  */
getFinalGroupName() const258     const OUString& getFinalGroupName() const { return maFieldGroupModel.msFinalGroupName; }
259     /** Set the finalized group name of this field.  */
setFinalGroupName(const OUString & rFinalGroupName)260     void            setFinalGroupName(const OUString& rFinalGroupName) { maFieldGroupModel.msFinalGroupName = rFinalGroupName; }
261 
262     /** Returns the shared or group item with the specified index. */
263     const PivotCacheItem* getCacheItem( sal_Int32 nItemIdx ) const;
264     /** Returns the names of all shared or group items. */
265     void                getCacheItemNames( ::std::vector< OUString >& orItemNames ) const;
266     /** Returns shared or group items. */
267     const PivotCacheItemList&  getCacheItems() const;
268 
269     /** Creates inplace numeric grouping settings. */
270     void                convertNumericGrouping(
271                             const css::uno::Reference< css::sheet::XDataPilotField >& rxDPField ) const;
272     /** Creates inplace date grouping settings or a new date group field. */
273     OUString     createDateGroupField(
274                             const css::uno::Reference< css::sheet::XDataPilotField >& rxBaseDPField ) const;
275     /** Creates a new grouped DataPilot field and returns its name. */
276     OUString     createParentGroupField(
277                             const css::uno::Reference< css::sheet::XDataPilotField >& rxBaseDPField,
278                             const PivotCacheField& rBaseCacheField,
279                             PivotCacheGroupItemVector& orItemNames ) const;
280 
281     /** Writes the title of the field into the passed sheet at the passed address. */
282     void                writeSourceHeaderCell( const WorksheetHelper& rSheetHelper,
283                             sal_Int32 nCol, sal_Int32 nRow ) const;
284     /** Writes a source field item value into the passed sheet. */
285     void                writeSourceDataCell( const WorksheetHelper& rSheetHelper,
286                             sal_Int32 nCol, sal_Int32 nRow,
287                             const PivotCacheItem& rItem ) const;
288 
289     /** Reads an item from the PCRECORD record and writes it to the passed sheet. */
290     void                importPCRecordItem( SequenceInputStream& rStrm,
291                             const WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const;
292 
293 private:
294     /** Tries to write the passed value to the passed sheet position. */
295     static void         writeItemToSourceDataCell( const WorksheetHelper& rSheetHelper,
296                             sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem );
297     /** Tries to write the value of a shared item to the passed sheet position. */
298     void                writeSharedItemToSourceDataCell( const WorksheetHelper& rSheetHelper,
299                             sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nItemIdx ) const;
300 
301 private:
302     typedef ::std::vector< sal_Int32 > IndexVector;
303 
304     PivotCacheItemList  maSharedItems;      /// All shared items of this field.
305     PivotCacheItemList  maGroupItems;       /// All group items of this field.
306     IndexVector         maDiscreteItems;    /// Mapping between group and base items.
307     PCFieldModel        maFieldModel;       /// Settings for this cache field.
308     PCSharedItemsModel  maSharedItemsModel; /// Settings for shared items.
309     PCFieldGroupModel   maFieldGroupModel;  /// Settings for item grouping.
310 };
311 
312 struct PCDefinitionModel
313 {
314     OUString     maRelId;            /// Relation identifier for cache records fragment.
315     OUString     maRefreshedBy;      /// Name of user who last refreshed the cache.
316     double              mfRefreshedDate;    /// Date/time of last refresh.
317     sal_Int32           mnRecords;          /// Number of data records in the cache.
318     sal_Int32           mnMissItemsLimit;   /// Limit for discarding unused items.
319     bool                mbInvalid;          /// True = cache needs refresh.
320     bool                mbSaveData;         /// True = cached item values are present.
321     bool                mbRefreshOnLoad;    /// True = try to refresh cache on load.
322     bool                mbOptimizeMemory;   /// True = application may optimize memory usage.
323     bool                mbEnableRefresh;    /// True = refreshing cache is enabled in UI.
324     bool                mbBackgroundQuery;  /// True = application queries data asynchronously.
325     bool                mbUpgradeOnRefresh; /// True = application may upgrade cache version.
326     bool                mbTupleCache;       /// True = cache stores OLAP functions.
327     bool                mbSupportSubquery;  /// True = data source supports subqueries.
328     bool                mbSupportDrill;     /// True = data source supports drilldown.
329 
330     explicit            PCDefinitionModel();
331 };
332 
333 struct PCSourceModel
334 {
335     sal_Int32           mnSourceType;       /// Type of the source data (sheet, consolidation, scenario, external).
336     sal_Int32           mnConnectionId;     /// Connection identifier for external data source.
337 
338     explicit            PCSourceModel();
339 };
340 
341 struct PCWorksheetSourceModel
342 {
343     OUString     maRelId;            /// Relation identifier for an external document URL.
344     OUString     maSheet;            /// Sheet name for cell range or sheet-local defined names.
345     OUString     maDefName;          /// Defined name containing a cell range if present.
346     ScRange      maRange;            /// Source cell range of the data.
347 
348     explicit            PCWorksheetSourceModel();
349 };
350 
351 class PivotCache : public WorkbookHelper
352 {
353 public:
354     explicit            PivotCache( const WorkbookHelper& rHelper );
355 
356     /** Reads pivot cache global settings from the pivotCacheDefinition element. */
357     void                importPivotCacheDefinition( const AttributeList& rAttribs );
358     /** Reads cache source settings from the cacheSource element. */
359     void                importCacheSource( const AttributeList& rAttribs );
360     /** Reads sheet source settings from the worksheetSource element. */
361     void                importWorksheetSource( const AttributeList& rAttribs, const ::oox::core::Relations& rRelations );
362 
363     /** Reads pivot cache global settings from the PCDEFINITION record. */
364     void                importPCDefinition( SequenceInputStream& rStrm );
365     /** Reads cache source settings from the PCDSOURCE record. */
366     void                importPCDSource( SequenceInputStream& rStrm );
367     /** Reads sheet source settings from the PCDSHEETSOURCE record. */
368     void                importPCDSheetSource( SequenceInputStream& rStrm, const ::oox::core::Relations& rRelations );
369 
370     /** Creates and returns a new pivot cache field. */
371     PivotCacheField&    createCacheField();
372     /** Checks validity of source data and creates a dummy data sheet for external sheet sources. */
373     void                finalizeImport();
374 
375     /** Returns true, if the pivot cache is based on a valid data source, so
376         that pivot tables can be created based on this pivot cache. */
isValidDataSource() const377     bool         isValidDataSource() const { return mbValidSource; }
378     /** Returns true, if the pivot cache is based on a dummy sheet created in finalizeImport. */
isBasedOnDummySheet() const379     bool         isBasedOnDummySheet() const { return mbDummySheet; }
380     /** Returns the internal cell range the cache is based on. */
381     const ScRange&
getSourceRange() const382                         getSourceRange() const { return maSheetSrcModel.maRange; }
383     /** Returns the relation identifier of the pivot cache records fragment. */
getRecordsRelId() const384     const OUString& getRecordsRelId() const { return maDefModel.maRelId; }
385 
386     /** Returns the cache field with the specified index. */
387     PivotCacheField* getCacheField( sal_Int32 nFieldIdx );
388     const PivotCacheField* getCacheField( sal_Int32 nFieldIdx ) const;
389     /** Returns the source column index of the field with the passed index. */
390     sal_Int32           getCacheDatabaseIndex( sal_Int32 nFieldIdx ) const;
391 
392     /** Writes the titles of all source fields into the passed sheet. */
393     void                writeSourceHeaderCells( const WorksheetHelper& rSheetHelper ) const;
394     /** Writes a source field item value into the passed sheet. */
395     void                writeSourceDataCell( const WorksheetHelper& rSheetHelper,
396                             sal_Int32 nColIdx, sal_Int32 nRowIdx,
397                             const PivotCacheItem& rItem ) const;
398 
399     /** Reads a PCRECORD record and writes all item values to the passed sheet. */
400     void                importPCRecord( SequenceInputStream& rStrm,
401                             const WorksheetHelper& rSheetHelper, sal_Int32 nRowIdx ) const;
402 
403 private:
404 
405     /** Finalizes the pivot cache if it is based on internal sheet data. */
406     void                finalizeInternalSheetSource();
407     /** Finalizes the pivot cache if it is based on sheet data of an external spreadsheet document. */
408     void                finalizeExternalSheetSource();
409     /** Creates a dummy sheet that will be filled with the pivot cache data. */
410     void                prepareSourceDataSheet();
411     /** Checks, if the row index has changed since last call, and initializes the sheet data buffer. */
412     void                updateSourceDataRow( const WorksheetHelper& rSheetHelper, sal_Int32 nRow ) const;
413 
414 private:
415     typedef RefVector< PivotCacheField >    PivotCacheFieldVector;
416     typedef ::std::vector< sal_Int32 >      IndexVector;
417 
418     PivotCacheFieldVector maFields;         /// All pivot cache fields.
419     PivotCacheFieldVector maDatabaseFields; /// All cache fields that are based on source data.
420     IndexVector         maDatabaseIndexes;  /// Database field index for all fields.
421     PCDefinitionModel   maDefModel;         /// Global pivot cache settings.
422     PCSourceModel       maSourceModel;      /// Pivot cache source settings.
423     PCWorksheetSourceModel maSheetSrcModel; /// Sheet source data if cache type is sheet.
424     ValueRangeSet       maColSpans;         /// Column spans used by SheetDataBuffer for optimized cell import.
425     OUString     maTargetUrl;        /// URL of an external source document.
426     mutable sal_Int32   mnCurrRow;          /// Current row index in dummy sheet.
427     bool                mbValidSource;      /// True = pivot cache is based on supported data source.
428     bool                mbDummySheet;       /// True = pivot cache is based on a dummy sheet.
429 };
430 
431 class PivotCacheBuffer : public WorkbookHelper
432 {
433 public:
434     explicit            PivotCacheBuffer( const WorkbookHelper& rHelper );
435 
436     /** Registers a pivot cache definition fragment. The fragment will be loaded on demand (OOXML/BIFF12 only). */
437     void                registerPivotCacheFragment( sal_Int32 nCacheId, const OUString& rFragmentPath );
438 
439     /** Imports and stores a pivot cache definition fragment on first call,
440         returns the imported cache on subsequent calls with the same identifier. */
441     PivotCache*         importPivotCacheFragment( sal_Int32 nCacheId );
442 
443 private:
444     /** Creates and returns a new pivot cache object with the passed identifier. */
445     PivotCache&         createPivotCache( sal_Int32 nCacheId );
446 
447 private:
448     typedef ::std::map< sal_Int32, OUString >    FragmentPathMap;
449     typedef RefMap< sal_Int32, PivotCache >             PivotCacheMap;
450 
451     FragmentPathMap           maFragmentPaths;
452     PivotCacheMap             maCaches;
453     std::vector< sal_Int32 >  maCacheIds;
454 };
455 
456 } // namespace oox::xls
457 
458 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
459