1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <memory> 21 #include <worksheethelper.hxx> 22 23 #include <algorithm> 24 #include <utility> 25 #include <com/sun/star/awt/Point.hpp> 26 #include <com/sun/star/awt/Size.hpp> 27 #include <com/sun/star/drawing/XDrawPageSupplier.hpp> 28 #include <com/sun/star/sheet/ConditionOperator2.hpp> 29 #include <com/sun/star/sheet/TableValidationVisibility.hpp> 30 #include <com/sun/star/sheet/ValidationType.hpp> 31 #include <com/sun/star/sheet/ValidationAlertStyle.hpp> 32 #include <com/sun/star/sheet/XCellAddressable.hpp> 33 #include <com/sun/star/sheet/XMultiFormulaTokens.hpp> 34 #include <com/sun/star/sheet/XSheetCellRangeContainer.hpp> 35 #include <com/sun/star/sheet/XSheetCondition2.hpp> 36 #include <com/sun/star/sheet/XSheetOutline.hpp> 37 #include <com/sun/star/sheet/XSpreadsheet.hpp> 38 #include <com/sun/star/table/XColumnRowRange.hpp> 39 #include <com/sun/star/text/WritingMode2.hpp> 40 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 41 #include <osl/diagnose.h> 42 #include <rtl/ustrbuf.hxx> 43 #include <oox/core/filterbase.hxx> 44 #include <oox/helper/propertyset.hxx> 45 #include <oox/token/properties.hxx> 46 #include <oox/token/tokens.hxx> 47 #include <addressconverter.hxx> 48 #include <autofilterbuffer.hxx> 49 #include <commentsbuffer.hxx> 50 #include <condformatbuffer.hxx> 51 #include <document.hxx> 52 #include <drawingfragment.hxx> 53 #include <pagesettings.hxx> 54 #include <querytablebuffer.hxx> 55 #include <sheetdatabuffer.hxx> 56 #include <stylesbuffer.hxx> 57 #include <tokenuno.hxx> 58 #include <unitconverter.hxx> 59 #include <viewsettings.hxx> 60 #include <worksheetbuffer.hxx> 61 #include <worksheetsettings.hxx> 62 #include <formulabuffer.hxx> 63 #include <scitems.hxx> 64 #include <editutil.hxx> 65 #include <tokenarray.hxx> 66 #include <tablebuffer.hxx> 67 #include <documentimport.hxx> 68 #include <stlsheet.hxx> 69 #include <stlpool.hxx> 70 #include <cellvalue.hxx> 71 #include <columnspanset.hxx> 72 #include <dbdata.hxx> 73 74 #include <svl/stritem.hxx> 75 #include <editeng/eeitem.hxx> 76 #include <editeng/editobj.hxx> 77 #include <editeng/flditem.hxx> 78 #include <tools/UnitConversion.hxx> 79 80 namespace oox::xls { 81 82 using namespace ::com::sun::star; 83 using namespace ::com::sun::star::beans; 84 using namespace ::com::sun::star::drawing; 85 using namespace ::com::sun::star::lang; 86 using namespace ::com::sun::star::sheet; 87 using namespace ::com::sun::star::table; 88 using namespace ::com::sun::star::text; 89 using namespace ::com::sun::star::uno; 90 91 namespace { 92 93 void lclUpdateProgressBar( const ISegmentProgressBarRef& rxProgressBar, double fPosition ) 94 { 95 if( rxProgressBar ) 96 rxProgressBar->setPosition( fPosition ); 97 } 98 99 } // namespace 100 101 ColumnModel::ColumnModel() : 102 maRange( -1 ), 103 mfWidth( 0.0 ), 104 mnXfId( -1 ), 105 mnLevel( 0 ), 106 mbShowPhonetic( false ), 107 mbHidden( false ), 108 mbCollapsed( false ) 109 { 110 } 111 112 bool ColumnModel::isMergeable( const ColumnModel& rModel ) const 113 { 114 return 115 (maRange.mnFirst <= rModel.maRange.mnFirst) && 116 (rModel.maRange.mnFirst <= maRange.mnLast + 1) && 117 (mfWidth == rModel.mfWidth) && 118 // ignore mnXfId, cell formatting is always set directly 119 (mnLevel == rModel.mnLevel) && 120 (mbHidden == rModel.mbHidden) && 121 (mbCollapsed == rModel.mbCollapsed); 122 } 123 124 RowModel::RowModel() : 125 mnRow( -1 ), 126 mfHeight( 0.0 ), 127 mnXfId( -1 ), 128 mnLevel( 0 ), 129 mbCustomHeight( false ), 130 mbCustomFormat( false ), 131 mbShowPhonetic( false ), 132 mbHidden( false ), 133 mbCollapsed( false ), 134 mbThickTop( false ), 135 mbThickBottom( false ) 136 { 137 } 138 139 void RowModel::insertColSpan( const ValueRange& rColSpan ) 140 { 141 if( (0 <= rColSpan.mnFirst) && (rColSpan.mnFirst <= rColSpan.mnLast) ) 142 maColSpans.insert( rColSpan ); 143 } 144 145 bool RowModel::isMergeable( const RowModel& rModel ) const 146 { 147 return 148 // ignore maColSpans - is handled separately in SheetDataBuffer class 149 (mfHeight == rModel.mfHeight) && 150 // ignore mnXfId, mbCustomFormat, mbShowPhonetic - cell formatting is always set directly 151 (mnLevel == rModel.mnLevel) && 152 (mbCustomHeight == rModel.mbCustomHeight) && 153 (mbHidden == rModel.mbHidden) && 154 (mbCollapsed == rModel.mbCollapsed); 155 } 156 157 PageBreakModel::PageBreakModel() 158 : mnColRow(0) 159 , mnMin(0) 160 , mnMax(0) 161 , mbManual(false) 162 { 163 } 164 165 HyperlinkModel::HyperlinkModel() 166 { 167 } 168 169 ValidationModel::ValidationModel() : 170 mnType( XML_none ), 171 mnOperator( XML_between ), 172 mnErrorStyle( XML_stop ), 173 mbShowInputMsg( false ), 174 mbShowErrorMsg( false ), 175 mbNoDropDown( false ), 176 mbAllowBlank( false ) 177 { 178 } 179 180 void ValidationModel::setBiffType( sal_uInt8 nType ) 181 { 182 static const sal_Int32 spnTypeIds[] = { 183 XML_none, XML_whole, XML_decimal, XML_list, XML_date, XML_time, XML_textLength, XML_custom }; 184 mnType = STATIC_ARRAY_SELECT( spnTypeIds, nType, XML_none ); 185 } 186 187 void ValidationModel::setBiffOperator( sal_uInt8 nOperator ) 188 { 189 static const sal_Int32 spnOperators[] = { 190 XML_between, XML_notBetween, XML_equal, XML_notEqual, 191 XML_greaterThan, XML_lessThan, XML_greaterThanOrEqual, XML_lessThanOrEqual }; 192 mnOperator = STATIC_ARRAY_SELECT( spnOperators, nOperator, XML_TOKEN_INVALID ); 193 } 194 195 void ValidationModel::setBiffErrorStyle( sal_uInt8 nErrorStyle ) 196 { 197 static const sal_Int32 spnErrorStyles[] = { XML_stop, XML_warning, XML_information }; 198 mnErrorStyle = STATIC_ARRAY_SELECT( spnErrorStyles, nErrorStyle, XML_stop ); 199 } 200 201 class WorksheetGlobals : public WorkbookHelper, public IWorksheetProgress 202 { 203 public: 204 explicit WorksheetGlobals( 205 const WorkbookHelper& rHelper, 206 const ISegmentProgressBarRef& rxProgressBar, 207 WorksheetType eSheetType, 208 SCTAB nSheet ); 209 210 /** Returns true, if this helper refers to an existing Calc sheet. */ 211 bool isValidSheet() const { return mxSheet.is(); } 212 213 /** Returns the type of this sheet. */ 214 WorksheetType getSheetType() const { return meSheetType; } 215 /** Returns the index of the current sheet. */ 216 SCTAB getSheetIndex() const { return maUsedArea.aStart.Tab(); } 217 /** Returns the XSpreadsheet interface of the current sheet. */ 218 const Reference< XSpreadsheet >& getSheet() const { return mxSheet; } 219 220 /** Returns the XCell interface for the passed cell address. */ 221 Reference< XCell > getCell( const ScAddress& rAddress ) const; 222 /** Returns the XCellRange interface for the passed cell range address. */ 223 Reference< XCellRange > getCellRange( const ScRange& rRange ) const; 224 /** Returns the XSheetCellRanges interface for the passed cell range addresses. */ 225 Reference< XSheetCellRanges > getCellRangeList( const ScRangeList& rRanges ) const; 226 227 /** Returns the XCellRange interface for a column. */ 228 Reference< XCellRange > getColumn( sal_Int32 nCol ) const; 229 /** Returns the XCellRange interface for a row. */ 230 Reference< XCellRange > getRow( sal_Int32 nRow ) const; 231 232 /** Returns the XDrawPage interface of the draw page of the current sheet. */ 233 Reference< XDrawPage > getDrawPage() const; 234 /** Returns the size of the entire drawing page in 1/100 mm. */ 235 const awt::Size& getDrawPageSize() const; 236 237 /** Returns the absolute position of the top-left corner of the cell in 1/100 mm. */ 238 awt::Point getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const; 239 240 /** Returns the address of the cell that contains the passed point in 1/100 mm. */ 241 ScAddress getCellAddressFromPosition( const awt::Point& rPosition ) const; 242 /** Returns the cell range address that contains the passed rectangle in 1/100 mm. */ 243 ScRange getCellRangeFromRectangle( const awt::Rectangle& rRect ) const; 244 245 /** Returns the buffer for cell contents and cell formatting. */ 246 SheetDataBuffer& getSheetData() { return maSheetData; } 247 /** Returns the conditional formatting in this sheet. */ 248 CondFormatBuffer& getCondFormats() { return maCondFormats; } 249 /** Returns the buffer for all cell comments in this sheet. */ 250 CommentsBuffer& getComments() { return maComments; } 251 /** Returns the auto filters for the sheet. */ 252 AutoFilterBuffer& getAutoFilters() { return maAutoFilters; } 253 /** Returns the buffer for all web query tables in this sheet. */ 254 QueryTableBuffer& getQueryTables() { return maQueryTables; } 255 /** Returns the worksheet settings object. */ 256 WorksheetSettings& getWorksheetSettings() { return maSheetSett; } 257 /** Returns the page/print settings for this sheet. */ 258 PageSettings& getPageSettings() { return maPageSett; } 259 /** Returns the view settings for this sheet. */ 260 SheetViewSettings& getSheetViewSettings() { return maSheetViewSett; } 261 /** Returns the VML drawing page for this sheet (OOXML/BIFF12 only). */ 262 VmlDrawing& getVmlDrawing() { return *mxVmlDrawing; } 263 /** returns the ExtLst entries that need to be filled */ 264 ExtLst& getExtLst() { return maExtLst; } 265 266 /** Sets a column or row page break described in the passed struct. */ 267 void setPageBreak( const PageBreakModel& rModel, bool bRowBreak ); 268 /** Inserts the hyperlink URL into the spreadsheet. */ 269 void setHyperlink( const HyperlinkModel& rModel ); 270 /** Inserts the data validation settings into the spreadsheet. */ 271 void setValidation( const ValidationModel& rModel ); 272 /** Sets the path to the DrawingML fragment of this sheet. */ 273 void setDrawingPath( const OUString& rDrawingPath ); 274 /** Sets the path to the legacy VML drawing fragment of this sheet. */ 275 void setVmlDrawingPath( const OUString& rVmlDrawingPath ); 276 277 /** Extends the used area of this sheet by the passed cell position. */ 278 void extendUsedArea( const ScAddress& rAddress ); 279 280 /** Extends the used area of this sheet by the passed cell range. */ 281 void extendUsedArea( const ScRange& rRange ); 282 /** Extends the shape bounding box by the position and size of the passed rectangle. */ 283 void extendShapeBoundingBox( const awt::Rectangle& rShapeRect ); 284 285 /** Sets base width for all columns (without padding pixels). This value 286 is only used, if base width has not been set with setDefaultColumnWidth(). */ 287 void setBaseColumnWidth( sal_Int32 nWidth ); 288 /** Sets default width for all columns. This function overrides the base 289 width set with the setBaseColumnWidth() function. */ 290 void setDefaultColumnWidth( double fWidth ); 291 /** Sets column settings for a specific column range. 292 @descr Column default formatting is converted directly, other settings 293 are cached and converted in the finalizeImport() call. */ 294 void setColumnModel( const ColumnModel& rModel ); 295 /** Converts column default cell formatting. */ 296 void convertColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId ); 297 298 /** Sets default height and hidden state for all unused rows in the sheet. */ 299 void setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom ); 300 /** Sets row settings for a specific row. 301 @descr Row default formatting is converted directly, other settings 302 are cached and converted in the finalizeImport() call. */ 303 void setRowModel( const RowModel& rModel ); 304 305 /** Initial conversion before importing the worksheet. */ 306 void initializeWorksheetImport(); 307 /** Final conversion after importing the worksheet. */ 308 void finalizeWorksheetImport(); 309 310 void finalizeDrawingImport(); 311 312 /// Allow the threaded importer to override our progress bar impl. 313 virtual ISegmentProgressBarRef getRowProgress() override 314 { 315 return mxRowProgress; 316 } 317 virtual void setCustomRowProgress( const ISegmentProgressBarRef &rxRowProgress ) override 318 { 319 mxRowProgress = rxRowProgress; 320 mbFastRowProgress = true; 321 } 322 323 private: 324 typedef ::std::vector< sal_Int32 > OutlineLevelVec; 325 typedef ::std::pair< ColumnModel, sal_Int32 > ColumnModelRange; 326 typedef ::std::map< sal_Int32, ColumnModelRange > ColumnModelRangeMap; 327 typedef ::std::pair< RowModel, sal_Int32 > RowModelRange; 328 typedef ::std::map< sal_Int32, RowModelRange > RowModelRangeMap; 329 330 /** Inserts all imported hyperlinks into their cell ranges. */ 331 void finalizeHyperlinkRanges(); 332 /** Generates the final URL for the passed hyperlink. */ 333 OUString getHyperlinkUrl( const HyperlinkModel& rHyperlink ) const; 334 /** Inserts a hyperlinks into the specified cell. */ 335 void insertHyperlink( const ScAddress& rAddress, const OUString& rUrl ); 336 337 /** Inserts all imported data validations into their cell ranges. */ 338 void finalizeValidationRanges() const; 339 340 /** Converts column properties for all columns in the sheet. */ 341 void convertColumns(); 342 /** Converts column properties. */ 343 void convertColumns( OutlineLevelVec& orColLevels, const ValueRange& rColRange, const ColumnModel& rModel ); 344 345 /** Converts row properties for all rows in the sheet. */ 346 void convertRows(const std::vector<sc::ColRowSpan>& rSpans); 347 /** Converts row properties. */ 348 void convertRows(OutlineLevelVec& orRowLevels, const ValueRange& rRowRange, 349 const RowModel& rModel, 350 const std::vector<sc::ColRowSpan>& rSpans, 351 double fDefHeight = -1.0); 352 353 /** Converts outline grouping for the passed column or row. */ 354 void convertOutlines( OutlineLevelVec& orLevels, sal_Int32 nColRow, sal_Int32 nLevel, bool bCollapsed, bool bRows ); 355 /** Groups columns or rows for the given range. */ 356 void groupColumnsOrRows( sal_Int32 nFirstColRow, sal_Int32 nLastColRow, bool bCollapsed, bool bRows ); 357 358 /** Imports the drawings of the sheet (DML, VML, DFF) and updates the used area. */ 359 void finalizeDrawings(); 360 361 /** Update the row import progress bar */ 362 void UpdateRowProgress( const ScRange& rUsedArea, SCROW nRow ); 363 364 private: 365 typedef ::std::unique_ptr< VmlDrawing > VmlDrawingPtr; 366 367 const ScAddress& mrMaxApiPos; /// Reference to maximum Calc cell address from address converter. 368 ScRange maUsedArea; /// Used area of the sheet, and sheet index of the sheet. 369 ColumnModel maDefColModel; /// Default column formatting. 370 ColumnModelRangeMap maColModels; /// Ranges of columns sorted by first column index. 371 RowModel maDefRowModel; /// Default row formatting. 372 RowModelRangeMap maRowModels; /// Ranges of rows sorted by first row index. 373 std::vector< HyperlinkModel > maHyperlinks; /// Cell ranges containing hyperlinks. 374 std::vector< ValidationModel > maValidations; /// Cell ranges containing data validation settings. 375 SheetDataBuffer maSheetData; /// Buffer for cell contents and cell formatting. 376 CondFormatBuffer maCondFormats; /// Buffer for conditional formatting. 377 CommentsBuffer maComments; /// Buffer for all cell comments in this sheet. 378 AutoFilterBuffer maAutoFilters; /// Sheet auto filters (not associated to a table). 379 QueryTableBuffer maQueryTables; /// Buffer for all web query tables in this sheet. 380 WorksheetSettings maSheetSett; /// Global settings for this sheet. 381 PageSettings maPageSett; /// Page/print settings for this sheet. 382 SheetViewSettings maSheetViewSett; /// View settings for this sheet. 383 VmlDrawingPtr mxVmlDrawing; /// Collection of all VML shapes. 384 ExtLst maExtLst; /// List of extended elements 385 OUString maDrawingPath; /// Path to DrawingML fragment. 386 OUString maVmlDrawingPath; /// Path to legacy VML drawing fragment. 387 awt::Size maDrawPageSize; /// Current size of the drawing page in 1/100 mm. 388 awt::Rectangle maShapeBoundingBox; /// Bounding box for all shapes from all drawings. 389 ISegmentProgressBarRef mxProgressBar; /// Sheet progress bar. 390 bool mbFastRowProgress; /// Do we have a progress bar thread ? 391 ISegmentProgressBarRef mxRowProgress; /// Progress bar for row/cell processing. 392 ISegmentProgressBarRef mxFinalProgress; /// Progress bar for finalization. 393 WorksheetType meSheetType; /// Type of this sheet. 394 Reference< XSpreadsheet > mxSheet; /// Reference to the current sheet. 395 bool mbHasDefWidth; /// True = default column width is set from defaultColWidth attribute. 396 }; 397 398 constexpr OUStringLiteral gaSheetCellRanges( u"com.sun.star.sheet.SheetCellRanges" ); /// Service name for a SheetCellRanges object. 399 400 WorksheetGlobals::WorksheetGlobals( const WorkbookHelper& rHelper, const ISegmentProgressBarRef& rxProgressBar, WorksheetType eSheetType, SCTAB nSheet ) : 401 WorkbookHelper( rHelper ), 402 mrMaxApiPos( rHelper.getAddressConverter().getMaxApiAddress() ), 403 maUsedArea( SCCOL_MAX, SCROW_MAX, nSheet, -1, -1, nSheet ), // Set start address to largest possible value, and end address to smallest 404 maSheetData( *this ), 405 maCondFormats( *this ), 406 maComments( *this ), 407 maAutoFilters( *this ), 408 maQueryTables( *this ), 409 maSheetSett( *this ), 410 maPageSett( *this ), 411 maSheetViewSett( *this ), 412 mxProgressBar( rxProgressBar ), 413 mbFastRowProgress( false ), 414 meSheetType( eSheetType ), 415 mxSheet(getSheetFromDoc( nSheet )), 416 mbHasDefWidth( false ) 417 { 418 if( !mxSheet.is() ) 419 maUsedArea.aStart.SetTab( -1 ); 420 421 // default column settings (width and hidden state may be updated later) 422 maDefColModel.mfWidth = 8.5; 423 maDefColModel.mnXfId = -1; 424 maDefColModel.mnLevel = 0; 425 maDefColModel.mbHidden = false; 426 maDefColModel.mbCollapsed = false; 427 428 // default row settings (height and hidden state may be updated later) 429 maDefRowModel.mfHeight = 0.0; 430 maDefRowModel.mnXfId = -1; 431 maDefRowModel.mnLevel = 0; 432 maDefRowModel.mbCustomHeight = false; 433 maDefRowModel.mbCustomFormat = false; 434 maDefRowModel.mbShowPhonetic = false; 435 maDefRowModel.mbHidden = false; 436 maDefRowModel.mbCollapsed = false; 437 438 // buffers 439 mxVmlDrawing.reset( new VmlDrawing( *this ) ); 440 441 // prepare progress bars 442 if( mxProgressBar ) 443 { 444 mxRowProgress = mxProgressBar->createSegment( 0.5 ); 445 mxFinalProgress = mxProgressBar->createSegment( 0.5 ); 446 } 447 } 448 449 Reference< XCell > WorksheetGlobals::getCell( const ScAddress& rAddress ) const 450 { 451 Reference< XCell > xCell; 452 if( mxSheet.is() ) try 453 { 454 xCell = mxSheet->getCellByPosition( rAddress.Col(), rAddress.Row() ); 455 } 456 catch( Exception& ) 457 { 458 } 459 return xCell; 460 } 461 462 Reference< XCellRange > WorksheetGlobals::getCellRange( const ScRange& rRange ) const 463 { 464 Reference< XCellRange > xRange; 465 if( mxSheet.is() ) try 466 { 467 xRange = mxSheet->getCellRangeByPosition( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row() ); 468 } 469 catch( Exception& ) 470 { 471 } 472 return xRange; 473 } 474 475 Reference< XSheetCellRanges > WorksheetGlobals::getCellRangeList( const ScRangeList& rRanges ) const 476 { 477 Reference< XSheetCellRanges > xRanges; 478 if( mxSheet.is() && !rRanges.empty() ) try 479 { 480 xRanges.set( getBaseFilter().getModelFactory()->createInstance( gaSheetCellRanges ), UNO_QUERY_THROW ); 481 Reference< XSheetCellRangeContainer > xRangeCont( xRanges, UNO_QUERY_THROW ); 482 xRangeCont->addRangeAddresses( AddressConverter::toApiSequence(rRanges), false ); 483 } 484 catch( Exception& ) 485 { 486 } 487 return xRanges; 488 } 489 490 Reference< XCellRange > WorksheetGlobals::getColumn( sal_Int32 nCol ) const 491 { 492 Reference< XCellRange > xColumn; 493 try 494 { 495 Reference< XColumnRowRange > xColRowRange( mxSheet, UNO_QUERY_THROW ); 496 Reference< XTableColumns > xColumns( xColRowRange->getColumns(), UNO_SET_THROW ); 497 xColumn.set( xColumns->getByIndex( nCol ), UNO_QUERY ); 498 } 499 catch( Exception& ) 500 { 501 } 502 return xColumn; 503 } 504 505 Reference< XCellRange > WorksheetGlobals::getRow( sal_Int32 nRow ) const 506 { 507 Reference< XCellRange > xRow; 508 try 509 { 510 Reference< XColumnRowRange > xColRowRange( mxSheet, UNO_QUERY_THROW ); 511 Reference< XTableRows > xRows( xColRowRange->getRows(), UNO_SET_THROW ); 512 xRow.set( xRows->getByIndex( nRow ), UNO_QUERY ); 513 } 514 catch( Exception& ) 515 { 516 } 517 return xRow; 518 } 519 520 Reference< XDrawPage > WorksheetGlobals::getDrawPage() const 521 { 522 Reference< XDrawPage > xDrawPage; 523 try 524 { 525 xDrawPage = Reference< XDrawPageSupplier >( mxSheet, UNO_QUERY_THROW )->getDrawPage(); 526 } 527 catch( Exception& ) 528 { 529 } 530 return xDrawPage; 531 } 532 533 const awt::Size& WorksheetGlobals::getDrawPageSize() const 534 { 535 OSL_ENSURE( (maDrawPageSize.Width > 0) && (maDrawPageSize.Height > 0), "WorksheetGlobals::getDrawPageSize - called too early, size invalid" ); 536 return maDrawPageSize; 537 } 538 539 awt::Point WorksheetGlobals::getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const 540 { 541 awt::Point aPoint; 542 PropertySet aCellProp( getCell( ScAddress( nCol, nRow, getSheetIndex() ) ) ); 543 aCellProp.getProperty( aPoint, PROP_Position ); 544 return aPoint; 545 } 546 547 namespace { 548 549 sal_Int32 lclGetMidAddr( sal_Int32 nBegAddr, sal_Int32 nEndAddr, sal_Int32 nBegPos, sal_Int32 nEndPos, sal_Int32 nSearchPos ) 550 { 551 // use sal_Int64 to prevent integer overflow 552 return nBegAddr + 1 + static_cast< sal_Int32 >( static_cast< sal_Int64 >( nEndAddr - nBegAddr - 2 ) * (nSearchPos - nBegPos) / (nEndPos - nBegPos) ); 553 } 554 555 bool lclPrepareInterval( sal_Int32 nBegAddr, sal_Int32& rnMidAddr, sal_Int32 nEndAddr, 556 sal_Int32 nBegPos, sal_Int32 nEndPos, sal_Int32 nSearchPos ) 557 { 558 // searched position before nBegPos -> use nBegAddr 559 if( nSearchPos <= nBegPos ) 560 { 561 rnMidAddr = nBegAddr; 562 return false; 563 } 564 565 // searched position after nEndPos, or begin next to end -> use nEndAddr 566 if( (nSearchPos >= nEndPos) || (nBegAddr + 1 >= nEndAddr) ) 567 { 568 rnMidAddr = nEndAddr; 569 return false; 570 } 571 572 /* Otherwise find mid address according to position. lclGetMidAddr() will 573 return an address between nBegAddr and nEndAddr. */ 574 rnMidAddr = lclGetMidAddr( nBegAddr, nEndAddr, nBegPos, nEndPos, nSearchPos ); 575 return true; 576 } 577 578 bool lclUpdateInterval( sal_Int32& rnBegAddr, sal_Int32& rnMidAddr, sal_Int32& rnEndAddr, 579 sal_Int32& rnBegPos, sal_Int32 nMidPos, sal_Int32& rnEndPos, sal_Int32 nSearchPos ) 580 { 581 // nSearchPos < nMidPos: use the interval [begin,mid] in the next iteration 582 if( nSearchPos < nMidPos ) 583 { 584 // if rnBegAddr is next to rnMidAddr, the latter is the column/row in question 585 if( rnBegAddr + 1 >= rnMidAddr ) 586 return false; 587 // otherwise, set interval end to mid 588 rnEndPos = nMidPos; 589 rnEndAddr = rnMidAddr; 590 rnMidAddr = lclGetMidAddr( rnBegAddr, rnEndAddr, rnBegPos, rnEndPos, nSearchPos ); 591 return true; 592 } 593 594 // nSearchPos > nMidPos: use the interval [mid,end] in the next iteration 595 if( nSearchPos > nMidPos ) 596 { 597 // if rnMidAddr is next to rnEndAddr, the latter is the column/row in question 598 if( rnMidAddr + 1 >= rnEndAddr ) 599 { 600 rnMidAddr = rnEndAddr; 601 return false; 602 } 603 // otherwise, set interval start to mid 604 rnBegPos = nMidPos; 605 rnBegAddr = rnMidAddr; 606 rnMidAddr = lclGetMidAddr( rnBegAddr, rnEndAddr, rnBegPos, rnEndPos, nSearchPos ); 607 return true; 608 } 609 610 // nSearchPos == nMidPos: rnMidAddr is the column/row in question, do not loop anymore 611 return false; 612 } 613 614 } // namespace 615 616 ScAddress WorksheetGlobals::getCellAddressFromPosition( const awt::Point& rPosition ) const 617 { 618 // starting cell address and its position in drawing layer (top-left edge) 619 sal_Int32 nBegCol = 0; 620 sal_Int32 nBegRow = 0; 621 awt::Point aBegPos( 0, 0 ); 622 623 // end cell address and its position in drawing layer (bottom-right edge) 624 sal_Int32 nEndCol = mrMaxApiPos.Col() + 1; 625 sal_Int32 nEndRow = mrMaxApiPos.Row() + 1; 626 awt::Point aEndPos( maDrawPageSize.Width, maDrawPageSize.Height ); 627 628 // starting point for interval search 629 sal_Int32 nMidCol, nMidRow; 630 bool bLoopCols = lclPrepareInterval( nBegCol, nMidCol, nEndCol, aBegPos.X, aEndPos.X, rPosition.X ); 631 bool bLoopRows = lclPrepareInterval( nBegRow, nMidRow, nEndRow, aBegPos.Y, aEndPos.Y, rPosition.Y ); 632 awt::Point aMidPos = getCellPosition( nMidCol, nMidRow ); 633 634 /* The loop will find the column/row index of the cell right of/below 635 the cell containing the passed point, unless the point is located at 636 the top or left border of the containing cell. */ 637 while( bLoopCols || bLoopRows ) 638 { 639 bLoopCols = bLoopCols && lclUpdateInterval( nBegCol, nMidCol, nEndCol, aBegPos.X, aMidPos.X, aEndPos.X, rPosition.X ); 640 bLoopRows = bLoopRows && lclUpdateInterval( nBegRow, nMidRow, nEndRow, aBegPos.Y, aMidPos.Y, aEndPos.Y, rPosition.Y ); 641 aMidPos = getCellPosition( nMidCol, nMidRow ); 642 } 643 644 /* The cell left of/above the current search position contains the passed 645 point, unless the point is located on the top/left border of the cell, 646 or the last column/row of the sheet has been reached. */ 647 if( aMidPos.X > rPosition.X ) --nMidCol; 648 if( aMidPos.Y > rPosition.Y ) --nMidRow; 649 return ScAddress( nMidCol, nMidRow, getSheetIndex() ); 650 } 651 652 ScRange WorksheetGlobals::getCellRangeFromRectangle( const awt::Rectangle& rRect ) const 653 { 654 ScAddress aStartAddr = getCellAddressFromPosition( awt::Point( rRect.X, rRect.Y ) ); 655 awt::Point aBotRight( rRect.X + rRect.Width, rRect.Y + rRect.Height ); 656 ScAddress aEndAddr = getCellAddressFromPosition( aBotRight ); 657 bool bMultiCols = aStartAddr.Col() < aEndAddr.Col(); 658 bool bMultiRows = aStartAddr.Row() < aEndAddr.Row(); 659 if( bMultiCols || bMultiRows ) 660 { 661 /* Reduce end position of the cell range to previous column or row, if 662 the rectangle ends exactly between two columns or rows. */ 663 awt::Point aEndPos = getCellPosition( aEndAddr.Col(), aEndAddr.Row() ); 664 if( bMultiCols && (aBotRight.X <= aEndPos.X) ) 665 aEndAddr.IncCol(-1); 666 if( bMultiRows && (aBotRight.Y <= aEndPos.Y) ) 667 aEndAddr.IncRow(-1); 668 } 669 return ScRange( aStartAddr.Col(), aStartAddr.Row(), getSheetIndex(), 670 aEndAddr.Col(), aEndAddr.Row(), getSheetIndex() ); 671 } 672 673 void WorksheetGlobals::setPageBreak( const PageBreakModel& rModel, bool bRowBreak ) 674 { 675 if( rModel.mbManual && (rModel.mnColRow > 0) ) 676 { 677 PropertySet aPropSet( bRowBreak ? getRow( rModel.mnColRow ) : getColumn( rModel.mnColRow ) ); 678 aPropSet.setProperty( PROP_IsStartOfNewPage, true ); 679 } 680 } 681 682 void WorksheetGlobals::setHyperlink( const HyperlinkModel& rModel ) 683 { 684 maHyperlinks.push_back( rModel ); 685 } 686 687 void WorksheetGlobals::setValidation( const ValidationModel& rModel ) 688 { 689 maValidations.push_back( rModel ); 690 } 691 692 void WorksheetGlobals::setDrawingPath( const OUString& rDrawingPath ) 693 { 694 maDrawingPath = rDrawingPath; 695 } 696 697 void WorksheetGlobals::setVmlDrawingPath( const OUString& rVmlDrawingPath ) 698 { 699 maVmlDrawingPath = rVmlDrawingPath; 700 } 701 702 void WorksheetGlobals::extendUsedArea( const ScAddress& rAddress ) 703 { 704 maUsedArea.aStart.SetCol( ::std::min( maUsedArea.aStart.Col(), rAddress.Col() ) ); 705 maUsedArea.aStart.SetRow( ::std::min( maUsedArea.aStart.Row(), rAddress.Row() ) ); 706 maUsedArea.aEnd.SetCol( ::std::max( maUsedArea.aEnd.Col(), rAddress.Col() ) ); 707 maUsedArea.aEnd.SetRow( ::std::max( maUsedArea.aEnd.Row(), rAddress.Row() ) ); 708 } 709 710 void WorksheetGlobals::extendUsedArea( const ScRange& rRange ) 711 { 712 extendUsedArea( rRange.aStart ); 713 extendUsedArea( rRange.aEnd ); 714 } 715 716 void WorksheetHelper::extendUsedArea( const ScRange& rRange ) 717 { 718 extendUsedArea( rRange.aStart ); 719 extendUsedArea( rRange.aEnd ); 720 } 721 722 void WorksheetGlobals::extendShapeBoundingBox( const awt::Rectangle& rShapeRect ) 723 { 724 if( (maShapeBoundingBox.Width == 0) && (maShapeBoundingBox.Height == 0) ) 725 { 726 // width and height of maShapeBoundingBox are assumed to be zero on first cell 727 maShapeBoundingBox = rShapeRect; 728 } 729 else 730 { 731 sal_Int32 nEndX = ::std::max( maShapeBoundingBox.X + maShapeBoundingBox.Width, rShapeRect.X + rShapeRect.Width ); 732 sal_Int32 nEndY = ::std::max( maShapeBoundingBox.Y + maShapeBoundingBox.Height, rShapeRect.Y + rShapeRect.Height ); 733 maShapeBoundingBox.X = ::std::min( maShapeBoundingBox.X, rShapeRect.X ); 734 maShapeBoundingBox.Y = ::std::min( maShapeBoundingBox.Y, rShapeRect.Y ); 735 maShapeBoundingBox.Width = nEndX - maShapeBoundingBox.X; 736 maShapeBoundingBox.Height = nEndY - maShapeBoundingBox.Y; 737 } 738 } 739 740 void WorksheetGlobals::setBaseColumnWidth( sal_Int32 nWidth ) 741 { 742 // do not modify width, if setDefaultColumnWidth() has been used 743 if( !mbHasDefWidth && (nWidth > 0) ) 744 { 745 // #i3006# add 5 pixels padding to the width 746 maDefColModel.mfWidth = nWidth + getUnitConverter().scaleValue( 5, Unit::ScreenX, Unit::Digit ); 747 } 748 } 749 750 void WorksheetGlobals::setDefaultColumnWidth( double fWidth ) 751 { 752 // overrides a width set with setBaseColumnWidth() 753 if( fWidth > 0.0 ) 754 { 755 maDefColModel.mfWidth = fWidth; 756 mbHasDefWidth = true; 757 } 758 } 759 760 void WorksheetGlobals::setColumnModel( const ColumnModel& rModel ) 761 { 762 // convert 1-based OOXML column indexes to 0-based API column indexes 763 sal_Int32 nFirstCol = rModel.maRange.mnFirst - 1; 764 sal_Int32 nLastCol = rModel.maRange.mnLast - 1; 765 if( !(getAddressConverter().checkCol( nFirstCol, true ) && (nFirstCol <= nLastCol)) ) 766 return; 767 768 // Validate last column index. 769 // If last column is equal to last possible column, Excel adds one 770 // more. We do that also in XclExpColinfo::SaveXml() and for 1024 end 771 // up with 1025 instead, which would lead to excess columns in 772 // checkCol(). Cater for this oddity. 773 if (nLastCol == mrMaxApiPos.Col() + 1) 774 --nLastCol; 775 // This is totally fouled up. If we saved 1025 and the file is saved 776 // with Excel again, it increments the value to 1026. 777 else if (nLastCol == mrMaxApiPos.Col() + 2) 778 nLastCol -= 2; 779 // Excel may add a column range for the remaining columns (with 780 // <cols><col .../></cols>), even if not used or only used to grey out 781 // columns in page break view. Don't let that trigger overflow warning, 782 // so check for the last possible column. If there really is content in 783 // the range that should be caught anyway. 784 else if (nLastCol == getAddressConverter().getMaxXlsAddress().Col()) 785 nLastCol = mrMaxApiPos.Col(); 786 // User may have applied custom column widths to arbitrary excess 787 // columns. Ignore those and don't track as overflow columns (false). 788 // Effectively this does the same as the above cases, just keep them 789 // for explanation. 790 // Actual data present should trigger the overflow detection later. 791 else if( !getAddressConverter().checkCol( nLastCol, false ) ) 792 nLastCol = mrMaxApiPos.Col(); 793 // try to find entry in column model map that is able to merge with the passed model 794 bool bInsertModel = true; 795 if( !maColModels.empty() ) 796 { 797 // find first column model range following nFirstCol (nFirstCol < aIt->first), or end of map 798 ColumnModelRangeMap::iterator aIt = maColModels.upper_bound( nFirstCol ); 799 OSL_ENSURE( aIt == maColModels.end(), "WorksheetGlobals::setColModel - columns are unsorted" ); 800 // if inserting before another column model, get last free column 801 OSL_ENSURE( (aIt == maColModels.end()) || (nLastCol < aIt->first), "WorksheetGlobals::setColModel - multiple models of the same column" ); 802 if( aIt != maColModels.end() ) 803 nLastCol = ::std::min( nLastCol, aIt->first - 1 ); 804 if( aIt != maColModels.begin() ) 805 { 806 // go to previous map element (which may be able to merge with the passed model) 807 --aIt; 808 // the usage of upper_bound() above ensures that aIt->first is less than or equal to nFirstCol now 809 sal_Int32& rnLastMapCol = aIt->second.second; 810 OSL_ENSURE( rnLastMapCol < nFirstCol, "WorksheetGlobals::setColModel - multiple models of the same column" ); 811 nFirstCol = ::std::max( rnLastMapCol + 1, nFirstCol ); 812 if( (rnLastMapCol + 1 == nFirstCol) && (nFirstCol <= nLastCol) && aIt->second.first.isMergeable( rModel ) ) 813 { 814 // can merge with existing model, update last column index 815 rnLastMapCol = nLastCol; 816 bInsertModel = false; 817 } 818 } 819 } 820 if( nFirstCol <= nLastCol ) 821 { 822 // insert the column model, if it has not been merged with another 823 if( bInsertModel ) 824 maColModels[ nFirstCol ] = ColumnModelRange( rModel, nLastCol ); 825 // set column formatting directly 826 convertColumnFormat( nFirstCol, nLastCol, rModel.mnXfId ); 827 } 828 } 829 830 void WorksheetGlobals::convertColumnFormat( sal_Int32 nFirstCol, sal_Int32 nLastCol, sal_Int32 nXfId ) 831 { 832 ScRange aRange( nFirstCol, 0, getSheetIndex(), nLastCol, mrMaxApiPos.Row(), getSheetIndex() ); 833 if( getAddressConverter().validateCellRange( aRange, true, false ) ) 834 { 835 const StylesBuffer& rStyles = getStyles(); 836 837 // Set cell styles via direct API - the preferred approach. 838 ScDocumentImport& rDoc = getDocImport(); 839 rStyles.writeCellXfToDoc(rDoc, aRange, nXfId); 840 } 841 } 842 843 void WorksheetGlobals::setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom ) 844 { 845 maDefRowModel.mfHeight = fHeight; 846 maDefRowModel.mbCustomHeight = bCustomHeight; 847 maDefRowModel.mbHidden = bHidden; 848 maDefRowModel.mbThickTop = bThickTop; 849 maDefRowModel.mbThickBottom = bThickBottom; 850 } 851 852 void WorksheetGlobals::setRowModel( const RowModel& rModel ) 853 { 854 // convert 1-based OOXML row index to 0-based API row index 855 sal_Int32 nRow = rModel.mnRow - 1; 856 if( getAddressConverter().checkRow( nRow, true ) ) 857 { 858 // try to find entry in row model map that is able to merge with the passed model 859 bool bInsertModel = true; 860 bool bUnusedRow = true; 861 if( !maRowModels.empty() ) 862 { 863 // find first row model range following nRow (nRow < aIt->first), or end of map 864 RowModelRangeMap::iterator aIt = maRowModels.upper_bound( nRow ); 865 OSL_ENSURE( aIt == maRowModels.end(), "WorksheetGlobals::setRowModel - rows are unsorted" ); 866 if( aIt != maRowModels.begin() ) 867 { 868 // go to previous map element (which may be able to merge with the passed model) 869 --aIt; 870 // the usage of upper_bound() above ensures that aIt->first is less than or equal to nRow now 871 sal_Int32& rnLastMapRow = aIt->second.second; 872 bUnusedRow = rnLastMapRow < nRow; 873 OSL_ENSURE( bUnusedRow, "WorksheetGlobals::setRowModel - multiple models of the same row" ); 874 if( (rnLastMapRow + 1 == nRow) && aIt->second.first.isMergeable( rModel ) ) 875 { 876 // can merge with existing model, update last row index 877 ++rnLastMapRow; 878 bInsertModel = false; 879 } 880 } 881 } 882 if( bUnusedRow ) 883 { 884 // insert the row model, if it has not been merged with another 885 if( bInsertModel ) 886 maRowModels[ nRow ] = RowModelRange( rModel, nRow ); 887 // set row formatting 888 maSheetData.setRowFormat( nRow, rModel.mnXfId, rModel.mbCustomFormat ); 889 // set column spans 890 maSheetData.setColSpans( nRow, rModel.maColSpans ); 891 } 892 } 893 894 UpdateRowProgress( maUsedArea, nRow ); 895 } 896 897 // This is called at a higher frequency inside the (threaded) inner loop. 898 void WorksheetGlobals::UpdateRowProgress( const ScRange& rUsedArea, SCROW nRow ) 899 { 900 if (!mxRowProgress || nRow < rUsedArea.aStart.Row() || rUsedArea.aEnd.Row() < nRow) 901 return; 902 903 double fNewPos = static_cast<double>(nRow - rUsedArea.aStart.Row() + 1.0) / (rUsedArea.aEnd.Row() - rUsedArea.aStart.Row() + 1.0); 904 905 if (mbFastRowProgress) 906 mxRowProgress->setPosition(fNewPos); 907 else 908 { 909 double fCurPos = mxRowProgress->getPosition(); 910 if (fCurPos < fNewPos && (fNewPos - fCurPos) > 0.3) 911 // Try not to re-draw progress bar too frequently. 912 mxRowProgress->setPosition(fNewPos); 913 } 914 } 915 916 void WorksheetGlobals::initializeWorksheetImport() 917 { 918 // set default cell style for unused cells 919 ScDocumentImport& rDoc = getDocImport(); 920 921 ScStyleSheet* pStyleSheet = 922 static_cast<ScStyleSheet*>(rDoc.getDoc().GetStyleSheetPool()->Find( 923 getStyles().getDefaultStyleName(), SfxStyleFamily::Para)); 924 925 if (pStyleSheet) 926 rDoc.setCellStyleToSheet(getSheetIndex(), *pStyleSheet); 927 928 /* Remember the current sheet index in global data, needed by global 929 objects, e.g. the chart converter. */ 930 setCurrentSheetIndex( getSheetIndex() ); 931 } 932 933 void WorksheetGlobals::finalizeWorksheetImport() 934 { 935 lclUpdateProgressBar( mxRowProgress, 1.0 ); 936 maSheetData.finalizeImport(); 937 // assumes getTables().finalizeImport ( which creates the DatabaseRanges ) 938 // has been called already 939 getTables().applyAutoFilters(); 940 941 getCondFormats().finalizeImport(); 942 lclUpdateProgressBar( mxFinalProgress, 0.25 ); 943 finalizeHyperlinkRanges(); 944 finalizeValidationRanges(); 945 maAutoFilters.finalizeImport( getSheetIndex() ); 946 maQueryTables.finalizeImport(); 947 maSheetSett.finalizeImport(); 948 maPageSett.finalizeImport(); 949 maSheetViewSett.finalizeImport(); 950 951 lclUpdateProgressBar( mxFinalProgress, 0.5 ); 952 convertColumns(); 953 954 // tdf#99913 rows hidden by filter need extra flag 955 ScDocument& rDoc = getScDocument(); 956 std::vector<sc::ColRowSpan> aSpans; 957 SCTAB nTab = getSheetIndex(); 958 ScDBData* pDBData = rDoc.GetAnonymousDBData(nTab); 959 if (pDBData && pDBData->HasAutoFilter()) 960 { 961 ScRange aRange; 962 pDBData->GetArea(aRange); 963 SCCOLROW nStartRow = static_cast<SCCOLROW>(aRange.aStart.Row()); 964 SCCOLROW nEndRow = static_cast<SCCOLROW>(aRange.aEnd.Row()); 965 aSpans.push_back(sc::ColRowSpan(nStartRow, nEndRow)); 966 } 967 ScDBCollection* pDocColl = rDoc.GetDBCollection(); 968 if (!pDocColl->empty()) 969 { 970 ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs(); 971 for (const auto& rxDB : rDBs) 972 { 973 if (rxDB->GetTab() == nTab && rxDB->HasAutoFilter()) 974 { 975 ScRange aRange; 976 rxDB->GetArea(aRange); 977 SCCOLROW nStartRow = static_cast<SCCOLROW>(aRange.aStart.Row()); 978 SCCOLROW nEndRow = static_cast<SCCOLROW>(aRange.aEnd.Row()); 979 aSpans.push_back(sc::ColRowSpan(nStartRow, nEndRow)); 980 } 981 } 982 } 983 convertRows(aSpans); 984 lclUpdateProgressBar( mxFinalProgress, 1.0 ); 985 } 986 987 void WorksheetGlobals::finalizeDrawingImport() 988 { 989 finalizeDrawings(); 990 991 // forget current sheet index in global data 992 setCurrentSheetIndex( -1 ); 993 } 994 995 // private -------------------------------------------------------------------- 996 997 void WorksheetGlobals::finalizeHyperlinkRanges() 998 { 999 for (auto const& link : maHyperlinks) 1000 { 1001 OUString aUrl = getHyperlinkUrl(link); 1002 // try to insert URL into each cell of the range 1003 if( !aUrl.isEmpty() ) 1004 for( ScAddress aAddress(link.maRange.aStart.Col(), link.maRange.aStart.Row(), getSheetIndex() ); aAddress.Row() <= link.maRange.aEnd.Row(); aAddress.IncRow() ) 1005 for( aAddress.SetCol(link.maRange.aStart.Col()); aAddress.Col() <= link.maRange.aEnd.Col(); aAddress.IncCol() ) 1006 insertHyperlink( aAddress, aUrl ); 1007 } 1008 } 1009 1010 OUString WorksheetGlobals::getHyperlinkUrl( const HyperlinkModel& rHyperlink ) const 1011 { 1012 OUStringBuffer aUrlBuffer; 1013 if( !rHyperlink.maTarget.isEmpty() ) 1014 aUrlBuffer.append( getBaseFilter().getAbsoluteUrl( rHyperlink.maTarget ) ); 1015 if( !rHyperlink.maLocation.isEmpty() ) 1016 aUrlBuffer.append( '#' ).append( rHyperlink.maLocation ); 1017 OUString aUrl = aUrlBuffer.makeStringAndClear(); 1018 1019 if( aUrl.startsWith("#") ) 1020 { 1021 sal_Int32 nSepPos = aUrl.lastIndexOf( '!' ); 1022 if( nSepPos > 0 ) 1023 { 1024 // Do not attempt to blindly convert '#SheetName!A1' to 1025 // '#SheetName.A1', it can be #SheetName!R1C1 as well. Hyperlink 1026 // handler has to handle all, but prefer '#SheetName.A1' if 1027 // possible. 1028 if (nSepPos < aUrl.getLength() - 1) 1029 { 1030 ScRange aRange; 1031 const ScDocumentImport& rDoc = getDocImport(); 1032 if ((aRange.ParseAny( aUrl.copy( nSepPos + 1 ), rDoc.getDoc(), 1033 formula::FormulaGrammar::CONV_XL_R1C1) 1034 & ScRefFlags::VALID) == ScRefFlags::ZERO) 1035 aUrl = aUrl.replaceAt( nSepPos, 1, rtl::OUStringChar( '.' ) ); 1036 } 1037 // #i66592# convert sheet names that have been renamed on import 1038 OUString aSheetName = aUrl.copy( 1, nSepPos - 1 ); 1039 OUString aCalcName = getWorksheets().getCalcSheetName( aSheetName ); 1040 if( !aCalcName.isEmpty() ) 1041 aUrl = aUrl.replaceAt( 1, nSepPos - 1, aCalcName ); 1042 } 1043 } 1044 1045 return aUrl; 1046 } 1047 1048 void WorksheetGlobals::insertHyperlink( const ScAddress& rAddress, const OUString& rUrl ) 1049 { 1050 ScDocumentImport& rDoc = getDocImport(); 1051 ScRefCellValue aCell(rDoc.getDoc(), rAddress); 1052 1053 if (aCell.meType == CELLTYPE_STRING || aCell.meType == CELLTYPE_EDIT) 1054 { 1055 OUString aStr = aCell.getString(&rDoc.getDoc()); 1056 ScFieldEditEngine& rEE = rDoc.getDoc().GetEditEngine(); 1057 rEE.Clear(); 1058 1059 SvxURLField aURLField(rUrl, aStr, SvxURLFormat::Repr); 1060 SvxFieldItem aURLItem(aURLField, EE_FEATURE_FIELD); 1061 rEE.QuickInsertField(aURLItem, ESelection()); 1062 1063 rDoc.setEditCell(rAddress, rEE.CreateTextObject()); 1064 } 1065 else 1066 { 1067 // Handle other cell types e.g. formulas ( and ? ) that have associated 1068 // hyperlinks. 1069 // Ideally all hyperlinks should be treated as below. For the moment, 1070 // given the current absence of ods support lets just handle what we 1071 // previously didn't handle the new way. 1072 // Unfortunately we won't be able to preserve such hyperlinks when 1073 // saving to ods. Note: when we are able to save such hyperlinks to ods 1074 // we should handle *all* imported hyperlinks as below ( e.g. as cell 1075 // attribute ) for better interoperability. 1076 1077 SfxStringItem aItem(ATTR_HYPERLINK, rUrl); 1078 rDoc.getDoc().ApplyAttr(rAddress.Col(), rAddress.Row(), rAddress.Tab(), aItem); 1079 } 1080 } 1081 1082 void WorksheetGlobals::finalizeValidationRanges() const 1083 { 1084 for (auto const& validation : maValidations) 1085 { 1086 PropertySet aPropSet( getCellRangeList(validation.maRanges) ); 1087 1088 Reference< XPropertySet > xValidation( aPropSet.getAnyProperty( PROP_Validation ), UNO_QUERY ); 1089 if( xValidation.is() ) 1090 { 1091 PropertySet aValProps( xValidation ); 1092 1093 try 1094 { 1095 const OUString aToken = validation.msRef.getToken( 0, ' ' ); 1096 1097 Reference<XSpreadsheet> xSheet = getSheetFromDoc( getCurrentSheetIndex() ); 1098 Reference<XCellRange> xDBCellRange; 1099 Reference<XCell> xCell; 1100 xDBCellRange = xSheet->getCellRangeByName( aToken ); 1101 1102 xCell = xDBCellRange->getCellByPosition( 0, 0 ); 1103 Reference<XCellAddressable> xCellAddressable( xCell, UNO_QUERY_THROW ); 1104 CellAddress aFirstCell = xCellAddressable->getCellAddress(); 1105 Reference<XSheetCondition> xCondition( xValidation, UNO_QUERY_THROW ); 1106 xCondition->setSourcePosition( aFirstCell ); 1107 } 1108 catch(const Exception&) 1109 { 1110 } 1111 1112 // convert validation type to API enum 1113 ValidationType eType = ValidationType_ANY; 1114 switch( validation.mnType ) 1115 { 1116 case XML_custom: eType = ValidationType_CUSTOM; break; 1117 case XML_date: eType = ValidationType_DATE; break; 1118 case XML_decimal: eType = ValidationType_DECIMAL; break; 1119 case XML_list: eType = ValidationType_LIST; break; 1120 case XML_none: eType = ValidationType_ANY; break; 1121 case XML_textLength: eType = ValidationType_TEXT_LEN; break; 1122 case XML_time: eType = ValidationType_TIME; break; 1123 case XML_whole: eType = ValidationType_WHOLE; break; 1124 default: OSL_FAIL( "WorksheetData::finalizeValidationRanges - unknown validation type" ); 1125 } 1126 aValProps.setProperty( PROP_Type, eType ); 1127 1128 // convert error alert style to API enum 1129 ValidationAlertStyle eAlertStyle = ValidationAlertStyle_STOP; 1130 switch( validation.mnErrorStyle ) 1131 { 1132 case XML_information: eAlertStyle = ValidationAlertStyle_INFO; break; 1133 case XML_stop: eAlertStyle = ValidationAlertStyle_STOP; break; 1134 case XML_warning: eAlertStyle = ValidationAlertStyle_WARNING; break; 1135 default: OSL_FAIL( "WorksheetData::finalizeValidationRanges - unknown error style" ); 1136 } 1137 aValProps.setProperty( PROP_ErrorAlertStyle, eAlertStyle ); 1138 1139 // convert dropdown style to API visibility constants 1140 sal_Int16 nVisibility = validation.mbNoDropDown ? TableValidationVisibility::INVISIBLE : TableValidationVisibility::UNSORTED; 1141 aValProps.setProperty( PROP_ShowList, nVisibility ); 1142 1143 // messages 1144 aValProps.setProperty( PROP_ShowInputMessage, validation.mbShowInputMsg ); 1145 aValProps.setProperty( PROP_InputTitle, validation.maInputTitle ); 1146 aValProps.setProperty( PROP_InputMessage, validation.maInputMessage ); 1147 aValProps.setProperty( PROP_ShowErrorMessage, validation.mbShowErrorMsg ); 1148 aValProps.setProperty( PROP_ErrorTitle, validation.maErrorTitle ); 1149 aValProps.setProperty( PROP_ErrorMessage, validation.maErrorMessage ); 1150 1151 // allow blank cells 1152 aValProps.setProperty( PROP_IgnoreBlankCells, validation.mbAllowBlank ); 1153 1154 try 1155 { 1156 // condition operator 1157 Reference< XSheetCondition2 > xSheetCond( xValidation, UNO_QUERY_THROW ); 1158 if( eType == ValidationType_CUSTOM ) 1159 xSheetCond->setConditionOperator( ConditionOperator2::FORMULA ); 1160 else 1161 xSheetCond->setConditionOperator( CondFormatBuffer::convertToApiOperator( validation.mnOperator ) ); 1162 1163 // condition formulas 1164 Reference< XMultiFormulaTokens > xTokens( xValidation, UNO_QUERY_THROW ); 1165 xTokens->setTokens( 0, validation.maTokens1 ); 1166 xTokens->setTokens( 1, validation.maTokens2 ); 1167 } 1168 catch( Exception& ) 1169 { 1170 } 1171 1172 // write back validation settings to cell range(s) 1173 aPropSet.setProperty( PROP_Validation, xValidation ); 1174 } 1175 } 1176 } 1177 1178 void WorksheetGlobals::convertColumns() 1179 { 1180 sal_Int32 nNextCol = 0; 1181 sal_Int32 nMaxCol = mrMaxApiPos.Col(); 1182 // stores first grouped column index for each level 1183 OutlineLevelVec aColLevels; 1184 1185 for (auto const& colModel : maColModels) 1186 { 1187 // column indexes are stored 0-based in maColModels 1188 ValueRange aColRange( ::std::max( colModel.first, nNextCol ), ::std::min( colModel.second.second, nMaxCol ) ); 1189 // process gap between two column models, use default column model 1190 if( nNextCol < aColRange.mnFirst ) 1191 convertColumns( aColLevels, ValueRange( nNextCol, aColRange.mnFirst - 1 ), maDefColModel ); 1192 // process the column model 1193 convertColumns( aColLevels, aColRange, colModel.second.first ); 1194 // cache next column to be processed 1195 nNextCol = aColRange.mnLast + 1; 1196 } 1197 1198 // remaining default columns to end of sheet 1199 convertColumns( aColLevels, ValueRange( nNextCol, nMaxCol ), maDefColModel ); 1200 // close remaining column outlines spanning to end of sheet 1201 convertOutlines( aColLevels, nMaxCol + 1, 0, false, false ); 1202 } 1203 1204 void WorksheetGlobals::convertColumns( OutlineLevelVec& orColLevels, 1205 const ValueRange& rColRange, const ColumnModel& rModel ) 1206 { 1207 // column width: convert 'number of characters' to column width in twips 1208 sal_Int32 nWidth = std::round(getUnitConverter().scaleValue( rModel.mfWidth, Unit::Digit, Unit::Twip )); 1209 1210 SCTAB nTab = getSheetIndex(); 1211 ScDocument& rDoc = getScDocument(); 1212 SCCOL nStartCol = rColRange.mnFirst; 1213 SCCOL nEndCol = rColRange.mnLast; 1214 1215 if( nWidth > 0 ) 1216 { 1217 // macro sheets have double width 1218 if( meSheetType == WorksheetType::Macro ) 1219 nWidth *= 2; 1220 1221 for( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol ) 1222 { 1223 rDoc.SetColWidthOnly(nCol, nTab, nWidth); 1224 } 1225 } 1226 1227 // hidden columns: TODO: #108683# hide columns later? 1228 if( rModel.mbHidden ) 1229 { 1230 rDoc.SetColHidden( nStartCol, nEndCol, nTab, true ); 1231 } 1232 1233 // outline settings for this column range 1234 convertOutlines( orColLevels, rColRange.mnFirst, rModel.mnLevel, rModel.mbCollapsed, false ); 1235 } 1236 1237 void WorksheetGlobals::convertRows(const std::vector<sc::ColRowSpan>& rSpans) 1238 { 1239 sal_Int32 nNextRow = 0; 1240 sal_Int32 nMaxRow = mrMaxApiPos.Row(); 1241 // stores first grouped row index for each level 1242 OutlineLevelVec aRowLevels; 1243 1244 for (auto const& rowModel : maRowModels) 1245 { 1246 // row indexes are stored 0-based in maRowModels 1247 ValueRange aRowRange( ::std::max( rowModel.first, nNextRow ), ::std::min( rowModel.second.second, nMaxRow ) ); 1248 // process gap between two row models, use default row model 1249 if( nNextRow < aRowRange.mnFirst ) 1250 convertRows(aRowLevels, ValueRange(nNextRow, aRowRange.mnFirst - 1), maDefRowModel, 1251 rSpans); 1252 // process the row model 1253 convertRows(aRowLevels, aRowRange, rowModel.second.first, rSpans, maDefRowModel.mfHeight); 1254 // cache next row to be processed 1255 nNextRow = aRowRange.mnLast + 1; 1256 } 1257 1258 // remaining default rows to end of sheet 1259 convertRows(aRowLevels, ValueRange(nNextRow, nMaxRow), maDefRowModel, rSpans); 1260 // close remaining row outlines spanning to end of sheet 1261 convertOutlines( aRowLevels, nMaxRow + 1, 0, false, true ); 1262 } 1263 1264 void WorksheetGlobals::convertRows(OutlineLevelVec& orRowLevels, const ValueRange& rRowRange, 1265 const RowModel& rModel, 1266 const std::vector<sc::ColRowSpan>& rSpans, double fDefHeight) 1267 { 1268 // row height: convert points to row height in twips 1269 double fHeight = (rModel.mfHeight >= 0.0) ? rModel.mfHeight : fDefHeight; 1270 sal_Int32 nHeight = std::round(o3tl::toTwips( fHeight, o3tl::Length::pt )); 1271 SCROW nStartRow = rRowRange.mnFirst; 1272 SCROW nEndRow = rRowRange.mnLast; 1273 SCTAB nTab = getSheetIndex(); 1274 if( nHeight > 0 ) 1275 { 1276 /* always import the row height, ensures better layout */ 1277 ScDocument& rDoc = getScDocument(); 1278 rDoc.SetRowHeightOnly(nStartRow, nEndRow, nTab, nHeight); 1279 if(rModel.mbCustomHeight) 1280 rDoc.SetManualHeight( nStartRow, nEndRow, nTab, true ); 1281 } 1282 1283 // hidden rows: TODO: #108683# hide rows later? 1284 if( rModel.mbHidden ) 1285 { 1286 ScDocument& rDoc = getScDocument(); 1287 rDoc.SetRowHidden( nStartRow, nEndRow, nTab, true ); 1288 for (const auto& rSpan : rSpans) 1289 { 1290 // tdf#99913 rows hidden by filter need extra flag 1291 if (rSpan.mnStart <= nStartRow && nStartRow <= rSpan.mnEnd) 1292 { 1293 SCROW nLast = ::std::min(nEndRow, rSpan.mnEnd); 1294 rDoc.SetRowFiltered(nStartRow, nLast, nTab, true); 1295 break; 1296 } 1297 } 1298 } 1299 1300 // outline settings for this row range 1301 convertOutlines( orRowLevels, rRowRange.mnFirst, rModel.mnLevel, rModel.mbCollapsed, true ); 1302 } 1303 1304 void WorksheetGlobals::convertOutlines( OutlineLevelVec& orLevels, 1305 sal_Int32 nColRow, sal_Int32 nLevel, bool bCollapsed, bool bRows ) 1306 { 1307 /* It is ensured from caller functions, that this function is called 1308 without any gaps between the processed column or row ranges. */ 1309 1310 OSL_ENSURE( nLevel >= 0, "WorksheetGlobals::convertOutlines - negative outline level" ); 1311 nLevel = ::std::max< sal_Int32 >( nLevel, 0 ); 1312 1313 sal_Int32 nSize = orLevels.size(); 1314 if( nSize < nLevel ) 1315 { 1316 // Outline level increased. Push the begin column position. 1317 orLevels.insert(orLevels.end(), nLevel - nSize, nColRow); 1318 } 1319 else if( nLevel < nSize ) 1320 { 1321 // Outline level decreased. Pop them all out. 1322 for( sal_Int32 nIndex = nLevel; nIndex < nSize; ++nIndex ) 1323 { 1324 sal_Int32 nFirstInLevel = orLevels.back(); 1325 orLevels.pop_back(); 1326 groupColumnsOrRows( nFirstInLevel, nColRow - 1, bCollapsed, bRows ); 1327 bCollapsed = false; // collapse only once 1328 } 1329 } 1330 } 1331 1332 void WorksheetGlobals::groupColumnsOrRows( sal_Int32 nFirstColRow, sal_Int32 nLastColRow, bool bCollapse, bool bRows ) 1333 { 1334 try 1335 { 1336 Reference< XSheetOutline > xOutline( mxSheet, UNO_QUERY_THROW ); 1337 if( bRows ) 1338 { 1339 CellRangeAddress aRange( getSheetIndex(), 0, nFirstColRow, 0, nLastColRow ); 1340 xOutline->group( aRange, TableOrientation_ROWS ); 1341 if( bCollapse ) 1342 xOutline->hideDetail( aRange ); 1343 } 1344 else 1345 { 1346 CellRangeAddress aRange( getSheetIndex(), nFirstColRow, 0, nLastColRow, 0 ); 1347 xOutline->group( aRange, TableOrientation_COLUMNS ); 1348 if( bCollapse ) 1349 xOutline->hideDetail( aRange ); 1350 } 1351 } 1352 catch( Exception& ) 1353 { 1354 } 1355 } 1356 1357 void WorksheetGlobals::finalizeDrawings() 1358 { 1359 // calculate the current drawing page size (after rows/columns are imported) 1360 PropertySet aRangeProp( getCellRange( ScRange( 0, 0, getSheetIndex(), mrMaxApiPos.Col(), mrMaxApiPos.Row(), getSheetIndex() ) ) ); 1361 aRangeProp.getProperty( maDrawPageSize, PROP_Size ); 1362 1363 // import DML and VML 1364 if( !maDrawingPath.isEmpty() ) 1365 importOoxFragment( new DrawingFragment( *this, maDrawingPath ) ); 1366 if( !maVmlDrawingPath.isEmpty() ) 1367 importOoxFragment( new VmlDrawingFragment( *this, maVmlDrawingPath ) ); 1368 1369 // comments (after callout shapes have been imported from VML/DFF) 1370 maComments.finalizeImport(); 1371 1372 /* Extend used area of the sheet by cells covered with drawing objects. 1373 Needed if the imported document is inserted as "OLE object from file" 1374 and thus does not provide an OLE size property by itself. */ 1375 if( (maShapeBoundingBox.Width > 0) || (maShapeBoundingBox.Height > 0) ) 1376 extendUsedArea( getCellRangeFromRectangle( maShapeBoundingBox ) ); 1377 1378 // if no used area is set, default to A1 1379 if( maUsedArea.aStart.Col() > maUsedArea.aEnd.Col() ) 1380 { 1381 maUsedArea.aStart.SetCol( 0 ); 1382 maUsedArea.aEnd.SetCol( 0 ); 1383 } 1384 1385 if( maUsedArea.aStart.Row() > maUsedArea.aEnd.Row() ) 1386 { 1387 maUsedArea.aStart.SetRow( 0 ); 1388 maUsedArea.aEnd.SetRow( 0 ); 1389 } 1390 1391 /* Register the used area of this sheet in global view settings. The 1392 global view settings will set the visible area if this document is an 1393 embedded OLE object. */ 1394 getViewSettings().setSheetUsedArea( maUsedArea ); 1395 1396 /* #i103686# Set right-to-left sheet layout. Must be done after all 1397 drawing shapes to simplify calculation of shape coordinates. */ 1398 if( maSheetViewSett.isSheetRightToLeft() ) 1399 { 1400 PropertySet aPropSet( mxSheet ); 1401 aPropSet.setProperty( PROP_TableLayout, WritingMode2::RL_TB ); 1402 } 1403 } 1404 1405 WorksheetHelper::WorksheetHelper( WorksheetGlobals& rSheetGlob ) : 1406 WorkbookHelper( rSheetGlob ), 1407 mrSheetGlob( rSheetGlob ) 1408 { 1409 } 1410 1411 ScDocument& WorksheetHelper::getScDocument() 1412 { 1413 return getDocImport().getDoc(); 1414 } 1415 1416 /*static*/ WorksheetGlobalsRef WorksheetHelper::constructGlobals( const WorkbookHelper& rHelper, 1417 const ISegmentProgressBarRef& rxProgressBar, WorksheetType eSheetType, SCTAB nSheet ) 1418 { 1419 WorksheetGlobalsRef xSheetGlob = std::make_shared<WorksheetGlobals>( rHelper, rxProgressBar, eSheetType, nSheet ); 1420 if( !xSheetGlob->isValidSheet() ) 1421 xSheetGlob.reset(); 1422 return xSheetGlob; 1423 } 1424 1425 /* static */ IWorksheetProgress *WorksheetHelper::getWorksheetInterface( const WorksheetGlobalsRef &xRef ) 1426 { 1427 return static_cast< IWorksheetProgress *>( xRef.get() ); 1428 } 1429 1430 WorksheetType WorksheetHelper::getSheetType() const 1431 { 1432 return mrSheetGlob.getSheetType(); 1433 } 1434 1435 SCTAB WorksheetHelper::getSheetIndex() const 1436 { 1437 return mrSheetGlob.getSheetIndex(); 1438 } 1439 1440 const Reference< XSpreadsheet >& WorksheetHelper::getSheet() const 1441 { 1442 return mrSheetGlob.getSheet(); 1443 } 1444 1445 Reference< XCell > WorksheetHelper::getCell( const ScAddress& rAddress ) const 1446 { 1447 return mrSheetGlob.getCell( rAddress ); 1448 } 1449 1450 Reference< XCellRange > WorksheetHelper::getCellRange( const ScRange& rRange ) const 1451 { 1452 return mrSheetGlob.getCellRange( rRange ); 1453 } 1454 1455 Reference< XDrawPage > WorksheetHelper::getDrawPage() const 1456 { 1457 return mrSheetGlob.getDrawPage(); 1458 } 1459 1460 awt::Point WorksheetHelper::getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const 1461 { 1462 return mrSheetGlob.getCellPosition( nCol, nRow ); 1463 } 1464 1465 const awt::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 ExtLst& WorksheetHelper::getExtLst() const 1516 { 1517 return mrSheetGlob.getExtLst(); 1518 } 1519 1520 void WorksheetHelper::setPageBreak( const PageBreakModel& rModel, bool bRowBreak ) 1521 { 1522 mrSheetGlob.setPageBreak( rModel, bRowBreak ); 1523 } 1524 1525 void WorksheetHelper::setHyperlink( const HyperlinkModel& rModel ) 1526 { 1527 mrSheetGlob.setHyperlink( rModel ); 1528 } 1529 1530 void WorksheetHelper::setValidation( const ValidationModel& rModel ) 1531 { 1532 mrSheetGlob.setValidation( rModel ); 1533 } 1534 1535 void WorksheetHelper::setDrawingPath( const OUString& rDrawingPath ) 1536 { 1537 mrSheetGlob.setDrawingPath( rDrawingPath ); 1538 } 1539 1540 void WorksheetHelper::setVmlDrawingPath( const OUString& rVmlDrawingPath ) 1541 { 1542 mrSheetGlob.setVmlDrawingPath( rVmlDrawingPath ); 1543 } 1544 1545 void WorksheetHelper::extendUsedArea( const ScAddress& rAddress ) 1546 { 1547 mrSheetGlob.extendUsedArea( rAddress ); 1548 } 1549 1550 void WorksheetHelper::extendShapeBoundingBox( const awt::Rectangle& rShapeRect ) 1551 { 1552 mrSheetGlob.extendShapeBoundingBox( rShapeRect ); 1553 } 1554 1555 void WorksheetHelper::setBaseColumnWidth( sal_Int32 nWidth ) 1556 { 1557 mrSheetGlob.setBaseColumnWidth( nWidth ); 1558 } 1559 1560 void WorksheetHelper::setDefaultColumnWidth( double fWidth ) 1561 { 1562 mrSheetGlob.setDefaultColumnWidth( fWidth ); 1563 } 1564 1565 void WorksheetHelper::setColumnModel( const ColumnModel& rModel ) 1566 { 1567 mrSheetGlob.setColumnModel( rModel ); 1568 } 1569 1570 void WorksheetHelper::setDefaultRowSettings( double fHeight, bool bCustomHeight, bool bHidden, bool bThickTop, bool bThickBottom ) 1571 { 1572 mrSheetGlob.setDefaultRowSettings( fHeight, bCustomHeight, bHidden, bThickTop, bThickBottom ); 1573 } 1574 1575 void WorksheetHelper::setRowModel( const RowModel& rModel ) 1576 { 1577 mrSheetGlob.setRowModel( rModel ); 1578 } 1579 1580 void WorksheetHelper::setCellFormulaValue( 1581 const ScAddress& rAddress, const OUString& rValueStr, sal_Int32 nCellType ) 1582 { 1583 getFormulaBuffer().setCellFormulaValue(rAddress, rValueStr, nCellType); 1584 } 1585 1586 void WorksheetHelper::putRichString( const ScAddress& rAddress, const RichString& rString, const oox::xls::Font* pFirstPortionFont ) 1587 { 1588 ScEditEngineDefaulter& rEE = getEditEngine(); 1589 1590 // The cell will own the text object instance returned from convert(). 1591 getDocImport().setEditCell(rAddress, rString.convert(rEE, pFirstPortionFont)); 1592 } 1593 1594 void WorksheetHelper::putFormulaTokens( const ScAddress& rAddress, const ApiTokenSequence& rTokens ) 1595 { 1596 ScDocumentImport& rDoc = getDocImport(); 1597 std::unique_ptr<ScTokenArray> pTokenArray(new ScTokenArray(rDoc.getDoc())); 1598 ScTokenConversion::ConvertToTokenArray(rDoc.getDoc(), *pTokenArray, rTokens); 1599 rDoc.setFormulaCell(rAddress, std::move(pTokenArray)); 1600 } 1601 1602 void WorksheetHelper::initializeWorksheetImport() 1603 { 1604 mrSheetGlob.initializeWorksheetImport(); 1605 } 1606 1607 void WorksheetHelper::finalizeWorksheetImport() 1608 { 1609 mrSheetGlob.finalizeWorksheetImport(); 1610 } 1611 1612 void WorksheetHelper::finalizeDrawingImport() 1613 { 1614 mrSheetGlob.finalizeDrawingImport(); 1615 } 1616 1617 void WorksheetHelper::setCellFormula( const ScAddress& rTokenAddress, const OUString& rTokenStr ) 1618 { 1619 getFormulaBuffer().setCellFormula( rTokenAddress, rTokenStr ); 1620 } 1621 1622 void WorksheetHelper::setCellFormula( 1623 const ScAddress& rAddr, sal_Int32 nSharedId, 1624 const OUString& rCellValue, sal_Int32 nValueType ) 1625 { 1626 getFormulaBuffer().setCellFormula(rAddr, nSharedId, rCellValue, nValueType); 1627 } 1628 1629 void WorksheetHelper::setCellArrayFormula( const ScRange& rRangeAddress, const ScAddress& rTokenAddress, const OUString& rTokenStr ) 1630 { 1631 getFormulaBuffer().setCellArrayFormula( rRangeAddress, rTokenAddress, rTokenStr ); 1632 } 1633 1634 void WorksheetHelper::createSharedFormulaMapEntry( 1635 const ScAddress& rAddress, sal_Int32 nSharedId, const OUString& rTokens ) 1636 { 1637 getFormulaBuffer().createSharedFormulaMapEntry(rAddress, nSharedId, rTokens); 1638 } 1639 1640 } // namespace oox 1641 1642 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1643
