| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #include "oox/xls/pivotcachebuffer.hxx" |
| |
| #include <set> |
| #include <com/sun/star/container/XIndexAccess.hpp> |
| #include <com/sun/star/container/XNameAccess.hpp> |
| #include <com/sun/star/container/XNamed.hpp> |
| #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> |
| #include <com/sun/star/sheet/DataPilotFieldGroupInfo.hpp> |
| #include <com/sun/star/sheet/XDataPilotFieldGrouping.hpp> |
| #include <rtl/ustrbuf.hxx> |
| #include "oox/core/filterbase.hxx" |
| #include "oox/helper/attributelist.hxx" |
| #include "oox/helper/containerhelper.hxx" |
| #include "oox/helper/propertyset.hxx" |
| #include "oox/xls/biffinputstream.hxx" |
| #include "oox/xls/defnamesbuffer.hxx" |
| #include "oox/xls/excelhandlers.hxx" |
| #include "oox/xls/pivotcachefragment.hxx" |
| #include "oox/xls/sheetdatabuffer.hxx" |
| #include "oox/xls/tablebuffer.hxx" |
| #include "oox/xls/unitconverter.hxx" |
| #include "oox/xls/worksheetbuffer.hxx" |
| |
| namespace oox { |
| namespace xls { |
| |
| // ============================================================================ |
| |
| using namespace ::com::sun::star::container; |
| using namespace ::com::sun::star::sheet; |
| using namespace ::com::sun::star::table; |
| using namespace ::com::sun::star::uno; |
| using namespace ::com::sun::star::util; |
| |
| using ::oox::core::Relations; |
| using ::rtl::OUString; |
| using ::rtl::OUStringBuffer; |
| |
| // ============================================================================ |
| |
| namespace { |
| |
| const sal_uInt16 BIFF12_PCDFIELD_SERVERFIELD = 0x0001; |
| const sal_uInt16 BIFF12_PCDFIELD_NOUNIQUEITEMS = 0x0002; |
| const sal_uInt16 BIFF12_PCDFIELD_DATABASEFIELD = 0x0004; |
| const sal_uInt16 BIFF12_PCDFIELD_HASCAPTION = 0x0008; |
| const sal_uInt16 BIFF12_PCDFIELD_MEMBERPROPFIELD = 0x0010; |
| const sal_uInt16 BIFF12_PCDFIELD_HASFORMULA = 0x0100; |
| const sal_uInt16 BIFF12_PCDFIELD_HASPROPERTYNAME = 0x0200; |
| |
| const sal_uInt16 BIFF12_PCDFSITEMS_HASSEMIMIXED = 0x0001; |
| const sal_uInt16 BIFF12_PCDFSITEMS_HASNONDATE = 0x0002; |
| const sal_uInt16 BIFF12_PCDFSITEMS_HASDATE = 0x0004; |
| const sal_uInt16 BIFF12_PCDFSITEMS_HASSTRING = 0x0008; |
| const sal_uInt16 BIFF12_PCDFSITEMS_HASBLANK = 0x0010; |
| const sal_uInt16 BIFF12_PCDFSITEMS_HASMIXED = 0x0020; |
| const sal_uInt16 BIFF12_PCDFSITEMS_ISNUMERIC = 0x0040; |
| const sal_uInt16 BIFF12_PCDFSITEMS_ISINTEGER = 0x0080; |
| const sal_uInt16 BIFF12_PCDFSITEMS_HASMINMAX = 0x0100; |
| const sal_uInt16 BIFF12_PCDFSITEMS_HASLONGTEXT = 0x0200; |
| |
| const sal_uInt16 BIFF12_PCITEM_ARRAY_DOUBLE = 0x0001; |
| const sal_uInt16 BIFF12_PCITEM_ARRAY_STRING = 0x0002; |
| const sal_uInt16 BIFF12_PCITEM_ARRAY_ERROR = 0x0010; |
| const sal_uInt16 BIFF12_PCITEM_ARRAY_DATE = 0x0020; |
| |
| const sal_uInt8 BIFF12_PCDFRANGEPR_AUTOSTART = 0x01; |
| const sal_uInt8 BIFF12_PCDFRANGEPR_AUTOEND = 0x02; |
| const sal_uInt8 BIFF12_PCDFRANGEPR_DATEGROUP = 0x04; |
| |
| const sal_uInt8 BIFF12_PCDEFINITION_SAVEDATA = 0x01; |
| const sal_uInt8 BIFF12_PCDEFINITION_INVALID = 0x02; |
| const sal_uInt8 BIFF12_PCDEFINITION_REFRESHONLOAD = 0x04; |
| const sal_uInt8 BIFF12_PCDEFINITION_OPTIMIZEMEMORY = 0x08; |
| const sal_uInt8 BIFF12_PCDEFINITION_ENABLEREFRESH = 0x10; |
| const sal_uInt8 BIFF12_PCDEFINITION_BACKGROUNDQUERY = 0x20; |
| const sal_uInt8 BIFF12_PCDEFINITION_UPGRADEONREFR = 0x40; |
| const sal_uInt8 BIFF12_PCDEFINITION_TUPELCACHE = 0x80; |
| |
| const sal_uInt8 BIFF12_PCDEFINITION_HASUSERNAME = 0x01; |
| const sal_uInt8 BIFF12_PCDEFINITION_HASRELID = 0x02; |
| const sal_uInt8 BIFF12_PCDEFINITION_SUPPORTSUBQUERY = 0x04; |
| const sal_uInt8 BIFF12_PCDEFINITION_SUPPORTDRILL = 0x08; |
| |
| const sal_uInt8 BIFF12_PCDWBSOURCE_HASRELID = 0x01; |
| const sal_uInt8 BIFF12_PCDWBSOURCE_HASSHEET = 0x02; |
| |
| // ---------------------------------------------------------------------------- |
| |
| const sal_uInt16 BIFF_PCDSOURCE_WORKSHEET = 0x0001; |
| const sal_uInt16 BIFF_PCDSOURCE_EXTERNAL = 0x0002; |
| const sal_uInt16 BIFF_PCDSOURCE_CONSOLIDATION = 0x0004; |
| const sal_uInt16 BIFF_PCDSOURCE_SCENARIO = 0x0010; |
| |
| const sal_uInt16 BIFF_PC_NOSTRING = 0xFFFF; |
| |
| const sal_uInt16 BIFF_PCDFIELD_HASITEMS = 0x0001; |
| const sal_uInt16 BIFF_PCDFIELD_HASUNSHAREDITEMS = 0x0002; |
| const sal_uInt16 BIFF_PCDFIELD_CALCULATED = 0x0004; |
| const sal_uInt16 BIFF_PCDFIELD_HASPARENT = 0x0008; |
| const sal_uInt16 BIFF_PCDFIELD_RANGEGROUP = 0x0010; |
| const sal_uInt16 BIFF_PCDFIELD_ISNUMERIC = 0x0020; |
| const sal_uInt16 BIFF_PCDFIELD_HASSEMIMIXED = 0x0080; |
| const sal_uInt16 BIFF_PCDFIELD_HASMINMAX = 0x0100; |
| const sal_uInt16 BIFF_PCDFIELD_HASLONGINDEX = 0x0200; |
| const sal_uInt16 BIFF_PCDFIELD_HASNONDATE = 0x0400; |
| const sal_uInt16 BIFF_PCDFIELD_HASDATE = 0x0800; |
| const sal_uInt16 BIFF_PCDFIELD_SERVERFIELD = 0x2000; |
| const sal_uInt16 BIFF_PCDFIELD_NOUNIQUEITEMS = 0x4000; |
| |
| const sal_uInt16 BIFF_PCDFRANGEPR_AUTOSTART = 0x0001; |
| const sal_uInt16 BIFF_PCDFRANGEPR_AUTOEND = 0x0002; |
| |
| const sal_uInt16 BIFF_PCDEFINITION_SAVEDATA = 0x0001; |
| const sal_uInt16 BIFF_PCDEFINITION_INVALID = 0x0002; |
| const sal_uInt16 BIFF_PCDEFINITION_REFRESHONLOAD = 0x0004; |
| const sal_uInt16 BIFF_PCDEFINITION_OPTIMIZEMEMORY = 0x0008; |
| const sal_uInt16 BIFF_PCDEFINITION_BACKGROUNDQUERY = 0x0010; |
| const sal_uInt16 BIFF_PCDEFINITION_ENABLEREFRESH = 0x0020; |
| |
| // ---------------------------------------------------------------------------- |
| |
| /** Adjusts the weird date format read from binary streams. |
| |
| Dates before 1900-Mar-01 are stored including the non-existing leap day |
| 1900-02-29. Time values (without date) are stored as times of day |
| 1900-Jan-00. Nothing has to be done when the workbook is stored in 1904 |
| date mode (dates before 1904-Jan-01 will not occur in this case). |
| */ |
| void lclAdjustBinDateTime( DateTime& orDateTime ) |
| { |
| if( (orDateTime.Year == 1900) && (orDateTime.Month <= 2) ) |
| { |
| OSL_ENSURE( (orDateTime.Month == 1) || ((orDateTime.Month == 2) && (orDateTime.Day > 0)), "lclAdjustBinDateTime - invalid date" ); |
| switch( orDateTime.Month ) |
| { |
| case 2: if( orDateTime.Day > 1 ) --orDateTime.Day; else { orDateTime.Day += 30; --orDateTime.Month; } break; |
| case 1: if( orDateTime.Day > 1 ) --orDateTime.Day; else { orDateTime.Day += 30; orDateTime.Month = 12; --orDateTime.Year; } break; |
| } |
| } |
| } |
| |
| } // namespace |
| |
| // ============================================================================ |
| |
| PivotCacheItem::PivotCacheItem() : |
| mnType( XML_m ) |
| { |
| } |
| |
| void PivotCacheItem::readString( const AttributeList& rAttribs ) |
| { |
| maValue <<= rAttribs.getXString( XML_v, OUString() ); |
| mnType = XML_s; |
| } |
| |
| void PivotCacheItem::readNumeric( const AttributeList& rAttribs ) |
| { |
| maValue <<= rAttribs.getDouble( XML_v, 0.0 ); |
| mnType = XML_n; |
| } |
| |
| void PivotCacheItem::readDate( const AttributeList& rAttribs ) |
| { |
| maValue <<= rAttribs.getDateTime( XML_v, DateTime() ); |
| mnType = XML_d; |
| } |
| |
| void PivotCacheItem::readBool( const AttributeList& rAttribs ) |
| { |
| maValue <<= rAttribs.getBool( XML_v, false ); |
| mnType = XML_b; |
| } |
| |
| void PivotCacheItem::readError( const AttributeList& rAttribs, const UnitConverter& rUnitConverter ) |
| { |
| maValue <<= static_cast< sal_Int32 >( rUnitConverter.calcBiffErrorCode( rAttribs.getXString( XML_v, OUString() ) ) ); |
| mnType = XML_e; |
| } |
| |
| void PivotCacheItem::readIndex( const AttributeList& rAttribs ) |
| { |
| maValue <<= rAttribs.getInteger( XML_v, -1 ); |
| mnType = XML_x; |
| } |
| |
| void PivotCacheItem::readString( SequenceInputStream& rStrm ) |
| { |
| maValue <<= BiffHelper::readString( rStrm ); |
| mnType = XML_s; |
| } |
| |
| void PivotCacheItem::readDouble( SequenceInputStream& rStrm ) |
| { |
| maValue <<= rStrm.readDouble(); |
| mnType = XML_n; |
| } |
| |
| void PivotCacheItem::readDate( SequenceInputStream& rStrm ) |
| { |
| DateTime aDateTime; |
| aDateTime.Year = rStrm.readuInt16(); |
| aDateTime.Month = rStrm.readuInt16(); |
| aDateTime.Day = rStrm.readuInt8(); |
| aDateTime.Hours = rStrm.readuInt8(); |
| aDateTime.Minutes = rStrm.readuInt8(); |
| aDateTime.Seconds = rStrm.readuInt8(); |
| lclAdjustBinDateTime( aDateTime ); |
| maValue <<= aDateTime; |
| mnType = XML_d; |
| } |
| |
| void PivotCacheItem::readBool( SequenceInputStream& rStrm ) |
| { |
| maValue <<= (rStrm.readuInt8() != 0); |
| mnType = XML_b; |
| } |
| |
| void PivotCacheItem::readError( SequenceInputStream& rStrm ) |
| { |
| maValue <<= static_cast< sal_Int32 >( rStrm.readuInt8() ); |
| mnType = XML_e; |
| } |
| |
| void PivotCacheItem::readIndex( SequenceInputStream& rStrm ) |
| { |
| maValue <<= rStrm.readInt32(); |
| mnType = XML_x; |
| } |
| |
| void PivotCacheItem::readString( BiffInputStream& rStrm, const WorkbookHelper& rHelper ) |
| { |
| maValue <<= (rHelper.getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( true, rHelper.getTextEncoding() ); |
| mnType = XML_s; |
| } |
| |
| void PivotCacheItem::readDouble( BiffInputStream& rStrm ) |
| { |
| maValue <<= rStrm.readDouble(); |
| mnType = XML_n; |
| } |
| |
| void PivotCacheItem::readInteger( BiffInputStream& rStrm ) |
| { |
| maValue <<= rStrm.readInt16(); |
| mnType = XML_i; // fake, used for BIFF only |
| } |
| |
| void PivotCacheItem::readDate( BiffInputStream& rStrm ) |
| { |
| DateTime aDateTime; |
| aDateTime.Year = rStrm.readuInt16(); |
| aDateTime.Month = rStrm.readuInt16(); |
| aDateTime.Day = rStrm.readuInt8(); |
| aDateTime.Hours = rStrm.readuInt8(); |
| aDateTime.Minutes = rStrm.readuInt8(); |
| aDateTime.Seconds = rStrm.readuInt8(); |
| lclAdjustBinDateTime( aDateTime ); |
| maValue <<= aDateTime; |
| mnType = XML_d; |
| } |
| |
| void PivotCacheItem::readBool( BiffInputStream& rStrm ) |
| { |
| maValue <<= (rStrm.readuInt8() != 0); |
| mnType = XML_b; |
| } |
| |
| void PivotCacheItem::readError( BiffInputStream& rStrm ) |
| { |
| maValue <<= static_cast< sal_Int32 >( rStrm.readuInt8() ); |
| mnType = XML_e; |
| } |
| |
| OUString PivotCacheItem::getName() const |
| { |
| switch( mnType ) |
| { |
| case XML_m: return OUString(); |
| case XML_s: return maValue.get< OUString >(); |
| case XML_n: return OUString::valueOf( maValue.get< double >() ); // !TODO |
| case XML_i: return OUString::valueOf( maValue.get< sal_Int32 >() ); |
| case XML_d: return OUString(); // !TODO |
| case XML_b: return OUString::valueOf( static_cast< sal_Bool >( maValue.get< bool >() ) ); // !TODO |
| case XML_e: return OUString(); // !TODO |
| } |
| OSL_ENSURE( false, "PivotCacheItem::getName - invalid data type" ); |
| return OUString(); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| PivotCacheItemList::PivotCacheItemList( const WorkbookHelper& rHelper ) : |
| WorkbookHelper( rHelper ) |
| { |
| } |
| |
| void PivotCacheItemList::importItem( sal_Int32 nElement, const AttributeList& rAttribs ) |
| { |
| PivotCacheItem& rItem = createItem(); |
| switch( nElement ) |
| { |
| case XLS_TOKEN( m ): break; |
| case XLS_TOKEN( s ): rItem.readString( rAttribs ); break; |
| case XLS_TOKEN( n ): rItem.readNumeric( rAttribs ); break; |
| case XLS_TOKEN( d ): rItem.readDate( rAttribs ); break; |
| case XLS_TOKEN( b ): rItem.readBool( rAttribs ); break; |
| case XLS_TOKEN( e ): rItem.readError( rAttribs, getUnitConverter() ); break; |
| default: OSL_ENSURE( false, "PivotCacheItemList::importItem - unknown element type" ); |
| } |
| } |
| |
| void PivotCacheItemList::importItem( sal_Int32 nRecId, SequenceInputStream& rStrm ) |
| { |
| if( nRecId == BIFF12_ID_PCITEM_ARRAY ) |
| { |
| importArray( rStrm ); |
| return; |
| } |
| |
| PivotCacheItem& rItem = createItem(); |
| switch( nRecId ) |
| { |
| case BIFF12_ID_PCITEM_MISSING: |
| case BIFF12_ID_PCITEMA_MISSING: break; |
| case BIFF12_ID_PCITEM_STRING: |
| case BIFF12_ID_PCITEMA_STRING: rItem.readString( rStrm ); break; |
| case BIFF12_ID_PCITEM_DOUBLE: |
| case BIFF12_ID_PCITEMA_DOUBLE: rItem.readDouble( rStrm ); break; |
| case BIFF12_ID_PCITEM_DATE: |
| case BIFF12_ID_PCITEMA_DATE: rItem.readDate( rStrm ); break; |
| case BIFF12_ID_PCITEM_BOOL: |
| case BIFF12_ID_PCITEMA_BOOL: rItem.readBool( rStrm ); break; |
| case BIFF12_ID_PCITEM_ERROR: |
| case BIFF12_ID_PCITEMA_ERROR: rItem.readError( rStrm ); break; |
| default: OSL_ENSURE( false, "PivotCacheItemList::importItem - unknown record type" ); |
| } |
| } |
| |
| void PivotCacheItemList::importItemList( BiffInputStream& rStrm, sal_uInt16 nCount ) |
| { |
| bool bLoop = true; |
| for( sal_uInt16 nItemIdx = 0; bLoop && (nItemIdx < nCount); ++nItemIdx ) |
| { |
| bLoop = rStrm.startNextRecord(); |
| if( bLoop ) switch( rStrm.getRecId() ) |
| { |
| case BIFF_ID_PCITEM_MISSING: createItem(); break; |
| case BIFF_ID_PCITEM_STRING: createItem().readString( rStrm, *this ); break; |
| case BIFF_ID_PCITEM_DOUBLE: createItem().readDouble( rStrm ); break; |
| case BIFF_ID_PCITEM_INTEGER: createItem().readInteger( rStrm ); break; |
| case BIFF_ID_PCITEM_DATE: createItem().readDate( rStrm ); break; |
| case BIFF_ID_PCITEM_BOOL: createItem().readBool( rStrm ); break; |
| case BIFF_ID_PCITEM_ERROR: createItem().readError( rStrm ); break; |
| default: rStrm.rewindRecord(); bLoop = false; |
| } |
| } |
| OSL_ENSURE( bLoop, "PivotCacheItemList::importItemList - could not read all cache item records" ); |
| } |
| |
| const PivotCacheItem* PivotCacheItemList::getCacheItem( sal_Int32 nItemIdx ) const |
| { |
| return ContainerHelper::getVectorElement( maItems, nItemIdx ); |
| } |
| |
| void PivotCacheItemList::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const |
| { |
| orItemNames.clear(); |
| orItemNames.reserve( maItems.size() ); |
| for( CacheItemVector::const_iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt ) |
| orItemNames.push_back( aIt->getName() ); |
| } |
| |
| // private -------------------------------------------------------------------- |
| |
| PivotCacheItem& PivotCacheItemList::createItem() |
| { |
| maItems.resize( maItems.size() + 1 ); |
| return maItems.back(); |
| } |
| |
| void PivotCacheItemList::importArray( SequenceInputStream& rStrm ) |
| { |
| sal_uInt16 nType = rStrm.readuInt16(); |
| sal_Int32 nCount = rStrm.readInt32(); |
| for( sal_Int32 nIdx = 0; !rStrm.isEof() && (nIdx < nCount); ++nIdx ) |
| { |
| switch( nType ) |
| { |
| case BIFF12_PCITEM_ARRAY_DOUBLE: createItem().readDouble( rStrm ); break; |
| case BIFF12_PCITEM_ARRAY_STRING: createItem().readString( rStrm ); break; |
| case BIFF12_PCITEM_ARRAY_ERROR: createItem().readError( rStrm ); break; |
| case BIFF12_PCITEM_ARRAY_DATE: createItem().readDate( rStrm ); break; |
| default: |
| OSL_ENSURE( false, "PivotCacheItemList::importArray - unknown data type" ); |
| nIdx = nCount; |
| } |
| } |
| } |
| |
| // ============================================================================ |
| |
| PCFieldModel::PCFieldModel() : |
| mnNumFmtId( 0 ), |
| mnSqlType( 0 ), |
| mnHierarchy( 0 ), |
| mnLevel( 0 ), |
| mnMappingCount( 0 ), |
| mbDatabaseField( true ), |
| mbServerField( false ), |
| mbUniqueList( true ), |
| mbMemberPropField( false ) |
| { |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| PCSharedItemsModel::PCSharedItemsModel() : |
| mbHasSemiMixed( true ), |
| mbHasNonDate( true ), |
| mbHasDate( false ), |
| mbHasString( true ), |
| mbHasBlank( false ), |
| mbHasMixed( false ), |
| mbIsNumeric( false ), |
| mbIsInteger( false ), |
| mbHasLongText( false ), |
| mbHasLongIndexes( false ) |
| { |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| PCFieldGroupModel::PCFieldGroupModel() : |
| mfStartValue( 0.0 ), |
| mfEndValue( 0.0 ), |
| mfInterval( 1.0 ), |
| mnParentField( -1 ), |
| mnBaseField( -1 ), |
| mnGroupBy( XML_range ), |
| mbRangeGroup( false ), |
| mbDateGroup( false ), |
| mbAutoStart( true ), |
| mbAutoEnd( true ) |
| { |
| } |
| |
| void PCFieldGroupModel::setBiffGroupBy( sal_uInt8 nGroupBy ) |
| { |
| static const sal_Int32 spnGroupBy[] = { XML_range, |
| XML_seconds, XML_minutes, XML_hours, XML_days, XML_months, XML_quarters, XML_years }; |
| mnGroupBy = STATIC_ARRAY_SELECT( spnGroupBy, nGroupBy, XML_range ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| PivotCacheField::PivotCacheField( const WorkbookHelper& rHelper, bool bIsDatabaseField ) : |
| WorkbookHelper( rHelper ), |
| maSharedItems( rHelper ), |
| maGroupItems( rHelper ) |
| { |
| maFieldModel.mbDatabaseField = bIsDatabaseField; |
| } |
| |
| void PivotCacheField::importCacheField( const AttributeList& rAttribs ) |
| { |
| maFieldModel.maName = rAttribs.getXString( XML_name, OUString() ); |
| maFieldModel.maCaption = rAttribs.getXString( XML_caption, OUString() ); |
| maFieldModel.maPropertyName = rAttribs.getXString( XML_propertyName, OUString() ); |
| maFieldModel.maFormula = rAttribs.getXString( XML_formula, OUString() ); |
| maFieldModel.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, 0 ); |
| maFieldModel.mnSqlType = rAttribs.getInteger( XML_sqlType, 0 ); |
| maFieldModel.mnHierarchy = rAttribs.getInteger( XML_hierarchy, 0 ); |
| maFieldModel.mnLevel = rAttribs.getInteger( XML_level, 0 ); |
| maFieldModel.mnMappingCount = rAttribs.getInteger( XML_mappingCount, 0 ); |
| maFieldModel.mbDatabaseField = rAttribs.getBool( XML_databaseField, true ); |
| maFieldModel.mbServerField = rAttribs.getBool( XML_serverField, false ); |
| maFieldModel.mbUniqueList = rAttribs.getBool( XML_uniqueList, true ); |
| maFieldModel.mbMemberPropField = rAttribs.getBool( XML_memberPropertyField, false ); |
| } |
| |
| void PivotCacheField::importSharedItems( const AttributeList& rAttribs ) |
| { |
| OSL_ENSURE( maSharedItems.empty(), "PivotCacheField::importSharedItems - multiple shared items elements" ); |
| maSharedItemsModel.mbHasSemiMixed = rAttribs.getBool( XML_containsSemiMixedTypes, true ); |
| maSharedItemsModel.mbHasNonDate = rAttribs.getBool( XML_containsNonDate, true ); |
| maSharedItemsModel.mbHasDate = rAttribs.getBool( XML_containsDate, false ); |
| maSharedItemsModel.mbHasString = rAttribs.getBool( XML_containsString, true ); |
| maSharedItemsModel.mbHasBlank = rAttribs.getBool( XML_containsBlank, false ); |
| maSharedItemsModel.mbHasMixed = rAttribs.getBool( XML_containsMixedTypes, false ); |
| maSharedItemsModel.mbIsNumeric = rAttribs.getBool( XML_containsNumber, false ); |
| maSharedItemsModel.mbIsInteger = rAttribs.getBool( XML_containsInteger, false ); |
| maSharedItemsModel.mbHasLongText = rAttribs.getBool( XML_longText, false ); |
| } |
| |
| void PivotCacheField::importSharedItem( sal_Int32 nElement, const AttributeList& rAttribs ) |
| { |
| maSharedItems.importItem( nElement, rAttribs ); |
| } |
| |
| void PivotCacheField::importFieldGroup( const AttributeList& rAttribs ) |
| { |
| maFieldGroupModel.mnParentField = rAttribs.getInteger( XML_par, -1 ); |
| maFieldGroupModel.mnBaseField = rAttribs.getInteger( XML_base, -1 ); |
| } |
| |
| void PivotCacheField::importRangePr( const AttributeList& rAttribs ) |
| { |
| maFieldGroupModel.maStartDate = rAttribs.getDateTime( XML_startDate, DateTime() ); |
| maFieldGroupModel.maEndDate = rAttribs.getDateTime( XML_endDate, DateTime() ); |
| maFieldGroupModel.mfStartValue = rAttribs.getDouble( XML_startNum, 0.0 ); |
| maFieldGroupModel.mfEndValue = rAttribs.getDouble( XML_endNum, 0.0 ); |
| maFieldGroupModel.mfInterval = rAttribs.getDouble( XML_groupInterval, 1.0 ); |
| maFieldGroupModel.mnGroupBy = rAttribs.getToken( XML_groupBy, XML_range ); |
| maFieldGroupModel.mbRangeGroup = true; |
| maFieldGroupModel.mbDateGroup = maFieldGroupModel.mnGroupBy != XML_range; |
| maFieldGroupModel.mbAutoStart = rAttribs.getBool( XML_autoStart, true ); |
| maFieldGroupModel.mbAutoEnd = rAttribs.getBool( XML_autoEnd, true ); |
| } |
| |
| void PivotCacheField::importDiscretePrItem( sal_Int32 nElement, const AttributeList& rAttribs ) |
| { |
| OSL_ENSURE( nElement == XLS_TOKEN( x ), "PivotCacheField::importDiscretePrItem - unexpected element" ); |
| if( nElement == XLS_TOKEN( x ) ) |
| maDiscreteItems.push_back( rAttribs.getInteger( XML_v, -1 ) ); |
| } |
| |
| void PivotCacheField::importGroupItem( sal_Int32 nElement, const AttributeList& rAttribs ) |
| { |
| maGroupItems.importItem( nElement, rAttribs ); |
| } |
| |
| void PivotCacheField::importPCDField( SequenceInputStream& rStrm ) |
| { |
| sal_uInt16 nFlags; |
| rStrm >> nFlags >> maFieldModel.mnNumFmtId; |
| maFieldModel.mnSqlType = rStrm.readInt16(); |
| rStrm >> maFieldModel.mnHierarchy >> maFieldModel.mnLevel >> maFieldModel.mnMappingCount >> maFieldModel.maName; |
| if( getFlag( nFlags, BIFF12_PCDFIELD_HASCAPTION ) ) |
| rStrm >> maFieldModel.maCaption; |
| if( getFlag( nFlags, BIFF12_PCDFIELD_HASFORMULA ) ) |
| rStrm.skip( ::std::max< sal_Int32 >( rStrm.readInt32(), 0 ) ); |
| if( maFieldModel.mnMappingCount > 0 ) |
| rStrm.skip( ::std::max< sal_Int32 >( rStrm.readInt32(), 0 ) ); |
| if( getFlag( nFlags, BIFF12_PCDFIELD_HASPROPERTYNAME ) ) |
| rStrm >> maFieldModel.maPropertyName; |
| |
| maFieldModel.mbDatabaseField = getFlag( nFlags, BIFF12_PCDFIELD_DATABASEFIELD ); |
| maFieldModel.mbServerField = getFlag( nFlags, BIFF12_PCDFIELD_SERVERFIELD ); |
| maFieldModel.mbUniqueList = !getFlag( nFlags, BIFF12_PCDFIELD_NOUNIQUEITEMS ); |
| maFieldModel.mbMemberPropField = getFlag( nFlags, BIFF12_PCDFIELD_MEMBERPROPFIELD ); |
| } |
| |
| void PivotCacheField::importPCDFSharedItems( SequenceInputStream& rStrm ) |
| { |
| sal_uInt16 nFlags; |
| rStrm >> nFlags; |
| maSharedItemsModel.mbHasSemiMixed = getFlag( nFlags, BIFF12_PCDFSITEMS_HASSEMIMIXED ); |
| maSharedItemsModel.mbHasNonDate = getFlag( nFlags, BIFF12_PCDFSITEMS_HASNONDATE ); |
| maSharedItemsModel.mbHasDate = getFlag( nFlags, BIFF12_PCDFSITEMS_HASDATE ); |
| maSharedItemsModel.mbHasString = getFlag( nFlags, BIFF12_PCDFSITEMS_HASSTRING ); |
| maSharedItemsModel.mbHasBlank = getFlag( nFlags, BIFF12_PCDFSITEMS_HASBLANK ); |
| maSharedItemsModel.mbHasMixed = getFlag( nFlags, BIFF12_PCDFSITEMS_HASMIXED ); |
| maSharedItemsModel.mbIsNumeric = getFlag( nFlags, BIFF12_PCDFSITEMS_ISNUMERIC ); |
| maSharedItemsModel.mbIsInteger = getFlag( nFlags, BIFF12_PCDFSITEMS_ISINTEGER ); |
| maSharedItemsModel.mbHasLongText = getFlag( nFlags, BIFF12_PCDFSITEMS_HASLONGTEXT ); |
| } |
| |
| void PivotCacheField::importPCDFSharedItem( sal_Int32 nRecId, SequenceInputStream& rStrm ) |
| { |
| maSharedItems.importItem( nRecId, rStrm ); |
| } |
| |
| void PivotCacheField::importPCDFieldGroup( SequenceInputStream& rStrm ) |
| { |
| rStrm >> maFieldGroupModel.mnParentField >> maFieldGroupModel.mnBaseField; |
| } |
| |
| void PivotCacheField::importPCDFRangePr( SequenceInputStream& rStrm ) |
| { |
| sal_uInt8 nGroupBy, nFlags; |
| rStrm >> nGroupBy >> nFlags >> maFieldGroupModel.mfStartValue >> maFieldGroupModel.mfEndValue >> maFieldGroupModel.mfInterval; |
| |
| maFieldGroupModel.setBiffGroupBy( nGroupBy ); |
| maFieldGroupModel.mbRangeGroup = true; |
| maFieldGroupModel.mbDateGroup = getFlag( nFlags, BIFF12_PCDFRANGEPR_DATEGROUP ); |
| maFieldGroupModel.mbAutoStart = getFlag( nFlags, BIFF12_PCDFRANGEPR_AUTOSTART ); |
| maFieldGroupModel.mbAutoEnd = getFlag( nFlags, BIFF12_PCDFRANGEPR_AUTOEND ); |
| |
| OSL_ENSURE( maFieldGroupModel.mbDateGroup == (maFieldGroupModel.mnGroupBy != XML_range), "PivotCacheField::importPCDFRangePr - wrong date flag" ); |
| if( maFieldGroupModel.mbDateGroup ) |
| { |
| maFieldGroupModel.maStartDate = getUnitConverter().calcDateTimeFromSerial( maFieldGroupModel.mfStartValue ); |
| maFieldGroupModel.maEndDate = getUnitConverter().calcDateTimeFromSerial( maFieldGroupModel.mfEndValue ); |
| } |
| } |
| |
| void PivotCacheField::importPCDFDiscretePrItem( sal_Int32 nRecId, SequenceInputStream& rStrm ) |
| { |
| OSL_ENSURE( nRecId == BIFF12_ID_PCITEM_INDEX, "PivotCacheField::importPCDFDiscretePrItem - unexpected record" ); |
| if( nRecId == BIFF12_ID_PCITEM_INDEX ) |
| maDiscreteItems.push_back( rStrm.readInt32() ); |
| } |
| |
| void PivotCacheField::importPCDFGroupItem( sal_Int32 nRecId, SequenceInputStream& rStrm ) |
| { |
| maGroupItems.importItem( nRecId, rStrm ); |
| } |
| |
| void PivotCacheField::importPCDField( BiffInputStream& rStrm ) |
| { |
| sal_uInt16 nFlags, nGroupItems, nBaseItems, nSharedItems; |
| rStrm >> nFlags; |
| maFieldGroupModel.mnParentField = rStrm.readuInt16(); |
| maFieldGroupModel.mnBaseField = rStrm.readuInt16(); |
| rStrm.skip( 2 ); // number of unique items (either shared or group) |
| rStrm >> nGroupItems >> nBaseItems >> nSharedItems; |
| maFieldModel.maName = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( true, getTextEncoding() ); |
| |
| maFieldModel.mbServerField = getFlag( nFlags, BIFF_PCDFIELD_SERVERFIELD ); |
| maFieldModel.mbUniqueList = !getFlag( nFlags, BIFF_PCDFIELD_NOUNIQUEITEMS ); |
| maSharedItemsModel.mbHasSemiMixed = getFlag( nFlags, BIFF_PCDFIELD_HASSEMIMIXED ); |
| maSharedItemsModel.mbHasNonDate = getFlag( nFlags, BIFF_PCDFIELD_HASNONDATE ); |
| maSharedItemsModel.mbHasDate = getFlag( nFlags, BIFF_PCDFIELD_HASDATE ); |
| maSharedItemsModel.mbIsNumeric = getFlag( nFlags, BIFF_PCDFIELD_ISNUMERIC ); |
| maSharedItemsModel.mbHasLongIndexes = getFlag( nFlags, BIFF_PCDFIELD_HASLONGINDEX ); |
| maFieldGroupModel.mbRangeGroup = getFlag( nFlags, BIFF_PCDFIELD_RANGEGROUP ); |
| |
| // in BIFF, presence of parent group field is denoted by a flag |
| if( !getFlag( nFlags, BIFF_PCDFIELD_HASPARENT ) ) |
| maFieldGroupModel.mnParentField = -1; |
| |
| // following PCDFSQLTYPE record contains SQL type |
| if( (rStrm.getNextRecId() == BIFF_ID_PCDFSQLTYPE) && rStrm.startNextRecord() ) |
| maFieldModel.mnSqlType = rStrm.readInt16(); |
| |
| // read group items, if any |
| if( nGroupItems > 0 ) |
| { |
| OSL_ENSURE( getFlag( nFlags, BIFF_PCDFIELD_HASITEMS ), "PivotCacheField::importPCDField - missing items flag" ); |
| maGroupItems.importItemList( rStrm, nGroupItems ); |
| |
| sal_uInt16 nNextRecId = rStrm.getNextRecId(); |
| bool bHasRangePr = nNextRecId == BIFF_ID_PCDFRANGEPR; |
| bool bHasDiscretePr = nNextRecId == BIFF_ID_PCDFDISCRETEPR; |
| |
| OSL_ENSURE( bHasRangePr || bHasDiscretePr, "PivotCacheField::importPCDField - missing group properties record" ); |
| OSL_ENSURE( bHasRangePr == maFieldGroupModel.mbRangeGroup, "PivotCacheField::importPCDField - invalid range grouping flag" ); |
| if( bHasRangePr && rStrm.startNextRecord() ) |
| importPCDFRangePr( rStrm ); |
| else if( bHasDiscretePr && rStrm.startNextRecord() ) |
| importPCDFDiscretePr( rStrm ); |
| } |
| |
| // read the shared items, if any |
| if( nSharedItems > 0 ) |
| { |
| OSL_ENSURE( getFlag( nFlags, BIFF_PCDFIELD_HASITEMS ), "PivotCacheField::importPCDField - missing items flag" ); |
| maSharedItems.importItemList( rStrm, nSharedItems ); |
| } |
| } |
| |
| void PivotCacheField::importPCDFRangePr( BiffInputStream& rStrm ) |
| { |
| sal_uInt16 nFlags; |
| rStrm >> nFlags; |
| maFieldGroupModel.setBiffGroupBy( extractValue< sal_uInt8 >( nFlags, 2, 3 ) ); |
| maFieldGroupModel.mbRangeGroup = true; |
| maFieldGroupModel.mbDateGroup = maFieldGroupModel.mnGroupBy != XML_range; |
| maFieldGroupModel.mbAutoStart = getFlag( nFlags, BIFF_PCDFRANGEPR_AUTOSTART ); |
| maFieldGroupModel.mbAutoEnd = getFlag( nFlags, BIFF_PCDFRANGEPR_AUTOEND ); |
| |
| /* Start, end, and interval are stored in 3 separate item records. Type of |
| the items is dependent on numeric/date mode. Numeric groups expect |
| three PCITEM_DOUBLE records, date groups expect two PCITEM_DATE records |
| and one PCITEM_INT record. */ |
| PivotCacheItemList aLimits( *this ); |
| aLimits.importItemList( rStrm, 3 ); |
| OSL_ENSURE( aLimits.size() == 3, "PivotCacheField::importPCDFRangePr - missing grouping records" ); |
| const PivotCacheItem* pStartValue = aLimits.getCacheItem( 0 ); |
| const PivotCacheItem* pEndValue = aLimits.getCacheItem( 1 ); |
| const PivotCacheItem* pInterval = aLimits.getCacheItem( 2 ); |
| if( pStartValue && pEndValue && pInterval ) |
| { |
| if( maFieldGroupModel.mbDateGroup ) |
| { |
| bool bHasTypes = (pStartValue->getType() == XML_d) && (pEndValue->getType() == XML_d) && (pInterval->getType() == XML_i); |
| OSL_ENSURE( bHasTypes, "PivotCacheField::importPCDFRangePr - wrong data types in grouping items" ); |
| if( bHasTypes ) |
| { |
| maFieldGroupModel.maStartDate = pStartValue->getValue().get< DateTime >(); |
| maFieldGroupModel.maEndDate = pEndValue->getValue().get< DateTime >(); |
| maFieldGroupModel.mfInterval = pInterval->getValue().get< sal_Int16 >(); |
| } |
| } |
| else |
| { |
| bool bHasTypes = (pStartValue->getType() == XML_n) && (pEndValue->getType() == XML_n) && (pInterval->getType() == XML_n); |
| OSL_ENSURE( bHasTypes, "PivotCacheField::importPCDFRangePr - wrong data types in grouping items" ); |
| if( bHasTypes ) |
| { |
| maFieldGroupModel.mfStartValue = pStartValue->getValue().get< double >(); |
| maFieldGroupModel.mfEndValue = pEndValue->getValue().get< double >(); |
| maFieldGroupModel.mfInterval = pInterval->getValue().get< double >(); |
| } |
| } |
| } |
| } |
| |
| void PivotCacheField::importPCDFDiscretePr( BiffInputStream& rStrm ) |
| { |
| sal_Int32 nCount = static_cast< sal_Int32 >( rStrm.size() / 2 ); |
| for( sal_Int32 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex ) |
| maDiscreteItems.push_back( rStrm.readuInt16() ); |
| } |
| |
| const PivotCacheItem* PivotCacheField::getCacheItem( sal_Int32 nItemIdx ) const |
| { |
| if( hasGroupItems() ) |
| return maGroupItems.getCacheItem( nItemIdx ); |
| if( hasSharedItems() ) |
| return maSharedItems.getCacheItem( nItemIdx ); |
| return 0; |
| } |
| |
| void PivotCacheField::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const |
| { |
| if( hasGroupItems() ) |
| maGroupItems.getCacheItemNames( orItemNames ); |
| else if( hasSharedItems() ) |
| maSharedItems.getCacheItemNames( orItemNames ); |
| } |
| |
| void PivotCacheField::convertNumericGrouping( const Reference< XDataPilotField >& rxDPField ) const |
| { |
| OSL_ENSURE( hasGroupItems() && hasNumericGrouping(), "PivotCacheField::convertNumericGrouping - not a numeric group field" ); |
| PropertySet aPropSet( rxDPField ); |
| if( hasGroupItems() && hasNumericGrouping() && aPropSet.is() ) |
| { |
| DataPilotFieldGroupInfo aGroupInfo; |
| aGroupInfo.HasAutoStart = maFieldGroupModel.mbAutoStart; |
| aGroupInfo.HasAutoEnd = maFieldGroupModel.mbAutoEnd; |
| aGroupInfo.HasDateValues = sal_False; |
| aGroupInfo.Start = maFieldGroupModel.mfStartValue; |
| aGroupInfo.End = maFieldGroupModel.mfEndValue; |
| aGroupInfo.Step = maFieldGroupModel.mfInterval; |
| aGroupInfo.GroupBy = 0; |
| aPropSet.setProperty( PROP_GroupInfo, aGroupInfo ); |
| } |
| } |
| |
| OUString PivotCacheField::createDateGroupField( const Reference< XDataPilotField >& rxBaseDPField ) const |
| { |
| OSL_ENSURE( hasGroupItems() && hasDateGrouping(), "PivotCacheField::createDateGroupField - not a numeric group field" ); |
| Reference< XDataPilotField > xDPGroupField; |
| PropertySet aPropSet( rxBaseDPField ); |
| if( hasGroupItems() && hasDateGrouping() && aPropSet.is() ) |
| { |
| bool bDayRanges = (maFieldGroupModel.mnGroupBy == XML_days) && (maFieldGroupModel.mfInterval >= 2.0); |
| |
| DataPilotFieldGroupInfo aGroupInfo; |
| aGroupInfo.HasAutoStart = maFieldGroupModel.mbAutoStart; |
| aGroupInfo.HasAutoEnd = maFieldGroupModel.mbAutoEnd; |
| aGroupInfo.HasDateValues = sal_True; |
| aGroupInfo.Start = getUnitConverter().calcSerialFromDateTime( maFieldGroupModel.maStartDate ); |
| aGroupInfo.End = getUnitConverter().calcSerialFromDateTime( maFieldGroupModel.maEndDate ); |
| aGroupInfo.Step = bDayRanges ? maFieldGroupModel.mfInterval : 0.0; |
| |
| using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy; |
| switch( maFieldGroupModel.mnGroupBy ) |
| { |
| case XML_years: aGroupInfo.GroupBy = YEARS; break; |
| case XML_quarters: aGroupInfo.GroupBy = QUARTERS; break; |
| case XML_months: aGroupInfo.GroupBy = MONTHS; break; |
| case XML_days: aGroupInfo.GroupBy = DAYS; break; |
| case XML_hours: aGroupInfo.GroupBy = HOURS; break; |
| case XML_minutes: aGroupInfo.GroupBy = MINUTES; break; |
| case XML_seconds: aGroupInfo.GroupBy = SECONDS; break; |
| default: OSL_ENSURE( false, "PivotCacheField::convertRangeGrouping - unknown date/time interval" ); |
| } |
| |
| try |
| { |
| Reference< XDataPilotFieldGrouping > xDPGrouping( rxBaseDPField, UNO_QUERY_THROW ); |
| xDPGroupField = xDPGrouping->createDateGroup( aGroupInfo ); |
| } |
| catch( Exception& ) |
| { |
| } |
| } |
| |
| Reference< XNamed > xFieldName( xDPGroupField, UNO_QUERY ); |
| return xFieldName.is() ? xFieldName->getName() : OUString(); |
| } |
| |
| OUString PivotCacheField::createParentGroupField( const Reference< XDataPilotField >& rxBaseDPField, PivotCacheGroupItemVector& orItemNames ) const |
| { |
| OSL_ENSURE( hasGroupItems() && !maDiscreteItems.empty(), "PivotCacheField::createParentGroupField - not a group field" ); |
| OSL_ENSURE( maDiscreteItems.size() == orItemNames.size(), "PivotCacheField::createParentGroupField - number of item names does not match grouping info" ); |
| Reference< XDataPilotFieldGrouping > xDPGrouping( rxBaseDPField, UNO_QUERY ); |
| if( !xDPGrouping.is() ) return OUString(); |
| |
| // map the group item indexes from maGroupItems to all item indexes from maDiscreteItems |
| typedef ::std::vector< sal_Int32 > GroupItemList; |
| typedef ::std::vector< GroupItemList > GroupItemMap; |
| GroupItemMap aItemMap( maGroupItems.size() ); |
| for( IndexVector::const_iterator aBeg = maDiscreteItems.begin(), aIt = aBeg, aEnd = maDiscreteItems.end(); aIt != aEnd; ++aIt ) |
| if( GroupItemList* pItems = ContainerHelper::getVectorElementAccess( aItemMap, *aIt ) ) |
| pItems->push_back( static_cast< sal_Int32 >( aIt - aBeg ) ); |
| |
| // process all groups |
| Reference< XDataPilotField > xDPGroupField; |
| for( GroupItemMap::iterator aBeg = aItemMap.begin(), aIt = aBeg, aEnd = aItemMap.end(); aIt != aEnd; ++aIt ) |
| { |
| OSL_ENSURE( !aIt->empty(), "PivotCacheField::createParentGroupField - item/group should not be empty" ); |
| // if the item count is greater than 1, the item is a group of items |
| if( aIt->size() > 1 ) |
| { |
| /* Insert the names of the items that are part of this group. Calc |
| expects the names of the members of the field whose members are |
| grouped (which may be the names of groups too). Excel provides |
| the names of the base field items instead (no group names |
| involved). Therefore, the passed collection of current item |
| names as they are already grouped is used here to resolve the |
| item names. */ |
| ::std::vector< OUString > aMembers; |
| for( GroupItemList::iterator aBeg2 = aIt->begin(), aIt2 = aBeg2, aEnd2 = aIt->end(); aIt2 != aEnd2; ++aIt2 ) |
| if( const PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, *aIt2 ) ) |
| if( ::std::find( aMembers.begin(), aMembers.end(), pName->maGroupName ) == aMembers.end() ) |
| aMembers.push_back( pName->maGroupName ); |
| |
| /* Check again, that this is not just a group that is not grouped |
| further with other items. */ |
| if( aMembers.size() > 1 ) try |
| { |
| // only the first call of createNameGroup() returns the new field |
| Reference< XDataPilotField > xDPNewField = xDPGrouping->createNameGroup( ContainerHelper::vectorToSequence( aMembers ) ); |
| OSL_ENSURE( xDPGroupField.is() != xDPNewField.is(), "PivotCacheField::createParentGroupField - missing group field" ); |
| if( !xDPGroupField.is() ) |
| xDPGroupField = xDPNewField; |
| |
| // get current grouping info |
| DataPilotFieldGroupInfo aGroupInfo; |
| PropertySet aPropSet( xDPGroupField ); |
| aPropSet.getProperty( aGroupInfo, PROP_GroupInfo ); |
| |
| /* Find the group object and the auto-generated group name. |
| The returned field contains all groups derived from the |
| previous field if that is grouped too. To find the correct |
| group, the first item used to create the group is serached. |
| Calc provides the original item names of the base field |
| when the group is querried for its members. Its does not |
| provide the names of members that are already groups in the |
| field used to create the new groups. (Is this a bug?) |
| Therefore, a name from the passed list of original item |
| names is used to find the correct group. */ |
| OUString aFirstItem; |
| if( const PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, aIt->front() ) ) |
| aFirstItem = pName->maOrigName; |
| Reference< XNamed > xGroupName; |
| OUString aAutoName; |
| Reference< XIndexAccess > xGroupsIA( aGroupInfo.Groups, UNO_QUERY_THROW ); |
| for( sal_Int32 nIdx = 0, nCount = xGroupsIA->getCount(); (nIdx < nCount) && (aAutoName.getLength() == 0); ++nIdx ) try |
| { |
| Reference< XNameAccess > xItemsNA( xGroupsIA->getByIndex( nIdx ), UNO_QUERY_THROW ); |
| if( xItemsNA->hasByName( aFirstItem ) ) |
| { |
| xGroupName.set( xGroupsIA->getByIndex( nIdx ), UNO_QUERY_THROW ); |
| aAutoName = xGroupName->getName(); |
| } |
| } |
| catch( Exception& ) |
| { |
| } |
| OSL_ENSURE( aAutoName.getLength() > 0, "PivotCacheField::createParentGroupField - cannot find auto-generated group name" ); |
| |
| // get the real group name from the list of group items |
| OUString aGroupName; |
| if( const PivotCacheItem* pGroupItem = maGroupItems.getCacheItem( static_cast< sal_Int32 >( aIt - aBeg ) ) ) |
| aGroupName = pGroupItem->getName(); |
| OSL_ENSURE( aGroupName.getLength() > 0, "PivotCacheField::createParentGroupField - cannot find group name" ); |
| if( aGroupName.getLength() == 0 ) |
| aGroupName = aAutoName; |
| |
| if( xGroupName.is() && (aGroupName.getLength() > 0) ) |
| { |
| // replace the auto-generated group name with the real name |
| if( aAutoName != aGroupName ) |
| { |
| xGroupName->setName( aGroupName ); |
| aPropSet.setProperty( PROP_GroupInfo, aGroupInfo ); |
| } |
| // replace original item names in passed vector with group name |
| for( GroupItemList::iterator aIt2 = aIt->begin(), aEnd2 = aIt->end(); aIt2 != aEnd2; ++aIt2 ) |
| if( PivotCacheGroupItem* pName = ContainerHelper::getVectorElementAccess( orItemNames, *aIt2 ) ) |
| pName->maGroupName = aGroupName; |
| } |
| } |
| catch( Exception& ) |
| { |
| } |
| } |
| } |
| |
| Reference< XNamed > xFieldName( xDPGroupField, UNO_QUERY ); |
| return xFieldName.is() ? xFieldName->getName() : OUString(); |
| } |
| |
| void PivotCacheField::writeSourceHeaderCell( WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const |
| { |
| CellModel aModel; |
| aModel.maCellAddr = CellAddress( rSheetHelper.getSheetIndex(), nCol, nRow ); |
| rSheetHelper.getSheetData().setStringCell( aModel, maFieldModel.maName ); |
| } |
| |
| void PivotCacheField::writeSourceDataCell( WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem ) const |
| { |
| bool bHasIndex = rItem.getType() == XML_x; |
| OSL_ENSURE( bHasIndex != maSharedItems.empty(), "PivotCacheField::writeSourceDataCell - shared items missing or not expected" ); |
| if( bHasIndex ) |
| writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, rItem.getValue().get< sal_Int32 >() ); |
| else |
| writeItemToSourceDataCell( rSheetHelper, nCol, nRow, rItem ); |
| } |
| |
| void PivotCacheField::importPCRecordItem( SequenceInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const |
| { |
| if( hasSharedItems() ) |
| { |
| writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, rStrm.readInt32() ); |
| } |
| else |
| { |
| PivotCacheItem aItem; |
| if( maSharedItemsModel.mbIsNumeric ) |
| aItem.readDouble( rStrm ); |
| else if( maSharedItemsModel.mbHasDate && !maSharedItemsModel.mbHasString ) |
| aItem.readDate( rStrm ); |
| else |
| aItem.readString( rStrm ); |
| writeItemToSourceDataCell( rSheetHelper, nCol, nRow, aItem ); |
| } |
| } |
| |
| void PivotCacheField::importPCItemIndex( BiffInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const |
| { |
| OSL_ENSURE( hasSharedItems(), "PivotCacheField::importPCItemIndex - invalid call, no shared items found" ); |
| sal_Int32 nIndex = maSharedItemsModel.mbHasLongIndexes ? rStrm.readuInt16() : rStrm.readuInt8(); |
| writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, nIndex ); |
| } |
| |
| // private -------------------------------------------------------------------- |
| |
| void PivotCacheField::writeItemToSourceDataCell( WorksheetHelper& rSheetHelper, |
| sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem ) const |
| { |
| if( rItem.getType() != XML_m ) |
| { |
| CellModel aModel; |
| aModel.maCellAddr = CellAddress( rSheetHelper.getSheetIndex(), nCol, nRow ); |
| SheetDataBuffer& rSheetData = rSheetHelper.getSheetData(); |
| switch( rItem.getType() ) |
| { |
| case XML_s: rSheetData.setStringCell( aModel, rItem.getValue().get< OUString >() ); break; |
| case XML_n: rSheetData.setValueCell( aModel, rItem.getValue().get< double >() ); break; |
| case XML_i: rSheetData.setValueCell( aModel, rItem.getValue().get< sal_Int16 >() ); break; |
| case XML_d: rSheetData.setDateTimeCell( aModel, rItem.getValue().get< DateTime >() ); break; |
| case XML_b: rSheetData.setBooleanCell( aModel, rItem.getValue().get< bool >() ); break; |
| case XML_e: rSheetData.setErrorCell( aModel, static_cast< sal_uInt8 >( rItem.getValue().get< sal_Int32 >() ) ); break; |
| default: OSL_ENSURE( false, "PivotCacheField::writeItemToSourceDataCell - unexpected item data type" ); |
| } |
| } |
| } |
| |
| void PivotCacheField::writeSharedItemToSourceDataCell( |
| WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nItemIdx ) const |
| { |
| if( const PivotCacheItem* pCacheItem = maSharedItems.getCacheItem( nItemIdx ) ) |
| writeItemToSourceDataCell( rSheetHelper, nCol, nRow, *pCacheItem ); |
| } |
| |
| // ============================================================================ |
| |
| PCDefinitionModel::PCDefinitionModel() : |
| mfRefreshedDate( 0.0 ), |
| mnRecords( 0 ), |
| mnMissItemsLimit( 0 ), |
| mnDatabaseFields( 0 ), |
| mbInvalid( false ), |
| mbSaveData( true ), |
| mbRefreshOnLoad( false ), |
| mbOptimizeMemory( false ), |
| mbEnableRefresh( true ), |
| mbBackgroundQuery( false ), |
| mbUpgradeOnRefresh( false ), |
| mbTupleCache( false ), |
| mbSupportSubquery( false ), |
| mbSupportDrill( false ) |
| { |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| PCSourceModel::PCSourceModel() : |
| mnSourceType( XML_TOKEN_INVALID ), |
| mnConnectionId( 0 ) |
| { |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| PCWorksheetSourceModel::PCWorksheetSourceModel() |
| { |
| maRange.StartColumn = maRange.StartRow = maRange.EndColumn = maRange.EndRow = -1; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| PivotCache::PivotCache( const WorkbookHelper& rHelper ) : |
| WorkbookHelper( rHelper ), |
| mnCurrRow( -1 ), |
| mbValidSource( false ), |
| mbDummySheet( false ) |
| { |
| } |
| |
| void PivotCache::importPivotCacheDefinition( const AttributeList& rAttribs ) |
| { |
| maDefModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() ); |
| maDefModel.maRefreshedBy = rAttribs.getXString( XML_refreshedBy, OUString() ); |
| maDefModel.mfRefreshedDate = rAttribs.getDouble( XML_refreshedDate, 0.0 ); |
| maDefModel.mnRecords = rAttribs.getInteger( XML_recordCount, 0 ); |
| maDefModel.mnMissItemsLimit = rAttribs.getInteger( XML_missingItemsLimit, 0 ); |
| maDefModel.mbInvalid = rAttribs.getBool( XML_invalid, false ); |
| maDefModel.mbSaveData = rAttribs.getBool( XML_saveData, true ); |
| maDefModel.mbRefreshOnLoad = rAttribs.getBool( XML_refreshOnLoad, false ); |
| maDefModel.mbOptimizeMemory = rAttribs.getBool( XML_optimizeMemory, false ); |
| maDefModel.mbEnableRefresh = rAttribs.getBool( XML_enableRefresh, true ); |
| maDefModel.mbBackgroundQuery = rAttribs.getBool( XML_backgroundQuery, false ); |
| maDefModel.mbUpgradeOnRefresh = rAttribs.getBool( XML_upgradeOnRefresh, false ); |
| maDefModel.mbTupleCache = rAttribs.getBool( XML_tupleCache, false ); |
| maDefModel.mbSupportSubquery = rAttribs.getBool( XML_supportSubquery, false ); |
| maDefModel.mbSupportDrill = rAttribs.getBool( XML_supportAdvancedDrill, false ); |
| } |
| |
| void PivotCache::importCacheSource( const AttributeList& rAttribs ) |
| { |
| maSourceModel.mnSourceType = rAttribs.getToken( XML_type, XML_TOKEN_INVALID ); |
| maSourceModel.mnConnectionId = rAttribs.getInteger( XML_connectionId, 0 ); |
| } |
| |
| void PivotCache::importWorksheetSource( const AttributeList& rAttribs, const Relations& rRelations ) |
| { |
| maSheetSrcModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() ); |
| maSheetSrcModel.maSheet = rAttribs.getXString( XML_sheet, OUString() ); |
| maSheetSrcModel.maDefName = rAttribs.getXString( XML_name, OUString() ); |
| |
| // resolve URL of external document |
| maTargetUrl = rRelations.getExternalTargetFromRelId( maSheetSrcModel.maRelId ); |
| // store range address unchecked with sheet index 0, will be resolved/checked later |
| getAddressConverter().convertToCellRangeUnchecked( maSheetSrcModel.maRange, rAttribs.getString( XML_ref, OUString() ), 0 ); |
| } |
| |
| void PivotCache::importPCDefinition( SequenceInputStream& rStrm ) |
| { |
| sal_uInt8 nFlags1, nFlags2; |
| rStrm.skip( 3 ); // create/refresh version id's |
| rStrm >> nFlags1 >> maDefModel.mnMissItemsLimit >> maDefModel.mfRefreshedDate >> nFlags2 >> maDefModel.mnRecords; |
| if( getFlag( nFlags2, BIFF12_PCDEFINITION_HASUSERNAME ) ) |
| rStrm >> maDefModel.maRefreshedBy; |
| if( getFlag( nFlags2, BIFF12_PCDEFINITION_HASRELID ) ) |
| rStrm >> maDefModel.maRelId; |
| |
| maDefModel.mbInvalid = getFlag( nFlags1, BIFF12_PCDEFINITION_INVALID ); |
| maDefModel.mbSaveData = getFlag( nFlags1, BIFF12_PCDEFINITION_SAVEDATA ); |
| maDefModel.mbRefreshOnLoad = getFlag( nFlags1, BIFF12_PCDEFINITION_REFRESHONLOAD ); |
| maDefModel.mbOptimizeMemory = getFlag( nFlags1, BIFF12_PCDEFINITION_OPTIMIZEMEMORY ); |
| maDefModel.mbEnableRefresh = getFlag( nFlags1, BIFF12_PCDEFINITION_ENABLEREFRESH ); |
| maDefModel.mbBackgroundQuery = getFlag( nFlags1, BIFF12_PCDEFINITION_BACKGROUNDQUERY ); |
| maDefModel.mbUpgradeOnRefresh = getFlag( nFlags1, BIFF12_PCDEFINITION_UPGRADEONREFR ); |
| maDefModel.mbTupleCache = getFlag( nFlags1, BIFF12_PCDEFINITION_TUPELCACHE ); |
| maDefModel.mbSupportSubquery = getFlag( nFlags2, BIFF12_PCDEFINITION_SUPPORTSUBQUERY ); |
| maDefModel.mbSupportDrill = getFlag( nFlags2, BIFF12_PCDEFINITION_SUPPORTDRILL ); |
| } |
| |
| void PivotCache::importPCDSource( SequenceInputStream& rStrm ) |
| { |
| sal_Int32 nSourceType; |
| rStrm >> nSourceType >> maSourceModel.mnConnectionId; |
| static const sal_Int32 spnSourceTypes[] = { XML_worksheet, XML_external, XML_consolidation, XML_scenario }; |
| maSourceModel.mnSourceType = STATIC_ARRAY_SELECT( spnSourceTypes, nSourceType, XML_TOKEN_INVALID ); |
| } |
| |
| void PivotCache::importPCDSheetSource( SequenceInputStream& rStrm, const Relations& rRelations ) |
| { |
| sal_uInt8 nIsDefName, nIsBuiltinName, nFlags; |
| rStrm >> nIsDefName >> nIsBuiltinName >> nFlags; |
| if( getFlag( nFlags, BIFF12_PCDWBSOURCE_HASSHEET ) ) |
| rStrm >> maSheetSrcModel.maSheet; |
| if( getFlag( nFlags, BIFF12_PCDWBSOURCE_HASRELID ) ) |
| rStrm >> maSheetSrcModel.maRelId; |
| |
| // read cell range or defined name |
| if( nIsDefName == 0 ) |
| { |
| BinRange aBinRange; |
| rStrm >> aBinRange; |
| // store range address unchecked with sheet index 0, will be resolved/checked later |
| getAddressConverter().convertToCellRangeUnchecked( maSheetSrcModel.maRange, aBinRange, 0 ); |
| } |
| else |
| { |
| rStrm >> maSheetSrcModel.maDefName; |
| if( nIsBuiltinName != 0 ) |
| maSheetSrcModel.maDefName = CREATE_OUSTRING( "_xlnm." ) + maSheetSrcModel.maDefName; |
| } |
| |
| // resolve URL of external document |
| maTargetUrl = rRelations.getExternalTargetFromRelId( maSheetSrcModel.maRelId ); |
| } |
| |
| void PivotCache::importPCDSource( BiffInputStream& rStrm ) |
| { |
| switch( rStrm.readuInt16() ) |
| { |
| case BIFF_PCDSOURCE_WORKSHEET: |
| { |
| maSourceModel.mnSourceType = XML_worksheet; |
| sal_uInt16 nNextRecId = rStrm.getNextRecId(); |
| switch( nNextRecId ) |
| { |
| case BIFF_ID_DCONREF: if( rStrm.startNextRecord() ) importDConRef( rStrm ); break; |
| case BIFF_ID_DCONNAME: if( rStrm.startNextRecord() ) importDConName( rStrm ); break; |
| case BIFF_ID_DCONBINAME: if( rStrm.startNextRecord() ) importDConBIName( rStrm ); break; |
| } |
| } |
| break; |
| case BIFF_PCDSOURCE_EXTERNAL: |
| maSourceModel.mnSourceType = XML_external; |
| break; |
| case BIFF_PCDSOURCE_CONSOLIDATION: |
| maSourceModel.mnSourceType = XML_consolidation; |
| break; |
| case BIFF_PCDSOURCE_SCENARIO: |
| maSourceModel.mnSourceType = XML_scenario; |
| break; |
| default: |
| maSourceModel.mnSourceType = XML_TOKEN_INVALID; |
| } |
| } |
| |
| void PivotCache::importPCDefinition( BiffInputStream& rStrm ) |
| { |
| sal_uInt16 nFlags, nUserNameLen; |
| rStrm >> maDefModel.mnRecords; |
| rStrm.skip( 2 ); // repeated cache ID |
| rStrm >> nFlags; |
| rStrm.skip( 2 ); // unused |
| rStrm >> maDefModel.mnDatabaseFields; |
| rStrm.skip( 6 ); // total field count, report record count, (repeated) cache type |
| rStrm >> nUserNameLen; |
| if( nUserNameLen != BIFF_PC_NOSTRING ) |
| maDefModel.maRefreshedBy = (getBiff() == BIFF8) ? |
| rStrm.readUniString( nUserNameLen ) : |
| rStrm.readCharArrayUC( nUserNameLen, getTextEncoding() ); |
| |
| maDefModel.mbInvalid = getFlag( nFlags, BIFF_PCDEFINITION_INVALID ); |
| maDefModel.mbSaveData = getFlag( nFlags, BIFF_PCDEFINITION_SAVEDATA ); |
| maDefModel.mbRefreshOnLoad = getFlag( nFlags, BIFF_PCDEFINITION_REFRESHONLOAD ); |
| maDefModel.mbOptimizeMemory = getFlag( nFlags, BIFF_PCDEFINITION_OPTIMIZEMEMORY ); |
| maDefModel.mbEnableRefresh = getFlag( nFlags, BIFF_PCDEFINITION_ENABLEREFRESH ); |
| maDefModel.mbBackgroundQuery = getFlag( nFlags, BIFF_PCDEFINITION_BACKGROUNDQUERY ); |
| |
| if( (rStrm.getNextRecId() == BIFF_ID_PCDEFINITION2) && rStrm.startNextRecord() ) |
| rStrm >> maDefModel.mfRefreshedDate; |
| } |
| |
| PivotCacheField& PivotCache::createCacheField( bool bInitDatabaseField ) |
| { |
| bool bIsDatabaseField = !bInitDatabaseField || (maFields.size() < maDefModel.mnDatabaseFields); |
| PivotCacheFieldVector::value_type xCacheField( new PivotCacheField( *this, bIsDatabaseField ) ); |
| maFields.push_back( xCacheField ); |
| return *xCacheField; |
| } |
| |
| void PivotCache::finalizeImport() |
| { |
| // collect all fields that are based on source data (needed to finalize source data below) |
| OSL_ENSURE( !maFields.empty(), "PivotCache::finalizeImport - no pivot cache fields found" ); |
| for( PivotCacheFieldVector::const_iterator aIt = maFields.begin(), aEnd = maFields.end(); aIt != aEnd; ++aIt ) |
| { |
| if( (*aIt)->isDatabaseField() ) |
| { |
| OSL_ENSURE( (aIt == maFields.begin()) || (*(aIt - 1))->isDatabaseField(), |
| "PivotCache::finalizeImport - database field follows a calculated field" ); |
| maDatabaseIndexes.push_back( static_cast< sal_Int32 >( maDatabaseFields.size() ) ); |
| maDatabaseFields.push_back( *aIt ); |
| } |
| else |
| { |
| maDatabaseIndexes.push_back( -1 ); |
| } |
| } |
| OSL_ENSURE( !maDatabaseFields.empty(), "PivotCache::finalizeImport - no pivot cache source fields found" ); |
| |
| // finalize source data depending on source type |
| switch( maSourceModel.mnSourceType ) |
| { |
| case XML_worksheet: |
| { |
| // decide whether an external document is used |
| bool bInternal = (maTargetUrl.getLength() == 0) && (maSheetSrcModel.maRelId.getLength() == 0); |
| bool bExternal = maTargetUrl.getLength() > 0; // relation ID may be empty, e.g. BIFF import |
| OSL_ENSURE( bInternal || bExternal, "PivotCache::finalizeImport - invalid external document URL" ); |
| if( bInternal ) |
| finalizeInternalSheetSource(); |
| else if( bExternal ) |
| finalizeExternalSheetSource(); |
| } |
| break; |
| |
| // currently, we only support worksheet data sources |
| case XML_external: |
| break; |
| case XML_consolidation: |
| break; |
| case XML_scenario: |
| break; |
| } |
| } |
| |
| sal_Int32 PivotCache::getCacheFieldCount() const |
| { |
| return static_cast< sal_Int32 >( maFields.size() ); |
| } |
| |
| const PivotCacheField* PivotCache::getCacheField( sal_Int32 nFieldIdx ) const |
| { |
| return maFields.get( nFieldIdx ).get(); |
| } |
| |
| sal_Int32 PivotCache::getCacheDatabaseIndex( sal_Int32 nFieldIdx ) const |
| { |
| return ContainerHelper::getVectorElement( maDatabaseIndexes, nFieldIdx, -1 ); |
| } |
| |
| void PivotCache::writeSourceHeaderCells( WorksheetHelper& rSheetHelper ) const |
| { |
| OSL_ENSURE( static_cast< size_t >( maSheetSrcModel.maRange.EndColumn - maSheetSrcModel.maRange.StartColumn + 1 ) == maDatabaseFields.size(), |
| "PivotCache::writeSourceHeaderCells - source cell range width does not match number of source fields" ); |
| sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn; |
| sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Column; |
| sal_Int32 nRow = maSheetSrcModel.maRange.StartRow; |
| mnCurrRow = -1; |
| updateSourceDataRow( rSheetHelper, nRow ); |
| for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol ) |
| (*aIt)->writeSourceHeaderCell( rSheetHelper, nCol, nRow ); |
| } |
| |
| void PivotCache::writeSourceDataCell( WorksheetHelper& rSheetHelper, sal_Int32 nColIdx, sal_Int32 nRowIdx, const PivotCacheItem& rItem ) const |
| { |
| sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn + nColIdx; |
| OSL_ENSURE( (maSheetSrcModel.maRange.StartColumn <= nCol) && (nCol <= maSheetSrcModel.maRange.EndColumn), "PivotCache::writeSourceDataCell - invalid column index" ); |
| sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx; |
| OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::writeSourceDataCell - invalid row index" ); |
| updateSourceDataRow( rSheetHelper, nRow ); |
| if( const PivotCacheField* pCacheField = maDatabaseFields.get( nColIdx ).get() ) |
| pCacheField->writeSourceDataCell( rSheetHelper, nCol, nRow, rItem ); |
| } |
| |
| void PivotCache::importPCRecord( SequenceInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nRowIdx ) const |
| { |
| sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx; |
| OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::importPCRecord - invalid row index" ); |
| sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn; |
| sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Column; |
| for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); !rStrm.isEof() && (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol ) |
| (*aIt)->importPCRecordItem( rStrm, rSheetHelper, nCol, nRow ); |
| } |
| |
| void PivotCache::importPCItemIndexList( BiffInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nRowIdx ) const |
| { |
| sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx; |
| OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::importPCItemIndexList - invalid row index" ); |
| sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn; |
| sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Column; |
| for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); !rStrm.isEof() && (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol ) |
| if( (*aIt)->hasSharedItems() ) |
| (*aIt)->importPCItemIndex( rStrm, rSheetHelper, nCol, nRow ); |
| } |
| |
| // private -------------------------------------------------------------------- |
| |
| void PivotCache::importDConRef( BiffInputStream& rStrm ) |
| { |
| BinRange aBinRange; |
| aBinRange.read( rStrm, false ); // always 8-bit column indexes |
| // store range address unchecked with sheet index 0, will be resolved/checked later |
| getAddressConverter().convertToCellRangeUnchecked( maSheetSrcModel.maRange, aBinRange, 0 ); |
| |
| // the URL with (required) sheet name and optional URL of an external document |
| importDConUrl( rStrm ); |
| OSL_ENSURE( maSheetSrcModel.maSheet.getLength() > 0, "PivotCache::importDConRef - missing sheet name" ); |
| } |
| |
| void PivotCache::importDConName( BiffInputStream& rStrm ) |
| { |
| maSheetSrcModel.maDefName = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() ); |
| OSL_ENSURE( maSheetSrcModel.maDefName.getLength() > 0, "PivotCache::importDConName - missing defined name" ); |
| importDConUrl( rStrm ); |
| } |
| |
| void PivotCache::importDConBIName( BiffInputStream& rStrm ) |
| { |
| sal_uInt8 nNameId = rStrm.readuInt8(); |
| rStrm.skip( 3 ); |
| maSheetSrcModel.maDefName = OUString( sal_Unicode( nNameId ) ); |
| importDConUrl( rStrm ); |
| } |
| |
| void PivotCache::importDConUrl( BiffInputStream& rStrm ) |
| { |
| // the URL with sheet name and optional URL of an external document |
| OUString aEncodedUrl; |
| if( getBiff() == BIFF8 ) |
| { |
| // empty string does not contain a flags byte, cannot use simple readUniString() here... |
| sal_uInt16 nChars = rStrm.readuInt16(); |
| if( nChars > 0 ) |
| aEncodedUrl = rStrm.readUniString( nChars ); |
| } |
| else |
| { |
| aEncodedUrl = rStrm.readByteStringUC( false, getTextEncoding() ); |
| } |
| |
| if( aEncodedUrl.getLength() > 0 ) |
| { |
| OUString aClassName; |
| getAddressConverter().parseBiffTargetUrl( aClassName, maTargetUrl, maSheetSrcModel.maSheet, aEncodedUrl, true ); |
| } |
| } |
| |
| void PivotCache::finalizeInternalSheetSource() |
| { |
| // resolve sheet name to sheet index |
| sal_Int16 nSheet = getWorksheets().getCalcSheetIndex( maSheetSrcModel.maSheet ); |
| |
| // if cache is based on a defined name or table, try to resolve to cell range |
| if( maSheetSrcModel.maDefName.getLength() > 0 ) |
| { |
| // local or global defined name |
| if( const DefinedName* pDefName = getDefinedNames().getByModelName( maSheetSrcModel.maDefName, nSheet ).get() ) |
| { |
| mbValidSource = pDefName->getAbsoluteRange( maSheetSrcModel.maRange ); |
| } |
| // table |
| else if( const Table* pTable = getTables().getTable( maSheetSrcModel.maDefName ).get() ) |
| { |
| // get original range from table, but exclude the totals row(s) |
| maSheetSrcModel.maRange = pTable->getOriginalRange(); |
| mbValidSource = (pTable->getHeight() - pTable->getTotalsRows()) > 1; |
| if( mbValidSource ) |
| maSheetSrcModel.maRange.EndRow -= pTable->getTotalsRows(); |
| } |
| } |
| // else try the cell range (if the sheet exists) |
| else if( nSheet >= 0 ) |
| { |
| // insert sheet index into the range, range address will be checked below |
| maSheetSrcModel.maRange.Sheet = nSheet; |
| mbValidSource = true; |
| } |
| // else sheet has been deleted, generate the source data from cache |
| else if( maSheetSrcModel.maSheet.getLength() > 0 ) |
| { |
| prepareSourceDataSheet(); |
| // return here to skip the source range check below |
| return; |
| } |
| |
| // check range location, do not allow ranges that overflow the sheet partly |
| mbValidSource = mbValidSource && |
| getAddressConverter().checkCellRange( maSheetSrcModel.maRange, false, true ) && |
| (maSheetSrcModel.maRange.StartRow < maSheetSrcModel.maRange.EndRow); |
| } |
| |
| void PivotCache::finalizeExternalSheetSource() |
| { |
| /* If pivot cache is based on external sheet data, try to restore sheet |
| data from cache records. No support for external defined names or tables, |
| sheet name and path to cache records fragment (OOXML only) are required. */ |
| bool bHasRelation = (getFilterType() == FILTER_BIFF) || (maDefModel.maRelId.getLength() > 0); |
| if( bHasRelation && (maSheetSrcModel.maDefName.getLength() == 0) && (maSheetSrcModel.maSheet.getLength() > 0) ) |
| prepareSourceDataSheet(); |
| } |
| |
| void PivotCache::prepareSourceDataSheet() |
| { |
| CellRangeAddress& rRange = maSheetSrcModel.maRange; |
| // data will be inserted in top-left cell, sheet index is still set to 0 (will be set below) |
| rRange.EndColumn -= rRange.StartColumn; |
| rRange.StartColumn = 0; |
| rRange.EndRow -= rRange.StartRow; |
| rRange.StartRow = 0; |
| // check range location, do not allow ranges that overflow the sheet partly |
| if( getAddressConverter().checkCellRange( rRange, false, true ) ) |
| { |
| maColSpans.insert( ValueRange( rRange.StartColumn, rRange.EndColumn ) ); |
| OUString aSheetName = CREATE_OUSTRING( "DPCache_" ) + maSheetSrcModel.maSheet; |
| rRange.Sheet = getWorksheets().insertEmptySheet( aSheetName, false ); |
| mbValidSource = mbDummySheet = rRange.Sheet >= 0; |
| } |
| } |
| |
| void PivotCache::updateSourceDataRow( WorksheetHelper& rSheetHelper, sal_Int32 nRow ) const |
| { |
| if( mnCurrRow != nRow ) |
| { |
| rSheetHelper.getSheetData().setColSpans( nRow, maColSpans ); |
| mnCurrRow = nRow; |
| } |
| } |
| |
| // ============================================================================ |
| |
| PivotCacheBuffer::PivotCacheBuffer( const WorkbookHelper& rHelper ) : |
| WorkbookHelper( rHelper ) |
| { |
| } |
| |
| void PivotCacheBuffer::registerPivotCacheFragment( sal_Int32 nCacheId, const OUString& rFragmentPath ) |
| { |
| OSL_ENSURE( nCacheId >= 0, "PivotCacheBuffer::registerPivotCacheFragment - invalid pivot cache identifier" ); |
| OSL_ENSURE( maFragmentPaths.count( nCacheId ) == 0, "PivotCacheBuffer::registerPivotCacheFragment - fragment path exists already" ); |
| if( (nCacheId >= 0) && (rFragmentPath.getLength() > 0) ) |
| maFragmentPaths[ nCacheId ] = rFragmentPath; |
| } |
| |
| void PivotCacheBuffer::importPivotCacheRef( BiffInputStream& rStrm ) |
| { |
| // read the PIVOTCACHE record that contains the stream ID |
| sal_Int32 nCacheId = rStrm.readuInt16(); |
| OSL_ENSURE( maFragmentPaths.count( nCacheId ) == 0, "PivotCacheBuffer::importPivotCacheRef - cache stream exists already" ); |
| OUStringBuffer aStrmName; |
| static const sal_Unicode spcHexChars[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; |
| for( sal_uInt8 nBit = 0; nBit < 16; nBit += 4 ) |
| aStrmName.insert( 0, spcHexChars[ extractValue< size_t >( nCacheId, nBit, 4 ) ] ); |
| aStrmName.insert( 0, (getBiff() == BIFF8) ? CREATE_OUSTRING( "_SX_DB_CUR/" ) : CREATE_OUSTRING( "_SX_DB/" ) ); |
| maFragmentPaths[ nCacheId ] = aStrmName.makeStringAndClear(); |
| |
| // try to read PCDSOURCE record (will read following data location records too) |
| sal_uInt16 nNextRecId = rStrm.getNextRecId(); |
| OSL_ENSURE( nNextRecId == BIFF_ID_PCDSOURCE, "PivotCacheBuffer::importPivotCacheRef - PCDSOURCE record expected" ); |
| if( (nNextRecId == BIFF_ID_PCDSOURCE) && rStrm.startNextRecord() ) |
| createPivotCache( nCacheId ).importPCDSource( rStrm ); |
| } |
| |
| PivotCache* PivotCacheBuffer::importPivotCacheFragment( sal_Int32 nCacheId ) |
| { |
| switch( getFilterType() ) |
| { |
| /* OOXML/BIFF12 filter: On first call for the cache ID, the pivot |
| cache object is created and inserted into maCaches. Then, the cache |
| definition fragment is read and the cache is returned. On |
| subsequent calls, the created cache will be found in maCaches and |
| returned immediately. */ |
| case FILTER_OOXML: |
| { |
| // try to find an imported pivot cache |
| if( PivotCache* pCache = maCaches.get( nCacheId ).get() ) |
| return pCache; |
| |
| // check if a fragment path exists for the passed cache identifier |
| FragmentPathMap::iterator aIt = maFragmentPaths.find( nCacheId ); |
| if( aIt == maFragmentPaths.end() ) |
| return 0; |
| |
| /* Import the cache fragment. This may create a dummy data sheet |
| for external sheet sources. */ |
| PivotCache& rCache = createPivotCache( nCacheId ); |
| importOoxFragment( new PivotCacheDefinitionFragment( *this, aIt->second, rCache ) ); |
| return &rCache; |
| } |
| |
| /* BIFF filter: Pivot table provides 0-based index into list of pivot |
| cache source links (PIVOTCACHE/PCDSOURCE/... record blocks in |
| workbook stream). First, this index has to be resolved to the cache |
| identifier that is used to manage the cache stream names (the |
| maFragmentPaths member). The cache object itself exists already |
| before the first call for the cache source index (see |
| PivotCacheBuffer::importPivotCacheRef() above), because source data |
| link is part of workbook data, not of the cache stream. To detect |
| subsequent calls with an already initialized cache, the entry in |
| maFragmentPaths will be removed after reading the cache stream. */ |
| case FILTER_BIFF: |
| { |
| /* Resolve cache index to cache identifier and try to find pivot |
| cache. Cache must exist already for a valid cache index. */ |
| nCacheId = ContainerHelper::getVectorElement( maCacheIds, nCacheId, -1 ); |
| PivotCache* pCache = maCaches.get( nCacheId ).get(); |
| if( !pCache ) |
| return 0; |
| |
| /* Try to find fragment path entry (stream name). If missing, the |
| stream has been read already, and the cache can be returned. */ |
| FragmentPathMap::iterator aIt = maFragmentPaths.find( nCacheId ); |
| if( aIt != maFragmentPaths.end() ) |
| { |
| /* Import the cache stream. This may create a dummy data sheet |
| for external sheet sources. */ |
| BiffPivotCacheFragment( *this, aIt->second, *pCache ).importFragment(); |
| // remove the fragment entry to mark that the cache is initialized |
| maFragmentPaths.erase( aIt ); |
| } |
| return pCache; |
| } |
| |
| case FILTER_UNKNOWN: |
| OSL_ENSURE( false, "PivotCacheBuffer::importPivotCacheFragment - unknown filter type" ); |
| } |
| return 0; |
| } |
| |
| PivotCache& PivotCacheBuffer::createPivotCache( sal_Int32 nCacheId ) |
| { |
| maCacheIds.push_back( nCacheId ); |
| PivotCacheMap::mapped_type& rxCache = maCaches[ nCacheId ]; |
| rxCache.reset( new PivotCache( *this ) ); |
| return *rxCache; |
| } |
| |
| // ============================================================================ |
| |
| } // namespace xls |
| } // namespace oox |