n#683578: Performance improvements for xlsx imports.

Specifically reduces the number of UNO calls for
importing cell attributes.
This commit is contained in:
Muthu Subramanian 2011-06-09 19:15:17 +05:30
parent 403eb7e5b1
commit 7e152b6746
2 changed files with 54 additions and 62 deletions

View file

@ -274,10 +274,9 @@ private:
/** Writes all cell formatting attributes to the passed row range. */
void writeXfIdRowRangeProperties( const XfIdRowRange& rXfIdRowRange ) const;
/** Writes all cell formatting attributes to the passed cell range. */
void writeXfIdRangeProperties( const XfIdRange& rXfIdRange ) const;
/** Tries to merge the ranges last inserted in maXfIdRanges with existing ranges. */
void mergeXfIdRanges();
/** Writes all cell formatting attributes to the passed cell range list. (depreciates writeXfIdRangeProperties) */
void writeXfIdRangeListProperties( sal_Int32 nXfId, sal_Int32 nNumFmtId, const ApiCellRangeList& rRanges ) const;
/** Merges the passed merged range and updates right/bottom cell borders. */
void finalizeMergedRange( const ::com::sun::star::table::CellRangeAddress& rRange );
@ -317,7 +316,8 @@ private:
bool tryExpand( const ::com::sun::star::table::CellAddress& rCellAddr, sal_Int32 nXfId, sal_Int32 nNumFmtId );
bool tryMerge( const XfIdRange& rXfIdRange );
};
typedef ::std::map< BinAddress, XfIdRange > XfIdRangeMap;
typedef ::std::pair< sal_Int32, sal_Int32 > XfIdNumFmtKey;
typedef ::std::map< XfIdNumFmtKey, ApiCellRangeList > XfIdRangeListMap;
/** Stores information about a merged cell range. */
struct MergedRange
@ -340,7 +340,7 @@ private:
maSharedFmlaAddr; /// Address of a cell containing a pending shared formula.
BinAddress maSharedBaseAddr; /// Base address of the pending shared formula.
XfIdRowRange maXfIdRowRange; /// Cached XF identifier for a range of rows.
XfIdRangeMap maXfIdRanges; /// Collected XF identifiers for cell ranges.
XfIdRangeListMap maXfIdRangeLists; /// Collected XF identifiers for cell rangelists.
MergedRangeList maMergedRanges; /// Merged cell ranges.
MergedRangeList maCenterFillRanges; /// Merged cell ranges from 'center across' or 'fill' alignment.
bool mbPendingSharedFmla; /// True = maSharedFmlaAddr and maSharedBaseAddr are valid.

View file

