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 */ 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 170 PivotCacheItem::PivotCacheItem() : 171 mnType( XML_m ) 172 { 173 } 174 175 void PivotCacheItem::readString( const AttributeList& rAttribs ) 176 { 177 maValue <<= rAttribs.getXString( XML_v, OUString() ); 178 mnType = XML_s; 179 } 180 181 void PivotCacheItem::readNumeric( const AttributeList& rAttribs ) 182 { 183 maValue <<= rAttribs.getDouble( XML_v, 0.0 ); 184 mnType = XML_n; 185 } 186 187 void PivotCacheItem::readDate( const AttributeList& rAttribs ) 188 { 189 maValue <<= rAttribs.getDateTime( XML_v, DateTime() ); 190 mnType = XML_d; 191 } 192 193 void PivotCacheItem::readBool( const AttributeList& rAttribs ) 194 { 195 maValue <<= rAttribs.getBool( XML_v, false ); 196 mnType = XML_b; 197 } 198 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 205 void PivotCacheItem::readIndex( const AttributeList& rAttribs ) 206 { 207 maValue <<= rAttribs.getInteger( XML_v, -1 ); 208 mnType = XML_x; 209 } 210 211 void PivotCacheItem::readString( SequenceInputStream& rStrm ) 212 { 213 maValue <<= BiffHelper::readString( rStrm ); 214 mnType = XML_s; 215 } 216 217 void PivotCacheItem::readDouble( SequenceInputStream& rStrm ) 218 { 219 maValue <<= rStrm.readDouble(); 220 mnType = XML_n; 221 } 222 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 237 void PivotCacheItem::readBool( SequenceInputStream& rStrm ) 238 { 239 maValue <<= (rStrm.readuInt8() != 0); 240 mnType = XML_b; 241 } 242 243 void PivotCacheItem::readError( SequenceInputStream& rStrm ) 244 { 245 maValue <<= static_cast< sal_Int32 >( rStrm.readuInt8() ); 246 mnType = XML_e; 247 } 248 249 void PivotCacheItem::readIndex( SequenceInputStream& rStrm ) 250 { 251 maValue <<= rStrm.readInt32(); 252 mnType = XML_x; 253 } 254 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 261 void PivotCacheItem::readDouble( BiffInputStream& rStrm ) 262 { 263 maValue <<= rStrm.readDouble(); 264 mnType = XML_n; 265 } 266 267 void PivotCacheItem::readInteger( BiffInputStream& rStrm ) 268 { 269 maValue <<= rStrm.readInt16(); 270 mnType = XML_i; // fake, used for BIFF only 271 } 272 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 287 void PivotCacheItem::readBool( BiffInputStream& rStrm ) 288 { 289 maValue <<= (rStrm.readuInt8() != 0); 290 mnType = XML_b; 291 } 292 293 void PivotCacheItem::readError( BiffInputStream& rStrm ) 294 { 295 maValue <<= static_cast< sal_Int32 >( rStrm.readuInt8() ); 296 mnType = XML_e; 297 } 298 299 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 317 PivotCacheItemList::PivotCacheItemList( const WorkbookHelper& rHelper ) : 318 WorkbookHelper( rHelper ) 319 { 320 } 321 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 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 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 385 const PivotCacheItem* PivotCacheItemList::getCacheItem( sal_Int32 nItemIdx ) const 386 { 387 return ContainerHelper::getVectorElement( maItems, nItemIdx ); 388 } 389 390 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 400 PivotCacheItem& PivotCacheItemList::createItem() 401 { 402 maItems.resize( maItems.size() + 1 ); 403 return maItems.back(); 404 } 405 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 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 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 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 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 481 PivotCacheField::PivotCacheField( const WorkbookHelper& rHelper, bool bIsDatabaseField ) : 482 WorkbookHelper( rHelper ), 483 maSharedItems( rHelper ), 484 maGroupItems( rHelper ) 485 { 486 maFieldModel.mbDatabaseField = bIsDatabaseField; 487 } 488 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 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 520 void PivotCacheField::importSharedItem( sal_Int32 nElement, const AttributeList& rAttribs ) 521 { 522 maSharedItems.importItem( nElement, rAttribs ); 523 } 524 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 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 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 552 void PivotCacheField::importGroupItem( sal_Int32 nElement, const AttributeList& rAttribs ) 553 { 554 maGroupItems.importItem( nElement, rAttribs ); 555 } 556 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 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 593 void PivotCacheField::importPCDFSharedItem( sal_Int32 nRecId, SequenceInputStream& rStrm ) 594 { 595 maSharedItems.importItem( nRecId, rStrm ); 596 } 597 598 void PivotCacheField::importPCDFieldGroup( SequenceInputStream& rStrm ) 599 { 600 rStrm >> maFieldGroupModel.mnParentField >> maFieldGroupModel.mnBaseField; 601 } 602 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 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 629 void PivotCacheField::importPCDFGroupItem( sal_Int32 nRecId, SequenceInputStream& rStrm ) 630 { 631 maGroupItems.importItem( nRecId, rStrm ); 632 } 633 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 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 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 741 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 750 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 758 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 776 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 820 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 933 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 940 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 950 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 969 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 978 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 999 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 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 1028 PCSourceModel::PCSourceModel() : 1029 mnSourceType( XML_TOKEN_INVALID ), 1030 mnConnectionId( 0 ) 1031 { 1032 } 1033 1034 // ---------------------------------------------------------------------------- 1035 1036 PCWorksheetSourceModel::PCWorksheetSourceModel() 1037 { 1038 maRange.StartColumn = maRange.StartRow = maRange.EndColumn = maRange.EndRow = -1; 1039 } 1040 1041 // ---------------------------------------------------------------------------- 1042 1043 PivotCache::PivotCache( const WorkbookHelper& rHelper ) : 1044 WorkbookHelper( rHelper ), 1045 mnCurrRow( -1 ), 1046 mbValidSource( false ), 1047 mbDummySheet( false ) 1048 { 1049 } 1050 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 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 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 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 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 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 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 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 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 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 1256 sal_Int32 PivotCache::getCacheFieldCount() const 1257 { 1258 return static_cast< sal_Int32 >( maFields.size() ); 1259 } 1260 1261 const PivotCacheField* PivotCache::getCacheField( sal_Int32 nFieldIdx ) const 1262 { 1263 return maFields.get( nFieldIdx ).get(); 1264 } 1265 1266 sal_Int32 PivotCache::getCacheDatabaseIndex( sal_Int32 nFieldIdx ) const 1267 { 1268 return ContainerHelper::getVectorElement( maDatabaseIndexes, nFieldIdx, -1 ); 1269 } 1270 1271 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 1284 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 1295 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 1305 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 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 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 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 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 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 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 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 1440 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 1451 PivotCacheBuffer::PivotCacheBuffer( const WorkbookHelper& rHelper ) : 1452 WorkbookHelper( rHelper ) 1453 { 1454 } 1455 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 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 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 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