blob: a1259dc7d859a12d148cb53bada90f22fdf8dd0e [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/worksheetfragment.hxx"
#include "oox/core/filterbase.hxx"
#include "oox/core/relations.hxx"
#include "oox/helper/attributelist.hxx"
#include "oox/xls/addressconverter.hxx"
#include "oox/xls/autofilterbuffer.hxx"
#include "oox/xls/autofiltercontext.hxx"
#include "oox/xls/biffinputstream.hxx"
#include "oox/xls/commentsfragment.hxx"
#include "oox/xls/condformatcontext.hxx"
#include "oox/xls/drawingfragment.hxx"
#include "oox/xls/drawingmanager.hxx"
#include "oox/xls/externallinkbuffer.hxx"
#include "oox/xls/pagesettings.hxx"
#include "oox/xls/pivottablefragment.hxx"
#include "oox/xls/querytablefragment.hxx"
#include "oox/xls/scenariobuffer.hxx"
#include "oox/xls/scenariocontext.hxx"
#include "oox/xls/sheetdatabuffer.hxx"
#include "oox/xls/sheetdatacontext.hxx"
#include "oox/xls/tablefragment.hxx"
#include "oox/xls/viewsettings.hxx"
#include "oox/xls/workbooksettings.hxx"
#include "oox/xls/worksheetsettings.hxx"
namespace oox {
namespace xls {
// ============================================================================
using namespace ::com::sun::star::table;
using namespace ::com::sun::star::uno;
using namespace ::oox::core;
using ::rtl::OUString;
using ::rtl::OUStringBuffer;
// ============================================================================
namespace {
const sal_uInt16 BIFF_COLINFO_HIDDEN = 0x0001;
const sal_uInt16 BIFF_COLINFO_SHOWPHONETIC = 0x0008;
const sal_uInt16 BIFF_COLINFO_COLLAPSED = 0x1000;
const sal_uInt16 BIFF_DEFROW_CUSTOMHEIGHT = 0x0001;
const sal_uInt16 BIFF_DEFROW_HIDDEN = 0x0002;
const sal_uInt16 BIFF_DEFROW_THICKTOP = 0x0004;
const sal_uInt16 BIFF_DEFROW_THICKBOTTOM = 0x0008;
const sal_uInt16 BIFF2_DEFROW_DEFHEIGHT = 0x8000;
const sal_uInt16 BIFF2_DEFROW_MASK = 0x7FFF;
const sal_uInt32 BIFF_DATAVAL_STRINGLIST = 0x00000080;
const sal_uInt32 BIFF_DATAVAL_ALLOWBLANK = 0x00000100;
const sal_uInt32 BIFF_DATAVAL_NODROPDOWN = 0x00000200;
const sal_uInt32 BIFF_DATAVAL_SHOWINPUT = 0x00040000;
const sal_uInt32 BIFF_DATAVAL_SHOWERROR = 0x00080000;
const sal_uInt32 BIFF_SHRFEATHEAD_SHEETPROT = 2;
const sal_Int32 BIFF12_OLEOBJECT_CONTENT = 1;
const sal_Int32 BIFF12_OLEOBJECT_ICON = 4;
const sal_Int32 BIFF12_OLEOBJECT_ALWAYS = 1;
const sal_Int32 BIFF12_OLEOBJECT_ONCALL = 3;
const sal_uInt16 BIFF12_OLEOBJECT_LINKED = 0x0001;
const sal_uInt16 BIFF12_OLEOBJECT_AUTOLOAD = 0x0002;
} // namespace
// ============================================================================
DataValidationsContext::DataValidationsContext( WorksheetFragmentBase& rFragment ) :
WorksheetContextBase( rFragment )
{
}
ContextHandlerRef DataValidationsContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
{
switch( getCurrentElement() )
{
case XLS_TOKEN( dataValidations ):
if( nElement == XLS_TOKEN( dataValidation ) )
{
importDataValidation( rAttribs );
return this;
}
break;
case XLS_TOKEN( dataValidation ):
switch( nElement )
{
case XLS_TOKEN( formula1 ):
case XLS_TOKEN( formula2 ):
return this; // collect formulas in onCharacters()
}
break;
}
return 0;
}
void DataValidationsContext::onCharacters( const OUString& rChars )
{
if( mxValModel.get() ) switch( getCurrentElement() )
{
case XLS_TOKEN( formula1 ):
mxValModel->maTokens1 = getFormulaParser().importFormula( mxValModel->maRanges.getBaseAddress(), rChars );
// process string list of a list validation (convert to list of string tokens)
if( mxValModel->mnType == XML_list )
getFormulaParser().convertStringToStringList( mxValModel->maTokens1, ',', true );
break;
case XLS_TOKEN( formula2 ):
mxValModel->maTokens2 = getFormulaParser().importFormula( mxValModel->maRanges.getBaseAddress(), rChars );
break;
}
}
void DataValidationsContext::onEndElement()
{
if( isCurrentElement( XLS_TOKEN( dataValidation ) ) && mxValModel.get() )
{
setValidation( *mxValModel );
mxValModel.reset();
}
}
ContextHandlerRef DataValidationsContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
{
if( nRecId == BIFF12_ID_DATAVALIDATION )
importDataValidation( rStrm );
return 0;
}
void DataValidationsContext::importDataValidation( const AttributeList& rAttribs )
{
mxValModel.reset( new ValidationModel );
getAddressConverter().convertToCellRangeList( mxValModel->maRanges, rAttribs.getString( XML_sqref, OUString() ), getSheetIndex(), true );
mxValModel->msRef = rAttribs.getString( XML_sqref, OUString() );
mxValModel->maInputTitle = rAttribs.getXString( XML_promptTitle, OUString() );
mxValModel->maInputMessage = rAttribs.getXString( XML_prompt, OUString() );
mxValModel->maErrorTitle = rAttribs.getXString( XML_errorTitle, OUString() );
mxValModel->maErrorMessage = rAttribs.getXString( XML_error, OUString() );
mxValModel->mnType = rAttribs.getToken( XML_type, XML_none );
mxValModel->mnOperator = rAttribs.getToken( XML_operator, XML_between );
mxValModel->mnErrorStyle = rAttribs.getToken( XML_errorStyle, XML_stop );
mxValModel->mbShowInputMsg = rAttribs.getBool( XML_showInputMessage, false );
mxValModel->mbShowErrorMsg = rAttribs.getBool( XML_showErrorMessage, false );
/* The attribute showDropDown@dataValidation is in fact a "suppress
dropdown" flag, as it was in the BIFF format! ECMA specification
and attribute name are plain wrong! */
mxValModel->mbNoDropDown = rAttribs.getBool( XML_showDropDown, false );
mxValModel->mbAllowBlank = rAttribs.getBool( XML_allowBlank, false );
}
void DataValidationsContext::importDataValidation( SequenceInputStream& rStrm )
{
ValidationModel aModel;
sal_uInt32 nFlags;
BinRangeList aRanges;
rStrm >> nFlags >> aRanges >> aModel.maErrorTitle >> aModel.maErrorMessage >> aModel.maInputTitle >> aModel.maInputMessage;
// equal flags in all BIFFs
aModel.setBiffType( extractValue< sal_uInt8 >( nFlags, 0, 4 ) );
aModel.setBiffOperator( extractValue< sal_uInt8 >( nFlags, 20, 4 ) );
aModel.setBiffErrorStyle( extractValue< sal_uInt8 >( nFlags, 4, 3 ) );
aModel.mbAllowBlank = getFlag( nFlags, BIFF_DATAVAL_ALLOWBLANK );
aModel.mbNoDropDown = getFlag( nFlags, BIFF_DATAVAL_NODROPDOWN );
aModel.mbShowInputMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWINPUT );
aModel.mbShowErrorMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWERROR );
// cell range list
getAddressConverter().convertToCellRangeList( aModel.maRanges, aRanges, getSheetIndex(), true );
// condition formula(s)
FormulaParser& rParser = getFormulaParser();
CellAddress aBaseAddr = aModel.maRanges.getBaseAddress();
aModel.maTokens1 = rParser.importFormula( aBaseAddr, FORMULATYPE_VALIDATION, rStrm );
aModel.maTokens2 = rParser.importFormula( aBaseAddr, FORMULATYPE_VALIDATION, rStrm );
// process string list of a list validation (convert to list of string tokens)
if( (aModel.mnType == XML_list) && getFlag( nFlags, BIFF_DATAVAL_STRINGLIST ) )
rParser.convertStringToStringList( aModel.maTokens1, ',', true );
// set validation data
setValidation( aModel );
}
// ============================================================================
WorksheetFragment::WorksheetFragment( const WorksheetHelper& rHelper, const OUString& rFragmentPath ) :
WorksheetFragmentBase( rHelper, rFragmentPath )
{
// import data tables related to this worksheet
RelationsRef xTableRels = getRelations().getRelationsFromType( CREATE_OFFICEDOC_RELATION_TYPE( "table" ) );
for( Relations::const_iterator aIt = xTableRels->begin(), aEnd = xTableRels->end(); aIt != aEnd; ++aIt )
importOoxFragment( new TableFragment( *this, getFragmentPathFromRelation( aIt->second ) ) );
// import comments related to this worksheet
OUString aCommentsFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "comments" ) );
if( aCommentsFragmentPath.getLength() > 0 )
importOoxFragment( new CommentsFragment( *this, aCommentsFragmentPath ) );
}
ContextHandlerRef WorksheetFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
{
switch( getCurrentElement() )
{
case XML_ROOT_CONTEXT: switch( getSheetType() )
{
case SHEETTYPE_WORKSHEET: return (nElement == XLS_TOKEN( worksheet )) ? this : 0;
case SHEETTYPE_CHARTSHEET: return 0;
case SHEETTYPE_MACROSHEET: return (nElement == XM_TOKEN( macrosheet )) ? this : 0;
case SHEETTYPE_DIALOGSHEET: return (nElement == XLS_TOKEN( dialogsheet )) ? this : 0;
case SHEETTYPE_MODULESHEET: return 0;
case SHEETTYPE_EMPTYSHEET: return 0;
}
break;
case XLS_TOKEN( worksheet ):
case XM_TOKEN( macrosheet ):
case XLS_TOKEN( dialogsheet ):
switch( nElement )
{
case XLS_TOKEN( sheetData ): return new SheetDataContext( *this );
case XLS_TOKEN( conditionalFormatting ): return new CondFormatContext( *this );
case XLS_TOKEN( dataValidations ): return new DataValidationsContext( *this );
case XLS_TOKEN( autoFilter ): return new AutoFilterContext( *this, getAutoFilters().createAutoFilter() );
case XLS_TOKEN( scenarios ): return new ScenariosContext( *this );
case XLS_TOKEN( sheetViews ):
case XLS_TOKEN( cols ):
case XLS_TOKEN( mergeCells ):
case XLS_TOKEN( hyperlinks ):
case XLS_TOKEN( rowBreaks ):
case XLS_TOKEN( colBreaks ):
case XLS_TOKEN( oleObjects ):
case XLS_TOKEN( controls ): return this;
case XLS_TOKEN( sheetPr ): getWorksheetSettings().importSheetPr( rAttribs ); return this;
case XLS_TOKEN( dimension ): importDimension( rAttribs ); break;
case XLS_TOKEN( sheetFormatPr ): importSheetFormatPr( rAttribs ); break;
case XLS_TOKEN( sheetProtection ): getWorksheetSettings().importSheetProtection( rAttribs ); break;
case XLS_TOKEN( phoneticPr ): getWorksheetSettings().importPhoneticPr( rAttribs ); break;
case XLS_TOKEN( printOptions ): getPageSettings().importPrintOptions( rAttribs ); break;
case XLS_TOKEN( pageMargins ): getPageSettings().importPageMargins( rAttribs ); break;
case XLS_TOKEN( pageSetup ): getPageSettings().importPageSetup( getRelations(), rAttribs ); break;
case XLS_TOKEN( headerFooter ): getPageSettings().importHeaderFooter( rAttribs ); return this;
case XLS_TOKEN( picture ): getPageSettings().importPicture( getRelations(), rAttribs ); break;
case XLS_TOKEN( drawing ): importDrawing( rAttribs ); break;
case XLS_TOKEN( legacyDrawing ): importLegacyDrawing( rAttribs ); break;
}
break;
case XLS_TOKEN( sheetPr ):
switch( nElement )
{
case XLS_TOKEN( tabColor ): getWorksheetSettings().importTabColor( rAttribs ); break;
case XLS_TOKEN( outlinePr ): getWorksheetSettings().importOutlinePr( rAttribs ); break;
case XLS_TOKEN( pageSetUpPr ): importPageSetUpPr( rAttribs ); break;
}
break;
case XLS_TOKEN( sheetViews ):
switch( nElement )
{
case XLS_TOKEN( sheetView ): getSheetViewSettings().importSheetView( rAttribs ); return this;
}
break;
case XLS_TOKEN( sheetView ):
switch( nElement )
{
case XLS_TOKEN( pane ): getSheetViewSettings().importPane( rAttribs ); break;
case XLS_TOKEN( selection ): getSheetViewSettings().importSelection( rAttribs ); break;
}
break;
case XLS_TOKEN( cols ):
if( nElement == XLS_TOKEN( col ) ) importCol( rAttribs );
break;
case XLS_TOKEN( mergeCells ):
if( nElement == XLS_TOKEN( mergeCell ) ) importMergeCell( rAttribs );
break;
case XLS_TOKEN( hyperlinks ):
if( nElement == XLS_TOKEN( hyperlink ) ) importHyperlink( rAttribs );
break;
case XLS_TOKEN( rowBreaks ):
if( nElement == XLS_TOKEN( brk ) ) importBrk( rAttribs, true );
break;
case XLS_TOKEN( colBreaks ):
if( nElement == XLS_TOKEN( brk ) ) importBrk( rAttribs, false );
break;
case XLS_TOKEN( headerFooter ):
switch( nElement )
{
case XLS_TOKEN( firstHeader ):
case XLS_TOKEN( firstFooter ):
case XLS_TOKEN( oddHeader ):
case XLS_TOKEN( oddFooter ):
case XLS_TOKEN( evenHeader ):
case XLS_TOKEN( evenFooter ): return this; // collect h/f contents in onCharacters()
}
break;
case XLS_TOKEN( oleObjects ):
if( nElement == XLS_TOKEN( oleObject ) ) importOleObject( rAttribs );
break;
case XLS_TOKEN( controls ):
if( nElement == XLS_TOKEN( control ) ) importControl( rAttribs );
break;
}
return 0;
}
void WorksheetFragment::onCharacters( const OUString& rChars )
{
switch( getCurrentElement() )
{
case XLS_TOKEN( firstHeader ):
case XLS_TOKEN( firstFooter ):
case XLS_TOKEN( oddHeader ):
case XLS_TOKEN( oddFooter ):
case XLS_TOKEN( evenHeader ):
case XLS_TOKEN( evenFooter ):
getPageSettings().importHeaderFooterCharacters( rChars, getCurrentElement() );
break;
}
}
ContextHandlerRef WorksheetFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
{
switch( getCurrentElement() )
{
case XML_ROOT_CONTEXT:
if( nRecId == BIFF12_ID_WORKSHEET ) return this;
break;
case BIFF12_ID_WORKSHEET:
switch( nRecId )
{
case BIFF12_ID_SHEETDATA: return new SheetDataContext( *this );
case BIFF12_ID_CONDFORMATTING: return new CondFormatContext( *this );
case BIFF12_ID_DATAVALIDATIONS: return new DataValidationsContext( *this );
case BIFF12_ID_AUTOFILTER: return new AutoFilterContext( *this, getAutoFilters().createAutoFilter() );
case BIFF12_ID_SCENARIOS: return new ScenariosContext( *this );
case BIFF12_ID_SHEETVIEWS:
case BIFF12_ID_COLS:
case BIFF12_ID_MERGECELLS:
case BIFF12_ID_ROWBREAKS:
case BIFF12_ID_COLBREAKS:
case BIFF12_ID_OLEOBJECTS:
case BIFF12_ID_CONTROLS: return this;
case BIFF12_ID_SHEETPR: getWorksheetSettings().importSheetPr( rStrm ); break;
case BIFF12_ID_DIMENSION: importDimension( rStrm ); break;
case BIFF12_ID_SHEETFORMATPR: importSheetFormatPr( rStrm ); break;
case BIFF12_ID_HYPERLINK: importHyperlink( rStrm ); break;
case BIFF12_ID_PAGEMARGINS: getPageSettings().importPageMargins( rStrm ); break;
case BIFF12_ID_PAGESETUP: getPageSettings().importPageSetup( getRelations(), rStrm ); break;
case BIFF12_ID_PRINTOPTIONS: getPageSettings().importPrintOptions( rStrm ); break;
case BIFF12_ID_HEADERFOOTER: getPageSettings().importHeaderFooter( rStrm ); break;
case BIFF12_ID_PICTURE: getPageSettings().importPicture( getRelations(), rStrm ); break;
case BIFF12_ID_SHEETPROTECTION: getWorksheetSettings().importSheetProtection( rStrm ); break;
case BIFF12_ID_PHONETICPR: getWorksheetSettings().importPhoneticPr( rStrm ); break;
case BIFF12_ID_DRAWING: importDrawing( rStrm ); break;
case BIFF12_ID_LEGACYDRAWING: importLegacyDrawing( rStrm ); break;
}
break;
case BIFF12_ID_SHEETVIEWS:
switch( nRecId )
{
case BIFF12_ID_SHEETVIEW: getSheetViewSettings().importSheetView( rStrm ); return this;
}
break;
case BIFF12_ID_SHEETVIEW:
switch( nRecId )
{
case BIFF12_ID_PANE: getSheetViewSettings().importPane( rStrm ); break;
case BIFF12_ID_SELECTION: getSheetViewSettings().importSelection( rStrm ); break;
}
break;
case BIFF12_ID_COLS:
if( nRecId == BIFF12_ID_COL ) importCol( rStrm );
break;
case BIFF12_ID_MERGECELLS:
if( nRecId == BIFF12_ID_MERGECELL ) importMergeCell( rStrm );
break;
case BIFF12_ID_ROWBREAKS:
if( nRecId == BIFF12_ID_BRK ) importBrk( rStrm, true );
break;
case BIFF12_ID_COLBREAKS:
if( nRecId == BIFF12_ID_BRK ) importBrk( rStrm, false );
break;
case BIFF12_ID_OLEOBJECTS:
if( nRecId == BIFF12_ID_OLEOBJECT ) importOleObject( rStrm );
break;
case BIFF12_ID_CONTROLS:
if( nRecId == BIFF12_ID_CONTROL ) importControl( rStrm );
break;
}
return 0;
}
const RecordInfo* WorksheetFragment::getRecordInfos() const
{
static const RecordInfo spRecInfos[] =
{
{ BIFF12_ID_AUTOFILTER, BIFF12_ID_AUTOFILTER + 1 },
{ BIFF12_ID_CFRULE, BIFF12_ID_CFRULE + 1 },
{ BIFF12_ID_COLBREAKS, BIFF12_ID_COLBREAKS + 1 },
{ BIFF12_ID_COLORSCALE, BIFF12_ID_COLORSCALE + 1 },
{ BIFF12_ID_COLS, BIFF12_ID_COLS + 1 },
{ BIFF12_ID_CONDFORMATTING, BIFF12_ID_CONDFORMATTING + 1 },
{ BIFF12_ID_CONTROLS, BIFF12_ID_CONTROLS + 2 },
{ BIFF12_ID_CUSTOMFILTERS, BIFF12_ID_CUSTOMFILTERS + 1 },
{ BIFF12_ID_CUSTOMSHEETVIEW, BIFF12_ID_CUSTOMSHEETVIEW + 1 },
{ BIFF12_ID_CUSTOMSHEETVIEWS, BIFF12_ID_CUSTOMSHEETVIEWS + 3 },
{ BIFF12_ID_DATABAR, BIFF12_ID_DATABAR + 1 },
{ BIFF12_ID_DATAVALIDATIONS, BIFF12_ID_DATAVALIDATIONS + 1 },
{ BIFF12_ID_DISCRETEFILTERS, BIFF12_ID_DISCRETEFILTERS + 1 },
{ BIFF12_ID_FILTERCOLUMN, BIFF12_ID_FILTERCOLUMN + 1 },
{ BIFF12_ID_HEADERFOOTER, BIFF12_ID_HEADERFOOTER + 1 },
{ BIFF12_ID_ICONSET, BIFF12_ID_ICONSET + 1 },
{ BIFF12_ID_MERGECELLS, BIFF12_ID_MERGECELLS + 1 },
{ BIFF12_ID_OLEOBJECTS, BIFF12_ID_OLEOBJECTS + 2 },
{ BIFF12_ID_ROW, -1 },
{ BIFF12_ID_ROWBREAKS, BIFF12_ID_ROWBREAKS + 1 },
{ BIFF12_ID_SCENARIO, BIFF12_ID_SCENARIO + 1 },
{ BIFF12_ID_SCENARIOS, BIFF12_ID_SCENARIOS + 1 },
{ BIFF12_ID_SHEETDATA, BIFF12_ID_SHEETDATA + 1 },
{ BIFF12_ID_SHEETVIEW, BIFF12_ID_SHEETVIEW + 1 },
{ BIFF12_ID_SHEETVIEWS, BIFF12_ID_SHEETVIEWS + 1 },
{ BIFF12_ID_TABLEPARTS, BIFF12_ID_TABLEPARTS + 2 },
{ BIFF12_ID_WORKSHEET, BIFF12_ID_WORKSHEET + 1 },
{ -1, -1 }
};
return spRecInfos;
}
void WorksheetFragment::initializeImport()
{
// initial processing in base class WorksheetHelper
initializeWorksheetImport();
// import query table fragments related to this worksheet
RelationsRef xQueryRels = getRelations().getRelationsFromType( CREATE_OFFICEDOC_RELATION_TYPE( "queryTable" ) );
for( Relations::const_iterator aIt = xQueryRels->begin(), aEnd = xQueryRels->end(); aIt != aEnd; ++aIt )
importOoxFragment( new QueryTableFragment( *this, getFragmentPathFromRelation( aIt->second ) ) );
// import pivot table fragments related to this worksheet
RelationsRef xPivotRels = getRelations().getRelationsFromType( CREATE_OFFICEDOC_RELATION_TYPE( "pivotTable" ) );
for( Relations::const_iterator aIt = xPivotRels->begin(), aEnd = xPivotRels->end(); aIt != aEnd; ++aIt )
importOoxFragment( new PivotTableFragment( *this, getFragmentPathFromRelation( aIt->second ) ) );
}
void WorksheetFragment::finalizeImport()
{
// final processing in base class WorksheetHelper
finalizeWorksheetImport();
}
// private --------------------------------------------------------------------
void WorksheetFragment::importPageSetUpPr( const AttributeList& rAttribs )
{
// for whatever reason, this flag is still stored separated from the page settings
getPageSettings().setFitToPagesMode( rAttribs.getBool( XML_fitToPage, false ) );
}
void WorksheetFragment::importDimension( const AttributeList& rAttribs )
{
CellRangeAddress aRange;
getAddressConverter().convertToCellRangeUnchecked( aRange, rAttribs.getString( XML_ref, OUString() ), getSheetIndex() );
/* OOXML stores the used area, if existing, or "A1" if the sheet is empty.
In case of "A1", the dimension at the WorksheetHelper object will not
be set. If the cell A1 exists, the used area will be updated while
importing the cell. */
if( (aRange.EndColumn > 0) || (aRange.EndRow > 0) )
extendUsedArea( aRange );
}
void WorksheetFragment::importSheetFormatPr( const AttributeList& rAttribs )
{
// default column settings
setBaseColumnWidth( rAttribs.getInteger( XML_baseColWidth, 8 ) );
setDefaultColumnWidth( rAttribs.getDouble( XML_defaultColWidth, 0.0 ) );
// default row settings
setDefaultRowSettings(
rAttribs.getDouble( XML_defaultRowHeight, 0.0 ),
rAttribs.getBool( XML_customHeight, false ),
rAttribs.getBool( XML_zeroHeight, false ),
rAttribs.getBool( XML_thickTop, false ),
rAttribs.getBool( XML_thickBottom, false ) );
}
void WorksheetFragment::importCol( const AttributeList& rAttribs )
{
ColumnModel aModel;
aModel.maRange.mnFirst = rAttribs.getInteger( XML_min, -1 );
aModel.maRange.mnLast = rAttribs.getInteger( XML_max, -1 );
aModel.mfWidth = rAttribs.getDouble( XML_width, 0.0 );
aModel.mnXfId = rAttribs.getInteger( XML_style, -1 );
aModel.mnLevel = rAttribs.getInteger( XML_outlineLevel, 0 );
aModel.mbShowPhonetic = rAttribs.getBool( XML_phonetic, false );
aModel.mbHidden = rAttribs.getBool( XML_hidden, false );
aModel.mbCollapsed = rAttribs.getBool( XML_collapsed, false );
// set column properties in the current sheet
setColumnModel( aModel );
}
void WorksheetFragment::importMergeCell( const AttributeList& rAttribs )
{
CellRangeAddress aRange;
if( getAddressConverter().convertToCellRange( aRange, rAttribs.getString( XML_ref, OUString() ), getSheetIndex(), true, true ) )
getSheetData().setMergedRange( aRange );
}
void WorksheetFragment::importHyperlink( const AttributeList& rAttribs )
{
HyperlinkModel aModel;
if( getAddressConverter().convertToCellRange( aModel.maRange, rAttribs.getString( XML_ref, OUString() ), getSheetIndex(), true, true ) )
{
aModel.maTarget = getRelations().getExternalTargetFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
aModel.maLocation = rAttribs.getXString( XML_location, OUString() );
aModel.maDisplay = rAttribs.getXString( XML_display, OUString() );
aModel.maTooltip = rAttribs.getXString( XML_tooltip, OUString() );
setHyperlink( aModel );
}
}
void WorksheetFragment::importBrk( const AttributeList& rAttribs, bool bRowBreak )
{
PageBreakModel aModel;
aModel.mnColRow = rAttribs.getInteger( XML_id, 0 );
aModel.mnMin = rAttribs.getInteger( XML_id, 0 );
aModel.mnMax = rAttribs.getInteger( XML_id, 0 );
aModel.mbManual = rAttribs.getBool( XML_man, false );
setPageBreak( aModel, bRowBreak );
}
void WorksheetFragment::importDrawing( const AttributeList& rAttribs )
{
setDrawingPath( getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ) );
}
void WorksheetFragment::importLegacyDrawing( const AttributeList& rAttribs )
{
setVmlDrawingPath( getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ) );
}
void WorksheetFragment::importOleObject( const AttributeList& rAttribs )
{
::oox::vml::OleObjectInfo aInfo;
aInfo.setShapeId( rAttribs.getInteger( XML_shapeId, 0 ) );
OSL_ENSURE( rAttribs.hasAttribute( XML_link ) != rAttribs.hasAttribute( R_TOKEN( id ) ),
"WorksheetFragment::importOleObject - OLE object must be either linked or embedded" );
aInfo.mbLinked = rAttribs.hasAttribute( XML_link );
if( aInfo.mbLinked )
aInfo.maTargetLink = getFormulaParser().importOleTargetLink( rAttribs.getString( XML_link, OUString() ) );
else if( rAttribs.hasAttribute( R_TOKEN( id ) ) )
importEmbeddedOleData( aInfo.maEmbeddedData, rAttribs.getString( R_TOKEN( id ), OUString() ) );
aInfo.maProgId = rAttribs.getString( XML_progId, OUString() );
aInfo.mbShowAsIcon = rAttribs.getToken( XML_dvAspect, XML_DVASPECT_CONTENT ) == XML_DVASPECT_ICON;
aInfo.mbAutoUpdate = rAttribs.getToken( XML_oleUpdate, XML_OLEUPDATE_ONCALL ) == XML_OLEUPDATE_ALWAYS;
aInfo.mbAutoLoad = rAttribs.getBool( XML_autoLoad, false );
getVmlDrawing().registerOleObject( aInfo );
}
void WorksheetFragment::importControl( const AttributeList& rAttribs )
{
::oox::vml::ControlInfo aInfo;
aInfo.setShapeId( rAttribs.getInteger( XML_shapeId, 0 ) );
aInfo.maFragmentPath = getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
aInfo.maName = rAttribs.getString( XML_name, OUString() );
getVmlDrawing().registerControl( aInfo );
}
void WorksheetFragment::importDimension( SequenceInputStream& rStrm )
{
BinRange aBinRange;
aBinRange.read( rStrm );
CellRangeAddress aRange;
getAddressConverter().convertToCellRangeUnchecked( aRange, aBinRange, getSheetIndex() );
/* BIFF12 stores the used area, if existing, or "A1" if the sheet is
empty. In case of "A1", the dimension at the WorksheetHelper object
will not be set. If the cell A1 exists, the used area will be updated
while importing the cell. */
if( (aRange.EndColumn > 0) || (aRange.EndRow > 0) )
extendUsedArea( aRange );
}
void WorksheetFragment::importSheetFormatPr( SequenceInputStream& rStrm )
{
sal_Int32 nDefaultWidth;
sal_uInt16 nBaseWidth, nDefaultHeight, nFlags;
rStrm >> nDefaultWidth >> nBaseWidth >> nDefaultHeight >> nFlags;
// base column with
setBaseColumnWidth( nBaseWidth );
// default width is stored as 1/256th of a character in BIFF12, convert to entire character
setDefaultColumnWidth( static_cast< double >( nDefaultWidth ) / 256.0 );
// row height is in twips in BIFF12, convert to points; equal flags in all BIFFs
setDefaultRowSettings(
nDefaultHeight / 20.0,
getFlag( nFlags, BIFF_DEFROW_CUSTOMHEIGHT ),
getFlag( nFlags, BIFF_DEFROW_HIDDEN ),
getFlag( nFlags, BIFF_DEFROW_THICKTOP ),
getFlag( nFlags, BIFF_DEFROW_THICKBOTTOM ) );
}
void WorksheetFragment::importCol( SequenceInputStream& rStrm )
{
ColumnModel aModel;
sal_Int32 nWidth;
sal_uInt16 nFlags;
rStrm >> aModel.maRange.mnFirst >> aModel.maRange.mnLast >> nWidth >> aModel.mnXfId >> nFlags;
// column indexes are 0-based in BIFF12, but ColumnModel expects 1-based
++aModel.maRange.mnFirst;
++aModel.maRange.mnLast;
// width is stored as 1/256th of a character in BIFF12, convert to entire character
aModel.mfWidth = static_cast< double >( nWidth ) / 256.0;
// equal flags in all BIFFs
aModel.mnLevel = extractValue< sal_Int32 >( nFlags, 8, 3 );
aModel.mbShowPhonetic = getFlag( nFlags, BIFF_COLINFO_SHOWPHONETIC );
aModel.mbHidden = getFlag( nFlags, BIFF_COLINFO_HIDDEN );
aModel.mbCollapsed = getFlag( nFlags, BIFF_COLINFO_COLLAPSED );
// set column properties in the current sheet
setColumnModel( aModel );
}
void WorksheetFragment::importMergeCell( SequenceInputStream& rStrm )
{
BinRange aBinRange;
rStrm >> aBinRange;
CellRangeAddress aRange;
if( getAddressConverter().convertToCellRange( aRange, aBinRange, getSheetIndex(), true, true ) )
getSheetData().setMergedRange( aRange );
}
void WorksheetFragment::importHyperlink( SequenceInputStream& rStrm )
{
BinRange aBinRange;
rStrm >> aBinRange;
HyperlinkModel aModel;
if( getAddressConverter().convertToCellRange( aModel.maRange, aBinRange, getSheetIndex(), true, true ) )
{
aModel.maTarget = getRelations().getExternalTargetFromRelId( BiffHelper::readString( rStrm ) );
rStrm >> aModel.maLocation >> aModel.maTooltip >> aModel.maDisplay;
setHyperlink( aModel );
}
}
void WorksheetFragment::importBrk( SequenceInputStream& rStrm, bool bRowBreak )
{
PageBreakModel aModel;
sal_Int32 nManual;
rStrm >> aModel.mnColRow >> aModel.mnMin >> aModel.mnMax >> nManual;
aModel.mbManual = nManual != 0;
setPageBreak( aModel, bRowBreak );
}
void WorksheetFragment::importDrawing( SequenceInputStream& rStrm )
{
setDrawingPath( getFragmentPathFromRelId( BiffHelper::readString( rStrm ) ) );
}
void WorksheetFragment::importLegacyDrawing( SequenceInputStream& rStrm )
{
setVmlDrawingPath( getFragmentPathFromRelId( BiffHelper::readString( rStrm ) ) );
}
void WorksheetFragment::importOleObject( SequenceInputStream& rStrm )
{
::oox::vml::OleObjectInfo aInfo;
sal_Int32 nAspect, nUpdateMode, nShapeId;
sal_uInt16 nFlags;
rStrm >> nAspect >> nUpdateMode >> nShapeId >> nFlags >> aInfo.maProgId;
aInfo.mbLinked = getFlag( nFlags, BIFF12_OLEOBJECT_LINKED );
if( aInfo.mbLinked )
aInfo.maTargetLink = getFormulaParser().importOleTargetLink( rStrm );
else
importEmbeddedOleData( aInfo.maEmbeddedData, BiffHelper::readString( rStrm ) );
aInfo.setShapeId( nShapeId );
aInfo.mbShowAsIcon = nAspect == BIFF12_OLEOBJECT_ICON;
aInfo.mbAutoUpdate = nUpdateMode == BIFF12_OLEOBJECT_ALWAYS;
aInfo.mbAutoLoad = getFlag( nFlags, BIFF12_OLEOBJECT_AUTOLOAD );
getVmlDrawing().registerOleObject( aInfo );
}
void WorksheetFragment::importControl( SequenceInputStream& rStrm )
{
::oox::vml::ControlInfo aInfo;
aInfo.setShapeId( rStrm.readInt32() );
aInfo.maFragmentPath = getFragmentPathFromRelId( BiffHelper::readString( rStrm ) );
rStrm >> aInfo.maName;
getVmlDrawing().registerControl( aInfo );
}
void WorksheetFragment::importEmbeddedOleData( StreamDataSequence& orEmbeddedData, const OUString& rRelId )
{
OUString aFragmentPath = getFragmentPathFromRelId( rRelId );
if( aFragmentPath.getLength() > 0 )
getBaseFilter().importBinaryData( orEmbeddedData, aFragmentPath );
}
// ============================================================================
BiffWorksheetFragment::BiffWorksheetFragment( const WorksheetHelper& rHelper, const BiffWorkbookFragmentBase& rParent ) :
BiffWorksheetFragmentBase( rHelper, rParent )
{
}
BiffWorksheetFragment::~BiffWorksheetFragment()
{
}
bool BiffWorksheetFragment::importFragment()
{
// initial processing in base class WorksheetHelper
initializeWorksheetImport();
// create a SheetDataContext object that implements cell import
BiffSheetDataContext aSheetData( *this );
WorkbookSettings& rWorkbookSett = getWorkbookSettings();
WorksheetSettings& rWorksheetSett = getWorksheetSettings();
SheetViewSettings& rSheetViewSett = getSheetViewSettings();
CondFormatBuffer& rCondFormats = getCondFormats();
PageSettings& rPageSett = getPageSettings();
BiffSheetDrawing& rDrawing = getBiffDrawing();
// process all record in this sheet fragment
BiffInputStream& rStrm = getInputStream();
while( rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) )
{
if( BiffHelper::isBofRecord( rStrm ) )
{
// skip unknown embedded fragments (BOF/EOF blocks)
skipFragment();
}
else
{
// cache base stream position to detect if record is already processed
sal_Int64 nStrmPos = rStrm.tellBase();
sal_uInt16 nRecId = rStrm.getRecId();
switch( nRecId )
{
// records in all BIFF versions
case BIFF_ID_BOTTOMMARGIN: rPageSett.importBottomMargin( rStrm ); break;
case BIFF_ID_CALCCOUNT: rWorkbookSett.importCalcCount( rStrm ); break;
case BIFF_ID_CALCMODE: rWorkbookSett.importCalcMode( rStrm ); break;
case BIFF_ID_DEFCOLWIDTH: importDefColWidth( rStrm ); break;
case BIFF_ID_DELTA: rWorkbookSett.importDelta( rStrm ); break;
case BIFF2_ID_DIMENSION: importDimension( rStrm ); break;
case BIFF3_ID_DIMENSION: importDimension( rStrm ); break;
case BIFF_ID_FOOTER: rPageSett.importFooter( rStrm ); break;
case BIFF_ID_HEADER: rPageSett.importHeader( rStrm ); break;
case BIFF_ID_HORPAGEBREAKS: importPageBreaks( rStrm, true ); break;
case BIFF_ID_ITERATION: rWorkbookSett.importIteration( rStrm ); break;
case BIFF_ID_LEFTMARGIN: rPageSett.importLeftMargin( rStrm ); break;
case BIFF_ID_NOTE: importNote( rStrm ); break;
case BIFF_ID_PANE: rSheetViewSett.importPane( rStrm ); break;
case BIFF_ID_PASSWORD: rWorksheetSett.importPassword( rStrm ); break;
case BIFF_ID_PRINTGRIDLINES: rPageSett.importPrintGridLines( rStrm ); break;
case BIFF_ID_PRINTHEADERS: rPageSett.importPrintHeaders( rStrm ); break;
case BIFF_ID_PROTECT: rWorksheetSett.importProtect( rStrm ); break;
case BIFF_ID_REFMODE: rWorkbookSett.importRefMode( rStrm ); break;
case BIFF_ID_RIGHTMARGIN: rPageSett.importRightMargin( rStrm ); break;
case BIFF_ID_SELECTION: rSheetViewSett.importSelection( rStrm ); break;
case BIFF_ID_TOPMARGIN: rPageSett.importTopMargin( rStrm ); break;
case BIFF_ID_VERPAGEBREAKS: importPageBreaks( rStrm, false ); break;
// BIFF specific records
default: switch( getBiff() )
{
case BIFF2: switch( nRecId )
{
case BIFF_ID_COLUMNDEFAULT: importColumnDefault( rStrm ); break;
case BIFF_ID_COLWIDTH: importColWidth( rStrm ); break;
case BIFF2_ID_DEFROWHEIGHT: importDefRowHeight( rStrm ); break;
case BIFF2_ID_WINDOW2: rSheetViewSett.importWindow2( rStrm ); break;
}
break;
case BIFF3: switch( nRecId )
{
case BIFF_ID_COLINFO: importColInfo( rStrm ); break;
case BIFF_ID_DEFCOLWIDTH: importDefColWidth( rStrm ); break;
case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight( rStrm ); break;
case BIFF_ID_HCENTER: rPageSett.importHorCenter( rStrm ); break;
case BIFF_ID_OBJ: rDrawing.importObj( rStrm ); break;
case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm ); break;
case BIFF_ID_SAVERECALC: rWorkbookSett.importSaveRecalc( rStrm ); break;
case BIFF_ID_SHEETPR: rWorksheetSett.importSheetPr( rStrm ); break;
case BIFF_ID_UNCALCED: rWorkbookSett.importUncalced( rStrm ); break;
case BIFF_ID_VCENTER: rPageSett.importVerCenter( rStrm ); break;
case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( rStrm ); break;
}
break;
case BIFF4: switch( nRecId )
{
case BIFF_ID_COLINFO: importColInfo( rStrm ); break;
case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight( rStrm ); break;
case BIFF_ID_HCENTER: rPageSett.importHorCenter( rStrm ); break;
case BIFF_ID_OBJ: rDrawing.importObj( rStrm ); break;
case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm ); break;
case BIFF_ID_PAGESETUP: rPageSett.importPageSetup( rStrm ); break;
case BIFF_ID_SAVERECALC: rWorkbookSett.importSaveRecalc( rStrm ); break;
case BIFF_ID_SHEETPR: rWorksheetSett.importSheetPr( rStrm ); break;
case BIFF_ID_STANDARDWIDTH: importStandardWidth( rStrm ); break;
case BIFF_ID_UNCALCED: rWorkbookSett.importUncalced( rStrm ); break;
case BIFF_ID_VCENTER: rPageSett.importVerCenter( rStrm ); break;
case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( rStrm ); break;
}
break;
case BIFF5: switch( nRecId )
{
case BIFF_ID_AUTOFILTER: importAutoFilter( rStrm ); break;
case BIFF_ID_COLINFO: importColInfo( rStrm ); break;
case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight( rStrm ); break;
case BIFF_ID_HCENTER: rPageSett.importHorCenter( rStrm ); break;
case BIFF_ID_MERGEDCELLS: importMergedCells( rStrm ); break; // #i62300# also in BIFF5
case BIFF_ID_OBJ: rDrawing.importObj( rStrm ); break;
case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm ); break;
case BIFF_ID_PAGESETUP: rPageSett.importPageSetup( rStrm ); break;
case BIFF_ID_PTDEFINITION: importPTDefinition( rStrm ); break;
case BIFF_ID_SAVERECALC: rWorkbookSett.importSaveRecalc( rStrm ); break;
case BIFF_ID_SCENPROTECT: rWorksheetSett.importScenProtect( rStrm ); break;
case BIFF_ID_SCL: rSheetViewSett.importScl( rStrm ); break;
case BIFF_ID_SHEETPR: rWorksheetSett.importSheetPr( rStrm ); break;
case BIFF_ID_STANDARDWIDTH: importStandardWidth( rStrm ); break;
case BIFF_ID_UNCALCED: rWorkbookSett.importUncalced( rStrm ); break;
case BIFF_ID_VCENTER: rPageSett.importVerCenter( rStrm ); break;
case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( rStrm ); break;
}
break;
case BIFF8: switch( nRecId )
{
case BIFF_ID_AUTOFILTER: importAutoFilter( rStrm ); break;
case BIFF_ID_CFHEADER: rCondFormats.importCfHeader( rStrm ); break;
case BIFF_ID_CODENAME: rWorksheetSett.importCodeName( rStrm ); break;
case BIFF_ID_COLINFO: importColInfo( rStrm ); break;
case BIFF_ID_DATAVALIDATION: importDataValidation( rStrm ); break;
case BIFF_ID_DATAVALIDATIONS: importDataValidations( rStrm ); break;
case BIFF3_ID_DEFROWHEIGHT: importDefRowHeight( rStrm ); break;
case BIFF_ID_HCENTER: rPageSett.importHorCenter( rStrm ); break;
case BIFF_ID_HYPERLINK: importHyperlink( rStrm ); break;
case BIFF_ID_LABELRANGES: importLabelRanges( rStrm ); break;
case BIFF_ID_MERGEDCELLS: importMergedCells( rStrm ); break;
case BIFF_ID_OBJ: rDrawing.importObj( rStrm ); break;
case BIFF_ID_OBJECTPROTECT: rWorksheetSett.importObjectProtect( rStrm ); break;
case BIFF_ID_PAGESETUP: rPageSett.importPageSetup( rStrm ); break;
case BIFF_ID_PHONETICPR: rWorksheetSett.importPhoneticPr( rStrm ); break;
case BIFF_ID_PICTURE: rPageSett.importPicture( rStrm ); break;
case BIFF_ID_PTDEFINITION: importPTDefinition( rStrm ); break;
case BIFF_ID_QUERYTABLE: importQueryTable( rStrm ); break;
case BIFF_ID_SAVERECALC: rWorkbookSett.importSaveRecalc( rStrm ); break;
case BIFF_ID_SCENARIOS: importScenarios( rStrm ); break;
case BIFF_ID_SCENPROTECT: rWorksheetSett.importScenProtect( rStrm ); break;
case BIFF_ID_SCL: rSheetViewSett.importScl( rStrm ); break;
case BIFF_ID_SHEETEXT: rWorksheetSett.importSheetExt( rStrm ); break;
case BIFF_ID_SHEETPR: rWorksheetSett.importSheetPr( rStrm ); break;
case BIFF_ID_SHAREDFEATHEAD: importSharedFeatHead( rStrm ); break;
case BIFF_ID_STANDARDWIDTH: importStandardWidth( rStrm ); break;
case BIFF_ID_UNCALCED: rWorkbookSett.importUncalced( rStrm ); break;
case BIFF_ID_VCENTER: rPageSett.importVerCenter( rStrm ); break;
case BIFF3_ID_WINDOW2: rSheetViewSett.importWindow2( rStrm ); break;
}
break;
case BIFF_UNKNOWN: break;
}
}
// record not processed, try record context objects
if( rStrm.tellBase() == nStrmPos )
{
// first, try cell table records
aSheetData.importRecord( rStrm );
// handle another open record context
if( mxContext.get() )
{
// if it was a cell table record, forget the other record context
if( rStrm.tellBase() == nStrmPos )
mxContext->importRecord( rStrm );
else
mxContext.reset();
}
}
}
}
// final processing in base class WorksheetHelper
finalizeWorksheetImport();
return rStrm.getRecId() == BIFF_ID_EOF;
}
// private --------------------------------------------------------------------
void BiffWorksheetFragment::importAutoFilter( BiffInputStream& rStrm )
{
mxContext.reset( new BiffAutoFilterContext( *this, getAutoFilters().createAutoFilter() ) );
mxContext->importRecord( rStrm );
}
void BiffWorksheetFragment::importColInfo( BiffInputStream& rStrm )
{
sal_uInt16 nFirstCol, nLastCol, nWidth, nXfId, nFlags;
rStrm >> nFirstCol >> nLastCol >> nWidth >> nXfId >> nFlags;
ColumnModel aModel;
// column indexes are 0-based in BIFF, but ColumnModel expects 1-based
aModel.maRange.mnFirst = static_cast< sal_Int32 >( nFirstCol ) + 1;
aModel.maRange.mnLast = static_cast< sal_Int32 >( nLastCol ) + 1;
// width is stored as 1/256th of a character in BIFF, convert to entire character
aModel.mfWidth = static_cast< double >( nWidth ) / 256.0;
aModel.mnXfId = nXfId;
aModel.mnLevel = extractValue< sal_Int32 >( nFlags, 8, 3 );
aModel.mbShowPhonetic = getFlag( nFlags, BIFF_COLINFO_SHOWPHONETIC );
aModel.mbHidden = getFlag( nFlags, BIFF_COLINFO_HIDDEN );
aModel.mbCollapsed = getFlag( nFlags, BIFF_COLINFO_COLLAPSED );
// set column properties in the current sheet
setColumnModel( aModel );
}
void BiffWorksheetFragment::importColumnDefault( BiffInputStream& rStrm )
{
sal_uInt16 nFirstCol, nLastCol, nXfId;
rStrm >> nFirstCol >> nLastCol >> nXfId;
setDefaultColumnFormat( nFirstCol, nLastCol, nXfId );
}
void BiffWorksheetFragment::importColWidth( BiffInputStream& rStrm )
{
sal_uInt8 nFirstCol, nLastCol;
sal_uInt16 nWidth;
rStrm >> nFirstCol >> nLastCol >> nWidth;
ColumnModel aModel;
// column indexes are 0-based in BIFF, but ColumnModel expects 1-based
aModel.maRange.mnFirst = static_cast< sal_Int32 >( nFirstCol ) + 1;
aModel.maRange.mnLast = static_cast< sal_Int32 >( nLastCol ) + 1;
// width is stored as 1/256th of a character in BIFF, convert to entire character
aModel.mfWidth = static_cast< double >( nWidth ) / 256.0;
// set column properties in the current sheet
setColumnModel( aModel );
}
void BiffWorksheetFragment::importDefColWidth( BiffInputStream& rStrm )
{
/* Stored as entire number of characters without padding pixels, which
will be added in setBaseColumnWidth(). Call has no effect, if a
width has already been set from the STANDARDWIDTH record. */
setBaseColumnWidth( rStrm.readuInt16() );
}
void BiffWorksheetFragment::importDefRowHeight( BiffInputStream& rStrm )
{
sal_uInt16 nFlags = BIFF_DEFROW_CUSTOMHEIGHT, nHeight;
if( getBiff() != BIFF2 )
rStrm >> nFlags;
rStrm >> nHeight;
if( getBiff() == BIFF2 )
nHeight &= BIFF2_DEFROW_MASK;
// row height is in twips in BIFF, convert to points
setDefaultRowSettings(
nHeight / 20.0,
getFlag( nFlags, BIFF_DEFROW_CUSTOMHEIGHT ),
getFlag( nFlags, BIFF_DEFROW_HIDDEN ),
getFlag( nFlags, BIFF_DEFROW_THICKTOP ),
getFlag( nFlags, BIFF_DEFROW_THICKBOTTOM ) );
}
void BiffWorksheetFragment::importDataValidations( BiffInputStream& rStrm )
{
sal_Int32 nObjId;
rStrm.skip( 10 );
rStrm >> nObjId;
//! TODO: invalidate object id in drawing object manager
}
namespace {
OUString lclReadDataValMessage( BiffInputStream& rStrm )
{
// empty strings are single NUL characters (string length is 1)
OUString aMessage = rStrm.readUniString( true );
if( (aMessage.getLength() == 1) && (aMessage[ 0 ] == 0) )
aMessage = OUString();
return aMessage;
}
ApiTokenSequence lclReadDataValFormula( BiffInputStream& rStrm, FormulaParser& rParser )
{
sal_uInt16 nFmlaSize = rStrm.readuInt16();
rStrm.skip( 2 );
return rParser.importFormula( CellAddress(), FORMULATYPE_VALIDATION, rStrm, &nFmlaSize );
}
} // namespace
void BiffWorksheetFragment::importDataValidation( BiffInputStream& rStrm )
{
ValidationModel aModel;
// flags
sal_uInt32 nFlags;
rStrm >> nFlags;
aModel.setBiffType( extractValue< sal_uInt8 >( nFlags, 0, 4 ) );
aModel.setBiffOperator( extractValue< sal_uInt8 >( nFlags, 20, 4 ) );
aModel.setBiffErrorStyle( extractValue< sal_uInt8 >( nFlags, 4, 3 ) );
aModel.mbAllowBlank = getFlag( nFlags, BIFF_DATAVAL_ALLOWBLANK );
aModel.mbNoDropDown = getFlag( nFlags, BIFF_DATAVAL_NODROPDOWN );
aModel.mbShowInputMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWINPUT );
aModel.mbShowErrorMsg = getFlag( nFlags, BIFF_DATAVAL_SHOWERROR );
// message strings
aModel.maInputTitle = lclReadDataValMessage( rStrm );
aModel.maErrorTitle = lclReadDataValMessage( rStrm );
aModel.maInputMessage = lclReadDataValMessage( rStrm );
aModel.maErrorMessage = lclReadDataValMessage( rStrm );
// condition formula(s)
FormulaParser& rParser = getFormulaParser();
aModel.maTokens1 = lclReadDataValFormula( rStrm, rParser );
aModel.maTokens2 = lclReadDataValFormula( rStrm, rParser );
// process string list of a list validation (convert to list of string tokens)
if( (aModel.mnType == XML_list) && getFlag( nFlags, BIFF_DATAVAL_STRINGLIST ) )
rParser.convertStringToStringList( aModel.maTokens1, '\0', true );
// cell range list
BinRangeList aRanges;
rStrm >> aRanges;
getAddressConverter().convertToCellRangeList( aModel.maRanges, aRanges, getSheetIndex(), true );
// set validation data
setValidation( aModel );
}
void BiffWorksheetFragment::importDimension( BiffInputStream& rStrm )
{
// 32-bit row indexes in BIFF8
bool bInt32Rows = (rStrm.getRecId() == BIFF3_ID_DIMENSION) && (getBiff() == BIFF8);
BinRange aBinRange;
aBinRange.read( rStrm, true, bInt32Rows );
/* BIFF stores the used area with end column and end row increased by 1
(first unused column and row). */
if( (aBinRange.maFirst.mnCol < aBinRange.maLast.mnCol) && (aBinRange.maFirst.mnRow < aBinRange.maLast.mnRow) )
{
// reduce range to used area
--aBinRange.maLast.mnCol;
--aBinRange.maLast.mnRow;
CellRangeAddress aRange;
getAddressConverter().convertToCellRangeUnchecked( aRange, aBinRange, getSheetIndex() );
extendUsedArea( aRange );
}
}
void BiffWorksheetFragment::importHyperlink( BiffInputStream& rStrm )
{
HyperlinkModel aModel;
// read cell range for the hyperlink
BinRange aBiffRange;
rStrm >> aBiffRange;
// #i80006# Excel silently ignores invalid hi-byte of column index (TODO: everywhere?)
aBiffRange.maFirst.mnCol &= 0xFF;
aBiffRange.maLast.mnCol &= 0xFF;
if( !getAddressConverter().convertToCellRange( aModel.maRange, aBiffRange, getSheetIndex(), true, true ) )
return;
// try to read the StdHlink data
if( !::oox::ole::OleHelper::importStdHlink( aModel, rStrm, true ) )
return;
// try to read the optional following SCREENTIP record
if( (rStrm.getNextRecId() == BIFF_ID_SCREENTIP) && rStrm.startNextRecord() )
{
rStrm.skip( 2 ); // repeated record id
// the cell range, again
rStrm >> aBiffRange;
CellRangeAddress aRange;
if( getAddressConverter().convertToCellRange( aRange, aBiffRange, getSheetIndex(), true, true ) &&
(aRange.StartColumn == aModel.maRange.StartColumn) &&
(aRange.StartRow == aModel.maRange.StartRow) &&
(aRange.EndColumn == aModel.maRange.EndColumn) &&
(aRange.EndRow == aModel.maRange.EndRow) )
{
/* This time, we have no string length, no flag field, and a
null-terminated 16-bit character array. */
aModel.maTooltip = rStrm.readNulUnicodeArray();
}
}
// store the hyperlink settings
setHyperlink( aModel );
}
void BiffWorksheetFragment::importLabelRanges( BiffInputStream& rStrm )
{
BinRangeList aBiffRowRanges, aBiffColRanges;
rStrm >> aBiffRowRanges >> aBiffColRanges;
ApiCellRangeList aColRanges, aRowRanges;
getAddressConverter().convertToCellRangeList( aColRanges, aBiffColRanges, getSheetIndex(), true );
getAddressConverter().convertToCellRangeList( aRowRanges, aBiffRowRanges, getSheetIndex(), true );
setLabelRanges( aColRanges, aRowRanges );
}
void BiffWorksheetFragment::importMergedCells( BiffInputStream& rStrm )
{
BinRangeList aBiffRanges;
rStrm >> aBiffRanges;
ApiCellRangeList aRanges;
getAddressConverter().convertToCellRangeList( aRanges, aBiffRanges, getSheetIndex(), true );
for( ApiCellRangeList::const_iterator aIt = aRanges.begin(), aEnd = aRanges.end(); aIt != aEnd; ++aIt )
getSheetData().setMergedRange( *aIt );
}
void BiffWorksheetFragment::importNote( BiffInputStream& rStrm )
{
getComments().createComment()->importNote( rStrm );
}
void BiffWorksheetFragment::importPageBreaks( BiffInputStream& rStrm, bool bRowBreak )
{
PageBreakModel aModel;
aModel.mbManual = true; // only manual breaks stored in BIFF
bool bBiff8 = getBiff() == BIFF8; // skip start/end columns or rows in BIFF8
sal_uInt16 nCount;
rStrm >> nCount;
for( sal_uInt16 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
{
aModel.mnColRow = rStrm.readuInt16();
setPageBreak( aModel, bRowBreak );
if( bBiff8 )
rStrm.skip( 4 );
}
}
void BiffWorksheetFragment::importPTDefinition( BiffInputStream& rStrm )
{
mxContext.reset( new BiffPivotTableContext( *this ) );
mxContext->importRecord( rStrm );
}
void BiffWorksheetFragment::importQueryTable( BiffInputStream& rStrm )
{
mxContext.reset( new BiffQueryTableContext( *this ) );
mxContext->importRecord( rStrm );
}
void BiffWorksheetFragment::importScenarios( BiffInputStream& rStrm )
{
getScenarios().createSheetScenarios( getSheetIndex() ).importScenarios( rStrm );
}
void BiffWorksheetFragment::importSharedFeatHead( BiffInputStream& rStrm )
{
rStrm.skip( 12 );
sal_uInt16 nType = rStrm.readuInt16();
rStrm.skip( 5 );
switch( nType )
{
case BIFF_SHRFEATHEAD_SHEETPROT:
if( rStrm.getRemaining() >= 4 )
getWorksheetSettings().importSheetProtection( rStrm );
break;
}
}
void BiffWorksheetFragment::importStandardWidth( BiffInputStream& rStrm )
{
sal_uInt16 nWidth;
rStrm >> nWidth;
// width is stored as 1/256th of a character in BIFF, convert to entire character
double fWidth = static_cast< double >( nWidth ) / 256.0;
// set as default width, will override the width from DEFCOLWIDTH record
setDefaultColumnWidth( fWidth );
}
// ============================================================================
} // namespace xls
} // namespace oox