summaryrefslogtreecommitdiff
path: root/oox/source/xls/worksheethelper.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'oox/source/xls/worksheethelper.cxx')
-rw-r--r--oox/source/xls/worksheethelper.cxx2293
1 files changed, 2293 insertions, 0 deletions
diff --git a/oox/source/xls/worksheethelper.cxx b/oox/source/xls/worksheethelper.cxx
new file mode 100644
index 000000000000..d169f514acce
--- /dev/null
+++ b/oox/source/xls/worksheethelper.cxx
@@ -0,0 +1,2293 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "oox/xls/worksheethelper.hxx"
+
+#include <algorithm>
+#include <list>
+#include <utility>
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sheet/TableValidationVisibility.hpp>
+#include <com/sun/star/sheet/ValidationType.hpp>
+#include <com/sun/star/sheet/ValidationAlertStyle.hpp>
+#include <com/sun/star/sheet/XCellAddressable.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/sheet/XFormulaTokens.hpp>
+#include <com/sun/star/sheet/XLabelRanges.hpp>
+#include <com/sun/star/sheet/XMultiFormulaTokens.hpp>
+#include <com/sun/star/sheet/XMultipleOperation.hpp>
+#include <com/sun/star/sheet/XSheetCellRangeContainer.hpp>
+#include <com/sun/star/sheet/XSheetCondition2.hpp>
+#include <com/sun/star/sheet/XSheetOutline.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/table/XColumnRowRange.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/XMergeable.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <rtl/ustrbuf.hxx>
+#include "oox/core/filterbase.hxx"
+#include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertyset.hxx"
+#include "oox/xls/addressconverter.hxx"
+#include "oox/xls/autofilterbuffer.hxx"
+#include "oox/xls/commentsbuffer.hxx"
+#include "oox/xls/condformatbuffer.hxx"
+#include "oox/xls/drawingfragment.hxx"
+#include "oox/xls/formulaparser.hxx"
+#include "oox/xls/pagesettings.hxx"
+#include "oox/xls/querytablebuffer.hxx"
+#include "oox/xls/sharedformulabuffer.hxx"
+#include "oox/xls/sharedstringsbuffer.hxx"
+#include "oox/xls/stylesbuffer.hxx"
+#include "oox/xls/unitconverter.hxx"
+#include "oox/xls/viewsettings.hxx"
+#include "oox/xls/workbooksettings.hxx"
+#include "oox/xls/worksheetbuffer.hxx"
+#include "oox/xls/worksheetsettings.hxx"
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::table;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+// ============================================================================
+
+namespace {
+
+void lclUpdateProgressBar( const ISegmentProgressBarRef& rxProgressBar, const CellRangeAddress& rUsedArea, sal_Int32 nRow )
+{
+ if( rxProgressBar.get() && (rUsedArea.StartRow <= nRow) && (nRow <= rUsedArea.EndRow) )
+ {
+ double fPosition = static_cast< double >( nRow - rUsedArea.StartRow + 1 ) / (rUsedArea.EndRow - rUsedArea.StartRow + 1);
+ if( rxProgressBar->getPosition() < fPosition )
+ rxProgressBar->setPosition( fPosition );
+ }
+}
+
+void lclUpdateProgressBar( const ISegmentProgressBarRef& rxProgressBar, double fPosition )
+{
+ if( rxProgressBar.get() )
+ rxProgressBar->setPosition( fPosition );
+}
+
+// ----------------------------------------------------------------------------
+
+struct ValueRange
+{
+ sal_Int32 mnFirst;
+ sal_Int32 mnLast;
+
+ inline explicit ValueRange( sal_Int32 nValue ) : mnFirst( nValue ), mnLast( nValue ) {}
+ inline explicit ValueRange( sal_Int32 nFirst, sal_Int32 nLast ) : mnFirst( nFirst ), mnLast( nLast ) {}
+};
+
+typedef ::std::vector< ValueRange > ValueRangeVector;
+
+// ----------------------------------------------------------------------------
+
+struct ValueRangeComp
+{
+ inline bool operator()( const ValueRange& rRange, sal_Int32 nValue ) const { return rRange.mnLast < nValue; }
+};
+
+
+// ----------------------------------------------------------------------------
+
+class ValueRangeSet
+{
+public:
+ inline explicit ValueRangeSet() {}
+
+ void insert( sal_Int32 nValue );
+ void intersect( ValueRangeVector& orRanges, sal_Int32 nFirst, sal_Int32 nLast ) const;
+
+private:
+ ValueRangeVector maData;
+};
+
+void ValueRangeSet::insert( sal_Int32 nValue )
+{
+ // find the first range that contains nValue or that follows nValue
+ ValueRangeVector::iterator aBeg = maData.begin();
+ ValueRangeVector::iterator aEnd = maData.end();
+ ValueRangeVector::iterator aNext = ::std::lower_bound( aBeg, aEnd, nValue, ValueRangeComp() );
+
+ // nothing to do if found range contains nValue
+ if( (aNext == aEnd) || (nValue < aNext->mnFirst) )
+ {
+ ValueRangeVector::iterator aPrev = (aNext == aBeg) ? aEnd : (aNext - 1);
+ bool bJoinPrev = (aPrev != aEnd) && (aPrev->mnLast + 1 == nValue);
+ bool bJoinNext = (aNext != aEnd) && (aNext->mnFirst - 1 == nValue);
+ if( bJoinPrev && bJoinNext )
+ {
+ aPrev->mnLast = aNext->mnLast;
+ maData.erase( aNext );
+ }
+ else if( bJoinPrev )
+ ++aPrev->mnLast;
+ else if( bJoinNext )
+ --aNext->mnFirst;
+ else
+ maData.insert( aNext, ValueRange( nValue ) );
+ }
+}
+
+void ValueRangeSet::intersect( ValueRangeVector& orRanges, sal_Int32 nFirst, sal_Int32 nLast ) const
+{
+ orRanges.clear();
+ // find the range that contains nFirst or the first range that follows nFirst
+ ValueRangeVector::const_iterator aIt = ::std::lower_bound( maData.begin(), maData.end(), nFirst, ValueRangeComp() );
+ for( ValueRangeVector::const_iterator aEnd = maData.end(); (aIt != aEnd) && (aIt->mnFirst <= nLast); ++aIt )
+ orRanges.push_back( ValueRange( ::std::max( aIt->mnFirst, nFirst ), ::std::min( aIt->mnLast, nLast ) ) );
+}
+
+} // namespace
+
+// ============================================================================
+// ============================================================================
+
+void CellModel::reset()
+{
+ mxCell.clear();
+ maValueStr = maFormulaRef = OUString();
+ mnCellType = mnFormulaType = XML_TOKEN_INVALID;
+ mnSharedId = mnXfId = mnNumFmtId = -1;
+ mbHasValueStr = mbShowPhonetic = false;
+}
+
+// ----------------------------------------------------------------------------
+
+DataTableModel::DataTableModel() :
+ mb2dTable( false ),
+ mbRowTable( false ),
+ mbRef1Deleted( false ),
+ mbRef2Deleted( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ColumnModel::ColumnModel() :
+ mnFirstCol( -1 ),
+ mnLastCol( -1 ),
+ mfWidth( 0.0 ),
+ mnXfId( -1 ),
+ mnLevel( 0 ),
+ mbShowPhonetic( false ),
+ mbHidden( false ),
+ mbCollapsed( false )
+{
+}
+
+bool ColumnModel::tryExpand( const ColumnModel& rModel )
+{
+ bool bExpandable =
+ (mnFirstCol <= rModel.mnFirstCol) &&
+ (rModel.mnFirstCol <= mnLastCol + 1) &&
+ (mfWidth == rModel.mfWidth) &&
+ // ignore mnXfId, cell formatting is always set directly
+ (mnLevel == rModel.mnLevel) &&
+ (mbHidden == rModel.mbHidden) &&
+ (mbCollapsed == rModel.mbCollapsed);
+
+ if( bExpandable )
+ mnLastCol = rModel.mnLastCol;
+ return bExpandable;
+}
+
+// ----------------------------------------------------------------------------
+
+RowModel::RowModel() :
+ mnFirstRow( -1 ),
+ mnLastRow( -1 ),
+ mfHeight( 0.0 ),
+ mnXfId( -1 ),
+ mnLevel( 0 ),
+ mbCustomHeight( false ),
+ mbCustomFormat( false ),
+ mbShowPhonetic( false ),
+ mbHidden( false ),
+ mbCollapsed( false ),
+ mbThickTop( false ),
+ mbThickBottom( false )
+{
+}
+
+bool RowModel::tryExpand( const RowModel& rModel )
+{
+ bool bExpandable =
+ (mnFirstRow <= rModel.mnFirstRow) &&
+ (rModel.mnFirstRow <= mnLastRow + 1) &&
+ (mfHeight == rModel.mfHeight) &&
+ // ignore mnXfId, mbCustomFormat, mbShowPhonetic - cell formatting is always set directly
+ (mnLevel == rModel.mnLevel) &&
+ (mbCustomHeight == rModel.mbCustomHeight) &&
+ (mbHidden == rModel.mbHidden) &&
+ (mbCollapsed == rModel.mbCollapsed);
+
+ if( bExpandable )
+ mnLastRow = rModel.mnLastRow;
+ return bExpandable;
+}
+
+// ----------------------------------------------------------------------------
+
+PageBreakModel::PageBreakModel() :
+ mnColRow( 0 ),
+ mbManual( false )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+HyperlinkModel::HyperlinkModel()
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ValidationModel::ValidationModel() :
+ mnType( XML_none ),
+ mnOperator( XML_between ),
+ mnErrorStyle( XML_stop ),
+ mbShowInputMsg( false ),
+ mbShowErrorMsg( false ),
+ mbNoDropDown( false ),
+ mbAllowBlank( false )
+{
+}
+
+void ValidationModel::setBiffType( sal_uInt8 nType )
+{
+ static const sal_Int32 spnTypeIds[] = {
+ XML_none, XML_whole, XML_decimal, XML_list, XML_date, XML_time, XML_textLength, XML_custom };
+ mnType = STATIC_ARRAY_SELECT( spnTypeIds, nType, XML_none );
+}
+
+void ValidationModel::setBiffOperator( sal_uInt8 nOperator )
+{
+ static const sal_Int32 spnOperators[] = {
+ XML_between, XML_notBetween, XML_equal, XML_notEqual,
+ XML_greaterThan, XML_lessThan, XML_greaterThanOrEqual, XML_lessThanOrEqual };
+ mnOperator = STATIC_ARRAY_SELECT( spnOperators, nOperator, XML_TOKEN_INVALID );
+}
+
+void ValidationModel::setBiffErrorStyle( sal_uInt8 nErrorStyle )
+{
+ static const sal_Int32 spnErrorStyles[] = { XML_stop, XML_warning, XML_information };
+ mnErrorStyle = STATIC_ARRAY_SELECT( spnErrorStyles, nErrorStyle, XML_stop );
+}
+
+// ============================================================================
+// ============================================================================
+
+class WorksheetData : public WorkbookHelper
+{
+public:
+ explicit WorksheetData(
+ const WorkbookHelper& rHelper,
+ const ISegmentProgressBarRef& rxProgressBar,
+ WorksheetType eSheetType,
+ sal_Int16 nSheet );
+
+ /** Returns true, if this helper refers to an existing Calc sheet. */
+ inline bool isValidSheet() const { return mxSheet.is(); }
+
+ /** Returns a cell formula simulating the passed boolean value. */
+ const OUString& getBooleanFormula( bool bValue ) const;
+
+ /** Returns the type of this sheet. */
+ inline WorksheetType getSheetType() const { return meSheetType; }
+ /** Returns the index of the current sheet. */
+ inline sal_Int16 getSheetIndex() const { return maUsedArea.Sheet; }
+ /** Returns the XSpreadsheet interface of the current sheet. */
+ inline const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XSpreadsheet >&
+ getSheet() const { return mxSheet; }
+
+ /** Returns the XCell interface for the passed cell address. */
+ Reference< XCell > getCell( const CellAddress& rAddress ) const;
+ /** Returns the XCellRange interface for the passed cell range address. */
+ Reference< XCellRange > getCellRange( const CellRangeAddress& rRange ) const;
+ /** Returns the XSheetCellRanges interface for the passed cell range addresses. */
+ Reference< XSheetCellRanges > getCellRangeList( const ApiCellRangeList& rRanges ) const;
+
+ /** Returns the XCellRange interface for a column. */
+ Reference< XCellRange > getColumn( sal_Int32 nCol ) const;
+ /** Returns the XCellRange interface for a row. */
+ Reference< XCellRange > getRow( sal_Int32 nRow ) const;
+
+ /** Returns the XTableColumns interface for a range of columns. */
+ Reference< XTableColumns > getColumns( sal_Int32 nFirstCol, sal_Int32 nLastCol ) const;
+ /** Returns the XTableRows interface for a range of rows. */
+ Reference< XTableRows > getRows( sal_Int32 nFirstRow, sal_Int32 nLastRow ) const;
+
+ /** Returns the XDrawPage interface of the draw page of the current sheet. */
+ Reference< XDrawPage > getDrawPage() const;
+ /** Returns the size of the entire drawing page in 1/100 mm. */
+ Size getDrawPageSize() const;
+
+ /** Returns the absolute position of the top-left corner of the cell in 1/100 mm. */
+ Point getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const;
+ /** Returns the size of the cell in 1/100 mm. */
+ Size getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const;
+
+ /** Returns the address of the cell that contains the passed point in 1/100 mm. */
+ CellAddress getCellAddressFromPosition( const Point& rPosition, const Size& rDrawPageSize ) const;
+ /** Returns the cell range address that contains the passed rectangle in 1/100 mm. */
+ CellRangeAddress getCellRangeFromRectangle( const Rectangle& rRect ) const;
+
+ /** Returns the worksheet settings object. */
+ inline WorksheetSettings& getWorksheetSettings() { return maSheetSett; }
+ /** Returns the buffer containing all shared formulas in this sheet. */
+ inline SharedFormulaBuffer& getSharedFormulas() { return maSharedFmlas; }
+ /** Returns the conditional formattings in this sheet. */
+ inline CondFormatBuffer& getCondFormats() { return maCondFormats; }
+ /** Returns the buffer for all cell comments in this sheet. */
+ inline CommentsBuffer& getComments() { return maComments; }
+ /** Returns the auto filters for the sheet. */
+ inline AutoFilterBuffer& getAutoFilters() { return maAutoFilters; }
+ /** Returns the buffer for all web query tables in this sheet. */
+ inline QueryTableBuffer& getQueryTables() { return maQueryTables; }
+ /** Returns the page/print settings for this sheet. */
+ inline PageSettings& getPageSettings() { return maPageSett; }
+ /** Returns the view settings for this sheet. */
+ inline SheetViewSettings& getSheetViewSettings() { return maSheetViewSett; }
+ /** Returns the VML drawing page for this sheet (OOXML/BIFF12 only!). */
+ inline VmlDrawing& getVmlDrawing() { return *mxVmlDrawing; }
+
+ /** Changes the current sheet type. */
+ inline void setSheetType( WorksheetType eSheetType ) { meSheetType = eSheetType; }
+ /** Stores the cell format at the passed address. */
+ void setCellFormat( const CellModel& rModel );
+ /** Merges the cells in the passed cell range. */
+ void setMergedRange( const CellRangeAddress& rRange );
+ /** Sets a column or row page break described in the passed struct. */
+ void setPageBreak( const PageBreakModel& rModel, bool bRowBreak );
+ /** Inserts the hyperlink URL into the spreadsheet. */
+ void setHyperlink( const HyperlinkModel& rModel );
+ /** Inserts the data validation settings into the spreadsheet. */
+ void setValidation( const ValidationModel& rModel );
+ /** Sets the path to the DrawingML fragment of this sheet. */
+ void setDrawingPath( const OUString& rDrawingPath );
+ /** Sets the path to the legacy VML drawing fragment of this sheet. */
+ void setVmlDrawingPath( const OUString& rVmlDrawingPath );
+
+ /** Extends the used area of this sheet by the passed cell position. */
+ void extendUsedArea( const CellAddress& rAddress );
+ /** Extends the used area of this sheet by the passed cell range. */
+ void extendUsedArea( const CellRangeAddress& rRange );
+ /** Extends the shape bounding box by the position and size of the passed rectangle. */
+ void extendShapeBoundingBox( const Rectangle& rShapeRect );
+
+ /** Sets base width for all columns (without padding pixels). This value
+ is only used, if base width has not been set with setDefaultColumnWidth(). */
+ void setBaseColumnWidth( sal_Int32 nWidth );
+ /** Sets default width for all columns. This function overrides the base
+ width set with the setBaseColumnWidth() function. */
+ void setDefaultColumnWidth( double fWidth );
+ /** Sets column settings for a specific column range.
+ @descr Column default formatting is converted directly, other settings
+ are cached and converted in the finalizeImport() call. */
+ void setColumnModel( const ColumnModel& rModel );
+
+ /** Sets default height and hidden state for all unused rows in the sheet. */
+ void setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom );
+ /** Sets row settings for a specific row.
+ @descr Row default formatting is converted directly, other settings
+ are cached and converted in the finalizeImport() call. */
+ void setRowModel( const RowModel& rModel );
+
+ /** Converts column default cell formatting. */
+ void convertColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId ) const;
+ /** Converts row default cell formatting. */
+ void convertRowFormat( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId ) const;
+
+ /** Initial conversion before importing the worksheet. */
+ void initializeWorksheetImport();
+ /** Final conversion after importing the worksheet. */
+ void finalizeWorksheetImport();
+
+private:
+ typedef ::std::vector< sal_Int32 > OutlineLevelVec;
+ typedef ::std::map< sal_Int32, ColumnModel > ColumnModelMap;
+ typedef ::std::map< sal_Int32, RowModel > RowModelMap;
+ typedef ::std::list< HyperlinkModel > HyperlinkModelList;
+ typedef ::std::list< ValidationModel > ValidationModelList;
+
+ struct XfIdRowRange
+ {
+ sal_Int32 mnFirstRow; /// Index of first row.
+ sal_Int32 mnLastRow; /// Index of last row.
+ sal_Int32 mnXfId; /// XF identifier for the row range.
+
+ explicit XfIdRowRange();
+ bool intersects( const CellRangeAddress& rRange ) const;
+ void set( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId );
+ bool tryExpand( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId );
+ };
+
+ struct XfIdRange
+ {
+ CellRangeAddress maRange; /// The formatted cell range.
+ sal_Int32 mnXfId; /// XF identifier for the range.
+ sal_Int32 mnNumFmtId; /// Number format id overriding the XF.
+
+ void set( const CellModel& rModel );
+ bool tryExpand( const CellModel& rModel );
+ bool tryMerge( const XfIdRange& rXfIdRange );
+ };
+
+ struct MergedRange
+ {
+ CellRangeAddress maRange; /// The formatted cell range.
+ sal_Int32 mnHorAlign; /// Horizontal alignment in the range.
+
+ explicit MergedRange( const CellRangeAddress& rRange );
+ explicit MergedRange( const CellAddress& rAddress, sal_Int32 nHorAlign );
+ bool tryExpand( const CellAddress& rAddress, sal_Int32 nHorAlign );
+ };
+
+ typedef ::std::pair< sal_Int32, sal_Int32 > RowColKey;
+ typedef ::std::map< RowColKey, XfIdRange > XfIdRangeMap;
+ typedef ::std::list< MergedRange > MergedRangeList;
+
+ /** 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();
+ /** Finalizes the remaining ranges in maXfIdRanges. */
+ void finalizeXfIdRanges();
+
+ /** Inserts all imported hyperlinks into their cell ranges. */
+ void finalizeHyperlinkRanges() const;
+ /** Generates the final URL for the passed hyperlink. */
+ OUString getHyperlinkUrl( const HyperlinkModel& rHyperlink ) const;
+ /** Inserts a hyperlinks into the specified cell. */
+ void insertHyperlink( const CellAddress& rAddress, const OUString& rUrl ) const;
+
+ /** Inserts all imported data validations into their cell ranges. */
+ void finalizeValidationRanges() const;
+
+ /** Merges all cached merged ranges and updates right/bottom cell borders. */
+ void finalizeMergedRanges();
+ /** Merges the passed merged range and updates right/bottom cell borders. */
+ void finalizeMergedRange( const CellRangeAddress& rRange );
+
+ /** Converts column properties for all columns in the sheet. */
+ void convertColumns();
+ /** Converts column properties. */
+ void convertColumns( OutlineLevelVec& orColLevels, sal_Int32 nFirstCol, sal_Int32 nLastCol, const ColumnModel& rModel );
+
+ /** Converts row properties for all rows in the sheet. */
+ void convertRows();
+ /** Converts row properties. */
+ void convertRows( OutlineLevelVec& orRowLevels, sal_Int32 nFirstRow, sal_Int32 nLastRow, const RowModel& rModel, double fDefHeight = -1.0 );
+
+ /** Converts outline grouping for the passed column or row. */
+ void convertOutlines( OutlineLevelVec& orLevels, sal_Int32 nColRow, sal_Int32 nLevel, bool bCollapsed, bool bRows );
+ /** Groups columns or rows for the given range. */
+ void groupColumnsOrRows( sal_Int32 nFirstColRow, sal_Int32 nLastColRow, bool bCollapsed, bool bRows );
+
+ /** Imports the drawings of the sheet (DML, VML), and updates the used area. */
+ void finalizeDrawings();
+
+private:
+ typedef ::std::auto_ptr< VmlDrawing > VmlDrawingPtr;
+
+ const OUString maTrueFormula; /// Replacement formula for TRUE boolean cells.
+ const OUString maFalseFormula; /// Replacement formula for FALSE boolean cells.
+ const OUString maSheetCellRanges; /// Service name for a SheetCellRanges object.
+ const OUString maUrlTextField; /// Service name for a URL text field.
+ const CellAddress& mrMaxApiPos; /// Reference to maximum Calc cell address from address converter.
+ CellRangeAddress maUsedArea; /// Used area of the sheet, and sheet index of the sheet.
+ ColumnModel maDefColModel; /// Default column formatting.
+ ColumnModelMap maColModels; /// Columns sorted by first column index.
+ RowModel maDefRowModel; /// Default row formatting.
+ RowModelMap maRowModels; /// Rows sorted by row index.
+ HyperlinkModelList maHyperlinks; /// Cell ranges containing hyperlinks.
+ ValidationModelList maValidations; /// Cell ranges containing data validation settings.
+ XfIdRowRange maXfIdRowRange; /// Cached XF identifier for a range of rows.
+ XfIdRangeMap maXfIdRanges; /// Collected XF identifiers for cell ranges.
+ MergedRangeList maMergedRanges; /// Merged cell ranges.
+ MergedRangeList maCenterFillRanges; /// Merged cell ranges from 'center across' or 'fill' alignment.
+ ValueRangeSet maManualRowHeights; /// Rows that need manual height independent from own settings.
+ WorksheetSettings maSheetSett; /// Global settings for this sheet.
+ SharedFormulaBuffer maSharedFmlas; /// Buffer for shared formulas in this sheet.
+ CondFormatBuffer maCondFormats; /// Buffer for conditional formattings.
+ CommentsBuffer maComments; /// Buffer for all cell comments in this sheet.
+ AutoFilterBuffer maAutoFilters; /// Sheet auto filters (not associated to a table).
+ QueryTableBuffer maQueryTables; /// Buffer for all web query tables in this sheet.
+ PageSettings maPageSett; /// Page/print settings for this sheet.
+ SheetViewSettings maSheetViewSett; /// View settings for this sheet.
+ VmlDrawingPtr mxVmlDrawing; /// Collection of all VML shapes.
+ OUString maDrawingPath; /// Path to DrawingML fragment.
+ OUString maVmlDrawingPath; /// Path to legacy VML drawing fragment.
+ Rectangle maShapeBoundingBox; /// Bounding box for all shapes from all drawings.
+ ISegmentProgressBarRef mxProgressBar; /// Sheet progress bar.
+ ISegmentProgressBarRef mxRowProgress; /// Progress bar for row/cell processing.
+ ISegmentProgressBarRef mxFinalProgress; /// Progress bar for finalization.
+ WorksheetType meSheetType; /// Type of this sheet.
+ Reference< XSpreadsheet > mxSheet; /// Reference to the current sheet.
+ bool mbHasDefWidth; /// True = default column width is set from defaultColWidth attribute.
+};
+
+// ----------------------------------------------------------------------------
+
+WorksheetData::WorksheetData( const WorkbookHelper& rHelper, const ISegmentProgressBarRef& rxProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) :
+ WorkbookHelper( rHelper ),
+ maTrueFormula( CREATE_OUSTRING( "=TRUE()" ) ),
+ maFalseFormula( CREATE_OUSTRING( "=FALSE()" ) ),
+ maSheetCellRanges( CREATE_OUSTRING( "com.sun.star.sheet.SheetCellRanges" ) ),
+ maUrlTextField( CREATE_OUSTRING( "com.sun.star.text.TextField.URL" ) ),
+ mrMaxApiPos( rHelper.getAddressConverter().getMaxApiAddress() ),
+ maUsedArea( nSheet, SAL_MAX_INT32, SAL_MAX_INT32, -1, -1 ),
+ maSheetSett( *this ),
+ maSharedFmlas( *this ),
+ maCondFormats( *this ),
+ maComments( *this ),
+ maAutoFilters( *this ),
+ maQueryTables( *this ),
+ maPageSett( *this ),
+ maSheetViewSett( *this ),
+ mxProgressBar( rxProgressBar ),
+ meSheetType( eSheetType ),
+ mbHasDefWidth( false )
+{
+ mxSheet = getSheetFromDoc( nSheet );
+ if( !mxSheet.is() )
+ maUsedArea.Sheet = -1;
+
+ // default column settings (width and hidden state may be updated later)
+ maDefColModel.mfWidth = 8.5;
+ maDefColModel.mnXfId = -1;
+ maDefColModel.mnLevel = 0;
+ maDefColModel.mbHidden = false;
+ maDefColModel.mbCollapsed = false;
+
+ // default row settings (height and hidden state may be updated later)
+ maDefRowModel.mfHeight = 0.0;
+ maDefRowModel.mnXfId = -1;
+ maDefRowModel.mnLevel = 0;
+ maDefRowModel.mbCustomHeight = false;
+ maDefRowModel.mbCustomFormat = false;
+ maDefRowModel.mbShowPhonetic = false;
+ maDefRowModel.mbHidden = false;
+ maDefRowModel.mbCollapsed = false;
+
+ // buffers
+ if( getFilterType() == FILTER_OOXML )
+ mxVmlDrawing.reset( new VmlDrawing( *this ) );
+
+ // prepare progress bars
+ if( mxProgressBar.get() )
+ {
+ mxRowProgress = mxProgressBar->createSegment( 0.5 );
+ mxFinalProgress = mxProgressBar->createSegment( 0.5 );
+ }
+}
+
+const OUString& WorksheetData::getBooleanFormula( bool bValue ) const
+{
+ return bValue ? maTrueFormula : maFalseFormula;
+}
+
+Reference< XCell > WorksheetData::getCell( const CellAddress& rAddress ) const
+{
+ Reference< XCell > xCell;
+ if( mxSheet.is() ) try
+ {
+ xCell = mxSheet->getCellByPosition( rAddress.Column, rAddress.Row );
+ }
+ catch( Exception& )
+ {
+ }
+ return xCell;
+}
+
+Reference< XCellRange > WorksheetData::getCellRange( const CellRangeAddress& rRange ) const
+{
+ Reference< XCellRange > xRange;
+ if( mxSheet.is() ) try
+ {
+ xRange = mxSheet->getCellRangeByPosition( rRange.StartColumn, rRange.StartRow, rRange.EndColumn, rRange.EndRow );
+ }
+ catch( Exception& )
+ {
+ }
+ return xRange;
+}
+
+Reference< XSheetCellRanges > WorksheetData::getCellRangeList( const ApiCellRangeList& rRanges ) const
+{
+ Reference< XSheetCellRanges > xRanges;
+ if( mxSheet.is() && !rRanges.empty() ) try
+ {
+ xRanges.set( getDocumentFactory()->createInstance( maSheetCellRanges ), UNO_QUERY_THROW );
+ Reference< XSheetCellRangeContainer > xRangeCont( xRanges, UNO_QUERY_THROW );
+ xRangeCont->addRangeAddresses( ContainerHelper::vectorToSequence( rRanges ), sal_False );
+ }
+ catch( Exception& )
+ {
+ }
+ return xRanges;
+}
+
+Reference< XCellRange > WorksheetData::getColumn( sal_Int32 nCol ) const
+{
+ Reference< XCellRange > xColumn;
+ try
+ {
+ Reference< XColumnRowRange > xColRowRange( mxSheet, UNO_QUERY_THROW );
+ Reference< XTableColumns > xColumns( xColRowRange->getColumns(), UNO_SET_THROW );
+ xColumn.set( xColumns->getByIndex( nCol ), UNO_QUERY );
+ }
+ catch( Exception& )
+ {
+ }
+ return xColumn;
+}
+
+Reference< XCellRange > WorksheetData::getRow( sal_Int32 nRow ) const
+{
+ Reference< XCellRange > xRow;
+ try
+ {
+ Reference< XColumnRowRange > xColRowRange( mxSheet, UNO_QUERY_THROW );
+ Reference< XTableRows > xRows( xColRowRange->getRows(), UNO_SET_THROW );
+ xRow.set( xRows->getByIndex( nRow ), UNO_QUERY );
+ }
+ catch( Exception& )
+ {
+ }
+ return xRow;
+}
+
+Reference< XTableColumns > WorksheetData::getColumns( sal_Int32 nFirstCol, sal_Int32 nLastCol ) const
+{
+ Reference< XTableColumns > xColumns;
+ nLastCol = ::std::min( nLastCol, mrMaxApiPos.Column );
+ if( (0 <= nFirstCol) && (nFirstCol <= nLastCol) )
+ {
+ Reference< XColumnRowRange > xRange( getCellRange( CellRangeAddress( getSheetIndex(), nFirstCol, 0, nLastCol, 0 ) ), UNO_QUERY );
+ if( xRange.is() )
+ xColumns = xRange->getColumns();
+ }
+ return xColumns;
+}
+
+Reference< XTableRows > WorksheetData::getRows( sal_Int32 nFirstRow, sal_Int32 nLastRow ) const
+{
+ Reference< XTableRows > xRows;
+ nLastRow = ::std::min( nLastRow, mrMaxApiPos.Row );
+ if( (0 <= nFirstRow) && (nFirstRow <= nLastRow) )
+ {
+ Reference< XColumnRowRange > xRange( getCellRange( CellRangeAddress( getSheetIndex(), 0, nFirstRow, 0, nLastRow ) ), UNO_QUERY );
+ if( xRange.is() )
+ xRows = xRange->getRows();
+ }
+ return xRows;
+}
+
+Reference< XDrawPage > WorksheetData::getDrawPage() const
+{
+ Reference< XDrawPage > xDrawPage;
+ try
+ {
+ xDrawPage = Reference< XDrawPageSupplier >( mxSheet, UNO_QUERY_THROW )->getDrawPage();
+ }
+ catch( Exception& )
+ {
+ }
+ return xDrawPage;
+}
+
+Size WorksheetData::getDrawPageSize() const
+{
+ Size aSize;
+ PropertySet aRangeProp( getCellRange( CellRangeAddress( getSheetIndex(), 0, 0, mrMaxApiPos.Column, mrMaxApiPos.Row ) ) );
+ aRangeProp.getProperty( aSize, PROP_Size );
+ return aSize;
+}
+
+Point WorksheetData::getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ Point aPoint;
+ PropertySet aCellProp( getCell( CellAddress( getSheetIndex(), nCol, nRow ) ) );
+ aCellProp.getProperty( aPoint, PROP_Position );
+ return aPoint;
+}
+
+Size WorksheetData::getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ Size aSize;
+ PropertySet aCellProp( getCell( CellAddress( getSheetIndex(), nCol, nRow ) ) );
+ aCellProp.getProperty( aSize, PROP_Size );
+ return aSize;
+}
+
+namespace {
+
+inline sal_Int32 lclGetMidAddr( sal_Int32 nBegAddr, sal_Int32 nEndAddr, sal_Int32 nBegPos, sal_Int32 nEndPos, sal_Int32 nSearchPos )
+{
+ // use sal_Int64 to prevent integer overflow
+ return nBegAddr + 1 + static_cast< sal_Int32 >( static_cast< sal_Int64 >( nEndAddr - nBegAddr - 2 ) * (nSearchPos - nBegPos) / (nEndPos - nBegPos) );
+}
+
+bool lclPrepareInterval( sal_Int32 nBegAddr, sal_Int32& rnMidAddr, sal_Int32 nEndAddr,
+ sal_Int32 nBegPos, sal_Int32 nEndPos, sal_Int32 nSearchPos )
+{
+ // searched position before nBegPos -> use nBegAddr
+ if( nSearchPos <= nBegPos )
+ {
+ rnMidAddr = nBegAddr;
+ return false;
+ }
+
+ // searched position after nEndPos, or begin next to end -> use nEndAddr
+ if( (nSearchPos >= nEndPos) || (nBegAddr + 1 >= nEndAddr) )
+ {
+ rnMidAddr = nEndAddr;
+ return false;
+ }
+
+ /* Otherwise find mid address according to position. lclGetMidAddr() will
+ return an address between nBegAddr and nEndAddr. */
+ rnMidAddr = lclGetMidAddr( nBegAddr, nEndAddr, nBegPos, nEndPos, nSearchPos );
+ return true;
+}
+
+bool lclUpdateInterval( sal_Int32& rnBegAddr, sal_Int32& rnMidAddr, sal_Int32& rnEndAddr,
+ sal_Int32& rnBegPos, sal_Int32 nMidPos, sal_Int32& rnEndPos, sal_Int32 nSearchPos )
+{
+ // nSearchPos < nMidPos: use the interval [begin,mid] in the next iteration
+ if( nSearchPos < nMidPos )
+ {
+ // if rnBegAddr is next to rnMidAddr, the latter is the column/row in question
+ if( rnBegAddr + 1 >= rnMidAddr )
+ return false;
+ // otherwise, set interval end to mid
+ rnEndPos = nMidPos;
+ rnEndAddr = rnMidAddr;
+ rnMidAddr = lclGetMidAddr( rnBegAddr, rnEndAddr, rnBegPos, rnEndPos, nSearchPos );
+ return true;
+ }
+
+ // nSearchPos > nMidPos: use the interval [mid,end] in the next iteration
+ if( nSearchPos > nMidPos )
+ {
+ // if rnMidAddr is next to rnEndAddr, the latter is the column/row in question
+ if( rnMidAddr + 1 >= rnEndAddr )
+ {
+ rnMidAddr = rnEndAddr;
+ return false;
+ }
+ // otherwise, set interval start to mid
+ rnBegPos = nMidPos;
+ rnBegAddr = rnMidAddr;
+ rnMidAddr = lclGetMidAddr( rnBegAddr, rnEndAddr, rnBegPos, rnEndPos, nSearchPos );
+ return true;
+ }
+
+ // nSearchPos == nMidPos: rnMidAddr is the column/row in question, do not loop anymore
+ return false;
+}
+
+} // namespace
+
+CellAddress WorksheetData::getCellAddressFromPosition( const Point& rPosition, const Size& rDrawPageSize ) const
+{
+ // starting cell address and its position in drawing layer (top-left edge)
+ sal_Int32 nBegCol = 0;
+ sal_Int32 nBegRow = 0;
+ Point aBegPos( 0, 0 );
+
+ // end cell address and its position in drawing layer (bottom-right edge)
+ sal_Int32 nEndCol = mrMaxApiPos.Column + 1;
+ sal_Int32 nEndRow = mrMaxApiPos.Row + 1;
+ Point aEndPos( rDrawPageSize.Width, rDrawPageSize.Height );
+
+ // starting point for interval search
+ sal_Int32 nMidCol, nMidRow;
+ bool bLoopCols = lclPrepareInterval( nBegCol, nMidCol, nEndCol, aBegPos.X, aEndPos.X, rPosition.X );
+ bool bLoopRows = lclPrepareInterval( nBegRow, nMidRow, nEndRow, aBegPos.Y, aEndPos.Y, rPosition.Y );
+ Point aMidPos = getCellPosition( nMidCol, nMidRow );
+
+ /* The loop will find the column/row index of the cell right of/below
+ the cell containing the passed point, unless the point is located at
+ the top or left border of the containing cell. */
+ while( bLoopCols || bLoopRows )
+ {
+ bLoopCols = bLoopCols && lclUpdateInterval( nBegCol, nMidCol, nEndCol, aBegPos.X, aMidPos.X, aEndPos.X, rPosition.X );
+ bLoopRows = bLoopRows && lclUpdateInterval( nBegRow, nMidRow, nEndRow, aBegPos.Y, aMidPos.Y, aEndPos.Y, rPosition.Y );
+ aMidPos = getCellPosition( nMidCol, nMidRow );
+ }
+
+ /* The cell left of/above the current search position contains the passed
+ point, unless the point is located on the top/left border of the cell,
+ or the last column/row of the sheet has been reached. */
+ if( aMidPos.X > rPosition.X ) --nMidCol;
+ if( aMidPos.Y > rPosition.Y ) --nMidRow;
+ return CellAddress( getSheetIndex(), nMidCol, nMidRow );
+}
+
+CellRangeAddress WorksheetData::getCellRangeFromRectangle( const Rectangle& rRect ) const
+{
+ Size aPageSize = getDrawPageSize();
+ CellAddress aStartAddr = getCellAddressFromPosition( Point( rRect.X, rRect.Y ), aPageSize );
+ Point aBotRight( rRect.X + rRect.Width, rRect.Y + rRect.Height );
+ CellAddress aEndAddr = getCellAddressFromPosition( aBotRight, aPageSize );
+ bool bMultiCols = aStartAddr.Column < aEndAddr.Column;
+ bool bMultiRows = aStartAddr.Row < aEndAddr.Row;
+ if( bMultiCols || bMultiRows )
+ {
+ /* Reduce end position of the cell range to previous column or row, if
+ the rectangle ends exactly between two columns or rows. */
+ Point aEndPos = getCellPosition( aEndAddr.Column, aEndAddr.Row );
+ if( bMultiCols && (aBotRight.X <= aEndPos.X) )
+ --aEndAddr.Column;
+ if( bMultiRows && (aBotRight.Y <= aEndPos.Y) )
+ --aEndAddr.Row;
+ }
+ return CellRangeAddress( getSheetIndex(), aStartAddr.Column, aStartAddr.Row, aEndAddr.Column, aEndAddr.Row );
+}
+
+void WorksheetData::setCellFormat( const CellModel& rModel )
+{
+ if( rModel.mxCell.is() && ((rModel.mnXfId >= 0) || (rModel.mnNumFmtId >= 0)) )
+ {
+ // try to merge existing ranges and to write some formatting properties
+ if( !maXfIdRanges.empty() )
+ {
+ // 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.maAddress.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++ );
+ }
+ else
+ ++aIt;
+ }
+ }
+ }
+
+ // try to expand last existing range, or create new range entry
+ if( maXfIdRanges.empty() || !maXfIdRanges.rbegin()->second.tryExpand( rModel ) )
+ maXfIdRanges[ RowColKey( rModel.maAddress.Row, rModel.maAddress.Column ) ].set( rModel );
+
+ // update merged ranges for 'center across selection' and 'fill'
+ if( const Xf* pXf = getStyles().getCellXf( rModel.mnXfId ).get() )
+ {
+ sal_Int32 nHorAlign = pXf->getAlignment().getModel().mnHorAlign;
+ if( (nHorAlign == XML_centerContinuous) || (nHorAlign == XML_fill) )
+ {
+ /* start new merged range, if cell is not empty (#108781#),
+ or try to expand last range with empty cell */
+ if( rModel.mnCellType != XML_TOKEN_INVALID )
+ maCenterFillRanges.push_back( MergedRange( rModel.maAddress, nHorAlign ) );
+ else if( !maCenterFillRanges.empty() )
+ maCenterFillRanges.rbegin()->tryExpand( rModel.maAddress, nHorAlign );
+ }
+ }
+ }
+}
+
+void WorksheetData::setMergedRange( const CellRangeAddress& rRange )
+{
+ maMergedRanges.push_back( MergedRange( rRange ) );
+}
+
+void WorksheetData::setPageBreak( const PageBreakModel& rModel, bool bRowBreak )
+{
+ if( rModel.mbManual && (rModel.mnColRow > 0) )
+ {
+ PropertySet aPropSet( bRowBreak ? getRow( rModel.mnColRow ) : getColumn( rModel.mnColRow ) );
+ aPropSet.setProperty( PROP_IsStartOfNewPage, true );
+ }
+}
+
+void WorksheetData::setHyperlink( const HyperlinkModel& rModel )
+{
+ maHyperlinks.push_back( rModel );
+}
+
+void WorksheetData::setValidation( const ValidationModel& rModel )
+{
+ maValidations.push_back( rModel );
+}
+
+void WorksheetData::setDrawingPath( const OUString& rDrawingPath )
+{
+ maDrawingPath = rDrawingPath;
+}
+
+void WorksheetData::setVmlDrawingPath( const OUString& rVmlDrawingPath )
+{
+ maVmlDrawingPath = rVmlDrawingPath;
+}
+
+void WorksheetData::extendUsedArea( const CellAddress& rAddress )
+{
+ maUsedArea.StartColumn = ::std::min( maUsedArea.StartColumn, rAddress.Column );
+ maUsedArea.StartRow = ::std::min( maUsedArea.StartRow, rAddress.Row );
+ maUsedArea.EndColumn = ::std::max( maUsedArea.EndColumn, rAddress.Column );
+ maUsedArea.EndRow = ::std::max( maUsedArea.EndRow, rAddress.Row );
+}
+
+void WorksheetData::extendUsedArea( const CellRangeAddress& rRange )
+{
+ extendUsedArea( CellAddress( rRange.Sheet, rRange.StartColumn, rRange.StartRow ) );
+ extendUsedArea( CellAddress( rRange.Sheet, rRange.EndColumn, rRange.EndRow ) );
+}
+
+void WorksheetData::extendShapeBoundingBox( const Rectangle& rShapeRect )
+{
+ if( (maShapeBoundingBox.Width == 0) && (maShapeBoundingBox.Height == 0) )
+ {
+ // width and height of maShapeBoundingBox are assumed to be zero on first cell
+ maShapeBoundingBox = rShapeRect;
+ }
+ else
+ {
+ sal_Int32 nEndX = ::std::max( maShapeBoundingBox.X + maShapeBoundingBox.Width, rShapeRect.X + rShapeRect.Width );
+ sal_Int32 nEndY = ::std::max( maShapeBoundingBox.Y + maShapeBoundingBox.Height, rShapeRect.Y + rShapeRect.Height );
+ maShapeBoundingBox.X = ::std::min( maShapeBoundingBox.X, rShapeRect.X );
+ maShapeBoundingBox.Y = ::std::min( maShapeBoundingBox.Y, rShapeRect.Y );
+ maShapeBoundingBox.Width = nEndX - maShapeBoundingBox.X;
+ maShapeBoundingBox.Height = nEndY - maShapeBoundingBox.Y;
+ }
+}
+
+void WorksheetData::setBaseColumnWidth( sal_Int32 nWidth )
+{
+ // do not modify width, if setDefaultColumnWidth() has been used
+ if( !mbHasDefWidth && (nWidth > 0) )
+ {
+ // #i3006# add 5 pixels padding to the width
+ const UnitConverter& rUnitConv = getUnitConverter();
+ maDefColModel.mfWidth = rUnitConv.scaleFromMm100(
+ rUnitConv.scaleToMm100( nWidth, UNIT_DIGIT ) + rUnitConv.scaleToMm100( 5, UNIT_SCREENX ), UNIT_DIGIT );
+ }
+}
+
+void WorksheetData::setDefaultColumnWidth( double fWidth )
+{
+ // overrides a width set with setBaseColumnWidth()
+ if( fWidth > 0.0 )
+ {
+ maDefColModel.mfWidth = fWidth;
+ mbHasDefWidth = true;
+ }
+}
+
+void WorksheetData::setColumnModel( const ColumnModel& rModel )
+{
+ // convert 1-based OOXML column indexes to 0-based API column indexes
+ sal_Int32 nFirstCol = rModel.mnFirstCol - 1;
+ sal_Int32 nLastCol = rModel.mnLastCol - 1;
+ if( (0 <= nFirstCol) && (nFirstCol <= mrMaxApiPos.Column) )
+ {
+ // set column formatting directly, nLastCol is checked inside the function
+ convertColumnFormat( nFirstCol, nLastCol, rModel.mnXfId );
+ // expand last entry or add new entry
+ if( maColModels.empty() || !maColModels.rbegin()->second.tryExpand( rModel ) )
+ maColModels[ nFirstCol ] = rModel;
+ }
+}
+
+void WorksheetData::setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom )
+{
+ maDefRowModel.mfHeight = fHeight;
+ maDefRowModel.mbCustomHeight = bCustomHeight;
+ maDefRowModel.mbHidden = bHidden;
+ maDefRowModel.mbThickTop = bThickTop;
+ maDefRowModel.mbThickBottom = bThickBottom;
+}
+
+void WorksheetData::setRowModel( const RowModel& rModel )
+{
+ // convert 1-based OOXML row indexes to 0-based API row indexes
+ sal_Int32 nFirstRow = rModel.mnFirstRow - 1;
+ sal_Int32 nLastRow = rModel.mnLastRow - 1;
+ if( (0 <= nFirstRow) && (nFirstRow <= mrMaxApiPos.Row) )
+ {
+ // set row formatting
+ if( rModel.mbCustomFormat )
+ {
+ // try to expand cached row range, if formatting is equal
+ if( (maXfIdRowRange.mnLastRow < 0) || !maXfIdRowRange.tryExpand( nFirstRow, nLastRow, rModel.mnXfId ) )
+ {
+ writeXfIdRowRangeProperties( maXfIdRowRange );
+ maXfIdRowRange.set( nFirstRow, nLastRow, rModel.mnXfId );
+ }
+ }
+ else if( maXfIdRowRange.mnLastRow >= 0 )
+ {
+ // finish last cached row range
+ writeXfIdRowRangeProperties( maXfIdRowRange );
+ maXfIdRowRange.set( -1, -1, -1 );
+ }
+
+ // expand last entry or add new entry
+ if( maRowModels.empty() || !maRowModels.rbegin()->second.tryExpand( rModel ) )
+ maRowModels[ nFirstRow ] = rModel;
+ }
+ lclUpdateProgressBar( mxRowProgress, maUsedArea, nLastRow );
+}
+
+void WorksheetData::convertColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId ) const
+{
+ CellRangeAddress aRange( getSheetIndex(), nFirstCol, 0, nLastCol, mrMaxApiPos.Row );
+ if( getAddressConverter().validateCellRange( aRange, true, false ) )
+ {
+ PropertySet aPropSet( getCellRange( aRange ) );
+ getStyles().writeCellXfToPropertySet( aPropSet, nXfId );
+ }
+}
+
+void WorksheetData::convertRowFormat( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId ) const
+{
+ CellRangeAddress aRange( getSheetIndex(), 0, nFirstRow, mrMaxApiPos.Column, nLastRow );
+ if( getAddressConverter().validateCellRange( aRange, true, false ) )
+ {
+ PropertySet aPropSet( getCellRange( aRange ) );
+ getStyles().writeCellXfToPropertySet( aPropSet, nXfId );
+ }
+}
+
+void WorksheetData::initializeWorksheetImport()
+{
+ // set default cell style for unused cells
+ PropertySet aPropSet( mxSheet );
+ aPropSet.setProperty( PROP_CellStyle, getStyles().getDefaultStyleName() );
+
+ /* Remember current sheet index in global data, needed by some global
+ objects, e.g. the chart converter. */
+ setCurrentSheetIndex( getSheetIndex() );
+}
+
+void WorksheetData::finalizeWorksheetImport()
+{
+ lclUpdateProgressBar( mxRowProgress, 1.0 );
+ finalizeXfIdRanges();
+ lclUpdateProgressBar( mxFinalProgress, 0.25 );
+ finalizeHyperlinkRanges();
+ finalizeValidationRanges();
+ finalizeMergedRanges();
+ maAutoFilters.finalizeImport( getSheetIndex() );
+ maSheetSett.finalizeImport();
+ maCondFormats.finalizeImport();
+ maQueryTables.finalizeImport();
+ maPageSett.finalizeImport();
+ maSheetViewSett.finalizeImport();
+ maSheetSett.finalizeImport();
+
+ lclUpdateProgressBar( mxFinalProgress, 0.5 );
+ convertColumns();
+ convertRows();
+ lclUpdateProgressBar( mxFinalProgress, 0.75 );
+ finalizeDrawings();
+ lclUpdateProgressBar( mxFinalProgress, 1.0 );
+
+ // reset current sheet index in global data
+ setCurrentSheetIndex( -1 );
+}
+
+// private --------------------------------------------------------------------
+
+WorksheetData::XfIdRowRange::XfIdRowRange() :
+ mnFirstRow( -1 ),
+ mnLastRow( -1 ),
+ mnXfId( -1 )
+{
+}
+
+bool WorksheetData::XfIdRowRange::intersects( const CellRangeAddress& rRange ) const
+{
+ return (rRange.StartRow <= mnLastRow) && (mnFirstRow <= rRange.EndRow);
+}
+
+void WorksheetData::XfIdRowRange::set( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId )
+{
+ mnFirstRow = nFirstRow;
+ mnLastRow = nLastRow;
+ mnXfId = nXfId;
+}
+
+bool WorksheetData::XfIdRowRange::tryExpand( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId )
+{
+ if( mnXfId == nXfId )
+ {
+ if( mnLastRow + 1 == nFirstRow )
+ {
+ mnLastRow = nLastRow;
+ return true;
+ }
+ if( mnFirstRow == nLastRow + 1 )
+ {
+ mnFirstRow = nFirstRow;
+ return true;
+ }
+ }
+ return false;
+}
+
+void WorksheetData::XfIdRange::set( const CellModel& rModel )
+{
+ maRange.Sheet = rModel.maAddress.Sheet;
+ maRange.StartColumn = maRange.EndColumn = rModel.maAddress.Column;
+ maRange.StartRow = maRange.EndRow = rModel.maAddress.Row;
+ mnXfId = rModel.mnXfId;
+ mnNumFmtId = rModel.mnNumFmtId;
+}
+
+bool WorksheetData::XfIdRange::tryExpand( const CellModel& rModel )
+{
+ if( (mnXfId == rModel.mnXfId) && (mnNumFmtId == rModel.mnNumFmtId) &&
+ (maRange.StartRow == rModel.maAddress.Row) &&
+ (maRange.EndRow == rModel.maAddress.Row) &&
+ (maRange.EndColumn + 1 == rModel.maAddress.Column) )
+ {
+ ++maRange.EndColumn;
+ return true;
+ }
+ return false;
+}
+
+bool WorksheetData::XfIdRange::tryMerge( const XfIdRange& rXfIdRange )
+{
+ if( (mnXfId == rXfIdRange.mnXfId) &&
+ (mnNumFmtId == rXfIdRange.mnNumFmtId) &&
+ (maRange.EndRow + 1 == rXfIdRange.maRange.StartRow) &&
+ (maRange.StartColumn == rXfIdRange.maRange.StartColumn) &&
+ (maRange.EndColumn == rXfIdRange.maRange.EndColumn) )
+ {
+ maRange.EndRow = rXfIdRange.maRange.EndRow;
+ return true;
+ }
+ return false;
+}
+
+
+WorksheetData::MergedRange::MergedRange( const CellRangeAddress& rRange ) :
+ maRange( rRange ),
+ mnHorAlign( XML_TOKEN_INVALID )
+{
+}
+
+WorksheetData::MergedRange::MergedRange( const CellAddress& rAddress, sal_Int32 nHorAlign ) :
+ maRange( rAddress.Sheet, rAddress.Column, rAddress.Row, rAddress.Column, rAddress.Row ),
+ mnHorAlign( nHorAlign )
+{
+}
+
+bool WorksheetData::MergedRange::tryExpand( const CellAddress& rAddress, sal_Int32 nHorAlign )
+{
+ if( (mnHorAlign == nHorAlign) && (maRange.StartRow == rAddress.Row) &&
+ (maRange.EndRow == rAddress.Row) && (maRange.EndColumn + 1 == rAddress.Column) )
+ {
+ ++maRange.EndColumn;
+ return true;
+ }
+ return false;
+}
+
+void WorksheetData::writeXfIdRowRangeProperties( const XfIdRowRange& rXfIdRowRange ) const
+{
+ if( (rXfIdRowRange.mnLastRow >= 0) && (rXfIdRowRange.mnXfId >= 0) )
+ convertRowFormat( rXfIdRowRange.mnFirstRow, rXfIdRowRange.mnLastRow, rXfIdRowRange.mnXfId );
+}
+
+void WorksheetData::writeXfIdRangeProperties( const XfIdRange& rXfIdRange ) 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 ) );
+ aPropSet.setProperties( aPropMap );
+}
+
+void WorksheetData::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 WorksheetData::finalizeXfIdRanges()
+{
+ // 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 );
+}
+
+void WorksheetData::finalizeHyperlinkRanges() const
+{
+ for( HyperlinkModelList::const_iterator aIt = maHyperlinks.begin(), aEnd = maHyperlinks.end(); aIt != aEnd; ++aIt )
+ {
+ OUString aUrl = getHyperlinkUrl( *aIt );
+ // try to insert URL into each cell of the range
+ if( aUrl.getLength() > 0 )
+ for( CellAddress aAddress( getSheetIndex(), aIt->maRange.StartColumn, aIt->maRange.StartRow ); aAddress.Row <= aIt->maRange.EndRow; ++aAddress.Row )
+ for( aAddress.Column = aIt->maRange.StartColumn; aAddress.Column <= aIt->maRange.EndColumn; ++aAddress.Column )
+ insertHyperlink( aAddress, aUrl );
+ }
+}
+
+OUString WorksheetData::getHyperlinkUrl( const HyperlinkModel& rHyperlink ) const
+{
+ OUStringBuffer aUrlBuffer;
+ if( rHyperlink.maTarget.getLength() > 0 )
+ aUrlBuffer.append( getBaseFilter().getAbsoluteUrl( rHyperlink.maTarget ) );
+ if( rHyperlink.maLocation.getLength() > 0 )
+ aUrlBuffer.append( sal_Unicode( '#' ) ).append( rHyperlink.maLocation );
+ OUString aUrl = aUrlBuffer.makeStringAndClear();
+
+ // convert '#SheetName!A1' to '#SheetName.A1'
+ if( (aUrl.getLength() > 0) && (aUrl[ 0 ] == '#') )
+ {
+ sal_Int32 nSepPos = aUrl.lastIndexOf( '!' );
+ if( nSepPos > 0 )
+ {
+ // replace the exclamation mark with a period
+ aUrl = aUrl.replaceAt( nSepPos, 1, OUString( sal_Unicode( '.' ) ) );
+ // #i66592# convert sheet names that have been renamed on import
+ OUString aSheetName = aUrl.copy( 1, nSepPos - 1 );
+ OUString aCalcName = getWorksheets().getCalcSheetName( aSheetName );
+ if( aCalcName.getLength() > 0 )
+ aUrl = aUrl.replaceAt( 1, nSepPos - 1, aCalcName );
+ }
+ }
+
+ return aUrl;
+}
+
+void WorksheetData::insertHyperlink( const CellAddress& rAddress, const OUString& rUrl ) const
+{
+ Reference< XCell > xCell = getCell( rAddress );
+ if( xCell.is() ) switch( xCell->getType() )
+ {
+ // #i54261# restrict creation of URL field to text cells
+ case ::com::sun::star::table::CellContentType_TEXT:
+ {
+ Reference< XText > xText( xCell, UNO_QUERY );
+ if( xText.is() )
+ {
+ // create a URL field object and set its properties
+ Reference< XTextContent > xUrlField( getDocumentFactory()->createInstance( maUrlTextField ), UNO_QUERY );
+ OSL_ENSURE( xUrlField.is(), "WorksheetData::insertHyperlink - cannot create text field" );
+ if( xUrlField.is() )
+ {
+ // properties of the URL field
+ PropertySet aPropSet( xUrlField );
+ aPropSet.setProperty( PROP_URL, rUrl );
+ aPropSet.setProperty( PROP_Representation, xText->getString() );
+ try
+ {
+ // insert the field into the cell
+ xText->setString( OUString() );
+ Reference< XTextRange > xRange( xText->createTextCursor(), UNO_QUERY_THROW );
+ xText->insertTextContent( xRange, xUrlField, sal_False );
+ }
+ catch( const Exception& )
+ {
+ OSL_FAIL( "WorksheetData::insertHyperlink - cannot insert text field" );
+ }
+ }
+ }
+ }
+ break;
+
+ // fix for #i31050# disabled, HYPERLINK is not able to return numeric value (#i91351#)
+#if 0
+ // #i31050# replace number with HYPERLINK function
+ case ::com::sun::star::table::CellContentType_VALUE:
+ {
+ Reference< XFormulaTokens > xTokens( xCell, UNO_QUERY );
+ OSL_ENSURE( xTokens.is(), "WorksheetHelper::insertHyperlink - missing formula interface" );
+ if( xTokens.is() )
+ {
+ SimpleFormulaContext aContext( xTokens, false, false );
+ getFormulaParser().convertNumberToHyperlink( aContext, rUrl, xCell->getValue() );
+ }
+ }
+ break;
+#endif
+
+ default:;
+ }
+}
+
+void WorksheetData::finalizeValidationRanges() const
+{
+ for( ValidationModelList::const_iterator aIt = maValidations.begin(), aEnd = maValidations.end(); aIt != aEnd; ++aIt )
+ {
+ PropertySet aPropSet( getCellRangeList( aIt->maRanges ) );
+
+ Reference< XPropertySet > xValidation( aPropSet.getAnyProperty( PROP_Validation ), UNO_QUERY );
+ if( xValidation.is() )
+ {
+ PropertySet aValProps( xValidation );
+ namespace csss = ::com::sun::star::sheet;
+
+ // convert validation type to API enum
+ ValidationType eType = csss::ValidationType_ANY;
+ switch( aIt->mnType )
+ {
+ case XML_custom: eType = csss::ValidationType_CUSTOM; break;
+ case XML_date: eType = csss::ValidationType_DATE; break;
+ case XML_decimal: eType = csss::ValidationType_DECIMAL; break;
+ case XML_list: eType = csss::ValidationType_LIST; break;
+ case XML_none: eType = csss::ValidationType_ANY; break;
+ case XML_textLength: eType = csss::ValidationType_TEXT_LEN; break;
+ case XML_time: eType = csss::ValidationType_TIME; break;
+ case XML_whole: eType = csss::ValidationType_WHOLE; break;
+ default: OSL_FAIL( "WorksheetData::finalizeValidationRanges - unknown validation type" );
+ }
+ aValProps.setProperty( PROP_Type, eType );
+
+ // convert error alert style to API enum
+ ValidationAlertStyle eAlertStyle = csss::ValidationAlertStyle_STOP;
+ switch( aIt->mnErrorStyle )
+ {
+ case XML_information: eAlertStyle = csss::ValidationAlertStyle_INFO; break;
+ case XML_stop: eAlertStyle = csss::ValidationAlertStyle_STOP; break;
+ case XML_warning: eAlertStyle = csss::ValidationAlertStyle_WARNING; break;
+ default: OSL_FAIL( "WorksheetData::finalizeValidationRanges - unknown error style" );
+ }
+ aValProps.setProperty( PROP_ErrorAlertStyle, eAlertStyle );
+
+ // convert dropdown style to API visibility constants
+ sal_Int16 nVisibility = aIt->mbNoDropDown ? csss::TableValidationVisibility::INVISIBLE : csss::TableValidationVisibility::UNSORTED;
+ aValProps.setProperty( PROP_ShowList, nVisibility );
+
+ // messages
+ aValProps.setProperty( PROP_ShowInputMessage, aIt->mbShowInputMsg );
+ aValProps.setProperty( PROP_InputTitle, aIt->maInputTitle );
+ aValProps.setProperty( PROP_InputMessage, aIt->maInputMessage );
+ aValProps.setProperty( PROP_ShowErrorMessage, aIt->mbShowErrorMsg );
+ aValProps.setProperty( PROP_ErrorTitle, aIt->maErrorTitle );
+ aValProps.setProperty( PROP_ErrorMessage, aIt->maErrorMessage );
+
+ // allow blank cells
+ aValProps.setProperty( PROP_IgnoreBlankCells, aIt->mbAllowBlank );
+
+ try
+ {
+ // condition operator
+ Reference< XSheetCondition2 > xSheetCond( xValidation, UNO_QUERY_THROW );
+ xSheetCond->setConditionOperator( CondFormatBuffer::convertToApiOperator( aIt->mnOperator ) );
+
+ // condition formulas
+ Reference< XMultiFormulaTokens > xTokens( xValidation, UNO_QUERY_THROW );
+ xTokens->setTokens( 0, aIt->maTokens1 );
+ xTokens->setTokens( 1, aIt->maTokens2 );
+ }
+ catch( Exception& )
+ {
+ }
+
+ // write back validation settings to cell range(s)
+ aPropSet.setProperty( PROP_Validation, xValidation );
+ }
+ }
+}
+
+void WorksheetData::finalizeMergedRanges()
+{
+ MergedRangeList::const_iterator aIt, aEnd;
+ for( aIt = maMergedRanges.begin(), aEnd = maMergedRanges.end(); aIt != aEnd; ++aIt )
+ finalizeMergedRange( aIt->maRange );
+ for( aIt = maCenterFillRanges.begin(), aEnd = maCenterFillRanges.end(); aIt != aEnd; ++aIt )
+ finalizeMergedRange( aIt->maRange );
+}
+
+void WorksheetData::finalizeMergedRange( const CellRangeAddress& rRange )
+{
+ bool bMultiCol = rRange.StartColumn < rRange.EndColumn;
+ bool bMultiRow = rRange.StartRow < rRange.EndRow;
+
+ if( bMultiCol || bMultiRow ) try
+ {
+ // merge the cell range
+ Reference< XMergeable > xMerge( getCellRange( rRange ), UNO_QUERY_THROW );
+ xMerge->merge( sal_True );
+
+ // if merging this range worked (no overlapping merged ranges), update cell borders
+ Reference< XCell > xTopLeft( getCell( CellAddress( getSheetIndex(), rRange.StartColumn, rRange.StartRow ) ), UNO_SET_THROW );
+ PropertySet aTopLeftProp( xTopLeft );
+
+ // copy right border of top-right cell to right border of top-left cell
+ if( bMultiCol )
+ {
+ PropertySet aTopRightProp( getCell( CellAddress( getSheetIndex(), rRange.EndColumn, rRange.StartRow ) ) );
+ BorderLine aLine;
+ if( aTopRightProp.getProperty( aLine, PROP_RightBorder ) )
+ aTopLeftProp.setProperty( PROP_RightBorder, aLine );
+ }
+
+ // copy bottom border of bottom-left cell to bottom border of top-left cell
+ if( bMultiRow )
+ {
+ PropertySet aBottomLeftProp( getCell( CellAddress( getSheetIndex(), rRange.StartColumn, rRange.EndRow ) ) );
+ BorderLine aLine;
+ if( aBottomLeftProp.getProperty( aLine, PROP_BottomBorder ) )
+ aTopLeftProp.setProperty( PROP_BottomBorder, aLine );
+ }
+
+ // #i93609# merged range in a single row: test if manual row height is needed
+ if( !bMultiRow )
+ {
+ bool bTextWrap = aTopLeftProp.getBoolProperty( PROP_IsTextWrapped );
+ if( !bTextWrap && (xTopLeft->getType() == ::com::sun::star::table::CellContentType_TEXT) )
+ {
+ Reference< XText > xText( xTopLeft, UNO_QUERY );
+ bTextWrap = xText.is() && (xText->getString().indexOf( '\x0A' ) >= 0);
+ }
+ if( bTextWrap )
+ maManualRowHeights.insert( rRange.StartRow );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void WorksheetData::convertColumns()
+{
+ sal_Int32 nNextCol = 0;
+ sal_Int32 nMaxCol = mrMaxApiPos.Column;
+ // stores first grouped column index for each level
+ OutlineLevelVec aColLevels;
+
+ for( ColumnModelMap::const_iterator aIt = maColModels.begin(), aEnd = maColModels.end(); aIt != aEnd; ++aIt )
+ {
+ // convert 1-based OOXML column indexes to 0-based API column indexes
+ sal_Int32 nFirstCol = ::std::max( aIt->second.mnFirstCol - 1, nNextCol );
+ sal_Int32 nLastCol = ::std::min( aIt->second.mnLastCol - 1, nMaxCol );
+
+ // process gap between two column models, use default column model
+ if( nNextCol < nFirstCol )
+ convertColumns( aColLevels, nNextCol, nFirstCol - 1, maDefColModel );
+ // process the column model
+ convertColumns( aColLevels, nFirstCol, nLastCol, aIt->second );
+
+ // cache next column to be processed
+ nNextCol = nLastCol + 1;
+ }
+
+ // remaining default columns to end of sheet
+ convertColumns( aColLevels, nNextCol, nMaxCol, maDefColModel );
+ // close remaining column outlines spanning to end of sheet
+ convertOutlines( aColLevels, nMaxCol + 1, 0, false, false );
+}
+
+void WorksheetData::convertColumns( OutlineLevelVec& orColLevels,
+ sal_Int32 nFirstCol, sal_Int32 nLastCol, const ColumnModel& rModel )
+{
+ PropertySet aPropSet( getColumns( nFirstCol, nLastCol ) );
+
+ // column width: convert 'number of characters' to column width in 1/100 mm
+ sal_Int32 nWidth = getUnitConverter().scaleToMm100( rModel.mfWidth, UNIT_DIGIT );
+ // macro sheets have double width
+ if( meSheetType == SHEETTYPE_MACROSHEET )
+ nWidth *= 2;
+ if( nWidth > 0 )
+ aPropSet.setProperty( PROP_Width, nWidth );
+
+ // hidden columns: TODO: #108683# hide columns later?
+ if( rModel.mbHidden )
+ aPropSet.setProperty( PROP_IsVisible, false );
+
+ // outline settings for this column range
+ convertOutlines( orColLevels, nFirstCol, rModel.mnLevel, rModel.mbCollapsed, false );
+}
+
+void WorksheetData::convertRows()
+{
+ sal_Int32 nNextRow = 0;
+ sal_Int32 nMaxRow = mrMaxApiPos.Row;
+ // stores first grouped row index for each level
+ OutlineLevelVec aRowLevels;
+
+ for( RowModelMap::const_iterator aIt = maRowModels.begin(), aEnd = maRowModels.end(); aIt != aEnd; ++aIt )
+ {
+ // convert 1-based OOXML row indexes to 0-based API row indexes
+ sal_Int32 nFirstRow = ::std::max( aIt->second.mnFirstRow - 1, nNextRow );
+ sal_Int32 nLastRow = ::std::min( aIt->second.mnLastRow - 1, nMaxRow );
+
+ // process gap between two row models, use default row model
+ if( nNextRow < nFirstRow )
+ convertRows( aRowLevels, nNextRow, nFirstRow - 1, maDefRowModel );
+ // process the row model
+ convertRows( aRowLevels, nFirstRow, nLastRow, aIt->second, maDefRowModel.mfHeight );
+
+ // cache next row to be processed
+ nNextRow = nLastRow + 1;
+ }
+
+ // remaining default rows to end of sheet
+ convertRows( aRowLevels, nNextRow, nMaxRow, maDefRowModel );
+ // close remaining row outlines spanning to end of sheet
+ convertOutlines( aRowLevels, nMaxRow + 1, 0, false, true );
+}
+
+void WorksheetData::convertRows( OutlineLevelVec& orRowLevels,
+ sal_Int32 nFirstRow, sal_Int32 nLastRow, const RowModel& rModel, double fDefHeight )
+{
+ // row height: convert points to row height in 1/100 mm
+ double fHeight = (rModel.mfHeight >= 0.0) ? rModel.mfHeight : fDefHeight;
+ sal_Int32 nHeight = getUnitConverter().scaleToMm100( fHeight, UNIT_POINT );
+ if( nHeight > 0 )
+ {
+ ValueRangeVector aManualRows;
+ if( rModel.mbCustomHeight )
+ aManualRows.push_back( ValueRange( nFirstRow, nLastRow ) );
+ else
+ maManualRowHeights.intersect( aManualRows, nFirstRow, nLastRow );
+ for( ValueRangeVector::const_iterator aIt = aManualRows.begin(), aEnd = aManualRows.end(); aIt != aEnd; ++aIt )
+ {
+ PropertySet aPropSet( getRows( aIt->mnFirst, aIt->mnLast ) );
+ aPropSet.setProperty( PROP_Height, nHeight );
+ }
+ }
+
+ // hidden rows: TODO: #108683# hide rows later?
+ if( rModel.mbHidden )
+ {
+ PropertySet aPropSet( getRows( nFirstRow, nLastRow ) );
+ aPropSet.setProperty( PROP_IsVisible, false );
+ }
+
+ // outline settings for this row range
+ convertOutlines( orRowLevels, nFirstRow, rModel.mnLevel, rModel.mbCollapsed, true );
+}
+
+void WorksheetData::convertOutlines( OutlineLevelVec& orLevels,
+ sal_Int32 nColRow, sal_Int32 nLevel, bool bCollapsed, bool bRows )
+{
+ /* It is ensured from caller functions, that this function is called
+ without any gaps between the processed column or row ranges. */
+
+ OSL_ENSURE( nLevel >= 0, "WorksheetData::convertOutlines - negative outline level" );
+ nLevel = ::std::max< sal_Int32 >( nLevel, 0 );
+
+ sal_Int32 nSize = orLevels.size();
+ if( nSize < nLevel )
+ {
+ // Outline level increased. Push the begin column position.
+ for( sal_Int32 nIndex = nSize; nIndex < nLevel; ++nIndex )
+ orLevels.push_back( nColRow );
+ }
+ else if( nLevel < nSize )
+ {
+ // Outline level decreased. Pop them all out.
+ for( sal_Int32 nIndex = nLevel; nIndex < nSize; ++nIndex )
+ {
+ sal_Int32 nFirstInLevel = orLevels.back();
+ orLevels.pop_back();
+ groupColumnsOrRows( nFirstInLevel, nColRow - 1, bCollapsed, bRows );
+ bCollapsed = false; // collapse only once
+ }
+ }
+}
+
+void WorksheetData::groupColumnsOrRows( sal_Int32 nFirstColRow, sal_Int32 nLastColRow, bool bCollapse, bool bRows )
+{
+ try
+ {
+ Reference< XSheetOutline > xOutline( mxSheet, UNO_QUERY_THROW );
+ if( bRows )
+ {
+ CellRangeAddress aRange( getSheetIndex(), 0, nFirstColRow, 0, nLastColRow );
+ xOutline->group( aRange, ::com::sun::star::table::TableOrientation_ROWS );
+ if( bCollapse )
+ xOutline->hideDetail( aRange );
+ }
+ else
+ {
+ CellRangeAddress aRange( getSheetIndex(), nFirstColRow, 0, nLastColRow, 0 );
+ xOutline->group( aRange, ::com::sun::star::table::TableOrientation_COLUMNS );
+ if( bCollapse )
+ xOutline->hideDetail( aRange );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void WorksheetData::finalizeDrawings()
+{
+ switch( getFilterType() )
+ {
+ case FILTER_OOXML:
+ // import DML and VML
+ if( maDrawingPath.getLength() > 0 )
+ importOoxFragment( new DrawingFragment( *this, maDrawingPath ) );
+ if( maVmlDrawingPath.getLength() > 0 )
+ importOoxFragment( new VmlDrawingFragment( *this, maVmlDrawingPath ) );
+ break;
+
+ case FILTER_BIFF:
+ // TODO: import DFF shapes
+ break;
+
+ case FILTER_UNKNOWN:
+ break;
+ }
+
+ // comments (after callout shapes have been imported from VML/DFF)
+ maComments.finalizeImport();
+
+ /* Extend used area of the sheet by cells covered with drawing objects.
+ Needed if the imported document is inserted as "OLE object from file"
+ and thus does not provide an OLE size property by itself. */
+ if( (maShapeBoundingBox.Width > 0) || (maShapeBoundingBox.Height > 0) )
+ extendUsedArea( getCellRangeFromRectangle( maShapeBoundingBox ) );
+
+ // if no used area is set, default to A1
+ if( maUsedArea.StartColumn > maUsedArea.EndColumn )
+ maUsedArea.StartColumn = maUsedArea.EndColumn = 0;
+ if( maUsedArea.StartRow > maUsedArea.EndRow )
+ maUsedArea.StartRow = maUsedArea.EndRow = 0;
+
+ /* Register the used area of this sheet in global view settings. The
+ global view settings will set the visible area if this document is an
+ embedded OLE object. */
+ getViewSettings().setSheetUsedArea( maUsedArea );
+
+ /* #i103686# Set right-to-left sheet layout. Must be done after all
+ drawing shapes to simplify calculation of shape coordinates. */
+ if( maSheetViewSett.isSheetRightToLeft() )
+ {
+ PropertySet aPropSet( mxSheet );
+ aPropSet.setProperty( PROP_TableLayout, ::com::sun::star::text::WritingMode2::RL_TB );
+ }
+}
+
+// ============================================================================
+// ============================================================================
+
+WorksheetHelper::WorksheetHelper( WorksheetData& rSheetData ) :
+ WorkbookHelper( rSheetData ),
+ mrSheetData( rSheetData )
+{
+}
+
+WorksheetType WorksheetHelper::getSheetType() const
+{
+ return mrSheetData.getSheetType();
+}
+
+sal_Int16 WorksheetHelper::getSheetIndex() const
+{
+ return mrSheetData.getSheetIndex();
+}
+
+const Reference< XSpreadsheet >& WorksheetHelper::getSheet() const
+{
+ return mrSheetData.getSheet();
+}
+
+Reference< XCell > WorksheetHelper::getCell( const CellAddress& rAddress ) const
+{
+ return mrSheetData.getCell( rAddress );
+}
+
+Reference< XCell > WorksheetHelper::getCell( const OUString& rAddressStr, CellAddress* opAddress ) const
+{
+ CellAddress aAddress;
+ if( getAddressConverter().convertToCellAddress( aAddress, rAddressStr, mrSheetData.getSheetIndex(), true ) )
+ {
+ if( opAddress ) *opAddress = aAddress;
+ return mrSheetData.getCell( aAddress );
+ }
+ return Reference< XCell >();
+}
+
+Reference< XCell > WorksheetHelper::getCell( const BinAddress& rBinAddress, CellAddress* opAddress ) const
+{
+ CellAddress aAddress;
+ if( getAddressConverter().convertToCellAddress( aAddress, rBinAddress, mrSheetData.getSheetIndex(), true ) )
+ {
+ if( opAddress ) *opAddress = aAddress;
+ return mrSheetData.getCell( aAddress );
+ }
+ return Reference< XCell >();
+}
+
+Reference< XCellRange > WorksheetHelper::getCellRange( const CellRangeAddress& rRange ) const
+{
+ return mrSheetData.getCellRange( rRange );
+}
+
+Reference< XCellRange > WorksheetHelper::getCellRange( const OUString& rRangeStr, CellRangeAddress* opRange ) const
+{
+ CellRangeAddress aRange;
+ if( getAddressConverter().convertToCellRange( aRange, rRangeStr, mrSheetData.getSheetIndex(), true, true ) )
+ {
+ if( opRange ) *opRange = aRange;
+ return mrSheetData.getCellRange( aRange );
+ }
+ return Reference< XCellRange >();
+}
+
+Reference< XCellRange > WorksheetHelper::getCellRange( const BinRange& rBinRange, CellRangeAddress* opRange ) const
+{
+ CellRangeAddress aRange;
+ if( getAddressConverter().convertToCellRange( aRange, rBinRange, mrSheetData.getSheetIndex(), true, true ) )
+ {
+ if( opRange ) *opRange = aRange;
+ return mrSheetData.getCellRange( aRange );
+ }
+ return Reference< XCellRange >();
+}
+
+Reference< XSheetCellRanges > WorksheetHelper::getCellRangeList( const ApiCellRangeList& rRanges ) const
+{
+ return mrSheetData.getCellRangeList( rRanges );
+}
+
+Reference< XSheetCellRanges > WorksheetHelper::getCellRangeList(
+ const OUString& rRangesStr, ApiCellRangeList* opRanges ) const
+{
+ ApiCellRangeList aRanges;
+ getAddressConverter().convertToCellRangeList( aRanges, rRangesStr, mrSheetData.getSheetIndex(), true );
+ if( opRanges ) *opRanges = aRanges;
+ return mrSheetData.getCellRangeList( aRanges );
+}
+
+Reference< XSheetCellRanges > WorksheetHelper::getCellRangeList(
+ const BinRangeList& rBinRanges, ApiCellRangeList* opRanges ) const
+{
+ ApiCellRangeList aRanges;
+ getAddressConverter().convertToCellRangeList( aRanges, rBinRanges, mrSheetData.getSheetIndex(), true );
+ if( opRanges ) *opRanges = aRanges;
+ return mrSheetData.getCellRangeList( aRanges );
+}
+
+CellAddress WorksheetHelper::getCellAddress( const Reference< XCell >& rxCell )
+{
+ CellAddress aAddress;
+ Reference< XCellAddressable > xAddressable( rxCell, UNO_QUERY );
+ OSL_ENSURE( xAddressable.is(), "WorksheetHelper::getCellAddress - cell reference not addressable" );
+ if( xAddressable.is() )
+ aAddress = xAddressable->getCellAddress();
+ return aAddress;
+}
+
+CellRangeAddress WorksheetHelper::getRangeAddress( const Reference< XCellRange >& rxRange )
+{
+ CellRangeAddress aRange;
+ Reference< XCellRangeAddressable > xAddressable( rxRange, UNO_QUERY );
+ OSL_ENSURE( xAddressable.is(), "WorksheetHelper::getRangeAddress - cell range reference not addressable" );
+ if( xAddressable.is() )
+ aRange = xAddressable->getRangeAddress();
+ return aRange;
+}
+
+Reference< XCellRange > WorksheetHelper::getColumn( sal_Int32 nCol ) const
+{
+ return mrSheetData.getColumn( nCol );
+}
+
+Reference< XCellRange > WorksheetHelper::getRow( sal_Int32 nRow ) const
+{
+ return mrSheetData.getRow( nRow );
+}
+
+Reference< XTableColumns > WorksheetHelper::getColumns( sal_Int32 nFirstCol, sal_Int32 nLastCol ) const
+{
+ return mrSheetData.getColumns( nFirstCol, nLastCol );
+}
+
+Reference< XTableRows > WorksheetHelper::getRows( sal_Int32 nFirstRow, sal_Int32 nLastRow ) const
+{
+ return mrSheetData.getRows( nFirstRow, nLastRow );
+}
+
+Reference< XDrawPage > WorksheetHelper::getDrawPage() const
+{
+ return mrSheetData.getDrawPage();
+}
+
+Point WorksheetHelper::getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return mrSheetData.getCellPosition( nCol, nRow );
+}
+
+Size WorksheetHelper::getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return mrSheetData.getCellSize( nCol, nRow );
+}
+
+Size WorksheetHelper::getDrawPageSize() const
+{
+ return mrSheetData.getDrawPageSize();
+}
+
+WorksheetSettings& WorksheetHelper::getWorksheetSettings() const
+{
+ return mrSheetData.getWorksheetSettings();
+}
+
+SharedFormulaBuffer& WorksheetHelper::getSharedFormulas() const
+{
+ return mrSheetData.getSharedFormulas();
+}
+
+CondFormatBuffer& WorksheetHelper::getCondFormats() const
+{
+ return mrSheetData.getCondFormats();
+}
+
+CommentsBuffer& WorksheetHelper::getComments() const
+{
+ return mrSheetData.getComments();
+}
+
+AutoFilterBuffer& WorksheetHelper::getAutoFilters() const
+{
+ return mrSheetData.getAutoFilters();
+}
+
+QueryTableBuffer& WorksheetHelper::getQueryTables() const
+{
+ return mrSheetData.getQueryTables();
+}
+
+PageSettings& WorksheetHelper::getPageSettings() const
+{
+ return mrSheetData.getPageSettings();
+}
+
+SheetViewSettings& WorksheetHelper::getSheetViewSettings() const
+{
+ return mrSheetData.getSheetViewSettings();
+}
+
+VmlDrawing& WorksheetHelper::getVmlDrawing() const
+{
+ return mrSheetData.getVmlDrawing();
+}
+
+void WorksheetHelper::setStringCell( const Reference< XCell >& rxCell, const OUString& rText ) const
+{
+ OSL_ENSURE( rxCell.is(), "WorksheetHelper::setStringCell - missing cell interface" );
+ Reference< XText > xText( rxCell, UNO_QUERY );
+ if( xText.is() )
+ xText->setString( rText );
+}
+
+void WorksheetHelper::setSharedStringCell( const Reference< XCell >& rxCell, sal_Int32 nStringId, sal_Int32 nXfId ) const
+{
+ OSL_ENSURE( rxCell.is(), "WorksheetHelper::setSharedStringCell - missing cell interface" );
+ getSharedStrings().convertString( Reference< XText >( rxCell, UNO_QUERY ), nStringId, nXfId );
+}
+
+void WorksheetHelper::setDateTimeCell( const Reference< XCell >& rxCell, const DateTime& rDateTime ) const
+{
+ OSL_ENSURE( rxCell.is(), "WorksheetHelper::setDateTimeCell - missing cell interface" );
+ // write serial date/time value into the cell
+ double fSerial = getUnitConverter().calcSerialFromDateTime( rDateTime );
+ rxCell->setValue( fSerial );
+ // set appropriate number format
+ using namespace ::com::sun::star::util::NumberFormat;
+ sal_Int16 nStdFmt = (fSerial < 1.0) ? TIME : (((rDateTime.Hours > 0) || (rDateTime.Minutes > 0) || (rDateTime.Seconds > 0)) ? DATETIME : DATE);
+ setStandardNumFmt( rxCell, nStdFmt );
+}
+
+void WorksheetHelper::setBooleanCell( const Reference< XCell >& rxCell, bool bValue ) const
+{
+ OSL_ENSURE( rxCell.is(), "WorksheetHelper::setBooleanCell - missing cell interface" );
+ rxCell->setFormula( mrSheetData.getBooleanFormula( bValue ) );
+}
+
+void WorksheetHelper::setErrorCell( const Reference< XCell >& rxCell, const OUString& rErrorCode ) const
+{
+ setErrorCell( rxCell, getUnitConverter().calcBiffErrorCode( rErrorCode ) );
+}
+
+void WorksheetHelper::setErrorCell( const Reference< XCell >& rxCell, sal_uInt8 nErrorCode ) const
+{
+ Reference< XFormulaTokens > xTokens( rxCell, UNO_QUERY );
+ OSL_ENSURE( xTokens.is(), "WorksheetHelper::setErrorCell - missing formula interface" );
+ if( xTokens.is() )
+ {
+ SimpleFormulaContext aContext( xTokens, false, false );
+ getFormulaParser().convertErrorToFormula( aContext, nErrorCode );
+ }
+}
+
+void WorksheetHelper::setCell( CellModel& orModel ) const
+{
+ OSL_ENSURE( orModel.mxCell.is(), "WorksheetHelper::setCell - missing cell interface" );
+ if( orModel.mbHasValueStr ) switch( orModel.mnCellType )
+ {
+ case XML_b:
+ setBooleanCell( orModel.mxCell, orModel.maValueStr.toDouble() != 0.0 );
+ // #108770# set 'Standard' number format for all Boolean cells
+ orModel.mnNumFmtId = 0;
+ break;
+ case XML_n:
+ orModel.mxCell->setValue( orModel.maValueStr.toDouble() );
+ break;
+ case XML_e:
+ setErrorCell( orModel.mxCell, orModel.maValueStr );
+ break;
+ case XML_str:
+ setStringCell( orModel.mxCell, orModel.maValueStr );
+ break;
+ case XML_s:
+ setSharedStringCell( orModel.mxCell, orModel.maValueStr.toInt32(), orModel.mnXfId );
+ break;
+ }
+}
+
+void WorksheetHelper::setStandardNumFmt( const Reference< XCell >& rxCell, sal_Int16 nStdNumFmt ) const
+{
+ try
+ {
+ Reference< XNumberFormatsSupplier > xNumFmtsSupp( getDocument(), UNO_QUERY_THROW );
+ Reference< XNumberFormatTypes > xNumFmtTypes( xNumFmtsSupp->getNumberFormats(), UNO_QUERY_THROW );
+ sal_Int32 nIndex = xNumFmtTypes->getStandardFormat( nStdNumFmt, Locale() );
+ PropertySet aPropSet( rxCell );
+ aPropSet.setProperty( PROP_NumberFormat, nIndex );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void WorksheetHelper::setSheetType( WorksheetType eSheetType )
+{
+ mrSheetData.setSheetType( eSheetType );
+}
+
+void WorksheetHelper::setCellFormat( const CellModel& rModel )
+{
+ mrSheetData.setCellFormat( rModel );
+}
+
+void WorksheetHelper::setMergedRange( const CellRangeAddress& rRange )
+{
+ mrSheetData.setMergedRange( rRange );
+}
+
+void WorksheetHelper::setPageBreak( const PageBreakModel& rModel, bool bRowBreak )
+{
+ mrSheetData.setPageBreak( rModel, bRowBreak );
+}
+
+void WorksheetHelper::setHyperlink( const HyperlinkModel& rModel )
+{
+ mrSheetData.setHyperlink( rModel );
+}
+
+void WorksheetHelper::setValidation( const ValidationModel& rModel )
+{
+ mrSheetData.setValidation( rModel );
+}
+
+void WorksheetHelper::setTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel ) const
+{
+ OSL_ENSURE( getAddressConverter().checkCellRange( rRange, true, false ), "WorksheetHelper::setTableOperation - invalid range" );
+ bool bOk = false;
+ if( !rModel.mbRef1Deleted && (rModel.maRef1.getLength() > 0) && (rRange.StartColumn > 0) && (rRange.StartRow > 0) )
+ {
+ CellRangeAddress aOpRange = rRange;
+ CellAddress aRef1, aRef2;
+ if( getAddressConverter().convertToCellAddress( aRef1, rModel.maRef1, mrSheetData.getSheetIndex(), true ) ) try
+ {
+ if( rModel.mb2dTable )
+ {
+ if( !rModel.mbRef2Deleted && getAddressConverter().convertToCellAddress( aRef2, rModel.maRef2, mrSheetData.getSheetIndex(), true ) )
+ {
+ // API call expects input values inside operation range
+ --aOpRange.StartColumn;
+ --aOpRange.StartRow;
+ // formula range is top-left cell of operation range
+ CellRangeAddress aFormulaRange( mrSheetData.getSheetIndex(), aOpRange.StartColumn, aOpRange.StartRow, aOpRange.StartColumn, aOpRange.StartRow );
+ // set multiple operation
+ Reference< XMultipleOperation > xMultOp( mrSheetData.getCellRange( aOpRange ), UNO_QUERY_THROW );
+ xMultOp->setTableOperation( aFormulaRange, ::com::sun::star::sheet::TableOperationMode_BOTH, aRef2, aRef1 );
+ bOk = true;
+ }
+ }
+ else if( rModel.mbRowTable )
+ {
+ // formula range is column to the left of operation range
+ CellRangeAddress aFormulaRange( mrSheetData.getSheetIndex(), aOpRange.StartColumn - 1, aOpRange.StartRow, aOpRange.StartColumn - 1, aOpRange.EndRow );
+ // API call expects input values (top row) inside operation range
+ --aOpRange.StartRow;
+ // set multiple operation
+ Reference< XMultipleOperation > xMultOp( mrSheetData.getCellRange( aOpRange ), UNO_QUERY_THROW );
+ xMultOp->setTableOperation( aFormulaRange, ::com::sun::star::sheet::TableOperationMode_ROW, aRef1, aRef1 );
+ bOk = true;
+ }
+ else
+ {
+ // formula range is row above operation range
+ CellRangeAddress aFormulaRange( mrSheetData.getSheetIndex(), aOpRange.StartColumn, aOpRange.StartRow - 1, aOpRange.EndColumn, aOpRange.StartRow - 1 );
+ // API call expects input values (left column) inside operation range
+ --aOpRange.StartColumn;
+ // set multiple operation
+ Reference< XMultipleOperation > xMultOp( mrSheetData.getCellRange( aOpRange ), UNO_QUERY_THROW );
+ xMultOp->setTableOperation( aFormulaRange, ::com::sun::star::sheet::TableOperationMode_COLUMN, aRef1, aRef1 );
+ bOk = true;
+ }
+ }
+ catch( Exception& )
+ {
+ }
+ }
+
+ // on error: fill cell range with error codes
+ if( !bOk )
+ {
+ for( CellAddress aPos( mrSheetData.getSheetIndex(), rRange.StartColumn, rRange.StartRow ); aPos.Row <= rRange.EndRow; ++aPos.Row )
+ for( aPos.Column = rRange.StartColumn; aPos.Column <= rRange.EndColumn; ++aPos.Column )
+ setErrorCell( mrSheetData.getCell( aPos ), BIFF_ERR_REF );
+ }
+}
+
+void WorksheetHelper::setLabelRanges( const ApiCellRangeList& rColRanges, const ApiCellRangeList& rRowRanges )
+{
+ const CellAddress& rMaxPos = getAddressConverter().getMaxApiAddress();
+ PropertySet aPropSet( getSheet() );
+
+ if( !rColRanges.empty() )
+ {
+ Reference< XLabelRanges > xLabelRanges( aPropSet.getAnyProperty( PROP_ColumnLabelRanges ), UNO_QUERY );
+ if( xLabelRanges.is() )
+ {
+ for( ApiCellRangeList::const_iterator aIt = rColRanges.begin(), aEnd = rColRanges.end(); aIt != aEnd; ++aIt )
+ {
+ CellRangeAddress aDataRange = *aIt;
+ if( aDataRange.EndRow < rMaxPos.Row )
+ {
+ aDataRange.StartRow = aDataRange.EndRow + 1;
+ aDataRange.EndRow = rMaxPos.Row;
+ }
+ else if( aDataRange.StartRow > 0 )
+ {
+ aDataRange.EndRow = aDataRange.StartRow - 1;
+ aDataRange.StartRow = 0;
+ }
+ xLabelRanges->addNew( *aIt, aDataRange );
+ }
+ }
+ }
+
+ if( !rRowRanges.empty() )
+ {
+ Reference< XLabelRanges > xLabelRanges( aPropSet.getAnyProperty( PROP_RowLabelRanges ), UNO_QUERY );
+ if( xLabelRanges.is() )
+ {
+ for( ApiCellRangeList::const_iterator aIt = rRowRanges.begin(), aEnd = rRowRanges.end(); aIt != aEnd; ++aIt )
+ {
+ CellRangeAddress aDataRange = *aIt;
+ if( aDataRange.EndColumn < rMaxPos.Column )
+ {
+ aDataRange.StartColumn = aDataRange.EndColumn + 1;
+ aDataRange.EndColumn = rMaxPos.Column;
+ }
+ else if( aDataRange.StartColumn > 0 )
+ {
+ aDataRange.EndColumn = aDataRange.StartColumn - 1;
+ aDataRange.StartColumn = 0;
+ }
+ xLabelRanges->addNew( *aIt, aDataRange );
+ }
+ }
+ }
+}
+
+void WorksheetHelper::setDrawingPath( const OUString& rDrawingPath )
+{
+ mrSheetData.setDrawingPath( rDrawingPath );
+}
+
+void WorksheetHelper::setVmlDrawingPath( const OUString& rVmlDrawingPath )
+{
+ mrSheetData.setVmlDrawingPath( rVmlDrawingPath );
+}
+
+void WorksheetHelper::extendUsedArea( const CellAddress& rAddress )
+{
+ mrSheetData.extendUsedArea( rAddress );
+}
+
+void WorksheetHelper::extendUsedArea( const CellRangeAddress& rRange )
+{
+ mrSheetData.extendUsedArea( rRange );
+}
+
+void WorksheetHelper::extendShapeBoundingBox( const Rectangle& rShapeRect )
+{
+ mrSheetData.extendShapeBoundingBox( rShapeRect );
+}
+
+void WorksheetHelper::setBaseColumnWidth( sal_Int32 nWidth )
+{
+ mrSheetData.setBaseColumnWidth( nWidth );
+}
+
+void WorksheetHelper::setDefaultColumnWidth( double fWidth )
+{
+ mrSheetData.setDefaultColumnWidth( fWidth );
+}
+
+void WorksheetHelper::setDefaultColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId )
+{
+ mrSheetData.convertColumnFormat( nFirstCol, nLastCol, nXfId );
+}
+
+void WorksheetHelper::setColumnModel( const ColumnModel& rModel )
+{
+ mrSheetData.setColumnModel( rModel );
+}
+
+void WorksheetHelper::setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom )
+{
+ mrSheetData.setDefaultRowSettings( fHeight, bCustomHeight, bHidden, bThickTop, bThickBottom );
+}
+
+void WorksheetHelper::setRowModel( const RowModel& rModel )
+{
+ mrSheetData.setRowModel( rModel );
+}
+
+void WorksheetHelper::initializeWorksheetImport()
+{
+ mrSheetData.initializeWorksheetImport();
+}
+
+void WorksheetHelper::finalizeWorksheetImport()
+{
+ mrSheetData.finalizeWorksheetImport();
+}
+
+// ============================================================================
+
+namespace prv {
+
+WorksheetDataOwner::WorksheetDataOwner( WorksheetDataRef xSheetData ) :
+ mxSheetData( xSheetData )
+{
+}
+
+WorksheetDataOwner::~WorksheetDataOwner()
+{
+}
+
+} // namespace prv
+
+// ----------------------------------------------------------------------------
+
+WorksheetHelperRoot::WorksheetHelperRoot( const WorkbookHelper& rHelper, const ISegmentProgressBarRef& rxProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) :
+ prv::WorksheetDataOwner( prv::WorksheetDataRef( new WorksheetData( rHelper, rxProgressBar, eSheetType, nSheet ) ) ),
+ WorksheetHelper( *mxSheetData )
+{
+}
+
+WorksheetHelperRoot::WorksheetHelperRoot( const WorksheetHelper& rHelper ) :
+ prv::WorksheetDataOwner( prv::WorksheetDataRef() ),
+ WorksheetHelper( rHelper )
+{
+}
+
+WorksheetHelperRoot::WorksheetHelperRoot( const WorksheetHelperRoot& rHelper ) :
+ prv::WorksheetDataOwner( rHelper.mxSheetData ),
+ WorksheetHelper( rHelper )
+{
+}
+
+bool WorksheetHelperRoot::isValidSheet() const
+{
+ return mxSheetData->isValidSheet();
+}
+
+// ============================================================================
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */