1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "oox/xls/pivotcachebuffer.hxx"
25
26 #include <set>
27 #include <com/sun/star/container/XIndexAccess.hpp>
28 #include <com/sun/star/container/XNameAccess.hpp>
29 #include <com/sun/star/container/XNamed.hpp>
30 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
31 #include <com/sun/star/sheet/DataPilotFieldGroupInfo.hpp>
32 #include <com/sun/star/sheet/XDataPilotFieldGrouping.hpp>
33 #include <rtl/ustrbuf.hxx>
34 #include "oox/core/filterbase.hxx"
35 #include "oox/helper/attributelist.hxx"
36 #include "oox/helper/containerhelper.hxx"
37 #include "oox/helper/propertyset.hxx"
38 #include "oox/xls/biffinputstream.hxx"
39 #include "oox/xls/defnamesbuffer.hxx"
40 #include "oox/xls/excelhandlers.hxx"
41 #include "oox/xls/pivotcachefragment.hxx"
42 #include "oox/xls/sheetdatabuffer.hxx"
43 #include "oox/xls/tablebuffer.hxx"
44 #include "oox/xls/unitconverter.hxx"
45 #include "oox/xls/worksheetbuffer.hxx"
46
47 namespace oox {
48 namespace xls {
49
50 // ============================================================================
51
52 using namespace ::com::sun::star::container;
53 using namespace ::com::sun::star::sheet;
54 using namespace ::com::sun::star::table;
55 using namespace ::com::sun::star::uno;
56 using namespace ::com::sun::star::util;
57
58 using ::oox::core::Relations;
59 using ::rtl::OUString;
60 using ::rtl::OUStringBuffer;
61
62 // ============================================================================
63
64 namespace {
65
66 const sal_uInt16 BIFF12_PCDFIELD_SERVERFIELD = 0x0001;
67 const sal_uInt16 BIFF12_PCDFIELD_NOUNIQUEITEMS = 0x0002;
68 const sal_uInt16 BIFF12_PCDFIELD_DATABASEFIELD = 0x0004;
69 const sal_uInt16 BIFF12_PCDFIELD_HASCAPTION = 0x0008;
70 const sal_uInt16 BIFF12_PCDFIELD_MEMBERPROPFIELD = 0x0010;
71 const sal_uInt16 BIFF12_PCDFIELD_HASFORMULA = 0x0100;
72 const sal_uInt16 BIFF12_PCDFIELD_HASPROPERTYNAME = 0x0200;
73
74 const sal_uInt16 BIFF12_PCDFSITEMS_HASSEMIMIXED = 0x0001;
75 const sal_uInt16 BIFF12_PCDFSITEMS_HASNONDATE = 0x0002;
76 const sal_uInt16 BIFF12_PCDFSITEMS_HASDATE = 0x0004;
77 const sal_uInt16 BIFF12_PCDFSITEMS_HASSTRING = 0x0008;
78 const sal_uInt16 BIFF12_PCDFSITEMS_HASBLANK = 0x0010;
79 const sal_uInt16 BIFF12_PCDFSITEMS_HASMIXED = 0x0020;
80 const sal_uInt16 BIFF12_PCDFSITEMS_ISNUMERIC = 0x0040;
81 const sal_uInt16 BIFF12_PCDFSITEMS_ISINTEGER = 0x0080;
82 const sal_uInt16 BIFF12_PCDFSITEMS_HASMINMAX = 0x0100;
83 const sal_uInt16 BIFF12_PCDFSITEMS_HASLONGTEXT = 0x0200;
84
85 const sal_uInt16 BIFF12_PCITEM_ARRAY_DOUBLE = 0x0001;
86 const sal_uInt16 BIFF12_PCITEM_ARRAY_STRING = 0x0002;
87 const sal_uInt16 BIFF12_PCITEM_ARRAY_ERROR = 0x0010;
88 const sal_uInt16 BIFF12_PCITEM_ARRAY_DATE = 0x0020;
89
90 const sal_uInt8 BIFF12_PCDFRANGEPR_AUTOSTART = 0x01;
91 const sal_uInt8 BIFF12_PCDFRANGEPR_AUTOEND = 0x02;
92 const sal_uInt8 BIFF12_PCDFRANGEPR_DATEGROUP = 0x04;
93
94 const sal_uInt8 BIFF12_PCDEFINITION_SAVEDATA = 0x01;
95 const sal_uInt8 BIFF12_PCDEFINITION_INVALID = 0x02;
96 const sal_uInt8 BIFF12_PCDEFINITION_REFRESHONLOAD = 0x04;
97 const sal_uInt8 BIFF12_PCDEFINITION_OPTIMIZEMEMORY = 0x08;
98 const sal_uInt8 BIFF12_PCDEFINITION_ENABLEREFRESH = 0x10;
99 const sal_uInt8 BIFF12_PCDEFINITION_BACKGROUNDQUERY = 0x20;
100 const sal_uInt8 BIFF12_PCDEFINITION_UPGRADEONREFR = 0x40;
101 const sal_uInt8 BIFF12_PCDEFINITION_TUPELCACHE = 0x80;
102
103 const sal_uInt8 BIFF12_PCDEFINITION_HASUSERNAME = 0x01;
104 const sal_uInt8 BIFF12_PCDEFINITION_HASRELID = 0x02;
105 const sal_uInt8 BIFF12_PCDEFINITION_SUPPORTSUBQUERY = 0x04;
106 const sal_uInt8 BIFF12_PCDEFINITION_SUPPORTDRILL = 0x08;
107
108 const sal_uInt8 BIFF12_PCDWBSOURCE_HASRELID = 0x01;
109 const sal_uInt8 BIFF12_PCDWBSOURCE_HASSHEET = 0x02;
110
111 // ----------------------------------------------------------------------------
112
113 const sal_uInt16 BIFF_PCDSOURCE_WORKSHEET = 0x0001;
114 const sal_uInt16 BIFF_PCDSOURCE_EXTERNAL = 0x0002;
115 const sal_uInt16 BIFF_PCDSOURCE_CONSOLIDATION = 0x0004;
116 const sal_uInt16 BIFF_PCDSOURCE_SCENARIO = 0x0010;
117
118 const sal_uInt16 BIFF_PC_NOSTRING = 0xFFFF;
119
120 const sal_uInt16 BIFF_PCDFIELD_HASITEMS = 0x0001;
121 const sal_uInt16 BIFF_PCDFIELD_HASUNSHAREDITEMS = 0x0002;
122 const sal_uInt16 BIFF_PCDFIELD_CALCULATED = 0x0004;
123 const sal_uInt16 BIFF_PCDFIELD_HASPARENT = 0x0008;
124 const sal_uInt16 BIFF_PCDFIELD_RANGEGROUP = 0x0010;
125 const sal_uInt16 BIFF_PCDFIELD_ISNUMERIC = 0x0020;
126 const sal_uInt16 BIFF_PCDFIELD_HASSEMIMIXED = 0x0080;
127 const sal_uInt16 BIFF_PCDFIELD_HASMINMAX = 0x0100;
128 const sal_uInt16 BIFF_PCDFIELD_HASLONGINDEX = 0x0200;
129 const sal_uInt16 BIFF_PCDFIELD_HASNONDATE = 0x0400;
130 const sal_uInt16 BIFF_PCDFIELD_HASDATE = 0x0800;
131 const sal_uInt16 BIFF_PCDFIELD_SERVERFIELD = 0x2000;
132 const sal_uInt16 BIFF_PCDFIELD_NOUNIQUEITEMS = 0x4000;
133
134 const sal_uInt16 BIFF_PCDFRANGEPR_AUTOSTART = 0x0001;
135 const sal_uInt16 BIFF_PCDFRANGEPR_AUTOEND = 0x0002;
136
137 const sal_uInt16 BIFF_PCDEFINITION_SAVEDATA = 0x0001;
138 const sal_uInt16 BIFF_PCDEFINITION_INVALID = 0x0002;
139 const sal_uInt16 BIFF_PCDEFINITION_REFRESHONLOAD = 0x0004;
140 const sal_uInt16 BIFF_PCDEFINITION_OPTIMIZEMEMORY = 0x0008;
141 const sal_uInt16 BIFF_PCDEFINITION_BACKGROUNDQUERY = 0x0010;
142 const sal_uInt16 BIFF_PCDEFINITION_ENABLEREFRESH = 0x0020;
143
144 // ----------------------------------------------------------------------------
145
146 /** Adjusts the weird date format read from binary streams.
147
148 Dates before 1900-Mar-01 are stored including the non-existing leap day
149 1900-02-29. Time values (without date) are stored as times of day
150 1900-Jan-00. Nothing has to be done when the workbook is stored in 1904
151 date mode (dates before 1904-Jan-01 will not occur in this case).
152 */
lclAdjustBinDateTime(DateTime & orDateTime)153 void lclAdjustBinDateTime( DateTime& orDateTime )
154 {
155 if( (orDateTime.Year == 1900) && (orDateTime.Month <= 2) )
156 {
157 OSL_ENSURE( (orDateTime.Month == 1) || ((orDateTime.Month == 2) && (orDateTime.Day > 0)), "lclAdjustBinDateTime - invalid date" );
158 switch( orDateTime.Month )
159 {
160 case 2: if( orDateTime.Day > 1 ) --orDateTime.Day; else { orDateTime.Day += 30; --orDateTime.Month; } break;
161 case 1: if( orDateTime.Day > 1 ) --orDateTime.Day; else { orDateTime.Day += 30; orDateTime.Month = 12; --orDateTime.Year; } break;
162 }
163 }
164 }
165
166 } // namespace
167
168 // ============================================================================
169
PivotCacheItem()170 PivotCacheItem::PivotCacheItem() :
171 mnType( XML_m )
172 {
173 }
174
readString(const AttributeList & rAttribs)175 void PivotCacheItem::readString( const AttributeList& rAttribs )
176 {
177 maValue <<= rAttribs.getXString( XML_v, OUString() );
178 mnType = XML_s;
179 }
180
readNumeric(const AttributeList & rAttribs)181 void PivotCacheItem::readNumeric( const AttributeList& rAttribs )
182 {
183 maValue <<= rAttribs.getDouble( XML_v, 0.0 );
184 mnType = XML_n;
185 }
186
readDate(const AttributeList & rAttribs)187 void PivotCacheItem::readDate( const AttributeList& rAttribs )
188 {
189 maValue <<= rAttribs.getDateTime( XML_v, DateTime() );
190 mnType = XML_d;
191 }
192
readBool(const AttributeList & rAttribs)193 void PivotCacheItem::readBool( const AttributeList& rAttribs )
194 {
195 maValue <<= rAttribs.getBool( XML_v, false );
196 mnType = XML_b;
197 }
198
readError(const AttributeList & rAttribs,const UnitConverter & rUnitConverter)199 void PivotCacheItem::readError( const AttributeList& rAttribs, const UnitConverter& rUnitConverter )
200 {
201 maValue <<= static_cast< sal_Int32 >( rUnitConverter.calcBiffErrorCode( rAttribs.getXString( XML_v, OUString() ) ) );
202 mnType = XML_e;
203 }
204
readIndex(const AttributeList & rAttribs)205 void PivotCacheItem::readIndex( const AttributeList& rAttribs )
206 {
207 maValue <<= rAttribs.getInteger( XML_v, -1 );
208 mnType = XML_x;
209 }
210
readString(SequenceInputStream & rStrm)211 void PivotCacheItem::readString( SequenceInputStream& rStrm )
212 {
213 maValue <<= BiffHelper::readString( rStrm );
214 mnType = XML_s;
215 }
216
readDouble(SequenceInputStream & rStrm)217 void PivotCacheItem::readDouble( SequenceInputStream& rStrm )
218 {
219 maValue <<= rStrm.readDouble();
220 mnType = XML_n;
221 }
222
readDate(SequenceInputStream & rStrm)223 void PivotCacheItem::readDate( SequenceInputStream& rStrm )
224 {
225 DateTime aDateTime;
226 aDateTime.Year = rStrm.readuInt16();
227 aDateTime.Month = rStrm.readuInt16();
228 aDateTime.Day = rStrm.readuInt8();
229 aDateTime.Hours = rStrm.readuInt8();
230 aDateTime.Minutes = rStrm.readuInt8();
231 aDateTime.Seconds = rStrm.readuInt8();
232 lclAdjustBinDateTime( aDateTime );
233 maValue <<= aDateTime;
234 mnType = XML_d;
235 }
236
readBool(SequenceInputStream & rStrm)237 void PivotCacheItem::readBool( SequenceInputStream& rStrm )
238 {
239 maValue <<= (rStrm.readuInt8() != 0);
240 mnType = XML_b;
241 }
242
readError(SequenceInputStream & rStrm)243 void PivotCacheItem::readError( SequenceInputStream& rStrm )
244 {
245 maValue <<= static_cast< sal_Int32 >( rStrm.readuInt8() );
246 mnType = XML_e;
247 }
248
readIndex(SequenceInputStream & rStrm)249 void PivotCacheItem::readIndex( SequenceInputStream& rStrm )
250 {
251 maValue <<= rStrm.readInt32();
252 mnType = XML_x;
253 }
254
readString(BiffInputStream & rStrm,const WorkbookHelper & rHelper)255 void PivotCacheItem::readString( BiffInputStream& rStrm, const WorkbookHelper& rHelper )
256 {
257 maValue <<= (rHelper.getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( true, rHelper.getTextEncoding() );
258 mnType = XML_s;
259 }
260
readDouble(BiffInputStream & rStrm)261 void PivotCacheItem::readDouble( BiffInputStream& rStrm )
262 {
263 maValue <<= rStrm.readDouble();
264 mnType = XML_n;
265 }
266
readInteger(BiffInputStream & rStrm)267 void PivotCacheItem::readInteger( BiffInputStream& rStrm )
268 {
269 maValue <<= rStrm.readInt16();
270 mnType = XML_i; // fake, used for BIFF only
271 }
272
readDate(BiffInputStream & rStrm)273 void PivotCacheItem::readDate( BiffInputStream& rStrm )
274 {
275 DateTime aDateTime;
276 aDateTime.Year = rStrm.readuInt16();
277 aDateTime.Month = rStrm.readuInt16();
278 aDateTime.Day = rStrm.readuInt8();
279 aDateTime.Hours = rStrm.readuInt8();
280 aDateTime.Minutes = rStrm.readuInt8();
281 aDateTime.Seconds = rStrm.readuInt8();
282 lclAdjustBinDateTime( aDateTime );
283 maValue <<= aDateTime;
284 mnType = XML_d;
285 }
286
readBool(BiffInputStream & rStrm)287 void PivotCacheItem::readBool( BiffInputStream& rStrm )
288 {
289 maValue <<= (rStrm.readuInt8() != 0);
290 mnType = XML_b;
291 }
292
readError(BiffInputStream & rStrm)293 void PivotCacheItem::readError( BiffInputStream& rStrm )
294 {
295 maValue <<= static_cast< sal_Int32 >( rStrm.readuInt8() );
296 mnType = XML_e;
297 }
298
getName() const299 OUString PivotCacheItem::getName() const
300 {
301 switch( mnType )
302 {
303 case XML_m: return OUString();
304 case XML_s: return maValue.get< OUString >();
305 case XML_n: return OUString::valueOf( maValue.get< double >() ); // !TODO
306 case XML_i: return OUString::valueOf( maValue.get< sal_Int32 >() );
307 case XML_d: return OUString(); // !TODO
308 case XML_b: return OUString::valueOf( static_cast< sal_Bool >( maValue.get< bool >() ) ); // !TODO
309 case XML_e: return OUString(); // !TODO
310 }
311 OSL_ENSURE( false, "PivotCacheItem::getName - invalid data type" );
312 return OUString();
313 }
314
315 // ----------------------------------------------------------------------------
316
PivotCacheItemList(const WorkbookHelper & rHelper)317 PivotCacheItemList::PivotCacheItemList( const WorkbookHelper& rHelper ) :
318 WorkbookHelper( rHelper )
319 {
320 }
321
importItem(sal_Int32 nElement,const AttributeList & rAttribs)322 void PivotCacheItemList::importItem( sal_Int32 nElement, const AttributeList& rAttribs )
323 {
324 PivotCacheItem& rItem = createItem();
325 switch( nElement )
326 {
327 case XLS_TOKEN( m ): break;
328 case XLS_TOKEN( s ): rItem.readString( rAttribs ); break;
329 case XLS_TOKEN( n ): rItem.readNumeric( rAttribs ); break;
330 case XLS_TOKEN( d ): rItem.readDate( rAttribs ); break;
331 case XLS_TOKEN( b ): rItem.readBool( rAttribs ); break;
332 case XLS_TOKEN( e ): rItem.readError( rAttribs, getUnitConverter() ); break;
333 default: OSL_ENSURE( false, "PivotCacheItemList::importItem - unknown element type" );
334 }
335 }
336
importItem(sal_Int32 nRecId,SequenceInputStream & rStrm)337 void PivotCacheItemList::importItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
338 {
339 if( nRecId == BIFF12_ID_PCITEM_ARRAY )
340 {
341 importArray( rStrm );
342 return;
343 }
344
345 PivotCacheItem& rItem = createItem();
346 switch( nRecId )
347 {
348 case BIFF12_ID_PCITEM_MISSING:
349 case BIFF12_ID_PCITEMA_MISSING: break;
350 case BIFF12_ID_PCITEM_STRING:
351 case BIFF12_ID_PCITEMA_STRING: rItem.readString( rStrm ); break;
352 case BIFF12_ID_PCITEM_DOUBLE:
353 case BIFF12_ID_PCITEMA_DOUBLE: rItem.readDouble( rStrm ); break;
354 case BIFF12_ID_PCITEM_DATE:
355 case BIFF12_ID_PCITEMA_DATE: rItem.readDate( rStrm ); break;
356 case BIFF12_ID_PCITEM_BOOL:
357 case BIFF12_ID_PCITEMA_BOOL: rItem.readBool( rStrm ); break;
358 case BIFF12_ID_PCITEM_ERROR:
359 case BIFF12_ID_PCITEMA_ERROR: rItem.readError( rStrm ); break;
360 default: OSL_ENSURE( false, "PivotCacheItemList::importItem - unknown record type" );
361 }
362 }
363
importItemList(BiffInputStream & rStrm,sal_uInt16 nCount)364 void PivotCacheItemList::importItemList( BiffInputStream& rStrm, sal_uInt16 nCount )
365 {
366 bool bLoop = true;
367 for( sal_uInt16 nItemIdx = 0; bLoop && (nItemIdx < nCount); ++nItemIdx )
368 {
369 bLoop = rStrm.startNextRecord();
370 if( bLoop ) switch( rStrm.getRecId() )
371 {
372 case BIFF_ID_PCITEM_MISSING: createItem(); break;
373 case BIFF_ID_PCITEM_STRING: createItem().readString( rStrm, *this ); break;
374 case BIFF_ID_PCITEM_DOUBLE: createItem().readDouble( rStrm ); break;
375 case BIFF_ID_PCITEM_INTEGER: createItem().readInteger( rStrm ); break;
376 case BIFF_ID_PCITEM_DATE: createItem().readDate( rStrm ); break;
377 case BIFF_ID_PCITEM_BOOL: createItem().readBool( rStrm ); break;
378 case BIFF_ID_PCITEM_ERROR: createItem().readError( rStrm ); break;
379 default: rStrm.rewindRecord(); bLoop = false;
380 }
381 }
382 OSL_ENSURE( bLoop, "PivotCacheItemList::importItemList - could not read all cache item records" );
383 }
384
getCacheItem(sal_Int32 nItemIdx) const385 const PivotCacheItem* PivotCacheItemList::getCacheItem( sal_Int32 nItemIdx ) const
386 {
387 return ContainerHelper::getVectorElement( maItems, nItemIdx );
388 }
389
getCacheItemNames(::std::vector<OUString> & orItemNames) const390 void PivotCacheItemList::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const
391 {
392 orItemNames.clear();
393 orItemNames.reserve( maItems.size() );
394 for( CacheItemVector::const_iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
395 orItemNames.push_back( aIt->getName() );
396 }
397
398 // private --------------------------------------------------------------------
399
createItem()400 PivotCacheItem& PivotCacheItemList::createItem()
401 {
402 maItems.resize( maItems.size() + 1 );
403 return maItems.back();
404 }
405
importArray(SequenceInputStream & rStrm)406 void PivotCacheItemList::importArray( SequenceInputStream& rStrm )
407 {
408 sal_uInt16 nType = rStrm.readuInt16();
409 sal_Int32 nCount = rStrm.readInt32();
410 for( sal_Int32 nIdx = 0; !rStrm.isEof() && (nIdx < nCount); ++nIdx )
411 {
412 switch( nType )
413 {
414 case BIFF12_PCITEM_ARRAY_DOUBLE: createItem().readDouble( rStrm ); break;
415 case BIFF12_PCITEM_ARRAY_STRING: createItem().readString( rStrm ); break;
416 case BIFF12_PCITEM_ARRAY_ERROR: createItem().readError( rStrm ); break;
417 case BIFF12_PCITEM_ARRAY_DATE: createItem().readDate( rStrm ); break;
418 default:
419 OSL_ENSURE( false, "PivotCacheItemList::importArray - unknown data type" );
420 nIdx = nCount;
421 }
422 }
423 }
424
425 // ============================================================================
426
PCFieldModel()427 PCFieldModel::PCFieldModel() :
428 mnNumFmtId( 0 ),
429 mnSqlType( 0 ),
430 mnHierarchy( 0 ),
431 mnLevel( 0 ),
432 mnMappingCount( 0 ),
433 mbDatabaseField( true ),
434 mbServerField( false ),
435 mbUniqueList( true ),
436 mbMemberPropField( false )
437 {
438 }
439
440 // ----------------------------------------------------------------------------
441
PCSharedItemsModel()442 PCSharedItemsModel::PCSharedItemsModel() :
443 mbHasSemiMixed( true ),
444 mbHasNonDate( true ),
445 mbHasDate( false ),
446 mbHasString( true ),
447 mbHasBlank( false ),
448 mbHasMixed( false ),
449 mbIsNumeric( false ),
450 mbIsInteger( false ),
451 mbHasLongText( false ),
452 mbHasLongIndexes( false )
453 {
454 }
455
456 // ----------------------------------------------------------------------------
457
PCFieldGroupModel()458 PCFieldGroupModel::PCFieldGroupModel() :
459 mfStartValue( 0.0 ),
460 mfEndValue( 0.0 ),
461 mfInterval( 1.0 ),
462 mnParentField( -1 ),
463 mnBaseField( -1 ),
464 mnGroupBy( XML_range ),
465 mbRangeGroup( false ),
466 mbDateGroup( false ),
467 mbAutoStart( true ),
468 mbAutoEnd( true )
469 {
470 }
471
setBiffGroupBy(sal_uInt8 nGroupBy)472 void PCFieldGroupModel::setBiffGroupBy( sal_uInt8 nGroupBy )
473 {
474 static const sal_Int32 spnGroupBy[] = { XML_range,
475 XML_seconds, XML_minutes, XML_hours, XML_days, XML_months, XML_quarters, XML_years };
476 mnGroupBy = STATIC_ARRAY_SELECT( spnGroupBy, nGroupBy, XML_range );
477 }
478
479 // ----------------------------------------------------------------------------
480
PivotCacheField(const WorkbookHelper & rHelper,bool bIsDatabaseField)481 PivotCacheField::PivotCacheField( const WorkbookHelper& rHelper, bool bIsDatabaseField ) :
482 WorkbookHelper( rHelper ),
483 maSharedItems( rHelper ),
484 maGroupItems( rHelper )
485 {
486 maFieldModel.mbDatabaseField = bIsDatabaseField;
487 }
488
importCacheField(const AttributeList & rAttribs)489 void PivotCacheField::importCacheField( const AttributeList& rAttribs )
490 {
491 maFieldModel.maName = rAttribs.getXString( XML_name, OUString() );
492 maFieldModel.maCaption = rAttribs.getXString( XML_caption, OUString() );
493 maFieldModel.maPropertyName = rAttribs.getXString( XML_propertyName, OUString() );
494 maFieldModel.maFormula = rAttribs.getXString( XML_formula, OUString() );
495 maFieldModel.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, 0 );
496 maFieldModel.mnSqlType = rAttribs.getInteger( XML_sqlType, 0 );
497 maFieldModel.mnHierarchy = rAttribs.getInteger( XML_hierarchy, 0 );
498 maFieldModel.mnLevel = rAttribs.getInteger( XML_level, 0 );
499 maFieldModel.mnMappingCount = rAttribs.getInteger( XML_mappingCount, 0 );
500 maFieldModel.mbDatabaseField = rAttribs.getBool( XML_databaseField, true );
501 maFieldModel.mbServerField = rAttribs.getBool( XML_serverField, false );
502 maFieldModel.mbUniqueList = rAttribs.getBool( XML_uniqueList, true );
503 maFieldModel.mbMemberPropField = rAttribs.getBool( XML_memberPropertyField, false );
504 }
505
importSharedItems(const AttributeList & rAttribs)506 void PivotCacheField::importSharedItems( const AttributeList& rAttribs )
507 {
508 OSL_ENSURE( maSharedItems.empty(), "PivotCacheField::importSharedItems - multiple shared items elements" );
509 maSharedItemsModel.mbHasSemiMixed = rAttribs.getBool( XML_containsSemiMixedTypes, true );
510 maSharedItemsModel.mbHasNonDate = rAttribs.getBool( XML_containsNonDate, true );
511 maSharedItemsModel.mbHasDate = rAttribs.getBool( XML_containsDate, false );
512 maSharedItemsModel.mbHasString = rAttribs.getBool( XML_containsString, true );
513 maSharedItemsModel.mbHasBlank = rAttribs.getBool( XML_containsBlank, false );
514 maSharedItemsModel.mbHasMixed = rAttribs.getBool( XML_containsMixedTypes, false );
515 maSharedItemsModel.mbIsNumeric = rAttribs.getBool( XML_containsNumber, false );
516 maSharedItemsModel.mbIsInteger = rAttribs.getBool( XML_containsInteger, false );
517 maSharedItemsModel.mbHasLongText = rAttribs.getBool( XML_longText, false );
518 }
519
importSharedItem(sal_Int32 nElement,const AttributeList & rAttribs)520 void PivotCacheField::importSharedItem( sal_Int32 nElement, const AttributeList& rAttribs )
521 {
522 maSharedItems.importItem( nElement, rAttribs );
523 }
524
importFieldGroup(const AttributeList & rAttribs)525 void PivotCacheField::importFieldGroup( const AttributeList& rAttribs )
526 {
527 maFieldGroupModel.mnParentField = rAttribs.getInteger( XML_par, -1 );
528 maFieldGroupModel.mnBaseField = rAttribs.getInteger( XML_base, -1 );
529 }
530
importRangePr(const AttributeList & rAttribs)531 void PivotCacheField::importRangePr( const AttributeList& rAttribs )
532 {
533 maFieldGroupModel.maStartDate = rAttribs.getDateTime( XML_startDate, DateTime() );
534 maFieldGroupModel.maEndDate = rAttribs.getDateTime( XML_endDate, DateTime() );
535 maFieldGroupModel.mfStartValue = rAttribs.getDouble( XML_startNum, 0.0 );
536 maFieldGroupModel.mfEndValue = rAttribs.getDouble( XML_endNum, 0.0 );
537 maFieldGroupModel.mfInterval = rAttribs.getDouble( XML_groupInterval, 1.0 );
538 maFieldGroupModel.mnGroupBy = rAttribs.getToken( XML_groupBy, XML_range );
539 maFieldGroupModel.mbRangeGroup = true;
540 maFieldGroupModel.mbDateGroup = maFieldGroupModel.mnGroupBy != XML_range;
541 maFieldGroupModel.mbAutoStart = rAttribs.getBool( XML_autoStart, true );
542 maFieldGroupModel.mbAutoEnd = rAttribs.getBool( XML_autoEnd, true );
543 }
544
importDiscretePrItem(sal_Int32 nElement,const AttributeList & rAttribs)545 void PivotCacheField::importDiscretePrItem( sal_Int32 nElement, const AttributeList& rAttribs )
546 {
547 OSL_ENSURE( nElement == XLS_TOKEN( x ), "PivotCacheField::importDiscretePrItem - unexpected element" );
548 if( nElement == XLS_TOKEN( x ) )
549 maDiscreteItems.push_back( rAttribs.getInteger( XML_v, -1 ) );
550 }
551
importGroupItem(sal_Int32 nElement,const AttributeList & rAttribs)552 void PivotCacheField::importGroupItem( sal_Int32 nElement, const AttributeList& rAttribs )
553 {
554 maGroupItems.importItem( nElement, rAttribs );
555 }
556
importPCDField(SequenceInputStream & rStrm)557 void PivotCacheField::importPCDField( SequenceInputStream& rStrm )
558 {
559 sal_uInt16 nFlags;
560 rStrm >> nFlags >> maFieldModel.mnNumFmtId;
561 maFieldModel.mnSqlType = rStrm.readInt16();
562 rStrm >> maFieldModel.mnHierarchy >> maFieldModel.mnLevel >> maFieldModel.mnMappingCount >> maFieldModel.maName;
563 if( getFlag( nFlags, BIFF12_PCDFIELD_HASCAPTION ) )
564 rStrm >> maFieldModel.maCaption;
565 if( getFlag( nFlags, BIFF12_PCDFIELD_HASFORMULA ) )
566 rStrm.skip( ::std::max< sal_Int32 >( rStrm.readInt32(), 0 ) );
567 if( maFieldModel.mnMappingCount > 0 )
568 rStrm.skip( ::std::max< sal_Int32 >( rStrm.readInt32(), 0 ) );
569 if( getFlag( nFlags, BIFF12_PCDFIELD_HASPROPERTYNAME ) )
570 rStrm >> maFieldModel.maPropertyName;
571
572 maFieldModel.mbDatabaseField = getFlag( nFlags, BIFF12_PCDFIELD_DATABASEFIELD );
573 maFieldModel.mbServerField = getFlag( nFlags, BIFF12_PCDFIELD_SERVERFIELD );
574 maFieldModel.mbUniqueList = !getFlag( nFlags, BIFF12_PCDFIELD_NOUNIQUEITEMS );
575 maFieldModel.mbMemberPropField = getFlag( nFlags, BIFF12_PCDFIELD_MEMBERPROPFIELD );
576 }
577
importPCDFSharedItems(SequenceInputStream & rStrm)578 void PivotCacheField::importPCDFSharedItems( SequenceInputStream& rStrm )
579 {
580 sal_uInt16 nFlags;
581 rStrm >> nFlags;
582 maSharedItemsModel.mbHasSemiMixed = getFlag( nFlags, BIFF12_PCDFSITEMS_HASSEMIMIXED );
583 maSharedItemsModel.mbHasNonDate = getFlag( nFlags, BIFF12_PCDFSITEMS_HASNONDATE );
584 maSharedItemsModel.mbHasDate = getFlag( nFlags, BIFF12_PCDFSITEMS_HASDATE );
585 maSharedItemsModel.mbHasString = getFlag( nFlags, BIFF12_PCDFSITEMS_HASSTRING );
586 maSharedItemsModel.mbHasBlank = getFlag( nFlags, BIFF12_PCDFSITEMS_HASBLANK );
587 maSharedItemsModel.mbHasMixed = getFlag( nFlags, BIFF12_PCDFSITEMS_HASMIXED );
588 maSharedItemsModel.mbIsNumeric = getFlag( nFlags, BIFF12_PCDFSITEMS_ISNUMERIC );
589 maSharedItemsModel.mbIsInteger = getFlag( nFlags, BIFF12_PCDFSITEMS_ISINTEGER );
590 maSharedItemsModel.mbHasLongText = getFlag( nFlags, BIFF12_PCDFSITEMS_HASLONGTEXT );
591 }
592
importPCDFSharedItem(sal_Int32 nRecId,SequenceInputStream & rStrm)593 void PivotCacheField::importPCDFSharedItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
594 {
595 maSharedItems.importItem( nRecId, rStrm );
596 }
597
importPCDFieldGroup(SequenceInputStream & rStrm)598 void PivotCacheField::importPCDFieldGroup( SequenceInputStream& rStrm )
599 {
600 rStrm >> maFieldGroupModel.mnParentField >> maFieldGroupModel.mnBaseField;
601 }
602
importPCDFRangePr(SequenceInputStream & rStrm)603 void PivotCacheField::importPCDFRangePr( SequenceInputStream& rStrm )
604 {
605 sal_uInt8 nGroupBy, nFlags;
606 rStrm >> nGroupBy >> nFlags >> maFieldGroupModel.mfStartValue >> maFieldGroupModel.mfEndValue >> maFieldGroupModel.mfInterval;
607
608 maFieldGroupModel.setBiffGroupBy( nGroupBy );
609 maFieldGroupModel.mbRangeGroup = true;
610 maFieldGroupModel.mbDateGroup = getFlag( nFlags, BIFF12_PCDFRANGEPR_DATEGROUP );
611 maFieldGroupModel.mbAutoStart = getFlag( nFlags, BIFF12_PCDFRANGEPR_AUTOSTART );
612 maFieldGroupModel.mbAutoEnd = getFlag( nFlags, BIFF12_PCDFRANGEPR_AUTOEND );
613
614 OSL_ENSURE( maFieldGroupModel.mbDateGroup == (maFieldGroupModel.mnGroupBy != XML_range), "PivotCacheField::importPCDFRangePr - wrong date flag" );
615 if( maFieldGroupModel.mbDateGroup )
616 {
617 maFieldGroupModel.maStartDate = getUnitConverter().calcDateTimeFromSerial( maFieldGroupModel.mfStartValue );
618 maFieldGroupModel.maEndDate = getUnitConverter().calcDateTimeFromSerial( maFieldGroupModel.mfEndValue );
619 }
620 }
621
importPCDFDiscretePrItem(sal_Int32 nRecId,SequenceInputStream & rStrm)622 void PivotCacheField::importPCDFDiscretePrItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
623 {
624 OSL_ENSURE( nRecId == BIFF12_ID_PCITEM_INDEX, "PivotCacheField::importPCDFDiscretePrItem - unexpected record" );
625 if( nRecId == BIFF12_ID_PCITEM_INDEX )
626 maDiscreteItems.push_back( rStrm.readInt32() );
627 }
628
importPCDFGroupItem(sal_Int32 nRecId,SequenceInputStream & rStrm)629 void PivotCacheField::importPCDFGroupItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
630 {
631 maGroupItems.importItem( nRecId, rStrm );
632 }
633
importPCDField(BiffInputStream & rStrm)634 void PivotCacheField::importPCDField( BiffInputStream& rStrm )
635 {
636 sal_uInt16 nFlags, nGroupItems, nBaseItems, nSharedItems;
637 rStrm >> nFlags;
638 maFieldGroupModel.mnParentField = rStrm.readuInt16();
639 maFieldGroupModel.mnBaseField = rStrm.readuInt16();
640 rStrm.skip( 2 ); // number of unique items (either shared or group)
641 rStrm >> nGroupItems >> nBaseItems >> nSharedItems;
642 maFieldModel.maName = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( true, getTextEncoding() );
643
644 maFieldModel.mbServerField = getFlag( nFlags, BIFF_PCDFIELD_SERVERFIELD );
645 maFieldModel.mbUniqueList = !getFlag( nFlags, BIFF_PCDFIELD_NOUNIQUEITEMS );
646 maSharedItemsModel.mbHasSemiMixed = getFlag( nFlags, BIFF_PCDFIELD_HASSEMIMIXED );
647 maSharedItemsModel.mbHasNonDate = getFlag( nFlags, BIFF_PCDFIELD_HASNONDATE );
648 maSharedItemsModel.mbHasDate = getFlag( nFlags, BIFF_PCDFIELD_HASDATE );
649 maSharedItemsModel.mbIsNumeric = getFlag( nFlags, BIFF_PCDFIELD_ISNUMERIC );
650 maSharedItemsModel.mbHasLongIndexes = getFlag( nFlags, BIFF_PCDFIELD_HASLONGINDEX );
651 maFieldGroupModel.mbRangeGroup = getFlag( nFlags, BIFF_PCDFIELD_RANGEGROUP );
652
653 // in BIFF, presence of parent group field is denoted by a flag
654 if( !getFlag( nFlags, BIFF_PCDFIELD_HASPARENT ) )
655 maFieldGroupModel.mnParentField = -1;
656
657 // following PCDFSQLTYPE record contains SQL type
658 if( (rStrm.getNextRecId() == BIFF_ID_PCDFSQLTYPE) && rStrm.startNextRecord() )
659 maFieldModel.mnSqlType = rStrm.readInt16();
660
661 // read group items, if any
662 if( nGroupItems > 0 )
663 {
664 OSL_ENSURE( getFlag( nFlags, BIFF_PCDFIELD_HASITEMS ), "PivotCacheField::importPCDField - missing items flag" );
665 maGroupItems.importItemList( rStrm, nGroupItems );
666
667 sal_uInt16 nNextRecId = rStrm.getNextRecId();
668 bool bHasRangePr = nNextRecId == BIFF_ID_PCDFRANGEPR;
669 bool bHasDiscretePr = nNextRecId == BIFF_ID_PCDFDISCRETEPR;
670
671 OSL_ENSURE( bHasRangePr || bHasDiscretePr, "PivotCacheField::importPCDField - missing group properties record" );
672 OSL_ENSURE( bHasRangePr == maFieldGroupModel.mbRangeGroup, "PivotCacheField::importPCDField - invalid range grouping flag" );
673 if( bHasRangePr && rStrm.startNextRecord() )
674 importPCDFRangePr( rStrm );
675 else if( bHasDiscretePr && rStrm.startNextRecord() )
676 importPCDFDiscretePr( rStrm );
677 }
678
679 // read the shared items, if any
680 if( nSharedItems > 0 )
681 {
682 OSL_ENSURE( getFlag( nFlags, BIFF_PCDFIELD_HASITEMS ), "PivotCacheField::importPCDField - missing items flag" );
683 maSharedItems.importItemList( rStrm, nSharedItems );
684 }
685 }
686
importPCDFRangePr(BiffInputStream & rStrm)687 void PivotCacheField::importPCDFRangePr( BiffInputStream& rStrm )
688 {
689 sal_uInt16 nFlags;
690 rStrm >> nFlags;
691 maFieldGroupModel.setBiffGroupBy( extractValue< sal_uInt8 >( nFlags, 2, 3 ) );
692 maFieldGroupModel.mbRangeGroup = true;
693 maFieldGroupModel.mbDateGroup = maFieldGroupModel.mnGroupBy != XML_range;
694 maFieldGroupModel.mbAutoStart = getFlag( nFlags, BIFF_PCDFRANGEPR_AUTOSTART );
695 maFieldGroupModel.mbAutoEnd = getFlag( nFlags, BIFF_PCDFRANGEPR_AUTOEND );
696
697 /* Start, end, and interval are stored in 3 separate item records. Type of
698 the items is dependent on numeric/date mode. Numeric groups expect
699 three PCITEM_DOUBLE records, date groups expect two PCITEM_DATE records
700 and one PCITEM_INT record. */
701 PivotCacheItemList aLimits( *this );
702 aLimits.importItemList( rStrm, 3 );
703 OSL_ENSURE( aLimits.size() == 3, "PivotCacheField::importPCDFRangePr - missing grouping records" );
704 const PivotCacheItem* pStartValue = aLimits.getCacheItem( 0 );
705 const PivotCacheItem* pEndValue = aLimits.getCacheItem( 1 );
706 const PivotCacheItem* pInterval = aLimits.getCacheItem( 2 );
707 if( pStartValue && pEndValue && pInterval )
708 {
709 if( maFieldGroupModel.mbDateGroup )
710 {
711 bool bHasTypes = (pStartValue->getType() == XML_d) && (pEndValue->getType() == XML_d) && (pInterval->getType() == XML_i);
712 OSL_ENSURE( bHasTypes, "PivotCacheField::importPCDFRangePr - wrong data types in grouping items" );
713 if( bHasTypes )
714 {
715 maFieldGroupModel.maStartDate = pStartValue->getValue().get< DateTime >();
716 maFieldGroupModel.maEndDate = pEndValue->getValue().get< DateTime >();
717 maFieldGroupModel.mfInterval = pInterval->getValue().get< sal_Int16 >();
718 }
719 }
720 else
721 {
722 bool bHasTypes = (pStartValue->getType() == XML_n) && (pEndValue->getType() == XML_n) && (pInterval->getType() == XML_n);
723 OSL_ENSURE( bHasTypes, "PivotCacheField::importPCDFRangePr - wrong data types in grouping items" );
724 if( bHasTypes )
725 {
726 maFieldGroupModel.mfStartValue = pStartValue->getValue().get< double >();
727 maFieldGroupModel.mfEndValue = pEndValue->getValue().get< double >();
728 maFieldGroupModel.mfInterval = pInterval->getValue().get< double >();
729 }
730 }
731 }
732 }
733
importPCDFDiscretePr(BiffInputStream & rStrm)734 void PivotCacheField::importPCDFDiscretePr( BiffInputStream& rStrm )
735 {
736 sal_Int32 nCount = static_cast< sal_Int32 >( rStrm.size() / 2 );
737 for( sal_Int32 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
738 maDiscreteItems.push_back( rStrm.readuInt16() );
739 }
740
getCacheItem(sal_Int32 nItemIdx) const741 const PivotCacheItem* PivotCacheField::getCacheItem( sal_Int32 nItemIdx ) const
742 {
743 if( hasGroupItems() )
744 return maGroupItems.getCacheItem( nItemIdx );
745 if( hasSharedItems() )
746 return maSharedItems.getCacheItem( nItemIdx );
747 return 0;
748 }
749
getCacheItemNames(::std::vector<OUString> & orItemNames) const750 void PivotCacheField::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const
751 {
752 if( hasGroupItems() )
753 maGroupItems.getCacheItemNames( orItemNames );
754 else if( hasSharedItems() )
755 maSharedItems.getCacheItemNames( orItemNames );
756 }
757
convertNumericGrouping(const Reference<XDataPilotField> & rxDPField) const758 void PivotCacheField::convertNumericGrouping( const Reference< XDataPilotField >& rxDPField ) const
759 {
760 OSL_ENSURE( hasGroupItems() && hasNumericGrouping(), "PivotCacheField::convertNumericGrouping - not a numeric group field" );
761 PropertySet aPropSet( rxDPField );
762 if( hasGroupItems() && hasNumericGrouping() && aPropSet.is() )
763 {
764 DataPilotFieldGroupInfo aGroupInfo;
765 aGroupInfo.HasAutoStart = maFieldGroupModel.mbAutoStart;
766 aGroupInfo.HasAutoEnd = maFieldGroupModel.mbAutoEnd;
767 aGroupInfo.HasDateValues = sal_False;
768 aGroupInfo.Start = maFieldGroupModel.mfStartValue;
769 aGroupInfo.End = maFieldGroupModel.mfEndValue;
770 aGroupInfo.Step = maFieldGroupModel.mfInterval;
771 aGroupInfo.GroupBy = 0;
772 aPropSet.setProperty( PROP_GroupInfo, aGroupInfo );
773 }
774 }
775
createDateGroupField(const Reference<XDataPilotField> & rxBaseDPField) const776 OUString PivotCacheField::createDateGroupField( const Reference< XDataPilotField >& rxBaseDPField ) const
777 {
778 OSL_ENSURE( hasGroupItems() && hasDateGrouping(), "PivotCacheField::createDateGroupField - not a numeric group field" );
779 Reference< XDataPilotField > xDPGroupField;
780 PropertySet aPropSet( rxBaseDPField );
781 if( hasGroupItems() && hasDateGrouping() && aPropSet.is() )
782 {
783 bool bDayRanges = (maFieldGroupModel.mnGroupBy == XML_days) && (maFieldGroupModel.mfInterval >= 2.0);
784
785 DataPilotFieldGroupInfo aGroupInfo;
786 aGroupInfo.HasAutoStart = maFieldGroupModel.mbAutoStart;
787 aGroupInfo.HasAutoEnd = maFieldGroupModel.mbAutoEnd;
788 aGroupInfo.HasDateValues = sal_True;
789 aGroupInfo.Start = getUnitConverter().calcSerialFromDateTime( maFieldGroupModel.maStartDate );
790 aGroupInfo.End = getUnitConverter().calcSerialFromDateTime( maFieldGroupModel.maEndDate );
791 aGroupInfo.Step = bDayRanges ? maFieldGroupModel.mfInterval : 0.0;
792
793 using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
794 switch( maFieldGroupModel.mnGroupBy )
795 {
796 case XML_years: aGroupInfo.GroupBy = YEARS; break;
797 case XML_quarters: aGroupInfo.GroupBy = QUARTERS; break;
798 case XML_months: aGroupInfo.GroupBy = MONTHS; break;
799 case XML_days: aGroupInfo.GroupBy = DAYS; break;
800 case XML_hours: aGroupInfo.GroupBy = HOURS; break;
801 case XML_minutes: aGroupInfo.GroupBy = MINUTES; break;
802 case XML_seconds: aGroupInfo.GroupBy = SECONDS; break;
803 default: OSL_ENSURE( false, "PivotCacheField::convertRangeGrouping - unknown date/time interval" );
804 }
805
806 try
807 {
808 Reference< XDataPilotFieldGrouping > xDPGrouping( rxBaseDPField, UNO_QUERY_THROW );
809 xDPGroupField = xDPGrouping->createDateGroup( aGroupInfo );
810 }
811 catch( Exception& )
812 {
813 }
814 }
815
816 Reference< XNamed > xFieldName( xDPGroupField, UNO_QUERY );
817 return xFieldName.is() ? xFieldName->getName() : OUString();
818 }
819
createParentGroupField(const Reference<XDataPilotField> & rxBaseDPField,PivotCacheGroupItemVector & orItemNames) const820 OUString PivotCacheField::createParentGroupField( const Reference< XDataPilotField >& rxBaseDPField, PivotCacheGroupItemVector& orItemNames ) const
821 {
822 OSL_ENSURE( hasGroupItems() && !maDiscreteItems.empty(), "PivotCacheField::createParentGroupField - not a group field" );
823 OSL_ENSURE( maDiscreteItems.size() == orItemNames.size(), "PivotCacheField::createParentGroupField - number of item names does not match grouping info" );
824 Reference< XDataPilotFieldGrouping > xDPGrouping( rxBaseDPField, UNO_QUERY );
825 if( !xDPGrouping.is() ) return OUString();
826
827 // map the group item indexes from maGroupItems to all item indexes from maDiscreteItems
828 typedef ::std::vector< sal_Int32 > GroupItemList;
829 typedef ::std::vector< GroupItemList > GroupItemMap;
830 GroupItemMap aItemMap( maGroupItems.size() );
831 for( IndexVector::const_iterator aBeg = maDiscreteItems.begin(), aIt = aBeg, aEnd = maDiscreteItems.end(); aIt != aEnd; ++aIt )
832 if( GroupItemList* pItems = ContainerHelper::getVectorElementAccess( aItemMap, *aIt ) )
833 pItems->push_back( static_cast< sal_Int32 >( aIt - aBeg ) );
834
835 // process all groups
836 Reference< XDataPilotField > xDPGroupField;
837 for( GroupItemMap::iterator aBeg = aItemMap.begin(), aIt = aBeg, aEnd = aItemMap.end(); aIt != aEnd; ++aIt )
838 {
839 OSL_ENSURE( !aIt->empty(), "PivotCacheField::createParentGroupField - item/group should not be empty" );
840 // if the item count is greater than 1, the item is a group of items
841 if( aIt->size() > 1 )
842 {
843 /* Insert the names of the items that are part of this group. Calc
844 expects the names of the members of the field whose members are
845 grouped (which may be the names of groups too). Excel provides
846 the names of the base field items instead (no group names
847 involved). Therefore, the passed collection of current item
848 names as they are already grouped is used here to resolve the
849 item names. */
850 ::std::vector< OUString > aMembers;
851 for( GroupItemList::iterator aBeg2 = aIt->begin(), aIt2 = aBeg2, aEnd2 = aIt->end(); aIt2 != aEnd2; ++aIt2 )
852 if( const PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, *aIt2 ) )
853 if( ::std::find( aMembers.begin(), aMembers.end(), pName->maGroupName ) == aMembers.end() )
854 aMembers.push_back( pName->maGroupName );
855
856 /* Check again, that this is not just a group that is not grouped
857 further with other items. */
858 if( aMembers.size() > 1 ) try
859 {
860 // only the first call of createNameGroup() returns the new field
861 Reference< XDataPilotField > xDPNewField = xDPGrouping->createNameGroup( ContainerHelper::vectorToSequence( aMembers ) );
862 OSL_ENSURE( xDPGroupField.is() != xDPNewField.is(), "PivotCacheField::createParentGroupField - missing group field" );
863 if( !xDPGroupField.is() )
864 xDPGroupField = xDPNewField;
865
866 // get current grouping info
867 DataPilotFieldGroupInfo aGroupInfo;
868 PropertySet aPropSet( xDPGroupField );
869 aPropSet.getProperty( aGroupInfo, PROP_GroupInfo );
870
871 /* Find the group object and the auto-generated group name.
872 The returned field contains all groups derived from the
873 previous field if that is grouped too. To find the correct
874 group, the first item used to create the group is serached.
875 Calc provides the original item names of the base field
876 when the group is querried for its members. Its does not
877 provide the names of members that are already groups in the
878 field used to create the new groups. (Is this a bug?)
879 Therefore, a name from the passed list of original item
880 names is used to find the correct group. */
881 OUString aFirstItem;
882 if( const PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, aIt->front() ) )
883 aFirstItem = pName->maOrigName;
884 Reference< XNamed > xGroupName;
885 OUString aAutoName;
886 Reference< XIndexAccess > xGroupsIA( aGroupInfo.Groups, UNO_QUERY_THROW );
887 for( sal_Int32 nIdx = 0, nCount = xGroupsIA->getCount(); (nIdx < nCount) && (aAutoName.getLength() == 0); ++nIdx ) try
888 {
889 Reference< XNameAccess > xItemsNA( xGroupsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
890 if( xItemsNA->hasByName( aFirstItem ) )
891 {
892 xGroupName.set( xGroupsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
893 aAutoName = xGroupName->getName();
894 }
895 }
896 catch( Exception& )
897 {
898 }
899 OSL_ENSURE( aAutoName.getLength() > 0, "PivotCacheField::createParentGroupField - cannot find auto-generated group name" );
900
901 // get the real group name from the list of group items
902 OUString aGroupName;
903 if( const PivotCacheItem* pGroupItem = maGroupItems.getCacheItem( static_cast< sal_Int32 >( aIt - aBeg ) ) )
904 aGroupName = pGroupItem->getName();
905 OSL_ENSURE( aGroupName.getLength() > 0, "PivotCacheField::createParentGroupField - cannot find group name" );
906 if( aGroupName.getLength() == 0 )
907 aGroupName = aAutoName;
908
909 if( xGroupName.is() && (aGroupName.getLength() > 0) )
910 {
911 // replace the auto-generated group name with the real name
912 if( aAutoName != aGroupName )
913 {
914 xGroupName->setName( aGroupName );
915 aPropSet.setProperty( PROP_GroupInfo, aGroupInfo );
916 }
917 // replace original item names in passed vector with group name
918 for( GroupItemList::iterator aIt2 = aIt->begin(), aEnd2 = aIt->end(); aIt2 != aEnd2; ++aIt2 )
919 if( PivotCacheGroupItem* pName = ContainerHelper::getVectorElementAccess( orItemNames, *aIt2 ) )
920 pName->maGroupName = aGroupName;
921 }
922 }
923 catch( Exception& )
924 {
925 }
926 }
927 }
928
929 Reference< XNamed > xFieldName( xDPGroupField, UNO_QUERY );
930 return xFieldName.is() ? xFieldName->getName() : OUString();
931 }
932
writeSourceHeaderCell(WorksheetHelper & rSheetHelper,sal_Int32 nCol,sal_Int32 nRow) const933 void PivotCacheField::writeSourceHeaderCell( WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
934 {
935 CellModel aModel;
936 aModel.maCellAddr = CellAddress( rSheetHelper.getSheetIndex(), nCol, nRow );
937 rSheetHelper.getSheetData().setStringCell( aModel, maFieldModel.maName );
938 }
939
writeSourceDataCell(WorksheetHelper & rSheetHelper,sal_Int32 nCol,sal_Int32 nRow,const PivotCacheItem & rItem) const940 void PivotCacheField::writeSourceDataCell( WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem ) const
941 {
942 bool bHasIndex = rItem.getType() == XML_x;
943 OSL_ENSURE( bHasIndex != maSharedItems.empty(), "PivotCacheField::writeSourceDataCell - shared items missing or not expected" );
944 if( bHasIndex )
945 writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, rItem.getValue().get< sal_Int32 >() );
946 else
947 writeItemToSourceDataCell( rSheetHelper, nCol, nRow, rItem );
948 }
949
importPCRecordItem(SequenceInputStream & rStrm,WorksheetHelper & rSheetHelper,sal_Int32 nCol,sal_Int32 nRow) const950 void PivotCacheField::importPCRecordItem( SequenceInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
951 {
952 if( hasSharedItems() )
953 {
954 writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, rStrm.readInt32() );
955 }
956 else
957 {
958 PivotCacheItem aItem;
959 if( maSharedItemsModel.mbIsNumeric )
960 aItem.readDouble( rStrm );
961 else if( maSharedItemsModel.mbHasDate && !maSharedItemsModel.mbHasString )
962 aItem.readDate( rStrm );
963 else
964 aItem.readString( rStrm );
965 writeItemToSourceDataCell( rSheetHelper, nCol, nRow, aItem );
966 }
967 }
968
importPCItemIndex(BiffInputStream & rStrm,WorksheetHelper & rSheetHelper,sal_Int32 nCol,sal_Int32 nRow) const969 void PivotCacheField::importPCItemIndex( BiffInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
970 {
971 OSL_ENSURE( hasSharedItems(), "PivotCacheField::importPCItemIndex - invalid call, no shared items found" );
972 sal_Int32 nIndex = maSharedItemsModel.mbHasLongIndexes ? rStrm.readuInt16() : rStrm.readuInt8();
973 writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, nIndex );
974 }
975
976 // private --------------------------------------------------------------------
977
writeItemToSourceDataCell(WorksheetHelper & rSheetHelper,sal_Int32 nCol,sal_Int32 nRow,const PivotCacheItem & rItem) const978 void PivotCacheField::writeItemToSourceDataCell( WorksheetHelper& rSheetHelper,
979 sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem ) const
980 {
981 if( rItem.getType() != XML_m )
982 {
983 CellModel aModel;
984 aModel.maCellAddr = CellAddress( rSheetHelper.getSheetIndex(), nCol, nRow );
985 SheetDataBuffer& rSheetData = rSheetHelper.getSheetData();
986 switch( rItem.getType() )
987 {
988 case XML_s: rSheetData.setStringCell( aModel, rItem.getValue().get< OUString >() ); break;
989 case XML_n: rSheetData.setValueCell( aModel, rItem.getValue().get< double >() ); break;
990 case XML_i: rSheetData.setValueCell( aModel, rItem.getValue().get< sal_Int16 >() ); break;
991 case XML_d: rSheetData.setDateTimeCell( aModel, rItem.getValue().get< DateTime >() ); break;
992 case XML_b: rSheetData.setBooleanCell( aModel, rItem.getValue().get< bool >() ); break;
993 case XML_e: rSheetData.setErrorCell( aModel, static_cast< sal_uInt8 >( rItem.getValue().get< sal_Int32 >() ) ); break;
994 default: OSL_ENSURE( false, "PivotCacheField::writeItemToSourceDataCell - unexpected item data type" );
995 }
996 }
997 }
998
writeSharedItemToSourceDataCell(WorksheetHelper & rSheetHelper,sal_Int32 nCol,sal_Int32 nRow,sal_Int32 nItemIdx) const999 void PivotCacheField::writeSharedItemToSourceDataCell(
1000 WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nItemIdx ) const
1001 {
1002 if( const PivotCacheItem* pCacheItem = maSharedItems.getCacheItem( nItemIdx ) )
1003 writeItemToSourceDataCell( rSheetHelper, nCol, nRow, *pCacheItem );
1004 }
1005
1006 // ============================================================================
1007
PCDefinitionModel()1008 PCDefinitionModel::PCDefinitionModel() :
1009 mfRefreshedDate( 0.0 ),
1010 mnRecords( 0 ),
1011 mnMissItemsLimit( 0 ),
1012 mnDatabaseFields( 0 ),
1013 mbInvalid( false ),
1014 mbSaveData( true ),
1015 mbRefreshOnLoad( false ),
1016 mbOptimizeMemory( false ),
1017 mbEnableRefresh( true ),
1018 mbBackgroundQuery( false ),
1019 mbUpgradeOnRefresh( false ),
1020 mbTupleCache( false ),
1021 mbSupportSubquery( false ),
1022 mbSupportDrill( false )
1023 {
1024 }
1025
1026 // ----------------------------------------------------------------------------
1027
PCSourceModel()1028 PCSourceModel::PCSourceModel() :
1029 mnSourceType( XML_TOKEN_INVALID ),
1030 mnConnectionId( 0 )
1031 {
1032 }
1033
1034 // ----------------------------------------------------------------------------
1035
PCWorksheetSourceModel()1036 PCWorksheetSourceModel::PCWorksheetSourceModel()
1037 {
1038 maRange.StartColumn = maRange.StartRow = maRange.EndColumn = maRange.EndRow = -1;
1039 }
1040
1041 // ----------------------------------------------------------------------------
1042
PivotCache(const WorkbookHelper & rHelper)1043 PivotCache::PivotCache( const WorkbookHelper& rHelper ) :
1044 WorkbookHelper( rHelper ),
1045 mnCurrRow( -1 ),
1046 mbValidSource( false ),
1047 mbDummySheet( false )
1048 {
1049 }
1050
importPivotCacheDefinition(const AttributeList & rAttribs)1051 void PivotCache::importPivotCacheDefinition( const AttributeList& rAttribs )
1052 {
1053 maDefModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
1054 maDefModel.maRefreshedBy = rAttribs.getXString( XML_refreshedBy, OUString() );
1055 maDefModel.mfRefreshedDate = rAttribs.getDouble( XML_refreshedDate, 0.0 );
1056 maDefModel.mnRecords = rAttribs.getInteger( XML_recordCount, 0 );
1057 maDefModel.mnMissItemsLimit = rAttribs.getInteger( XML_missingItemsLimit, 0 );
1058 maDefModel.mbInvalid = rAttribs.getBool( XML_invalid, false );
1059 maDefModel.mbSaveData = rAttribs.getBool( XML_saveData, true );
1060 maDefModel.mbRefreshOnLoad = rAttribs.getBool( XML_refreshOnLoad, false );
1061 maDefModel.mbOptimizeMemory = rAttribs.getBool( XML_optimizeMemory, false );
1062 maDefModel.mbEnableRefresh = rAttribs.getBool( XML_enableRefresh, true );
1063 maDefModel.mbBackgroundQuery = rAttribs.getBool( XML_backgroundQuery, false );
1064 maDefModel.mbUpgradeOnRefresh = rAttribs.getBool( XML_upgradeOnRefresh, false );
1065 maDefModel.mbTupleCache = rAttribs.getBool( XML_tupleCache, false );
1066 maDefModel.mbSupportSubquery = rAttribs.getBool( XML_supportSubquery, false );
1067 maDefModel.mbSupportDrill = rAttribs.getBool( XML_supportAdvancedDrill, false );
1068 }
1069
importCacheSource(const AttributeList & rAttribs)1070 void PivotCache::importCacheSource( const AttributeList& rAttribs )
1071 {
1072 maSourceModel.mnSourceType = rAttribs.getToken( XML_type, XML_TOKEN_INVALID );
1073 maSourceModel.mnConnectionId = rAttribs.getInteger( XML_connectionId, 0 );
1074 }
1075
importWorksheetSource(const AttributeList & rAttribs,const Relations & rRelations)1076 void PivotCache::importWorksheetSource( const AttributeList& rAttribs, const Relations& rRelations )
1077 {
1078 maSheetSrcModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
1079 maSheetSrcModel.maSheet = rAttribs.getXString( XML_sheet, OUString() );
1080 maSheetSrcModel.maDefName = rAttribs.getXString( XML_name, OUString() );
1081
1082 // resolve URL of external document
1083 maTargetUrl = rRelations.getExternalTargetFromRelId( maSheetSrcModel.maRelId );
1084 // store range address unchecked with sheet index 0, will be resolved/checked later
1085 getAddressConverter().convertToCellRangeUnchecked( maSheetSrcModel.maRange, rAttribs.getString( XML_ref, OUString() ), 0 );
1086 }
1087
importPCDefinition(SequenceInputStream & rStrm)1088 void PivotCache::importPCDefinition( SequenceInputStream& rStrm )
1089 {
1090 sal_uInt8 nFlags1, nFlags2;
1091 rStrm.skip( 3 ); // create/refresh version id's
1092 rStrm >> nFlags1 >> maDefModel.mnMissItemsLimit >> maDefModel.mfRefreshedDate >> nFlags2 >> maDefModel.mnRecords;
1093 if( getFlag( nFlags2, BIFF12_PCDEFINITION_HASUSERNAME ) )
1094 rStrm >> maDefModel.maRefreshedBy;
1095 if( getFlag( nFlags2, BIFF12_PCDEFINITION_HASRELID ) )
1096 rStrm >> maDefModel.maRelId;
1097
1098 maDefModel.mbInvalid = getFlag( nFlags1, BIFF12_PCDEFINITION_INVALID );
1099 maDefModel.mbSaveData = getFlag( nFlags1, BIFF12_PCDEFINITION_SAVEDATA );
1100 maDefModel.mbRefreshOnLoad = getFlag( nFlags1, BIFF12_PCDEFINITION_REFRESHONLOAD );
1101 maDefModel.mbOptimizeMemory = getFlag( nFlags1, BIFF12_PCDEFINITION_OPTIMIZEMEMORY );
1102 maDefModel.mbEnableRefresh = getFlag( nFlags1, BIFF12_PCDEFINITION_ENABLEREFRESH );
1103 maDefModel.mbBackgroundQuery = getFlag( nFlags1, BIFF12_PCDEFINITION_BACKGROUNDQUERY );
1104 maDefModel.mbUpgradeOnRefresh = getFlag( nFlags1, BIFF12_PCDEFINITION_UPGRADEONREFR );
1105 maDefModel.mbTupleCache = getFlag( nFlags1, BIFF12_PCDEFINITION_TUPELCACHE );
1106 maDefModel.mbSupportSubquery = getFlag( nFlags2, BIFF12_PCDEFINITION_SUPPORTSUBQUERY );
1107 maDefModel.mbSupportDrill = getFlag( nFlags2, BIFF12_PCDEFINITION_SUPPORTDRILL );
1108 }
1109
importPCDSource(SequenceInputStream & rStrm)1110 void PivotCache::importPCDSource( SequenceInputStream& rStrm )
1111 {
1112 sal_Int32 nSourceType;
1113 rStrm >> nSourceType >> maSourceModel.mnConnectionId;
1114 static const sal_Int32 spnSourceTypes[] = { XML_worksheet, XML_external, XML_consolidation, XML_scenario };
1115 maSourceModel.mnSourceType = STATIC_ARRAY_SELECT( spnSourceTypes, nSourceType, XML_TOKEN_INVALID );
1116 }
1117
importPCDSheetSource(SequenceInputStream & rStrm,const Relations & rRelations)1118 void PivotCache::importPCDSheetSource( SequenceInputStream& rStrm, const Relations& rRelations )
1119 {
1120 sal_uInt8 nIsDefName, nIsBuiltinName, nFlags;
1121 rStrm >> nIsDefName >> nIsBuiltinName >> nFlags;
1122 if( getFlag( nFlags, BIFF12_PCDWBSOURCE_HASSHEET ) )
1123 rStrm >> maSheetSrcModel.maSheet;
1124 if( getFlag( nFlags, BIFF12_PCDWBSOURCE_HASRELID ) )
1125 rStrm >> maSheetSrcModel.maRelId;
1126
1127 // read cell range or defined name
1128 if( nIsDefName == 0 )
1129 {
1130 BinRange aBinRange;
1131 rStrm >> aBinRange;
1132 // store range address unchecked with sheet index 0, will be resolved/checked later
1133 getAddressConverter().convertToCellRangeUnchecked( maSheetSrcModel.maRange, aBinRange, 0 );
1134 }
1135 else
1136 {
1137 rStrm >> maSheetSrcModel.maDefName;
1138 if( nIsBuiltinName != 0 )
1139 maSheetSrcModel.maDefName = CREATE_OUSTRING( "_xlnm." ) + maSheetSrcModel.maDefName;
1140 }
1141
1142 // resolve URL of external document
1143 maTargetUrl = rRelations.getExternalTargetFromRelId( maSheetSrcModel.maRelId );
1144 }
1145
importPCDSource(BiffInputStream & rStrm)1146 void PivotCache::importPCDSource( BiffInputStream& rStrm )
1147 {
1148 switch( rStrm.readuInt16() )
1149 {
1150 case BIFF_PCDSOURCE_WORKSHEET:
1151 {
1152 maSourceModel.mnSourceType = XML_worksheet;
1153 sal_uInt16 nNextRecId = rStrm.getNextRecId();
1154 switch( nNextRecId )
1155 {
1156 case BIFF_ID_DCONREF: if( rStrm.startNextRecord() ) importDConRef( rStrm ); break;
1157 case BIFF_ID_DCONNAME: if( rStrm.startNextRecord() ) importDConName( rStrm ); break;
1158 case BIFF_ID_DCONBINAME: if( rStrm.startNextRecord() ) importDConBIName( rStrm ); break;
1159 }
1160 }
1161 break;
1162 case BIFF_PCDSOURCE_EXTERNAL:
1163 maSourceModel.mnSourceType = XML_external;
1164 break;
1165 case BIFF_PCDSOURCE_CONSOLIDATION:
1166 maSourceModel.mnSourceType = XML_consolidation;
1167 break;
1168 case BIFF_PCDSOURCE_SCENARIO:
1169 maSourceModel.mnSourceType = XML_scenario;
1170 break;
1171 default:
1172 maSourceModel.mnSourceType = XML_TOKEN_INVALID;
1173 }
1174 }
1175
importPCDefinition(BiffInputStream & rStrm)1176 void PivotCache::importPCDefinition( BiffInputStream& rStrm )
1177 {
1178 sal_uInt16 nFlags, nUserNameLen;
1179 rStrm >> maDefModel.mnRecords;
1180 rStrm.skip( 2 ); // repeated cache ID
1181 rStrm >> nFlags;
1182 rStrm.skip( 2 ); // unused
1183 rStrm >> maDefModel.mnDatabaseFields;
1184 rStrm.skip( 6 ); // total field count, report record count, (repeated) cache type
1185 rStrm >> nUserNameLen;
1186 if( nUserNameLen != BIFF_PC_NOSTRING )
1187 maDefModel.maRefreshedBy = (getBiff() == BIFF8) ?
1188 rStrm.readUniString( nUserNameLen ) :
1189 rStrm.readCharArrayUC( nUserNameLen, getTextEncoding() );
1190
1191 maDefModel.mbInvalid = getFlag( nFlags, BIFF_PCDEFINITION_INVALID );
1192 maDefModel.mbSaveData = getFlag( nFlags, BIFF_PCDEFINITION_SAVEDATA );
1193 maDefModel.mbRefreshOnLoad = getFlag( nFlags, BIFF_PCDEFINITION_REFRESHONLOAD );
1194 maDefModel.mbOptimizeMemory = getFlag( nFlags, BIFF_PCDEFINITION_OPTIMIZEMEMORY );
1195 maDefModel.mbEnableRefresh = getFlag( nFlags, BIFF_PCDEFINITION_ENABLEREFRESH );
1196 maDefModel.mbBackgroundQuery = getFlag( nFlags, BIFF_PCDEFINITION_BACKGROUNDQUERY );
1197
1198 if( (rStrm.getNextRecId() == BIFF_ID_PCDEFINITION2) && rStrm.startNextRecord() )
1199 rStrm >> maDefModel.mfRefreshedDate;
1200 }
1201
createCacheField(bool bInitDatabaseField)1202 PivotCacheField& PivotCache::createCacheField( bool bInitDatabaseField )
1203 {
1204 bool bIsDatabaseField = !bInitDatabaseField || (maFields.size() < maDefModel.mnDatabaseFields);
1205 PivotCacheFieldVector::value_type xCacheField( new PivotCacheField( *this, bIsDatabaseField ) );
1206 maFields.push_back( xCacheField );
1207 return *xCacheField;
1208 }
1209
finalizeImport()1210 void PivotCache::finalizeImport()
1211 {
1212 // collect all fields that are based on source data (needed to finalize source data below)
1213 OSL_ENSURE( !maFields.empty(), "PivotCache::finalizeImport - no pivot cache fields found" );
1214 for( PivotCacheFieldVector::const_iterator aIt = maFields.begin(), aEnd = maFields.end(); aIt != aEnd; ++aIt )
1215 {
1216 if( (*aIt)->isDatabaseField() )
1217 {
1218 OSL_ENSURE( (aIt == maFields.begin()) || (*(aIt - 1))->isDatabaseField(),
1219 "PivotCache::finalizeImport - database field follows a calculated field" );
1220 maDatabaseIndexes.push_back( static_cast< sal_Int32 >( maDatabaseFields.size() ) );
1221 maDatabaseFields.push_back( *aIt );
1222 }
1223 else
1224 {
1225 maDatabaseIndexes.push_back( -1 );
1226 }
1227 }
1228 OSL_ENSURE( !maDatabaseFields.empty(), "PivotCache::finalizeImport - no pivot cache source fields found" );
1229
1230 // finalize source data depending on source type
1231 switch( maSourceModel.mnSourceType )
1232 {
1233 case XML_worksheet:
1234 {
1235 // decide whether an external document is used
1236 bool bInternal = (maTargetUrl.getLength() == 0) && (maSheetSrcModel.maRelId.getLength() == 0);
1237 bool bExternal = maTargetUrl.getLength() > 0; // relation ID may be empty, e.g. BIFF import
1238 OSL_ENSURE( bInternal || bExternal, "PivotCache::finalizeImport - invalid external document URL" );
1239 if( bInternal )
1240 finalizeInternalSheetSource();
1241 else if( bExternal )
1242 finalizeExternalSheetSource();
1243 }
1244 break;
1245
1246 // currently, we only support worksheet data sources
1247 case XML_external:
1248 break;
1249 case XML_consolidation:
1250 break;
1251 case XML_scenario:
1252 break;
1253 }
1254 }
1255
getCacheFieldCount() const1256 sal_Int32 PivotCache::getCacheFieldCount() const
1257 {
1258 return static_cast< sal_Int32 >( maFields.size() );
1259 }
1260
getCacheField(sal_Int32 nFieldIdx) const1261 const PivotCacheField* PivotCache::getCacheField( sal_Int32 nFieldIdx ) const
1262 {
1263 return maFields.get( nFieldIdx ).get();
1264 }
1265
getCacheDatabaseIndex(sal_Int32 nFieldIdx) const1266 sal_Int32 PivotCache::getCacheDatabaseIndex( sal_Int32 nFieldIdx ) const
1267 {
1268 return ContainerHelper::getVectorElement( maDatabaseIndexes, nFieldIdx, -1 );
1269 }
1270
writeSourceHeaderCells(WorksheetHelper & rSheetHelper) const1271 void PivotCache::writeSourceHeaderCells( WorksheetHelper& rSheetHelper ) const
1272 {
1273 OSL_ENSURE( static_cast< size_t >( maSheetSrcModel.maRange.EndColumn - maSheetSrcModel.maRange.StartColumn + 1 ) == maDatabaseFields.size(),
1274 "PivotCache::writeSourceHeaderCells - source cell range width does not match number of source fields" );
1275 sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn;
1276 sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Column;
1277 sal_Int32 nRow = maSheetSrcModel.maRange.StartRow;
1278 mnCurrRow = -1;
1279 updateSourceDataRow( rSheetHelper, nRow );
1280 for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol )
1281 (*aIt)->writeSourceHeaderCell( rSheetHelper, nCol, nRow );
1282 }
1283
writeSourceDataCell(WorksheetHelper & rSheetHelper,sal_Int32 nColIdx,sal_Int32 nRowIdx,const PivotCacheItem & rItem) const1284 void PivotCache::writeSourceDataCell( WorksheetHelper& rSheetHelper, sal_Int32 nColIdx, sal_Int32 nRowIdx, const PivotCacheItem& rItem ) const
1285 {
1286 sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn + nColIdx;
1287 OSL_ENSURE( (maSheetSrcModel.maRange.StartColumn <= nCol) && (nCol <= maSheetSrcModel.maRange.EndColumn), "PivotCache::writeSourceDataCell - invalid column index" );
1288 sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx;
1289 OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::writeSourceDataCell - invalid row index" );
1290 updateSourceDataRow( rSheetHelper, nRow );
1291 if( const PivotCacheField* pCacheField = maDatabaseFields.get( nColIdx ).get() )
1292 pCacheField->writeSourceDataCell( rSheetHelper, nCol, nRow, rItem );
1293 }
1294
importPCRecord(SequenceInputStream & rStrm,WorksheetHelper & rSheetHelper,sal_Int32 nRowIdx) const1295 void PivotCache::importPCRecord( SequenceInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nRowIdx ) const
1296 {
1297 sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx;
1298 OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::importPCRecord - invalid row index" );
1299 sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn;
1300 sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Column;
1301 for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); !rStrm.isEof() && (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol )
1302 (*aIt)->importPCRecordItem( rStrm, rSheetHelper, nCol, nRow );
1303 }
1304
importPCItemIndexList(BiffInputStream & rStrm,WorksheetHelper & rSheetHelper,sal_Int32 nRowIdx) const1305 void PivotCache::importPCItemIndexList( BiffInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nRowIdx ) const
1306 {
1307 sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx;
1308 OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::importPCItemIndexList - invalid row index" );
1309 sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn;
1310 sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Column;
1311 for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); !rStrm.isEof() && (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol )
1312 if( (*aIt)->hasSharedItems() )
1313 (*aIt)->importPCItemIndex( rStrm, rSheetHelper, nCol, nRow );
1314 }
1315
1316 // private --------------------------------------------------------------------
1317
importDConRef(BiffInputStream & rStrm)1318 void PivotCache::importDConRef( BiffInputStream& rStrm )
1319 {
1320 BinRange aBinRange;
1321 aBinRange.read( rStrm, false ); // always 8-bit column indexes
1322 // store range address unchecked with sheet index 0, will be resolved/checked later
1323 getAddressConverter().convertToCellRangeUnchecked( maSheetSrcModel.maRange, aBinRange, 0 );
1324
1325 // the URL with (required) sheet name and optional URL of an external document
1326 importDConUrl( rStrm );
1327 OSL_ENSURE( maSheetSrcModel.maSheet.getLength() > 0, "PivotCache::importDConRef - missing sheet name" );
1328 }
1329
importDConName(BiffInputStream & rStrm)1330 void PivotCache::importDConName( BiffInputStream& rStrm )
1331 {
1332 maSheetSrcModel.maDefName = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() );
1333 OSL_ENSURE( maSheetSrcModel.maDefName.getLength() > 0, "PivotCache::importDConName - missing defined name" );
1334 importDConUrl( rStrm );
1335 }
1336
importDConBIName(BiffInputStream & rStrm)1337 void PivotCache::importDConBIName( BiffInputStream& rStrm )
1338 {
1339 sal_uInt8 nNameId = rStrm.readuInt8();
1340 rStrm.skip( 3 );
1341 maSheetSrcModel.maDefName = OUString( sal_Unicode( nNameId ) );
1342 importDConUrl( rStrm );
1343 }
1344
importDConUrl(BiffInputStream & rStrm)1345 void PivotCache::importDConUrl( BiffInputStream& rStrm )
1346 {
1347 // the URL with sheet name and optional URL of an external document
1348 OUString aEncodedUrl;
1349 if( getBiff() == BIFF8 )
1350 {
1351 // empty string does not contain a flags byte, cannot use simple readUniString() here...
1352 sal_uInt16 nChars = rStrm.readuInt16();
1353 if( nChars > 0 )
1354 aEncodedUrl = rStrm.readUniString( nChars );
1355 }
1356 else
1357 {
1358 aEncodedUrl = rStrm.readByteStringUC( false, getTextEncoding() );
1359 }
1360
1361 if( aEncodedUrl.getLength() > 0 )
1362 {
1363 OUString aClassName;
1364 getAddressConverter().parseBiffTargetUrl( aClassName, maTargetUrl, maSheetSrcModel.maSheet, aEncodedUrl, true );
1365 }
1366 }
1367
finalizeInternalSheetSource()1368 void PivotCache::finalizeInternalSheetSource()
1369 {
1370 // resolve sheet name to sheet index
1371 sal_Int16 nSheet = getWorksheets().getCalcSheetIndex( maSheetSrcModel.maSheet );
1372
1373 // if cache is based on a defined name or table, try to resolve to cell range
1374 if( maSheetSrcModel.maDefName.getLength() > 0 )
1375 {
1376 // local or global defined name
1377 if( const DefinedName* pDefName = getDefinedNames().getByModelName( maSheetSrcModel.maDefName, nSheet ).get() )
1378 {
1379 mbValidSource = pDefName->getAbsoluteRange( maSheetSrcModel.maRange );
1380 }
1381 // table
1382 else if( const Table* pTable = getTables().getTable( maSheetSrcModel.maDefName ).get() )
1383 {
1384 // get original range from table, but exclude the totals row(s)
1385 maSheetSrcModel.maRange = pTable->getOriginalRange();
1386 mbValidSource = (pTable->getHeight() - pTable->getTotalsRows()) > 1;
1387 if( mbValidSource )
1388 maSheetSrcModel.maRange.EndRow -= pTable->getTotalsRows();
1389 }
1390 }
1391 // else try the cell range (if the sheet exists)
1392 else if( nSheet >= 0 )
1393 {
1394 // insert sheet index into the range, range address will be checked below
1395 maSheetSrcModel.maRange.Sheet = nSheet;
1396 mbValidSource = true;
1397 }
1398 // else sheet has been deleted, generate the source data from cache
1399 else if( maSheetSrcModel.maSheet.getLength() > 0 )
1400 {
1401 prepareSourceDataSheet();
1402 // return here to skip the source range check below
1403 return;
1404 }
1405
1406 // check range location, do not allow ranges that overflow the sheet partly
1407 mbValidSource = mbValidSource &&
1408 getAddressConverter().checkCellRange( maSheetSrcModel.maRange, false, true ) &&
1409 (maSheetSrcModel.maRange.StartRow < maSheetSrcModel.maRange.EndRow);
1410 }
1411
finalizeExternalSheetSource()1412 void PivotCache::finalizeExternalSheetSource()
1413 {
1414 /* If pivot cache is based on external sheet data, try to restore sheet
1415 data from cache records. No support for external defined names or tables,
1416 sheet name and path to cache records fragment (OOXML only) are required. */
1417 bool bHasRelation = (getFilterType() == FILTER_BIFF) || (maDefModel.maRelId.getLength() > 0);
1418 if( bHasRelation && (maSheetSrcModel.maDefName.getLength() == 0) && (maSheetSrcModel.maSheet.getLength() > 0) )
1419 prepareSourceDataSheet();
1420 }
1421
prepareSourceDataSheet()1422 void PivotCache::prepareSourceDataSheet()
1423 {
1424 CellRangeAddress& rRange = maSheetSrcModel.maRange;
1425 // data will be inserted in top-left cell, sheet index is still set to 0 (will be set below)
1426 rRange.EndColumn -= rRange.StartColumn;
1427 rRange.StartColumn = 0;
1428 rRange.EndRow -= rRange.StartRow;
1429 rRange.StartRow = 0;
1430 // check range location, do not allow ranges that overflow the sheet partly
1431 if( getAddressConverter().checkCellRange( rRange, false, true ) )
1432 {
1433 maColSpans.insert( ValueRange( rRange.StartColumn, rRange.EndColumn ) );
1434 OUString aSheetName = CREATE_OUSTRING( "DPCache_" ) + maSheetSrcModel.maSheet;
1435 rRange.Sheet = getWorksheets().insertEmptySheet( aSheetName, false );
1436 mbValidSource = mbDummySheet = rRange.Sheet >= 0;
1437 }
1438 }
1439
updateSourceDataRow(WorksheetHelper & rSheetHelper,sal_Int32 nRow) const1440 void PivotCache::updateSourceDataRow( WorksheetHelper& rSheetHelper, sal_Int32 nRow ) const
1441 {
1442 if( mnCurrRow != nRow )
1443 {
1444 rSheetHelper.getSheetData().setColSpans( nRow, maColSpans );
1445 mnCurrRow = nRow;
1446 }
1447 }
1448
1449 // ============================================================================
1450
PivotCacheBuffer(const WorkbookHelper & rHelper)1451 PivotCacheBuffer::PivotCacheBuffer( const WorkbookHelper& rHelper ) :
1452 WorkbookHelper( rHelper )
1453 {
1454 }
1455
registerPivotCacheFragment(sal_Int32 nCacheId,const OUString & rFragmentPath)1456 void PivotCacheBuffer::registerPivotCacheFragment( sal_Int32 nCacheId, const OUString& rFragmentPath )
1457 {
1458 OSL_ENSURE( nCacheId >= 0, "PivotCacheBuffer::registerPivotCacheFragment - invalid pivot cache identifier" );
1459 OSL_ENSURE( maFragmentPaths.count( nCacheId ) == 0, "PivotCacheBuffer::registerPivotCacheFragment - fragment path exists already" );
1460 if( (nCacheId >= 0) && (rFragmentPath.getLength() > 0) )
1461 maFragmentPaths[ nCacheId ] = rFragmentPath;
1462 }
1463
importPivotCacheRef(BiffInputStream & rStrm)1464 void PivotCacheBuffer::importPivotCacheRef( BiffInputStream& rStrm )
1465 {
1466 // read the PIVOTCACHE record that contains the stream ID
1467 sal_Int32 nCacheId = rStrm.readuInt16();
1468 OSL_ENSURE( maFragmentPaths.count( nCacheId ) == 0, "PivotCacheBuffer::importPivotCacheRef - cache stream exists already" );
1469 OUStringBuffer aStrmName;
1470 static const sal_Unicode spcHexChars[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
1471 for( sal_uInt8 nBit = 0; nBit < 16; nBit += 4 )
1472 aStrmName.insert( 0, spcHexChars[ extractValue< size_t >( nCacheId, nBit, 4 ) ] );
1473 aStrmName.insert( 0, (getBiff() == BIFF8) ? CREATE_OUSTRING( "_SX_DB_CUR/" ) : CREATE_OUSTRING( "_SX_DB/" ) );
1474 maFragmentPaths[ nCacheId ] = aStrmName.makeStringAndClear();
1475
1476 // try to read PCDSOURCE record (will read following data location records too)
1477 sal_uInt16 nNextRecId = rStrm.getNextRecId();
1478 OSL_ENSURE( nNextRecId == BIFF_ID_PCDSOURCE, "PivotCacheBuffer::importPivotCacheRef - PCDSOURCE record expected" );
1479 if( (nNextRecId == BIFF_ID_PCDSOURCE) && rStrm.startNextRecord() )
1480 createPivotCache( nCacheId ).importPCDSource( rStrm );
1481 }
1482
importPivotCacheFragment(sal_Int32 nCacheId)1483 PivotCache* PivotCacheBuffer::importPivotCacheFragment( sal_Int32 nCacheId )
1484 {
1485 switch( getFilterType() )
1486 {
1487 /* OOXML/BIFF12 filter: On first call for the cache ID, the pivot
1488 cache object is created and inserted into maCaches. Then, the cache
1489 definition fragment is read and the cache is returned. On
1490 subsequent calls, the created cache will be found in maCaches and
1491 returned immediately. */
1492 case FILTER_OOXML:
1493 {
1494 // try to find an imported pivot cache
1495 if( PivotCache* pCache = maCaches.get( nCacheId ).get() )
1496 return pCache;
1497
1498 // check if a fragment path exists for the passed cache identifier
1499 FragmentPathMap::iterator aIt = maFragmentPaths.find( nCacheId );
1500 if( aIt == maFragmentPaths.end() )
1501 return 0;
1502
1503 /* Import the cache fragment. This may create a dummy data sheet
1504 for external sheet sources. */
1505 PivotCache& rCache = createPivotCache( nCacheId );
1506 importOoxFragment( new PivotCacheDefinitionFragment( *this, aIt->second, rCache ) );
1507 return &rCache;
1508 }
1509
1510 /* BIFF filter: Pivot table provides 0-based index into list of pivot
1511 cache source links (PIVOTCACHE/PCDSOURCE/... record blocks in
1512 workbook stream). First, this index has to be resolved to the cache
1513 identifier that is used to manage the cache stream names (the
1514 maFragmentPaths member). The cache object itself exists already
1515 before the first call for the cache source index (see
1516 PivotCacheBuffer::importPivotCacheRef() above), because source data
1517 link is part of workbook data, not of the cache stream. To detect
1518 subsequent calls with an already initialized cache, the entry in
1519 maFragmentPaths will be removed after reading the cache stream. */
1520 case FILTER_BIFF:
1521 {
1522 /* Resolve cache index to cache identifier and try to find pivot
1523 cache. Cache must exist already for a valid cache index. */
1524 nCacheId = ContainerHelper::getVectorElement( maCacheIds, nCacheId, -1 );
1525 PivotCache* pCache = maCaches.get( nCacheId ).get();
1526 if( !pCache )
1527 return 0;
1528
1529 /* Try to find fragment path entry (stream name). If missing, the
1530 stream has been read already, and the cache can be returned. */
1531 FragmentPathMap::iterator aIt = maFragmentPaths.find( nCacheId );
1532 if( aIt != maFragmentPaths.end() )
1533 {
1534 /* Import the cache stream. This may create a dummy data sheet
1535 for external sheet sources. */
1536 BiffPivotCacheFragment( *this, aIt->second, *pCache ).importFragment();
1537 // remove the fragment entry to mark that the cache is initialized
1538 maFragmentPaths.erase( aIt );
1539 }
1540 return pCache;
1541 }
1542
1543 case FILTER_UNKNOWN:
1544 OSL_ENSURE( false, "PivotCacheBuffer::importPivotCacheFragment - unknown filter type" );
1545 }
1546 return 0;
1547 }
1548
createPivotCache(sal_Int32 nCacheId)1549 PivotCache& PivotCacheBuffer::createPivotCache( sal_Int32 nCacheId )
1550 {
1551 maCacheIds.push_back( nCacheId );
1552 PivotCacheMap::mapped_type& rxCache = maCaches[ nCacheId ];
1553 rxCache.reset( new PivotCache( *this ) );
1554 return *rxCache;
1555 }
1556
1557 // ============================================================================
1558
1559 } // namespace xls
1560 } // namespace oox
1561