blob: de7eab9a1906716efd98377ccc9a1447cf188959 [file] [log] [blame]
/**************************************************************
*
* 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/pivottablebuffer.hxx"
#include <set>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/sheet/CellFlags.hpp>
#include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
#include <com/sun/star/sheet/DataPilotFieldLayoutInfo.hpp>
#include <com/sun/star/sheet/DataPilotFieldLayoutMode.hpp>
#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
#include <com/sun/star/sheet/DataPilotFieldReference.hpp>
#include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
#include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
#include <com/sun/star/sheet/DataPilotFieldShowItemsMode.hpp>
#include <com/sun/star/sheet/DataPilotFieldSortInfo.hpp>
#include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
#include <com/sun/star/sheet/GeneralFunction.hpp>
#include <com/sun/star/sheet/XDataPilotDataLayoutFieldSupplier.hpp>
#include <com/sun/star/sheet/XDataPilotField.hpp>
#include <com/sun/star/sheet/XDataPilotTablesSupplier.hpp>
#include <com/sun/star/sheet/XSheetOperation.hpp>
#include "oox/helper/attributelist.hxx"
#include "oox/helper/containerhelper.hxx"
#include "oox/helper/propertyset.hxx"
#include "oox/xls/addressconverter.hxx"
#include "oox/xls/biffinputstream.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 ::rtl::OUString;
// ============================================================================
namespace {
const sal_Int32 OOX_PT_DATALAYOUTFIELD = -2; /// Placeholder index of data layout field.
const sal_Int32 OOX_PT_PREVIOUS_ITEM = 0x001000FC; /// Calculation of data item result is based on previous item.
const sal_Int32 OOX_PT_NEXT_ITEM = 0x001000FD; /// Calculation of data item result is based on next item.
// ----------------------------------------------------------------------------
const sal_uInt32 BIFF12_PTFIELD_DATAFIELD = 0x00000008;
const sal_uInt32 BIFF12_PTFIELD_DEFAULT = 0x00000100;
const sal_uInt32 BIFF12_PTFIELD_SUM = 0x00000200;
const sal_uInt32 BIFF12_PTFIELD_COUNTA = 0x00000400;
const sal_uInt32 BIFF12_PTFIELD_AVERAGE = 0x00000800;
const sal_uInt32 BIFF12_PTFIELD_MAX = 0x00001000;
const sal_uInt32 BIFF12_PTFIELD_MIN = 0x00002000;
const sal_uInt32 BIFF12_PTFIELD_PRODUCT = 0x00004000;
const sal_uInt32 BIFF12_PTFIELD_COUNT = 0x00008000;
const sal_uInt32 BIFF12_PTFIELD_STDDEV = 0x00010000;
const sal_uInt32 BIFF12_PTFIELD_STDDEVP = 0x00020000;
const sal_uInt32 BIFF12_PTFIELD_VAR = 0x00040000;
const sal_uInt32 BIFF12_PTFIELD_VARP = 0x00080000;
const sal_uInt32 BIFF12_PTFIELD_SHOWALL = 0x00000020;
const sal_uInt32 BIFF12_PTFIELD_OUTLINE = 0x00000040;
const sal_uInt32 BIFF12_PTFIELD_INSERTBLANKROW = 0x00000080;
const sal_uInt32 BIFF12_PTFIELD_SUBTOTALTOP = 0x00000100;
const sal_uInt32 BIFF12_PTFIELD_INSERTPAGEBREAK = 0x00000800;
const sal_uInt32 BIFF12_PTFIELD_AUTOSORT = 0x00001000;
const sal_uInt32 BIFF12_PTFIELD_SORTASCENDING = 0x00002000;
const sal_uInt32 BIFF12_PTFIELD_AUTOSHOW = 0x00004000;
const sal_uInt32 BIFF12_PTFIELD_AUTOSHOWTOP = 0x00008000;
const sal_uInt32 BIFF12_PTFIELD_MULTIPAGEITEMS = 0x00080000;
const sal_uInt16 BIFF12_PTFITEM_HIDDEN = 0x0001;
const sal_uInt16 BIFF12_PTFITEM_HIDEDETAILS = 0x0002;
const sal_uInt8 BIFF12_PTPAGEFIELD_HASNAME = 0x01;
const sal_uInt8 BIFF12_PTPAGEFIELD_HASOLAPCAPTION = 0x02;
const sal_Int32 BIFF12_PTPAGEFIELD_MULTIITEMS = 0x001000FE;
const sal_uInt16 BIFF12_PTFILTER_HASNAME = 0x0001;
const sal_uInt16 BIFF12_PTFILTER_HASDESCRIPTION = 0x0002;
const sal_uInt16 BIFF12_PTFILTER_HASSTRVALUE1 = 0x0004;
const sal_uInt16 BIFF12_PTFILTER_HASSTRVALUE2 = 0x0008;
const sal_uInt8 BIFF12_TOP10FILTER_TOP = 0x01;
const sal_uInt8 BIFF12_TOP10FILTER_PERCENT = 0x02;
const sal_uInt32 BIFF12_PTDEF_SHOWITEMS = 0x00000100;
const sal_uInt32 BIFF12_PTDEF_DISABLEFIELDLIST = 0x00000400;
const sal_uInt32 BIFF12_PTDEF_HIDECALCMEMBERS = 0x00001000;
const sal_uInt32 BIFF12_PTDEF_WITHHIDDENTOTALS = 0x00002000;
const sal_uInt32 BIFF12_PTDEF_HIDEDRILL = 0x00100000;
const sal_uInt32 BIFF12_PTDEF_PRINTDRILL = 0x00200000;
const sal_uInt32 BIFF12_PTDEF_HIDEHEADERS = 0x80000000;
const sal_uInt32 BIFF12_PTDEF_SHOWEMPTYROW = 0x00000004;
const sal_uInt32 BIFF12_PTDEF_SHOWEMPTYCOL = 0x00000008;
const sal_uInt32 BIFF12_PTDEF_ENABLEDRILL = 0x00000020;
const sal_uInt32 BIFF12_PTDEF_PRESERVEFORMATTING = 0x00000080;
const sal_uInt32 BIFF12_PTDEF_USEAUTOFORMAT = 0x00000100;
const sal_uInt32 BIFF12_PTDEF_SHOWERROR = 0x00000200;
const sal_uInt32 BIFF12_PTDEF_SHOWMISSING = 0x00000400;
const sal_uInt32 BIFF12_PTDEF_PAGEOVERTHENDOWN = 0x00000800;
const sal_uInt32 BIFF12_PTDEF_SUBTOTALHIDDENITEMS = 0x00001000;
const sal_uInt32 BIFF12_PTDEF_ROWGRANDTOTALS = 0x00002000;
const sal_uInt32 BIFF12_PTDEF_COLGRANDTOTALS = 0x00004000;
const sal_uInt32 BIFF12_PTDEF_FIELDPRINTTITLES = 0x00008000;
const sal_uInt32 BIFF12_PTDEF_ITEMPRINTTITLES = 0x00020000;
const sal_uInt32 BIFF12_PTDEF_MERGEITEM = 0x00040000;
const sal_uInt32 BIFF12_PTDEF_HASDATACAPTION = 0x00080000;
const sal_uInt32 BIFF12_PTDEF_HASGRANDTOTALCAPTION = 0x00100000;
const sal_uInt32 BIFF12_PTDEF_HASPAGESTYLE = 0x00200000;
const sal_uInt32 BIFF12_PTDEF_HASPIVOTTABLESTYLE = 0x00400000;
const sal_uInt32 BIFF12_PTDEF_HASVACATEDSTYLE = 0x00800000;
const sal_uInt32 BIFF12_PTDEF_APPLYNUMFMT = 0x01000000;
const sal_uInt32 BIFF12_PTDEF_APPLYFONT = 0x02000000;
const sal_uInt32 BIFF12_PTDEF_APPLYALIGNMENT = 0x04000000;
const sal_uInt32 BIFF12_PTDEF_APPLYBORDER = 0x08000000;
const sal_uInt32 BIFF12_PTDEF_APPLYFILL = 0x10000000;
const sal_uInt32 BIFF12_PTDEF_APPLYPROTECTION = 0x20000000;
const sal_uInt32 BIFF12_PTDEF_HASTAG = 0x40000000;
const sal_uInt32 BIFF12_PTDEF_NOERRORCAPTION = 0x00000040;
const sal_uInt32 BIFF12_PTDEF_NOMISSINGCAPTION = 0x00000080;
const sal_uInt32 BIFF12_PTDEF_HASROWHEADERCAPTION = 0x00000400;
const sal_uInt32 BIFF12_PTDEF_HASCOLHEADERCAPTION = 0x00000800;
const sal_uInt32 BIFF12_PTDEF_FIELDLISTSORTASC = 0x00001000;
const sal_uInt32 BIFF12_PTDEF_NOCUSTOMLISTSORT = 0x00004000;
const sal_uInt8 BIFF12_PTDEF_ROWAXIS = 1;
const sal_uInt8 BIFF12_PTDEF_COLAXIS = 2;
// ----------------------------------------------------------------------------
const sal_uInt16 BIFF_PT_NOSTRING = 0xFFFF;
const sal_uInt16 BIFF_PTFIELD_DATAFIELD = 0x0008;
const sal_uInt16 BIFF_PTFIELD_DEFAULT = 0x0001;
const sal_uInt16 BIFF_PTFIELD_SUM = 0x0002;
const sal_uInt16 BIFF_PTFIELD_COUNTA = 0x0004;
const sal_uInt16 BIFF_PTFIELD_AVERAGE = 0x0008;
const sal_uInt16 BIFF_PTFIELD_MAX = 0x0010;
const sal_uInt16 BIFF_PTFIELD_MIN = 0x0020;
const sal_uInt16 BIFF_PTFIELD_PRODUCT = 0x0040;
const sal_uInt16 BIFF_PTFIELD_COUNT = 0x0080;
const sal_uInt16 BIFF_PTFIELD_STDDEV = 0x0100;
const sal_uInt16 BIFF_PTFIELD_STDDEVP = 0x0200;
const sal_uInt16 BIFF_PTFIELD_VAR = 0x0400;
const sal_uInt16 BIFF_PTFIELD_VARP = 0x0800;
const sal_uInt32 BIFF_PTFIELD2_SHOWALL = 0x00000001;
const sal_uInt32 BIFF_PTFIELD2_AUTOSORT = 0x00000200;
const sal_uInt32 BIFF_PTFIELD2_SORTASCENDING = 0x00000400;
const sal_uInt32 BIFF_PTFIELD2_AUTOSHOW = 0x00000800;
const sal_uInt32 BIFF_PTFIELD2_AUTOSHOWTOP = 0x00001000;
const sal_uInt32 BIFF_PTFIELD2_OUTLINE = 0x00200000;
const sal_uInt32 BIFF_PTFIELD2_INSERTBLANKROW = 0x00400000;
const sal_uInt32 BIFF_PTFIELD2_SUBTOTALTOP = 0x00800000;
const sal_uInt16 BIFF_PTFITEM_HIDDEN = 0x0001;
const sal_uInt16 BIFF_PTFITEM_HIDEDETAILS = 0x0002;
const sal_uInt16 BIFF_PTDEF_ROWGRANDTOTALS = 0x0001;
const sal_uInt16 BIFF_PTDEF_COLGRANDTOTALS = 0x0002;
const sal_uInt8 BIFF_PTDEF_ROWAXIS = 1;
const sal_uInt8 BIFF_PTDEF_COLAXIS = 2;
const sal_uInt32 BIFF_PTDEF2_PAGEOVERTHENDOWN = 0x00000001;
const sal_uInt32 BIFF_PTDE2F_ENABLEDRILL = 0x00020000;
const sal_uInt32 BIFF_PTDEF2_PRESERVEFORMATTING = 0x00080000;
const sal_uInt32 BIFF_PTDEF2_MERGEITEM = 0x00100000;
const sal_uInt32 BIFF_PTDEF2_SHOWERROR = 0x00200000;
const sal_uInt32 BIFF_PTDEF2_SHOWMISSING = 0x00400000;
const sal_uInt32 BIFF_PTDEF2_SUBTOTALHIDDENITEMS = 0x00800000;
const sal_Int16 BIFF_PTPAGEFIELDS_ALLITEMS = 0x7FFD;
const sal_Int16 BIFF_PTDATAFIELD_PREVIOUS = 0x7FFB;
const sal_Int16 BIFF_PTDATAFIELD_NEXT = 0x7FFC;
// ----------------------------------------------------------------------------
OUString lclReadPivotString( const WorkbookHelper& rHelper, BiffInputStream& rStrm, sal_uInt16 nLen )
{
if( nLen == BIFF_PT_NOSTRING )
return OUString();
return (rHelper.getBiff() == BIFF8) ? rStrm.readUniStringBody( nLen ) : rStrm.readCharArrayUC( nLen, rHelper.getTextEncoding() );
}
} // namespace
// ============================================================================
PTFieldItemModel::PTFieldItemModel() :
mnCacheItem( -1 ),
mnType( XML_data ),
mbShowDetails( true ),
mbHidden( false )
{
}
void PTFieldItemModel::setBiffType( sal_uInt16 nType )
{
static const sal_Int32 spnTypes[] = { XML_data, XML_default,
XML_sum, XML_countA, XML_avg, XML_max, XML_min, XML_product, XML_count,
XML_stdDev, XML_stdDevP, XML_var, XML_varP, XML_grand, XML_blank };
mnType = STATIC_ARRAY_SELECT( spnTypes, nType, XML_data );
}
// ----------------------------------------------------------------------------
PTFieldModel::PTFieldModel() :
mnAxis( XML_TOKEN_INVALID ),
mnNumFmtId( 0 ),
mnAutoShowItems( 10 ),
mnAutoShowRankBy( -1 ),
mnSortType( XML_manual ),
mnSortRefField( -1 ),
mnSortRefItem( -1 ),
mbDataField( false ),
mbDefaultSubtotal( true ),
mbSumSubtotal( false ),
mbCountASubtotal( false ),
mbAverageSubtotal( false ),
mbMaxSubtotal( false ),
mbMinSubtotal( false ),
mbProductSubtotal( false ),
mbCountSubtotal( false ),
mbStdDevSubtotal( false ),
mbStdDevPSubtotal( false ),
mbVarSubtotal( false ),
mbVarPSubtotal( false ),
mbShowAll( true ),
mbOutline( true ),
mbSubtotalTop( true ),
mbInsertBlankRow( false ),
mbInsertPageBreak( false ),
mbAutoShow( false ),
mbTopAutoShow( true ),
mbMultiPageItems( false )
{
}
void PTFieldModel::setBiffAxis( sal_uInt8 nAxis )
{
/* Weird. The axis field is organized as bit field, but only one of the
row/col/page flags are allowed at the same time and refer to the values
'axisRow', 'axisCol', and 'axisPage' of the XML attribute
'pivotField@axis'. Additionally, the fourth bit determines if the field
is a data field, which may appear combined with the row/col/page flags.
Therefore, this bit is unrelated to the 'axisValues' value of the
'pivotField@axis' attribute, but refers to the 'pivotField@dataField'
boolean attribute. */
static const sal_Int32 spnAxisIds[] = { XML_TOKEN_INVALID, XML_axisRow, XML_axisCol, XML_TOKEN_INVALID, XML_axisPage };
mnAxis = STATIC_ARRAY_SELECT( spnAxisIds, nAxis, XML_TOKEN_INVALID );
}
// ----------------------------------------------------------------------------
PTPageFieldModel::PTPageFieldModel() :
mnField( -1 ),
mnItem( BIFF12_PTPAGEFIELD_MULTIITEMS )
{
}
// ----------------------------------------------------------------------------
PTDataFieldModel::PTDataFieldModel() :
mnField( -1 ),
mnSubtotal( XML_sum ),
mnShowDataAs( XML_normal ),
mnBaseField( -1 ),
mnBaseItem( -1 ),
mnNumFmtId( 0 )
{
}
void PTDataFieldModel::setBiffSubtotal( sal_Int32 nSubtotal )
{
static sal_Int32 spnSubtotals[] = { XML_sum, XML_count, XML_average, XML_max, XML_min, XML_product, XML_countNums, XML_stdDev, XML_stdDevp, XML_var, XML_varp };
mnSubtotal = STATIC_ARRAY_SELECT( spnSubtotals, nSubtotal, XML_TOKEN_INVALID );
}
void PTDataFieldModel::setBiffShowDataAs( sal_Int32 nShowDataAs )
{
static sal_Int32 spnShowDataAs[] = { XML_normal, XML_difference, XML_percent, XML_percentDiff, XML_runTotal, XML_percentOfRow, XML_percentOfCol, XML_percentOfTotal, XML_index };
mnShowDataAs = STATIC_ARRAY_SELECT( spnShowDataAs, nShowDataAs, XML_TOKEN_INVALID );
}
// ----------------------------------------------------------------------------
PivotTableField::PivotTableField( PivotTable& rPivotTable, sal_Int32 nFieldIndex ) :
WorkbookHelper( rPivotTable ),
mrPivotTable( rPivotTable ),
mnFieldIndex( nFieldIndex )
{
}
void PivotTableField::importPivotField( const AttributeList& rAttribs )
{
/* The documentation mentions a value 'axisValues' for the attribute
'pivotField@axis'. But this value is not used to mark a data field, as
data fields may be inserted in one of the row/column/page dimensions at
the same time. Therefore, the boolean attribute 'pivotField@dataField'
is really used to mark data fields. */
maModel.mnAxis = rAttribs.getToken( XML_axis, XML_TOKEN_INVALID );
maModel.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, 0 );
maModel.mnAutoShowItems = rAttribs.getInteger( XML_itemPageCount, 10 );
maModel.mnAutoShowRankBy = rAttribs.getInteger( XML_rankBy, -1 );
maModel.mnSortType = rAttribs.getToken( XML_sortType, XML_manual );
maModel.mbDataField = rAttribs.getBool( XML_dataField, false );
maModel.mbDefaultSubtotal = rAttribs.getBool( XML_defaultSubtotal, true );
maModel.mbSumSubtotal = rAttribs.getBool( XML_sumSubtotal, false );
maModel.mbCountASubtotal = rAttribs.getBool( XML_countASubtotal, false );
maModel.mbAverageSubtotal = rAttribs.getBool( XML_avgSubtotal, false );
maModel.mbMaxSubtotal = rAttribs.getBool( XML_maxSubtotal, false );
maModel.mbMinSubtotal = rAttribs.getBool( XML_minSubtotal, false );
maModel.mbProductSubtotal = rAttribs.getBool( XML_productSubtotal, false );
maModel.mbCountSubtotal = rAttribs.getBool( XML_countSubtotal, false );
maModel.mbStdDevSubtotal = rAttribs.getBool( XML_stdDevSubtotal, false );
maModel.mbStdDevPSubtotal = rAttribs.getBool( XML_stdDevPSubtotal, false );
maModel.mbVarSubtotal = rAttribs.getBool( XML_varSubtotal, false );
maModel.mbVarPSubtotal = rAttribs.getBool( XML_varPSubtotal, false );
maModel.mbShowAll = rAttribs.getBool( XML_showAll, true );
maModel.mbOutline = rAttribs.getBool( XML_outline, true );
maModel.mbSubtotalTop = rAttribs.getBool( XML_subtotalTop, true );
maModel.mbInsertBlankRow = rAttribs.getBool( XML_insertBlankRow, false );
maModel.mbInsertPageBreak = rAttribs.getBool( XML_insertPageBreak, false );
maModel.mbAutoShow = rAttribs.getBool( XML_autoShow, false );
maModel.mbTopAutoShow = rAttribs.getBool( XML_topAutoShow, true );
maModel.mbMultiPageItems = rAttribs.getBool( XML_multipleItemSelectionAllowed, false );
}
void PivotTableField::importItem( const AttributeList& rAttribs )
{
PTFieldItemModel aModel;
aModel.mnCacheItem = rAttribs.getInteger( XML_x, -1 );
aModel.mnType = rAttribs.getToken( XML_t, XML_data );
aModel.mbShowDetails = rAttribs.getBool( XML_sd, true );
aModel.mbHidden = rAttribs.getBool( XML_h, false );
maItems.push_back( aModel );
}
void PivotTableField::importReference( const AttributeList& rAttribs )
{
// field index is stored as unsigned integer
maModel.mnSortRefField = static_cast< sal_Int32 >( rAttribs.getUnsigned( XML_field, SAL_MAX_UINT32 ) );
}
void PivotTableField::importReferenceItem( const AttributeList& rAttribs )
{
maModel.mnSortRefItem = rAttribs.getInteger( XML_v, -1 );
}
void PivotTableField::importPTField( SequenceInputStream& rStrm )
{
sal_uInt32 nFlags1, nFlags2;
rStrm >> nFlags1 >> maModel.mnNumFmtId >> nFlags2 >> maModel.mnAutoShowItems >> maModel.mnAutoShowRankBy;
maModel.setBiffAxis( extractValue< sal_uInt8 >( nFlags1, 0, 3 ) );
maModel.mbDataField = getFlag( nFlags1, BIFF12_PTFIELD_DATAFIELD );
maModel.mbDefaultSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_DEFAULT );
maModel.mbSumSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_SUM );
maModel.mbCountASubtotal = getFlag( nFlags1, BIFF12_PTFIELD_COUNTA );
maModel.mbAverageSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_AVERAGE );
maModel.mbMaxSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_MAX );
maModel.mbMinSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_MIN );
maModel.mbProductSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_PRODUCT );
maModel.mbCountSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_COUNT );
maModel.mbStdDevSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_STDDEV );
maModel.mbStdDevPSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_STDDEVP );
maModel.mbVarSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_VAR );
maModel.mbVarPSubtotal = getFlag( nFlags1, BIFF12_PTFIELD_VARP );
maModel.mbShowAll = getFlag( nFlags2, BIFF12_PTFIELD_SHOWALL );
maModel.mbOutline = getFlag( nFlags2, BIFF12_PTFIELD_OUTLINE );
maModel.mbSubtotalTop = getFlag( nFlags2, BIFF12_PTFIELD_SUBTOTALTOP );
maModel.mbInsertBlankRow = getFlag( nFlags2, BIFF12_PTFIELD_INSERTBLANKROW );
maModel.mbInsertPageBreak = getFlag( nFlags2, BIFF12_PTFIELD_INSERTPAGEBREAK );
maModel.mbAutoShow = getFlag( nFlags2, BIFF12_PTFIELD_AUTOSHOW );
maModel.mbTopAutoShow = getFlag( nFlags2, BIFF12_PTFIELD_AUTOSHOWTOP );
maModel.mbMultiPageItems = getFlag( nFlags2, BIFF12_PTFIELD_MULTIPAGEITEMS );
bool bAutoSort = getFlag( nFlags2, BIFF12_PTFIELD_AUTOSORT );
bool bAscending = getFlag( nFlags2, BIFF12_PTFIELD_SORTASCENDING );
maModel.mnSortType = bAutoSort ? (bAscending ? XML_ascending : XML_descending) : XML_manual;
}
void PivotTableField::importPTFItem( SequenceInputStream& rStrm )
{
PTFieldItemModel aModel;
sal_uInt8 nType;
sal_uInt16 nFlags;
rStrm >> nType >> nFlags >> aModel.mnCacheItem;
aModel.setBiffType( nType );
aModel.mbShowDetails = !getFlag( nFlags, BIFF12_PTFITEM_HIDEDETAILS );
aModel.mbHidden = getFlag( nFlags, BIFF12_PTFITEM_HIDDEN );
maItems.push_back( aModel );
}
void PivotTableField::importPTReference( SequenceInputStream& rStrm )
{
rStrm >> maModel.mnSortRefField;
}
void PivotTableField::importPTReferenceItem( SequenceInputStream& rStrm )
{
rStrm >> maModel.mnSortRefItem;
}
void PivotTableField::importPTField( BiffInputStream& rStrm )
{
sal_uInt16 nAxis, nSubtCount, nSubtotals;
rStrm >> nAxis >> nSubtCount >> nSubtotals;
rStrm.skip( 2 ); // item count
maModel.setBiffAxis( extractValue< sal_uInt8 >( nAxis, 0, 3 ) );
maModel.mbDataField = getFlag( nAxis, BIFF_PTFIELD_DATAFIELD );
maModel.mbDefaultSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_DEFAULT );
maModel.mbSumSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_SUM );
maModel.mbCountASubtotal = getFlag( nSubtotals, BIFF_PTFIELD_COUNTA );
maModel.mbAverageSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_AVERAGE );
maModel.mbMaxSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_MAX );
maModel.mbMinSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_MIN );
maModel.mbProductSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_PRODUCT );
maModel.mbCountSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_COUNT );
maModel.mbStdDevSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_STDDEV );
maModel.mbStdDevPSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_STDDEVP );
maModel.mbVarSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_VAR );
maModel.mbVarPSubtotal = getFlag( nSubtotals, BIFF_PTFIELD_VARP );
// set different defaults for BIFF
maModel.mbShowAll = maModel.mbOutline = maModel.mbSubtotalTop = false;
// read following items
while( (rStrm.getNextRecId() == BIFF_ID_PTFITEM) && rStrm.startNextRecord() )
importPTFItem( rStrm );
// read following PTFIELD2 record with additional field settings
if( (getBiff() == BIFF8) && (rStrm.getNextRecId() == BIFF_ID_PTFIELD2) && rStrm.startNextRecord() )
importPTField2( rStrm );
}
void PivotTableField::importPTField2( BiffInputStream& rStrm )
{
sal_uInt32 nFlags;
rStrm >> nFlags;
maModel.mnSortRefItem = rStrm.readInt16();
maModel.mnAutoShowRankBy = rStrm.readInt16();
maModel.mnNumFmtId = rStrm.readuInt16();
maModel.mnAutoShowItems = extractValue< sal_Int32 >( nFlags, 24, 8 );
maModel.mbShowAll = getFlag( nFlags, BIFF_PTFIELD2_SHOWALL );
maModel.mbOutline = getFlag( nFlags, BIFF_PTFIELD2_OUTLINE );
maModel.mbSubtotalTop = getFlag( nFlags, BIFF_PTFIELD2_SUBTOTALTOP );
maModel.mbInsertBlankRow = getFlag( nFlags, BIFF_PTFIELD2_INSERTBLANKROW );
maModel.mbAutoShow = getFlag( nFlags, BIFF_PTFIELD2_AUTOSHOW );
maModel.mbTopAutoShow = getFlag( nFlags, BIFF_PTFIELD2_AUTOSHOWTOP );
bool bAutoSort = getFlag( nFlags, BIFF_PTFIELD2_AUTOSORT );
bool bAscending = getFlag( nFlags, BIFF_PTFIELD2_SORTASCENDING );
maModel.mnSortType = bAutoSort ? (bAscending ? XML_ascending : XML_descending) : XML_manual;
// mnSortRefField == OOX_PT_DATALAYOUTFIELD will indicate sorting by data field
if( maModel.mnSortRefItem >= 0 )
maModel.mnSortRefField = OOX_PT_DATALAYOUTFIELD;
}
void PivotTableField::importPTFItem( BiffInputStream& rStrm )
{
PTFieldItemModel aModel;
sal_uInt16 nType, nFlags;
sal_Int16 nCacheItem;
rStrm >> nType >> nFlags >> nCacheItem;
aModel.setBiffType( nType );
aModel.mnCacheItem = nCacheItem;
aModel.mbShowDetails = !getFlag( nFlags, BIFF_PTFITEM_HIDEDETAILS );
aModel.mbHidden = getFlag( nFlags, BIFF_PTFITEM_HIDDEN );
maItems.push_back( aModel );
}
void PivotTableField::finalizeImport( const Reference< XDataPilotDescriptor >& rxDPDesc )
{
/* Process all fields based on source data, other fields (e.g. group
fields) are processed from here. PivotCacahe::getDatabaseIndex()
returns -1 for all fields not based on source data. */
Reference< XDataPilotField > xDPField;
sal_Int32 nDatabaseIdx = mrPivotTable.getCacheDatabaseIndex( mnFieldIndex );
if( (nDatabaseIdx >= 0) && rxDPDesc.is() ) try
{
// try to get the source field and its name from passed DataPilot descriptor
Reference< XIndexAccess > xDPFieldsIA( rxDPDesc->getDataPilotFields(), UNO_SET_THROW );
xDPField.set( xDPFieldsIA->getByIndex( nDatabaseIdx ), UNO_QUERY_THROW );
Reference< XNamed > xDPFieldName( xDPField, UNO_QUERY_THROW );
maDPFieldName = xDPFieldName->getName();
OSL_ENSURE( maDPFieldName.getLength() > 0, "PivotTableField::finalizeImport - no field name in source data found" );
// try to convert grouping settings
if( const PivotCacheField* pCacheField = mrPivotTable.getCacheField( mnFieldIndex ) )
{
// numeric grouping is done inplace, no nested group fields will appear
if( pCacheField->hasNumericGrouping() )
{
pCacheField->convertNumericGrouping( xDPField );
}
else if( pCacheField->hasDateGrouping() )
{
// first date group settings are inplace
pCacheField->createDateGroupField( xDPField );
// create all nested group fields (if any)
mrPivotTable.finalizeDateGroupingImport( xDPField, mnFieldIndex );
}
else if( pCacheField->hasParentGrouping() )
{
// create a list of all item names, needed to map between original and group items
::std::vector< OUString > aItems;
pCacheField->getCacheItemNames( aItems );
PivotCacheGroupItemVector aItemNames;
for( ::std::vector< OUString >::iterator aIt = aItems.begin(), aEnd = aItems.end(); aIt != aEnd; ++aIt )
aItemNames.push_back( PivotCacheGroupItem( *aIt ) );
// create all nested group fields (if any)
mrPivotTable.finalizeParentGroupingImport( xDPField, *pCacheField, aItemNames );
}
}
}
catch( Exception& )
{
}
}
void PivotTableField::finalizeDateGroupingImport( const Reference< XDataPilotField >& rxBaseDPField, sal_Int32 nBaseFieldIdx )
{
if( maDPFieldName.getLength() == 0 ) // prevent endless loops if file format is broken
{
if( const PivotCacheField* pCacheField = mrPivotTable.getCacheField( mnFieldIndex ) )
{
if( !pCacheField->isDatabaseField() && pCacheField->hasDateGrouping() && (pCacheField->getGroupBaseField() == nBaseFieldIdx) )
{
maDPFieldName = pCacheField->createDateGroupField( rxBaseDPField );
OSL_ENSURE( maDPFieldName.getLength() > 0, "PivotTableField::finalizeDateGroupingImport - cannot create date group field" );
}
}
}
}
void PivotTableField::finalizeParentGroupingImport( const Reference< XDataPilotField >& rxBaseDPField, PivotCacheGroupItemVector& orItemNames )
{
if( maDPFieldName.getLength() == 0 ) // prevent endless loops if file format is broken
{
if( const PivotCacheField* pCacheField = mrPivotTable.getCacheField( mnFieldIndex ) )
{
maDPFieldName = pCacheField->createParentGroupField( rxBaseDPField, orItemNames );
// on success, try to create nested group fields
Reference< XDataPilotField > xDPField = mrPivotTable.getDataPilotField( maDPFieldName );
if( xDPField.is() )
mrPivotTable.finalizeParentGroupingImport( xDPField, *pCacheField, orItemNames );
}
}
}
void PivotTableField::convertRowField()
{
convertRowColPageField( XML_axisRow );
}
void PivotTableField::convertColField()
{
convertRowColPageField( XML_axisCol );
}
void PivotTableField::convertHiddenField()
{
convertRowColPageField( XML_TOKEN_INVALID );
}
void PivotTableField::convertPageField( const PTPageFieldModel& rPageField )
{
OSL_ENSURE( rPageField.mnField == mnFieldIndex, "PivotTableField::convertPageField - wrong field index" );
// convert all settings common for row/column/page fields
Reference< XDataPilotField > xDPField = convertRowColPageField( XML_axisPage );
if( xDPField.is() )
{
PropertySet aPropSet( xDPField );
using namespace ::com::sun::star::sheet;
// find cache item used as 'selected page'
sal_Int32 nCacheItem = -1;
if( maModel.mbMultiPageItems )
{
// multiple items may be selected
OSL_ENSURE( rPageField.mnItem == BIFF12_PTPAGEFIELD_MULTIITEMS, "PivotTableField::convertPageField - unexpected cache item index" );
// try to find a single visible item
bool bHasMultiItems = false;
for( ItemModelVector::iterator aIt = maItems.begin(), aEnd = maItems.end(); (aIt != aEnd) && !bHasMultiItems; ++aIt )
{
if( (aIt->mnType == XML_data) && !aIt->mbHidden )
{
bHasMultiItems = nCacheItem >= 0;
nCacheItem = bHasMultiItems ? -1 : aIt->mnCacheItem;
}
}
}
else
{
// single item may be selected
if( (0 <= rPageField.mnItem) && (rPageField.mnItem < static_cast< sal_Int32 >( maItems.size() )) )
nCacheItem = maItems[ rPageField.mnItem ].mnCacheItem;
}
if( nCacheItem >= 0 )
{
if( const PivotCacheField* pCacheField = mrPivotTable.getCacheField( mnFieldIndex ) )
{
if( const PivotCacheItem* pSharedItem = pCacheField->getCacheItem( nCacheItem ) )
{
OUString aSelectedPage = pSharedItem->getName();
aPropSet.setProperty( PROP_SelectedPage, aSelectedPage );
}
}
}
}
}
void PivotTableField::convertDataField( const PTDataFieldModel& rDataField )
{
OSL_ENSURE( rDataField.mnField == mnFieldIndex, "PivotTableField::convertDataField - wrong field index" );
OSL_ENSURE( maModel.mbDataField, "PivotTableField::convertDataField - not a data field" );
Reference< XDataPilotField > xDPField = mrPivotTable.getDataPilotField( maDPFieldName );
if( xDPField.is() )
{
PropertySet aPropSet( xDPField );
using namespace ::com::sun::star::sheet;
// field orientation
aPropSet.setProperty( PROP_Orientation, DataPilotFieldOrientation_DATA );
/* Field aggregation function. Documentation is a little bit confused
about which names to use for the count functions. The name 'count'
means 'count all', and 'countNum' means 'count numbers'. On the
other hand, for subtotals, 'countA' means 'count all', and 'count'
means 'count numbers' (see above). */
GeneralFunction eAggFunc = GeneralFunction_SUM;
switch( rDataField.mnSubtotal )
{
case XML_sum: eAggFunc = GeneralFunction_SUM; break;
case XML_count: eAggFunc = GeneralFunction_COUNT; break;
case XML_average: eAggFunc = GeneralFunction_AVERAGE; break;
case XML_max: eAggFunc = GeneralFunction_MAX; break;
case XML_min: eAggFunc = GeneralFunction_MIN; break;
case XML_product: eAggFunc = GeneralFunction_PRODUCT; break;
case XML_countNums: eAggFunc = GeneralFunction_COUNTNUMS; break;
case XML_stdDev: eAggFunc = GeneralFunction_STDEV; break;
case XML_stdDevp: eAggFunc = GeneralFunction_STDEVP; break;
case XML_var: eAggFunc = GeneralFunction_VAR; break;
case XML_varp: eAggFunc = GeneralFunction_VARP; break;
default: OSL_ENSURE( false, "PivotTableField::convertDataField - unknown aggregation function" );
}
aPropSet.setProperty( PROP_Function, eAggFunc );
// field reference ('show data as')
DataPilotFieldReference aReference;
aReference.ReferenceType = DataPilotFieldReferenceType::NONE;
switch( rDataField.mnShowDataAs )
{
case XML_difference: aReference.ReferenceType = DataPilotFieldReferenceType::ITEM_DIFFERENCE; break;
case XML_percent: aReference.ReferenceType = DataPilotFieldReferenceType::ITEM_PERCENTAGE; break;
case XML_percentDiff: aReference.ReferenceType = DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE; break;
case XML_runTotal: aReference.ReferenceType = DataPilotFieldReferenceType::RUNNING_TOTAL; break;
case XML_percentOfRow: aReference.ReferenceType = DataPilotFieldReferenceType::ROW_PERCENTAGE; break;
case XML_percentOfCol: aReference.ReferenceType = DataPilotFieldReferenceType::COLUMN_PERCENTAGE; break;
case XML_percentOfTotal: aReference.ReferenceType = DataPilotFieldReferenceType::TOTAL_PERCENTAGE; break;
case XML_index: aReference.ReferenceType = DataPilotFieldReferenceType::INDEX; break;
}
if( aReference.ReferenceType != DataPilotFieldReferenceType::NONE )
{
if( const PivotCacheField* pCacheField = mrPivotTable.getCacheField( rDataField.mnBaseField ) )
{
aReference.ReferenceField = pCacheField->getName();
switch( rDataField.mnBaseItem )
{
case OOX_PT_PREVIOUS_ITEM:
aReference.ReferenceItemType = DataPilotFieldReferenceItemType::PREVIOUS;
break;
case OOX_PT_NEXT_ITEM:
aReference.ReferenceItemType = DataPilotFieldReferenceItemType::NEXT;
break;
default:
aReference.ReferenceItemType = DataPilotFieldReferenceItemType::NAMED;
if( const PivotCacheItem* pCacheItem = pCacheField->getCacheItem( rDataField.mnBaseItem ) )
aReference.ReferenceItemName = pCacheItem->getName();
}
aPropSet.setProperty( PROP_Reference, aReference );
}
}
}
}
// private --------------------------------------------------------------------
Reference< XDataPilotField > PivotTableField::convertRowColPageField( sal_Int32 nAxis )
{
bool bDataLayout = mnFieldIndex == OOX_PT_DATALAYOUTFIELD;
Reference< XDataPilotField > xDPField = bDataLayout ? mrPivotTable.getDataLayoutField() : mrPivotTable.getDataPilotField( maDPFieldName );
OSL_ENSURE( bDataLayout || (nAxis == maModel.mnAxis), "PivotTableField::convertRowColPageField - field axis mismatch" );
if( xDPField.is() )
{
PropertySet aPropSet( xDPField );
using namespace ::com::sun::star::sheet;
// field orientation
DataPilotFieldOrientation eFieldOrient = DataPilotFieldOrientation_HIDDEN;
switch( nAxis )
{
case XML_axisRow: eFieldOrient = DataPilotFieldOrientation_ROW; break;
case XML_axisCol: eFieldOrient = DataPilotFieldOrientation_COLUMN; break;
case XML_axisPage: eFieldOrient = DataPilotFieldOrientation_PAGE; break;
}
if( eFieldOrient != DataPilotFieldOrientation_HIDDEN )
aPropSet.setProperty( PROP_Orientation, eFieldOrient );
// all other settings not for the data layout field
if( !bDataLayout )
{
/* Field subtotal functions. Ignore the 'defaultSubtotal' flag, if
explicit functions are set. This is different behaviour between
XML (where 'defaultSubtotal' is set regardless of other
functions) and binary formats (where 'defaultSubtotal' is not
set if other functions are set). */
::std::vector< GeneralFunction > aSubtotals;
/* Order of subtotals is fixed in Excel. Documentation is a little
bit confused about which names to use for the count functions.
For subtotals, 'countA' means 'count all', and 'count' means
'count numbers'. On the other hand, for the data field
aggregation function, 'count' means 'count all', and 'countNum'
means 'count numbers' (see below). */
if( maModel.mbSumSubtotal ) aSubtotals.push_back( GeneralFunction_SUM );
if( maModel.mbCountASubtotal ) aSubtotals.push_back( GeneralFunction_COUNT );
if( maModel.mbAverageSubtotal ) aSubtotals.push_back( GeneralFunction_AVERAGE );
if( maModel.mbMaxSubtotal ) aSubtotals.push_back( GeneralFunction_MAX );
if( maModel.mbMinSubtotal ) aSubtotals.push_back( GeneralFunction_MIN );
if( maModel.mbProductSubtotal ) aSubtotals.push_back( GeneralFunction_PRODUCT );
if( maModel.mbCountSubtotal ) aSubtotals.push_back( GeneralFunction_COUNTNUMS );
if( maModel.mbStdDevSubtotal ) aSubtotals.push_back( GeneralFunction_STDEV );
if( maModel.mbStdDevPSubtotal ) aSubtotals.push_back( GeneralFunction_STDEVP );
if( maModel.mbVarSubtotal ) aSubtotals.push_back( GeneralFunction_VAR );
if( maModel.mbVarPSubtotal ) aSubtotals.push_back( GeneralFunction_VARP );
// if no function is set manually, check the 'defaultSubtotal' flag
if( aSubtotals.empty() && maModel.mbDefaultSubtotal )
aSubtotals.push_back( GeneralFunction_AUTO );
aPropSet.setProperty( PROP_Subtotals, ContainerHelper::vectorToSequence( aSubtotals ) );
// layout settings
DataPilotFieldLayoutInfo aLayoutInfo;
aLayoutInfo.LayoutMode = maModel.mbOutline ?
(maModel.mbSubtotalTop ? DataPilotFieldLayoutMode::OUTLINE_SUBTOTALS_TOP : DataPilotFieldLayoutMode::OUTLINE_SUBTOTALS_BOTTOM) :
DataPilotFieldLayoutMode::TABULAR_LAYOUT;
aLayoutInfo.AddEmptyLines = maModel.mbInsertBlankRow;
aPropSet.setProperty( PROP_LayoutInfo, aLayoutInfo );
aPropSet.setProperty( PROP_ShowEmpty, maModel.mbShowAll );
// auto show (OOXML/BIFF12 only)
if( maModel.mbAutoShow )
{
DataPilotFieldAutoShowInfo aAutoShowInfo;
aAutoShowInfo.IsEnabled = sal_True;
aAutoShowInfo.ShowItemsMode = maModel.mbTopAutoShow ? DataPilotFieldShowItemsMode::FROM_TOP : DataPilotFieldShowItemsMode::FROM_BOTTOM;
aAutoShowInfo.ItemCount = maModel.mnAutoShowItems;
if( const PivotCacheField* pCacheField = mrPivotTable.getCacheFieldOfDataField( maModel.mnAutoShowRankBy ) )
aAutoShowInfo.DataField = pCacheField->getName();
aPropSet.setProperty( PROP_AutoShowInfo, aAutoShowInfo );
}
// auto sort
DataPilotFieldSortInfo aSortInfo;
aSortInfo.IsAscending = maModel.mnSortType == XML_ascending;
if( (maModel.mnSortType != XML_ascending) && (maModel.mnSortType != XML_descending) )
{
aSortInfo.Mode = DataPilotFieldSortMode::MANUAL;
}
else
{
const PivotCacheField* pCacheField = (maModel.mnSortRefField == OOX_PT_DATALAYOUTFIELD) ?
mrPivotTable.getCacheFieldOfDataField( maModel.mnSortRefItem ) : 0;
if( pCacheField )
{
aSortInfo.Mode = DataPilotFieldSortMode::DATA;
aSortInfo.Field = pCacheField->getName();
}
else
{
aSortInfo.Mode = DataPilotFieldSortMode::NAME;
}
}
aPropSet.setProperty( PROP_SortInfo, aSortInfo );
// item settings
if( const PivotCacheField* pCacheField = mrPivotTable.getCacheField( mnFieldIndex ) ) try
{
Reference< XNameAccess > xDPItemsNA( xDPField->getItems(), UNO_QUERY_THROW );
for( ItemModelVector::iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
{
if( aIt->mnType == XML_data )
{
if( const PivotCacheItem* pSharedItem = pCacheField->getCacheItem( aIt->mnCacheItem ) ) try
{
PropertySet aItemProp( xDPItemsNA->getByName( pSharedItem->getName() ) );
aItemProp.setProperty( PROP_ShowDetail, aIt->mbShowDetails );
aItemProp.setProperty( PROP_IsHidden, aIt->mbHidden );
}
catch( Exception& )
{
// catch every failed container access to be able to process following items
}
}
}
}
catch( Exception& )
{
}
}
}
return xDPField;
}
// ============================================================================
PTFilterModel::PTFilterModel() :
mfValue( 0.0 ),
mnField( -1 ),
mnMemPropField( -1 ),
mnType( XML_TOKEN_INVALID ),
mnEvalOrder( 0 ),
mnId( -1 ),
mnMeasureField( -1 ),
mnMeasureHier( -1 ),
mbTopFilter( true )
{
}
// ----------------------------------------------------------------------------
PivotTableFilter::PivotTableFilter( const PivotTable& rPivotTable ) :
WorkbookHelper( rPivotTable ),
mrPivotTable( rPivotTable )
{
}
void PivotTableFilter::importFilter( const AttributeList& rAttribs )
{
maModel.maName = rAttribs.getXString( XML_name, OUString() );
maModel.maDescription = rAttribs.getXString( XML_description, OUString() );
maModel.maStrValue1 = rAttribs.getXString( XML_stringValue1, OUString() );
maModel.maStrValue2 = rAttribs.getXString( XML_stringValue2, OUString() );
maModel.mnField = rAttribs.getInteger( XML_fld, -1 );
maModel.mnMemPropField = rAttribs.getInteger( XML_mpFld, -1 );
maModel.mnType = rAttribs.getToken( XML_type, XML_TOKEN_INVALID );
maModel.mnEvalOrder = rAttribs.getInteger( XML_evalOrder, 0 );
maModel.mnId = rAttribs.getInteger( XML_id, -1 );
maModel.mnMeasureField = rAttribs.getInteger( XML_iMeasureFld, -1 );
maModel.mnMeasureHier = rAttribs.getInteger( XML_iMeasureHier, -1 );
}
void PivotTableFilter::importTop10( const AttributeList& rAttribs )
{
OSL_ENSURE( rAttribs.getBool( XML_percent, false ) == (maModel.mnType == XML_percent),
"PivotTableFilter::importTop10 - unexpected value of percent attribute" );
maModel.mfValue = rAttribs.getDouble( XML_val, 0.0 );
maModel.mbTopFilter = rAttribs.getBool( XML_top, true );
}
void PivotTableFilter::importPTFilter( SequenceInputStream& rStrm )
{
sal_Int32 nType;
sal_uInt16 nFlags;
rStrm >> maModel.mnField >> maModel.mnMemPropField >> nType;
rStrm.skip( 4 ); // unused
rStrm >> maModel.mnId >> maModel.mnMeasureField >> maModel.mnMeasureHier >> nFlags;
if( getFlag( nFlags, BIFF12_PTFILTER_HASNAME ) )
rStrm >> maModel.maName;
if( getFlag( nFlags, BIFF12_PTFILTER_HASDESCRIPTION ) )
rStrm >> maModel.maDescription;
if( getFlag( nFlags, BIFF12_PTFILTER_HASSTRVALUE1 ) )
rStrm >> maModel.maStrValue1;
if( getFlag( nFlags, BIFF12_PTFILTER_HASSTRVALUE2 ) )
rStrm >> maModel.maStrValue2;
static sal_Int32 spnTypes[] =
{
XML_unknown,
// data field top10 filter (1-3)
XML_count, XML_percent, XML_sum,
// caption filter (4-17)
XML_captionEqual, XML_captionNotEqual,
XML_captionBeginsWith, XML_captionNotBeginsWith, XML_captionEndsWith, XML_captionNotEndsWith,
XML_captionContains, XML_captionNotContains, XML_captionGreaterThan, XML_captionGreaterThanOrEqual,
XML_captionLessThan, XML_captionLessThanOrEqual, XML_captionBetween, XML_captionNotBetween,
// value filter (18-25)
XML_valueEqual, XML_valueNotEqual, XML_valueGreaterThan, XML_valueGreaterThanOrEqual,
XML_valueLessThan, XML_valueLessThanOrEqual, XML_valueBetween, XML_valueNotBetween,
// date filter (26-65)
XML_dateEqual, XML_dateOlderThan, XML_dateNewerThan, XML_dateBetween,
XML_tomorrow, XML_today, XML_yesterday, XML_nextWeek, XML_thisWeek, XML_lastWeek,
XML_nextMonth, XML_thisMonth, XML_lastMonth, XML_nextQuarter, XML_thisQuarter, XML_lastQuarter,
XML_nextYear, XML_thisYear, XML_lastYear, XML_yearToDate, XML_Q1, XML_Q2, XML_Q3, XML_Q4,
XML_M1, XML_M2, XML_M3, XML_M4, XML_M5, XML_M6, XML_M7, XML_M8, XML_M9, XML_M10, XML_M11, XML_M12,
XML_dateNotEqual, XML_dateOlderThanOrEqual, XML_dateNewerThanOrEqual, XML_dateNotBetween
};
maModel.mnType = STATIC_ARRAY_SELECT( spnTypes, nType, XML_TOKEN_INVALID );
}
void PivotTableFilter::importTop10Filter( SequenceInputStream& rStrm )
{
sal_uInt8 nFlags;
rStrm >> nFlags >> maModel.mfValue;
OSL_ENSURE( getFlag( nFlags, BIFF12_TOP10FILTER_PERCENT ) == (maModel.mnType == XML_percent),
"PivotTableFilter::importTop10 - unexpected value of percent attribute" );
maModel.mbTopFilter = getFlag( nFlags, BIFF12_TOP10FILTER_TOP );
}
void PivotTableFilter::finalizeImport()
{
// only simple top10 filter supported
if( maModel.mnType == XML_count )
{
PropertySet aPropSet( mrPivotTable.getDataPilotField( maModel.mnField ) );
if( aPropSet.is() )
{
using namespace ::com::sun::star::sheet;
DataPilotFieldAutoShowInfo aAutoShowInfo;
aAutoShowInfo.IsEnabled = sal_True;
aAutoShowInfo.ShowItemsMode = maModel.mbTopFilter ? DataPilotFieldShowItemsMode::FROM_TOP : DataPilotFieldShowItemsMode::FROM_BOTTOM;
aAutoShowInfo.ItemCount = getLimitedValue< sal_Int32, double >( maModel.mfValue, 0, SAL_MAX_INT32 );
if( const PivotCacheField* pCacheField = mrPivotTable.getCacheFieldOfDataField( maModel.mnMeasureField ) )
aAutoShowInfo.DataField = pCacheField->getName();
aPropSet.setProperty( PROP_AutoShowInfo, aAutoShowInfo );
}
}
}
// ============================================================================
PTDefinitionModel::PTDefinitionModel() :
mnCacheId( -1 ),
mnDataPosition( 0 ),
mnPageWrap( 0 ),
mnIndent( 1 ),
mnChartFormat( 0 ),
mnRowFields( 0 ),
mnColFields( 0 ),
mbDataOnRows( false ),
mbShowError( false ),
mbShowMissing( true ),
mbShowItems( true ),
mbDisableFieldList( false ),
mbShowCalcMembers( true ),
mbVisualTotals( true ),
mbShowDrill( true ),
mbPrintDrill( false ),
mbEnableDrill( true ),
mbPreserveFormatting( true ),
mbUseAutoFormat( false ),
mbPageOverThenDown( false ),
mbSubtotalHiddenItems( false ),
mbRowGrandTotals( true ),
mbColGrandTotals( true ),
mbFieldPrintTitles( false ),
mbItemPrintTitles( false ),
mbMergeItem( false ),
mbShowEmptyRow( false ),
mbShowEmptyCol( false ),
mbShowHeaders( true ),
mbFieldListSortAsc( false ),
mbCustomListSort( true )
{
}
// ----------------------------------------------------------------------------
PTLocationModel::PTLocationModel() :
mnFirstHeaderRow( 0 ),
mnFirstDataRow( 0 ),
mnFirstDataCol( 0 ),
mnRowPageCount( 0 ),
mnColPageCount( 0 )
{
}
// ----------------------------------------------------------------------------
PivotTable::PivotTable( const WorkbookHelper& rHelper ) :
WorkbookHelper( rHelper ),
maDataField( *this, OOX_PT_DATALAYOUTFIELD ),
mpPivotCache( 0 )
{
}
void PivotTable::importPivotTableDefinition( const AttributeList& rAttribs )
{
maDefModel.maName = rAttribs.getXString( XML_name, OUString() );
maDefModel.maDataCaption = rAttribs.getXString( XML_dataCaption , OUString() );
maDefModel.maGrandTotalCaption = rAttribs.getXString( XML_grandTotalCaption, OUString() );
maDefModel.maRowHeaderCaption = rAttribs.getXString( XML_rowHeaderCaption, OUString() );
maDefModel.maColHeaderCaption = rAttribs.getXString( XML_colHeaderCaption, OUString() );
maDefModel.maErrorCaption = rAttribs.getXString( XML_errorCaption, OUString() );
maDefModel.maMissingCaption = rAttribs.getXString( XML_missingCaption, OUString() );
maDefModel.maPageStyle = rAttribs.getXString( XML_pageStyle, OUString() );
maDefModel.maPivotTableStyle = rAttribs.getXString( XML_pivotTableStyle, OUString() );
maDefModel.maVacatedStyle = rAttribs.getXString( XML_vacatedStyle, OUString() );
maDefModel.maTag = rAttribs.getXString( XML_tag, OUString() );
maDefModel.mnCacheId = rAttribs.getInteger( XML_cacheId, -1 );
maDefModel.mnDataPosition = rAttribs.getInteger( XML_dataPosition, 0 );
maDefModel.mnPageWrap = rAttribs.getInteger( XML_pageWrap, 0 );
maDefModel.mnIndent = rAttribs.getInteger( XML_indent, 1 );
maDefModel.mnChartFormat = rAttribs.getInteger( XML_chartFormat, 0 );
maDefModel.mnAutoFormatId = rAttribs.getInteger( XML_autoFormatId, 0 );
maDefModel.mbDataOnRows = rAttribs.getBool( XML_dataOnRows, false );
maDefModel.mbShowError = rAttribs.getBool( XML_showError, false );
maDefModel.mbShowMissing = rAttribs.getBool( XML_showMissing, true );
maDefModel.mbShowItems = rAttribs.getBool( XML_showItems, true );
maDefModel.mbDisableFieldList = rAttribs.getBool( XML_disableFieldList, false );
maDefModel.mbShowCalcMembers = rAttribs.getBool( XML_showCalcMbrs, true );
maDefModel.mbVisualTotals = rAttribs.getBool( XML_visualTotals, true );
maDefModel.mbShowDrill = rAttribs.getBool( XML_showDrill, true );
maDefModel.mbPrintDrill = rAttribs.getBool( XML_printDrill, false );
maDefModel.mbEnableDrill = rAttribs.getBool( XML_enableDrill, true );
maDefModel.mbPreserveFormatting = rAttribs.getBool( XML_preserveFormatting, true );
maDefModel.mbUseAutoFormat = rAttribs.getBool( XML_useAutoFormatting, false );
maDefModel.mbPageOverThenDown = rAttribs.getBool( XML_pageOverThenDown, false );
maDefModel.mbSubtotalHiddenItems = rAttribs.getBool( XML_subtotalHiddenItems, false );
maDefModel.mbRowGrandTotals = rAttribs.getBool( XML_rowGrandTotals, true );
maDefModel.mbColGrandTotals = rAttribs.getBool( XML_colGrandTotals, true );
maDefModel.mbFieldPrintTitles = rAttribs.getBool( XML_fieldPrintTitles, false );
maDefModel.mbItemPrintTitles = rAttribs.getBool( XML_itemPrintTitles, false );
maDefModel.mbMergeItem = rAttribs.getBool( XML_mergeItem, false );
maDefModel.mbShowEmptyRow = rAttribs.getBool( XML_showEmptyRow, false );
maDefModel.mbShowEmptyCol = rAttribs.getBool( XML_showEmptyCol, false );
maDefModel.mbShowHeaders = rAttribs.getBool( XML_showHeaders, true );
maDefModel.mbFieldListSortAsc = rAttribs.getBool( XML_fieldListSortAscending, false );
maDefModel.mbCustomListSort = rAttribs.getBool( XML_customListSort, true );
maDefModel.mbApplyNumFmt = rAttribs.getBool( XML_applyNumberFormats, false );
maDefModel.mbApplyFont = rAttribs.getBool( XML_applyFontFormats, false );
maDefModel.mbApplyAlignment = rAttribs.getBool( XML_applyAlignmentFormats, false );
maDefModel.mbApplyBorder = rAttribs.getBool( XML_applyBorderFormats, false );
maDefModel.mbApplyFill = rAttribs.getBool( XML_applyPatternFormats, false );
// OOXML and BIFF12 documentation differ: OOXML mentions width/height, BIFF12 mentions protection
maDefModel.mbApplyProtection = rAttribs.getBool( XML_applyWidthHeightFormats, false );
}
void PivotTable::importLocation( const AttributeList& rAttribs, sal_Int16 nSheet )
{
getAddressConverter().convertToCellRangeUnchecked( maLocationModel.maRange, rAttribs.getString( XML_ref, OUString() ), nSheet );
maLocationModel.mnFirstHeaderRow = rAttribs.getInteger( XML_firstHeaderRow, 0 );
maLocationModel.mnFirstDataRow = rAttribs.getInteger( XML_firstDataRow, 0 );
maLocationModel.mnFirstDataCol = rAttribs.getInteger( XML_firstDataCol, 0 );
maLocationModel.mnRowPageCount = rAttribs.getInteger( XML_rowPageCount, 0 );
maLocationModel.mnColPageCount = rAttribs.getInteger( XML_colPageCount, 0 );
}
void PivotTable::importRowField( const AttributeList& rAttribs )
{
importField( maRowFields, rAttribs );
}
void PivotTable::importColField( const AttributeList& rAttribs )
{
importField( maColFields, rAttribs );
}
void PivotTable::importPageField( const AttributeList& rAttribs )
{
PTPageFieldModel aModel;
aModel.maName = rAttribs.getXString( XML_name, OUString() );
aModel.mnField = rAttribs.getInteger( XML_fld, -1 );
// specification is wrong, XML_item is not the cache item, but the field item
aModel.mnItem = rAttribs.getInteger( XML_item, BIFF12_PTPAGEFIELD_MULTIITEMS );
maPageFields.push_back( aModel );
}
void PivotTable::importDataField( const AttributeList& rAttribs )
{
PTDataFieldModel aModel;
aModel.maName = rAttribs.getXString( XML_name, OUString() );
aModel.mnField = rAttribs.getInteger( XML_fld, -1 );
aModel.mnSubtotal = rAttribs.getToken( XML_subtotal, XML_sum );
aModel.mnShowDataAs = rAttribs.getToken( XML_showDataAs, XML_normal );
aModel.mnBaseField = rAttribs.getInteger( XML_baseField, -1 );
aModel.mnBaseItem = rAttribs.getInteger( XML_baseItem, -1 );
aModel.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, 0 );
maDataFields.push_back( aModel );
}
void PivotTable::importPTDefinition( SequenceInputStream& rStrm )
{
sal_uInt32 nFlags1, nFlags2, nFlags3;
sal_uInt8 nDataAxis;
rStrm >> nFlags1 >> nFlags2 >> nFlags3 >> nDataAxis;
maDefModel.mnPageWrap = rStrm.readuInt8();
rStrm.skip( 2 ); // refresh versions
rStrm >> maDefModel.mnDataPosition;
maDefModel.mnAutoFormatId = rStrm.readuInt16();
rStrm.skip( 2 ); // unused
rStrm >> maDefModel.mnChartFormat >> maDefModel.mnCacheId >> maDefModel.maName;
if( getFlag( nFlags2, BIFF12_PTDEF_HASDATACAPTION ) )
rStrm >> maDefModel.maDataCaption;
if( getFlag( nFlags2, BIFF12_PTDEF_HASGRANDTOTALCAPTION ) )
rStrm >> maDefModel.maGrandTotalCaption;
if( !getFlag( nFlags3, BIFF12_PTDEF_NOERRORCAPTION ) ) // missing flag indicates existing string
rStrm >> maDefModel.maErrorCaption;
if( !getFlag( nFlags3, BIFF12_PTDEF_NOMISSINGCAPTION ) ) // missing flag indicates existing string
rStrm >> maDefModel.maMissingCaption;
if( getFlag( nFlags2, BIFF12_PTDEF_HASPAGESTYLE ) )
rStrm >> maDefModel.maPageStyle;
if( getFlag( nFlags2, BIFF12_PTDEF_HASPIVOTTABLESTYLE ) )
rStrm >> maDefModel.maPivotTableStyle;
if( getFlag( nFlags2, BIFF12_PTDEF_HASVACATEDSTYLE ) )
rStrm >> maDefModel.maVacatedStyle;
if( getFlag( nFlags2, BIFF12_PTDEF_HASTAG ) )
rStrm >> maDefModel.maTag;
if( getFlag( nFlags3, BIFF12_PTDEF_HASCOLHEADERCAPTION ) ) // TODO: right order (col/row)? spec is unclear
rStrm >> maDefModel.maColHeaderCaption;
if( getFlag( nFlags3, BIFF12_PTDEF_HASROWHEADERCAPTION ) )
rStrm >> maDefModel.maRowHeaderCaption;
OSL_ENSURE( (nDataAxis == BIFF12_PTDEF_ROWAXIS) || (nDataAxis == BIFF12_PTDEF_COLAXIS),
"PivotTable::importPTDefinition - unexpected axis position for data field" );
maDefModel.mnIndent = extractValue< sal_uInt8 >( nFlags1, 24, 7 );
maDefModel.mbDataOnRows = nDataAxis == BIFF12_PTDEF_ROWAXIS;
maDefModel.mbShowError = getFlag( nFlags2, BIFF12_PTDEF_SHOWERROR );
maDefModel.mbShowMissing = getFlag( nFlags2, BIFF12_PTDEF_SHOWMISSING );
maDefModel.mbShowItems = getFlag( nFlags1, BIFF12_PTDEF_SHOWITEMS );
maDefModel.mbDisableFieldList = getFlag( nFlags1, BIFF12_PTDEF_DISABLEFIELDLIST );
maDefModel.mbShowCalcMembers = !getFlag( nFlags1, BIFF12_PTDEF_HIDECALCMEMBERS );
maDefModel.mbVisualTotals = !getFlag( nFlags1, BIFF12_PTDEF_WITHHIDDENTOTALS );
maDefModel.mbShowDrill = !getFlag( nFlags1, BIFF12_PTDEF_HIDEDRILL );
maDefModel.mbPrintDrill = getFlag( nFlags1, BIFF12_PTDEF_PRINTDRILL );
maDefModel.mbEnableDrill = getFlag( nFlags2, BIFF12_PTDEF_ENABLEDRILL );
maDefModel.mbPreserveFormatting = getFlag( nFlags2, BIFF12_PTDEF_PRESERVEFORMATTING );
maDefModel.mbUseAutoFormat = getFlag( nFlags2, BIFF12_PTDEF_USEAUTOFORMAT );
maDefModel.mbPageOverThenDown = getFlag( nFlags2, BIFF12_PTDEF_PAGEOVERTHENDOWN );
maDefModel.mbSubtotalHiddenItems = getFlag( nFlags2, BIFF12_PTDEF_SUBTOTALHIDDENITEMS );
maDefModel.mbRowGrandTotals = getFlag( nFlags2, BIFF12_PTDEF_ROWGRANDTOTALS );
maDefModel.mbColGrandTotals = getFlag( nFlags2, BIFF12_PTDEF_COLGRANDTOTALS );
maDefModel.mbFieldPrintTitles = getFlag( nFlags2, BIFF12_PTDEF_FIELDPRINTTITLES );
maDefModel.mbItemPrintTitles = getFlag( nFlags2, BIFF12_PTDEF_ITEMPRINTTITLES );
maDefModel.mbMergeItem = getFlag( nFlags2, BIFF12_PTDEF_MERGEITEM );
maDefModel.mbApplyNumFmt = getFlag( nFlags2, BIFF12_PTDEF_APPLYNUMFMT );
maDefModel.mbApplyFont = getFlag( nFlags2, BIFF12_PTDEF_APPLYFONT );
maDefModel.mbApplyAlignment = getFlag( nFlags2, BIFF12_PTDEF_APPLYALIGNMENT );
maDefModel.mbApplyBorder = getFlag( nFlags2, BIFF12_PTDEF_APPLYBORDER );
maDefModel.mbApplyFill = getFlag( nFlags2, BIFF12_PTDEF_APPLYFILL );
maDefModel.mbApplyProtection = getFlag( nFlags2, BIFF12_PTDEF_APPLYPROTECTION );
maDefModel.mbShowEmptyRow = getFlag( nFlags2, BIFF12_PTDEF_SHOWEMPTYROW );
maDefModel.mbShowEmptyCol = getFlag( nFlags2, BIFF12_PTDEF_SHOWEMPTYCOL );
maDefModel.mbShowHeaders = !getFlag( nFlags1, BIFF12_PTDEF_HIDEHEADERS );
maDefModel.mbFieldListSortAsc = getFlag( nFlags3, BIFF12_PTDEF_FIELDLISTSORTASC );
maDefModel.mbCustomListSort = !getFlag( nFlags3, BIFF12_PTDEF_NOCUSTOMLISTSORT );
}
void PivotTable::importPTLocation( SequenceInputStream& rStrm, sal_Int16 nSheet )
{
BinRange aBinRange;
rStrm >> aBinRange >> maLocationModel.mnFirstHeaderRow
>> maLocationModel.mnFirstDataRow >> maLocationModel.mnFirstDataCol
>> maLocationModel.mnRowPageCount >> maLocationModel.mnColPageCount;
getAddressConverter().convertToCellRangeUnchecked( maLocationModel.maRange, aBinRange, nSheet );
}
void PivotTable::importPTRowFields( SequenceInputStream& rStrm )
{
importFields( maRowFields, rStrm );
}
void PivotTable::importPTColFields( SequenceInputStream& rStrm )
{
importFields( maColFields, rStrm );
}
void PivotTable::importPTPageField( SequenceInputStream& rStrm )
{
PTPageFieldModel aModel;
sal_uInt8 nFlags;
rStrm >> aModel.mnField >> aModel.mnItem;
rStrm.skip( 4 ); // hierarchy
rStrm >> nFlags;
if( getFlag( nFlags, BIFF12_PTPAGEFIELD_HASNAME ) )
rStrm >> aModel.maName;
maPageFields.push_back( aModel );
}
void PivotTable::importPTDataField( SequenceInputStream& rStrm )
{
PTDataFieldModel aModel;
sal_Int32 nSubtotal, nShowDataAs;
sal_uInt8 nHasName;
rStrm >> aModel.mnField >> nSubtotal >> nShowDataAs >> aModel.mnBaseField >> aModel.mnBaseItem >> aModel.mnNumFmtId >> nHasName;
if( nHasName == 1 )
rStrm >> aModel.maName;
aModel.setBiffSubtotal( nSubtotal );
aModel.setBiffShowDataAs( nShowDataAs );
maDataFields.push_back( aModel );
}
void PivotTable::importPTDefinition( BiffInputStream& rStrm, sal_Int16 nSheet )
{
BinRange aBinRange;
sal_uInt16 nFlags, nTabNameLen, nDataNameLen;
rStrm >> aBinRange;
maLocationModel.mnFirstHeaderRow = rStrm.readuInt16();
maLocationModel.mnFirstDataRow = rStrm.readuInt16();
maLocationModel.mnFirstDataCol = rStrm.readuInt16();
maDefModel.mnCacheId = rStrm.readuInt16();
rStrm.skip( 2 ); // unused
maDefModel.mbDataOnRows = rStrm.readuInt16() == BIFF_PTDEF_ROWAXIS;
maDefModel.mnDataPosition = rStrm.readInt16();
rStrm.skip( 2 ); // number of fields
rStrm >> maDefModel.mnRowFields >> maDefModel.mnColFields;
rStrm.skip( 8 ); // number of page fields, data fields, data rows, data columns
rStrm >> nFlags;
maDefModel.mnChartFormat = rStrm.readuInt16();
rStrm >> nTabNameLen >> nDataNameLen;
maDefModel.maName = lclReadPivotString( *this, rStrm, nTabNameLen );
maDefModel.maDataCaption = lclReadPivotString( *this, rStrm, nDataNameLen );
maDefModel.mbRowGrandTotals = getFlag( nFlags, BIFF_PTDEF_ROWGRANDTOTALS );
maDefModel.mbColGrandTotals = getFlag( nFlags, BIFF_PTDEF_COLGRANDTOTALS );
getAddressConverter().convertToCellRangeUnchecked( maLocationModel.maRange, aBinRange, nSheet );
}
void PivotTable::importPTDefinition2( BiffInputStream& rStrm )
{
if( getBiff() == BIFF8 )
{
sal_uInt16 nErrCaptLen, nMissCaptLen, nTagLen, nPageStyleLen, nTabStyleLen, nVacStyleLen;
sal_uInt32 nFlags;
rStrm.skip( 2 ); // number of formatting records
rStrm >> nErrCaptLen >> nMissCaptLen >> nTagLen;
rStrm.skip( 6 ); // number of selection records, page rows, page columns
rStrm >> nFlags >> nPageStyleLen >> nTabStyleLen >> nVacStyleLen;
maDefModel.maErrorCaption = lclReadPivotString( *this, rStrm, nErrCaptLen );
maDefModel.maMissingCaption = lclReadPivotString( *this, rStrm, nMissCaptLen );
maDefModel.maTag = lclReadPivotString( *this, rStrm, nTagLen );
maDefModel.maPageStyle = lclReadPivotString( *this, rStrm, nPageStyleLen );
maDefModel.maPivotTableStyle = lclReadPivotString( *this, rStrm, nTabStyleLen );
maDefModel.maVacatedStyle = lclReadPivotString( *this, rStrm, nVacStyleLen );
maDefModel.mbShowError = getFlag( nFlags, BIFF_PTDEF2_SHOWERROR );
maDefModel.mbShowMissing = getFlag( nFlags, BIFF_PTDEF2_SHOWMISSING );
maDefModel.mbEnableDrill = getFlag( nFlags, BIFF_PTDE2F_ENABLEDRILL );
maDefModel.mbPreserveFormatting = getFlag( nFlags, BIFF_PTDEF2_PRESERVEFORMATTING );
maDefModel.mbPageOverThenDown = getFlag( nFlags, BIFF_PTDEF2_PAGEOVERTHENDOWN );
maDefModel.mbSubtotalHiddenItems = getFlag( nFlags, BIFF_PTDEF2_SUBTOTALHIDDENITEMS );
maDefModel.mbMergeItem = getFlag( nFlags, BIFF_PTDEF2_MERGEITEM );
}
}
void PivotTable::importPTRowColFields( BiffInputStream& rStrm )
{
// first PTROWCOLFIELDS record contains row fields unless there are no row fields
if( (maDefModel.mnRowFields > 0) && maRowFields.empty() )
importFields( maRowFields, rStrm, maDefModel.mnRowFields );
else if( (maDefModel.mnColFields > 0) && maColFields.empty() )
importFields( maColFields, rStrm, maDefModel.mnColFields );
}
void PivotTable::importPTPageFields( BiffInputStream& rStrm )
{
while( rStrm.getRemaining() >= 6 )
{
PTPageFieldModel aModel;
sal_Int16 nField, nItem;
rStrm >> nField >> nItem;
rStrm.skip( 2 ); // dropdown object ID
aModel.mnField = nField;
aModel.mnItem = (nItem == BIFF_PTPAGEFIELDS_ALLITEMS) ? BIFF12_PTPAGEFIELD_MULTIITEMS : nItem;
maPageFields.push_back( aModel );
}
}
void PivotTable::importPTDataField( BiffInputStream& rStrm )
{
PTDataFieldModel aModel;
sal_Int16 nField, nBaseField, nBaseItem;
sal_uInt16 nSubtotal, nShowDataAs, nNumFmt, nNameLen;
rStrm >> nField >> nSubtotal >> nShowDataAs >> nBaseField >> nBaseItem >> nNumFmt >> nNameLen;
aModel.maName = lclReadPivotString( *this, rStrm, nNameLen );
aModel.mnField = nField;
aModel.setBiffSubtotal( nSubtotal );
aModel.setBiffShowDataAs( nShowDataAs );
aModel.mnBaseField = nBaseField;
switch( nBaseItem )
{
case BIFF_PTDATAFIELD_PREVIOUS: aModel.mnBaseItem = OOX_PT_PREVIOUS_ITEM; break;
case BIFF_PTDATAFIELD_NEXT: aModel.mnBaseItem = OOX_PT_NEXT_ITEM; break;
default: aModel.mnBaseItem = nBaseItem;
}
aModel.mnNumFmtId = nNumFmt;
maDataFields.push_back( aModel );
}
PivotTableField& PivotTable::createTableField()
{
sal_Int32 nFieldIndex = static_cast< sal_Int32 >( maFields.size() );
PivotTableFieldVector::value_type xTableField( new PivotTableField( *this, nFieldIndex ) );
maFields.push_back( xTableField );
return *xTableField;
}
PivotTableFilter& PivotTable::createTableFilter()
{
PivotTableFilterVector::value_type xTableFilter( new PivotTableFilter( *this ) );
maFilters.push_back( xTableFilter );
return *xTableFilter;
}
void PivotTable::finalizeImport()
{
if( getAddressConverter().validateCellRange( maLocationModel.maRange, true, true ) )
{
mpPivotCache = getPivotCaches().importPivotCacheFragment( maDefModel.mnCacheId );
if( mpPivotCache && mpPivotCache->isValidDataSource() && (maDefModel.maName.getLength() > 0) )
{
// clear destination area of the original pivot table
try
{
Reference< XSheetOperation > xSheetOp( getCellRangeFromDoc( maLocationModel.maRange ), UNO_QUERY_THROW );
using namespace ::com::sun::star::sheet::CellFlags;
xSheetOp->clearContents( VALUE | DATETIME | STRING | FORMULA | HARDATTR | STYLES | EDITATTR | FORMATTED );
}
catch( Exception& )
{
}
try
{
// create a new data pilot descriptor based on the source data
Reference< XDataPilotTablesSupplier > xDPTablesSupp( getSheetFromDoc( maLocationModel.maRange.Sheet ), UNO_QUERY_THROW );
Reference< XDataPilotTables > xDPTables( xDPTablesSupp->getDataPilotTables(), UNO_SET_THROW );
mxDPDescriptor.set( xDPTables->createDataPilotDescriptor(), UNO_SET_THROW );
mxDPDescriptor->setSourceRange( mpPivotCache->getSourceRange() );
mxDPDescriptor->setTag( maDefModel.maTag );
// global data pilot properties
PropertySet aDescProp( mxDPDescriptor );
aDescProp.setProperty( PROP_ColumnGrand, maDefModel.mbColGrandTotals );
aDescProp.setProperty( PROP_RowGrand, maDefModel.mbRowGrandTotals );
aDescProp.setProperty( PROP_ShowFilterButton, false );
aDescProp.setProperty( PROP_DrillDownOnDoubleClick, maDefModel.mbEnableDrill );
// finalize all fields, this finds field names and creates grouping fields
maFields.forEachMem( &PivotTableField::finalizeImport, ::boost::cref( mxDPDescriptor ) );
// all row fields
for( IndexVector::iterator aIt = maRowFields.begin(), aEnd = maRowFields.end(); aIt != aEnd; ++aIt )
if( PivotTableField* pField = getTableField( *aIt ) )
pField->convertRowField();
// all column fields
for( IndexVector::iterator aIt = maColFields.begin(), aEnd = maColFields.end(); aIt != aEnd; ++aIt )
if( PivotTableField* pField = getTableField( *aIt ) )
pField->convertColField();
// all page fields
for( PageFieldVector::iterator aIt = maPageFields.begin(), aEnd = maPageFields.end(); aIt != aEnd; ++aIt )
if( PivotTableField* pField = getTableField( aIt->mnField ) )
pField->convertPageField( *aIt );
// all hidden fields
::std::set< sal_Int32 > aVisFields;
aVisFields.insert( maRowFields.begin(), maRowFields.end() );
aVisFields.insert( maColFields.begin(), maColFields.end() );
for( PageFieldVector::iterator aIt = maPageFields.begin(), aEnd = maPageFields.end(); aIt != aEnd; ++aIt )
aVisFields.insert( aIt->mnField );
for( PivotTableFieldVector::iterator aBeg = maFields.begin(), aIt = aBeg, aEnd = maFields.end(); aIt != aEnd; ++aIt )
if( aVisFields.count( static_cast< sal_Int32 >( aIt - aBeg ) ) == 0 )
(*aIt)->convertHiddenField();
// all data fields
for( DataFieldVector::iterator aIt = maDataFields.begin(), aEnd = maDataFields.end(); aIt != aEnd; ++aIt )
if( PivotTableField* pField = getTableField( aIt->mnField ) )
pField->convertDataField( *aIt );
// filters
maFilters.forEachMem( &PivotTableFilter::finalizeImport );
// calculate base position of table
CellAddress aPos( maLocationModel.maRange.Sheet, maLocationModel.maRange.StartColumn, maLocationModel.maRange.StartRow );
/* If page fields exist, include them into the destination
area (they are excluded in Excel). Add an extra blank row. */
if( !maPageFields.empty() )
aPos.Row = ::std::max< sal_Int32 >( static_cast< sal_Int32 >( aPos.Row - maPageFields.size() - 1 ), 0 );
// insert the DataPilot table into the sheet
xDPTables->insertNewByName( maDefModel.maName, aPos, mxDPDescriptor );
}
catch( Exception& )
{
OSL_ENSURE( false, "PivotTable::finalizeImport - exception while creating the DataPilot table" );
}
}
}
}
void PivotTable::finalizeDateGroupingImport( const Reference< XDataPilotField >& rxBaseDPField, sal_Int32 nBaseFieldIdx )
{
// process all fields, there is no chaining information in the cache fields
maFields.forEachMem( &PivotTableField::finalizeDateGroupingImport, ::boost::cref( rxBaseDPField ), nBaseFieldIdx );
}
void PivotTable::finalizeParentGroupingImport( const Reference< XDataPilotField >& rxBaseDPField,
const PivotCacheField& rBaseCacheField, PivotCacheGroupItemVector& orItemNames )
{
// try to create parent group fields that group the items of the passed base field
if( PivotTableField* pParentTableField = maFields.get( rBaseCacheField.getParentGroupField() ).get() )
pParentTableField->finalizeParentGroupingImport( rxBaseDPField, orItemNames );
}
Reference< XDataPilotField > PivotTable::getDataPilotField( const OUString& rFieldName ) const
{
Reference< XDataPilotField > xDPField;
if( (rFieldName.getLength() > 0) && mxDPDescriptor.is() ) try
{
Reference< XNameAccess > xDPFieldsNA( mxDPDescriptor->getDataPilotFields(), UNO_QUERY_THROW );
xDPField.set( xDPFieldsNA->getByName( rFieldName ), UNO_QUERY );
}
catch( Exception& )
{
}
return xDPField;
}
Reference< XDataPilotField > PivotTable::getDataPilotField( sal_Int32 nFieldIdx ) const
{
Reference< XDataPilotField > xDPField;
if( const PivotTableField* pTableField = maFields.get( nFieldIdx ).get() )
xDPField = getDataPilotField( pTableField->getDPFieldName() );
return xDPField;
}
Reference< XDataPilotField > PivotTable::getDataLayoutField() const
{
Reference< XDataPilotField > xDPField;
try
{
Reference< XDataPilotDataLayoutFieldSupplier > xDPDataFieldSupp( mxDPDescriptor, UNO_QUERY_THROW );
xDPField = xDPDataFieldSupp->getDataLayoutField();
}
catch( Exception& )
{
}
return xDPField;
}
const PivotCacheField* PivotTable::getCacheField( sal_Int32 nFieldIdx ) const
{
return mpPivotCache ? mpPivotCache->getCacheField( nFieldIdx ) : 0;
}
const PivotCacheField* PivotTable::getCacheFieldOfDataField( sal_Int32 nDataItemIdx ) const
{
const PTDataFieldModel* pDataField = ContainerHelper::getVectorElement( maDataFields, nDataItemIdx );
return pDataField ? getCacheField( pDataField->mnField ) : 0;
}
sal_Int32 PivotTable::getCacheDatabaseIndex( sal_Int32 nFieldIdx ) const
{
return mpPivotCache ? mpPivotCache->getCacheDatabaseIndex( nFieldIdx ) : -1;
}
// private --------------------------------------------------------------------
PivotTableField* PivotTable::getTableField( sal_Int32 nFieldIdx )
{
return (nFieldIdx == OOX_PT_DATALAYOUTFIELD) ? &maDataField : maFields.get( nFieldIdx ).get();
}
void PivotTable::importField( IndexVector& orFields, const AttributeList& rAttribs )
{
orFields.push_back( rAttribs.getInteger( XML_x, -1 ) );
}
void PivotTable::importFields( IndexVector& orFields, SequenceInputStream& rStrm )
{
OSL_ENSURE( orFields.empty(), "PivotTable::importFields - multiple record instances" );
orFields.clear();
sal_Int32 nCount = rStrm.readInt32();
OSL_ENSURE( 4 * nCount == rStrm.getRemaining(), "PivotTable::importFields - invalid field count" );
nCount = static_cast< sal_Int32 >( rStrm.getRemaining() / 4 );
for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
orFields.push_back( rStrm.readInt32() );
}
void PivotTable::importFields( IndexVector& orFields, BiffInputStream& rStrm, sal_Int32 nCount )
{
OSL_ENSURE( orFields.empty(), "PivotTable::importFields - multiple record instances" );
orFields.clear();
OSL_ENSURE( 2 * nCount == rStrm.getRemaining(), "PivotTable::importFields - invalid field count" );
nCount = static_cast< sal_Int32 >( rStrm.getRemaining() / 2 );
for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
orFields.push_back( rStrm.readInt16() );
}
// ============================================================================
PivotTableBuffer::PivotTableBuffer( const WorkbookHelper& rHelper ) :
WorkbookHelper( rHelper )
{
}
PivotTable& PivotTableBuffer::createPivotTable()
{
PivotTableVector::value_type xTable( new PivotTable( *this ) );
maTables.push_back( xTable );
return *xTable;
}
void PivotTableBuffer::finalizeImport()
{
maTables.forEachMem( &PivotTable::finalizeImport );
}
// ============================================================================
} // namespace xls
} // namespace oox