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