xref: /trunk/main/oox/source/xls/worksheethelper.cxx (revision 0dac23a0)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "oox/xls/worksheethelper.hxx"
29 
30 #include <algorithm>
31 #include <list>
32 #include <utility>
33 #include <com/sun/star/awt/Point.hpp>
34 #include <com/sun/star/awt/Size.hpp>
35 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
36 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
37 #include <com/sun/star/sheet/TableValidationVisibility.hpp>
38 #include <com/sun/star/sheet/ValidationType.hpp>
39 #include <com/sun/star/sheet/ValidationAlertStyle.hpp>
40 #include <com/sun/star/sheet/XCellAddressable.hpp>
41 #include <com/sun/star/sheet/XCellRangeAddressable.hpp>
42 #include <com/sun/star/sheet/XFormulaTokens.hpp>
43 #include <com/sun/star/sheet/XLabelRanges.hpp>
44 #include <com/sun/star/sheet/XMultiFormulaTokens.hpp>
45 #include <com/sun/star/sheet/XSheetCellRangeContainer.hpp>
46 #include <com/sun/star/sheet/XSheetCondition.hpp>
47 #include <com/sun/star/sheet/XSheetOutline.hpp>
48 #include <com/sun/star/sheet/XSpreadsheet.hpp>
49 #include <com/sun/star/table/XColumnRowRange.hpp>
50 #include <com/sun/star/text/WritingMode2.hpp>
51 #include <com/sun/star/text/XText.hpp>
52 #include <rtl/ustrbuf.hxx>
53 #include "oox/core/filterbase.hxx"
54 #include "oox/helper/propertyset.hxx"
55 #include "oox/xls/addressconverter.hxx"
56 #include "oox/xls/autofilterbuffer.hxx"
57 #include "oox/xls/commentsbuffer.hxx"
58 #include "oox/xls/condformatbuffer.hxx"
59 #include "oox/xls/drawingfragment.hxx"
60 #include "oox/xls/drawingmanager.hxx"
61 #include "oox/xls/formulaparser.hxx"
62 #include "oox/xls/pagesettings.hxx"
63 #include "oox/xls/querytablebuffer.hxx"
64 #include "oox/xls/sharedstringsbuffer.hxx"
65 #include "oox/xls/sheetdatabuffer.hxx"
66 #include "oox/xls/stylesbuffer.hxx"
67 #include "oox/xls/unitconverter.hxx"
68 #include "oox/xls/viewsettings.hxx"
69 #include "oox/xls/workbooksettings.hxx"
70 #include "oox/xls/worksheetbuffer.hxx"
71 #include "oox/xls/worksheetsettings.hxx"
72 
73 namespace oox {
74 namespace xls {
75 
76 // ============================================================================
77 
78 using namespace ::com::sun::star::awt;
79 using namespace ::com::sun::star::beans;
80 using namespace ::com::sun::star::drawing;
81 using namespace ::com::sun::star::lang;
82 using namespace ::com::sun::star::sheet;
83 using namespace ::com::sun::star::table;
84 using namespace ::com::sun::star::text;
85 using namespace ::com::sun::star::uno;
86 using namespace ::com::sun::star::util;
87 
88 using ::rtl::OUString;
89 using ::rtl::OUStringBuffer;
90 
91 // ============================================================================
92 
93 namespace {
94 
95 void lclUpdateProgressBar( const ISegmentProgressBarRef& rxProgressBar, const CellRangeAddress& rUsedArea, sal_Int32 nRow )
96 {
97     if( rxProgressBar.get() && (rUsedArea.StartRow <= nRow) && (nRow <= rUsedArea.EndRow) )
98     {
99         double fPosition = static_cast< double >( nRow - rUsedArea.StartRow + 1 ) / (rUsedArea.EndRow - rUsedArea.StartRow + 1);
100         if( rxProgressBar->getPosition() < fPosition )
101             rxProgressBar->setPosition( fPosition );
102     }
103 }
104 
105 void lclUpdateProgressBar( const ISegmentProgressBarRef& rxProgressBar, double fPosition )
106 {
107     if( rxProgressBar.get() )
108         rxProgressBar->setPosition( fPosition );
109 }
110 
111 } // namespace
112 
113 // ============================================================================
114 // ============================================================================
115 
116 ColumnModel::ColumnModel() :
117     maRange( -1 ),
118     mfWidth( 0.0 ),
119     mnXfId( -1 ),
120     mnLevel( 0 ),
121     mbShowPhonetic( false ),
122     mbHidden( false ),
123     mbCollapsed( false )
124 {
125 }
126 
127 bool ColumnModel::isMergeable( const ColumnModel& rModel ) const
128 {
129     return
130         (maRange.mnFirst        <= rModel.maRange.mnFirst) &&
131         (rModel.maRange.mnFirst <= maRange.mnLast + 1) &&
132         (mfWidth                == rModel.mfWidth) &&
133         // ignore mnXfId, cell formatting is always set directly
134         (mnLevel                == rModel.mnLevel) &&
135         (mbHidden               == rModel.mbHidden) &&
136         (mbCollapsed            == rModel.mbCollapsed);
137 }
138 
139 // ----------------------------------------------------------------------------
140 
141 RowModel::RowModel() :
142     mnRow( -1 ),
143     mfHeight( 0.0 ),
144     mnXfId( -1 ),
145     mnLevel( 0 ),
146     mbCustomHeight( false ),
147     mbCustomFormat( false ),
148     mbShowPhonetic( false ),
149     mbHidden( false ),
150     mbCollapsed( false ),
151     mbThickTop( false ),
152     mbThickBottom( false )
153 {
154 }
155 
156 void RowModel::insertColSpan( const ValueRange& rColSpan )
157 {
158     if( (0 <= rColSpan.mnFirst) && (rColSpan.mnFirst <= rColSpan.mnLast) )
159         maColSpans.insert( rColSpan );
160 }
161 
162 bool RowModel::isMergeable( const RowModel& rModel ) const
163 {
164     return
165         // ignore maColSpans - is handled separately in SheetDataBuffer class
166         (mfHeight       == rModel.mfHeight) &&
167         // ignore mnXfId, mbCustomFormat, mbShowPhonetic - cell formatting is always set directly
168         (mnLevel        == rModel.mnLevel) &&
169         (mbCustomHeight == rModel.mbCustomHeight) &&
170         (mbHidden       == rModel.mbHidden) &&
171         (mbCollapsed    == rModel.mbCollapsed);
172 }
173 
174 // ----------------------------------------------------------------------------
175 
176 PageBreakModel::PageBreakModel() :
177     mnColRow( 0 ),
178     mbManual( false )
179 {
180 }
181 
182 // ----------------------------------------------------------------------------
183 
184 HyperlinkModel::HyperlinkModel()
185 {
186 }
187 
188 // ----------------------------------------------------------------------------
189 
190 ValidationModel::ValidationModel() :
191     mnType( XML_none ),
192     mnOperator( XML_between ),
193     mnErrorStyle( XML_stop ),
194     mbShowInputMsg( false ),
195     mbShowErrorMsg( false ),
196     mbNoDropDown( false ),
197     mbAllowBlank( false )
198 {
199 }
200 
201 void ValidationModel::setBiffType( sal_uInt8 nType )
202 {
203     static const sal_Int32 spnTypeIds[] = {
204         XML_none, XML_whole, XML_decimal, XML_list, XML_date, XML_time, XML_textLength, XML_custom };
205     mnType = STATIC_ARRAY_SELECT( spnTypeIds, nType, XML_none );
206 }
207 
208 void ValidationModel::setBiffOperator( sal_uInt8 nOperator )
209 {
210     static const sal_Int32 spnOperators[] = {
211         XML_between, XML_notBetween, XML_equal, XML_notEqual,
212         XML_greaterThan, XML_lessThan, XML_greaterThanOrEqual, XML_lessThanOrEqual };
213     mnOperator = STATIC_ARRAY_SELECT( spnOperators, nOperator, XML_TOKEN_INVALID );
214 }
215 
216 void ValidationModel::setBiffErrorStyle( sal_uInt8 nErrorStyle )
217 {
218     static const sal_Int32 spnErrorStyles[] = { XML_stop, XML_warning, XML_information };
219     mnErrorStyle = STATIC_ARRAY_SELECT( spnErrorStyles, nErrorStyle, XML_stop );
220 }
221 
222 // ============================================================================
223 // ============================================================================
224 
225 class WorksheetGlobals : public WorkbookHelper
226 {
227 public:
228     explicit            WorksheetGlobals(
229                             const WorkbookHelper& rHelper,
230                             const ISegmentProgressBarRef& rxProgressBar,
231                             WorksheetType eSheetType,
232                             sal_Int16 nSheet );
233 
234     /** Returns true, if this helper refers to an existing Calc sheet. */
235     inline bool         isValidSheet() const { return mxSheet.is(); }
236 
237     /** Returns the type of this sheet. */
238     inline WorksheetType getSheetType() const { return meSheetType; }
239     /** Returns the index of the current sheet. */
240     inline sal_Int16    getSheetIndex() const { return maUsedArea.Sheet; }
241     /** Returns the XSpreadsheet interface of the current sheet. */
242     inline const Reference< XSpreadsheet >& getSheet() const { return mxSheet; }
243 
244     /** Returns the XCell interface for the passed cell address. */
245     Reference< XCell >  getCell( const CellAddress& rAddress ) const;
246     /** Returns the XCellRange interface for the passed cell range address. */
247     Reference< XCellRange > getCellRange( const CellRangeAddress& rRange ) const;
248     /** Returns the XSheetCellRanges interface for the passed cell range addresses. */
249     Reference< XSheetCellRanges > getCellRangeList( const ApiCellRangeList& rRanges ) const;
250 
251     /** Returns the XCellRange interface for a column. */
252     Reference< XCellRange > getColumn( sal_Int32 nCol ) const;
253     /** Returns the XCellRange interface for a row. */
254     Reference< XCellRange > getRow( sal_Int32 nRow ) const;
255 
256     /** Returns the XTableColumns interface for a range of columns. */
257     Reference< XTableColumns > getColumns( const ValueRange& rColRange ) const;
258     /** Returns the XTableRows interface for a range of rows. */
259     Reference< XTableRows > getRows( const ValueRange& rRowRange ) const;
260 
261     /** Returns the XDrawPage interface of the draw page of the current sheet. */
262     Reference< XDrawPage > getDrawPage() const;
263     /** Returns the size of the entire drawing page in 1/100 mm. */
264     const Size&         getDrawPageSize() const;
265 
266     /** Returns the absolute position of the top-left corner of the cell in 1/100 mm. */
267     Point               getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const;
268     /** Returns the size of the cell in 1/100 mm. */
269     Size                getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const;
270 
271     /** Returns the address of the cell that contains the passed point in 1/100 mm. */
272     CellAddress         getCellAddressFromPosition( const Point& rPosition ) const;
273     /** Returns the cell range address that contains the passed rectangle in 1/100 mm. */
274     CellRangeAddress    getCellRangeFromRectangle( const Rectangle& rRect ) const;
275 
276     /** Returns the buffer for cell contents and cell formatting. */
277     inline SheetDataBuffer& getSheetData() { return maSheetData; }
278     /** Returns the conditional formattings in this sheet. */
279     inline CondFormatBuffer& getCondFormats() { return maCondFormats; }
280     /** Returns the buffer for all cell comments in this sheet. */
281     inline CommentsBuffer& getComments() { return maComments; }
282     /** Returns the auto filters for the sheet. */
283     inline AutoFilterBuffer& getAutoFilters() { return maAutoFilters; }
284     /** Returns the buffer for all web query tables in this sheet. */
285     inline QueryTableBuffer& getQueryTables() { return maQueryTables; }
286     /** Returns the worksheet settings object. */
287     inline WorksheetSettings& getWorksheetSettings() { return maSheetSett; }
288     /** Returns the page/print settings for this sheet. */
289     inline PageSettings& getPageSettings() { return maPageSett; }
290     /** Returns the view settings for this sheet. */
291     inline SheetViewSettings& getSheetViewSettings() { return maSheetViewSett; }
292     /** Returns the VML drawing page for this sheet (OOXML/BIFF12 only). */
293     inline VmlDrawing&  getVmlDrawing() { return *mxVmlDrawing; }
294     /** Returns the BIFF drawing page for this sheet (BIFF2-BIFF8 only). */
295     inline BiffSheetDrawing& getBiffDrawing() const { return *mxBiffDrawing; }
296 
297     /** Changes the current sheet type. */
298     inline void         setSheetType( WorksheetType eSheetType ) { meSheetType = eSheetType; }
299     /** Sets a column or row page break described in the passed struct. */
300     void                setPageBreak( const PageBreakModel& rModel, bool bRowBreak );
301     /** Inserts the hyperlink URL into the spreadsheet. */
302     void                setHyperlink( const HyperlinkModel& rModel );
303     /** Inserts the data validation settings into the spreadsheet. */
304     void                setValidation( const ValidationModel& rModel );
305     /** Sets the path to the DrawingML fragment of this sheet. */
306     void                setDrawingPath( const OUString& rDrawingPath );
307     /** Sets the path to the legacy VML drawing fragment of this sheet. */
308     void                setVmlDrawingPath( const OUString& rVmlDrawingPath );
309 
310     /** Extends the used area of this sheet by the passed cell position. */
311     void                extendUsedArea( const CellAddress& rAddress );
312     /** Extends the used area of this sheet by the passed cell range. */
313     void                extendUsedArea( const CellRangeAddress& rRange );
314     /** Extends the shape bounding box by the position and size of the passed rectangle. */
315     void                extendShapeBoundingBox( const Rectangle& rShapeRect );
316 
317     /** Sets base width for all columns (without padding pixels). This value
318         is only used, if base width has not been set with setDefaultColumnWidth(). */
319     void                setBaseColumnWidth( sal_Int32 nWidth );
320     /** Sets default width for all columns. This function overrides the base
321         width set with the setBaseColumnWidth() function. */
322     void                setDefaultColumnWidth( double fWidth );
323     /** Sets column settings for a specific column range.
324         @descr  Column default formatting is converted directly, other settings
325         are cached and converted in the finalizeImport() call. */
326     void                setColumnModel( const ColumnModel& rModel );
327     /** Converts column default cell formatting. */
328     void                convertColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId ) const;
329 
330     /** Sets default height and hidden state for all unused rows in the sheet. */
331     void                setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom );
332     /** Sets row settings for a specific row.
333         @descr  Row default formatting is converted directly, other settings
334         are cached and converted in the finalizeImport() call. */
335     void                setRowModel( const RowModel& rModel );
336     /** Specifies that the passed row needs to set its height manually. */
337     void                setManualRowHeight( sal_Int32 nRow );
338 
339     /** Initial conversion before importing the worksheet. */
340     void                initializeWorksheetImport();
341     /** Final conversion after importing the worksheet. */
342     void                finalizeWorksheetImport();
343 
344 private:
345     typedef ::std::vector< sal_Int32 >                  OutlineLevelVec;
346     typedef ::std::pair< ColumnModel, sal_Int32 >       ColumnModelRange;
347     typedef ::std::map< sal_Int32, ColumnModelRange >   ColumnModelRangeMap;
348     typedef ::std::pair< RowModel, sal_Int32 >          RowModelRange;
349     typedef ::std::map< sal_Int32, RowModelRange >      RowModelRangeMap;
350     typedef ::std::list< HyperlinkModel >               HyperlinkModelList;
351     typedef ::std::list< ValidationModel >              ValidationModelList;
352 
353     /** Inserts all imported hyperlinks into their cell ranges. */
354     void                finalizeHyperlinkRanges() const;
355     /** Generates the final URL for the passed hyperlink. */
356     OUString            getHyperlinkUrl( const HyperlinkModel& rHyperlink ) const;
357     /** Inserts a hyperlinks into the specified cell. */
358     void                insertHyperlink( const CellAddress& rAddress, const OUString& rUrl ) const;
359 
360     /** Inserts all imported data validations into their cell ranges. */
361     void                finalizeValidationRanges() const;
362 
363     /** Converts column properties for all columns in the sheet. */
364     void                convertColumns();
365     /** Converts column properties. */
366     void                convertColumns( OutlineLevelVec& orColLevels, const ValueRange& rColRange, const ColumnModel& rModel );
367 
368     /** Converts row properties for all rows in the sheet. */
369     void                convertRows();
370     /** Converts row properties. */
371     void                convertRows( OutlineLevelVec& orRowLevels, const ValueRange& rRowRange, const RowModel& rModel, double fDefHeight = -1.0 );
372 
373     /** Converts outline grouping for the passed column or row. */
374     void                convertOutlines( OutlineLevelVec& orLevels, sal_Int32 nColRow, sal_Int32 nLevel, bool bCollapsed, bool bRows );
375     /** Groups columns or rows for the given range. */
376     void                groupColumnsOrRows( sal_Int32 nFirstColRow, sal_Int32 nLastColRow, bool bCollapsed, bool bRows );
377 
378     /** Imports the drawings of the sheet (DML, VML, DFF) and updates the used area. */
379     void                finalizeDrawings();
380 
381 private:
382     typedef ::std::auto_ptr< VmlDrawing >       VmlDrawingPtr;
383     typedef ::std::auto_ptr< BiffSheetDrawing > BiffSheetDrawingPtr;
384 
385     const OUString      maSheetCellRanges;  /// Service name for a SheetCellRanges object.
386     const OUString      maUrlTextField;     /// Service name for a URL text field.
387     const CellAddress&  mrMaxApiPos;        /// Reference to maximum Calc cell address from address converter.
388     CellRangeAddress    maUsedArea;         /// Used area of the sheet, and sheet index of the sheet.
389     ColumnModel         maDefColModel;      /// Default column formatting.
390     ColumnModelRangeMap maColModels;        /// Ranges of columns sorted by first column index.
391     RowModel            maDefRowModel;      /// Default row formatting.
392     RowModelRangeMap    maRowModels;        /// Ranges of rows sorted by first row index.
393     HyperlinkModelList  maHyperlinks;       /// Cell ranges containing hyperlinks.
394     ValidationModelList maValidations;      /// Cell ranges containing data validation settings.
395     ValueRangeSet       maManualRowHeights; /// Rows that need manual height independent from own settings.
396     SheetDataBuffer     maSheetData;        /// Buffer for cell contents and cell formatting.
397     CondFormatBuffer    maCondFormats;      /// Buffer for conditional formattings.
398     CommentsBuffer      maComments;         /// Buffer for all cell comments in this sheet.
399     AutoFilterBuffer    maAutoFilters;      /// Sheet auto filters (not associated to a table).
400     QueryTableBuffer    maQueryTables;      /// Buffer for all web query tables in this sheet.
401     WorksheetSettings   maSheetSett;        /// Global settings for this sheet.
402     PageSettings        maPageSett;         /// Page/print settings for this sheet.
403     SheetViewSettings   maSheetViewSett;    /// View settings for this sheet.
404     VmlDrawingPtr       mxVmlDrawing;       /// Collection of all VML shapes.
405     BiffSheetDrawingPtr mxBiffDrawing;      /// Collection of all BIFF/DFF shapes.
406     OUString            maDrawingPath;      /// Path to DrawingML fragment.
407     OUString            maVmlDrawingPath;   /// Path to legacy VML drawing fragment.
408     Size                maDrawPageSize;     /// Current size of the drawing page in 1/100 mm.
409     Rectangle           maShapeBoundingBox; /// Bounding box for all shapes from all drawings.
410     ISegmentProgressBarRef mxProgressBar;   /// Sheet progress bar.
411     ISegmentProgressBarRef mxRowProgress;   /// Progress bar for row/cell processing.
412     ISegmentProgressBarRef mxFinalProgress; /// Progress bar for finalization.
413     WorksheetType       meSheetType;        /// Type of this sheet.
414     Reference< XSpreadsheet > mxSheet;      /// Reference to the current sheet.
415     bool                mbHasDefWidth;      /// True = default column width is set from defaultColWidth attribute.
416 };
417 
418 // ----------------------------------------------------------------------------
419 
420 WorksheetGlobals::WorksheetGlobals( const WorkbookHelper& rHelper, const ISegmentProgressBarRef& rxProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) :
421     WorkbookHelper( rHelper ),
422     maSheetCellRanges( CREATE_OUSTRING( "com.sun.star.sheet.SheetCellRanges" ) ),
423     maUrlTextField( CREATE_OUSTRING( "com.sun.star.text.TextField.URL" ) ),
424     mrMaxApiPos( rHelper.getAddressConverter().getMaxApiAddress() ),
425     maUsedArea( nSheet, SAL_MAX_INT32, SAL_MAX_INT32, -1, -1 ),
426     maSheetData( *this ),
427     maCondFormats( *this ),
428     maComments( *this ),
429     maAutoFilters( *this ),
430     maQueryTables( *this ),
431     maSheetSett( *this ),
432     maPageSett( *this ),
433     maSheetViewSett( *this ),
434     mxProgressBar( rxProgressBar ),
435     meSheetType( eSheetType ),
436     mbHasDefWidth( false )
437 {
438     mxSheet = getSheetFromDoc( nSheet );
439     if( !mxSheet.is() )
440         maUsedArea.Sheet = -1;
441 
442     // default column settings (width and hidden state may be updated later)
443     maDefColModel.mfWidth = 8.5;
444     maDefColModel.mnXfId = -1;
445     maDefColModel.mnLevel = 0;
446     maDefColModel.mbHidden = false;
447     maDefColModel.mbCollapsed = false;
448 
449     // default row settings (height and hidden state may be updated later)
450     maDefRowModel.mfHeight = 0.0;
451     maDefRowModel.mnXfId = -1;
452     maDefRowModel.mnLevel = 0;
453     maDefRowModel.mbCustomHeight = false;
454     maDefRowModel.mbCustomFormat = false;
455     maDefRowModel.mbShowPhonetic = false;
456     maDefRowModel.mbHidden = false;
457     maDefRowModel.mbCollapsed = false;
458 
459     // buffers
460     switch( getFilterType() )
461     {
462         case FILTER_OOXML:
463             mxVmlDrawing.reset( new VmlDrawing( *this ) );
464         break;
465         case FILTER_BIFF:
466             mxBiffDrawing.reset( new BiffSheetDrawing( *this ) );
467         break;
468         case FILTER_UNKNOWN:
469         break;
470     }
471 
472     // prepare progress bars
473     if( mxProgressBar.get() )
474     {
475         mxRowProgress = mxProgressBar->createSegment( 0.5 );
476         mxFinalProgress = mxProgressBar->createSegment( 0.5 );
477     }
478 }
479 
480 Reference< XCell > WorksheetGlobals::getCell( const CellAddress& rAddress ) const
481 {
482     Reference< XCell > xCell;
483     if( mxSheet.is() ) try
484     {
485         xCell = mxSheet->getCellByPosition( rAddress.Column, rAddress.Row );
486     }
487     catch( Exception& )
488     {
489     }
490     return xCell;
491 }
492 
493 Reference< XCellRange > WorksheetGlobals::getCellRange( const CellRangeAddress& rRange ) const
494 {
495     Reference< XCellRange > xRange;
496     if( mxSheet.is() ) try
497     {
498         xRange = mxSheet->getCellRangeByPosition( rRange.StartColumn, rRange.StartRow, rRange.EndColumn, rRange.EndRow );
499     }
500     catch( Exception& )
501     {
502     }
503     return xRange;
504 }
505 
506 Reference< XSheetCellRanges > WorksheetGlobals::getCellRangeList( const ApiCellRangeList& rRanges ) const
507 {
508     Reference< XSheetCellRanges > xRanges;
509     if( mxSheet.is() && !rRanges.empty() ) try
510     {
511         xRanges.set( getBaseFilter().getModelFactory()->createInstance( maSheetCellRanges ), UNO_QUERY_THROW );
512         Reference< XSheetCellRangeContainer > xRangeCont( xRanges, UNO_QUERY_THROW );
513         xRangeCont->addRangeAddresses( ContainerHelper::vectorToSequence( rRanges ), sal_False );
514     }
515     catch( Exception& )
516     {
517     }
518     return xRanges;
519 }
520 
521 Reference< XCellRange > WorksheetGlobals::getColumn( sal_Int32 nCol ) const
522 {
523     Reference< XCellRange > xColumn;
524     try
525     {
526         Reference< XColumnRowRange > xColRowRange( mxSheet, UNO_QUERY_THROW );
527         Reference< XTableColumns > xColumns( xColRowRange->getColumns(), UNO_SET_THROW );
528         xColumn.set( xColumns->getByIndex( nCol ), UNO_QUERY );
529     }
530     catch( Exception& )
531     {
532     }
533     return xColumn;
534 }
535 
536 Reference< XCellRange > WorksheetGlobals::getRow( sal_Int32 nRow ) const
537 {
538     Reference< XCellRange > xRow;
539     try
540     {
541         Reference< XColumnRowRange > xColRowRange( mxSheet, UNO_QUERY_THROW );
542         Reference< XTableRows > xRows( xColRowRange->getRows(), UNO_SET_THROW );
543         xRow.set( xRows->getByIndex( nRow ), UNO_QUERY );
544     }
545     catch( Exception& )
546     {
547     }
548     return xRow;
549 }
550 
551 Reference< XTableColumns > WorksheetGlobals::getColumns( const ValueRange& rColRange ) const
552 {
553     Reference< XTableColumns > xColumns;
554     sal_Int32 nLastCol = ::std::min( rColRange.mnLast, mrMaxApiPos.Column );
555     if( (0 <= rColRange.mnFirst) && (rColRange.mnFirst <= nLastCol) )
556     {
557         Reference< XColumnRowRange > xRange( getCellRange( CellRangeAddress( getSheetIndex(), rColRange.mnFirst, 0, nLastCol, 0 ) ), UNO_QUERY );
558         if( xRange.is() )
559             xColumns = xRange->getColumns();
560     }
561     return xColumns;
562 }
563 
564 Reference< XTableRows > WorksheetGlobals::getRows( const ValueRange& rRowRange ) const
565 {
566     Reference< XTableRows > xRows;
567     sal_Int32 nLastRow = ::std::min( rRowRange.mnLast, mrMaxApiPos.Row );
568     if( (0 <= rRowRange.mnFirst) && (rRowRange.mnFirst <= nLastRow) )
569     {
570         Reference< XColumnRowRange > xRange( getCellRange( CellRangeAddress( getSheetIndex(), 0, rRowRange.mnFirst, 0, nLastRow ) ), UNO_QUERY );
571         if( xRange.is() )
572             xRows = xRange->getRows();
573     }
574     return xRows;
575 }
576 
577 Reference< XDrawPage > WorksheetGlobals::getDrawPage() const
578 {
579     Reference< XDrawPage > xDrawPage;
580     try
581     {
582         xDrawPage = Reference< XDrawPageSupplier >( mxSheet, UNO_QUERY_THROW )->getDrawPage();
583     }
584     catch( Exception& )
585     {
586     }
587     return xDrawPage;
588 }
589 
590 const Size& WorksheetGlobals::getDrawPageSize() const
591 {
592     OSL_ENSURE( (maDrawPageSize.Width > 0) && (maDrawPageSize.Height > 0), "WorksheetGlobals::getDrawPageSize - called too early, size invalid" );
593     return maDrawPageSize;
594 }
595 
596 Point WorksheetGlobals::getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const
597 {
598     Point aPoint;
599     PropertySet aCellProp( getCell( CellAddress( getSheetIndex(), nCol, nRow ) ) );
600     aCellProp.getProperty( aPoint, PROP_Position );
601     return aPoint;
602 }
603 
604 Size WorksheetGlobals::getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const
605 {
606     Size aSize;
607     PropertySet aCellProp( getCell( CellAddress( getSheetIndex(), nCol, nRow ) ) );
608     aCellProp.getProperty( aSize, PROP_Size );
609     return aSize;
610 }
611 
612 namespace {
613 
614 inline sal_Int32 lclGetMidAddr( sal_Int32 nBegAddr, sal_Int32 nEndAddr, sal_Int32 nBegPos, sal_Int32 nEndPos, sal_Int32 nSearchPos )
615 {
616     // use sal_Int64 to prevent integer overflow
617     return nBegAddr + 1 + static_cast< sal_Int32 >( static_cast< sal_Int64 >( nEndAddr - nBegAddr - 2 ) * (nSearchPos - nBegPos) / (nEndPos - nBegPos) );
618 }
619 
620 bool lclPrepareInterval( sal_Int32 nBegAddr, sal_Int32& rnMidAddr, sal_Int32 nEndAddr,
621         sal_Int32 nBegPos, sal_Int32 nEndPos, sal_Int32 nSearchPos )
622 {
623     // searched position before nBegPos -> use nBegAddr
624     if( nSearchPos <= nBegPos )
625     {
626         rnMidAddr = nBegAddr;
627         return false;
628     }
629 
630     // searched position after nEndPos, or begin next to end -> use nEndAddr
631     if( (nSearchPos >= nEndPos) || (nBegAddr + 1 >= nEndAddr) )
632     {
633         rnMidAddr = nEndAddr;
634         return false;
635     }
636 
637     /*  Otherwise find mid address according to position. lclGetMidAddr() will
638         return an address between nBegAddr and nEndAddr. */
639     rnMidAddr = lclGetMidAddr( nBegAddr, nEndAddr, nBegPos, nEndPos, nSearchPos );
640     return true;
641 }
642 
643 bool lclUpdateInterval( sal_Int32& rnBegAddr, sal_Int32& rnMidAddr, sal_Int32& rnEndAddr,
644         sal_Int32& rnBegPos, sal_Int32 nMidPos, sal_Int32& rnEndPos, sal_Int32 nSearchPos )
645 {
646     // nSearchPos < nMidPos: use the interval [begin,mid] in the next iteration
647     if( nSearchPos < nMidPos )
648     {
649         // if rnBegAddr is next to rnMidAddr, the latter is the column/row in question
650         if( rnBegAddr + 1 >= rnMidAddr )
651             return false;
652         // otherwise, set interval end to mid
653         rnEndPos = nMidPos;
654         rnEndAddr = rnMidAddr;
655         rnMidAddr = lclGetMidAddr( rnBegAddr, rnEndAddr, rnBegPos, rnEndPos, nSearchPos );
656         return true;
657     }
658 
659     // nSearchPos > nMidPos: use the interval [mid,end] in the next iteration
660     if( nSearchPos > nMidPos )
661     {
662         // if rnMidAddr is next to rnEndAddr, the latter is the column/row in question
663         if( rnMidAddr + 1 >= rnEndAddr )
664         {
665             rnMidAddr = rnEndAddr;
666             return false;
667         }
668         // otherwise, set interval start to mid
669         rnBegPos = nMidPos;
670         rnBegAddr = rnMidAddr;
671         rnMidAddr = lclGetMidAddr( rnBegAddr, rnEndAddr, rnBegPos, rnEndPos, nSearchPos );
672         return true;
673     }
674 
675     // nSearchPos == nMidPos: rnMidAddr is the column/row in question, do not loop anymore
676     return false;
677 }
678 
679 } // namespace
680 
681 CellAddress WorksheetGlobals::getCellAddressFromPosition( const Point& rPosition ) const
682 {
683     // starting cell address and its position in drawing layer (top-left edge)
684     sal_Int32 nBegCol = 0;
685     sal_Int32 nBegRow = 0;
686     Point aBegPos( 0, 0 );
687 
688     // end cell address and its position in drawing layer (bottom-right edge)
689     sal_Int32 nEndCol = mrMaxApiPos.Column + 1;
690     sal_Int32 nEndRow = mrMaxApiPos.Row + 1;
691     Point aEndPos( maDrawPageSize.Width, maDrawPageSize.Height );
692 
693     // starting point for interval search
694     sal_Int32 nMidCol, nMidRow;
695     bool bLoopCols = lclPrepareInterval( nBegCol, nMidCol, nEndCol, aBegPos.X, aEndPos.X, rPosition.X );
696     bool bLoopRows = lclPrepareInterval( nBegRow, nMidRow, nEndRow, aBegPos.Y, aEndPos.Y, rPosition.Y );
697     Point aMidPos = getCellPosition( nMidCol, nMidRow );
698 
699     /*  The loop will find the column/row index of the cell right of/below
700         the cell containing the passed point, unless the point is located at
701         the top or left border of the containing cell. */
702     while( bLoopCols || bLoopRows )
703     {
704         bLoopCols = bLoopCols && lclUpdateInterval( nBegCol, nMidCol, nEndCol, aBegPos.X, aMidPos.X, aEndPos.X, rPosition.X );
705         bLoopRows = bLoopRows && lclUpdateInterval( nBegRow, nMidRow, nEndRow, aBegPos.Y, aMidPos.Y, aEndPos.Y, rPosition.Y );
706         aMidPos = getCellPosition( nMidCol, nMidRow );
707     }
708 
709     /*  The cell left of/above the current search position contains the passed
710         point, unless the point is located on the top/left border of the cell,
711         or the last column/row of the sheet has been reached. */
712     if( aMidPos.X > rPosition.X ) --nMidCol;
713     if( aMidPos.Y > rPosition.Y ) --nMidRow;
714     return CellAddress( getSheetIndex(), nMidCol, nMidRow );
715 }
716 
717 CellRangeAddress WorksheetGlobals::getCellRangeFromRectangle( const Rectangle& rRect ) const
718 {
719     CellAddress aStartAddr = getCellAddressFromPosition( Point( rRect.X, rRect.Y ) );
720     Point aBotRight( rRect.X + rRect.Width, rRect.Y + rRect.Height );
721     CellAddress aEndAddr = getCellAddressFromPosition( aBotRight );
722     bool bMultiCols = aStartAddr.Column < aEndAddr.Column;
723     bool bMultiRows = aStartAddr.Row < aEndAddr.Row;
724     if( bMultiCols || bMultiRows )
725     {
726         /*  Reduce end position of the cell range to previous column or row, if
727             the rectangle ends exactly between two columns or rows. */
728         Point aEndPos = getCellPosition( aEndAddr.Column, aEndAddr.Row );
729         if( bMultiCols && (aBotRight.X <= aEndPos.X) )
730             --aEndAddr.Column;
731         if( bMultiRows && (aBotRight.Y <= aEndPos.Y) )
732             --aEndAddr.Row;
733     }
734     return CellRangeAddress( getSheetIndex(), aStartAddr.Column, aStartAddr.Row, aEndAddr.Column, aEndAddr.Row );
735 }
736 
737 void WorksheetGlobals::setPageBreak( const PageBreakModel& rModel, bool bRowBreak )
738 {
739     if( rModel.mbManual && (rModel.mnColRow > 0) )
740     {
741         PropertySet aPropSet( bRowBreak ? getRow( rModel.mnColRow ) : getColumn( rModel.mnColRow ) );
742         aPropSet.setProperty( PROP_IsStartOfNewPage, true );
743     }
744 }
745 
746 void WorksheetGlobals::setHyperlink( const HyperlinkModel& rModel )
747 {
748     maHyperlinks.push_back( rModel );
749 }
750 
751 void WorksheetGlobals::setValidation( const ValidationModel& rModel )
752 {
753     maValidations.push_back( rModel );
754 }
755 
756 void WorksheetGlobals::setDrawingPath( const OUString& rDrawingPath )
757 {
758     maDrawingPath = rDrawingPath;
759 }
760 
761 void WorksheetGlobals::setVmlDrawingPath( const OUString& rVmlDrawingPath )
762 {
763     maVmlDrawingPath = rVmlDrawingPath;
764 }
765 
766 void WorksheetGlobals::extendUsedArea( const CellAddress& rAddress )
767 {
768     maUsedArea.StartColumn = ::std::min( maUsedArea.StartColumn, rAddress.Column );
769     maUsedArea.StartRow    = ::std::min( maUsedArea.StartRow,    rAddress.Row );
770     maUsedArea.EndColumn   = ::std::max( maUsedArea.EndColumn,   rAddress.Column );
771     maUsedArea.EndRow      = ::std::max( maUsedArea.EndRow,      rAddress.Row );
772 }
773 
774 void WorksheetGlobals::extendUsedArea( const CellRangeAddress& rRange )
775 {
776     extendUsedArea( CellAddress( rRange.Sheet, rRange.StartColumn, rRange.StartRow ) );
777     extendUsedArea( CellAddress( rRange.Sheet, rRange.EndColumn, rRange.EndRow ) );
778 }
779 
780 void WorksheetGlobals::extendShapeBoundingBox( const Rectangle& rShapeRect )
781 {
782     if( (maShapeBoundingBox.Width == 0) && (maShapeBoundingBox.Height == 0) )
783     {
784         // width and height of maShapeBoundingBox are assumed to be zero on first cell
785         maShapeBoundingBox = rShapeRect;
786     }
787     else
788     {
789         sal_Int32 nEndX = ::std::max( maShapeBoundingBox.X + maShapeBoundingBox.Width, rShapeRect.X + rShapeRect.Width );
790         sal_Int32 nEndY = ::std::max( maShapeBoundingBox.Y + maShapeBoundingBox.Height, rShapeRect.Y + rShapeRect.Height );
791         maShapeBoundingBox.X = ::std::min( maShapeBoundingBox.X, rShapeRect.X );
792         maShapeBoundingBox.Y = ::std::min( maShapeBoundingBox.Y, rShapeRect.Y );
793         maShapeBoundingBox.Width = nEndX - maShapeBoundingBox.X;
794         maShapeBoundingBox.Height = nEndY - maShapeBoundingBox.Y;
795     }
796 }
797 
798 void WorksheetGlobals::setBaseColumnWidth( sal_Int32 nWidth )
799 {
800     // do not modify width, if setDefaultColumnWidth() has been used
801     if( !mbHasDefWidth && (nWidth > 0) )
802     {
803         // #i3006# add 5 pixels padding to the width
804         const UnitConverter& rUnitConv = getUnitConverter();
805         maDefColModel.mfWidth = rUnitConv.scaleFromMm100(
806             rUnitConv.scaleToMm100( nWidth, UNIT_DIGIT ) + rUnitConv.scaleToMm100( 5, UNIT_SCREENX ), UNIT_DIGIT );
807     }
808 }
809 
810 void WorksheetGlobals::setDefaultColumnWidth( double fWidth )
811 {
812     // overrides a width set with setBaseColumnWidth()
813     if( fWidth > 0.0 )
814     {
815         maDefColModel.mfWidth = fWidth;
816         mbHasDefWidth = true;
817     }
818 }
819 
820 void WorksheetGlobals::setColumnModel( const ColumnModel& rModel )
821 {
822     // convert 1-based OOXML column indexes to 0-based API column indexes
823     sal_Int32 nFirstCol = rModel.maRange.mnFirst - 1;
824     sal_Int32 nLastCol = rModel.maRange.mnLast - 1;
825     if( getAddressConverter().checkCol( nFirstCol, true ) && (nFirstCol <= nLastCol) )
826     {
827         // validate last column index
828         if( !getAddressConverter().checkCol( nLastCol, true ) )
829             nLastCol = mrMaxApiPos.Column;
830         // try to find entry in column model map that is able to merge with the passed model
831         bool bInsertModel = true;
832         if( !maColModels.empty() )
833         {
834             // find first column model range following nFirstCol (nFirstCol < aIt->first), or end of map
835             ColumnModelRangeMap::iterator aIt = maColModels.upper_bound( nFirstCol );
836             OSL_ENSURE( aIt == maColModels.end(), "WorksheetGlobals::setColModel - columns are unsorted" );
837             // if inserting before another column model, get last free column
838             OSL_ENSURE( (aIt == maColModels.end()) || (nLastCol < aIt->first), "WorksheetGlobals::setColModel - multiple models of the same column" );
839             if( aIt != maColModels.end() )
840                 nLastCol = ::std::min( nLastCol, aIt->first - 1 );
841             if( aIt != maColModels.begin() )
842             {
843                 // go to previous map element (which may be able to merge with the passed model)
844                 --aIt;
845                 // the usage of upper_bound() above ensures that aIt->first is less than or equal to nFirstCol now
846                 sal_Int32& rnLastMapCol = aIt->second.second;
847                 OSL_ENSURE( rnLastMapCol < nFirstCol, "WorksheetGlobals::setColModel - multiple models of the same column" );
848                 nFirstCol = ::std::max( rnLastMapCol + 1, nFirstCol );
849                 if( (rnLastMapCol + 1 == nFirstCol) && (nFirstCol <= nLastCol) && aIt->second.first.isMergeable( rModel ) )
850                 {
851                     // can merge with existing model, update last column index
852                     rnLastMapCol = nLastCol;
853                     bInsertModel = false;
854                 }
855             }
856         }
857         if( nFirstCol <= nLastCol )
858         {
859             // insert the column model, if it has not been merged with another
860             if( bInsertModel )
861                 maColModels[ nFirstCol ] = ColumnModelRange( rModel, nLastCol );
862             // set column formatting directly
863             convertColumnFormat( nFirstCol, nLastCol, rModel.mnXfId );
864         }
865     }
866 }
867 
868 void WorksheetGlobals::convertColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId ) const
869 {
870     CellRangeAddress aRange( getSheetIndex(), nFirstCol, 0, nLastCol, mrMaxApiPos.Row );
871     if( getAddressConverter().validateCellRange( aRange, true, false ) )
872     {
873         PropertySet aPropSet( getCellRange( aRange ) );
874         getStyles().writeCellXfToPropertySet( aPropSet, nXfId );
875     }
876 }
877 
878 void WorksheetGlobals::setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom )
879 {
880     maDefRowModel.mfHeight = fHeight;
881     maDefRowModel.mbCustomHeight = bCustomHeight;
882     maDefRowModel.mbHidden = bHidden;
883     maDefRowModel.mbThickTop = bThickTop;
884     maDefRowModel.mbThickBottom = bThickBottom;
885 }
886 
887 void WorksheetGlobals::setRowModel( const RowModel& rModel )
888 {
889     // convert 1-based OOXML row index to 0-based API row index
890     sal_Int32 nRow = rModel.mnRow - 1;
891     if( getAddressConverter().checkRow( nRow, true ) )
892     {
893         // try to find entry in row model map that is able to merge with the passed model
894         bool bInsertModel = true;
895         bool bUnusedRow = true;
896         if( !maRowModels.empty() )
897         {
898             // find first row model range following nRow (nRow < aIt->first), or end of map
899             RowModelRangeMap::iterator aIt = maRowModels.upper_bound( nRow );
900             OSL_ENSURE( aIt == maRowModels.end(), "WorksheetGlobals::setRowModel - rows are unsorted" );
901             if( aIt != maRowModels.begin() )
902             {
903                 // go to previous map element (which may be able to merge with the passed model)
904                 --aIt;
905                 // the usage of upper_bound() above ensures that aIt->first is less than or equal to nRow now
906                 sal_Int32& rnLastMapRow = aIt->second.second;
907                 bUnusedRow = rnLastMapRow < nRow;
908                 OSL_ENSURE( bUnusedRow, "WorksheetGlobals::setRowModel - multiple models of the same row" );
909                 if( (rnLastMapRow + 1 == nRow) && aIt->second.first.isMergeable( rModel ) )
910                 {
911                     // can merge with existing model, update last row index
912                     ++rnLastMapRow;
913                     bInsertModel = false;
914                 }
915             }
916         }
917         if( bUnusedRow )
918         {
919             // insert the row model, if it has not been merged with another
920             if( bInsertModel )
921                 maRowModels[ nRow ] = RowModelRange( rModel, nRow );
922             // set row formatting
923             maSheetData.setRowFormat( nRow, rModel.mnXfId, rModel.mbCustomFormat );
924             // set column spans
925             maSheetData.setColSpans( nRow, rModel.maColSpans );
926         }
927     }
928     lclUpdateProgressBar( mxRowProgress, maUsedArea, nRow );
929 }
930 
931 void WorksheetGlobals::setManualRowHeight( sal_Int32 nRow )
932 {
933     maManualRowHeights.insert( nRow );
934 }
935 
936 void WorksheetGlobals::initializeWorksheetImport()
937 {
938     // set default cell style for unused cells
939     PropertySet aPropSet( mxSheet );
940     aPropSet.setProperty( PROP_CellStyle, getStyles().getDefaultStyleName() );
941 
942     /*  Remember the current sheet index in global data, needed by global
943         objects, e.g. the chart converter. */
944     setCurrentSheetIndex( getSheetIndex() );
945 }
946 
947 void WorksheetGlobals::finalizeWorksheetImport()
948 {
949     lclUpdateProgressBar( mxRowProgress, 1.0 );
950     maSheetData.finalizeImport();
951     lclUpdateProgressBar( mxFinalProgress, 0.25 );
952     finalizeHyperlinkRanges();
953     finalizeValidationRanges();
954     maAutoFilters.finalizeImport( getSheetIndex() );
955     maCondFormats.finalizeImport();
956     maQueryTables.finalizeImport();
957     maSheetSett.finalizeImport();
958     maPageSett.finalizeImport();
959     maSheetViewSett.finalizeImport();
960 
961     lclUpdateProgressBar( mxFinalProgress, 0.5 );
962     convertColumns();
963     convertRows();
964     lclUpdateProgressBar( mxFinalProgress, 0.75 );
965     finalizeDrawings();
966     lclUpdateProgressBar( mxFinalProgress, 1.0 );
967 
968     // forget current sheet index in global data
969     setCurrentSheetIndex( -1 );
970 }
971 
972 // private --------------------------------------------------------------------
973 
974 void WorksheetGlobals::finalizeHyperlinkRanges() const
975 {
976     for( HyperlinkModelList::const_iterator aIt = maHyperlinks.begin(), aEnd = maHyperlinks.end(); aIt != aEnd; ++aIt )
977     {
978         OUString aUrl = getHyperlinkUrl( *aIt );
979         // try to insert URL into each cell of the range
980         if( aUrl.getLength() > 0 )
981             for( CellAddress aAddress( getSheetIndex(), aIt->maRange.StartColumn, aIt->maRange.StartRow ); aAddress.Row <= aIt->maRange.EndRow; ++aAddress.Row )
982                 for( aAddress.Column = aIt->maRange.StartColumn; aAddress.Column <= aIt->maRange.EndColumn; ++aAddress.Column )
983                     insertHyperlink( aAddress, aUrl );
984     }
985 }
986 
987 OUString WorksheetGlobals::getHyperlinkUrl( const HyperlinkModel& rHyperlink ) const
988 {
989     OUStringBuffer aUrlBuffer;
990     if( rHyperlink.maTarget.getLength() > 0 )
991         aUrlBuffer.append( getBaseFilter().getAbsoluteUrl( rHyperlink.maTarget ) );
992     if( rHyperlink.maLocation.getLength() > 0 )
993         aUrlBuffer.append( sal_Unicode( '#' ) ).append( rHyperlink.maLocation );
994     OUString aUrl = aUrlBuffer.makeStringAndClear();
995 
996     // convert '#SheetName!A1' to '#SheetName.A1'
997     if( (aUrl.getLength() > 0) && (aUrl[ 0 ] == '#') )
998     {
999         sal_Int32 nSepPos = aUrl.lastIndexOf( '!' );
1000         if( nSepPos > 0 )
1001         {
1002             // replace the exclamation mark with a period
1003             aUrl = aUrl.replaceAt( nSepPos, 1, OUString( sal_Unicode( '.' ) ) );
1004             // #i66592# convert sheet names that have been renamed on import
1005             OUString aSheetName = aUrl.copy( 1, nSepPos - 1 );
1006             OUString aCalcName = getWorksheets().getCalcSheetName( aSheetName );
1007             if( aCalcName.getLength() > 0 )
1008                 aUrl = aUrl.replaceAt( 1, nSepPos - 1, aCalcName );
1009         }
1010     }
1011 
1012     return aUrl;
1013 }
1014 
1015 void WorksheetGlobals::insertHyperlink( const CellAddress& rAddress, const OUString& rUrl ) const
1016 {
1017     Reference< XCell > xCell = getCell( rAddress );
1018     if( xCell.is() ) switch( xCell->getType() )
1019     {
1020         // #i54261# restrict creation of URL field to text cells
1021         case CellContentType_TEXT:
1022         {
1023             Reference< XText > xText( xCell, UNO_QUERY );
1024             if( xText.is() )
1025             {
1026                 // create a URL field object and set its properties
1027                 Reference< XTextContent > xUrlField( getBaseFilter().getModelFactory()->createInstance( maUrlTextField ), UNO_QUERY );
1028                 OSL_ENSURE( xUrlField.is(), "WorksheetGlobals::insertHyperlink - cannot create text field" );
1029                 if( xUrlField.is() )
1030                 {
1031                     // properties of the URL field
1032                     PropertySet aPropSet( xUrlField );
1033                     aPropSet.setProperty( PROP_URL, rUrl );
1034                     aPropSet.setProperty( PROP_Representation, xText->getString() );
1035                     try
1036                     {
1037                         // insert the field into the cell
1038                         xText->setString( OUString() );
1039                         Reference< XTextRange > xRange( xText->createTextCursor(), UNO_QUERY_THROW );
1040                         xText->insertTextContent( xRange, xUrlField, sal_False );
1041                     }
1042                     catch( const Exception& )
1043                     {
1044                         OSL_ENSURE( false, "WorksheetGlobals::insertHyperlink - cannot insert text field" );
1045                     }
1046                 }
1047             }
1048         }
1049         break;
1050 
1051         // fix for #i31050# disabled, HYPERLINK is not able to return numeric value (#i91351#)
1052 #if 0
1053         // #i31050# replace number with HYPERLINK function
1054         case CellContentType_VALUE:
1055         {
1056             Reference< XFormulaTokens > xTokens( xCell, UNO_QUERY );
1057             ApiTokenSequence aTokens = getFormulaParser().convertNumberToHyperlink( rUrl, xCell->getValue() );
1058             OSL_ENSURE( xTokens.is(), "WorksheetHelper::insertHyperlink - missing formula token interface" );
1059             if( xTokens.is() && aTokens.hasElements() )
1060                 xTokens->setTokens( aTokens );
1061         }
1062         break;
1063 #endif
1064 
1065         default:;
1066     }
1067 }
1068 
1069 void WorksheetGlobals::finalizeValidationRanges() const
1070 {
1071     for( ValidationModelList::const_iterator aIt = maValidations.begin(), aEnd = maValidations.end(); aIt != aEnd; ++aIt )
1072     {
1073         PropertySet aPropSet( getCellRangeList( aIt->maRanges ) );
1074 
1075         Reference< XPropertySet > xValidation( aPropSet.getAnyProperty( PROP_Validation ), UNO_QUERY );
1076         if( xValidation.is() )
1077         {
1078             PropertySet aValProps( xValidation );
1079 
1080             // convert validation type to API enum
1081             ValidationType eType = ValidationType_ANY;
1082             switch( aIt->mnType )
1083             {
1084                 case XML_custom:        eType = ValidationType_CUSTOM;      break;
1085                 case XML_date:          eType = ValidationType_DATE;        break;
1086                 case XML_decimal:       eType = ValidationType_DECIMAL;     break;
1087                 case XML_list:          eType = ValidationType_LIST;        break;
1088                 case XML_none:          eType = ValidationType_ANY;         break;
1089                 case XML_textLength:    eType = ValidationType_TEXT_LEN;    break;
1090                 case XML_time:          eType = ValidationType_TIME;        break;
1091                 case XML_whole:         eType = ValidationType_WHOLE;       break;
1092                 default:    OSL_ENSURE( false, "WorksheetGlobals::finalizeValidationRanges - unknown validation type" );
1093             }
1094             aValProps.setProperty( PROP_Type, eType );
1095 
1096             // convert error alert style to API enum
1097             ValidationAlertStyle eAlertStyle = ValidationAlertStyle_STOP;
1098             switch( aIt->mnErrorStyle )
1099             {
1100                 case XML_information:   eAlertStyle = ValidationAlertStyle_INFO;    break;
1101                 case XML_stop:          eAlertStyle = ValidationAlertStyle_STOP;    break;
1102                 case XML_warning:       eAlertStyle = ValidationAlertStyle_WARNING; break;
1103                 default:    OSL_ENSURE( false, "WorksheetGlobals::finalizeValidationRanges - unknown error style" );
1104             }
1105             aValProps.setProperty( PROP_ErrorAlertStyle, eAlertStyle );
1106 
1107             // convert dropdown style to API visibility constants
1108             sal_Int16 nVisibility = aIt->mbNoDropDown ? TableValidationVisibility::INVISIBLE : TableValidationVisibility::UNSORTED;
1109             aValProps.setProperty( PROP_ShowList, nVisibility );
1110 
1111             // messages
1112             aValProps.setProperty( PROP_ShowInputMessage, aIt->mbShowInputMsg );
1113             aValProps.setProperty( PROP_InputTitle, aIt->maInputTitle );
1114             aValProps.setProperty( PROP_InputMessage, aIt->maInputMessage );
1115             aValProps.setProperty( PROP_ShowErrorMessage, aIt->mbShowErrorMsg );
1116             aValProps.setProperty( PROP_ErrorTitle, aIt->maErrorTitle );
1117             aValProps.setProperty( PROP_ErrorMessage, aIt->maErrorMessage );
1118 
1119             // allow blank cells
1120             aValProps.setProperty( PROP_IgnoreBlankCells, aIt->mbAllowBlank );
1121 
1122             try
1123             {
1124                 // condition operator
1125                 Reference< XSheetCondition > xSheetCond( xValidation, UNO_QUERY_THROW );
1126                 xSheetCond->setOperator( CondFormatBuffer::convertToApiOperator( aIt->mnOperator ) );
1127 
1128                 // condition formulas
1129                 Reference< XMultiFormulaTokens > xTokens( xValidation, UNO_QUERY_THROW );
1130                 xTokens->setTokens( 0, aIt->maTokens1 );
1131                 xTokens->setTokens( 1, aIt->maTokens2 );
1132             }
1133             catch( Exception& )
1134             {
1135             }
1136 
1137             // write back validation settings to cell range(s)
1138             aPropSet.setProperty( PROP_Validation, xValidation );
1139         }
1140     }
1141 }
1142 
1143 void WorksheetGlobals::convertColumns()
1144 {
1145     sal_Int32 nNextCol = 0;
1146     sal_Int32 nMaxCol = mrMaxApiPos.Column;
1147     // stores first grouped column index for each level
1148     OutlineLevelVec aColLevels;
1149 
1150     for( ColumnModelRangeMap::iterator aIt = maColModels.begin(), aEnd = maColModels.end(); aIt != aEnd; ++aIt )
1151     {
1152         // column indexes are stored 0-based in maColModels
1153         ValueRange aColRange( ::std::max( aIt->first, nNextCol ), ::std::min( aIt->second.second, nMaxCol ) );
1154         // process gap between two column models, use default column model
1155         if( nNextCol < aColRange.mnFirst )
1156             convertColumns( aColLevels, ValueRange( nNextCol, aColRange.mnFirst - 1 ), maDefColModel );
1157         // process the column model
1158         convertColumns( aColLevels, aColRange, aIt->second.first );
1159         // cache next column to be processed
1160         nNextCol = aColRange.mnLast + 1;
1161     }
1162 
1163     // remaining default columns to end of sheet
1164     convertColumns( aColLevels, ValueRange( nNextCol, nMaxCol ), maDefColModel );
1165     // close remaining column outlines spanning to end of sheet
1166     convertOutlines( aColLevels, nMaxCol + 1, 0, false, false );
1167 }
1168 
1169 void WorksheetGlobals::convertColumns( OutlineLevelVec& orColLevels,
1170         const ValueRange& rColRange, const ColumnModel& rModel )
1171 {
1172     PropertySet aPropSet( getColumns( rColRange ) );
1173 
1174     // column width: convert 'number of characters' to column width in 1/100 mm
1175     sal_Int32 nWidth = getUnitConverter().scaleToMm100( rModel.mfWidth, UNIT_DIGIT );
1176     // macro sheets have double width
1177     if( meSheetType == SHEETTYPE_MACROSHEET )
1178         nWidth *= 2;
1179     if( nWidth > 0 )
1180         aPropSet.setProperty( PROP_Width, nWidth );
1181 
1182     // hidden columns: TODO: #108683# hide columns later?
1183     if( rModel.mbHidden )
1184         aPropSet.setProperty( PROP_IsVisible, false );
1185 
1186     // outline settings for this column range
1187     convertOutlines( orColLevels, rColRange.mnFirst, rModel.mnLevel, rModel.mbCollapsed, false );
1188 }
1189 
1190 void WorksheetGlobals::convertRows()
1191 {
1192     sal_Int32 nNextRow = 0;
1193     sal_Int32 nMaxRow = mrMaxApiPos.Row;
1194     // stores first grouped row index for each level
1195     OutlineLevelVec aRowLevels;
1196 
1197     for( RowModelRangeMap::iterator aIt = maRowModels.begin(), aEnd = maRowModels.end(); aIt != aEnd; ++aIt )
1198     {
1199         // row indexes are stored 0-based in maRowModels
1200         ValueRange aRowRange( ::std::max( aIt->first, nNextRow ), ::std::min( aIt->second.second, nMaxRow ) );
1201         // process gap between two row models, use default row model
1202         if( nNextRow < aRowRange.mnFirst )
1203             convertRows( aRowLevels, ValueRange( nNextRow, aRowRange.mnFirst - 1 ), maDefRowModel );
1204         // process the row model
1205         convertRows( aRowLevels, aRowRange, aIt->second.first, maDefRowModel.mfHeight );
1206         // cache next row to be processed
1207         nNextRow = aRowRange.mnLast + 1;
1208     }
1209 
1210     // remaining default rows to end of sheet
1211     convertRows( aRowLevels, ValueRange( nNextRow, nMaxRow ), maDefRowModel );
1212     // close remaining row outlines spanning to end of sheet
1213     convertOutlines( aRowLevels, nMaxRow + 1, 0, false, true );
1214 }
1215 
1216 void WorksheetGlobals::convertRows( OutlineLevelVec& orRowLevels,
1217         const ValueRange& rRowRange, const RowModel& rModel, double fDefHeight )
1218 {
1219     // row height: convert points to row height in 1/100 mm
1220     double fHeight = (rModel.mfHeight >= 0.0) ? rModel.mfHeight : fDefHeight;
1221     sal_Int32 nHeight = getUnitConverter().scaleToMm100( fHeight, UNIT_POINT );
1222     if( nHeight > 0 )
1223     {
1224         /*  Get all rows that have custom height inside the passed row model.
1225             If the model has the custom height flag set, all its rows have
1226             custom height, otherwise get all rows specified in the class member
1227             maManualRowHeights that are inside the passed row model. */
1228         ValueRangeVector aManualRows;
1229         if( rModel.mbCustomHeight )
1230             aManualRows.push_back( rRowRange );
1231         else
1232             aManualRows = maManualRowHeights.getIntersection( rRowRange );
1233         for( ValueRangeVector::const_iterator aIt = aManualRows.begin(), aEnd = aManualRows.end(); aIt != aEnd; ++aIt )
1234         {
1235             PropertySet aPropSet( getRows( *aIt ) );
1236             aPropSet.setProperty( PROP_Height, nHeight );
1237         }
1238     }
1239 
1240     // hidden rows: TODO: #108683# hide rows later?
1241     if( rModel.mbHidden )
1242     {
1243         PropertySet aPropSet( getRows( rRowRange ) );
1244         /*  #i116460# Use VisibleFlag instead of IsVisible: directly set the
1245             flag, without drawing layer update etc. (only possible before
1246             shapes are inserted). */
1247         aPropSet.setProperty( PROP_VisibleFlag, false );
1248     }
1249 
1250     // outline settings for this row range
1251     convertOutlines( orRowLevels, rRowRange.mnFirst, rModel.mnLevel, rModel.mbCollapsed, true );
1252 }
1253 
1254 void WorksheetGlobals::convertOutlines( OutlineLevelVec& orLevels,
1255         sal_Int32 nColRow, sal_Int32 nLevel, bool bCollapsed, bool bRows )
1256 {
1257     /*  It is ensured from caller functions, that this function is called
1258         without any gaps between the processed column or row ranges. */
1259 
1260     OSL_ENSURE( nLevel >= 0, "WorksheetGlobals::convertOutlines - negative outline level" );
1261     nLevel = ::std::max< sal_Int32 >( nLevel, 0 );
1262 
1263     sal_Int32 nSize = orLevels.size();
1264     if( nSize < nLevel )
1265     {
1266         // Outline level increased. Push the begin column position.
1267         for( sal_Int32 nIndex = nSize; nIndex < nLevel; ++nIndex )
1268             orLevels.push_back( nColRow );
1269     }
1270     else if( nLevel < nSize )
1271     {
1272         // Outline level decreased. Pop them all out.
1273         for( sal_Int32 nIndex = nLevel; nIndex < nSize; ++nIndex )
1274         {
1275             sal_Int32 nFirstInLevel = orLevels.back();
1276             orLevels.pop_back();
1277             groupColumnsOrRows( nFirstInLevel, nColRow - 1, bCollapsed, bRows );
1278             bCollapsed = false; // collapse only once
1279         }
1280     }
1281 }
1282 
1283 void WorksheetGlobals::groupColumnsOrRows( sal_Int32 nFirstColRow, sal_Int32 nLastColRow, bool bCollapse, bool bRows )
1284 {
1285     try
1286     {
1287         Reference< XSheetOutline > xOutline( mxSheet, UNO_QUERY_THROW );
1288         if( bRows )
1289         {
1290             CellRangeAddress aRange( getSheetIndex(), 0, nFirstColRow, 0, nLastColRow );
1291             xOutline->group( aRange, TableOrientation_ROWS );
1292             if( bCollapse )
1293                 xOutline->hideDetail( aRange );
1294         }
1295         else
1296         {
1297             CellRangeAddress aRange( getSheetIndex(), nFirstColRow, 0, nLastColRow, 0 );
1298             xOutline->group( aRange, TableOrientation_COLUMNS );
1299             if( bCollapse )
1300                 xOutline->hideDetail( aRange );
1301         }
1302     }
1303     catch( Exception& )
1304     {
1305     }
1306 }
1307 
1308 void WorksheetGlobals::finalizeDrawings()
1309 {
1310     // calculate the current drawing page size (after rows/columns are imported)
1311     PropertySet aRangeProp( getCellRange( CellRangeAddress( getSheetIndex(), 0, 0, mrMaxApiPos.Column, mrMaxApiPos.Row ) ) );
1312     aRangeProp.getProperty( maDrawPageSize, PROP_Size );
1313 
1314     switch( getFilterType() )
1315     {
1316         case FILTER_OOXML:
1317             // import DML and VML
1318             if( maDrawingPath.getLength() > 0 )
1319                 importOoxFragment( new DrawingFragment( *this, maDrawingPath ) );
1320             if( maVmlDrawingPath.getLength() > 0 )
1321                 importOoxFragment( new VmlDrawingFragment( *this, maVmlDrawingPath ) );
1322         break;
1323 
1324         case FILTER_BIFF:
1325             // convert BIFF3-BIFF5 drawing objects, or import and convert DFF stream
1326             getBiffDrawing().finalizeImport();
1327         break;
1328 
1329         case FILTER_UNKNOWN:
1330         break;
1331     }
1332 
1333     // comments (after callout shapes have been imported from VML/DFF)
1334     maComments.finalizeImport();
1335 
1336     /*  Extend used area of the sheet by cells covered with drawing objects.
1337         Needed if the imported document is inserted as "OLE object from file"
1338         and thus does not provide an OLE size property by itself. */
1339     if( (maShapeBoundingBox.Width > 0) || (maShapeBoundingBox.Height > 0) )
1340         extendUsedArea( getCellRangeFromRectangle( maShapeBoundingBox ) );
1341 
1342     // if no used area is set, default to A1
1343     if( maUsedArea.StartColumn > maUsedArea.EndColumn )
1344         maUsedArea.StartColumn = maUsedArea.EndColumn = 0;
1345     if( maUsedArea.StartRow > maUsedArea.EndRow )
1346         maUsedArea.StartRow = maUsedArea.EndRow = 0;
1347 
1348     /*  Register the used area of this sheet in global view settings. The
1349         global view settings will set the visible area if this document is an
1350         embedded OLE object. */
1351     getViewSettings().setSheetUsedArea( maUsedArea );
1352 
1353     /*  #i103686# Set right-to-left sheet layout. Must be done after all
1354         drawing shapes to simplify calculation of shape coordinates. */
1355     if( maSheetViewSett.isSheetRightToLeft() )
1356     {
1357         PropertySet aPropSet( mxSheet );
1358         aPropSet.setProperty( PROP_TableLayout, WritingMode2::RL_TB );
1359     }
1360 }
1361 
1362 // ============================================================================
1363 // ============================================================================
1364 
1365 WorksheetHelper::WorksheetHelper( WorksheetGlobals& rSheetGlob ) :
1366     WorkbookHelper( rSheetGlob ),
1367     mrSheetGlob( rSheetGlob )
1368 {
1369 }
1370 
1371 /*static*/ WorksheetGlobalsRef WorksheetHelper::constructGlobals( const WorkbookHelper& rHelper,
1372         const ISegmentProgressBarRef& rxProgressBar, WorksheetType eSheetType, sal_Int16 nSheet )
1373 {
1374     WorksheetGlobalsRef xSheetGlob( new WorksheetGlobals( rHelper, rxProgressBar, eSheetType, nSheet ) );
1375     if( !xSheetGlob->isValidSheet() )
1376         xSheetGlob.reset();
1377     return xSheetGlob;
1378 }
1379 
1380 WorksheetType WorksheetHelper::getSheetType() const
1381 {
1382     return mrSheetGlob.getSheetType();
1383 }
1384 
1385 sal_Int16 WorksheetHelper::getSheetIndex() const
1386 {
1387     return mrSheetGlob.getSheetIndex();
1388 }
1389 
1390 const Reference< XSpreadsheet >& WorksheetHelper::getSheet() const
1391 {
1392     return mrSheetGlob.getSheet();
1393 }
1394 
1395 Reference< XCell > WorksheetHelper::getCell( const CellAddress& rAddress ) const
1396 {
1397     return mrSheetGlob.getCell( rAddress );
1398 }
1399 
1400 Reference< XCellRange > WorksheetHelper::getCellRange( const CellRangeAddress& rRange ) const
1401 {
1402     return mrSheetGlob.getCellRange( rRange );
1403 }
1404 
1405 Reference< XSheetCellRanges > WorksheetHelper::getCellRangeList( const ApiCellRangeList& rRanges ) const
1406 {
1407     return mrSheetGlob.getCellRangeList( rRanges );
1408 }
1409 
1410 CellAddress WorksheetHelper::getCellAddress( const Reference< XCell >& rxCell )
1411 {
1412     CellAddress aAddress;
1413     Reference< XCellAddressable > xAddressable( rxCell, UNO_QUERY );
1414     OSL_ENSURE( xAddressable.is(), "WorksheetHelper::getCellAddress - cell reference not addressable" );
1415     if( xAddressable.is() )
1416         aAddress = xAddressable->getCellAddress();
1417     return aAddress;
1418 }
1419 
1420 CellRangeAddress WorksheetHelper::getRangeAddress( const Reference< XCellRange >& rxRange )
1421 {
1422     CellRangeAddress aRange;
1423     Reference< XCellRangeAddressable > xAddressable( rxRange, UNO_QUERY );
1424     OSL_ENSURE( xAddressable.is(), "WorksheetHelper::getRangeAddress - cell range reference not addressable" );
1425     if( xAddressable.is() )
1426         aRange = xAddressable->getRangeAddress();
1427     return aRange;
1428 }
1429 
1430 Reference< XCellRange > WorksheetHelper::getColumn( sal_Int32 nCol ) const
1431 {
1432     return mrSheetGlob.getColumn( nCol );
1433 }
1434 
1435 Reference< XCellRange > WorksheetHelper::getRow( sal_Int32 nRow ) const
1436 {
1437     return mrSheetGlob.getRow( nRow );
1438 }
1439 
1440 Reference< XTableColumns > WorksheetHelper::getColumns( const ValueRange& rColRange ) const
1441 {
1442     return mrSheetGlob.getColumns( rColRange );
1443 }
1444 
1445 Reference< XTableRows > WorksheetHelper::getRows( const ValueRange& rRowRange ) const
1446 {
1447     return mrSheetGlob.getRows( rRowRange );
1448 }
1449 
1450 Reference< XDrawPage > WorksheetHelper::getDrawPage() const
1451 {
1452     return mrSheetGlob.getDrawPage();
1453 }
1454 
1455 Point WorksheetHelper::getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const
1456 {
1457     return mrSheetGlob.getCellPosition( nCol, nRow );
1458 }
1459 
1460 Size WorksheetHelper::getCellSize( sal_Int32 nCol, sal_Int32 nRow ) const
1461 {
1462     return mrSheetGlob.getCellSize( nCol, nRow );
1463 }
1464 
1465 Size WorksheetHelper::getDrawPageSize() const
1466 {
1467     return mrSheetGlob.getDrawPageSize();
1468 }
1469 
1470 SheetDataBuffer& WorksheetHelper::getSheetData() const
1471 {
1472     return mrSheetGlob.getSheetData();
1473 }
1474 
1475 CondFormatBuffer& WorksheetHelper::getCondFormats() const
1476 {
1477     return mrSheetGlob.getCondFormats();
1478 }
1479 
1480 CommentsBuffer& WorksheetHelper::getComments() const
1481 {
1482     return mrSheetGlob.getComments();
1483 }
1484 
1485 AutoFilterBuffer& WorksheetHelper::getAutoFilters() const
1486 {
1487     return mrSheetGlob.getAutoFilters();
1488 }
1489 
1490 QueryTableBuffer& WorksheetHelper::getQueryTables() const
1491 {
1492     return mrSheetGlob.getQueryTables();
1493 }
1494 
1495 WorksheetSettings& WorksheetHelper::getWorksheetSettings() const
1496 {
1497     return mrSheetGlob.getWorksheetSettings();
1498 }
1499 
1500 PageSettings& WorksheetHelper::getPageSettings() const
1501 {
1502     return mrSheetGlob.getPageSettings();
1503 }
1504 
1505 SheetViewSettings& WorksheetHelper::getSheetViewSettings() const
1506 {
1507     return mrSheetGlob.getSheetViewSettings();
1508 }
1509 
1510 VmlDrawing& WorksheetHelper::getVmlDrawing() const
1511 {
1512     return mrSheetGlob.getVmlDrawing();
1513 }
1514 
1515 BiffSheetDrawing& WorksheetHelper::getBiffDrawing() const
1516 {
1517     return mrSheetGlob.getBiffDrawing();
1518 }
1519 
1520 void WorksheetHelper::setSheetType( WorksheetType eSheetType )
1521 {
1522     mrSheetGlob.setSheetType( eSheetType );
1523 }
1524 
1525 void WorksheetHelper::setPageBreak( const PageBreakModel& rModel, bool bRowBreak )
1526 {
1527     mrSheetGlob.setPageBreak( rModel, bRowBreak );
1528 }
1529 
1530 void WorksheetHelper::setHyperlink( const HyperlinkModel& rModel )
1531 {
1532     mrSheetGlob.setHyperlink( rModel );
1533 }
1534 
1535 void WorksheetHelper::setValidation( const ValidationModel& rModel )
1536 {
1537     mrSheetGlob.setValidation( rModel );
1538 }
1539 
1540 void WorksheetHelper::setLabelRanges( const ApiCellRangeList& rColRanges, const ApiCellRangeList& rRowRanges )
1541 {
1542     const CellAddress& rMaxPos = getAddressConverter().getMaxApiAddress();
1543     PropertySet aPropSet( getSheet() );
1544 
1545     if( !rColRanges.empty() )
1546     {
1547         Reference< XLabelRanges > xLabelRanges( aPropSet.getAnyProperty( PROP_ColumnLabelRanges ), UNO_QUERY );
1548         if( xLabelRanges.is() )
1549         {
1550             for( ApiCellRangeList::const_iterator aIt = rColRanges.begin(), aEnd = rColRanges.end(); aIt != aEnd; ++aIt )
1551             {
1552                 CellRangeAddress aDataRange = *aIt;
1553                 if( aDataRange.EndRow < rMaxPos.Row )
1554                 {
1555                     aDataRange.StartRow = aDataRange.EndRow + 1;
1556                     aDataRange.EndRow = rMaxPos.Row;
1557                 }
1558                 else if( aDataRange.StartRow > 0 )
1559                 {
1560                     aDataRange.EndRow = aDataRange.StartRow - 1;
1561                     aDataRange.StartRow = 0;
1562                 }
1563                 xLabelRanges->addNew( *aIt, aDataRange );
1564             }
1565         }
1566     }
1567 
1568     if( !rRowRanges.empty() )
1569     {
1570         Reference< XLabelRanges > xLabelRanges( aPropSet.getAnyProperty( PROP_RowLabelRanges ), UNO_QUERY );
1571         if( xLabelRanges.is() )
1572         {
1573             for( ApiCellRangeList::const_iterator aIt = rRowRanges.begin(), aEnd = rRowRanges.end(); aIt != aEnd; ++aIt )
1574             {
1575                 CellRangeAddress aDataRange = *aIt;
1576                 if( aDataRange.EndColumn < rMaxPos.Column )
1577                 {
1578                     aDataRange.StartColumn = aDataRange.EndColumn + 1;
1579                     aDataRange.EndColumn = rMaxPos.Column;
1580                 }
1581                 else if( aDataRange.StartColumn > 0 )
1582                 {
1583                     aDataRange.EndColumn = aDataRange.StartColumn - 1;
1584                     aDataRange.StartColumn = 0;
1585                 }
1586                 xLabelRanges->addNew( *aIt, aDataRange );
1587             }
1588         }
1589     }
1590 }
1591 
1592 void WorksheetHelper::setDrawingPath( const OUString& rDrawingPath )
1593 {
1594     mrSheetGlob.setDrawingPath( rDrawingPath );
1595 }
1596 
1597 void WorksheetHelper::setVmlDrawingPath( const OUString& rVmlDrawingPath )
1598 {
1599     mrSheetGlob.setVmlDrawingPath( rVmlDrawingPath );
1600 }
1601 
1602 void WorksheetHelper::extendUsedArea( const CellAddress& rAddress )
1603 {
1604     mrSheetGlob.extendUsedArea( rAddress );
1605 }
1606 
1607 void WorksheetHelper::extendUsedArea( const CellRangeAddress& rRange )
1608 {
1609     mrSheetGlob.extendUsedArea( rRange );
1610 }
1611 
1612 void WorksheetHelper::extendShapeBoundingBox( const Rectangle& rShapeRect )
1613 {
1614     mrSheetGlob.extendShapeBoundingBox( rShapeRect );
1615 }
1616 
1617 void WorksheetHelper::setBaseColumnWidth( sal_Int32 nWidth )
1618 {
1619     mrSheetGlob.setBaseColumnWidth( nWidth );
1620 }
1621 
1622 void WorksheetHelper::setDefaultColumnWidth( double fWidth )
1623 {
1624     mrSheetGlob.setDefaultColumnWidth( fWidth );
1625 }
1626 
1627 void WorksheetHelper::setDefaultColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId )
1628 {
1629     mrSheetGlob.convertColumnFormat( nFirstCol, nLastCol, nXfId );
1630 }
1631 
1632 void WorksheetHelper::setColumnModel( const ColumnModel& rModel )
1633 {
1634     mrSheetGlob.setColumnModel( rModel );
1635 }
1636 
1637 void WorksheetHelper::setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom )
1638 {
1639     mrSheetGlob.setDefaultRowSettings( fHeight, bCustomHeight, bHidden, bThickTop, bThickBottom );
1640 }
1641 
1642 void WorksheetHelper::setRowModel( const RowModel& rModel )
1643 {
1644     mrSheetGlob.setRowModel( rModel );
1645 }
1646 
1647 void WorksheetHelper::setManualRowHeight( sal_Int32 nRow )
1648 {
1649     mrSheetGlob.setManualRowHeight( nRow );
1650 }
1651 
1652 void WorksheetHelper::putValue( const CellAddress& rAddress, double fValue ) const
1653 {
1654     Reference< XCell > xCell = getCell( rAddress );
1655     OSL_ENSURE( xCell.is(), "WorksheetHelper::putValue - missing cell interface" );
1656     if( xCell.is() ) xCell->setValue( fValue );
1657 }
1658 
1659 void WorksheetHelper::putString( const CellAddress& rAddress, const OUString& rText ) const
1660 {
1661     Reference< XText > xText( getCell( rAddress ), UNO_QUERY );
1662     OSL_ENSURE( xText.is(), "WorksheetHelper::putString - missing text interface" );
1663     if( xText.is() ) xText->setString( rText );
1664 }
1665 
1666 void WorksheetHelper::putRichString( const CellAddress& rAddress, const RichString& rString, const Font* pFirstPortionFont ) const
1667 {
1668     Reference< XText > xText( getCell( rAddress ), UNO_QUERY );
1669     OSL_ENSURE( xText.is(), "WorksheetHelper::putRichString - missing text interface" );
1670     /*  Passing false will always append the portions to the XText. This is
1671         essential for special rich formatting attributes at the leading text
1672         portion supported by edit cells only, e.g. font escapement. */
1673     rString.convert( xText, false, pFirstPortionFont );
1674 }
1675 
1676 void WorksheetHelper::putFormulaTokens( const CellAddress& rAddress, const ApiTokenSequence& rTokens ) const
1677 {
1678     Reference< XFormulaTokens > xTokens( getCell( rAddress ), UNO_QUERY );
1679     OSL_ENSURE( xTokens.is(), "WorksheetHelper::putFormulaTokens - missing token interface" );
1680     if( xTokens.is() ) xTokens->setTokens( rTokens );
1681 }
1682 
1683 void WorksheetHelper::initializeWorksheetImport()
1684 {
1685     mrSheetGlob.initializeWorksheetImport();
1686 }
1687 
1688 void WorksheetHelper::finalizeWorksheetImport()
1689 {
1690     mrSheetGlob.finalizeWorksheetImport();
1691 }
1692 
1693 // ============================================================================
1694 // ============================================================================
1695 
1696 } // namespace xls
1697 } // namespace oox
1698