@ -545,11 +545,8 @@ void SheetDataBuffer::finalizeImport()
// write default formatting of remaining row range
writeXfIdRowRangeProperties( maXfIdRowRange );
// try to merge remaining inserted ranges
mergeXfIdRanges();
// write all formatting
for( XfIdRangeMap::const_iterator aIt = maXfIdRanges.begin(), aEnd = maXfIdRanges.end(); aIt != aEnd; ++aIt )
writeXfIdRangeProperties( aIt->second );
for( XfIdRangeListMap::const_iterator aIt = maXfIdRangeLists.begin(), aEnd = maXfIdRangeLists.end(); aIt != aEnd; aIt++ )
writeXfIdRangeListProperties( aIt->first.first, aIt->first.second, aIt->second );
// merge all cached merged ranges and update right/bottom cell borders
for( MergedRangeList::iterator aIt = maMergedRanges.begin(), aEnd = maMergedRanges.end(); aIt != aEnd; ++aIt )
@ -786,34 +783,49 @@ void SheetDataBuffer::setCellFormat( const CellModel& rModel, sal_Int32 nNumFmtI
{
if( (rModel.mnXfId >= 0) || (nNumFmtId >= 0) )
{
// try to merge existing ranges and to write some formatting properties
if( !maXfIdRanges.empty() )
ApiCellRangeList::reverse_iterator aIt = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rbegin();
ApiCellRangeList::reverse_iterator aItEnd = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rend();
/* The xlsx sheet data contains row wise information.
* It is sufficient to check if the row range size is one
*/
if( aIt != aItEnd &&
aIt->Sheet == rModel.maCellAddr.Sheet &&
aIt->StartRow == aIt->EndRow &&
aIt->StartRow == rModel.maCellAddr.Row &&
(aIt->EndColumn+1) == rModel.maCellAddr.Column )
{
// get row index of last inserted cell
sal_Int32 nLastRow = maXfIdRanges.rbegin()->second.maRange.StartRow;
// row changed - try to merge ranges of last row with existing ranges
if( rModel.maCellAddr.Row != nLastRow )
{
mergeXfIdRanges();
// write format properties of all ranges above last row and remove them
XfIdRangeMap::iterator aIt = maXfIdRanges.begin(), aEnd = maXfIdRanges.end();
while( aIt != aEnd )
{
// check that range cannot be merged with current row, and that range is not in cached row range
if( (aIt->second.maRange.EndRow < nLastRow) && !maXfIdRowRange.intersects( aIt->second.maRange ) )
{
writeXfIdRangeProperties( aIt->second );
maXfIdRanges.erase( aIt++ );
aIt->EndColumn++; // Expand Column
}
else
++aIt;
}
}
{
maXfIdRangeLists[ XfIdNumFmtKey (rModel.mnXfId, nNumFmtId ) ].push_back(
CellRangeAddress( rModel.maCellAddr.Sheet, rModel.maCellAddr.Column, rModel.maCellAddr.Row,
rModel.maCellAddr.Column, rModel.maCellAddr.Row ) );
}
// try to expand last existing range, or create new range entry
if( maXfIdRanges.empty() || !maXfIdRanges.rbegin()->second.tryExpand( rModel.maCellAddr, rModel.mnXfId, nNumFmtId ) )
maXfIdRanges[ BinAddress( rModel.maCellAddr ) ].set( rModel.maCellAddr, rModel.mnXfId, nNumFmtId );
aIt = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rbegin();
aItEnd = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rend();
ApiCellRangeList::reverse_iterator aItM = aIt+1;
while( aItM != aItEnd )
{
if( aIt->Sheet == aItM->Sheet )
{
/* Try to merge this with the previous range */
if( aIt->StartRow == (aItM->EndRow + 1) &&
aIt->StartColumn == aItM->StartColumn &&
aIt->EndColumn == aItM->EndColumn)
{
aItM->EndRow = aIt->EndRow;
maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].pop_back();
break;
}
else if( aIt->StartRow > aItM->EndRow + 1 )
break; // Un-necessary to check with any other rows
}
else
break;
aItM++;
}
// update merged ranges for 'center across selection' and 'fill'
if( const Xf* pXf = getStyles().getCellXf( rModel.mnXfId ).get() )
@ -846,38 +858,18 @@ void SheetDataBuffer::writeXfIdRowRangeProperties( const XfIdRowRange& rXfIdRowR
}
}
void SheetDataBuffer::writeXfIdRangeProperties( const XfIdRange& rXfIdRange ) const
void SheetDataBuffer::writeXfIdRangeListProperties( sal_Int32 nXfId, sal_Int32 nNumFmtId, const ApiCellRangeList& rRanges ) const
{
StylesBuffer& rStyles = getStyles();
PropertyMap aPropMap;
if( rXfIdRange.mnXfId >= 0 )
rStyles.writeCellXfToPropertyMap( aPropMap, rXfIdRange.mnXfId );
if( rXfIdRange.mnNumFmtId >= 0 )
rStyles.writeNumFmtToPropertyMap( aPropMap, rXfIdRange.mnNumFmtId );
PropertySet aPropSet( getCellRange( rXfIdRange.maRange ) );
if( nXfId >= 0 )
rStyles.writeCellXfToPropertyMap( aPropMap, nXfId );
if( nNumFmtId >= 0 )
rStyles.writeNumFmtToPropertyMap( aPropMap, nNumFmtId );
PropertySet aPropSet( getCellRangeList( rRanges ) );
aPropSet.setProperties( aPropMap );
}
void SheetDataBuffer::mergeXfIdRanges()
{
if( !maXfIdRanges.empty() )
{
// get row index of last range
sal_Int32 nLastRow = maXfIdRanges.rbegin()->second.maRange.StartRow;
// process all ranges located in the same row of the last range
XfIdRangeMap::iterator aMergeIt = maXfIdRanges.end();
while( (aMergeIt != maXfIdRanges.begin()) && ((--aMergeIt)->second.maRange.StartRow == nLastRow) )
{
const XfIdRange& rMergeXfIdRange = aMergeIt->second;
// try to find a range that can be merged with rMergeRange
bool bFound = false;
for( XfIdRangeMap::iterator aIt = maXfIdRanges.begin(); !bFound && (aIt != aMergeIt); ++aIt )
if( (bFound = aIt->second.tryMerge( rMergeXfIdRange )) == true )
maXfIdRanges.erase( aMergeIt++ );
}
}
}
void SheetDataBuffer::finalizeMergedRange( const CellRangeAddress& rRange )
{
bool bMultiCol = rRange.StartColumn < rRange.EndColumn;