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