summaryrefslogtreecommitdiffstats
path: root/sc/source/filter/oox/worksheethelper.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/oox/worksheethelper.cxx')
-rw-r--r--sc/source/filter/oox/worksheethelper.cxx1655
1 files changed, 1655 insertions, 0 deletions
diff --git a/sc/source/filter/oox/worksheethelper.cxx b/sc/source/filter/oox/worksheethelper.cxx
new file mode 100644
index 000000000..0d0aa8ce7
--- /dev/null
+++ b/sc/source/filter/oox/worksheethelper.cxx
@@ -0,0 +1,1655 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <memory>
+#include <worksheethelper.hxx>
+
+#include <algorithm>
+#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/sheet/ConditionOperator2.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/XMultiFormulaTokens.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/lang/XMultiServiceFactory.hpp>
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <oox/core/filterbase.hxx>
+#include <oox/helper/propertyset.hxx>
+#include <oox/token/properties.hxx>
+#include <oox/token/tokens.hxx>
+#include <addressconverter.hxx>
+#include <autofilterbuffer.hxx>
+#include <commentsbuffer.hxx>
+#include <condformatbuffer.hxx>
+#include <document.hxx>
+#include <drawingfragment.hxx>
+#include <pagesettings.hxx>
+#include <querytablebuffer.hxx>
+#include <sheetdatabuffer.hxx>
+#include <stylesbuffer.hxx>
+#include <tokenuno.hxx>
+#include <unitconverter.hxx>
+#include <viewsettings.hxx>
+#include <worksheetbuffer.hxx>
+#include <worksheetsettings.hxx>
+#include <formulabuffer.hxx>
+#include <scitems.hxx>
+#include <editutil.hxx>
+#include <tokenarray.hxx>
+#include <tablebuffer.hxx>
+#include <documentimport.hxx>
+#include <stlsheet.hxx>
+#include <stlpool.hxx>
+#include <cellvalue.hxx>
+#include <columnspanset.hxx>
+#include <dbdata.hxx>
+
+#include <svl/stritem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/flditem.hxx>
+#include <tools/gen.hxx>
+
+namespace oox::xls {
+
+using namespace ::com::sun::star;
+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;
+
+namespace {
+
+void lclUpdateProgressBar( const ISegmentProgressBarRef& rxProgressBar, double fPosition )
+{
+ if( rxProgressBar )
+ rxProgressBar->setPosition( fPosition );
+}
+
+// TODO Needed because input might be >32-bit (in 64-bit builds),
+// or a negative, already overflown value (in 32-bit builds)
+sal_Int32 lclClampToNonNegativeInt32( tools::Long aVal )
+{
+ if ( aVal > SAL_MAX_INT32 || aVal < 0 )
+ {
+ SAL_WARN( "sc.filter", "Overflow detected, " << aVal << " does not fit into sal_Int32, or is negative." );
+ return SAL_MAX_INT32;
+ }
+ return static_cast<sal_Int32>( aVal );
+}
+
+} // namespace
+
+ColumnModel::ColumnModel() :
+ maRange( -1 ),
+ mfWidth( 0.0 ),
+ mnXfId( -1 ),
+ mnLevel( 0 ),
+ mbShowPhonetic( false ),
+ mbHidden( false ),
+ mbCollapsed( false )
+{
+}
+
+bool ColumnModel::isMergeable( const ColumnModel& rModel ) const
+{
+ return
+ (maRange.mnFirst <= rModel.maRange.mnFirst) &&
+ (rModel.maRange.mnFirst <= maRange.mnLast + 1) &&
+ (mfWidth == rModel.mfWidth) &&
+ // ignore mnXfId, cell formatting is always set directly
+ (mnLevel == rModel.mnLevel) &&
+ (mbHidden == rModel.mbHidden) &&
+ (mbCollapsed == rModel.mbCollapsed);
+}
+
+RowModel::RowModel() :
+ mnRow( -1 ),
+ mfHeight( 0.0 ),
+ mnXfId( -1 ),
+ mnLevel( 0 ),
+ mbCustomHeight( false ),
+ mbCustomFormat( false ),
+ mbShowPhonetic( false ),
+ mbHidden( false ),
+ mbCollapsed( false ),
+ mbThickTop( false ),
+ mbThickBottom( false )
+{
+}
+
+void RowModel::insertColSpan( const ValueRange& rColSpan )
+{
+ if( (0 <= rColSpan.mnFirst) && (rColSpan.mnFirst <= rColSpan.mnLast) )
+ maColSpans.insert( rColSpan );
+}
+
+bool RowModel::isMergeable( const RowModel& rModel ) const
+{
+ return
+ // ignore maColSpans - is handled separately in SheetDataBuffer class
+ (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);
+}
+
+PageBreakModel::PageBreakModel()
+ : mnColRow(0)
+ , mnMin(0)
+ , mnMax(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 WorksheetGlobals : public WorkbookHelper, public IWorksheetProgress
+{
+public:
+ explicit WorksheetGlobals(
+ const WorkbookHelper& rHelper,
+ const ISegmentProgressBarRef& rxProgressBar,
+ WorksheetType eSheetType,
+ SCTAB nSheet );
+
+ /** Returns true, if this helper refers to an existing Calc sheet. */
+ bool isValidSheet() const { return mxSheet.is(); }
+
+ /** Returns the type of this sheet. */
+ WorksheetType getSheetType() const { return meSheetType; }
+ /** Returns the index of the current sheet. */
+ SCTAB getSheetIndex() const { return maUsedArea.aStart.Tab(); }
+ /** Returns the XSpreadsheet interface of the current sheet. */
+ const Reference< XSpreadsheet >& getSheet() const { return mxSheet; }
+
+ /** Returns the XCell interface for the passed cell address. */
+ Reference< XCell > getCell( const ScAddress& rAddress ) const;
+ /** Returns the XCellRange interface for the passed cell range address. */
+ Reference< XCellRange > getCellRange( const ScRange& rRange ) const;
+ /** Returns the XSheetCellRanges interface for the passed cell range addresses. */
+ Reference< XSheetCellRanges > getCellRangeList( const ScRangeList& 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 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. */
+ const awt::Size& getDrawPageSize() const;
+
+ /** Returns the absolute position of the top-left corner of the cell in 1/100 mm. */
+ awt::Point getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const;
+
+ /** Returns the address of the cell that contains the passed point in 1/100 mm. */
+ ScAddress getCellAddressFromPosition( const awt::Point& rPosition ) const;
+ /** Returns the cell range address that contains the passed rectangle in 1/100 mm. */
+ ScRange getCellRangeFromRectangle( const awt::Rectangle& rRect ) const;
+
+ /** Returns the buffer for cell contents and cell formatting. */
+ SheetDataBuffer& getSheetData() { return maSheetData; }
+ /** Returns the conditional formatting in this sheet. */
+ CondFormatBuffer& getCondFormats() { return maCondFormats; }
+ /** Returns the buffer for all cell comments in this sheet. */
+ CommentsBuffer& getComments() { return maComments; }
+ /** Returns the auto filters for the sheet. */
+ AutoFilterBuffer& getAutoFilters() { return maAutoFilters; }
+ /** Returns the buffer for all web query tables in this sheet. */
+ QueryTableBuffer& getQueryTables() { return maQueryTables; }
+ /** Returns the worksheet settings object. */
+ WorksheetSettings& getWorksheetSettings() { return maSheetSett; }
+ /** Returns the page/print settings for this sheet. */
+ PageSettings& getPageSettings() { return maPageSett; }
+ /** Returns the view settings for this sheet. */
+ SheetViewSettings& getSheetViewSettings() { return maSheetViewSett; }
+ /** Returns the VML drawing page for this sheet (OOXML/BIFF12 only). */
+ VmlDrawing& getVmlDrawing() { return *mxVmlDrawing; }
+ /** returns the ExtLst entries that need to be filled */
+ ExtLst& getExtLst() { return maExtLst; }
+
+ /** 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 ScAddress& rAddress );
+
+ /** Extends the used area of this sheet by the passed cell range. */
+ void extendUsedArea( const ScRange& rRange );
+ /** Extends the shape bounding box by the position and size of the passed rectangle. */
+ void extendShapeBoundingBox( const awt::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 );
+ /** Converts column default cell formatting. */
+ void convertColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId );
+
+ /** 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 );
+
+ /** Initial conversion before importing the worksheet. */
+ void initializeWorksheetImport();
+ /** Final conversion after importing the worksheet. */
+ void finalizeWorksheetImport();
+
+ void finalizeDrawingImport();
+
+ /// Allow the threaded importer to override our progress bar impl.
+ virtual ISegmentProgressBarRef getRowProgress() override
+ {
+ return mxRowProgress;
+ }
+ virtual void setCustomRowProgress( const ISegmentProgressBarRef &rxRowProgress ) override
+ {
+ mxRowProgress = rxRowProgress;
+ mbFastRowProgress = true;
+ }
+
+private:
+ typedef ::std::vector< sal_Int32 > OutlineLevelVec;
+ typedef ::std::pair< ColumnModel, sal_Int32 > ColumnModelRange;
+ typedef ::std::map< sal_Int32, ColumnModelRange > ColumnModelRangeMap;
+ typedef ::std::pair< RowModel, sal_Int32 > RowModelRange;
+ typedef ::std::map< sal_Int32, RowModelRange > RowModelRangeMap;
+
+ /** Inserts all imported hyperlinks into their cell ranges. */
+ void finalizeHyperlinkRanges();
+ /** Generates the final URL for the passed hyperlink. */
+ OUString getHyperlinkUrl( const HyperlinkModel& rHyperlink ) const;
+ /** Inserts a hyperlinks into the specified cell. */
+ void insertHyperlink( const ScAddress& rAddress, const OUString& rUrl );
+
+ /** Inserts all imported data validations into their cell ranges. */
+ void finalizeValidationRanges() const;
+
+ /** Converts column properties for all columns in the sheet. */
+ void convertColumns();
+ /** Converts column properties. */
+ void convertColumns( OutlineLevelVec& orColLevels, const ValueRange& rColRange, const ColumnModel& rModel );
+
+ /** Converts row properties for all rows in the sheet. */
+ void convertRows(const std::vector<sc::ColRowSpan>& rSpans);
+ /** Converts row properties. */
+ void convertRows(OutlineLevelVec& orRowLevels, const ValueRange& rRowRange,
+ const RowModel& rModel,
+ const std::vector<sc::ColRowSpan>& rSpans,
+ 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, DFF) and updates the used area. */
+ void finalizeDrawings();
+
+ /** Update the row import progress bar */
+ void UpdateRowProgress( const ScRange& rUsedArea, SCROW nRow );
+
+private:
+ typedef ::std::unique_ptr< VmlDrawing > VmlDrawingPtr;
+
+ const ScAddress& mrMaxApiPos; /// Reference to maximum Calc cell address from address converter.
+ ScRange maUsedArea; /// Used area of the sheet, and sheet index of the sheet.
+ ColumnModel maDefColModel; /// Default column formatting.
+ ColumnModelRangeMap maColModels; /// Ranges of columns sorted by first column index.
+ RowModel maDefRowModel; /// Default row formatting.
+ RowModelRangeMap maRowModels; /// Ranges of rows sorted by first row index.
+ std::vector< HyperlinkModel > maHyperlinks; /// Cell ranges containing hyperlinks.
+ std::vector< ValidationModel > maValidations; /// Cell ranges containing data validation settings.
+ SheetDataBuffer maSheetData; /// Buffer for cell contents and cell formatting.
+ CondFormatBuffer maCondFormats; /// Buffer for conditional formatting.
+ 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.
+ WorksheetSettings maSheetSett; /// Global settings for this sheet.
+ PageSettings maPageSett; /// Page/print settings for this sheet.
+ SheetViewSettings maSheetViewSett; /// View settings for this sheet.
+ VmlDrawingPtr mxVmlDrawing; /// Collection of all VML shapes.
+ ExtLst maExtLst; /// List of extended elements
+ OUString maDrawingPath; /// Path to DrawingML fragment.
+ OUString maVmlDrawingPath; /// Path to legacy VML drawing fragment.
+ awt::Size maDrawPageSize; /// Current size of the drawing page in 1/100 mm.
+ awt::Rectangle maShapeBoundingBox; /// Bounding box for all shapes from all drawings.
+ ISegmentProgressBarRef mxProgressBar; /// Sheet progress bar.
+ bool mbFastRowProgress; /// Do we have a progress bar thread ?
+ 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.
+};
+
+constexpr OUStringLiteral gaSheetCellRanges( u"com.sun.star.sheet.SheetCellRanges" ); /// Service name for a SheetCellRanges object.
+
+WorksheetGlobals::WorksheetGlobals( const WorkbookHelper& rHelper, const ISegmentProgressBarRef& rxProgressBar, WorksheetType eSheetType, SCTAB nSheet ) :
+ WorkbookHelper( rHelper ),
+ mrMaxApiPos( rHelper.getAddressConverter().getMaxApiAddress() ),
+ maUsedArea( SCCOL_MAX, SCROW_MAX, nSheet, -1, -1, nSheet ), // Set start address to largest possible value, and end address to smallest
+ maSheetData( *this ),
+ maCondFormats( *this ),
+ maComments( *this ),
+ maAutoFilters( *this ),
+ maQueryTables( *this ),
+ maSheetSett( *this ),
+ maPageSett( *this ),
+ maSheetViewSett( *this ),
+ mxProgressBar( rxProgressBar ),
+ mbFastRowProgress( false ),
+ meSheetType( eSheetType ),
+ mxSheet(getSheetFromDoc( nSheet )),
+ mbHasDefWidth( false )
+{
+ if( !mxSheet.is() )
+ maUsedArea.aStart.SetTab( -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
+ mxVmlDrawing.reset( new VmlDrawing( *this ) );
+
+ // prepare progress bars
+ if( mxProgressBar )
+ {
+ mxRowProgress = mxProgressBar->createSegment( 0.5 );
+ mxFinalProgress = mxProgressBar->createSegment( 0.5 );
+ }
+}
+
+Reference< XCell > WorksheetGlobals::getCell( const ScAddress& rAddress ) const
+{
+ Reference< XCell > xCell;
+ if( mxSheet.is() ) try
+ {
+ xCell = mxSheet->getCellByPosition( rAddress.Col(), rAddress.Row() );
+ }
+ catch( Exception& )
+ {
+ }
+ return xCell;
+}
+
+Reference< XCellRange > WorksheetGlobals::getCellRange( const ScRange& rRange ) const
+{
+ Reference< XCellRange > xRange;
+ if( mxSheet.is() ) try
+ {
+ xRange = mxSheet->getCellRangeByPosition( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row() );
+ }
+ catch( Exception& )
+ {
+ }
+ return xRange;
+}
+
+Reference< XSheetCellRanges > WorksheetGlobals::getCellRangeList( const ScRangeList& rRanges ) const
+{
+ Reference< XSheetCellRanges > xRanges;
+ if( mxSheet.is() && !rRanges.empty() ) try
+ {
+ xRanges.set( getBaseFilter().getModelFactory()->createInstance( gaSheetCellRanges ), UNO_QUERY_THROW );
+ Reference< XSheetCellRangeContainer > xRangeCont( xRanges, UNO_QUERY_THROW );
+ xRangeCont->addRangeAddresses( AddressConverter::toApiSequence(rRanges), false );
+ }
+ catch( Exception& )
+ {
+ }
+ return xRanges;
+}
+
+Reference< XCellRange > WorksheetGlobals::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 > WorksheetGlobals::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< XDrawPage > WorksheetGlobals::getDrawPage() const
+{
+ Reference< XDrawPage > xDrawPage;
+ try
+ {
+ xDrawPage = Reference< XDrawPageSupplier >( mxSheet, UNO_QUERY_THROW )->getDrawPage();
+ }
+ catch( Exception& )
+ {
+ }
+ return xDrawPage;
+}
+
+const awt::Size& WorksheetGlobals::getDrawPageSize() const
+{
+ OSL_ENSURE( (maDrawPageSize.Width > 0) && (maDrawPageSize.Height > 0), "WorksheetGlobals::getDrawPageSize - called too early, size invalid" );
+ return maDrawPageSize;
+}
+
+awt::Point WorksheetGlobals::getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ const tools::Rectangle aMMRect( getScDocument().GetMMRect( nCol, nRow, nCol, nRow, getSheetIndex() ) );
+ awt::Point aPoint( lclClampToNonNegativeInt32( aMMRect.Left() ),
+ lclClampToNonNegativeInt32( aMMRect.Top() ) );
+ return aPoint;
+}
+
+namespace {
+
+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
+
+ScAddress WorksheetGlobals::getCellAddressFromPosition( const awt::Point& rPosition ) const
+{
+ // starting cell address and its position in drawing layer (top-left edge)
+ sal_Int32 nBegCol = 0;
+ sal_Int32 nBegRow = 0;
+ awt::Point aBegPos( 0, 0 );
+
+ // end cell address and its position in drawing layer (bottom-right edge)
+ sal_Int32 nEndCol = mrMaxApiPos.Col() + 1;
+ sal_Int32 nEndRow = mrMaxApiPos.Row() + 1;
+ awt::Point aEndPos( maDrawPageSize.Width, maDrawPageSize.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 );
+ awt::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 ScAddress( nMidCol, nMidRow, getSheetIndex() );
+}
+
+ScRange WorksheetGlobals::getCellRangeFromRectangle( const awt::Rectangle& rRect ) const
+{
+ ScAddress aStartAddr = getCellAddressFromPosition( awt::Point( rRect.X, rRect.Y ) );
+ awt::Point aBotRight( rRect.X + rRect.Width, rRect.Y + rRect.Height );
+ ScAddress aEndAddr = getCellAddressFromPosition( aBotRight );
+ bool bMultiCols = aStartAddr.Col() < aEndAddr.Col();
+ 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. */
+ awt::Point aEndPos = getCellPosition( aEndAddr.Col(), aEndAddr.Row() );
+ if( bMultiCols && (aBotRight.X <= aEndPos.X) )
+ aEndAddr.IncCol(-1);
+ if( bMultiRows && (aBotRight.Y <= aEndPos.Y) )
+ aEndAddr.IncRow(-1);
+ }
+ return ScRange( aStartAddr.Col(), aStartAddr.Row(), getSheetIndex(),
+ aEndAddr.Col(), aEndAddr.Row(), getSheetIndex() );
+}
+
+void WorksheetGlobals::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 WorksheetGlobals::setHyperlink( const HyperlinkModel& rModel )
+{
+ maHyperlinks.push_back( rModel );
+}
+
+void WorksheetGlobals::setValidation( const ValidationModel& rModel )
+{
+ maValidations.push_back( rModel );
+}
+
+void WorksheetGlobals::setDrawingPath( const OUString& rDrawingPath )
+{
+ maDrawingPath = rDrawingPath;
+}
+
+void WorksheetGlobals::setVmlDrawingPath( const OUString& rVmlDrawingPath )
+{
+ maVmlDrawingPath = rVmlDrawingPath;
+}
+
+void WorksheetGlobals::extendUsedArea( const ScAddress& rAddress )
+{
+ maUsedArea.aStart.SetCol( ::std::min( maUsedArea.aStart.Col(), rAddress.Col() ) );
+ maUsedArea.aStart.SetRow( ::std::min( maUsedArea.aStart.Row(), rAddress.Row() ) );
+ maUsedArea.aEnd.SetCol( ::std::max( maUsedArea.aEnd.Col(), rAddress.Col() ) );
+ maUsedArea.aEnd.SetRow( ::std::max( maUsedArea.aEnd.Row(), rAddress.Row() ) );
+}
+
+void WorksheetGlobals::extendUsedArea( const ScRange& rRange )
+{
+ extendUsedArea( rRange.aStart );
+ extendUsedArea( rRange.aEnd );
+}
+
+void WorksheetHelper::extendUsedArea( const ScRange& rRange )
+{
+ extendUsedArea( rRange.aStart );
+ extendUsedArea( rRange.aEnd );
+}
+
+void WorksheetGlobals::extendShapeBoundingBox( const awt::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 WorksheetGlobals::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
+ maDefColModel.mfWidth = nWidth + getUnitConverter().scaleValue( 5, Unit::ScreenX, Unit::Digit );
+ }
+}
+
+void WorksheetGlobals::setDefaultColumnWidth( double fWidth )
+{
+ // overrides a width set with setBaseColumnWidth()
+ if( fWidth > 0.0 )
+ {
+ maDefColModel.mfWidth = fWidth;
+ mbHasDefWidth = true;
+ }
+}
+
+void WorksheetGlobals::setColumnModel( const ColumnModel& rModel )
+{
+ // convert 1-based OOXML column indexes to 0-based API column indexes
+ sal_Int32 nFirstCol = rModel.maRange.mnFirst - 1;
+ sal_Int32 nLastCol = rModel.maRange.mnLast - 1;
+ if( !(getAddressConverter().checkCol( nFirstCol, true ) && (nFirstCol <= nLastCol)) )
+ return;
+
+ // Validate last column index.
+ // If last column is equal to last possible column, Excel adds one
+ // more. We do that also in XclExpColinfo::SaveXml() and for 1024 end
+ // up with 1025 instead, which would lead to excess columns in
+ // checkCol(). Cater for this oddity.
+ if (nLastCol == mrMaxApiPos.Col() + 1)
+ --nLastCol;
+ // This is totally fouled up. If we saved 1025 and the file is saved
+ // with Excel again, it increments the value to 1026.
+ else if (nLastCol == mrMaxApiPos.Col() + 2)
+ nLastCol -= 2;
+ // Excel may add a column range for the remaining columns (with
+ // <cols><col .../></cols>), even if not used or only used to grey out
+ // columns in page break view. Don't let that trigger overflow warning,
+ // so check for the last possible column. If there really is content in
+ // the range that should be caught anyway.
+ else if (nLastCol == getAddressConverter().getMaxXlsAddress().Col())
+ nLastCol = mrMaxApiPos.Col();
+ // User may have applied custom column widths to arbitrary excess
+ // columns. Ignore those and don't track as overflow columns (false).
+ // Effectively this does the same as the above cases, just keep them
+ // for explanation.
+ // Actual data present should trigger the overflow detection later.
+ else if( !getAddressConverter().checkCol( nLastCol, false ) )
+ nLastCol = mrMaxApiPos.Col();
+ // try to find entry in column model map that is able to merge with the passed model
+ bool bInsertModel = true;
+ if( !maColModels.empty() )
+ {
+ // find first column model range following nFirstCol (nFirstCol < aIt->first), or end of map
+ ColumnModelRangeMap::iterator aIt = maColModels.upper_bound( nFirstCol );
+ OSL_ENSURE( aIt == maColModels.end(), "WorksheetGlobals::setColModel - columns are unsorted" );
+ // if inserting before another column model, get last free column
+ OSL_ENSURE( (aIt == maColModels.end()) || (nLastCol < aIt->first), "WorksheetGlobals::setColModel - multiple models of the same column" );
+ if( aIt != maColModels.end() )
+ nLastCol = ::std::min( nLastCol, aIt->first - 1 );
+ if( aIt != maColModels.begin() )
+ {
+ // go to previous map element (which may be able to merge with the passed model)
+ --aIt;
+ // the usage of upper_bound() above ensures that aIt->first is less than or equal to nFirstCol now
+ sal_Int32& rnLastMapCol = aIt->second.second;
+ OSL_ENSURE( rnLastMapCol < nFirstCol, "WorksheetGlobals::setColModel - multiple models of the same column" );
+ nFirstCol = ::std::max( rnLastMapCol + 1, nFirstCol );
+ if( (rnLastMapCol + 1 == nFirstCol) && (nFirstCol <= nLastCol) && aIt->second.first.isMergeable( rModel ) )
+ {
+ // can merge with existing model, update last column index
+ rnLastMapCol = nLastCol;
+ bInsertModel = false;
+ }
+ }
+ }
+ if( nFirstCol <= nLastCol )
+ {
+ // insert the column model, if it has not been merged with another
+ if( bInsertModel )
+ maColModels[ nFirstCol ] = ColumnModelRange( rModel, nLastCol );
+ // set column formatting directly
+ convertColumnFormat( nFirstCol, nLastCol, rModel.mnXfId );
+ }
+}
+
+void WorksheetGlobals::convertColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId )
+{
+ ScRange aRange( nFirstCol, 0, getSheetIndex(), nLastCol, mrMaxApiPos.Row(), getSheetIndex() );
+ if( getAddressConverter().validateCellRange( aRange, true, false ) )
+ {
+ const StylesBuffer& rStyles = getStyles();
+
+ // Set cell styles via direct API - the preferred approach.
+ ScDocumentImport& rDoc = getDocImport();
+ rStyles.writeCellXfToDoc(rDoc, aRange, nXfId);
+ }
+}
+
+void WorksheetGlobals::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 WorksheetGlobals::setRowModel( const RowModel& rModel )
+{
+ // convert 1-based OOXML row index to 0-based API row index
+ sal_Int32 nRow = rModel.mnRow - 1;
+ if( getAddressConverter().checkRow( nRow, true ) )
+ {
+ // try to find entry in row model map that is able to merge with the passed model
+ bool bInsertModel = true;
+ bool bUnusedRow = true;
+ if( !maRowModels.empty() )
+ {
+ // find first row model range following nRow (nRow < aIt->first), or end of map
+ RowModelRangeMap::iterator aIt = maRowModels.upper_bound( nRow );
+ OSL_ENSURE( aIt == maRowModels.end(), "WorksheetGlobals::setRowModel - rows are unsorted" );
+ if( aIt != maRowModels.begin() )
+ {
+ // go to previous map element (which may be able to merge with the passed model)
+ --aIt;
+ // the usage of upper_bound() above ensures that aIt->first is less than or equal to nRow now
+ sal_Int32& rnLastMapRow = aIt->second.second;
+ bUnusedRow = rnLastMapRow < nRow;
+ OSL_ENSURE( bUnusedRow, "WorksheetGlobals::setRowModel - multiple models of the same row" );
+ if( (rnLastMapRow + 1 == nRow) && aIt->second.first.isMergeable( rModel ) )
+ {
+ // can merge with existing model, update last row index
+ ++rnLastMapRow;
+ bInsertModel = false;
+ }
+ }
+ }
+ if( bUnusedRow )
+ {
+ // insert the row model, if it has not been merged with another
+ if( bInsertModel )
+ maRowModels[ nRow ] = RowModelRange( rModel, nRow );
+ // set row formatting
+ maSheetData.setRowFormat( nRow, rModel.mnXfId, rModel.mbCustomFormat );
+ // set column spans
+ maSheetData.setColSpans( nRow, rModel.maColSpans );
+ }
+ }
+
+ UpdateRowProgress( maUsedArea, nRow );
+}
+
+// This is called at a higher frequency inside the (threaded) inner loop.
+void WorksheetGlobals::UpdateRowProgress( const ScRange& rUsedArea, SCROW nRow )
+{
+ if (!mxRowProgress || nRow < rUsedArea.aStart.Row() || rUsedArea.aEnd.Row() < nRow)
+ return;
+
+ double fNewPos = static_cast<double>(nRow - rUsedArea.aStart.Row() + 1.0) / (rUsedArea.aEnd.Row() - rUsedArea.aStart.Row() + 1.0);
+
+ if (mbFastRowProgress)
+ mxRowProgress->setPosition(fNewPos);
+ else
+ {
+ double fCurPos = mxRowProgress->getPosition();
+ if (fCurPos < fNewPos && (fNewPos - fCurPos) > 0.3)
+ // Try not to re-draw progress bar too frequently.
+ mxRowProgress->setPosition(fNewPos);
+ }
+}
+
+void WorksheetGlobals::initializeWorksheetImport()
+{
+ // set default cell style for unused cells
+ ScDocumentImport& rDoc = getDocImport();
+
+ ScStyleSheet* pStyleSheet =
+ static_cast<ScStyleSheet*>(rDoc.getDoc().GetStyleSheetPool()->Find(
+ getStyles().getDefaultStyleName(), SfxStyleFamily::Para));
+
+ if (pStyleSheet)
+ rDoc.setCellStyleToSheet(getSheetIndex(), *pStyleSheet);
+
+ /* Remember the current sheet index in global data, needed by global
+ objects, e.g. the chart converter. */
+ setCurrentSheetIndex( getSheetIndex() );
+}
+
+void WorksheetGlobals::finalizeWorksheetImport()
+{
+ lclUpdateProgressBar( mxRowProgress, 1.0 );
+ maSheetData.finalizeImport();
+ // assumes getTables().finalizeImport ( which creates the DatabaseRanges )
+ // has been called already
+ getTables().applyAutoFilters();
+
+ getCondFormats().finalizeImport();
+ lclUpdateProgressBar( mxFinalProgress, 0.25 );
+ finalizeHyperlinkRanges();
+ finalizeValidationRanges();
+ maAutoFilters.finalizeImport( getSheetIndex() );
+ maQueryTables.finalizeImport();
+ maSheetSett.finalizeImport();
+ maPageSett.finalizeImport();
+ maSheetViewSett.finalizeImport();
+
+ lclUpdateProgressBar( mxFinalProgress, 0.5 );
+ convertColumns();
+
+ // tdf#99913 rows hidden by filter need extra flag
+ ScDocument& rDoc = getScDocument();
+ std::vector<sc::ColRowSpan> aSpans;
+ SCTAB nTab = getSheetIndex();
+ ScDBData* pDBData = rDoc.GetAnonymousDBData(nTab);
+ if (pDBData && pDBData->HasAutoFilter())
+ {
+ ScRange aRange;
+ pDBData->GetArea(aRange);
+ SCCOLROW nStartRow = static_cast<SCCOLROW>(aRange.aStart.Row());
+ SCCOLROW nEndRow = static_cast<SCCOLROW>(aRange.aEnd.Row());
+ aSpans.push_back(sc::ColRowSpan(nStartRow, nEndRow));
+ }
+ ScDBCollection* pDocColl = rDoc.GetDBCollection();
+ if (!pDocColl->empty())
+ {
+ ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs();
+ for (const auto& rxDB : rDBs)
+ {
+ if (rxDB->GetTab() == nTab && rxDB->HasAutoFilter())
+ {
+ ScRange aRange;
+ rxDB->GetArea(aRange);
+ SCCOLROW nStartRow = static_cast<SCCOLROW>(aRange.aStart.Row());
+ SCCOLROW nEndRow = static_cast<SCCOLROW>(aRange.aEnd.Row());
+ aSpans.push_back(sc::ColRowSpan(nStartRow, nEndRow));
+ }
+ }
+ }
+ convertRows(aSpans);
+ lclUpdateProgressBar( mxFinalProgress, 1.0 );
+}
+
+void WorksheetGlobals::finalizeDrawingImport()
+{
+ finalizeDrawings();
+
+ // forget current sheet index in global data
+ setCurrentSheetIndex( -1 );
+}
+
+// private --------------------------------------------------------------------
+
+void WorksheetGlobals::finalizeHyperlinkRanges()
+{
+ for (auto const& link : maHyperlinks)
+ {
+ OUString aUrl = getHyperlinkUrl(link);
+ // try to insert URL into each cell of the range
+ if( !aUrl.isEmpty() )
+ for( ScAddress aAddress(link.maRange.aStart.Col(), link.maRange.aStart.Row(), getSheetIndex() ); aAddress.Row() <= link.maRange.aEnd.Row(); aAddress.IncRow() )
+ for( aAddress.SetCol(link.maRange.aStart.Col()); aAddress.Col() <= link.maRange.aEnd.Col(); aAddress.IncCol() )
+ insertHyperlink( aAddress, aUrl );
+ }
+}
+
+OUString WorksheetGlobals::getHyperlinkUrl( const HyperlinkModel& rHyperlink ) const
+{
+ OUStringBuffer aUrlBuffer;
+ if( !rHyperlink.maTarget.isEmpty() )
+ aUrlBuffer.append( getBaseFilter().getAbsoluteUrl( rHyperlink.maTarget ) );
+ if( !rHyperlink.maLocation.isEmpty() )
+ aUrlBuffer.append( '#' ).append( rHyperlink.maLocation );
+ OUString aUrl = aUrlBuffer.makeStringAndClear();
+
+ if( aUrl.startsWith("#") )
+ {
+ sal_Int32 nSepPos = aUrl.lastIndexOf( '!' );
+ if( nSepPos > 0 )
+ {
+ // Do not attempt to blindly convert '#SheetName!A1' to
+ // '#SheetName.A1', it can be #SheetName!R1C1 as well. Hyperlink
+ // handler has to handle all, but prefer '#SheetName.A1' if
+ // possible.
+ if (nSepPos < aUrl.getLength() - 1)
+ {
+ ScRange aRange;
+ const ScDocumentImport& rDoc = getDocImport();
+ if ((aRange.ParseAny( aUrl.copy( nSepPos + 1 ), rDoc.getDoc(),
+ formula::FormulaGrammar::CONV_XL_R1C1)
+ & ScRefFlags::VALID) == ScRefFlags::ZERO)
+ aUrl = aUrl.replaceAt( nSepPos, 1, rtl::OUStringChar( '.' ) );
+ }
+ // #i66592# convert sheet names that have been renamed on import
+ OUString aSheetName = aUrl.copy( 1, nSepPos - 1 );
+ OUString aCalcName = getWorksheets().getCalcSheetName( aSheetName );
+ if( !aCalcName.isEmpty() )
+ aUrl = aUrl.replaceAt( 1, nSepPos - 1, aCalcName );
+ }
+ }
+
+ return aUrl;
+}
+
+void WorksheetGlobals::insertHyperlink( const ScAddress& rAddress, const OUString& rUrl )
+{
+ ScDocumentImport& rDoc = getDocImport();
+ ScRefCellValue aCell(rDoc.getDoc(), rAddress);
+
+ if (aCell.meType == CELLTYPE_STRING || aCell.meType == CELLTYPE_EDIT)
+ {
+ OUString aStr = aCell.getString(&rDoc.getDoc());
+ ScFieldEditEngine& rEE = rDoc.getDoc().GetEditEngine();
+ rEE.Clear();
+
+ SvxURLField aURLField(rUrl, aStr, SvxURLFormat::Repr);
+ SvxFieldItem aURLItem(aURLField, EE_FEATURE_FIELD);
+ rEE.QuickInsertField(aURLItem, ESelection());
+
+ rDoc.setEditCell(rAddress, rEE.CreateTextObject());
+ }
+ else
+ {
+ // Handle other cell types e.g. formulas ( and ? ) that have associated
+ // hyperlinks.
+ // Ideally all hyperlinks should be treated as below. For the moment,
+ // given the current absence of ods support lets just handle what we
+ // previously didn't handle the new way.
+ // Unfortunately we won't be able to preserve such hyperlinks when
+ // saving to ods. Note: when we are able to save such hyperlinks to ods
+ // we should handle *all* imported hyperlinks as below ( e.g. as cell
+ // attribute ) for better interoperability.
+
+ SfxStringItem aItem(ATTR_HYPERLINK, rUrl);
+ rDoc.getDoc().ApplyAttr(rAddress.Col(), rAddress.Row(), rAddress.Tab(), aItem);
+ }
+}
+
+void WorksheetGlobals::finalizeValidationRanges() const
+{
+ for (auto const& validation : maValidations)
+ {
+ PropertySet aPropSet( getCellRangeList(validation.maRanges) );
+
+ Reference< XPropertySet > xValidation( aPropSet.getAnyProperty( PROP_Validation ), UNO_QUERY );
+ if( xValidation.is() )
+ {
+ PropertySet aValProps( xValidation );
+
+ try
+ {
+ const OUString aToken = validation.msRef.getToken( 0, ' ' );
+
+ Reference<XSpreadsheet> xSheet = getSheetFromDoc( getCurrentSheetIndex() );
+ Reference<XCellRange> xDBCellRange;
+ Reference<XCell> xCell;
+ xDBCellRange = xSheet->getCellRangeByName( aToken );
+
+ xCell = xDBCellRange->getCellByPosition( 0, 0 );
+ Reference<XCellAddressable> xCellAddressable( xCell, UNO_QUERY_THROW );
+ CellAddress aFirstCell = xCellAddressable->getCellAddress();
+ Reference<XSheetCondition> xCondition( xValidation, UNO_QUERY_THROW );
+ xCondition->setSourcePosition( aFirstCell );
+ }
+ catch(const Exception&)
+ {
+ }
+
+ // convert validation type to API enum
+ ValidationType eType = ValidationType_ANY;
+ switch( validation.mnType )
+ {
+ case XML_custom: eType = ValidationType_CUSTOM; break;
+ case XML_date: eType = ValidationType_DATE; break;
+ case XML_decimal: eType = ValidationType_DECIMAL; break;
+ case XML_list: eType = ValidationType_LIST; break;
+ case XML_none: eType = ValidationType_ANY; break;
+ case XML_textLength: eType = ValidationType_TEXT_LEN; break;
+ case XML_time: eType = ValidationType_TIME; break;
+ case XML_whole: eType = 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 = ValidationAlertStyle_STOP;
+ switch( validation.mnErrorStyle )
+ {
+ case XML_information: eAlertStyle = ValidationAlertStyle_INFO; break;
+ case XML_stop: eAlertStyle = ValidationAlertStyle_STOP; break;
+ case XML_warning: eAlertStyle = 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 = validation.mbNoDropDown ? TableValidationVisibility::INVISIBLE : TableValidationVisibility::UNSORTED;
+ aValProps.setProperty( PROP_ShowList, nVisibility );
+
+ // messages
+ aValProps.setProperty( PROP_ShowInputMessage, validation.mbShowInputMsg );
+ aValProps.setProperty( PROP_InputTitle, validation.maInputTitle );
+ aValProps.setProperty( PROP_InputMessage, validation.maInputMessage );
+ aValProps.setProperty( PROP_ShowErrorMessage, validation.mbShowErrorMsg );
+ aValProps.setProperty( PROP_ErrorTitle, validation.maErrorTitle );
+ aValProps.setProperty( PROP_ErrorMessage, validation.maErrorMessage );
+
+ // allow blank cells
+ aValProps.setProperty( PROP_IgnoreBlankCells, validation.mbAllowBlank );
+
+ try
+ {
+ // condition operator
+ Reference< XSheetCondition2 > xSheetCond( xValidation, UNO_QUERY_THROW );
+ if( eType == ValidationType_CUSTOM )
+ xSheetCond->setConditionOperator( ConditionOperator2::FORMULA );
+ else
+ xSheetCond->setConditionOperator( CondFormatBuffer::convertToApiOperator( validation.mnOperator ) );
+
+ // condition formulas
+ Reference< XMultiFormulaTokens > xTokens( xValidation, UNO_QUERY_THROW );
+ xTokens->setTokens( 0, validation.maTokens1 );
+ xTokens->setTokens( 1, validation.maTokens2 );
+ }
+ catch( Exception& )
+ {
+ }
+
+ // write back validation settings to cell range(s)
+ aPropSet.setProperty( PROP_Validation, xValidation );
+ }
+ }
+}
+
+void WorksheetGlobals::convertColumns()
+{
+ sal_Int32 nNextCol = 0;
+ sal_Int32 nMaxCol = mrMaxApiPos.Col();
+ // stores first grouped column index for each level
+ OutlineLevelVec aColLevels;
+
+ for (auto const& colModel : maColModels)
+ {
+ // column indexes are stored 0-based in maColModels
+ ValueRange aColRange( ::std::max( colModel.first, nNextCol ), ::std::min( colModel.second.second, nMaxCol ) );
+ // process gap between two column models, use default column model
+ if( nNextCol < aColRange.mnFirst )
+ convertColumns( aColLevels, ValueRange( nNextCol, aColRange.mnFirst - 1 ), maDefColModel );
+ // process the column model
+ convertColumns( aColLevels, aColRange, colModel.second.first );
+ // cache next column to be processed
+ nNextCol = aColRange.mnLast + 1;
+ }
+
+ // remaining default columns to end of sheet
+ convertColumns( aColLevels, ValueRange( nNextCol, nMaxCol ), maDefColModel );
+ // close remaining column outlines spanning to end of sheet
+ convertOutlines( aColLevels, nMaxCol + 1, 0, false, false );
+}
+
+void WorksheetGlobals::convertColumns( OutlineLevelVec& orColLevels,
+ const ValueRange& rColRange, const ColumnModel& rModel )
+{
+ // column width: convert 'number of characters' to column width in twips
+ sal_Int32 nWidth = std::round(getUnitConverter().scaleValue( rModel.mfWidth, Unit::Digit, Unit::Twip ));
+
+ SCTAB nTab = getSheetIndex();
+ ScDocument& rDoc = getScDocument();
+ SCCOL nStartCol = rColRange.mnFirst;
+ SCCOL nEndCol = rColRange.mnLast;
+
+ if( nWidth > 0 )
+ {
+ // macro sheets have double width
+ if( meSheetType == WorksheetType::Macro )
+ nWidth *= 2;
+
+ for( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
+ {
+ rDoc.SetColWidthOnly(nCol, nTab, nWidth);
+ }
+ }
+
+ // hidden columns: TODO: #108683# hide columns later?
+ if( rModel.mbHidden )
+ {
+ rDoc.SetColHidden( nStartCol, nEndCol, nTab, true );
+ }
+
+ // outline settings for this column range
+ convertOutlines( orColLevels, rColRange.mnFirst, rModel.mnLevel, rModel.mbCollapsed, false );
+}
+
+void WorksheetGlobals::convertRows(const std::vector<sc::ColRowSpan>& rSpans)
+{
+ sal_Int32 nNextRow = 0;
+ sal_Int32 nMaxRow = mrMaxApiPos.Row();
+ // stores first grouped row index for each level
+ OutlineLevelVec aRowLevels;
+
+ for (auto const& rowModel : maRowModels)
+ {
+ // row indexes are stored 0-based in maRowModels
+ ValueRange aRowRange( ::std::max( rowModel.first, nNextRow ), ::std::min( rowModel.second.second, nMaxRow ) );
+ // process gap between two row models, use default row model
+ if( nNextRow < aRowRange.mnFirst )
+ convertRows(aRowLevels, ValueRange(nNextRow, aRowRange.mnFirst - 1), maDefRowModel,
+ rSpans);
+ // process the row model
+ convertRows(aRowLevels, aRowRange, rowModel.second.first, rSpans, maDefRowModel.mfHeight);
+ // cache next row to be processed
+ nNextRow = aRowRange.mnLast + 1;
+ }
+
+ // remaining default rows to end of sheet
+ convertRows(aRowLevels, ValueRange(nNextRow, nMaxRow), maDefRowModel, rSpans);
+ // close remaining row outlines spanning to end of sheet
+ convertOutlines( aRowLevels, nMaxRow + 1, 0, false, true );
+}
+
+void WorksheetGlobals::convertRows(OutlineLevelVec& orRowLevels, const ValueRange& rRowRange,
+ const RowModel& rModel,
+ const std::vector<sc::ColRowSpan>& rSpans, double fDefHeight)
+{
+ // row height: convert points to row height in twips
+ double fHeight = (rModel.mfHeight >= 0.0) ? rModel.mfHeight : fDefHeight;
+ sal_Int32 nHeight = std::round(o3tl::toTwips( fHeight, o3tl::Length::pt ));
+ SCROW nStartRow = rRowRange.mnFirst;
+ SCROW nEndRow = rRowRange.mnLast;
+ SCTAB nTab = getSheetIndex();
+ if( nHeight > 0 )
+ {
+ /* always import the row height, ensures better layout */
+ ScDocument& rDoc = getScDocument();
+ rDoc.SetRowHeightOnly(nStartRow, nEndRow, nTab, nHeight);
+ if(rModel.mbCustomHeight)
+ rDoc.SetManualHeight( nStartRow, nEndRow, nTab, true );
+ }
+
+ // hidden rows: TODO: #108683# hide rows later?
+ if( rModel.mbHidden )
+ {
+ ScDocument& rDoc = getScDocument();
+ rDoc.SetRowHidden( nStartRow, nEndRow, nTab, true );
+ for (const auto& rSpan : rSpans)
+ {
+ // tdf#99913 rows hidden by filter need extra flag
+ if (rSpan.mnStart <= nStartRow && nStartRow <= rSpan.mnEnd)
+ {
+ SCROW nLast = ::std::min(nEndRow, rSpan.mnEnd);
+ rDoc.SetRowFiltered(nStartRow, nLast, nTab, true);
+ break;
+ }
+ }
+ }
+
+ // outline settings for this row range
+ convertOutlines( orRowLevels, rRowRange.mnFirst, rModel.mnLevel, rModel.mbCollapsed, true );
+}
+
+void WorksheetGlobals::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, "WorksheetGlobals::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.
+ orLevels.insert(orLevels.end(), nLevel - nSize, 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 WorksheetGlobals::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, TableOrientation_ROWS );
+ if( bCollapse )
+ xOutline->hideDetail( aRange );
+ }
+ else
+ {
+ CellRangeAddress aRange( getSheetIndex(), nFirstColRow, 0, nLastColRow, 0 );
+ xOutline->group( aRange, TableOrientation_COLUMNS );
+ if( bCollapse )
+ xOutline->hideDetail( aRange );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void WorksheetGlobals::finalizeDrawings()
+{
+ // calculate the current drawing page size (after rows/columns are imported)
+ const Size aPageSize( getScDocument().GetMMRect( 0, 0, mrMaxApiPos.Col(), mrMaxApiPos.Row(), getSheetIndex() ).GetSize() );
+ maDrawPageSize.Width = lclClampToNonNegativeInt32( aPageSize.Width() );
+ maDrawPageSize.Height = lclClampToNonNegativeInt32( aPageSize.Height() );
+
+ // import DML and VML
+ if( !maDrawingPath.isEmpty() )
+ importOoxFragment( new DrawingFragment( *this, maDrawingPath ) );
+ if( !maVmlDrawingPath.isEmpty() )
+ importOoxFragment( new VmlDrawingFragment( *this, maVmlDrawingPath ) );
+
+ // 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.aStart.Col() > maUsedArea.aEnd.Col() )
+ {
+ maUsedArea.aStart.SetCol( 0 );
+ maUsedArea.aEnd.SetCol( 0 );
+ }
+
+ if( maUsedArea.aStart.Row() > maUsedArea.aEnd.Row() )
+ {
+ maUsedArea.aStart.SetRow( 0 );
+ maUsedArea.aEnd.SetRow( 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, WritingMode2::RL_TB );
+ }
+}
+
+WorksheetHelper::WorksheetHelper( WorksheetGlobals& rSheetGlob ) :
+ WorkbookHelper( rSheetGlob ),
+ mrSheetGlob( rSheetGlob )
+{
+}
+
+ScDocument& WorksheetHelper::getScDocument()
+{
+ return getDocImport().getDoc();
+}
+
+/*static*/ WorksheetGlobalsRef WorksheetHelper::constructGlobals( const WorkbookHelper& rHelper,
+ const ISegmentProgressBarRef& rxProgressBar, WorksheetType eSheetType, SCTAB nSheet )
+{
+ WorksheetGlobalsRef xSheetGlob = std::make_shared<WorksheetGlobals>( rHelper, rxProgressBar, eSheetType, nSheet );
+ if( !xSheetGlob->isValidSheet() )
+ xSheetGlob.reset();
+ return xSheetGlob;
+}
+
+/* static */ IWorksheetProgress *WorksheetHelper::getWorksheetInterface( const WorksheetGlobalsRef &xRef )
+{
+ return static_cast< IWorksheetProgress *>( xRef.get() );
+}
+
+WorksheetType WorksheetHelper::getSheetType() const
+{
+ return mrSheetGlob.getSheetType();
+}
+
+SCTAB WorksheetHelper::getSheetIndex() const
+{
+ return mrSheetGlob.getSheetIndex();
+}
+
+const Reference< XSpreadsheet >& WorksheetHelper::getSheet() const
+{
+ return mrSheetGlob.getSheet();
+}
+
+Reference< XCell > WorksheetHelper::getCell( const ScAddress& rAddress ) const
+{
+ return mrSheetGlob.getCell( rAddress );
+}
+
+Reference< XCellRange > WorksheetHelper::getCellRange( const ScRange& rRange ) const
+{
+ return mrSheetGlob.getCellRange( rRange );
+}
+
+Reference< XDrawPage > WorksheetHelper::getDrawPage() const
+{
+ return mrSheetGlob.getDrawPage();
+}
+
+awt::Point WorksheetHelper::getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const
+{
+ return mrSheetGlob.getCellPosition( nCol, nRow );
+}
+
+const awt::Size& WorksheetHelper::getDrawPageSize() const
+{
+ return mrSheetGlob.getDrawPageSize();
+}
+
+SheetDataBuffer& WorksheetHelper::getSheetData() const
+{
+ return mrSheetGlob.getSheetData();
+}
+
+CondFormatBuffer& WorksheetHelper::getCondFormats() const
+{
+ return mrSheetGlob.getCondFormats();
+}
+
+CommentsBuffer& WorksheetHelper::getComments() const
+{
+ return mrSheetGlob.getComments();
+}
+
+AutoFilterBuffer& WorksheetHelper::getAutoFilters() const
+{
+ return mrSheetGlob.getAutoFilters();
+}
+
+QueryTableBuffer& WorksheetHelper::getQueryTables() const
+{
+ return mrSheetGlob.getQueryTables();
+}
+
+WorksheetSettings& WorksheetHelper::getWorksheetSettings() const
+{
+ return mrSheetGlob.getWorksheetSettings();
+}
+
+PageSettings& WorksheetHelper::getPageSettings() const
+{
+ return mrSheetGlob.getPageSettings();
+}
+
+SheetViewSettings& WorksheetHelper::getSheetViewSettings() const
+{
+ return mrSheetGlob.getSheetViewSettings();
+}
+
+VmlDrawing& WorksheetHelper::getVmlDrawing() const
+{
+ return mrSheetGlob.getVmlDrawing();
+}
+
+ExtLst& WorksheetHelper::getExtLst() const
+{
+ return mrSheetGlob.getExtLst();
+}
+
+void WorksheetHelper::setPageBreak( const PageBreakModel& rModel, bool bRowBreak )
+{
+ mrSheetGlob.setPageBreak( rModel, bRowBreak );
+}
+
+void WorksheetHelper::setHyperlink( const HyperlinkModel& rModel )
+{
+ mrSheetGlob.setHyperlink( rModel );
+}
+
+void WorksheetHelper::setValidation( const ValidationModel& rModel )
+{
+ mrSheetGlob.setValidation( rModel );
+}
+
+void WorksheetHelper::setDrawingPath( const OUString& rDrawingPath )
+{
+ mrSheetGlob.setDrawingPath( rDrawingPath );
+}
+
+void WorksheetHelper::setVmlDrawingPath( const OUString& rVmlDrawingPath )
+{
+ mrSheetGlob.setVmlDrawingPath( rVmlDrawingPath );
+}
+
+void WorksheetHelper::extendUsedArea( const ScAddress& rAddress )
+{
+ mrSheetGlob.extendUsedArea( rAddress );
+}
+
+void WorksheetHelper::extendShapeBoundingBox( const awt::Rectangle& rShapeRect )
+{
+ mrSheetGlob.extendShapeBoundingBox( rShapeRect );
+}
+
+void WorksheetHelper::setBaseColumnWidth( sal_Int32 nWidth )
+{
+ mrSheetGlob.setBaseColumnWidth( nWidth );
+}
+
+void WorksheetHelper::setDefaultColumnWidth( double fWidth )
+{
+ mrSheetGlob.setDefaultColumnWidth( fWidth );
+}
+
+void WorksheetHelper::setColumnModel( const ColumnModel& rModel )
+{
+ mrSheetGlob.setColumnModel( rModel );
+}
+
+void WorksheetHelper::setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom )
+{
+ mrSheetGlob.setDefaultRowSettings( fHeight, bCustomHeight, bHidden, bThickTop, bThickBottom );
+}
+
+void WorksheetHelper::setRowModel( const RowModel& rModel )
+{
+ mrSheetGlob.setRowModel( rModel );
+}
+
+void WorksheetHelper::setCellFormulaValue(
+ const ScAddress& rAddress, const OUString& rValueStr, sal_Int32 nCellType )
+{
+ getFormulaBuffer().setCellFormulaValue(rAddress, rValueStr, nCellType);
+}
+
+void WorksheetHelper::putRichString( const ScAddress& rAddress, const RichString& rString, const oox::xls::Font* pFirstPortionFont )
+{
+ ScEditEngineDefaulter& rEE = getEditEngine();
+
+ // The cell will own the text object instance returned from convert().
+ getDocImport().setEditCell(rAddress, rString.convert(rEE, pFirstPortionFont));
+}
+
+void WorksheetHelper::putFormulaTokens( const ScAddress& rAddress, const ApiTokenSequence& rTokens )
+{
+ ScDocumentImport& rDoc = getDocImport();
+ std::unique_ptr<ScTokenArray> pTokenArray(new ScTokenArray(rDoc.getDoc()));
+ ScTokenConversion::ConvertToTokenArray(rDoc.getDoc(), *pTokenArray, rTokens);
+ rDoc.setFormulaCell(rAddress, std::move(pTokenArray));
+}
+
+void WorksheetHelper::initializeWorksheetImport()
+{
+ mrSheetGlob.initializeWorksheetImport();
+}
+
+void WorksheetHelper::finalizeWorksheetImport()
+{
+ mrSheetGlob.finalizeWorksheetImport();
+}
+
+void WorksheetHelper::finalizeDrawingImport()
+{
+ mrSheetGlob.finalizeDrawingImport();
+}
+
+void WorksheetHelper::setCellFormula( const ScAddress& rTokenAddress, const OUString& rTokenStr )
+{
+ getFormulaBuffer().setCellFormula( rTokenAddress, rTokenStr );
+}
+
+void WorksheetHelper::setCellFormula(
+ const ScAddress& rAddr, sal_Int32 nSharedId,
+ const OUString& rCellValue, sal_Int32 nValueType )
+{
+ getFormulaBuffer().setCellFormula(rAddr, nSharedId, rCellValue, nValueType);
+}
+
+void WorksheetHelper::setCellArrayFormula( const ScRange& rRangeAddress, const ScAddress& rTokenAddress, const OUString& rTokenStr )
+{
+ getFormulaBuffer().setCellArrayFormula( rRangeAddress, rTokenAddress, rTokenStr );
+}
+
+void WorksheetHelper::createSharedFormulaMapEntry(
+ const ScAddress& rAddress, sal_Int32 nSharedId, const OUString& rTokens )
+{
+ getFormulaBuffer().createSharedFormulaMapEntry(rAddress, nSharedId, rTokens);
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */