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 "vbarange.hxx" 21 22 #include <comphelper/types.hxx> 23 #include <cppuhelper/exc_hlp.hxx> 24 #include <o3tl/any.hxx> 25 #include <o3tl/safeint.hxx> 26 #include <o3tl/unit_conversion.hxx> 27 #include <rtl/math.hxx> 28 #include <tools/diagnose_ex.h> 29 #include <o3tl/string_view.hxx> 30 31 #include <com/sun/star/script/ArrayWrapper.hpp> 32 #include <com/sun/star/script/XTypeConverter.hpp> 33 #include <com/sun/star/script/vba/VBAEventId.hpp> 34 #include <com/sun/star/script/vba/XVBAEventProcessor.hpp> 35 #include <com/sun/star/sheet/XDatabaseRange.hpp> 36 #include <com/sun/star/sheet/XUnnamedDatabaseRanges.hpp> 37 #include <com/sun/star/sheet/XGoalSeek.hpp> 38 #include <com/sun/star/sheet/XSheetOperation.hpp> 39 #include <com/sun/star/sheet/CellFlags.hpp> 40 #include <com/sun/star/table/XColumnRowRange.hpp> 41 #include <com/sun/star/sheet/XCellAddressable.hpp> 42 #include <com/sun/star/table/CellContentType.hpp> 43 #include <com/sun/star/sheet/XCellSeries.hpp> 44 #include <com/sun/star/text/XTextRange.hpp> 45 #include <com/sun/star/sheet/XCellRangeAddressable.hpp> 46 #include <com/sun/star/table/CellAddress.hpp> 47 #include <com/sun/star/table/CellRangeAddress.hpp> 48 #include <com/sun/star/sheet/XSpreadsheetView.hpp> 49 #include <com/sun/star/sheet/XCellRangeReferrer.hpp> 50 #include <com/sun/star/sheet/XSheetCellRange.hpp> 51 #include <com/sun/star/sheet/XSpreadsheet.hpp> 52 #include <com/sun/star/sheet/XSheetCellCursor.hpp> 53 #include <com/sun/star/sheet/XArrayFormulaRange.hpp> 54 #include <com/sun/star/sheet/XNamedRange.hpp> 55 #include <com/sun/star/sheet/XNamedRanges.hpp> 56 #include <com/sun/star/sheet/XPrintAreas.hpp> 57 #include <com/sun/star/sheet/XCellRangesQuery.hpp> 58 #include <com/sun/star/beans/XPropertySet.hpp> 59 #include <com/sun/star/frame/XModel.hpp> 60 #include <com/sun/star/view/XSelectionSupplier.hpp> 61 #include <com/sun/star/table/XTableRows.hpp> 62 #include <com/sun/star/table/XTableColumns.hpp> 63 #include <com/sun/star/table/TableSortField.hpp> 64 #include <com/sun/star/util/XMergeable.hpp> 65 #include <com/sun/star/uno/XComponentContext.hpp> 66 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> 67 #include <com/sun/star/util/XNumberFormatsSupplier.hpp> 68 #include <com/sun/star/util/XNumberFormats.hpp> 69 #include <com/sun/star/util/NumberFormat.hpp> 70 #include <com/sun/star/util/XNumberFormatTypes.hpp> 71 #include <com/sun/star/util/XReplaceable.hpp> 72 #include <com/sun/star/util/XSortable.hpp> 73 #include <com/sun/star/sheet/XCellRangeMovement.hpp> 74 #include <com/sun/star/sheet/FormulaResult.hpp> 75 #include <com/sun/star/sheet/FilterOperator2.hpp> 76 #include <com/sun/star/sheet/TableFilterField2.hpp> 77 #include <com/sun/star/sheet/XSheetFilterDescriptor2.hpp> 78 #include <com/sun/star/sheet/FilterConnection.hpp> 79 #include <com/sun/star/util/TriState.hpp> 80 81 #include <com/sun/star/sheet/XSubTotalCalculatable.hpp> 82 #include <com/sun/star/sheet/XSubTotalDescriptor.hpp> 83 #include <com/sun/star/sheet/GeneralFunction.hpp> 84 85 #include <com/sun/star/sheet/XSheetAnnotationsSupplier.hpp> 86 #include <com/sun/star/sheet/XSheetAnnotations.hpp> 87 88 #include <ooo/vba/excel/XlPasteSpecialOperation.hpp> 89 #include <ooo/vba/excel/XlPasteType.hpp> 90 #include <ooo/vba/excel/XlFindLookIn.hpp> 91 #include <ooo/vba/excel/XlLookAt.hpp> 92 #include <ooo/vba/excel/XlSearchOrder.hpp> 93 #include <ooo/vba/excel/XlSortOrder.hpp> 94 #include <ooo/vba/excel/XlYesNoGuess.hpp> 95 #include <ooo/vba/excel/XlSortOrientation.hpp> 96 #include <ooo/vba/excel/XlSortMethod.hpp> 97 #include <ooo/vba/excel/XlDirection.hpp> 98 #include <ooo/vba/excel/XlSortDataOption.hpp> 99 #include <ooo/vba/excel/XlDeleteShiftDirection.hpp> 100 #include <ooo/vba/excel/XlInsertShiftDirection.hpp> 101 #include <ooo/vba/excel/XlReferenceStyle.hpp> 102 #include <ooo/vba/excel/XlBordersIndex.hpp> 103 #include <ooo/vba/excel/XlPageBreak.hpp> 104 #include <ooo/vba/excel/XlAutoFilterOperator.hpp> 105 #include <ooo/vba/excel/XlAutoFillType.hpp> 106 #include <ooo/vba/excel/XlCellType.hpp> 107 #include <ooo/vba/excel/XlSpecialCellsValue.hpp> 108 #include <ooo/vba/excel/XlConsolidationFunction.hpp> 109 #include <ooo/vba/excel/XlSearchDirection.hpp> 110 111 #include <scitems.hxx> 112 #include <svl/srchitem.hxx> 113 #include <cellsuno.hxx> 114 #include <dbdata.hxx> 115 #include <docfunc.hxx> 116 #include <columnspanset.hxx> 117 #include <queryparam.hxx> 118 #include <sortparam.hxx> 119 120 #include <sfx2/dispatch.hxx> 121 #include <sfx2/app.hxx> 122 #include <sfx2/bindings.hxx> 123 #include <sfx2/viewfrm.hxx> 124 #include <sc.hrc> 125 #include <unonames.hxx> 126 127 #include "excelvbahelper.hxx" 128 #include "vbaapplication.hxx" 129 #include "vbafont.hxx" 130 #include "vbacomment.hxx" 131 #include "vbainterior.hxx" 132 #include "vbacharacters.hxx" 133 #include "vbaborders.hxx" 134 #include "vbaworksheet.hxx" 135 #include "vbavalidation.hxx" 136 #include "vbahyperlinks.hxx" 137 138 #include <tabvwsh.hxx> 139 #include <rangelst.hxx> 140 #include <convuno.hxx> 141 #include <compiler.hxx> 142 #include <patattr.hxx> 143 #include <olinetab.hxx> 144 #include <transobj.hxx> 145 #include <queryentry.hxx> 146 #include <markdata.hxx> 147 #include <basic/sberrors.hxx> 148 #include <cppuhelper/implbase.hxx> 149 150 #include <global.hxx> 151 152 #include "vbastyle.hxx" 153 #include "vbaname.hxx" 154 #include <vector> 155 #include <vbahelper/vbacollectionimpl.hxx> 156 157 #include <com/sun/star/bridge/oleautomation/Date.hpp> 158 #include <tokenarray.hxx> 159 #include <tokenuno.hxx> 160 161 #include <memory> 162 163 using namespace ::ooo::vba; 164 using namespace ::com::sun::star; 165 using ::std::vector; 166 167 // difference between VBA and file format width, in character units 168 const double fExtraWidth = 182.0 / 256.0; 169 170 const sal_Int16 supportedIndexTable[] = { excel::XlBordersIndex::xlEdgeLeft, excel::XlBordersIndex::xlEdgeTop, excel::XlBordersIndex::xlEdgeBottom, excel::XlBordersIndex::xlEdgeRight, excel::XlBordersIndex::xlDiagonalDown, excel::XlBordersIndex::xlDiagonalUp, excel::XlBordersIndex::xlInsideVertical, excel::XlBordersIndex::xlInsideHorizontal }; 171 172 static sal_uInt16 lcl_pointsToTwips( double nVal ) 173 { 174 nVal = nVal * static_cast<double>(20); 175 short nTwips = static_cast<short>(nVal); 176 return nTwips; 177 } 178 static double lcl_TwipsToPoints( sal_uInt16 nVal ) 179 { 180 double nPoints = nVal; 181 return nPoints / 20; 182 } 183 184 static double lcl_Round2DecPlaces( double nVal ) 185 { 186 nVal = (nVal * double(100)); 187 tools::Long tmp = static_cast<tools::Long>(nVal); 188 if ( ( nVal - tmp ) >= 0.5 ) 189 ++tmp; 190 nVal = double(tmp)/100; 191 return nVal; 192 } 193 194 static uno::Any lcl_makeRange( const uno::Reference< XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, const uno::Any& rAny, bool bIsRows, bool bIsColumns ) 195 { 196 uno::Reference< table::XCellRange > xCellRange(rAny, uno::UNO_QUERY_THROW); 197 return uno::Any( uno::Reference< excel::XRange >( new ScVbaRange( rParent, rContext, xCellRange, bIsRows, bIsColumns ) ) ); 198 } 199 200 static uno::Reference< excel::XRange > lcl_makeXRangeFromSheetCellRanges( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< sheet::XSheetCellRanges >& xLocSheetCellRanges, ScDocShell* pDoc ) 201 { 202 uno::Reference< excel::XRange > xRange; 203 const uno::Sequence< table::CellRangeAddress > sAddresses = xLocSheetCellRanges->getRangeAddresses(); 204 ScRangeList aCellRanges; 205 if ( sAddresses.hasElements() ) 206 { 207 for ( const auto& rAddress : sAddresses ) 208 { 209 ScRange refRange; 210 ScUnoConversion::FillScRange( refRange, rAddress ); 211 aCellRanges.push_back( refRange ); 212 } 213 // Single range 214 if ( aCellRanges.size() == 1 ) 215 { 216 uno::Reference< table::XCellRange > xTmpRange( new ScCellRangeObj( pDoc, aCellRanges.front() ) ); 217 xRange = new ScVbaRange( xParent, xContext, xTmpRange ); 218 } 219 else 220 { 221 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pDoc, aCellRanges ) ); 222 xRange = new ScVbaRange( xParent, xContext, xRanges ); 223 } 224 } 225 return xRange; 226 } 227 228 ScCellRangesBase* ScVbaRange::getCellRangesBase() 229 { 230 if( mxRanges.is() ) 231 return comphelper::getFromUnoTunnel<ScCellRangesBase>( mxRanges ); 232 if( mxRange.is() ) 233 return comphelper::getFromUnoTunnel<ScCellRangesBase>( mxRange ); 234 throw uno::RuntimeException("General Error creating range - Unknown" ); 235 } 236 237 ScCellRangeObj* ScVbaRange::getCellRangeObj() 238 { 239 return dynamic_cast< ScCellRangeObj* >( getCellRangesBase() ); 240 } 241 242 SfxItemSet* ScVbaRange::getCurrentDataSet( ) 243 { 244 SfxItemSet* pDataSet = excel::ScVbaCellRangeAccess::GetDataSet( getCellRangesBase() ); 245 if ( !pDataSet ) 246 throw uno::RuntimeException("Can't access Itemset for range" ); 247 return pDataSet; 248 } 249 250 void ScVbaRange::fireChangeEvent() 251 { 252 if( !ScVbaApplication::getDocumentEventsEnabled() ) 253 return; 254 255 ScDocument& rDoc = getScDocument(); 256 const uno::Reference< script::vba::XVBAEventProcessor >& xVBAEvents = rDoc.GetVbaEventProcessor(); 257 if( xVBAEvents.is() ) try 258 { 259 uno::Sequence< uno::Any > aArgs{ uno::Any(uno::Reference< excel::XRange >( this )) }; 260 xVBAEvents->processVbaEvent( script::vba::VBAEventId::WORKSHEET_CHANGE, aArgs ); 261 } 262 catch( uno::Exception& ) 263 { 264 } 265 } 266 267 namespace { 268 269 class SingleRangeEnumeration : public EnumerationHelper_BASE 270 { 271 uno::Reference< table::XCellRange > m_xRange; 272 bool bHasMore; 273 public: 274 /// @throws uno::RuntimeException 275 explicit SingleRangeEnumeration( const uno::Reference< table::XCellRange >& xRange ) : m_xRange( xRange ), bHasMore( true ) { } 276 virtual sal_Bool SAL_CALL hasMoreElements( ) override { return bHasMore; } 277 virtual uno::Any SAL_CALL nextElement( ) override 278 { 279 if ( !bHasMore ) 280 throw container::NoSuchElementException(); 281 bHasMore = false; 282 return uno::Any( m_xRange ); 283 } 284 }; 285 286 // very simple class to pass to ScVbaCollectionBaseImpl containing 287 // just one item 288 289 class SingleRangeIndexAccess : public ::cppu::WeakImplHelper< container::XIndexAccess, 290 container::XEnumerationAccess > 291 { 292 private: 293 uno::Reference< table::XCellRange > m_xRange; 294 295 public: 296 explicit SingleRangeIndexAccess( const uno::Reference< table::XCellRange >& xRange ) : m_xRange( xRange ) {} 297 // XIndexAccess 298 virtual ::sal_Int32 SAL_CALL getCount() override { return 1; } 299 virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override 300 { 301 if ( Index != 0 ) 302 throw lang::IndexOutOfBoundsException(); 303 return uno::Any( m_xRange ); 304 } 305 // XElementAccess 306 virtual uno::Type SAL_CALL getElementType() override { return cppu::UnoType<table::XCellRange>::get(); } 307 virtual sal_Bool SAL_CALL hasElements() override { return true; } 308 // XEnumerationAccess 309 virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration() override { return new SingleRangeEnumeration( m_xRange ); } 310 311 }; 312 313 class RangesEnumerationImpl : public EnumerationHelperImpl 314 { 315 bool mbIsRows; 316 bool mbIsColumns; 317 public: 318 /// @throws uno::RuntimeException 319 RangesEnumerationImpl( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration, bool bIsRows, bool bIsColumns ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ), mbIsRows( bIsRows ), mbIsColumns( bIsColumns ) {} 320 virtual uno::Any SAL_CALL nextElement( ) override 321 { 322 return lcl_makeRange( m_xParent, m_xContext, m_xEnumeration->nextElement(), mbIsRows, mbIsColumns ); 323 } 324 }; 325 326 class ScVbaRangeAreas : public ScVbaCollectionBaseImpl 327 { 328 bool mbIsRows; 329 bool mbIsColumns; 330 public: 331 ScVbaRangeAreas( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XIndexAccess >& xIndexAccess, bool bIsRows, bool bIsColumns ) : ScVbaCollectionBaseImpl( xParent, xContext, xIndexAccess ), mbIsRows( bIsRows ), mbIsColumns( bIsColumns ) {} 332 333 // XEnumerationAccess 334 virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration() override; 335 336 // XElementAccess 337 virtual uno::Type SAL_CALL getElementType() override { return cppu::UnoType<excel::XRange>::get(); } 338 339 virtual uno::Any createCollectionObject( const uno::Any& aSource ) override; 340 341 virtual OUString getServiceImplName() override { return OUString(); } 342 343 virtual uno::Sequence< OUString > getServiceNames() override { return uno::Sequence< OUString >(); } 344 345 }; 346 347 } 348 349 uno::Reference< container::XEnumeration > SAL_CALL 350 ScVbaRangeAreas::createEnumeration() 351 { 352 uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); 353 return new RangesEnumerationImpl( mxParent, mxContext, xEnumAccess->createEnumeration(), mbIsRows, mbIsColumns ); 354 } 355 356 uno::Any 357 ScVbaRangeAreas::createCollectionObject( const uno::Any& aSource ) 358 { 359 return lcl_makeRange( mxParent, mxContext, aSource, mbIsRows, mbIsColumns ); 360 } 361 362 // assume that xIf is in fact a ScCellRangesBase 363 /// @throws uno::RuntimeException 364 static ScDocShell* 365 getDocShellFromIf( const uno::Reference< uno::XInterface >& xIf ) 366 { 367 ScCellRangesBase* pUno = comphelper::getFromUnoTunnel<ScCellRangesBase>( xIf ); 368 if ( !pUno ) 369 throw uno::RuntimeException("Failed to access underlying uno range object" ); 370 return pUno->GetDocShell(); 371 } 372 373 /// @throws uno::RuntimeException 374 static ScDocShell* 375 getDocShellFromRange( const uno::Reference< table::XCellRange >& xRange ) 376 { 377 // need the ScCellRangesBase to get docshell 378 uno::Reference< uno::XInterface > xIf( xRange ); 379 return getDocShellFromIf(xIf ); 380 } 381 382 /// @throws uno::RuntimeException 383 static ScDocShell* 384 getDocShellFromRanges( const uno::Reference< sheet::XSheetCellRangeContainer >& xRanges ) 385 { 386 // need the ScCellRangesBase to get docshell 387 uno::Reference< uno::XInterface > xIf( xRanges ); 388 return getDocShellFromIf(xIf ); 389 } 390 391 /// @throws uno::RuntimeException 392 static uno::Reference< frame::XModel > getModelFromXIf( const uno::Reference< uno::XInterface >& xIf ) 393 { 394 ScDocShell* pDocShell = getDocShellFromIf(xIf ); 395 return pDocShell->GetModel(); 396 } 397 398 /// @throws uno::RuntimeException 399 static uno::Reference< frame::XModel > getModelFromRange( const uno::Reference< table::XCellRange >& xRange ) 400 { 401 // the XInterface for getImplementation can be any derived interface, no need for queryInterface 402 uno::Reference< uno::XInterface > xIf( xRange ); 403 return getModelFromXIf( xIf ); 404 } 405 406 static ScDocument& 407 getDocumentFromRange( const uno::Reference< table::XCellRange >& xRange ) 408 { 409 ScDocShell* pDocShell = getDocShellFromRange( xRange ); 410 if ( !pDocShell ) 411 throw uno::RuntimeException("Failed to access underlying docshell from uno range object" ); 412 ScDocument& rDoc = pDocShell->GetDocument(); 413 return rDoc; 414 } 415 416 ScDocument& 417 ScVbaRange::getScDocument() 418 { 419 if ( mxRanges.is() ) 420 { 421 uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); 422 uno::Reference< table::XCellRange > xRange( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW ); 423 return getDocumentFromRange( xRange ); 424 } 425 return getDocumentFromRange( mxRange ); 426 } 427 428 ScDocShell* 429 ScVbaRange::getScDocShell() 430 { 431 if ( mxRanges.is() ) 432 { 433 uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); 434 uno::Reference< table::XCellRange > xRange( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW ); 435 return getDocShellFromRange( xRange ); 436 } 437 return getDocShellFromRange( mxRange ); 438 } 439 440 ScVbaRange* ScVbaRange::getImplementation( const uno::Reference< excel::XRange >& rxRange ) 441 { 442 // FIXME: always save to use dynamic_cast? Or better to (implement and) use XTunnel? 443 return dynamic_cast< ScVbaRange* >( rxRange.get() ); 444 } 445 446 uno::Reference< frame::XModel > ScVbaRange::getUnoModel() 447 { 448 if( ScDocShell* pDocShell = getScDocShell() ) 449 return pDocShell->GetModel(); 450 throw uno::RuntimeException(); 451 } 452 453 uno::Reference< frame::XModel > ScVbaRange::getUnoModel( const uno::Reference< excel::XRange >& rxRange ) 454 { 455 if( ScVbaRange* pScVbaRange = getImplementation( rxRange ) ) 456 return pScVbaRange->getUnoModel(); 457 throw uno::RuntimeException(); 458 } 459 460 const ScRangeList& ScVbaRange::getScRangeList() 461 { 462 if( ScCellRangesBase* pScRangesBase = getCellRangesBase() ) 463 return pScRangesBase->GetRangeList(); 464 throw uno::RuntimeException("Cannot obtain UNO range implementation object" ); 465 } 466 467 const ScRangeList& ScVbaRange::getScRangeList( const uno::Reference< excel::XRange >& rxRange ) 468 { 469 if( ScVbaRange* pScVbaRange = getImplementation( rxRange ) ) 470 return pScVbaRange->getScRangeList(); 471 throw uno::RuntimeException("Cannot obtain VBA range implementation object" ); 472 } 473 474 namespace { 475 476 class NumFormatHelper 477 { 478 uno::Reference< util::XNumberFormatsSupplier > mxSupplier; 479 uno::Reference< beans::XPropertySet > mxRangeProps; 480 uno::Reference< util::XNumberFormats > mxFormats; 481 public: 482 explicit NumFormatHelper( const uno::Reference< table::XCellRange >& xRange ) 483 { 484 mxSupplier.set( getModelFromRange( xRange ), uno::UNO_QUERY_THROW ); 485 mxRangeProps.set( xRange, uno::UNO_QUERY_THROW); 486 mxFormats = mxSupplier->getNumberFormats(); 487 } 488 uno::Reference< beans::XPropertySet > getNumberProps() 489 { 490 tools::Long nIndexKey = 0; 491 uno::Any aValue = mxRangeProps->getPropertyValue( "NumberFormat" ); 492 aValue >>= nIndexKey; 493 494 if ( mxFormats.is() ) 495 return mxFormats->getByKey( nIndexKey ); 496 return uno::Reference< beans::XPropertySet > (); 497 } 498 499 bool isBooleanType() 500 { 501 502 return (getNumberFormat() & util::NumberFormat::LOGICAL) != 0; 503 } 504 505 bool isDateType() 506 { 507 sal_Int16 nType = getNumberFormat(); 508 return ( nType & util::NumberFormat::DATETIME ) != 0; 509 } 510 511 OUString getNumberFormatString() 512 { 513 uno::Reference< uno::XInterface > xIf( mxRangeProps, uno::UNO_QUERY_THROW ); 514 ScCellRangesBase* pUnoCellRange = comphelper::getFromUnoTunnel<ScCellRangesBase>( xIf ); 515 if ( pUnoCellRange ) 516 { 517 518 SfxItemSet* pDataSet = excel::ScVbaCellRangeAccess::GetDataSet( pUnoCellRange ); 519 SfxItemState eState = pDataSet->GetItemState( ATTR_VALUE_FORMAT); 520 // one of the cells in the range is not like the other ;-) 521 // so return a zero length format to indicate that 522 if ( eState == SfxItemState::DONTCARE ) 523 return OUString(); 524 } 525 526 uno::Reference< beans::XPropertySet > xNumberProps( getNumberProps(), uno::UNO_SET_THROW ); 527 OUString aFormatString; 528 uno::Any aString = xNumberProps->getPropertyValue( "FormatString" ); 529 aString >>= aFormatString; 530 return aFormatString; 531 } 532 533 sal_Int16 getNumberFormat() 534 { 535 uno::Reference< beans::XPropertySet > xNumberProps = getNumberProps(); 536 sal_Int16 nType = ::comphelper::getINT16( 537 xNumberProps->getPropertyValue( "Type" ) ); 538 return nType; 539 } 540 541 void setNumberFormat( const OUString& rFormat ) 542 { 543 // #163288# treat "General" as "Standard" format 544 sal_Int32 nNewIndex = 0; 545 if( !rFormat.equalsIgnoreAsciiCase( "General" ) ) 546 { 547 lang::Locale aLocale; 548 uno::Reference< beans::XPropertySet > xNumProps = getNumberProps(); 549 xNumProps->getPropertyValue( "Locale" ) >>= aLocale; 550 nNewIndex = mxFormats->queryKey( rFormat, aLocale, false ); 551 if ( nNewIndex == -1 ) // format not defined 552 nNewIndex = mxFormats->addNew( rFormat, aLocale ); 553 } 554 mxRangeProps->setPropertyValue( "NumberFormat", uno::Any( nNewIndex ) ); 555 } 556 557 void setNumberFormat( sal_Int16 nType ) 558 { 559 uno::Reference< beans::XPropertySet > xNumberProps = getNumberProps(); 560 lang::Locale aLocale; 561 xNumberProps->getPropertyValue( "Locale" ) >>= aLocale; 562 uno::Reference<util::XNumberFormatTypes> xTypes( mxFormats, uno::UNO_QUERY ); 563 if ( xTypes.is() ) 564 { 565 sal_Int32 nNewIndex = xTypes->getStandardFormat( nType, aLocale ); 566 mxRangeProps->setPropertyValue( "NumberFormat", uno::Any( nNewIndex ) ); 567 } 568 } 569 570 }; 571 572 struct CellPos 573 { 574 CellPos( sal_Int32 nRow, sal_Int32 nCol, sal_Int32 nArea ):m_nRow(nRow), m_nCol(nCol), m_nArea( nArea ) {}; 575 sal_Int32 m_nRow; 576 sal_Int32 m_nCol; 577 sal_Int32 m_nArea; 578 }; 579 580 } 581 582 typedef ::cppu::WeakImplHelper< container::XEnumeration > CellsEnumeration_BASE; 583 typedef ::std::vector< CellPos > vCellPos; 584 585 namespace { 586 587 // #FIXME - QUICK 588 // we could probably could and should modify CellsEnumeration below 589 // to handle rows and columns (but I do this separately for now 590 // and... this class only handles single areas (does it have to handle 591 // multi area ranges??) 592 class ColumnsRowEnumeration: public CellsEnumeration_BASE 593 { 594 uno::Reference< excel::XRange > mxRange; 595 sal_Int32 mMaxElems; 596 sal_Int32 mCurElem; 597 598 public: 599 ColumnsRowEnumeration( const uno::Reference< excel::XRange >& xRange, sal_Int32 nElems ) : mxRange( xRange ), mMaxElems( nElems ), mCurElem( 0 ) 600 { 601 } 602 603 virtual sal_Bool SAL_CALL hasMoreElements() override { return mCurElem < mMaxElems; } 604 605 virtual uno::Any SAL_CALL nextElement() override 606 { 607 if ( !hasMoreElements() ) 608 throw container::NoSuchElementException(); 609 sal_Int32 vbaIndex = 1 + mCurElem++; 610 return uno::Any( mxRange->Item( uno::Any( vbaIndex ), uno::Any() ) ); 611 } 612 }; 613 614 class CellsEnumeration : public CellsEnumeration_BASE 615 { 616 uno::WeakReference< XHelperInterface > mxParent; 617 uno::Reference< uno::XComponentContext > mxContext; 618 uno::Reference< XCollection > m_xAreas; 619 vCellPos m_CellPositions; 620 vCellPos::const_iterator m_it; 621 622 /// @throws uno::RuntimeException 623 uno::Reference< table::XCellRange > getArea( sal_Int32 nVBAIndex ) 624 { 625 if ( nVBAIndex < 1 || nVBAIndex > m_xAreas->getCount() ) 626 throw uno::RuntimeException(); 627 uno::Reference< excel::XRange > xRange( m_xAreas->Item( uno::Any(nVBAIndex), uno::Any() ), uno::UNO_QUERY_THROW ); 628 uno::Reference< table::XCellRange > xCellRange( ScVbaRange::getCellRange( xRange ), uno::UNO_QUERY_THROW ); 629 return xCellRange; 630 } 631 632 void populateArea( sal_Int32 nVBAIndex ) 633 { 634 uno::Reference< table::XCellRange > xRange = getArea( nVBAIndex ); 635 uno::Reference< table::XColumnRowRange > xColumnRowRange(xRange, uno::UNO_QUERY_THROW ); 636 sal_Int32 nRowCount = xColumnRowRange->getRows()->getCount(); 637 sal_Int32 nColCount = xColumnRowRange->getColumns()->getCount(); 638 for ( sal_Int32 i=0; i<nRowCount; ++i ) 639 { 640 for ( sal_Int32 j=0; j<nColCount; ++j ) 641 m_CellPositions.emplace_back( i,j,nVBAIndex ); 642 } 643 } 644 public: 645 CellsEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< XCollection >& xAreas ): mxParent( xParent ), mxContext( xContext ), m_xAreas( xAreas ) 646 { 647 sal_Int32 nItems = m_xAreas->getCount(); 648 for ( sal_Int32 index=1; index <= nItems; ++index ) 649 { 650 populateArea( index ); 651 } 652 m_it = m_CellPositions.begin(); 653 } 654 virtual sal_Bool SAL_CALL hasMoreElements() override { return m_it != m_CellPositions.end(); } 655 656 virtual uno::Any SAL_CALL nextElement() override 657 { 658 if ( !hasMoreElements() ) 659 throw container::NoSuchElementException(); 660 CellPos aPos = *m_it++; 661 662 uno::Reference< table::XCellRange > xRangeArea = getArea( aPos.m_nArea ); 663 uno::Reference< table::XCellRange > xCellRange( xRangeArea->getCellByPosition( aPos.m_nCol, aPos.m_nRow ), uno::UNO_QUERY_THROW ); 664 return uno::Any( uno::Reference< excel::XRange >( new ScVbaRange( mxParent, mxContext, xCellRange ) ) ); 665 666 } 667 }; 668 669 } 670 671 constexpr OUStringLiteral ISVISIBLE = u"IsVisible"; 672 const char EQUALS[] = "="; 673 const char NOTEQUALS[] = "<>"; 674 const char GREATERTHAN[] = ">"; 675 const char GREATERTHANEQUALS[] = ">="; 676 const char LESSTHAN[] = "<"; 677 const char LESSTHANEQUALS[] = "<="; 678 constexpr OUStringLiteral STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY(u"The command you chose cannot be performed with multiple selections.\nSelect a single range and click the command again"); 679 constexpr OUStringLiteral CELLSTYLE = u"CellStyle"; 680 681 namespace { 682 683 class CellValueSetter : public ValueSetter 684 { 685 protected: 686 uno::Any maValue; 687 public: 688 explicit CellValueSetter( const uno::Any& aValue ); 689 virtual bool processValue( const uno::Any& aValue, const uno::Reference< table::XCell >& xCell ) override; 690 virtual void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override; 691 692 }; 693 694 } 695 696 CellValueSetter::CellValueSetter( const uno::Any& aValue ): maValue( aValue ) {} 697 698 void 699 CellValueSetter::visitNode( sal_Int32 /*i*/, sal_Int32 /*j*/, const uno::Reference< table::XCell >& xCell ) 700 { 701 processValue( maValue, xCell ); 702 } 703 704 bool 705 CellValueSetter::processValue( const uno::Any& aValue, const uno::Reference< table::XCell >& xCell ) 706 { 707 708 bool isExtracted = false; 709 switch ( aValue.getValueTypeClass() ) 710 { 711 case uno::TypeClass_BOOLEAN: 712 { 713 bool bState = false; 714 if ( aValue >>= bState ) 715 { 716 uno::Reference< table::XCellRange > xRange( xCell, uno::UNO_QUERY_THROW ); 717 if ( bState ) 718 xCell->setValue( double(1) ); 719 else 720 xCell->setValue( double(0) ); 721 NumFormatHelper cellNumFormat( xRange ); 722 cellNumFormat.setNumberFormat( util::NumberFormat::LOGICAL ); 723 } 724 break; 725 } 726 case uno::TypeClass_STRING: 727 { 728 OUString aString; 729 if ( aValue >>= aString ) 730 { 731 // The required behavior for a string value is: 732 // 1. If the first character is a single quote, use the rest as a string cell, regardless of the cell's number format. 733 // 2. Otherwise, if the cell's number format is "text", use the string value as a string cell. 734 // 3. Otherwise, parse the string value in English locale, and apply a corresponding number format with the cell's locale 735 // if the cell's number format was "General". 736 // Case 1 is handled here, the rest in ScCellObj::InputEnglishString 737 738 if ( aString.toChar() == '\'' ) // case 1 - handle with XTextRange 739 { 740 OUString aRemainder( aString.copy(1) ); // strip the quote 741 uno::Reference< text::XTextRange > xTextRange( xCell, uno::UNO_QUERY_THROW ); 742 xTextRange->setString( aRemainder ); 743 } 744 else 745 { 746 // call implementation method InputEnglishString 747 ScCellObj* pCellObj = dynamic_cast< ScCellObj* >( xCell.get() ); 748 if ( pCellObj ) 749 pCellObj->InputEnglishString( aString ); 750 } 751 } 752 else 753 isExtracted = false; 754 break; 755 } 756 default: 757 { 758 double nDouble = 0.0; 759 if ( aValue >>= nDouble ) 760 { 761 uno::Reference< table::XCellRange > xRange( xCell, uno::UNO_QUERY_THROW ); 762 NumFormatHelper cellFormat( xRange ); 763 // If we are setting a number and the cell types was logical 764 // then we need to reset the logical format. ( see case uno::TypeClass_BOOLEAN: 765 // handling above ) 766 if ( cellFormat.isBooleanType() ) 767 cellFormat.setNumberFormat("General"); 768 xCell->setValue( nDouble ); 769 } 770 else 771 isExtracted = false; 772 break; 773 } 774 } 775 return isExtracted; 776 777 } 778 779 namespace { 780 781 class CellValueGetter : public ValueGetter 782 { 783 protected: 784 uno::Any maValue; 785 public: 786 CellValueGetter() {} 787 virtual void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override; 788 virtual void processValue( const uno::Any& aValue ) override; 789 const uno::Any& getValue() const override { return maValue; } 790 791 }; 792 793 } 794 795 void 796 CellValueGetter::processValue( const uno::Any& aValue ) 797 { 798 maValue = aValue; 799 } 800 void CellValueGetter::visitNode( sal_Int32 /*x*/, sal_Int32 /*y*/, const uno::Reference< table::XCell >& xCell ) 801 { 802 uno::Any aValue; 803 table::CellContentType eType = xCell->getType(); 804 if( eType == table::CellContentType_VALUE || eType == table::CellContentType_FORMULA ) 805 { 806 if ( eType == table::CellContentType_FORMULA ) 807 { 808 809 OUString sFormula = xCell->getFormula(); 810 if ( sFormula == "=TRUE()" ) 811 aValue <<= true; 812 else if ( sFormula == "=FALSE()" ) 813 aValue <<= false; 814 else 815 { 816 uno::Reference< beans::XPropertySet > xProp( xCell, uno::UNO_QUERY_THROW ); 817 818 sal_Int32 nResultType = sheet::FormulaResult::VALUE; 819 // some formulas give textual results 820 xProp->getPropertyValue( "FormulaResultType2" ) >>= nResultType; 821 822 if ( nResultType == sheet::FormulaResult::STRING ) 823 { 824 uno::Reference< text::XTextRange > xTextRange(xCell, ::uno::UNO_QUERY_THROW); 825 aValue <<= xTextRange->getString(); 826 } 827 else 828 aValue <<= xCell->getValue(); 829 } 830 } 831 else 832 { 833 uno::Reference< table::XCellRange > xRange( xCell, uno::UNO_QUERY_THROW ); 834 NumFormatHelper cellFormat( xRange ); 835 if ( cellFormat.isBooleanType() ) 836 aValue <<= ( xCell->getValue() != 0.0 ); 837 else if ( cellFormat.isDateType() ) 838 aValue <<= bridge::oleautomation::Date( xCell->getValue() ); 839 else 840 aValue <<= xCell->getValue(); 841 } 842 } 843 if( eType == table::CellContentType_TEXT ) 844 { 845 uno::Reference< text::XTextRange > xTextRange(xCell, ::uno::UNO_QUERY_THROW); 846 aValue <<= xTextRange->getString(); 847 } 848 processValue( aValue ); 849 } 850 851 namespace { 852 853 class CellFormulaValueSetter : public CellValueSetter 854 { 855 private: 856 ScDocument& m_rDoc; 857 formula::FormulaGrammar::Grammar m_eGrammar; 858 public: 859 CellFormulaValueSetter( const uno::Any& aValue, ScDocument& rDoc, formula::FormulaGrammar::Grammar eGram ):CellValueSetter( aValue ), m_rDoc( rDoc ), m_eGrammar( eGram ){} 860 protected: 861 bool processValue( const uno::Any& aValue, const uno::Reference< table::XCell >& xCell ) override 862 { 863 OUString sFormula; 864 double aDblValue = 0.0; 865 if ( aValue >>= sFormula ) 866 { 867 // convert to GRAM_API style grammar because XCell::setFormula 868 // always compile it in that grammar. Perhaps 869 // css.sheet.FormulaParser should be used in future to directly 870 // pass formula tokens when that API stabilizes. 871 if ( m_eGrammar != formula::FormulaGrammar::GRAM_API && ( o3tl::starts_with(o3tl::trim(sFormula), u"=") ) ) 872 { 873 uno::Reference< uno::XInterface > xIf( xCell, uno::UNO_QUERY_THROW ); 874 ScCellRangesBase* pUnoRangesBase = dynamic_cast< ScCellRangesBase* >( xIf.get() ); 875 if ( pUnoRangesBase ) 876 { 877 const ScRangeList& rCellRanges = pUnoRangesBase->GetRangeList(); 878 if (!rCellRanges.empty()) 879 { 880 ScCompiler aCompiler( m_rDoc, rCellRanges.front().aStart, m_eGrammar ); 881 // compile the string in the format passed in 882 std::unique_ptr<ScTokenArray> pArray(aCompiler.CompileString(sFormula)); 883 // convert to API grammar 884 aCompiler.SetGrammar( formula::FormulaGrammar::GRAM_API ); 885 OUString sConverted; 886 aCompiler.CreateStringFromTokenArray(sConverted); 887 sFormula = EQUALS + sConverted; 888 } 889 } 890 } 891 892 xCell->setFormula( sFormula ); 893 return true; 894 } 895 else if ( aValue >>= aDblValue ) 896 { 897 xCell->setValue( aDblValue ); 898 return true; 899 } 900 return false; 901 } 902 903 }; 904 905 class CellFormulaValueGetter : public CellValueGetter 906 { 907 private: 908 ScDocument& m_rDoc; 909 formula::FormulaGrammar::Grammar m_eGrammar; 910 public: 911 CellFormulaValueGetter(ScDocument& rDoc, formula::FormulaGrammar::Grammar eGram ) : m_rDoc( rDoc ), m_eGrammar( eGram ) {} 912 virtual void visitNode( sal_Int32 /*x*/, sal_Int32 /*y*/, const uno::Reference< table::XCell >& xCell ) override 913 { 914 uno::Any aValue; 915 aValue <<= xCell->getFormula(); 916 // XCell::getFormula() returns the formula in API grammar, convert. 917 if ((xCell->getType() == table::CellContentType_FORMULA) 918 && m_eGrammar != formula::FormulaGrammar::GRAM_API) 919 { 920 uno::Reference< uno::XInterface > xIf( xCell, uno::UNO_QUERY_THROW ); 921 ScCellRangesBase* pUnoRangesBase = dynamic_cast< ScCellRangesBase* >( xIf.get() ); 922 if (pUnoRangesBase) 923 { 924 OUString sVal; 925 aValue >>= sVal; 926 const ScRangeList& rCellRanges = pUnoRangesBase->GetRangeList(); 927 if (!rCellRanges.empty()) 928 { 929 // Compile string from API grammar. 930 ScCompiler aCompiler( m_rDoc, rCellRanges.front().aStart, formula::FormulaGrammar::GRAM_API ); 931 std::unique_ptr<ScTokenArray> pArray(aCompiler.CompileString(sVal)); 932 // Convert to desired grammar. 933 aCompiler.SetGrammar( m_eGrammar ); 934 OUString sConverted; 935 aCompiler.CreateStringFromTokenArray(sConverted); 936 sVal = EQUALS + sConverted; 937 aValue <<= sVal; 938 } 939 } 940 } 941 942 processValue( aValue ); 943 } 944 945 }; 946 947 class Dim2ArrayValueGetter : public ArrayVisitor 948 { 949 protected: 950 uno::Any maValue; 951 ValueGetter& mValueGetter; 952 void processValue( sal_Int32 x, sal_Int32 y, const uno::Any& aValue ) 953 { 954 uno::Sequence< uno::Sequence< uno::Any > >& aMatrix = const_cast<css::uno::Sequence<css::uno::Sequence<css::uno::Any>> &>(*o3tl::doAccess<uno::Sequence<uno::Sequence<uno::Any>>>(maValue)); 955 aMatrix.getArray()[x].getArray()[y] = aValue; 956 } 957 958 public: 959 Dim2ArrayValueGetter(sal_Int32 nRowCount, sal_Int32 nColCount, ValueGetter& rValueGetter ): mValueGetter(rValueGetter) 960 { 961 uno::Sequence< uno::Sequence< uno::Any > > aMatrix; 962 aMatrix.realloc( nRowCount ); 963 auto pMatrix = aMatrix.getArray(); 964 for ( sal_Int32 index = 0; index < nRowCount; ++index ) 965 pMatrix[index].realloc( nColCount ); 966 maValue <<= aMatrix; 967 } 968 void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override 969 970 { 971 mValueGetter.visitNode( x, y, xCell ); 972 processValue( x, y, mValueGetter.getValue() ); 973 } 974 const uno::Any& getValue() const { return maValue; } 975 976 }; 977 978 } 979 980 constexpr OUStringLiteral sNA = u"#N/A"; 981 982 namespace { 983 984 class Dim1ArrayValueSetter : public ArrayVisitor 985 { 986 uno::Sequence< uno::Any > aMatrix; 987 sal_Int32 nColCount; 988 ValueSetter& mCellValueSetter; 989 public: 990 Dim1ArrayValueSetter( const uno::Any& aValue, ValueSetter& rCellValueSetter ):mCellValueSetter( rCellValueSetter ) 991 { 992 aValue >>= aMatrix; 993 nColCount = aMatrix.getLength(); 994 } 995 virtual void visitNode( sal_Int32 /*x*/, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override 996 { 997 if ( y < nColCount ) 998 mCellValueSetter.processValue( aMatrix[ y ], xCell ); 999 else 1000 mCellValueSetter.processValue( uno::Any( OUString(sNA) ), xCell ); 1001 } 1002 }; 1003 1004 class Dim2ArrayValueSetter : public ArrayVisitor 1005 { 1006 uno::Sequence< uno::Sequence< uno::Any > > aMatrix; 1007 ValueSetter& mCellValueSetter; 1008 sal_Int32 nRowCount; 1009 sal_Int32 nColCount; 1010 public: 1011 Dim2ArrayValueSetter( const uno::Any& aValue, ValueSetter& rCellValueSetter ) : mCellValueSetter( rCellValueSetter ) 1012 { 1013 aValue >>= aMatrix; 1014 nRowCount = aMatrix.getLength(); 1015 nColCount = aMatrix[0].getLength(); 1016 } 1017 1018 virtual void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override 1019 { 1020 if ( x < nRowCount && y < nColCount ) 1021 mCellValueSetter.processValue( aMatrix[ x ][ y ], xCell ); 1022 else 1023 mCellValueSetter.processValue( uno::Any( OUString(sNA) ), xCell ); 1024 1025 } 1026 }; 1027 1028 class RangeProcessor 1029 { 1030 public: 1031 virtual void process( const uno::Reference< excel::XRange >& xRange ) = 0; 1032 1033 protected: 1034 ~RangeProcessor() {} 1035 }; 1036 1037 class RangeValueProcessor : public RangeProcessor 1038 { 1039 const uno::Any& m_aVal; 1040 public: 1041 explicit RangeValueProcessor( const uno::Any& rVal ):m_aVal( rVal ) {} 1042 virtual ~RangeValueProcessor() {} 1043 virtual void process( const uno::Reference< excel::XRange >& xRange ) override 1044 { 1045 xRange->setValue( m_aVal ); 1046 } 1047 }; 1048 1049 class RangeFormulaProcessor : public RangeProcessor 1050 { 1051 const uno::Any& m_aVal; 1052 public: 1053 explicit RangeFormulaProcessor( const uno::Any& rVal ):m_aVal( rVal ) {} 1054 virtual ~RangeFormulaProcessor() {} 1055 virtual void process( const uno::Reference< excel::XRange >& xRange ) override 1056 { 1057 xRange->setFormula( m_aVal ); 1058 } 1059 }; 1060 1061 class RangeCountProcessor : public RangeProcessor 1062 { 1063 sal_Int32 nCount; 1064 public: 1065 RangeCountProcessor():nCount(0){} 1066 virtual ~RangeCountProcessor() {} 1067 virtual void process( const uno::Reference< excel::XRange >& xRange ) override 1068 { 1069 nCount = nCount + xRange->getCount(); 1070 } 1071 sal_Int32 value() { return nCount; } 1072 }; 1073 class AreasVisitor 1074 { 1075 private: 1076 uno::Reference< XCollection > m_Areas; 1077 public: 1078 explicit AreasVisitor( const uno::Reference< XCollection >& rAreas ):m_Areas( rAreas ){} 1079 1080 void visit( RangeProcessor& processor ) 1081 { 1082 if ( m_Areas.is() ) 1083 { 1084 sal_Int32 nItems = m_Areas->getCount(); 1085 for ( sal_Int32 index=1; index <= nItems; ++index ) 1086 { 1087 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); 1088 processor.process( xRange ); 1089 } 1090 } 1091 } 1092 }; 1093 1094 class RangeHelper 1095 { 1096 uno::Reference< table::XCellRange > m_xCellRange; 1097 1098 public: 1099 /// @throws uno::RuntimeException 1100 explicit RangeHelper( const uno::Reference< table::XCellRange >& xCellRange ) : m_xCellRange( xCellRange ) 1101 { 1102 if ( !m_xCellRange.is() ) 1103 throw uno::RuntimeException(); 1104 } 1105 /// @throws uno::RuntimeException 1106 explicit RangeHelper( const uno::Any& rCellRange ) 1107 { 1108 m_xCellRange.set(rCellRange, uno::UNO_QUERY_THROW); 1109 } 1110 /// @throws uno::RuntimeException 1111 uno::Reference< sheet::XSheetCellRange > getSheetCellRange() const 1112 { 1113 return uno::Reference< sheet::XSheetCellRange >(m_xCellRange, uno::UNO_QUERY_THROW); 1114 } 1115 /// @throws uno::RuntimeException 1116 uno::Reference< sheet::XSpreadsheet > getSpreadSheet() const 1117 { 1118 return getSheetCellRange()->getSpreadsheet(); 1119 } 1120 1121 /// @throws uno::RuntimeException 1122 uno::Reference< table::XCellRange > getCellRangeFromSheet() const 1123 { 1124 return uno::Reference< table::XCellRange >(getSpreadSheet(), uno::UNO_QUERY_THROW ); 1125 } 1126 1127 /// @throws uno::RuntimeException 1128 uno::Reference< sheet::XCellRangeAddressable > getCellRangeAddressable() const 1129 { 1130 return uno::Reference< sheet::XCellRangeAddressable >(m_xCellRange, ::uno::UNO_QUERY_THROW); 1131 1132 } 1133 1134 /// @throws uno::RuntimeException 1135 uno::Reference< sheet::XSheetCellCursor > getSheetCellCursor() const 1136 { 1137 return uno::Reference< sheet::XSheetCellCursor >( getSpreadSheet()->createCursorByRange( getSheetCellRange() ), uno::UNO_SET_THROW ); 1138 } 1139 1140 static uno::Reference< excel::XRange > createRangeFromRange( const uno::Reference< XHelperInterface >& xParent, const uno::Reference<uno::XComponentContext >& xContext, 1141 const uno::Reference< table::XCellRange >& xRange, const uno::Reference< sheet::XCellRangeAddressable >& xCellRangeAddressable ) 1142 { 1143 return uno::Reference< excel::XRange >( new ScVbaRange( xParent, xContext, 1144 xRange->getCellRangeByPosition( 1145 xCellRangeAddressable->getRangeAddress().StartColumn, 1146 xCellRangeAddressable->getRangeAddress().StartRow, 1147 xCellRangeAddressable->getRangeAddress().EndColumn, 1148 xCellRangeAddressable->getRangeAddress().EndRow ) ) ); 1149 } 1150 1151 }; 1152 1153 } 1154 1155 bool 1156 ScVbaRange::getCellRangesForAddress( ScRefFlags& rResFlags, std::u16string_view sAddress, ScDocShell* pDocSh, ScRangeList& rCellRanges, formula::FormulaGrammar::AddressConvention eConv, char cDelimiter ) 1157 { 1158 1159 if ( pDocSh ) 1160 { 1161 ScDocument& rDoc = pDocSh->GetDocument(); 1162 rResFlags = rCellRanges.Parse( sAddress, rDoc, eConv, 0, cDelimiter ); 1163 if ( rResFlags & ScRefFlags::VALID ) 1164 { 1165 return true; 1166 } 1167 } 1168 return false; 1169 } 1170 1171 bool getScRangeListForAddress( const OUString& sName, ScDocShell* pDocSh, const ScRange& refRange, ScRangeList& aCellRanges, formula::FormulaGrammar::AddressConvention aConv ) 1172 { 1173 // see if there is a match with a named range 1174 uno::Reference< beans::XPropertySet > xProps( pDocSh->GetModel(), uno::UNO_QUERY_THROW ); 1175 uno::Reference< container::XNameAccess > xNameAccess( xProps->getPropertyValue( "NamedRanges" ), uno::UNO_QUERY_THROW ); 1176 // Strange enough you can have Range( "namedRange1, namedRange2, etc," ) 1177 // loop around each ',' separated name 1178 std::vector< OUString > vNames; 1179 sal_Int32 nIndex = 0; 1180 do 1181 { 1182 OUString aToken = sName.getToken( 0, ',', nIndex ); 1183 vNames.push_back( aToken ); 1184 } while ( nIndex >= 0 ); 1185 1186 if ( vNames.empty() ) 1187 vNames.push_back( sName ); 1188 1189 for ( const auto& rName : vNames ) 1190 { 1191 formula::FormulaGrammar::AddressConvention eConv = aConv; 1192 // spaces are illegal ( but the user of course can enter them ) 1193 OUString sAddress = rName.trim(); 1194 // if a local name ( on the active sheet ) exists this will 1195 // take precedence over a global with the same name 1196 if ( !xNameAccess->hasByName( sAddress ) ) 1197 { 1198 // try a local name 1199 ScDocument& rDoc = pDocSh->GetDocument(); 1200 SCTAB nCurTab = ScDocShell::GetCurTab(); 1201 ScRangeName* pRangeName = rDoc.GetRangeName(nCurTab); 1202 if (pRangeName) 1203 { 1204 // TODO: Handle local names correctly: 1205 // bool bLocalName = pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(sAddress)) != nullptr; 1206 } 1207 } 1208 char aChar = 0; 1209 if ( xNameAccess->hasByName( sAddress ) ) 1210 { 1211 uno::Reference< sheet::XNamedRange > xNamed( xNameAccess->getByName( sAddress ), uno::UNO_QUERY_THROW ); 1212 sAddress = xNamed->getContent(); 1213 // As the address comes from OOO, the addressing 1214 // style is may not be XL_A1 1215 eConv = pDocSh->GetDocument().GetAddressConvention(); 1216 aChar = ';'; 1217 } 1218 1219 ScRefFlags nFlags = ScRefFlags::ZERO; 1220 if ( !ScVbaRange::getCellRangesForAddress( nFlags, sAddress, pDocSh, aCellRanges, eConv, aChar ) ) 1221 return false; 1222 1223 bool bTabFromReferrer = !( nFlags & ScRefFlags::TAB_3D ); 1224 1225 for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i ) 1226 { 1227 ScRange & rRange = aCellRanges[ i ]; 1228 rRange.aStart.SetCol( refRange.aStart.Col() + rRange.aStart.Col() ); 1229 rRange.aStart.SetRow( refRange.aStart.Row() + rRange.aStart.Row() ); 1230 rRange.aStart.SetTab( bTabFromReferrer ? refRange.aStart.Tab() : rRange.aStart.Tab() ); 1231 rRange.aEnd.SetCol( refRange.aStart.Col() + rRange.aEnd.Col() ); 1232 rRange.aEnd.SetRow( refRange.aStart.Row() + rRange.aEnd.Row() ); 1233 rRange.aEnd.SetTab( bTabFromReferrer ? refRange.aEnd.Tab() : rRange.aEnd.Tab() ); 1234 } 1235 } 1236 return true; 1237 } 1238 1239 /// @throws uno::RuntimeException 1240 static rtl::Reference<ScVbaRange> 1241 getRangeForName( const uno::Reference< uno::XComponentContext >& xContext, const OUString& sName, ScDocShell* pDocSh, const table::CellRangeAddress& pAddr, formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_XL_A1 ) 1242 { 1243 ScRangeList aCellRanges; 1244 ScRange refRange; 1245 ScUnoConversion::FillScRange( refRange, pAddr ); 1246 if ( !getScRangeListForAddress ( sName, pDocSh, refRange, aCellRanges, eConv ) ) 1247 throw uno::RuntimeException(); 1248 // Single range 1249 if ( aCellRanges.size() == 1 ) 1250 { 1251 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pDocSh, aCellRanges.front() ) ); 1252 uno::Reference< XHelperInterface > xFixThisParent = excel::getUnoSheetModuleObj( xRange ); 1253 return new ScVbaRange( xFixThisParent, xContext, xRange ); 1254 } 1255 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pDocSh, aCellRanges ) ); 1256 1257 uno::Reference< XHelperInterface > xFixThisParent = excel::getUnoSheetModuleObj( xRanges ); 1258 return new ScVbaRange( xFixThisParent, xContext, xRanges ); 1259 } 1260 1261 namespace { 1262 1263 /// @throws uno::RuntimeException 1264 template< typename RangeType > 1265 table::CellRangeAddress lclGetRangeAddress( const uno::Reference< RangeType >& rxCellRange ) 1266 { 1267 return uno::Reference< sheet::XCellRangeAddressable >( rxCellRange, uno::UNO_QUERY_THROW )->getRangeAddress(); 1268 } 1269 1270 /// @throws uno::RuntimeException 1271 void lclClearRange( const uno::Reference< table::XCellRange >& rxCellRange ) 1272 { 1273 using namespace ::com::sun::star::sheet::CellFlags; 1274 sal_Int32 const nFlags = VALUE | DATETIME | STRING | ANNOTATION | FORMULA | HARDATTR | STYLES | EDITATTR | FORMATTED; 1275 uno::Reference< sheet::XSheetOperation > xSheetOperation( rxCellRange, uno::UNO_QUERY_THROW ); 1276 xSheetOperation->clearContents( nFlags ); 1277 } 1278 1279 /// @throws uno::RuntimeException 1280 uno::Reference< sheet::XSheetCellRange > lclExpandToMerged( const uno::Reference< table::XCellRange >& rxCellRange, bool bRecursive ) 1281 { 1282 uno::Reference< sheet::XSheetCellRange > xNewCellRange( rxCellRange, uno::UNO_QUERY_THROW ); 1283 uno::Reference< sheet::XSpreadsheet > xSheet( xNewCellRange->getSpreadsheet(), uno::UNO_SET_THROW ); 1284 table::CellRangeAddress aNewAddress = lclGetRangeAddress( xNewCellRange ); 1285 table::CellRangeAddress aOldAddress; 1286 // expand as long as there are new merged ranges included 1287 do 1288 { 1289 aOldAddress = aNewAddress; 1290 uno::Reference< sheet::XSheetCellCursor > xCursor( xSheet->createCursorByRange( xNewCellRange ), uno::UNO_SET_THROW ); 1291 xCursor->collapseToMergedArea(); 1292 xNewCellRange.set( xCursor, uno::UNO_QUERY_THROW ); 1293 aNewAddress = lclGetRangeAddress( xNewCellRange ); 1294 } 1295 while( bRecursive && (aOldAddress != aNewAddress) ); 1296 return xNewCellRange; 1297 } 1298 1299 /// @throws uno::RuntimeException 1300 uno::Reference< sheet::XSheetCellRangeContainer > lclExpandToMerged( const uno::Reference< sheet::XSheetCellRangeContainer >& rxCellRanges ) 1301 { 1302 if( !rxCellRanges.is() ) 1303 throw uno::RuntimeException("Missing cell ranges object" ); 1304 sal_Int32 nCount = rxCellRanges->getCount(); 1305 if( nCount < 1 ) 1306 throw uno::RuntimeException("Missing cell ranges object" ); 1307 1308 ScRangeList aScRanges; 1309 for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) 1310 { 1311 uno::Reference< table::XCellRange > xRange( rxCellRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); 1312 table::CellRangeAddress aRangeAddr = lclGetRangeAddress( lclExpandToMerged( xRange, /*bRecursive*/true ) ); 1313 ScRange aScRange; 1314 ScUnoConversion::FillScRange( aScRange, aRangeAddr ); 1315 aScRanges.push_back( aScRange ); 1316 } 1317 return new ScCellRangesObj( getDocShellFromRanges( rxCellRanges ), aScRanges ); 1318 } 1319 1320 /// @throws uno::RuntimeException 1321 void lclExpandAndMerge( const uno::Reference< table::XCellRange >& rxCellRange, bool bMerge ) 1322 { 1323 uno::Reference< util::XMergeable > xMerge( lclExpandToMerged( rxCellRange, true ), uno::UNO_QUERY_THROW ); 1324 // Calc cannot merge over merged ranges, always unmerge first 1325 xMerge->merge( false ); 1326 if( !bMerge ) 1327 return; 1328 1329 // clear all contents of the covered cells (not the top-left cell) 1330 table::CellRangeAddress aRangeAddr = lclGetRangeAddress( rxCellRange ); 1331 sal_Int32 nLastColIdx = aRangeAddr.EndColumn - aRangeAddr.StartColumn; 1332 sal_Int32 nLastRowIdx = aRangeAddr.EndRow - aRangeAddr.StartRow; 1333 // clear cells of top row, right of top-left cell 1334 if( nLastColIdx > 0 ) 1335 lclClearRange( rxCellRange->getCellRangeByPosition( 1, 0, nLastColIdx, 0 ) ); 1336 // clear all rows below top row 1337 if( nLastRowIdx > 0 ) 1338 lclClearRange( rxCellRange->getCellRangeByPosition( 0, 1, nLastColIdx, nLastRowIdx ) ); 1339 // merge the range 1340 xMerge->merge( true ); 1341 } 1342 1343 /// @throws uno::RuntimeException 1344 util::TriState lclGetMergedState( const uno::Reference< table::XCellRange >& rxCellRange ) 1345 { 1346 /* 1) Check if range is completely inside one single merged range. To do 1347 this, try to extend from top-left cell only (not from entire range). 1348 This will exclude cases where this range consists of several merged 1349 ranges (or parts of them). */ 1350 table::CellRangeAddress aRangeAddr = lclGetRangeAddress( rxCellRange ); 1351 uno::Reference< table::XCellRange > xTopLeft( rxCellRange->getCellRangeByPosition( 0, 0, 0, 0 ), uno::UNO_SET_THROW ); 1352 uno::Reference< sheet::XSheetCellRange > xExpanded( lclExpandToMerged( xTopLeft, false ), uno::UNO_SET_THROW ); 1353 table::CellRangeAddress aExpAddr = lclGetRangeAddress( xExpanded ); 1354 // check that expanded range has more than one cell (really merged) 1355 if( ((aExpAddr.StartColumn < aExpAddr.EndColumn) || (aExpAddr.StartRow < aExpAddr.EndRow)) && ScUnoConversion::Contains( aExpAddr, aRangeAddr ) ) 1356 return util::TriState_YES; 1357 1358 /* 2) Check if this range contains any merged cells (completely or 1359 partly). This seems to be hardly possible via API, as 1360 XMergeable::getIsMerged() returns only true, if the top-left cell of a 1361 merged range is part of this range, so cases where just the lower part 1362 of a merged range is part of this range are not covered. */ 1363 ScRange aScRange; 1364 ScUnoConversion::FillScRange( aScRange, aRangeAddr ); 1365 bool bHasMerged = getDocumentFromRange( rxCellRange ).HasAttrib( aScRange, HasAttrFlags::Merged | HasAttrFlags::Overlapped ); 1366 return bHasMerged ? util::TriState_INDETERMINATE : util::TriState_NO; 1367 } 1368 1369 } // namespace 1370 1371 css::uno::Reference< excel::XRange > 1372 ScVbaRange::getRangeObjectForName( 1373 const uno::Reference< uno::XComponentContext >& xContext, const OUString& sRangeName, 1374 ScDocShell* pDocSh, formula::FormulaGrammar::AddressConvention eConv ) 1375 { 1376 table::CellRangeAddress refAddr; 1377 return getRangeForName( xContext, sRangeName, pDocSh, refAddr, eConv ); 1378 } 1379 1380 /// @throws uno::RuntimeException 1381 static table::CellRangeAddress getCellRangeAddressForVBARange( const uno::Any& aParam, ScDocShell* pDocSh ) 1382 { 1383 uno::Reference< table::XCellRange > xRangeParam; 1384 switch ( aParam.getValueTypeClass() ) 1385 { 1386 case uno::TypeClass_STRING: 1387 { 1388 OUString rString; 1389 aParam >>= rString; 1390 ScRangeList aCellRanges; 1391 ScRange refRange; 1392 if ( getScRangeListForAddress ( rString, pDocSh, refRange, aCellRanges ) ) 1393 { 1394 if ( aCellRanges.size() == 1 ) 1395 { 1396 table::CellRangeAddress aRangeAddress; 1397 ScUnoConversion::FillApiRange( aRangeAddress, aCellRanges.front() ); 1398 return aRangeAddress; 1399 } 1400 } 1401 } 1402 break; 1403 1404 case uno::TypeClass_INTERFACE: 1405 { 1406 uno::Reference< excel::XRange > xRange; 1407 aParam >>= xRange; 1408 if ( xRange.is() ) 1409 xRange->getCellRange() >>= xRangeParam; 1410 } 1411 break; 1412 1413 default: 1414 throw uno::RuntimeException("Can't extract CellRangeAddress from type" ); 1415 } 1416 return lclGetRangeAddress( xRangeParam ); 1417 } 1418 1419 /// @throws uno::RuntimeException 1420 static uno::Reference< XCollection > 1421 lcl_setupBorders( const uno::Reference< excel::XRange >& xParentRange, const uno::Reference<uno::XComponentContext>& xContext, const uno::Reference< table::XCellRange >& xRange ) 1422 { 1423 uno::Reference< XHelperInterface > xParent( xParentRange, uno::UNO_QUERY_THROW ); 1424 ScDocument& rDoc = getDocumentFromRange(xRange); 1425 ScVbaPalette aPalette( rDoc.GetDocumentShell() ); 1426 uno::Reference< XCollection > borders( new ScVbaBorders( xParent, xContext, xRange, aPalette ) ); 1427 return borders; 1428 } 1429 1430 ScVbaRange::ScVbaRange( uno::Sequence< uno::Any> const & args, 1431 uno::Reference< uno::XComponentContext> const & xContext ) : ScVbaRange_BASE( getXSomethingFromArgs< XHelperInterface >( args, 0 ), xContext, getXSomethingFromArgs< beans::XPropertySet >( args, 1, false ), getModelFromXIf( getXSomethingFromArgs< uno::XInterface >( args, 1 ) ), true ), mbIsRows( false ), mbIsColumns( false ) 1432 { 1433 mxRange.set( mxPropertySet, uno::UNO_QUERY ); 1434 mxRanges.set( mxPropertySet, uno::UNO_QUERY ); 1435 uno::Reference< container::XIndexAccess > xIndex; 1436 if ( mxRange.is() ) 1437 { 1438 xIndex = new SingleRangeIndexAccess( mxRange ); 1439 } 1440 else if ( mxRanges.is() ) 1441 { 1442 xIndex.set( mxRanges, uno::UNO_QUERY_THROW ); 1443 } 1444 m_Areas = new ScVbaRangeAreas( mxParent, mxContext, xIndex, mbIsRows, mbIsColumns ); 1445 } 1446 1447 ScVbaRange::ScVbaRange( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< table::XCellRange >& xRange, bool bIsRows, bool bIsColumns ) 1448 : ScVbaRange_BASE( xParent, xContext, uno::Reference< beans::XPropertySet >( xRange, uno::UNO_QUERY_THROW ), getModelFromRange( xRange), true ), mxRange( xRange ), 1449 mbIsRows( bIsRows ), 1450 mbIsColumns( bIsColumns ) 1451 { 1452 if ( !xContext.is() ) 1453 throw lang::IllegalArgumentException("context is not set ", uno::Reference< uno::XInterface >() , 1 ); 1454 if ( !xRange.is() ) 1455 throw lang::IllegalArgumentException("range is not set ", uno::Reference< uno::XInterface >() , 1 ); 1456 1457 uno::Reference< container::XIndexAccess > xIndex( new SingleRangeIndexAccess( xRange ) ); 1458 m_Areas = new ScVbaRangeAreas( mxParent, mxContext, xIndex, mbIsRows, mbIsColumns ); 1459 1460 } 1461 1462 ScVbaRange::ScVbaRange(const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< sheet::XSheetCellRangeContainer >& xRanges, bool bIsRows, bool bIsColumns) 1463 : ScVbaRange_BASE( xParent, xContext, uno::Reference< beans::XPropertySet >( xRanges, uno::UNO_QUERY_THROW ), getModelFromXIf( uno::Reference< uno::XInterface >( xRanges, uno::UNO_QUERY_THROW ) ), true ), mxRanges( xRanges ),mbIsRows( bIsRows ), mbIsColumns( bIsColumns ) 1464 1465 { 1466 uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); 1467 m_Areas = new ScVbaRangeAreas( xParent, mxContext, xIndex, mbIsRows, mbIsColumns ); 1468 1469 } 1470 1471 ScVbaRange::~ScVbaRange() 1472 { 1473 } 1474 1475 uno::Reference< XCollection >& ScVbaRange::getBorders() 1476 { 1477 if ( !m_Borders.is() ) 1478 { 1479 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW ); 1480 m_Borders = lcl_setupBorders( this, mxContext, uno::Reference< table::XCellRange >( xRange->getCellRange(), uno::UNO_QUERY_THROW ) ); 1481 } 1482 return m_Borders; 1483 } 1484 1485 void 1486 ScVbaRange::visitArray( ArrayVisitor& visitor ) 1487 { 1488 ScDocShell* pDocSh = nullptr; 1489 if(ScCellRangeObj* range = dynamic_cast<ScCellRangeObj*>(mxRange.get())) 1490 pDocSh = range->GetDocShell(); 1491 if ( pDocSh ) 1492 pDocSh->LockPaint(); 1493 table::CellRangeAddress aRangeAddr = lclGetRangeAddress( mxRange ); 1494 sal_Int32 nRowCount = aRangeAddr.EndRow - aRangeAddr.StartRow + 1; 1495 sal_Int32 nColCount = aRangeAddr.EndColumn - aRangeAddr.StartColumn + 1; 1496 for ( sal_Int32 i=0; i<nRowCount; ++i ) 1497 { 1498 for ( sal_Int32 j=0; j<nColCount; ++j ) 1499 { 1500 uno::Reference< table::XCell > xCell( mxRange->getCellByPosition( j, i ), uno::UNO_SET_THROW ); 1501 1502 visitor.visitNode( i, j, xCell ); 1503 } 1504 } 1505 if ( pDocSh ) 1506 pDocSh->UnlockPaint(); 1507 } 1508 1509 uno::Any 1510 ScVbaRange::getValue( ValueGetter& valueGetter) 1511 { 1512 uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY_THROW ); 1513 // single cell range 1514 if ( isSingleCellRange() ) 1515 { 1516 visitArray( valueGetter ); 1517 return valueGetter.getValue(); 1518 } 1519 sal_Int32 nRowCount = xColumnRowRange->getRows()->getCount(); 1520 sal_Int32 nColCount = xColumnRowRange->getColumns()->getCount(); 1521 // multi cell range ( return array ) 1522 Dim2ArrayValueGetter arrayGetter( nRowCount, nColCount, valueGetter ); 1523 visitArray( arrayGetter ); 1524 return uno::Any( script::ArrayWrapper( false, arrayGetter.getValue() ) ); 1525 } 1526 1527 uno::Any SAL_CALL 1528 ScVbaRange::getValue() 1529 { 1530 // #TODO code within the test below "if ( m_Areas... " can be removed 1531 // Test is performed only because m_xRange is NOT set to be 1532 // the first range in m_Areas ( to force failure while 1533 // the implementations for each method are being updated ) 1534 if ( m_Areas->getCount() > 1 ) 1535 { 1536 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); 1537 return xRange->getValue(); 1538 } 1539 1540 CellValueGetter valueGetter; 1541 return getValue( valueGetter ); 1542 1543 } 1544 1545 void 1546 ScVbaRange::setValue( const uno::Any& aValue, ValueSetter& valueSetter ) 1547 { 1548 uno::TypeClass aClass = aValue.getValueTypeClass(); 1549 if ( aClass == uno::TypeClass_SEQUENCE ) 1550 { 1551 const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( mxContext ); 1552 uno::Any aConverted; 1553 try 1554 { 1555 // test for single dimension, could do 1556 // with a better test than this 1557 if ( aValue.getValueTypeName().indexOf('[') == aValue.getValueTypeName().lastIndexOf('[') ) 1558 { 1559 aConverted = xConverter->convertTo( aValue, cppu::UnoType<uno::Sequence< uno::Any >>::get() ); 1560 Dim1ArrayValueSetter setter( aConverted, valueSetter ); 1561 visitArray( setter ); 1562 } 1563 else 1564 { 1565 aConverted = xConverter->convertTo( aValue, cppu::UnoType<uno::Sequence< uno::Sequence< uno::Any > >>::get() ); 1566 Dim2ArrayValueSetter setter( aConverted, valueSetter ); 1567 visitArray( setter ); 1568 } 1569 } 1570 catch ( const uno::Exception& ) 1571 { 1572 TOOLS_WARN_EXCEPTION("sc", "Bahhh, caught" ); 1573 } 1574 } 1575 else 1576 { 1577 visitArray( valueSetter ); 1578 } 1579 fireChangeEvent(); 1580 } 1581 1582 void SAL_CALL 1583 ScVbaRange::setValue( const uno::Any &aValue ) 1584 { 1585 // If this is a multiple selection apply setValue over all areas 1586 if ( m_Areas->getCount() > 1 ) 1587 { 1588 AreasVisitor aVisitor( m_Areas ); 1589 RangeValueProcessor valueProcessor( aValue ); 1590 aVisitor.visit( valueProcessor ); 1591 return; 1592 } 1593 CellValueSetter valueSetter( aValue ); 1594 setValue( aValue, valueSetter ); 1595 } 1596 1597 void SAL_CALL 1598 ScVbaRange::Clear() 1599 { 1600 using namespace ::com::sun::star::sheet::CellFlags; 1601 sal_Int32 const nFlags = VALUE | DATETIME | STRING | FORMULA | HARDATTR | EDITATTR | FORMATTED; 1602 ClearContents( nFlags, true ); 1603 } 1604 1605 //helper ClearContent 1606 void 1607 ScVbaRange::ClearContents( sal_Int32 nFlags, bool bFireEvent ) 1608 { 1609 // #TODO code within the test below "if ( m_Areas... " can be removed 1610 // Test is performed only because m_xRange is NOT set to be 1611 // the first range in m_Areas ( to force failure while 1612 // the implementations for each method are being updated ) 1613 if ( m_Areas->getCount() > 1 ) 1614 { 1615 sal_Int32 nItems = m_Areas->getCount(); 1616 for ( sal_Int32 index=1; index <= nItems; ++index ) 1617 { 1618 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); 1619 ScVbaRange* pRange = getImplementation( xRange ); 1620 if ( pRange ) 1621 pRange->ClearContents( nFlags, false ); // do not fire for single ranges 1622 } 1623 // fire change event for the entire range list 1624 if( bFireEvent ) fireChangeEvent(); 1625 return; 1626 } 1627 1628 uno::Reference< sheet::XSheetOperation > xSheetOperation(mxRange, uno::UNO_QUERY_THROW); 1629 xSheetOperation->clearContents( nFlags ); 1630 if( bFireEvent ) fireChangeEvent(); 1631 } 1632 1633 void SAL_CALL 1634 ScVbaRange::ClearComments() 1635 { 1636 ClearContents( sheet::CellFlags::ANNOTATION, false ); 1637 } 1638 1639 void SAL_CALL 1640 ScVbaRange::ClearContents() 1641 { 1642 using namespace ::com::sun::star::sheet::CellFlags; 1643 sal_Int32 const nFlags = VALUE | DATETIME | STRING | FORMULA; 1644 ClearContents( nFlags, true ); 1645 } 1646 1647 void SAL_CALL 1648 ScVbaRange::ClearFormats() 1649 { 1650 // FIXME: need to check if we need to combine FORMATTED 1651 using namespace ::com::sun::star::sheet::CellFlags; 1652 sal_Int32 const nFlags = HARDATTR | FORMATTED | EDITATTR; 1653 ClearContents( nFlags, false ); 1654 } 1655 1656 void 1657 ScVbaRange::setFormulaValue( const uno::Any& rFormula, formula::FormulaGrammar::Grammar eGram ) 1658 { 1659 // If this is a multiple selection apply setFormula over all areas 1660 if ( m_Areas->getCount() > 1 ) 1661 { 1662 AreasVisitor aVisitor( m_Areas ); 1663 RangeFormulaProcessor valueProcessor( rFormula ); 1664 aVisitor.visit( valueProcessor ); 1665 return; 1666 } 1667 CellFormulaValueSetter formulaValueSetter( rFormula, getScDocument(), eGram ); 1668 setValue( rFormula, formulaValueSetter ); 1669 } 1670 1671 uno::Any 1672 ScVbaRange::getFormulaValue( formula::FormulaGrammar::Grammar eGram ) 1673 { 1674 // #TODO code within the test below "if ( m_Areas... " can be removed 1675 // Test is performed only because m_xRange is NOT set to be 1676 // the first range in m_Areas ( to force failure while 1677 // the implementations for each method are being updated ) 1678 if ( m_Areas->getCount() > 1 ) 1679 { 1680 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); 1681 return xRange->getFormula(); 1682 } 1683 CellFormulaValueGetter valueGetter( getScDocument(), eGram ); 1684 return getValue( valueGetter ); 1685 1686 } 1687 1688 uno::Any 1689 ScVbaRange::getFormula() 1690 { 1691 return getFormulaValue( formula::FormulaGrammar::GRAM_ENGLISH_XL_A1 ); 1692 } 1693 1694 void 1695 ScVbaRange::setFormula(const uno::Any &rFormula ) 1696 { 1697 setFormulaValue( rFormula, formula::FormulaGrammar::GRAM_ENGLISH_XL_A1 ); 1698 } 1699 1700 uno::Any 1701 ScVbaRange::getFormulaR1C1() 1702 { 1703 return getFormulaValue( formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1 ); 1704 } 1705 1706 void 1707 ScVbaRange::setFormulaR1C1(const uno::Any& rFormula ) 1708 { 1709 setFormulaValue( rFormula, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1 ); 1710 } 1711 1712 uno::Any 1713 ScVbaRange::getFormulaLocal() 1714 { 1715 return getFormulaValue( formula::FormulaGrammar::GRAM_NATIVE_XL_A1 ); 1716 } 1717 1718 void 1719 ScVbaRange::setFormulaLocal(const uno::Any &rFormula ) 1720 { 1721 setFormulaValue( rFormula, formula::FormulaGrammar::GRAM_NATIVE_XL_A1 ); 1722 } 1723 1724 uno::Any 1725 ScVbaRange::getFormulaR1C1Local() 1726 { 1727 return getFormulaValue( formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1 ); 1728 } 1729 1730 void 1731 ScVbaRange::setFormulaR1C1Local(const uno::Any& rFormula ) 1732 { 1733 setFormulaValue( rFormula, formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1 ); 1734 } 1735 1736 sal_Int32 1737 ScVbaRange::getCount() 1738 { 1739 // If this is a multiple selection apply setValue over all areas 1740 if ( m_Areas->getCount() > 1 ) 1741 { 1742 AreasVisitor aVisitor( m_Areas ); 1743 RangeCountProcessor valueProcessor; 1744 aVisitor.visit( valueProcessor ); 1745 return valueProcessor.value(); 1746 } 1747 sal_Int32 rowCount = 0; 1748 sal_Int32 colCount = 0; 1749 uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY_THROW ); 1750 rowCount = xColumnRowRange->getRows()->getCount(); 1751 colCount = xColumnRowRange->getColumns()->getCount(); 1752 1753 if( mbIsRows ) 1754 return rowCount; 1755 if( mbIsColumns ) 1756 return colCount; 1757 return rowCount * colCount; 1758 } 1759 1760 sal_Int32 1761 ScVbaRange::getRow() 1762 { 1763 // #TODO code within the test below "if ( m_Areas... " can be removed 1764 // Test is performed only because m_xRange is NOT set to be 1765 // the first range in m_Areas ( to force failure while 1766 // the implementations for each method are being updated ) 1767 if ( m_Areas->getCount() > 1 ) 1768 { 1769 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); 1770 return xRange->getRow(); 1771 } 1772 uno::Reference< sheet::XCellAddressable > xCellAddressable(mxRange->getCellByPosition(0, 0), uno::UNO_QUERY_THROW ); 1773 return xCellAddressable->getCellAddress().Row + 1; // Zero value indexing 1774 } 1775 1776 sal_Int32 1777 ScVbaRange::getColumn() 1778 { 1779 // #TODO code within the test below "if ( m_Areas... " can be removed 1780 // Test is performed only because m_xRange is NOT set to be 1781 // the first range in m_Areas ( to force failure while 1782 // the implementations for each method are being updated ) 1783 if ( m_Areas->getCount() > 1 ) 1784 { 1785 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); 1786 return xRange->getColumn(); 1787 } 1788 uno::Reference< sheet::XCellAddressable > xCellAddressable(mxRange->getCellByPosition(0, 0), uno::UNO_QUERY_THROW ); 1789 return xCellAddressable->getCellAddress().Column + 1; // Zero value indexing 1790 } 1791 1792 uno::Any 1793 ScVbaRange::HasFormula() 1794 { 1795 if ( m_Areas->getCount() > 1 ) 1796 { 1797 sal_Int32 nItems = m_Areas->getCount(); 1798 uno::Any aResult = aNULL(); 1799 for ( sal_Int32 index=1; index <= nItems; ++index ) 1800 { 1801 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); 1802 // if the HasFormula for any area is different to another 1803 // return null 1804 if ( index > 1 ) 1805 if ( aResult != xRange->HasFormula() ) 1806 return aNULL(); 1807 aResult = xRange->HasFormula(); 1808 if ( aNULL() == aResult ) 1809 return aNULL(); 1810 } 1811 return aResult; 1812 } 1813 uno::Reference< uno::XInterface > xIf( mxRange, uno::UNO_QUERY_THROW ); 1814 ScCellRangesBase* pThisRanges = dynamic_cast< ScCellRangesBase * > ( xIf.get() ); 1815 if ( pThisRanges ) 1816 { 1817 uno::Reference<uno::XInterface> xRanges( pThisRanges->queryFormulaCells( sheet::FormulaResult::ERROR | sheet::FormulaResult::VALUE | sheet::FormulaResult::STRING ), uno::UNO_QUERY_THROW ); 1818 ScCellRangesBase* pFormulaRanges = dynamic_cast< ScCellRangesBase * > ( xRanges.get() ); 1819 assert(pFormulaRanges); 1820 // check if there are no formula cell, return false 1821 if ( pFormulaRanges->GetRangeList().empty() ) 1822 return uno::Any(false); 1823 1824 // check if there are holes (where some cells are not formulas) 1825 // or returned range is not equal to this range 1826 if ( ( pFormulaRanges->GetRangeList().size() > 1 ) 1827 || ( pFormulaRanges->GetRangeList().front().aStart != pThisRanges->GetRangeList().front().aStart ) 1828 || ( pFormulaRanges->GetRangeList().front().aEnd != pThisRanges->GetRangeList().front().aEnd ) 1829 ) 1830 return aNULL(); // should return aNULL; 1831 } 1832 return uno::Any( true ); 1833 } 1834 void 1835 ScVbaRange::fillSeries( sheet::FillDirection nFillDirection, sheet::FillMode nFillMode, sheet::FillDateMode nFillDateMode, double fStep, double fEndValue ) 1836 { 1837 if ( m_Areas->getCount() > 1 ) 1838 { 1839 // Multi-Area Range 1840 uno::Reference< XCollection > xCollection( m_Areas, uno::UNO_SET_THROW ); 1841 for ( sal_Int32 index = 1; index <= xCollection->getCount(); ++index ) 1842 { 1843 uno::Reference< excel::XRange > xRange( xCollection->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW ); 1844 ScVbaRange* pThisRange = getImplementation( xRange ); 1845 pThisRange->fillSeries( nFillDirection, nFillMode, nFillDateMode, fStep, fEndValue ); 1846 1847 } 1848 return; 1849 } 1850 1851 uno::Reference< sheet::XCellSeries > xCellSeries(mxRange, uno::UNO_QUERY_THROW ); 1852 xCellSeries->fillSeries( nFillDirection, nFillMode, nFillDateMode, fStep, fEndValue ); 1853 fireChangeEvent(); 1854 } 1855 1856 void 1857 ScVbaRange::FillLeft() 1858 { 1859 fillSeries(sheet::FillDirection_TO_LEFT, 1860 sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF); 1861 } 1862 1863 void 1864 ScVbaRange::FillRight() 1865 { 1866 fillSeries(sheet::FillDirection_TO_RIGHT, 1867 sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF); 1868 } 1869 1870 void 1871 ScVbaRange::FillUp() 1872 { 1873 fillSeries(sheet::FillDirection_TO_TOP, 1874 sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF); 1875 } 1876 1877 void 1878 ScVbaRange::FillDown() 1879 { 1880 fillSeries(sheet::FillDirection_TO_BOTTOM, 1881 sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF); 1882 } 1883 1884 OUString 1885 ScVbaRange::getText() 1886 { 1887 // #TODO code within the test below "if ( m_Areas... " can be removed 1888 // Test is performed only because m_xRange is NOT set to be 1889 // the first range in m_Areas ( to force failure while 1890 // the implementations for each method are being updated ) 1891 if ( m_Areas->getCount() > 1 ) 1892 { 1893 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); 1894 return xRange->getText(); 1895 } 1896 uno::Reference< text::XTextRange > xTextRange(mxRange->getCellByPosition(0,0), uno::UNO_QUERY_THROW ); 1897 return xTextRange->getString(); 1898 } 1899 1900 uno::Reference< excel::XRange > 1901 ScVbaRange::Offset( const ::uno::Any &nRowOff, const uno::Any &nColOff ) 1902 { 1903 SCROW nRowOffset = 0; 1904 SCCOL nColOffset = 0; 1905 bool bIsRowOffset = ( nRowOff >>= nRowOffset ); 1906 bool bIsColumnOffset = ( nColOff >>= nColOffset ); 1907 ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); 1908 1909 ScRangeList aCellRanges = pUnoRangesBase->GetRangeList(); 1910 1911 for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i ) 1912 { 1913 ScRange & rRange = aCellRanges[ i ]; 1914 if ( bIsColumnOffset ) 1915 { 1916 rRange.aStart.SetCol( rRange.aStart.Col() + nColOffset ); 1917 rRange.aEnd.SetCol( rRange.aEnd.Col() + nColOffset ); 1918 } 1919 if ( bIsRowOffset ) 1920 { 1921 rRange.aStart.SetRow( rRange.aStart.Row() + nRowOffset ); 1922 rRange.aEnd.SetRow( rRange.aEnd.Row() + nRowOffset ); 1923 } 1924 } 1925 1926 if ( aCellRanges.size() > 1 ) // Multi-Area 1927 { 1928 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pUnoRangesBase->GetDocShell(), aCellRanges ) ); 1929 return new ScVbaRange( mxParent, mxContext, xRanges ); 1930 } 1931 // normal range 1932 const ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( aCellRanges)); 1933 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange)); 1934 return new ScVbaRange( mxParent, mxContext, xRange ); 1935 } 1936 1937 uno::Reference< excel::XRange > 1938 ScVbaRange::CurrentRegion() 1939 { 1940 // #TODO code within the test below "if ( m_Areas... " can be removed 1941 // Test is performed only because m_xRange is NOT set to be 1942 // the first range in m_Areas ( to force failure while 1943 // the implementations for each method are being updated ) 1944 if ( m_Areas->getCount() > 1 ) 1945 { 1946 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); 1947 return xRange->CurrentRegion(); 1948 } 1949 1950 RangeHelper helper( mxRange ); 1951 uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = 1952 helper.getSheetCellCursor(); 1953 xSheetCellCursor->collapseToCurrentRegion(); 1954 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW); 1955 return RangeHelper::createRangeFromRange( mxParent, mxContext, helper.getCellRangeFromSheet(), xCellRangeAddressable ); 1956 } 1957 1958 uno::Reference< excel::XRange > 1959 ScVbaRange::CurrentArray() 1960 { 1961 // #TODO code within the test below "if ( m_Areas... " can be removed 1962 // Test is performed only because m_xRange is NOT set to be 1963 // the first range in m_Areas ( to force failure while 1964 // the implementations for each method are being updated ) 1965 if ( m_Areas->getCount() > 1 ) 1966 { 1967 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); 1968 return xRange->CurrentArray(); 1969 } 1970 RangeHelper helper( mxRange ); 1971 uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = 1972 helper.getSheetCellCursor(); 1973 xSheetCellCursor->collapseToCurrentArray(); 1974 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW); 1975 return RangeHelper::createRangeFromRange( mxParent, mxContext, helper.getCellRangeFromSheet(), xCellRangeAddressable ); 1976 } 1977 1978 uno::Any 1979 ScVbaRange::getFormulaArray() 1980 { 1981 // #TODO code within the test below "if ( m_Areas... " can be removed 1982 // Test is performed only because m_xRange is NOT set to be 1983 // the first range in m_Areas ( to force failure while 1984 // the implementations for each method are being updated ) 1985 if ( m_Areas->getCount() > 1 ) 1986 { 1987 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); 1988 return xRange->getFormulaArray(); 1989 } 1990 1991 // return a formula if there is one or else an array 1992 // still not sure when the return as array code should run 1993 // ( I think it is if there is more than one formula ) at least 1994 // that is what the doc says ( but I am not even sure how to detect that ) 1995 // for the moment any tests we have pass 1996 uno::Reference< sheet::XArrayFormulaRange> xFormulaArray( mxRange, uno::UNO_QUERY_THROW ); 1997 if ( !xFormulaArray->getArrayFormula().isEmpty() ) 1998 return uno::Any( xFormulaArray->getArrayFormula() ); 1999 2000 uno::Reference< sheet::XCellRangeFormula> xCellRangeFormula( mxRange, uno::UNO_QUERY_THROW ); 2001 const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( mxContext ); 2002 uno::Any aSingleValueOrMatrix; 2003 // When dealing with a single element ( embedded in the sequence of sequence ) unwrap and return 2004 // that value 2005 uno::Sequence< uno::Sequence<OUString> > aTmpSeq = xCellRangeFormula->getFormulaArray(); 2006 if ( aTmpSeq.getLength() == 1 ) 2007 { 2008 if ( aTmpSeq[ 0 ].getLength() == 1 ) 2009 aSingleValueOrMatrix <<= aTmpSeq[ 0 ][ 0 ]; 2010 } 2011 else 2012 aSingleValueOrMatrix = xConverter->convertTo( uno::Any( aTmpSeq ) , cppu::UnoType<uno::Sequence< uno::Sequence< uno::Any > >>::get() ) ; 2013 return aSingleValueOrMatrix; 2014 } 2015 2016 void 2017 ScVbaRange::setFormulaArray(const uno::Any& rFormula) 2018 { 2019 // #TODO code within the test below "if ( m_Areas... " can be removed 2020 // Test is performed only because m_xRange is NOT set to be 2021 // the first range in m_Areas ( to force failure while 2022 // the implementations for each method are being updated ) 2023 if ( m_Areas->getCount() > 1 ) 2024 { 2025 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); 2026 return xRange->setFormulaArray( rFormula ); 2027 } 2028 // #TODO need to distinguish between getFormula and getFormulaArray e.g. (R1C1) 2029 // but for the moment it's just easier to treat them the same for setting 2030 // seems 2031 uno::Reference< lang::XMultiServiceFactory > xModelFactory( getUnoModel(), uno::UNO_QUERY_THROW ); 2032 uno::Reference< sheet::XFormulaParser > xParser( xModelFactory->createInstance( "com.sun.star.sheet.FormulaParser" ), uno::UNO_QUERY_THROW ); 2033 uno::Reference< sheet::XCellRangeAddressable > xSource( mxRange, uno::UNO_QUERY_THROW); 2034 2035 table::CellRangeAddress aRangeAddress = xSource->getRangeAddress(); 2036 // #TODO check if api orders the address 2037 // e.g. do we need to order the RangeAddress to get the topleft ( or can we assume it 2038 // is in the correct order ) 2039 table::CellAddress aAddress; 2040 aAddress.Sheet = aRangeAddress.Sheet; 2041 aAddress.Column = aRangeAddress.StartColumn; 2042 aAddress.Row = aRangeAddress.StartRow; 2043 OUString sFormula; 2044 rFormula >>= sFormula; 2045 uno::Sequence<sheet::FormulaToken> aTokens = xParser->parseFormula( sFormula, aAddress ); 2046 ScTokenArray aTokenArray(getScDocument()); 2047 (void)ScTokenConversion::ConvertToTokenArray( getScDocument(), aTokenArray, aTokens ); 2048 2049 getScDocShell()->GetDocFunc().EnterMatrix( getScRangeList()[0], nullptr, &aTokenArray, OUString(), true, true, OUString(), formula::FormulaGrammar::GRAM_API ); 2050 } 2051 2052 OUString 2053 ScVbaRange::Characters(const uno::Any& Start, const uno::Any& Length) 2054 { 2055 // #TODO code within the test below "if ( m_Areas... " can be removed 2056 // Test is performed only because m_xRange is NOT set to be 2057 // the first range in m_Areas ( to force failure while 2058 // the implementations for each method are being updated ) 2059 if ( m_Areas->getCount() > 1 ) 2060 { 2061 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); 2062 return xRange->Characters( Start, Length ); 2063 } 2064 2065 tools::Long nIndex = 0, nCount = 0; 2066 OUString rString; 2067 uno::Reference< text::XTextRange > xTextRange(mxRange, ::uno::UNO_QUERY_THROW ); 2068 rString = xTextRange->getString(); 2069 if( !( Start >>= nIndex ) && !( Length >>= nCount ) ) 2070 return rString; 2071 if(!( Start >>= nIndex ) ) 2072 nIndex = 1; 2073 if(!( Length >>= nCount ) ) 2074 nIndex = rString.getLength(); 2075 return rString.copy( --nIndex, nCount ); // Zero value indexing 2076 } 2077 2078 OUString 2079 ScVbaRange::Address( const uno::Any& RowAbsolute, const uno::Any& ColumnAbsolute, const uno::Any& ReferenceStyle, const uno::Any& External, const uno::Any& RelativeTo ) 2080 { 2081 if ( m_Areas->getCount() > 1 ) 2082 { 2083 // Multi-Area Range 2084 OUStringBuffer sAddress; 2085 uno::Reference< XCollection > xCollection( m_Areas, uno::UNO_SET_THROW ); 2086 uno::Any aExternalCopy = External; 2087 for ( sal_Int32 index = 1; index <= xCollection->getCount(); ++index ) 2088 { 2089 uno::Reference< excel::XRange > xRange( xCollection->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW ); 2090 if ( index > 1 ) 2091 { 2092 sAddress.append(","); 2093 // force external to be false 2094 // only first address should have the 2095 // document and sheet specifications 2096 aExternalCopy <<= false; 2097 } 2098 sAddress.append(xRange->Address( RowAbsolute, ColumnAbsolute, ReferenceStyle, aExternalCopy, RelativeTo )); 2099 } 2100 return sAddress.makeStringAndClear(); 2101 2102 } 2103 ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 ); 2104 if ( ReferenceStyle.hasValue() ) 2105 { 2106 sal_Int32 refStyle = excel::XlReferenceStyle::xlA1; 2107 ReferenceStyle >>= refStyle; 2108 if ( refStyle == excel::XlReferenceStyle::xlR1C1 ) 2109 dDetails = ScAddress::Details( formula::FormulaGrammar::CONV_XL_R1C1, 0, 0 ); 2110 } 2111 // default 2112 ScRefFlags nFlags = ScRefFlags::RANGE_ABS; 2113 ScDocShell* pDocShell = getScDocShell(); 2114 ScDocument& rDoc = pDocShell->GetDocument(); 2115 2116 RangeHelper thisRange( mxRange ); 2117 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 2118 ScRange aRange( static_cast< SCCOL >( thisAddress.StartColumn ), static_cast< SCROW >( thisAddress.StartRow ), static_cast< SCTAB >( thisAddress.Sheet ), static_cast< SCCOL >( thisAddress.EndColumn ), static_cast< SCROW >( thisAddress.EndRow ), static_cast< SCTAB >( thisAddress.Sheet ) ); 2119 constexpr ScRefFlags ROW_ABS = ScRefFlags::ROW_ABS | ScRefFlags::ROW2_ABS; 2120 constexpr ScRefFlags COL_ABS = ScRefFlags::COL_ABS | ScRefFlags::COL2_ABS; 2121 2122 if ( RowAbsolute.hasValue() ) 2123 { 2124 bool bVal = true; 2125 RowAbsolute >>= bVal; 2126 if ( !bVal ) 2127 nFlags &= ~ROW_ABS; 2128 } 2129 if ( ColumnAbsolute.hasValue() ) 2130 { 2131 bool bVal = true; 2132 ColumnAbsolute >>= bVal; 2133 if ( !bVal ) 2134 nFlags &= ~COL_ABS; 2135 } 2136 if ( External.hasValue() ) 2137 { 2138 bool bLocal = false; 2139 External >>= bLocal; 2140 if ( bLocal ) 2141 nFlags |= ScRefFlags::TAB_3D | ScRefFlags::FORCE_DOC; 2142 } 2143 if ( RelativeTo.hasValue() ) 2144 { 2145 // #TODO should I throw an error if R1C1 is not set? 2146 2147 table::CellRangeAddress refAddress = getCellRangeAddressForVBARange( RelativeTo, pDocShell ); 2148 dDetails = ScAddress::Details( formula::FormulaGrammar::CONV_XL_R1C1, static_cast< SCROW >( refAddress.StartRow ), static_cast< SCCOL >( refAddress.StartColumn ) ); 2149 } 2150 return aRange.Format(rDoc, nFlags, dDetails); 2151 } 2152 2153 uno::Reference < excel::XFont > 2154 ScVbaRange::Font() 2155 { 2156 uno::Reference< beans::XPropertySet > xProps(mxRange, ::uno::UNO_QUERY ); 2157 ScDocument& rDoc = getScDocument(); 2158 if ( mxRange.is() ) 2159 xProps.set(mxRange, ::uno::UNO_QUERY ); 2160 else if ( mxRanges.is() ) 2161 xProps.set(mxRanges, ::uno::UNO_QUERY ); 2162 2163 ScVbaPalette aPalette( rDoc.GetDocumentShell() ); 2164 ScCellRangeObj* pRangeObj = nullptr; 2165 try 2166 { 2167 pRangeObj = getCellRangeObj(); 2168 } 2169 catch( uno::Exception& ) 2170 { 2171 } 2172 return new ScVbaFont( this, mxContext, aPalette, xProps, pRangeObj ); 2173 } 2174 2175 uno::Reference< excel::XRange > 2176 ScVbaRange::Cells( const uno::Any &nRowIndex, const uno::Any &nColumnIndex ) 2177 { 2178 // #TODO code within the test below "if ( m_Areas... " can be removed 2179 // Test is performed only because m_xRange is NOT set to be 2180 // the first range in m_Areas ( to force failure while 2181 // the implementations for each method are being updated ) 2182 if ( m_Areas->getCount() > 1 ) 2183 { 2184 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); 2185 return xRange->Cells( nRowIndex, nColumnIndex ); 2186 } 2187 2188 // Performance: Use a common helper method for ScVbaRange::Cells and ScVbaWorksheet::Cells, 2189 // instead of creating a new ScVbaRange object in often-called ScVbaWorksheet::Cells 2190 return CellsHelper( getScDocument(), mxParent, mxContext, mxRange, nRowIndex, nColumnIndex ); 2191 } 2192 2193 // static 2194 uno::Reference< excel::XRange > 2195 ScVbaRange::CellsHelper( const ScDocument& rDoc, 2196 const uno::Reference< ov::XHelperInterface >& xParent, 2197 const uno::Reference< uno::XComponentContext >& xContext, 2198 const uno::Reference< css::table::XCellRange >& xRange, 2199 const uno::Any &nRowIndex, const uno::Any &nColumnIndex ) 2200 { 2201 sal_Int32 nRow = 0, nColumn = 0; 2202 2203 bool bIsIndex = nRowIndex.hasValue(); 2204 bool bIsColumnIndex = nColumnIndex.hasValue(); 2205 2206 // Sometimes we might get a float or a double or whatever 2207 // set in the Any, we should convert as appropriate 2208 // #FIXME - perhaps worth turning this into some sort of 2209 // conversion routine e.g. bSuccess = getValueFromAny( nRow, nRowIndex, cppu::UnoType<sal_Int32>::get() ) 2210 if ( nRowIndex.hasValue() && !( nRowIndex >>= nRow ) ) 2211 { 2212 const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( xContext ); 2213 uno::Any aConverted; 2214 try 2215 { 2216 aConverted = xConverter->convertTo( nRowIndex, cppu::UnoType<sal_Int32>::get() ); 2217 bIsIndex = ( aConverted >>= nRow ); 2218 } 2219 catch( uno::Exception& ) {} // silence any errors 2220 } 2221 2222 if ( bIsColumnIndex ) 2223 { 2224 // Column index can be a col address e.g Cells( 1, "B" ) etc. 2225 OUString sCol; 2226 if ( nColumnIndex >>= sCol ) 2227 { 2228 ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 ); 2229 ScRange tmpRange; 2230 ScRefFlags flags = tmpRange.ParseCols( rDoc, sCol, dDetails ); 2231 if ( (flags & ScRefFlags::COL_VALID) == ScRefFlags::ZERO ) 2232 throw uno::RuntimeException(); 2233 nColumn = tmpRange.aStart.Col() + 1; 2234 } 2235 else 2236 { 2237 if ( !( nColumnIndex >>= nColumn ) ) 2238 { 2239 const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( xContext ); 2240 uno::Any aConverted; 2241 try 2242 { 2243 aConverted = xConverter->convertTo( nColumnIndex, cppu::UnoType<sal_Int32>::get() ); 2244 bIsColumnIndex = ( aConverted >>= nColumn ); 2245 } 2246 catch( uno::Exception& ) {} // silence any errors 2247 } 2248 } 2249 } 2250 RangeHelper thisRange( xRange ); 2251 table::CellRangeAddress thisRangeAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 2252 uno::Reference< table::XCellRange > xSheetRange = thisRange.getCellRangeFromSheet(); 2253 if( !bIsIndex && !bIsColumnIndex ) // .Cells 2254 // #FIXME needs proper parent ( Worksheet ) 2255 return uno::Reference< excel::XRange >( new ScVbaRange( xParent, xContext, xRange ) ); 2256 2257 sal_Int32 nIndex = --nRow; 2258 if( bIsIndex && !bIsColumnIndex ) // .Cells(n) 2259 { 2260 uno::Reference< table::XColumnRowRange > xColumnRowRange(xRange, ::uno::UNO_QUERY_THROW); 2261 sal_Int32 nColCount = xColumnRowRange->getColumns()->getCount(); 2262 2263 if ( !nIndex || nIndex < 0 ) 2264 nRow = 0; 2265 else 2266 nRow = nIndex / nColCount; 2267 nColumn = nIndex % nColCount; 2268 } 2269 else 2270 --nColumn; 2271 nRow = nRow + thisRangeAddress.StartRow; 2272 nColumn = nColumn + thisRangeAddress.StartColumn; 2273 return new ScVbaRange( xParent, xContext, xSheetRange->getCellRangeByPosition( nColumn, nRow, nColumn, nRow ) ); 2274 } 2275 2276 void 2277 ScVbaRange::Select() 2278 { 2279 ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); 2280 if ( !pUnoRangesBase ) 2281 throw uno::RuntimeException("Failed to access underlying uno range object" ); 2282 ScDocShell* pShell = pUnoRangesBase->GetDocShell(); 2283 if ( !pShell ) 2284 return; 2285 2286 uno::Reference< frame::XModel > xModel( pShell->GetModel(), uno::UNO_SET_THROW ); 2287 uno::Reference< view::XSelectionSupplier > xSelection( xModel->getCurrentController(), uno::UNO_QUERY_THROW ); 2288 if ( mxRanges.is() ) 2289 xSelection->select( uno::Any( lclExpandToMerged( mxRanges ) ) ); 2290 else 2291 xSelection->select( uno::Any( lclExpandToMerged( mxRange, true ) ) ); 2292 // set focus on document e.g. 2293 // ThisComponent.CurrentController.Frame.getContainerWindow.SetFocus 2294 try 2295 { 2296 uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW ); 2297 uno::Reference< frame::XFrame > xFrame( xController->getFrame(), uno::UNO_SET_THROW ); 2298 uno::Reference< awt::XWindow > xWin( xFrame->getContainerWindow(), uno::UNO_SET_THROW ); 2299 xWin->setFocus(); 2300 } 2301 catch( uno::Exception& ) 2302 { 2303 } 2304 } 2305 2306 static bool cellInRange( const table::CellRangeAddress& rAddr, sal_Int32 nCol, sal_Int32 nRow ) 2307 { 2308 return nCol >= rAddr.StartColumn && nCol <= rAddr.EndColumn && 2309 nRow >= rAddr.StartRow && nRow <= rAddr.EndRow; 2310 } 2311 2312 static void setCursor( SCCOL nCol, SCROW nRow, const uno::Reference< frame::XModel >& xModel, bool bInSel = true ) 2313 { 2314 ScTabViewShell* pShell = excel::getBestViewShell( xModel ); 2315 if ( pShell ) 2316 { 2317 if ( bInSel ) 2318 pShell->SetCursor( nCol, nRow ); 2319 else 2320 pShell->MoveCursorAbs( nCol, nRow, SC_FOLLOW_NONE, false, false, true ); 2321 } 2322 } 2323 2324 void 2325 ScVbaRange::Activate() 2326 { 2327 // get first cell of current range 2328 uno::Reference< table::XCellRange > xCellRange; 2329 if ( mxRanges.is() ) 2330 { 2331 uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); 2332 xCellRange.set( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW ); 2333 } 2334 else 2335 xCellRange.set( mxRange, uno::UNO_SET_THROW ); 2336 2337 RangeHelper thisRange( xCellRange ); 2338 uno::Reference< sheet::XCellRangeAddressable > xThisRangeAddress = thisRange.getCellRangeAddressable(); 2339 table::CellRangeAddress thisRangeAddress = xThisRangeAddress->getRangeAddress(); 2340 uno::Reference< frame::XModel > xModel; 2341 ScDocShell* pShell = getScDocShell(); 2342 2343 if ( pShell ) 2344 xModel = pShell->GetModel(); 2345 2346 if ( !xModel.is() ) 2347 throw uno::RuntimeException(); 2348 2349 // get current selection 2350 uno::Reference< sheet::XCellRangeAddressable > xRange( xModel->getCurrentSelection(), ::uno::UNO_QUERY); 2351 2352 uno::Reference< sheet::XSheetCellRanges > xRanges( xModel->getCurrentSelection(), ::uno::UNO_QUERY); 2353 2354 if ( xRanges.is() ) 2355 { 2356 const uno::Sequence< table::CellRangeAddress > nAddrs = xRanges->getRangeAddresses(); 2357 for ( const auto& rAddr : nAddrs ) 2358 { 2359 if ( cellInRange( rAddr, thisRangeAddress.StartColumn, thisRangeAddress.StartRow ) ) 2360 { 2361 setCursor( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), xModel ); 2362 return; 2363 } 2364 2365 } 2366 } 2367 2368 if ( xRange.is() && cellInRange( xRange->getRangeAddress(), thisRangeAddress.StartColumn, thisRangeAddress.StartRow ) ) 2369 setCursor( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), xModel ); 2370 else 2371 { 2372 // if this range is multi cell select the range other 2373 // wise just position the cell at this single range position 2374 if ( isSingleCellRange() ) 2375 // This top-leftmost cell of this Range is not in the current 2376 // selection so just select this range 2377 setCursor( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), xModel, false ); 2378 else 2379 Select(); 2380 } 2381 2382 } 2383 2384 ScRange ScVbaRange::obtainRangeEvenIfRangeListIsEmpty( const ScRangeList& rCellRanges ) const 2385 { 2386 // XXX It may be that using the current range list was never correct, but 2387 // always the initial sheet range would be instead, history is unclear. 2388 2389 if (!rCellRanges.empty()) 2390 return rCellRanges.front(); 2391 2392 table::CellRangeAddress aRA( lclGetRangeAddress( mxRange )); 2393 return ScRange( aRA.StartColumn, aRA.StartRow, aRA.Sheet, aRA.EndColumn, aRA.EndRow, aRA.Sheet); 2394 } 2395 2396 uno::Reference< excel::XRange > 2397 ScVbaRange::Rows(const uno::Any& aIndex ) 2398 { 2399 if ( aIndex.hasValue() ) 2400 { 2401 ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); 2402 ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( pUnoRangesBase->GetRangeList())); 2403 2404 sal_Int32 nValue = 0; 2405 OUString sAddress; 2406 if( aIndex >>= nValue ) 2407 { 2408 aRange.aStart.SetRow( aRange.aStart.Row() + --nValue ); 2409 aRange.aEnd.SetRow( aRange.aStart.Row() ); 2410 } 2411 else if ( aIndex >>= sAddress ) 2412 { 2413 ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 ); 2414 ScRange tmpRange; 2415 tmpRange.ParseRows( getScDocument(), sAddress, dDetails ); 2416 SCROW nStartRow = tmpRange.aStart.Row(); 2417 SCROW nEndRow = tmpRange.aEnd.Row(); 2418 2419 aRange.aStart.SetRow( aRange.aStart.Row() + nStartRow ); 2420 aRange.aEnd.SetRow( aRange.aStart.Row() + ( nEndRow - nStartRow )); 2421 } 2422 else 2423 throw uno::RuntimeException("Illegal param" ); 2424 2425 if ( aRange.aStart.Row() < 0 || aRange.aEnd.Row() < 0 ) 2426 throw uno::RuntimeException("Internal failure, illegal param" ); 2427 // return a normal range ( even for multi-selection 2428 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange ) ); 2429 return new ScVbaRange( mxParent, mxContext, xRange, true ); 2430 } 2431 // Rows() - no params 2432 if ( m_Areas->getCount() > 1 ) 2433 return new ScVbaRange( mxParent, mxContext, mxRanges, true ); 2434 return new ScVbaRange( mxParent, mxContext, mxRange, true ); 2435 } 2436 2437 uno::Reference< excel::XRange > 2438 ScVbaRange::Columns(const uno::Any& aIndex ) 2439 { 2440 ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); 2441 ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( pUnoRangesBase->GetRangeList())); 2442 2443 if ( aIndex.hasValue() ) 2444 { 2445 OUString sAddress; 2446 sal_Int32 nValue = 0; 2447 if ( aIndex >>= nValue ) 2448 { 2449 aRange.aStart.SetCol( aRange.aStart.Col() + static_cast< SCCOL > ( --nValue ) ); 2450 aRange.aEnd.SetCol( aRange.aStart.Col() ); 2451 } 2452 2453 else if ( aIndex >>= sAddress ) 2454 { 2455 ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 ); 2456 ScRange tmpRange; 2457 tmpRange.ParseCols( getScDocument(), sAddress, dDetails ); 2458 SCCOL nStartCol = tmpRange.aStart.Col(); 2459 SCCOL nEndCol = tmpRange.aEnd.Col(); 2460 2461 aRange.aStart.SetCol( aRange.aStart.Col() + nStartCol ); 2462 aRange.aEnd.SetCol( aRange.aStart.Col() + ( nEndCol - nStartCol )); 2463 } 2464 else 2465 throw uno::RuntimeException("Illegal param" ); 2466 2467 if ( aRange.aStart.Col() < 0 || aRange.aEnd.Col() < 0 ) 2468 throw uno::RuntimeException("Internal failure, illegal param" ); 2469 } 2470 // Columns() - no params 2471 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange ) ); 2472 return new ScVbaRange( mxParent, mxContext, xRange, false, true ); 2473 } 2474 2475 void 2476 ScVbaRange::setMergeCells( const uno::Any& aIsMerged ) 2477 { 2478 bool bMerge = extractBoolFromAny( aIsMerged ); 2479 2480 if( mxRanges.is() ) 2481 { 2482 sal_Int32 nCount = mxRanges->getCount(); 2483 2484 // VBA does nothing (no error) if the own ranges overlap somehow 2485 ::std::vector< table::CellRangeAddress > aList; 2486 for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) 2487 { 2488 uno::Reference< sheet::XCellRangeAddressable > xRangeAddr( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); 2489 table::CellRangeAddress aAddress = xRangeAddr->getRangeAddress(); 2490 if (std::any_of(aList.begin(), aList.end(), 2491 [&aAddress](const table::CellRangeAddress& rAddress) 2492 { return ScUnoConversion::Intersects( rAddress, aAddress ); })) 2493 return; 2494 aList.push_back( aAddress ); 2495 } 2496 2497 // (un)merge every range after it has been extended to intersecting merged ranges from sheet 2498 for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) 2499 { 2500 uno::Reference< table::XCellRange > xRange( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); 2501 lclExpandAndMerge( xRange, bMerge ); 2502 } 2503 return; 2504 } 2505 2506 // otherwise, merge single range 2507 lclExpandAndMerge( mxRange, bMerge ); 2508 } 2509 2510 uno::Any 2511 ScVbaRange::getMergeCells() 2512 { 2513 if( mxRanges.is() ) 2514 { 2515 sal_Int32 nCount = mxRanges->getCount(); 2516 for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) 2517 { 2518 uno::Reference< table::XCellRange > xRange( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); 2519 util::TriState eMerged = lclGetMergedState( xRange ); 2520 /* Excel always returns NULL, if one range of the range list is 2521 partly or completely merged. Even if all ranges are completely 2522 merged, the return value is still NULL. */ 2523 if( eMerged != util::TriState_NO ) 2524 return aNULL(); 2525 } 2526 // no range is merged anyhow, return false 2527 return uno::Any( false ); 2528 } 2529 2530 // otherwise, check single range 2531 switch( lclGetMergedState( mxRange ) ) 2532 { 2533 case util::TriState_YES: return uno::Any( true ); 2534 case util::TriState_NO: return uno::Any( false ); 2535 default: return aNULL(); 2536 } 2537 } 2538 2539 void 2540 ScVbaRange::Copy(const ::uno::Any& Destination) 2541 { 2542 if ( Destination.hasValue() ) 2543 { 2544 // TODO copy with multiple selections should work here too 2545 if ( m_Areas->getCount() > 1 ) 2546 throw uno::RuntimeException("That command cannot be used on multiple selections" ); 2547 uno::Reference< excel::XRange > xRange( Destination, uno::UNO_QUERY_THROW ); 2548 uno::Any aRange = xRange->getCellRange(); 2549 uno::Reference< table::XCellRange > xCellRange; 2550 aRange >>= xCellRange; 2551 uno::Reference< sheet::XSheetCellRange > xSheetCellRange(xCellRange, ::uno::UNO_QUERY_THROW); 2552 uno::Reference< sheet::XSpreadsheet > xSheet = xSheetCellRange->getSpreadsheet(); 2553 uno::Reference< table::XCellRange > xDest( xSheet, uno::UNO_QUERY_THROW ); 2554 uno::Reference< sheet::XCellRangeMovement > xMover( xSheet, uno::UNO_QUERY_THROW); 2555 uno::Reference< sheet::XCellAddressable > xDestination( xDest->getCellByPosition( 2556 xRange->getColumn()-1,xRange->getRow()-1), uno::UNO_QUERY_THROW ); 2557 uno::Reference< sheet::XCellRangeAddressable > xSource( mxRange, uno::UNO_QUERY); 2558 xMover->copyRange( xDestination->getCellAddress(), xSource->getRangeAddress() ); 2559 if ( ScVbaRange* pRange = getImplementation( xRange ) ) 2560 pRange->fireChangeEvent(); 2561 } 2562 else 2563 { 2564 Select(); 2565 excel::implnCopy(getUnoModel()); 2566 } 2567 } 2568 2569 void 2570 ScVbaRange::Cut(const ::uno::Any& Destination) 2571 { 2572 if ( m_Areas->getCount() > 1 ) 2573 throw uno::RuntimeException("That command cannot be used on multiple selections" ); 2574 if (Destination.hasValue()) 2575 { 2576 uno::Reference< excel::XRange > xRange( Destination, uno::UNO_QUERY_THROW ); 2577 uno::Reference< table::XCellRange > xCellRange( xRange->getCellRange(), uno::UNO_QUERY_THROW ); 2578 uno::Reference< sheet::XSheetCellRange > xSheetCellRange(xCellRange, ::uno::UNO_QUERY_THROW ); 2579 uno::Reference< sheet::XSpreadsheet > xSheet = xSheetCellRange->getSpreadsheet(); 2580 uno::Reference< table::XCellRange > xDest( xSheet, uno::UNO_QUERY_THROW ); 2581 uno::Reference< sheet::XCellRangeMovement > xMover( xSheet, uno::UNO_QUERY_THROW); 2582 uno::Reference< sheet::XCellAddressable > xDestination( xDest->getCellByPosition( 2583 xRange->getColumn()-1,xRange->getRow()-1), uno::UNO_QUERY); 2584 uno::Reference< sheet::XCellRangeAddressable > xSource( mxRange, uno::UNO_QUERY); 2585 xMover->moveRange( xDestination->getCellAddress(), xSource->getRangeAddress() ); 2586 } 2587 else 2588 { 2589 uno::Reference< frame::XModel > xModel = getModelFromRange( mxRange ); 2590 Select(); 2591 excel::implnCut( xModel ); 2592 } 2593 } 2594 2595 void 2596 ScVbaRange::setNumberFormat( const uno::Any& aFormat ) 2597 { 2598 OUString sFormat; 2599 aFormat >>= sFormat; 2600 if ( m_Areas->getCount() > 1 ) 2601 { 2602 sal_Int32 nItems = m_Areas->getCount(); 2603 for ( sal_Int32 index=1; index <= nItems; ++index ) 2604 { 2605 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); 2606 xRange->setNumberFormat( aFormat ); 2607 } 2608 return; 2609 } 2610 NumFormatHelper numFormat( mxRange ); 2611 numFormat.setNumberFormat( sFormat ); 2612 } 2613 2614 uno::Any 2615 ScVbaRange::getNumberFormat() 2616 { 2617 2618 if ( m_Areas->getCount() > 1 ) 2619 { 2620 sal_Int32 nItems = m_Areas->getCount(); 2621 uno::Any aResult = aNULL(); 2622 for ( sal_Int32 index=1; index <= nItems; ++index ) 2623 { 2624 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); 2625 // if the numberformat of one area is different to another 2626 // return null 2627 if ( index > 1 ) 2628 if ( aResult != xRange->getNumberFormat() ) 2629 return aNULL(); 2630 aResult = xRange->getNumberFormat(); 2631 if ( aNULL() == aResult ) 2632 return aNULL(); 2633 } 2634 return aResult; 2635 } 2636 NumFormatHelper numFormat( mxRange ); 2637 OUString sFormat = numFormat.getNumberFormatString(); 2638 if ( !sFormat.isEmpty() ) 2639 return uno::Any( sFormat ); 2640 return aNULL(); 2641 } 2642 2643 uno::Reference< excel::XRange > 2644 ScVbaRange::Resize( const uno::Any &RowSize, const uno::Any &ColumnSize ) 2645 { 2646 tools::Long nRowSize = 0, nColumnSize = 0; 2647 bool bIsRowChanged = ( RowSize >>= nRowSize ), bIsColumnChanged = ( ColumnSize >>= nColumnSize ); 2648 uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, ::uno::UNO_QUERY_THROW); 2649 uno::Reference< sheet::XSheetCellRange > xSheetRange(mxRange, ::uno::UNO_QUERY_THROW); 2650 uno::Reference< sheet::XSheetCellCursor > xCursor( xSheetRange->getSpreadsheet()->createCursorByRange(xSheetRange), ::uno::UNO_SET_THROW ); 2651 2652 if( !bIsRowChanged ) 2653 nRowSize = xColumnRowRange->getRows()->getCount(); 2654 if( !bIsColumnChanged ) 2655 nColumnSize = xColumnRowRange->getColumns()->getCount(); 2656 2657 xCursor->collapseToSize( nColumnSize, nRowSize ); 2658 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xCursor, ::uno::UNO_QUERY_THROW ); 2659 uno::Reference< table::XCellRange > xRange( xSheetRange->getSpreadsheet(), ::uno::UNO_QUERY_THROW ); 2660 return new ScVbaRange( mxParent, mxContext,xRange->getCellRangeByPosition( 2661 xCellRangeAddressable->getRangeAddress().StartColumn, 2662 xCellRangeAddressable->getRangeAddress().StartRow, 2663 xCellRangeAddressable->getRangeAddress().EndColumn, 2664 xCellRangeAddressable->getRangeAddress().EndRow ) ); 2665 } 2666 2667 void 2668 ScVbaRange::setWrapText( const uno::Any& aIsWrapped ) 2669 { 2670 if ( m_Areas->getCount() > 1 ) 2671 { 2672 sal_Int32 nItems = m_Areas->getCount(); 2673 for ( sal_Int32 index=1; index <= nItems; ++index ) 2674 { 2675 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); 2676 xRange->setWrapText( aIsWrapped ); 2677 } 2678 return; 2679 } 2680 2681 uno::Reference< beans::XPropertySet > xProps(mxRange, ::uno::UNO_QUERY_THROW ); 2682 bool bIsWrapped = extractBoolFromAny( aIsWrapped ); 2683 xProps->setPropertyValue( "IsTextWrapped", uno::Any( bIsWrapped ) ); 2684 } 2685 2686 uno::Any 2687 ScVbaRange::getWrapText() 2688 { 2689 if ( m_Areas->getCount() > 1 ) 2690 { 2691 sal_Int32 nItems = m_Areas->getCount(); 2692 uno::Any aResult; 2693 for ( sal_Int32 index=1; index <= nItems; ++index ) 2694 { 2695 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); 2696 if ( index > 1 ) 2697 if ( aResult != xRange->getWrapText() ) 2698 return aNULL(); 2699 aResult = xRange->getWrapText(); 2700 } 2701 return aResult; 2702 } 2703 2704 SfxItemSet* pDataSet = getCurrentDataSet(); 2705 2706 SfxItemState eState = pDataSet->GetItemState( ATTR_LINEBREAK); 2707 if ( eState == SfxItemState::DONTCARE ) 2708 return aNULL(); 2709 2710 uno::Reference< beans::XPropertySet > xProps(mxRange, ::uno::UNO_QUERY_THROW ); 2711 uno::Any aValue = xProps->getPropertyValue( "IsTextWrapped" ); 2712 return aValue; 2713 } 2714 2715 uno::Reference< excel::XInterior > ScVbaRange::Interior( ) 2716 { 2717 uno::Reference< beans::XPropertySet > xProps( mxRange, uno::UNO_QUERY_THROW ); 2718 return new ScVbaInterior ( this, mxContext, xProps, &getScDocument() ); 2719 } 2720 uno::Reference< excel::XRange > 2721 ScVbaRange::Range( const uno::Any &Cell1, const uno::Any &Cell2 ) 2722 { 2723 return Range( Cell1, Cell2, false ); 2724 } 2725 uno::Reference< excel::XRange > 2726 ScVbaRange::Range( const uno::Any &Cell1, const uno::Any &Cell2, bool bForceUseInpuRangeTab ) 2727 2728 { 2729 uno::Reference< table::XCellRange > xCellRange = mxRange; 2730 2731 if ( m_Areas->getCount() > 1 ) 2732 { 2733 uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); 2734 xCellRange.set( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW ); 2735 } 2736 else 2737 xCellRange.set( mxRange ); 2738 2739 RangeHelper thisRange( xCellRange ); 2740 uno::Reference< table::XCellRange > xRanges = thisRange.getCellRangeFromSheet(); 2741 uno::Reference< sheet::XCellRangeAddressable > xAddressable( xRanges, uno::UNO_QUERY_THROW ); 2742 2743 uno::Reference< table::XCellRange > xReferrer = 2744 xRanges->getCellRangeByPosition( getColumn()-1, getRow()-1, 2745 xAddressable->getRangeAddress().EndColumn, 2746 xAddressable->getRangeAddress().EndRow ); 2747 // xAddressable now for this range 2748 xAddressable.set( xReferrer, uno::UNO_QUERY_THROW ); 2749 2750 if( !Cell1.hasValue() ) 2751 throw uno::RuntimeException( "Invalid Argument" ); 2752 2753 table::CellRangeAddress parentRangeAddress = xAddressable->getRangeAddress(); 2754 2755 ScRange aRange; 2756 // Cell1 defined only 2757 if ( !Cell2.hasValue() ) 2758 { 2759 OUString sName; 2760 Cell1 >>= sName; 2761 RangeHelper referRange( xReferrer ); 2762 table::CellRangeAddress referAddress = referRange.getCellRangeAddressable()->getRangeAddress(); 2763 return getRangeForName( mxContext, sName, getScDocShell(), referAddress ); 2764 2765 } 2766 else 2767 { 2768 table::CellRangeAddress cell1, cell2; 2769 cell1 = getCellRangeAddressForVBARange( Cell1, getScDocShell() ); 2770 // Cell1 & Cell2 defined 2771 // Excel seems to combine the range as the range defined by 2772 // the combination of Cell1 & Cell2 2773 2774 cell2 = getCellRangeAddressForVBARange( Cell2, getScDocShell() ); 2775 2776 table::CellRangeAddress resultAddress; 2777 resultAddress.StartColumn = ( cell1.StartColumn < cell2.StartColumn ) ? cell1.StartColumn : cell2.StartColumn; 2778 resultAddress.StartRow = ( cell1.StartRow < cell2.StartRow ) ? cell1.StartRow : cell2.StartRow; 2779 resultAddress.EndColumn = std::max( cell1.EndColumn, cell2.EndColumn ); 2780 resultAddress.EndRow = std::max( cell1.EndRow, cell2.EndRow ); 2781 if ( bForceUseInpuRangeTab ) 2782 { 2783 // this is a call from Application.Range( x,y ) 2784 // it's possible for x or y to specify a different sheet from 2785 // the current or active on ( but they must be the same ) 2786 if ( cell1.Sheet != cell2.Sheet ) 2787 throw uno::RuntimeException(); 2788 parentRangeAddress.Sheet = cell1.Sheet; 2789 } 2790 else 2791 { 2792 // this is not a call from Application.Range( x,y ) 2793 // if a different sheet from this range is specified it's 2794 // an error 2795 if ( parentRangeAddress.Sheet != cell1.Sheet 2796 || parentRangeAddress.Sheet != cell2.Sheet 2797 ) 2798 throw uno::RuntimeException(); 2799 2800 } 2801 ScUnoConversion::FillScRange( aRange, resultAddress ); 2802 } 2803 ScRange parentAddress; 2804 ScUnoConversion::FillScRange( parentAddress, parentRangeAddress); 2805 if ( aRange.aStart.Col() >= 0 && aRange.aStart.Row() >= 0 && aRange.aEnd.Col() >= 0 && aRange.aEnd.Row() >= 0 ) 2806 { 2807 sal_Int32 nStartX = parentAddress.aStart.Col() + aRange.aStart.Col(); 2808 sal_Int32 nStartY = parentAddress.aStart.Row() + aRange.aStart.Row(); 2809 sal_Int32 nEndX = parentAddress.aStart.Col() + aRange.aEnd.Col(); 2810 sal_Int32 nEndY = parentAddress.aStart.Row() + aRange.aEnd.Row(); 2811 2812 if ( nStartX <= nEndX && nEndX <= parentAddress.aEnd.Col() && 2813 nStartY <= nEndY && nEndY <= parentAddress.aEnd.Row() ) 2814 { 2815 ScRange aNew( static_cast<SCCOL>(nStartX), static_cast<SCROW>(nStartY), parentAddress.aStart.Tab(), 2816 static_cast<SCCOL>(nEndX), static_cast<SCROW>(nEndY), parentAddress.aEnd.Tab() ); 2817 xCellRange = new ScCellRangeObj( getScDocShell(), aNew ); 2818 } 2819 } 2820 2821 return new ScVbaRange( mxParent, mxContext, xCellRange ); 2822 2823 } 2824 2825 // Allow access to underlying openoffice uno api ( useful for debugging 2826 // with openoffice basic ) 2827 uno::Any SAL_CALL ScVbaRange::getCellRange( ) 2828 { 2829 uno::Any aAny; 2830 if ( mxRanges.is() ) 2831 aAny <<= mxRanges; 2832 else if ( mxRange.is() ) 2833 aAny <<= mxRange; 2834 return aAny; 2835 } 2836 2837 uno::Any ScVbaRange::getCellRange( const uno::Reference< excel::XRange >& rxRange ) 2838 { 2839 if( ScVbaRange* pVbaRange = getImplementation( rxRange ) ) 2840 return pVbaRange->getCellRange(); 2841 throw uno::RuntimeException(); 2842 } 2843 2844 static InsertDeleteFlags getPasteFlags (sal_Int32 Paste) 2845 { 2846 InsertDeleteFlags nFlags = InsertDeleteFlags::NONE; 2847 switch (Paste) { 2848 case excel::XlPasteType::xlPasteComments: 2849 nFlags = InsertDeleteFlags::NOTE;break; 2850 case excel::XlPasteType::xlPasteFormats: 2851 nFlags = InsertDeleteFlags::ATTRIB;break; 2852 case excel::XlPasteType::xlPasteFormulas: 2853 nFlags = InsertDeleteFlags::FORMULA;break; 2854 case excel::XlPasteType::xlPasteFormulasAndNumberFormats : 2855 case excel::XlPasteType::xlPasteValues: 2856 nFlags = ( InsertDeleteFlags::VALUE | InsertDeleteFlags::DATETIME | InsertDeleteFlags::STRING | InsertDeleteFlags::SPECIAL_BOOLEAN ); break; 2857 case excel::XlPasteType::xlPasteValuesAndNumberFormats: 2858 nFlags = InsertDeleteFlags::VALUE | InsertDeleteFlags::ATTRIB; break; 2859 case excel::XlPasteType::xlPasteColumnWidths: 2860 case excel::XlPasteType::xlPasteValidation: 2861 nFlags = InsertDeleteFlags::NONE;break; 2862 case excel::XlPasteType::xlPasteAll: 2863 case excel::XlPasteType::xlPasteAllExceptBorders: 2864 default: 2865 nFlags = InsertDeleteFlags::ALL;break; 2866 } 2867 return nFlags; 2868 } 2869 2870 static ScPasteFunc 2871 getPasteFormulaBits( sal_Int32 Operation) 2872 { 2873 ScPasteFunc nFormulaBits = ScPasteFunc::NONE; 2874 switch (Operation) 2875 { 2876 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationAdd: 2877 nFormulaBits = ScPasteFunc::ADD; break; 2878 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationSubtract: 2879 nFormulaBits = ScPasteFunc::SUB;break; 2880 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationMultiply: 2881 nFormulaBits = ScPasteFunc::MUL;break; 2882 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationDivide: 2883 nFormulaBits = ScPasteFunc::DIV;break; 2884 2885 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationNone: 2886 default: 2887 nFormulaBits = ScPasteFunc::NONE; break; 2888 } 2889 2890 return nFormulaBits; 2891 } 2892 void SAL_CALL 2893 ScVbaRange::PasteSpecial( const uno::Any& Paste, const uno::Any& Operation, const uno::Any& SkipBlanks, const uno::Any& Transpose ) 2894 { 2895 if ( m_Areas->getCount() > 1 ) 2896 throw uno::RuntimeException("That command cannot be used on multiple selections" ); 2897 ScDocShell* pShell = getScDocShell(); 2898 2899 if (!pShell) 2900 throw uno::RuntimeException("That command cannot be used with no ScDocShell" ); 2901 2902 uno::Reference< frame::XModel > xModel(pShell->GetModel(), uno::UNO_SET_THROW); 2903 uno::Reference< view::XSelectionSupplier > xSelection( xModel->getCurrentController(), uno::UNO_QUERY_THROW ); 2904 // select this range 2905 xSelection->select( uno::Any( mxRange ) ); 2906 // set up defaults 2907 sal_Int32 nPaste = excel::XlPasteType::xlPasteAll; 2908 sal_Int32 nOperation = excel::XlPasteSpecialOperation::xlPasteSpecialOperationNone; 2909 bool bTranspose = false; 2910 bool bSkipBlanks = false; 2911 2912 if ( Paste.hasValue() ) 2913 Paste >>= nPaste; 2914 if ( Operation.hasValue() ) 2915 Operation >>= nOperation; 2916 if ( SkipBlanks.hasValue() ) 2917 SkipBlanks >>= bSkipBlanks; 2918 if ( Transpose.hasValue() ) 2919 Transpose >>= bTranspose; 2920 2921 InsertDeleteFlags nFlags = getPasteFlags(nPaste); 2922 ScPasteFunc nFormulaBits = getPasteFormulaBits(nOperation); 2923 2924 excel::implnPasteSpecial(xModel, nFlags, nFormulaBits, bSkipBlanks, bTranspose); 2925 } 2926 2927 uno::Reference< excel::XRange > 2928 ScVbaRange::getEntireColumnOrRow( bool bColumn ) 2929 { 2930 ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); 2931 // copy the range list 2932 ScRangeList aCellRanges = pUnoRangesBase->GetRangeList(); 2933 ScDocument& rDoc = getScDocument(); 2934 2935 for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i ) 2936 { 2937 ScRange & rRange = aCellRanges[ i ]; 2938 if ( bColumn ) 2939 { 2940 rRange.aStart.SetRow( 0 ); 2941 rRange.aEnd.SetRow( rDoc.MaxRow() ); 2942 } 2943 else 2944 { 2945 rRange.aStart.SetCol( 0 ); 2946 rRange.aEnd.SetCol( rDoc.MaxCol() ); 2947 } 2948 } 2949 if ( aCellRanges.size() > 1 ) // Multi-Area 2950 { 2951 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pUnoRangesBase->GetDocShell(), aCellRanges ) ); 2952 2953 return new ScVbaRange( mxParent, mxContext, xRanges, !bColumn, bColumn ); 2954 } 2955 const ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( aCellRanges)); 2956 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange)); 2957 return new ScVbaRange( mxParent, mxContext, xRange, !bColumn, bColumn ); 2958 } 2959 2960 uno::Reference< excel::XRange > SAL_CALL 2961 ScVbaRange::getEntireRow() 2962 { 2963 return getEntireColumnOrRow(false); 2964 } 2965 2966 uno::Reference< excel::XRange > SAL_CALL 2967 ScVbaRange::getEntireColumn() 2968 { 2969 return getEntireColumnOrRow(true); 2970 } 2971 2972 uno::Reference< excel::XComment > SAL_CALL 2973 ScVbaRange::AddComment( const uno::Any& Text ) 2974 { 2975 // if there is already a comment in the top-left cell then throw 2976 if( getComment().is() ) 2977 throw uno::RuntimeException(); 2978 2979 // workaround: Excel allows to create empty comment, Calc does not 2980 OUString aNoteText; 2981 if( Text.hasValue() && !(Text >>= aNoteText) ) 2982 throw uno::RuntimeException(); 2983 if( aNoteText.isEmpty() ) 2984 aNoteText = " "; 2985 2986 // try to create a new annotation 2987 table::CellRangeAddress aRangePos = lclGetRangeAddress( mxRange ); 2988 table::CellAddress aNotePos( aRangePos.Sheet, aRangePos.StartColumn, aRangePos.StartRow ); 2989 uno::Reference< sheet::XSheetCellRange > xCellRange( mxRange, uno::UNO_QUERY_THROW ); 2990 uno::Reference< sheet::XSheetAnnotationsSupplier > xAnnosSupp( xCellRange->getSpreadsheet(), uno::UNO_QUERY_THROW ); 2991 uno::Reference< sheet::XSheetAnnotations > xAnnos( xAnnosSupp->getAnnotations(), uno::UNO_SET_THROW ); 2992 xAnnos->insertNew( aNotePos, aNoteText ); 2993 return new ScVbaComment( this, mxContext, getUnoModel(), mxRange ); 2994 } 2995 2996 uno::Reference< excel::XComment > SAL_CALL 2997 ScVbaRange::getComment() 2998 { 2999 // intentional behavior to return a null object if no 3000 // comment defined 3001 uno::Reference< excel::XComment > xComment( new ScVbaComment( this, mxContext, getUnoModel(), mxRange ) ); 3002 if ( xComment->Text( uno::Any(), uno::Any(), uno::Any() ).isEmpty() ) 3003 return nullptr; 3004 return xComment; 3005 3006 } 3007 3008 /// @throws uno::RuntimeException 3009 static uno::Reference< beans::XPropertySet > 3010 getRowOrColumnProps( const uno::Reference< table::XCellRange >& xCellRange, bool bRows ) 3011 { 3012 uno::Reference< table::XColumnRowRange > xColRow( xCellRange, uno::UNO_QUERY_THROW ); 3013 uno::Reference< beans::XPropertySet > xProps; 3014 if ( bRows ) 3015 xProps.set( xColRow->getRows(), uno::UNO_QUERY_THROW ); 3016 else 3017 xProps.set( xColRow->getColumns(), uno::UNO_QUERY_THROW ); 3018 return xProps; 3019 } 3020 3021 uno::Any SAL_CALL 3022 ScVbaRange::getHidden() 3023 { 3024 // if multi-area result is the result of the 3025 // first area 3026 if ( m_Areas->getCount() > 1 ) 3027 { 3028 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(sal_Int32(1)), uno::Any() ), uno::UNO_QUERY_THROW ); 3029 return xRange->getHidden(); 3030 } 3031 bool bIsVisible = false; 3032 try 3033 { 3034 uno::Reference< beans::XPropertySet > xProps = getRowOrColumnProps( mxRange, mbIsRows ); 3035 if ( !( xProps->getPropertyValue( ISVISIBLE ) >>= bIsVisible ) ) 3036 throw uno::RuntimeException("Failed to get IsVisible property" ); 3037 } 3038 catch( const uno::Exception& e ) 3039 { 3040 css::uno::Any anyEx = cppu::getCaughtException(); 3041 throw css::lang::WrappedTargetRuntimeException( e.Message, 3042 nullptr, anyEx ); 3043 } 3044 return uno::Any( !bIsVisible ); 3045 } 3046 3047 void SAL_CALL 3048 ScVbaRange::setHidden( const uno::Any& _hidden ) 3049 { 3050 if ( m_Areas->getCount() > 1 ) 3051 { 3052 sal_Int32 nItems = m_Areas->getCount(); 3053 for ( sal_Int32 index=1; index <= nItems; ++index ) 3054 { 3055 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); 3056 xRange->setHidden( _hidden ); 3057 } 3058 return; 3059 } 3060 3061 bool bHidden = extractBoolFromAny( _hidden ); 3062 try 3063 { 3064 uno::Reference< beans::XPropertySet > xProps = getRowOrColumnProps( mxRange, mbIsRows ); 3065 xProps->setPropertyValue( ISVISIBLE, uno::Any( !bHidden ) ); 3066 } 3067 catch( const uno::Exception& e ) 3068 { 3069 css::uno::Any anyEx = cppu::getCaughtException(); 3070 throw css::lang::WrappedTargetRuntimeException( e.Message, 3071 nullptr, anyEx ); 3072 } 3073 } 3074 3075 sal_Bool SAL_CALL 3076 ScVbaRange::Replace( const OUString& What, const OUString& Replacement, const uno::Any& LookAt, const uno::Any& SearchOrder, const uno::Any& MatchCase, const uno::Any& MatchByte, const uno::Any& SearchFormat, const uno::Any& ReplaceFormat ) 3077 { 3078 if ( m_Areas->getCount() > 1 ) 3079 { 3080 for ( sal_Int32 index = 1; index <= m_Areas->getCount(); ++index ) 3081 { 3082 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW ); 3083 xRange->Replace( What, Replacement, LookAt, SearchOrder, MatchCase, MatchByte, SearchFormat, ReplaceFormat ); 3084 } 3085 return true; // seems to return true always ( or at least I haven't found the trick of 3086 } 3087 3088 // sanity check required params 3089 if ( What.isEmpty() ) 3090 throw uno::RuntimeException("Range::Replace, missing params" ); 3091 OUString sWhat = VBAToRegexp( What); 3092 // #TODO #FIXME SearchFormat & ReplacesFormat are not processed 3093 // What do we do about MatchByte... we don't seem to support that 3094 const SvxSearchItem& globalSearchOptions = ScGlobal::GetSearchItem(); 3095 SvxSearchItem newOptions( globalSearchOptions ); 3096 3097 uno::Reference< util::XReplaceable > xReplace( mxRange, uno::UNO_QUERY ); 3098 if ( xReplace.is() ) 3099 { 3100 uno::Reference< util::XReplaceDescriptor > xDescriptor = 3101 xReplace->createReplaceDescriptor(); 3102 3103 xDescriptor->setSearchString( sWhat); 3104 xDescriptor->setPropertyValue( SC_UNO_SRCHREGEXP, uno::Any( true ) ); 3105 xDescriptor->setReplaceString( Replacement); 3106 if ( LookAt.hasValue() ) 3107 { 3108 // sets SearchWords ( true is Cell match ) 3109 sal_Int16 nLook = ::comphelper::getINT16( LookAt ); 3110 bool bSearchWords = false; 3111 if ( nLook == excel::XlLookAt::xlPart ) 3112 bSearchWords = false; 3113 else if ( nLook == excel::XlLookAt::xlWhole ) 3114 bSearchWords = true; 3115 else 3116 throw uno::RuntimeException("Range::Replace, illegal value for LookAt" ); 3117 // set global search props ( affects the find dialog 3118 // and of course the defaults for this method 3119 newOptions.SetWordOnly( bSearchWords ); 3120 xDescriptor->setPropertyValue( SC_UNO_SRCHWORDS, uno::Any( bSearchWords ) ); 3121 } 3122 // sets SearchByRow ( true for Rows ) 3123 if ( SearchOrder.hasValue() ) 3124 { 3125 sal_Int16 nSearchOrder = ::comphelper::getINT16( SearchOrder ); 3126 bool bSearchByRow = false; 3127 if ( nSearchOrder == excel::XlSearchOrder::xlByColumns ) 3128 bSearchByRow = false; 3129 else if ( nSearchOrder == excel::XlSearchOrder::xlByRows ) 3130 bSearchByRow = true; 3131 else 3132 throw uno::RuntimeException("Range::Replace, illegal value for SearchOrder" ); 3133 3134 newOptions.SetRowDirection( bSearchByRow ); 3135 xDescriptor->setPropertyValue( SC_UNO_SRCHBYROW, uno::Any( bSearchByRow ) ); 3136 } 3137 if ( MatchCase.hasValue() ) 3138 { 3139 bool bMatchCase = false; 3140 3141 // SearchCaseSensitive 3142 MatchCase >>= bMatchCase; 3143 xDescriptor->setPropertyValue( SC_UNO_SRCHCASE, uno::Any( bMatchCase ) ); 3144 } 3145 3146 ScGlobal::SetSearchItem( newOptions ); 3147 // ignore MatchByte for the moment, it's not supported in 3148 // OOo.org afaik 3149 3150 uno::Reference< container::XIndexAccess > xIndexAccess = xReplace->findAll( xDescriptor ); 3151 xReplace->replaceAll( xDescriptor ); 3152 if ( xIndexAccess.is() && xIndexAccess->getCount() > 0 ) 3153 { 3154 for ( sal_Int32 i = 0; i < xIndexAccess->getCount(); ++i ) 3155 { 3156 uno::Reference< table::XCellRange > xCellRange( xIndexAccess->getByIndex( i ), uno::UNO_QUERY ); 3157 if ( xCellRange.is() ) 3158 { 3159 uno::Reference< excel::XRange > xRange( new ScVbaRange( mxParent, mxContext, xCellRange ) ); 3160 uno::Reference< container::XEnumerationAccess > xEnumAccess( xRange, uno::UNO_QUERY_THROW ); 3161 uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration(); 3162 while ( xEnum->hasMoreElements() ) 3163 { 3164 uno::Reference< excel::XRange > xNextRange( xEnum->nextElement(), uno::UNO_QUERY_THROW ); 3165 ScVbaRange* pRange = dynamic_cast< ScVbaRange * > ( xNextRange.get() ); 3166 if ( pRange ) 3167 pRange->fireChangeEvent(); 3168 } 3169 } 3170 } 3171 } 3172 } 3173 return true; // always 3174 } 3175 3176 uno::Reference< excel::XRange > SAL_CALL 3177 ScVbaRange::Find( const uno::Any& What, const uno::Any& After, const uno::Any& LookIn, const uno::Any& LookAt, const uno::Any& SearchOrder, const uno::Any& SearchDirection, const uno::Any& MatchCase, const uno::Any& /*MatchByte*/, const uno::Any& /*SearchFormat*/ ) 3178 { 3179 // return a Range object that represents the first cell where that information is found. 3180 OUString sWhat; 3181 sal_Int32 nWhat = 0; 3182 double fWhat = 0.0; 3183 3184 // string. 3185 if( What >>= sWhat ) 3186 {} 3187 else if( What >>= nWhat ) 3188 { 3189 sWhat = OUString::number( nWhat ); 3190 } 3191 else if( What >>= fWhat ) 3192 { 3193 sWhat = OUString::number( fWhat ); 3194 } 3195 else 3196 throw uno::RuntimeException("Range::Find, missing search-for-what param" ); 3197 3198 OUString sSearch = VBAToRegexp( sWhat ); 3199 3200 const SvxSearchItem& globalSearchOptions = ScGlobal::GetSearchItem(); 3201 SvxSearchItem newOptions( globalSearchOptions ); 3202 3203 uno::Reference< util::XSearchable > xSearch( mxRange, uno::UNO_QUERY ); 3204 if( xSearch.is() ) 3205 { 3206 uno::Reference< util::XSearchDescriptor > xDescriptor = xSearch->createSearchDescriptor(); 3207 xDescriptor->setSearchString( sSearch ); 3208 xDescriptor->setPropertyValue( SC_UNO_SRCHREGEXP, uno::Any( true ) ); 3209 3210 uno::Reference< excel::XRange > xAfterRange; 3211 uno::Reference< table::XCellRange > xStartCell; 3212 if( After >>= xAfterRange ) 3213 { 3214 // After must be a single cell in the range 3215 if( xAfterRange->getCount() > 1 ) 3216 throw uno::RuntimeException("After must be a single cell." ); 3217 uno::Reference< excel::XRange > xCell( Cells( uno::Any( xAfterRange->getRow() ), uno::Any( xAfterRange->getColumn() ) ), uno::UNO_SET_THROW ); 3218 xStartCell.set( xAfterRange->getCellRange(), uno::UNO_QUERY_THROW ); 3219 } 3220 3221 // LookIn 3222 if( LookIn.hasValue() ) 3223 { 3224 sal_Int32 nLookIn = 0; 3225 if( LookIn >>= nLookIn ) 3226 { 3227 SvxSearchCellType nSearchType; 3228 switch( nLookIn ) 3229 { 3230 case excel::XlFindLookIn::xlComments : 3231 nSearchType = SvxSearchCellType::NOTE; // Notes 3232 break; 3233 case excel::XlFindLookIn::xlFormulas : 3234 nSearchType = SvxSearchCellType::FORMULA; 3235 break; 3236 case excel::XlFindLookIn::xlValues : 3237 nSearchType = SvxSearchCellType::VALUE; 3238 break; 3239 default: 3240 throw uno::RuntimeException("Range::Find, illegal value for LookIn." ); 3241 } 3242 newOptions.SetCellType( nSearchType ); 3243 xDescriptor->setPropertyValue( "SearchType", uno::Any( static_cast<sal_uInt16>(nSearchType) ) ); 3244 } 3245 } 3246 3247 // LookAt 3248 if ( LookAt.hasValue() ) 3249 { 3250 sal_Int16 nLookAt = ::comphelper::getINT16( LookAt ); 3251 bool bSearchWords = false; 3252 if ( nLookAt == excel::XlLookAt::xlPart ) 3253 bSearchWords = false; 3254 else if ( nLookAt == excel::XlLookAt::xlWhole ) 3255 bSearchWords = true; 3256 else 3257 throw uno::RuntimeException("Range::Find, illegal value for LookAt" ); 3258 newOptions.SetWordOnly( bSearchWords ); 3259 xDescriptor->setPropertyValue( SC_UNO_SRCHWORDS, uno::Any( bSearchWords ) ); 3260 } 3261 3262 // SearchOrder 3263 if ( SearchOrder.hasValue() ) 3264 { 3265 sal_Int16 nSearchOrder = ::comphelper::getINT16( SearchOrder ); 3266 bool bSearchByRow = false; 3267 if ( nSearchOrder == excel::XlSearchOrder::xlByColumns ) 3268 bSearchByRow = false; 3269 else if ( nSearchOrder == excel::XlSearchOrder::xlByRows ) 3270 bSearchByRow = true; 3271 else 3272 throw uno::RuntimeException("Range::Find, illegal value for SearchOrder" ); 3273 3274 newOptions.SetRowDirection( bSearchByRow ); 3275 xDescriptor->setPropertyValue( SC_UNO_SRCHBYROW, uno::Any( bSearchByRow ) ); 3276 } 3277 3278 // SearchDirection 3279 if ( SearchDirection.hasValue() ) 3280 { 3281 sal_Int32 nSearchDirection = 0; 3282 if( SearchDirection >>= nSearchDirection ) 3283 { 3284 bool bSearchBackwards = false; 3285 if ( nSearchDirection == excel::XlSearchDirection::xlNext ) 3286 bSearchBackwards = false; 3287 else if( nSearchDirection == excel::XlSearchDirection::xlPrevious ) 3288 bSearchBackwards = true; 3289 else 3290 throw uno::RuntimeException("Range::Find, illegal value for SearchDirection" ); 3291 newOptions.SetBackward( bSearchBackwards ); 3292 xDescriptor->setPropertyValue( "SearchBackwards", uno::Any( bSearchBackwards ) ); 3293 } 3294 } 3295 3296 // MatchCase 3297 bool bMatchCase = false; 3298 if ( MatchCase.hasValue() ) 3299 { 3300 // SearchCaseSensitive 3301 if( !( MatchCase >>= bMatchCase ) ) 3302 throw uno::RuntimeException("Range::Find illegal value for MatchCase" ); 3303 } 3304 xDescriptor->setPropertyValue( SC_UNO_SRCHCASE, uno::Any( bMatchCase ) ); 3305 3306 // MatchByte 3307 // SearchFormat 3308 // ignore 3309 3310 ScGlobal::SetSearchItem( newOptions ); 3311 3312 uno::Reference< uno::XInterface > xInterface = xStartCell.is() ? xSearch->findNext( xStartCell, xDescriptor) : xSearch->findFirst( xDescriptor ); 3313 uno::Reference< table::XCellRange > xCellRange( xInterface, uno::UNO_QUERY ); 3314 // if we are searching from a starting cell and failed to find a match 3315 // then try from the beginning 3316 if ( !xCellRange.is() && xStartCell.is() ) 3317 { 3318 xInterface = xSearch->findFirst( xDescriptor ); 3319 xCellRange.set( xInterface, uno::UNO_QUERY ); 3320 } 3321 if ( xCellRange.is() ) 3322 { 3323 uno::Reference< excel::XRange > xResultRange = new ScVbaRange( mxParent, mxContext, xCellRange ); 3324 if( xResultRange.is() ) 3325 { 3326 return xResultRange; 3327 } 3328 } 3329 3330 } 3331 3332 return uno::Reference< excel::XRange >(); 3333 } 3334 3335 static uno::Reference< table::XCellRange > processKey( const uno::Any& Key, const uno::Reference< uno::XComponentContext >& xContext, ScDocShell* pDocSh ) 3336 { 3337 uno::Reference< excel::XRange > xKeyRange; 3338 if ( Key.getValueType() == cppu::UnoType<excel::XRange>::get() ) 3339 { 3340 xKeyRange.set( Key, uno::UNO_QUERY_THROW ); 3341 } 3342 else if ( Key.getValueType() == ::cppu::UnoType<OUString>::get() ) 3343 3344 { 3345 OUString sRangeName = ::comphelper::getString( Key ); 3346 table::CellRangeAddress aRefAddr; 3347 if ( !pDocSh ) 3348 throw uno::RuntimeException("Range::Sort no docshell to calculate key param" ); 3349 xKeyRange = getRangeForName( xContext, sRangeName, pDocSh, aRefAddr ); 3350 } 3351 else 3352 throw uno::RuntimeException("Range::Sort illegal type value for key param" ); 3353 uno::Reference< table::XCellRange > xKey; 3354 xKey.set( xKeyRange->getCellRange(), uno::UNO_QUERY_THROW ); 3355 return xKey; 3356 } 3357 3358 // helper method for Sort 3359 /// @throws uno::RuntimeException 3360 static sal_Int32 findSortPropertyIndex( const uno::Sequence< beans::PropertyValue >& props, 3361 const OUString& sPropName ) 3362 { 3363 const beans::PropertyValue* pProp = std::find_if(props.begin(), props.end(), 3364 [&sPropName](const beans::PropertyValue& rProp) { return rProp.Name == sPropName; }); 3365 3366 if ( pProp == props.end() ) 3367 throw uno::RuntimeException("Range::Sort unknown sort property" ); 3368 return static_cast<sal_Int32>(std::distance(props.begin(), pProp)); 3369 } 3370 3371 // helper method for Sort 3372 /// @throws uno::RuntimeException 3373 static void updateTableSortField( const uno::Reference< table::XCellRange >& xParentRange, 3374 const uno::Reference< table::XCellRange >& xColRowKey, sal_Int16 nOrder, 3375 table::TableSortField& aTableField, bool bIsSortColumn, bool bMatchCase ) 3376 { 3377 RangeHelper parentRange( xParentRange ); 3378 RangeHelper colRowRange( xColRowKey ); 3379 3380 table::CellRangeAddress parentRangeAddress = parentRange.getCellRangeAddressable()->getRangeAddress(); 3381 3382 table::CellRangeAddress colRowKeyAddress = colRowRange.getCellRangeAddressable()->getRangeAddress(); 3383 3384 // make sure that upper left point of key range is within the 3385 // parent range 3386 if ( 3387 ( bIsSortColumn || colRowKeyAddress.StartColumn < parentRangeAddress.StartColumn || 3388 colRowKeyAddress.StartColumn > parentRangeAddress.EndColumn ) 3389 && 3390 ( !bIsSortColumn || colRowKeyAddress.StartRow < parentRangeAddress.StartRow || 3391 colRowKeyAddress.StartRow > parentRangeAddress.EndRow ) 3392 ) 3393 throw uno::RuntimeException("Illegal Key param" ); 3394 3395 //determine col/row index 3396 if ( bIsSortColumn ) 3397 aTableField.Field = colRowKeyAddress.StartRow - parentRangeAddress.StartRow; 3398 else 3399 aTableField.Field = colRowKeyAddress.StartColumn - parentRangeAddress.StartColumn; 3400 aTableField.IsCaseSensitive = bMatchCase; 3401 3402 if ( nOrder == excel::XlSortOrder::xlAscending ) 3403 aTableField.IsAscending = true; 3404 else 3405 aTableField.IsAscending = false; 3406 3407 3408 } 3409 3410 void SAL_CALL 3411 ScVbaRange::Sort( const uno::Any& Key1, const uno::Any& Order1, const uno::Any& Key2, const uno::Any& /*Type*/, const uno::Any& Order2, const uno::Any& Key3, const uno::Any& Order3, const uno::Any& Header, const uno::Any& OrderCustom, const uno::Any& MatchCase, const uno::Any& Orientation, const uno::Any& SortMethod, const uno::Any& DataOption1, const uno::Any& DataOption2, const uno::Any& DataOption3 ) 3412 { 3413 // #TODO# #FIXME# can we do something with Type 3414 if ( m_Areas->getCount() > 1 ) 3415 throw uno::RuntimeException("That command cannot be used on multiple selections" ); 3416 3417 sal_Int16 nDataOption1 = excel::XlSortDataOption::xlSortNormal; 3418 sal_Int16 nDataOption2 = excel::XlSortDataOption::xlSortNormal; 3419 sal_Int16 nDataOption3 = excel::XlSortDataOption::xlSortNormal; 3420 3421 ScDocument& rDoc = getScDocument(); 3422 3423 RangeHelper thisRange( mxRange ); 3424 table::CellRangeAddress thisRangeAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 3425 ScSortParam aSortParam; 3426 SCTAB nTab = thisRangeAddress.Sheet; 3427 rDoc.GetSortParam( aSortParam, nTab ); 3428 3429 if ( DataOption1.hasValue() ) 3430 DataOption1 >>= nDataOption1; 3431 if ( DataOption2.hasValue() ) 3432 DataOption2 >>= nDataOption2; 3433 if ( DataOption3.hasValue() ) 3434 DataOption3 >>= nDataOption3; 3435 3436 // 1) #TODO #FIXME need to process DataOption[1..3] not used currently 3437 // 2) #TODO #FIXME need to refactor this ( below ) into an IsSingleCell() method 3438 uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY_THROW ); 3439 3440 // set up defaults 3441 3442 sal_Int16 nOrder1 = aSortParam.maKeyState[0].bAscending ? excel::XlSortOrder::xlAscending : excel::XlSortOrder::xlDescending; 3443 sal_Int16 nOrder2 = aSortParam.maKeyState[1].bAscending ? excel::XlSortOrder::xlAscending : excel::XlSortOrder::xlDescending; 3444 sal_Int16 nOrder3 = aSortParam.maKeyState[2].bAscending ? excel::XlSortOrder::xlAscending : excel::XlSortOrder::xlDescending; 3445 3446 sal_Int16 nCustom = aSortParam.nUserIndex; 3447 sal_Int16 nSortMethod = excel::XlSortMethod::xlPinYin; 3448 bool bMatchCase = aSortParam.bCaseSens; 3449 3450 // seems to work opposite to expected, see below 3451 sal_Int16 nOrientation = aSortParam.bByRow ? excel::XlSortOrientation::xlSortColumns : excel::XlSortOrientation::xlSortRows; 3452 3453 if ( Orientation.hasValue() ) 3454 { 3455 // Documentation says xlSortRows is default but that doesn't appear to be 3456 // the case. Also it appears that xlSortColumns is the default which 3457 // strangely enough sorts by Row 3458 nOrientation = ::comphelper::getINT16( Orientation ); 3459 // persist new option to be next calls default 3460 if ( nOrientation == excel::XlSortOrientation::xlSortRows ) 3461 aSortParam.bByRow = false; 3462 else 3463 aSortParam.bByRow = true; 3464 3465 } 3466 3467 bool bIsSortColumns=false; // sort by row 3468 3469 if ( nOrientation == excel::XlSortOrientation::xlSortRows ) 3470 bIsSortColumns = true; 3471 sal_Int16 nHeader = aSortParam.nCompatHeader; 3472 bool bContainsHeader = false; 3473 3474 if ( Header.hasValue() ) 3475 { 3476 nHeader = ::comphelper::getINT16( Header ); 3477 aSortParam.nCompatHeader = nHeader; 3478 } 3479 3480 if ( nHeader == excel::XlYesNoGuess::xlGuess ) 3481 { 3482 bool bHasColHeader = rDoc.HasColHeader( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), static_cast< SCCOL >( thisRangeAddress.EndColumn ), static_cast< SCROW >( thisRangeAddress.EndRow ), static_cast< SCTAB >( thisRangeAddress.Sheet )); 3483 bool bHasRowHeader = rDoc.HasRowHeader( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), static_cast< SCCOL >( thisRangeAddress.EndColumn ), static_cast< SCROW >( thisRangeAddress.EndRow ), static_cast< SCTAB >( thisRangeAddress.Sheet ) ); 3484 if ( bHasColHeader || bHasRowHeader ) 3485 nHeader = excel::XlYesNoGuess::xlYes; 3486 else 3487 nHeader = excel::XlYesNoGuess::xlNo; 3488 aSortParam.nCompatHeader = nHeader; 3489 } 3490 3491 if ( nHeader == excel::XlYesNoGuess::xlYes ) 3492 bContainsHeader = true; 3493 3494 if ( SortMethod.hasValue() ) 3495 { 3496 nSortMethod = ::comphelper::getINT16( SortMethod ); 3497 } 3498 3499 if ( OrderCustom.hasValue() ) 3500 { 3501 OrderCustom >>= nCustom; 3502 --nCustom; // 0-based in OOo 3503 aSortParam.nUserIndex = nCustom; 3504 } 3505 3506 if ( MatchCase.hasValue() ) 3507 { 3508 MatchCase >>= bMatchCase; 3509 aSortParam.bCaseSens = bMatchCase; 3510 } 3511 3512 if ( Order1.hasValue() ) 3513 { 3514 nOrder1 = ::comphelper::getINT16(Order1); 3515 if ( nOrder1 == excel::XlSortOrder::xlAscending ) 3516 aSortParam.maKeyState[0].bAscending = true; 3517 else 3518 aSortParam.maKeyState[0].bAscending = false; 3519 3520 } 3521 if ( Order2.hasValue() ) 3522 { 3523 nOrder2 = ::comphelper::getINT16(Order2); 3524 if ( nOrder2 == excel::XlSortOrder::xlAscending ) 3525 aSortParam.maKeyState[1].bAscending = true; 3526 else 3527 aSortParam.maKeyState[1].bAscending = false; 3528 } 3529 if ( Order3.hasValue() ) 3530 { 3531 nOrder3 = ::comphelper::getINT16(Order3); 3532 if ( nOrder3 == excel::XlSortOrder::xlAscending ) 3533 aSortParam.maKeyState[2].bAscending = true; 3534 else 3535 aSortParam.maKeyState[2].bAscending = false; 3536 } 3537 3538 uno::Reference< table::XCellRange > xKey1; 3539 uno::Reference< table::XCellRange > xKey2; 3540 uno::Reference< table::XCellRange > xKey3; 3541 ScDocShell* pDocShell = getScDocShell(); 3542 xKey1 = processKey( Key1, mxContext, pDocShell ); 3543 if ( !xKey1.is() ) 3544 throw uno::RuntimeException("Range::Sort needs a key1 param" ); 3545 3546 if ( Key2.hasValue() ) 3547 xKey2 = processKey( Key2, mxContext, pDocShell ); 3548 if ( Key3.hasValue() ) 3549 xKey3 = processKey( Key3, mxContext, pDocShell ); 3550 3551 uno::Reference< util::XSortable > xSort( mxRange, uno::UNO_QUERY_THROW ); 3552 uno::Sequence< beans::PropertyValue > sortDescriptor = xSort->createSortDescriptor(); 3553 auto psortDescriptor = sortDescriptor.getArray(); 3554 sal_Int32 nTableSortFieldIndex = findSortPropertyIndex( sortDescriptor, "SortFields" ); 3555 3556 uno::Sequence< table::TableSortField > sTableFields(1); 3557 sal_Int32 nTableIndex = 0; 3558 updateTableSortField( mxRange, xKey1, nOrder1, sTableFields.getArray()[ nTableIndex++ ], bIsSortColumns, bMatchCase ); 3559 3560 if ( xKey2.is() ) 3561 { 3562 sTableFields.realloc( sTableFields.getLength() + 1 ); 3563 updateTableSortField( mxRange, xKey2, nOrder2, sTableFields.getArray()[ nTableIndex++ ], bIsSortColumns, bMatchCase ); 3564 } 3565 if ( xKey3.is() ) 3566 { 3567 sTableFields.realloc( sTableFields.getLength() + 1 ); 3568 updateTableSortField( mxRange, xKey3, nOrder3, sTableFields.getArray()[ nTableIndex++ ], bIsSortColumns, bMatchCase ); 3569 } 3570 psortDescriptor[ nTableSortFieldIndex ].Value <<= sTableFields; 3571 3572 sal_Int32 nIndex = findSortPropertyIndex( sortDescriptor, "IsSortColumns" ); 3573 psortDescriptor[ nIndex ].Value <<= bIsSortColumns; 3574 3575 nIndex = findSortPropertyIndex( sortDescriptor, "ContainsHeader" ); 3576 psortDescriptor[ nIndex ].Value <<= bContainsHeader; 3577 3578 rDoc.SetSortParam( aSortParam, nTab ); 3579 xSort->sort( sortDescriptor ); 3580 3581 // #FIXME #TODO 3582 // The SortMethod param is not processed ( not sure what its all about, need to 3583 (void)nSortMethod; 3584 } 3585 3586 uno::Reference< excel::XRange > SAL_CALL 3587 ScVbaRange::End( ::sal_Int32 Direction ) 3588 { 3589 if ( m_Areas->getCount() > 1 ) 3590 { 3591 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW ); 3592 return xRange->End( Direction ); 3593 } 3594 3595 // #FIXME #TODO 3596 // euch! found my orig implementation sucked, so 3597 // trying this even sucker one (really need to use/expose code in 3598 // around ScTabView::MoveCursorArea(), that's the bit that calculates 3599 // where the cursor should go) 3600 // Main problem with this method is the ultra hacky attempt to preserve 3601 // the ActiveCell, there should be no need to go to these extremes 3602 3603 // Save ActiveSheet/ActiveCell pos (to restore later) 3604 uno::Any aDft; 3605 uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW ); 3606 uno::Reference< excel::XWorksheet > sActiveSheet = xApplication->getActiveSheet(); 3607 OUString sActiveCell = xApplication->getActiveCell()->Address(aDft, aDft, aDft, aDft, aDft ); 3608 3609 // position current cell upper left of this range 3610 Cells( uno::Any( sal_Int32(1) ), uno::Any( sal_Int32(1) ) )->Select(); 3611 3612 uno::Reference< frame::XModel > xModel = getModelFromRange( mxRange ); 3613 3614 SfxViewFrame* pViewFrame = excel::getViewFrame( xModel ); 3615 if ( pViewFrame ) 3616 { 3617 SfxAllItemSet aArgs( SfxGetpApp()->GetPool() ); 3618 // Hoping this will make sure this slot is called 3619 // synchronously 3620 SfxBoolItem sfxAsync( SID_ASYNCHRON, false ); 3621 aArgs.Put( sfxAsync, sfxAsync.Which() ); 3622 SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher(); 3623 3624 sal_uInt16 nSID = 0; 3625 3626 switch( Direction ) 3627 { 3628 case excel::XlDirection::xlDown: 3629 nSID = SID_CURSORBLKDOWN; 3630 break; 3631 case excel::XlDirection::xlUp: 3632 nSID = SID_CURSORBLKUP; 3633 break; 3634 case excel::XlDirection::xlToLeft: 3635 nSID = SID_CURSORBLKLEFT; 3636 break; 3637 case excel::XlDirection::xlToRight: 3638 nSID = SID_CURSORBLKRIGHT; 3639 break; 3640 default: 3641 throw uno::RuntimeException(": Invalid ColumnIndex" ); 3642 } 3643 if ( pDispatcher ) 3644 { 3645 pDispatcher->Execute( nSID, SfxCallMode::SYNCHRON, aArgs ); 3646 } 3647 } 3648 3649 // result is the ActiveCell 3650 OUString sMoved = xApplication->getActiveCell()->Address(aDft, aDft, aDft, aDft, aDft ); 3651 3652 uno::Any aVoid; 3653 uno::Reference< excel::XRange > resultCell; 3654 resultCell.set( xApplication->getActiveSheet()->Range( uno::Any( sMoved ), aVoid ), uno::UNO_SET_THROW ); 3655 3656 // restore old ActiveCell 3657 uno::Reference< excel::XRange > xOldActiveCell( sActiveSheet->Range( uno::Any( sActiveCell ), aVoid ), uno::UNO_SET_THROW ); 3658 xOldActiveCell->Select(); 3659 3660 3661 // return result 3662 return resultCell; 3663 } 3664 3665 bool 3666 ScVbaRange::isSingleCellRange() const 3667 { 3668 uno::Reference< sheet::XCellRangeAddressable > xAddressable( mxRange, uno::UNO_QUERY ); 3669 if ( xAddressable.is() ) 3670 { 3671 table::CellRangeAddress aRangeAddr = xAddressable->getRangeAddress(); 3672 return ( aRangeAddr.EndColumn == aRangeAddr.StartColumn && aRangeAddr.EndRow == aRangeAddr.StartRow ); 3673 } 3674 return false; 3675 } 3676 3677 uno::Reference< excel::XCharacters > SAL_CALL 3678 ScVbaRange::characters( const uno::Any& Start, const uno::Any& Length ) 3679 { 3680 if ( !isSingleCellRange() ) 3681 throw uno::RuntimeException("Can't create Characters property for multicell range " ); 3682 uno::Reference< text::XSimpleText > xSimple(mxRange->getCellByPosition(0,0) , uno::UNO_QUERY_THROW ); 3683 ScDocument& rDoc = getDocumentFromRange(mxRange); 3684 3685 ScVbaPalette aPalette( rDoc.GetDocumentShell() ); 3686 return new ScVbaCharacters( this, mxContext, aPalette, xSimple, Start, Length ); 3687 } 3688 3689 void SAL_CALL 3690 ScVbaRange::Delete( const uno::Any& Shift ) 3691 { 3692 if ( m_Areas->getCount() > 1 ) 3693 { 3694 sal_Int32 nItems = m_Areas->getCount(); 3695 for ( sal_Int32 index=1; index <= nItems; ++index ) 3696 { 3697 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); 3698 xRange->Delete( Shift ); 3699 } 3700 return; 3701 } 3702 sheet::CellDeleteMode mode = sheet::CellDeleteMode_NONE ; 3703 RangeHelper thisRange( mxRange ); 3704 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 3705 if ( Shift.hasValue() ) 3706 { 3707 sal_Int32 nShift = 0; 3708 Shift >>= nShift; 3709 switch ( nShift ) 3710 { 3711 case excel::XlDeleteShiftDirection::xlShiftUp: 3712 mode = sheet::CellDeleteMode_UP; 3713 break; 3714 case excel::XlDeleteShiftDirection::xlShiftToLeft: 3715 mode = sheet::CellDeleteMode_LEFT; 3716 break; 3717 default: 3718 throw uno::RuntimeException("Illegal parameter " ); 3719 } 3720 } 3721 else 3722 { 3723 ScDocument& rDoc = getScDocument(); 3724 bool bFullRow = ( thisAddress.StartColumn == 0 && thisAddress.EndColumn == rDoc.MaxCol() ); 3725 sal_Int32 nCols = thisAddress.EndColumn - thisAddress.StartColumn; 3726 sal_Int32 nRows = thisAddress.EndRow - thisAddress.StartRow; 3727 if ( mbIsRows || bFullRow || ( nCols >= nRows ) ) 3728 mode = sheet::CellDeleteMode_UP; 3729 else 3730 mode = sheet::CellDeleteMode_LEFT; 3731 } 3732 uno::Reference< sheet::XCellRangeMovement > xCellRangeMove( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW ); 3733 xCellRangeMove->removeRange( thisAddress, mode ); 3734 3735 } 3736 3737 //XElementAccess 3738 sal_Bool SAL_CALL 3739 ScVbaRange::hasElements() 3740 { 3741 uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY ); 3742 if ( xColumnRowRange.is() ) 3743 if ( xColumnRowRange->getRows()->getCount() || 3744 xColumnRowRange->getColumns()->getCount() ) 3745 return true; 3746 return false; 3747 } 3748 3749 // XEnumerationAccess 3750 uno::Reference< container::XEnumeration > SAL_CALL 3751 ScVbaRange::createEnumeration() 3752 { 3753 if ( mbIsColumns || mbIsRows ) 3754 { 3755 uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY ); 3756 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW ); 3757 sal_Int32 nElems = 0; 3758 if ( mbIsColumns ) 3759 nElems = xColumnRowRange->getColumns()->getCount(); 3760 else 3761 nElems = xColumnRowRange->getRows()->getCount(); 3762 return new ColumnsRowEnumeration( xRange, nElems ); 3763 3764 } 3765 return new CellsEnumeration( mxParent, mxContext, m_Areas ); 3766 } 3767 3768 OUString SAL_CALL 3769 ScVbaRange::getDefaultMethodName( ) 3770 { 3771 return "Item"; 3772 } 3773 3774 // returns calc internal col. width ( in points ) 3775 double 3776 ScVbaRange::getCalcColWidth(const table::CellRangeAddress& rAddress) 3777 { 3778 ScDocument& rDoc = getScDocument(); 3779 sal_uInt16 nWidth = rDoc.GetOriginalWidth( static_cast< SCCOL >( rAddress.StartColumn ), static_cast< SCTAB >( rAddress.Sheet ) ); 3780 double nPoints = lcl_TwipsToPoints( nWidth ); 3781 nPoints = lcl_Round2DecPlaces( nPoints ); 3782 return nPoints; 3783 } 3784 3785 double 3786 ScVbaRange::getCalcRowHeight(const table::CellRangeAddress& rAddress) 3787 { 3788 ScDocument& rDoc = getDocumentFromRange( mxRange ); 3789 sal_uInt16 nWidth = rDoc.GetOriginalHeight( rAddress.StartRow, rAddress.Sheet ); 3790 double nPoints = lcl_TwipsToPoints( nWidth ); 3791 nPoints = lcl_Round2DecPlaces( nPoints ); 3792 return nPoints; 3793 } 3794 3795 // return Char Width in points 3796 static double getDefaultCharWidth( ScDocShell* pDocShell ) 3797 { 3798 ScDocument& rDoc = pDocShell->GetDocument(); 3799 OutputDevice* pRefDevice = rDoc.GetRefDevice(); 3800 ScPatternAttr* pAttr = rDoc.GetDefPattern(); 3801 vcl::Font aDefFont; 3802 pAttr->GetFont( aDefFont, SC_AUTOCOL_BLACK, pRefDevice ); 3803 pRefDevice->SetFont( aDefFont ); 3804 tools::Long nCharWidth = pRefDevice->GetTextWidth( OUString( '0' ) ); // 1/100th mm 3805 return o3tl::convert<double>(nCharWidth, o3tl::Length::mm100, o3tl::Length::pt); 3806 } 3807 3808 uno::Any SAL_CALL 3809 ScVbaRange::getColumnWidth() 3810 { 3811 sal_Int32 nLen = m_Areas->getCount(); 3812 if ( nLen > 1 ) 3813 { 3814 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW ); 3815 return xRange->getColumnWidth(); 3816 } 3817 3818 double nColWidth = 0; 3819 ScDocShell* pShell = getScDocShell(); 3820 if ( pShell ) 3821 { 3822 double defaultCharWidth = getDefaultCharWidth( pShell ); 3823 RangeHelper thisRange( mxRange ); 3824 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 3825 sal_Int32 nStartCol = thisAddress.StartColumn; 3826 sal_Int32 nEndCol = thisAddress.EndColumn; 3827 sal_uInt16 nColTwips = 0; 3828 for( sal_Int32 nCol = nStartCol ; nCol <= nEndCol; ++nCol ) 3829 { 3830 thisAddress.StartColumn = nCol; 3831 sal_uInt16 nCurTwips = pShell->GetDocument().GetOriginalWidth( static_cast< SCCOL >( thisAddress.StartColumn ), static_cast< SCTAB >( thisAddress.Sheet ) ); 3832 if ( nCol == nStartCol ) 3833 nColTwips = nCurTwips; 3834 if ( nColTwips != nCurTwips ) 3835 return aNULL(); 3836 } 3837 nColWidth = lcl_TwipsToPoints( nColTwips ); 3838 if ( nColWidth != 0.0 ) 3839 nColWidth = ( nColWidth / defaultCharWidth ) - fExtraWidth; 3840 } 3841 nColWidth = lcl_Round2DecPlaces( nColWidth ); 3842 return uno::Any( nColWidth ); 3843 } 3844 3845 void SAL_CALL 3846 ScVbaRange::setColumnWidth( const uno::Any& _columnwidth ) 3847 { 3848 sal_Int32 nLen = m_Areas->getCount(); 3849 if ( nLen > 1 ) 3850 { 3851 for ( sal_Int32 index = 1; index != nLen; ++index ) 3852 { 3853 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW ); 3854 xRange->setColumnWidth( _columnwidth ); 3855 } 3856 return; 3857 } 3858 double nColWidth = 0; 3859 _columnwidth >>= nColWidth; 3860 nColWidth = lcl_Round2DecPlaces( nColWidth ); 3861 ScDocShell* pDocShell = getScDocShell(); 3862 if ( !pDocShell ) 3863 return; 3864 3865 if ( nColWidth != 0.0 ) 3866 nColWidth = ( nColWidth + fExtraWidth ) * getDefaultCharWidth( pDocShell ); 3867 RangeHelper thisRange( mxRange ); 3868 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 3869 sal_uInt16 nTwips = lcl_pointsToTwips( nColWidth ); 3870 3871 std::vector<sc::ColRowSpan> aColArr(1, sc::ColRowSpan(thisAddress.StartColumn, thisAddress.EndColumn)); 3872 // #163561# use mode SC_SIZE_DIRECT: hide for width 0, show for other values 3873 pDocShell->GetDocFunc().SetWidthOrHeight( 3874 true, aColArr, thisAddress.Sheet, SC_SIZE_DIRECT, nTwips, true, true); 3875 } 3876 3877 uno::Any SAL_CALL 3878 ScVbaRange::getWidth() 3879 { 3880 if ( m_Areas->getCount() > 1 ) 3881 { 3882 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW ); 3883 return xRange->getWidth(); 3884 } 3885 uno::Reference< table::XColumnRowRange > xColRowRange( mxRange, uno::UNO_QUERY_THROW ); 3886 uno::Reference< container::XIndexAccess > xIndexAccess( xColRowRange->getColumns(), uno::UNO_QUERY_THROW ); 3887 sal_Int32 nElems = xIndexAccess->getCount(); 3888 double nWidth = 0; 3889 for ( sal_Int32 index=0; index<nElems; ++index ) 3890 { 3891 uno::Reference< sheet::XCellRangeAddressable > xAddressable( xIndexAccess->getByIndex( index ), uno::UNO_QUERY_THROW ); 3892 double nTmpWidth = getCalcColWidth( xAddressable->getRangeAddress() ); 3893 nWidth += nTmpWidth; 3894 } 3895 return uno::Any( nWidth ); 3896 } 3897 3898 uno::Any SAL_CALL 3899 ScVbaRange::Areas( const uno::Any& item) 3900 { 3901 if ( !item.hasValue() ) 3902 return uno::Any( m_Areas ); 3903 return m_Areas->Item( item, uno::Any() ); 3904 } 3905 3906 uno::Reference< excel::XRange > 3907 ScVbaRange::getArea( sal_Int32 nIndex ) 3908 { 3909 if ( !m_Areas.is() ) 3910 throw uno::RuntimeException("No areas available" ); 3911 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( ++nIndex ), uno::Any() ), uno::UNO_QUERY_THROW ); 3912 return xRange; 3913 } 3914 3915 uno::Any 3916 ScVbaRange::Borders( const uno::Any& item ) 3917 { 3918 if ( !item.hasValue() ) 3919 return uno::Any( getBorders() ); 3920 return getBorders()->Item( item, uno::Any() ); 3921 } 3922 3923 uno::Any SAL_CALL 3924 ScVbaRange::BorderAround( const css::uno::Any& LineStyle, const css::uno::Any& Weight, 3925 const css::uno::Any& ColorIndex, const css::uno::Any& Color ) 3926 { 3927 sal_Int32 nCount = getBorders()->getCount(); 3928 3929 for( sal_Int32 i = 0; i < nCount; i++ ) 3930 { 3931 const sal_Int32 nLineType = supportedIndexTable[i]; 3932 switch( nLineType ) 3933 { 3934 case excel::XlBordersIndex::xlEdgeLeft: 3935 case excel::XlBordersIndex::xlEdgeTop: 3936 case excel::XlBordersIndex::xlEdgeBottom: 3937 case excel::XlBordersIndex::xlEdgeRight: 3938 { 3939 uno::Reference< excel::XBorder > xBorder( m_Borders->Item( uno::Any( nLineType ), uno::Any() ), uno::UNO_QUERY_THROW ); 3940 if( LineStyle.hasValue() ) 3941 { 3942 xBorder->setLineStyle( LineStyle ); 3943 } 3944 if( Weight.hasValue() ) 3945 { 3946 xBorder->setWeight( Weight ); 3947 } 3948 if( ColorIndex.hasValue() ) 3949 { 3950 xBorder->setColorIndex( ColorIndex ); 3951 } 3952 if( Color.hasValue() ) 3953 { 3954 xBorder->setColor( Color ); 3955 } 3956 break; 3957 } 3958 case excel::XlBordersIndex::xlInsideVertical: 3959 case excel::XlBordersIndex::xlInsideHorizontal: 3960 case excel::XlBordersIndex::xlDiagonalDown: 3961 case excel::XlBordersIndex::xlDiagonalUp: 3962 break; 3963 default: 3964 return uno::Any( false ); 3965 } 3966 } 3967 return uno::Any( true ); 3968 } 3969 3970 uno::Any SAL_CALL 3971 ScVbaRange::getRowHeight() 3972 { 3973 sal_Int32 nLen = m_Areas->getCount(); 3974 if ( nLen > 1 ) 3975 { 3976 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW ); 3977 return xRange->getRowHeight(); 3978 } 3979 3980 // if any row's RowHeight in the 3981 // range is different from any other, then return NULL 3982 RangeHelper thisRange( mxRange ); 3983 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 3984 3985 sal_Int32 nStartRow = thisAddress.StartRow; 3986 sal_Int32 nEndRow = thisAddress.EndRow; 3987 sal_uInt16 nRowTwips = 0; 3988 // #TODO probably possible to use the SfxItemSet (and see if 3989 // SfxItemState::DONTCARE is set) to improve performance 3990 // #CHECKME looks like this is general behaviour not just row Range specific 3991 // if ( mbIsRows ) 3992 ScDocShell* pShell = getScDocShell(); 3993 if ( pShell ) 3994 { 3995 for ( sal_Int32 nRow = nStartRow ; nRow <= nEndRow; ++nRow ) 3996 { 3997 thisAddress.StartRow = nRow; 3998 sal_uInt16 nCurTwips = pShell->GetDocument().GetOriginalHeight( thisAddress.StartRow, thisAddress.Sheet ); 3999 if ( nRow == nStartRow ) 4000 nRowTwips = nCurTwips; 4001 if ( nRowTwips != nCurTwips ) 4002 return aNULL(); 4003 } 4004 } 4005 double nHeight = lcl_Round2DecPlaces( lcl_TwipsToPoints( nRowTwips ) ); 4006 return uno::Any( nHeight ); 4007 } 4008 4009 void SAL_CALL 4010 ScVbaRange::setRowHeight( const uno::Any& _rowheight) 4011 { 4012 sal_Int32 nLen = m_Areas->getCount(); 4013 if ( nLen > 1 ) 4014 { 4015 for ( sal_Int32 index = 1; index != nLen; ++index ) 4016 { 4017 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW ); 4018 xRange->setRowHeight( _rowheight ); 4019 } 4020 return; 4021 } 4022 double nHeight = 0; // Incoming height is in points 4023 _rowheight >>= nHeight; 4024 nHeight = lcl_Round2DecPlaces( nHeight ); 4025 RangeHelper thisRange( mxRange ); 4026 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 4027 sal_uInt16 nTwips = lcl_pointsToTwips( nHeight ); 4028 4029 ScDocShell* pDocShell = getDocShellFromRange( mxRange ); 4030 std::vector<sc::ColRowSpan> aRowArr(1, sc::ColRowSpan(thisAddress.StartRow, thisAddress.EndRow)); 4031 pDocShell->GetDocFunc().SetWidthOrHeight( 4032 false, aRowArr, thisAddress.Sheet, SC_SIZE_ORIGINAL, nTwips, true, true); 4033 } 4034 4035 uno::Any SAL_CALL 4036 ScVbaRange::getPageBreak() 4037 { 4038 sal_Int32 nPageBreak = excel::XlPageBreak::xlPageBreakNone; 4039 ScDocShell* pShell = getDocShellFromRange( mxRange ); 4040 if ( pShell ) 4041 { 4042 RangeHelper thisRange( mxRange ); 4043 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 4044 bool bColumn = false; 4045 4046 if (thisAddress.StartRow==0) 4047 bColumn = true; 4048 4049 uno::Reference< frame::XModel > xModel = pShell->GetModel(); 4050 if ( xModel.is() ) 4051 { 4052 ScDocument& rDoc = getDocumentFromRange( mxRange ); 4053 4054 ScBreakType nBreak = ScBreakType::NONE; 4055 if ( !bColumn ) 4056 nBreak = rDoc.HasRowBreak(thisAddress.StartRow, thisAddress.Sheet); 4057 else 4058 nBreak = rDoc.HasColBreak(thisAddress.StartColumn, thisAddress.Sheet); 4059 4060 if (nBreak & ScBreakType::Page) 4061 nPageBreak = excel::XlPageBreak::xlPageBreakAutomatic; 4062 4063 if (nBreak & ScBreakType::Manual) 4064 nPageBreak = excel::XlPageBreak::xlPageBreakManual; 4065 } 4066 } 4067 4068 return uno::Any( nPageBreak ); 4069 } 4070 4071 void SAL_CALL 4072 ScVbaRange::setPageBreak( const uno::Any& _pagebreak) 4073 { 4074 sal_Int32 nPageBreak = 0; 4075 _pagebreak >>= nPageBreak; 4076 4077 ScDocShell* pShell = getDocShellFromRange( mxRange ); 4078 if ( !pShell ) 4079 return; 4080 4081 RangeHelper thisRange( mxRange ); 4082 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 4083 if ((thisAddress.StartColumn==0) && (thisAddress.StartRow==0)) 4084 return; 4085 bool bColumn = false; 4086 4087 if (thisAddress.StartRow==0) 4088 bColumn = true; 4089 4090 ScAddress aAddr( static_cast<SCCOL>(thisAddress.StartColumn), thisAddress.StartRow, thisAddress.Sheet ); 4091 uno::Reference< frame::XModel > xModel = pShell->GetModel(); 4092 if ( xModel.is() ) 4093 { 4094 ScTabViewShell* pViewShell = excel::getBestViewShell( xModel ); 4095 if ( nPageBreak == excel::XlPageBreak::xlPageBreakManual ) 4096 pViewShell->InsertPageBreak( bColumn, true, &aAddr); 4097 else if ( nPageBreak == excel::XlPageBreak::xlPageBreakNone ) 4098 pViewShell->DeletePageBreak( bColumn, true, &aAddr); 4099 } 4100 } 4101 4102 uno::Any SAL_CALL 4103 ScVbaRange::getHeight() 4104 { 4105 if ( m_Areas->getCount() > 1 ) 4106 { 4107 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW ); 4108 return xRange->getHeight(); 4109 } 4110 4111 uno::Reference< table::XColumnRowRange > xColRowRange( mxRange, uno::UNO_QUERY_THROW ); 4112 uno::Reference< container::XIndexAccess > xIndexAccess( xColRowRange->getRows(), uno::UNO_QUERY_THROW ); 4113 sal_Int32 nElems = xIndexAccess->getCount(); 4114 double nHeight = 0; 4115 for ( sal_Int32 index=0; index<nElems; ++index ) 4116 { 4117 uno::Reference< sheet::XCellRangeAddressable > xAddressable( xIndexAccess->getByIndex( index ), uno::UNO_QUERY_THROW ); 4118 nHeight += getCalcRowHeight(xAddressable->getRangeAddress() ); 4119 } 4120 return uno::Any( nHeight ); 4121 } 4122 4123 awt::Point 4124 ScVbaRange::getPosition() const 4125 { 4126 awt::Point aPoint; 4127 uno::Reference< beans::XPropertySet > xProps; 4128 if ( mxRange.is() ) 4129 xProps.set( mxRange, uno::UNO_QUERY_THROW ); 4130 else 4131 xProps.set( mxRanges, uno::UNO_QUERY_THROW ); 4132 xProps->getPropertyValue( "Position" ) >>= aPoint; 4133 return aPoint; 4134 } 4135 uno::Any SAL_CALL 4136 ScVbaRange::getLeft() 4137 { 4138 // helperapi returns the first ranges left ( and top below ) 4139 if ( m_Areas->getCount() > 1 ) 4140 return getArea( 0 )->getLeft(); 4141 awt::Point aPoint = getPosition(); 4142 return uno::Any(o3tl::convert<double>(aPoint.X, o3tl::Length::mm100, o3tl::Length::pt)); 4143 } 4144 4145 uno::Any SAL_CALL 4146 ScVbaRange::getTop() 4147 { 4148 // helperapi returns the first ranges top 4149 if ( m_Areas->getCount() > 1 ) 4150 return getArea( 0 )->getTop(); 4151 awt::Point aPoint= getPosition(); 4152 return uno::Any(o3tl::convert<double>(aPoint.Y, o3tl::Length::mm100, o3tl::Length::pt)); 4153 } 4154 4155 static uno::Reference< sheet::XCellRangeReferrer > getNamedRange( const uno::Reference< uno::XInterface >& xIf, const uno::Reference< table::XCellRange >& thisRange ) 4156 { 4157 uno::Reference< beans::XPropertySet > xProps( xIf, uno::UNO_QUERY_THROW ); 4158 uno::Reference< container::XNameAccess > xNameAccess( xProps->getPropertyValue( "NamedRanges" ), uno::UNO_QUERY_THROW ); 4159 4160 const uno::Sequence< OUString > sNames = xNameAccess->getElementNames(); 4161 // uno::Reference< table::XCellRange > thisRange( getCellRange(), uno::UNO_QUERY_THROW ); 4162 uno::Reference< sheet::XCellRangeReferrer > xNamedRange; 4163 for ( const auto& rName : sNames ) 4164 { 4165 uno::Reference< sheet::XCellRangeReferrer > xName( xNameAccess->getByName( rName ), uno::UNO_QUERY ); 4166 if ( xName.is() ) 4167 { 4168 if ( thisRange == xName->getReferredCells() ) 4169 { 4170 xNamedRange = xName; 4171 break; 4172 } 4173 } 4174 } 4175 return xNamedRange; 4176 } 4177 4178 uno::Reference< excel::XName > 4179 ScVbaRange::getName() 4180 { 4181 uno::Reference< beans::XPropertySet > xProps( getUnoModel(), uno::UNO_QUERY ); 4182 uno::Reference< table::XCellRange > thisRange( getCellRange(), uno::UNO_QUERY_THROW ); 4183 // Application range 4184 uno::Reference< sheet::XCellRangeReferrer > xNamedRange = getNamedRange( xProps, thisRange ); 4185 4186 if ( !xNamedRange.is() ) 4187 { 4188 // not in application range then assume it might be in 4189 // sheet namedranges 4190 RangeHelper aRange( thisRange ); 4191 uno::Reference< sheet::XSpreadsheet > xSheet = aRange.getSpreadSheet(); 4192 xProps.set( xSheet, uno::UNO_QUERY ); 4193 // impl here 4194 xNamedRange = getNamedRange( xProps, thisRange ); 4195 } 4196 if ( xProps.is() && xNamedRange.is() ) 4197 { 4198 uno::Reference< sheet::XNamedRanges > xNamedRanges( xProps, uno::UNO_QUERY_THROW ); 4199 uno::Reference< sheet::XNamedRange > xName( xNamedRange, uno::UNO_QUERY_THROW ); 4200 return new ScVbaName( mxParent, mxContext, xName, xNamedRanges, getUnoModel() ); 4201 } 4202 return uno::Reference< excel::XName >(); 4203 } 4204 4205 uno::Reference< excel::XWorksheet > 4206 ScVbaRange::getWorksheet() 4207 { 4208 // #TODO #FIXME parent should always be set up ( currently that's not 4209 // the case ) 4210 uno::Reference< excel::XWorksheet > xSheet( getParent(), uno::UNO_QUERY ); 4211 if ( !xSheet.is() ) 4212 { 4213 uno::Reference< table::XCellRange > xRange = mxRange; 4214 4215 if ( mxRanges.is() ) // assign xRange to first range 4216 { 4217 uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); 4218 xRange.set( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW ); 4219 } 4220 ScDocShell* pDocShell = getDocShellFromRange(xRange); 4221 RangeHelper rHelper(xRange); 4222 // parent should be Thisworkbook 4223 xSheet.set( new ScVbaWorksheet( uno::Reference< XHelperInterface >(), mxContext,rHelper.getSpreadSheet(),pDocShell->GetModel()) ); 4224 } 4225 return xSheet; 4226 } 4227 4228 // #TODO remove this ugly application processing 4229 // Process an application Range request e.g. 'Range("a1,b2,a4:b6") 4230 uno::Reference< excel::XRange > 4231 ScVbaRange::ApplicationRange( const uno::Reference< uno::XComponentContext >& xContext, const css::uno::Any &Cell1, const css::uno::Any &Cell2 ) 4232 { 4233 // Although the documentation seems clear that Range without a 4234 // qualifier then it's a shortcut for ActiveSheet.Range 4235 // however, similarly Application.Range is apparently also a 4236 // shortcut for ActiveSheet.Range 4237 // The is however a subtle behavioural difference I've come across 4238 // wrt to named ranges. 4239 // If a named range "test" exists { Sheet1!$A1 } and the active sheet 4240 // is Sheet2 then the following will fail 4241 // msgbox ActiveSheet.Range("test").Address ' fails 4242 // msgbox WorkSheets("Sheet2").Range("test").Address 4243 // but!!! 4244 // msgbox Range("test").Address ' works 4245 // msgbox Application.Range("test").Address ' works 4246 4247 // Single param Range 4248 OUString sRangeName; 4249 Cell1 >>= sRangeName; 4250 if ( Cell1.hasValue() && !Cell2.hasValue() && !sRangeName.isEmpty() ) 4251 { 4252 uno::Reference< beans::XPropertySet > xPropSet( getCurrentExcelDoc(xContext), uno::UNO_QUERY_THROW ); 4253 4254 uno::Reference< container::XNameAccess > xNamed( xPropSet->getPropertyValue( "NamedRanges" ), uno::UNO_QUERY_THROW ); 4255 uno::Reference< sheet::XCellRangeReferrer > xReferrer; 4256 try 4257 { 4258 xReferrer.set ( xNamed->getByName( sRangeName ), uno::UNO_QUERY ); 4259 } 4260 catch( uno::Exception& /*e*/ ) 4261 { 4262 // do nothing 4263 } 4264 if ( xReferrer.is() ) 4265 { 4266 uno::Reference< table::XCellRange > xRange = xReferrer->getReferredCells(); 4267 if ( xRange.is() ) 4268 { 4269 uno::Reference< excel::XRange > xVbRange = new ScVbaRange( excel::getUnoSheetModuleObj( xRange ), xContext, xRange ); 4270 return xVbRange; 4271 } 4272 } 4273 } 4274 4275 uno::Reference<table::XCellRange> xSheetRange; 4276 4277 try 4278 { 4279 uno::Reference<sheet::XSpreadsheetView> xView( 4280 getCurrentExcelDoc(xContext)->getCurrentController(), uno::UNO_QUERY_THROW); 4281 4282 xSheetRange.set(xView->getActiveSheet(), uno::UNO_QUERY_THROW); 4283 } 4284 catch (const uno::Exception&) 4285 { 4286 return uno::Reference<excel::XRange>(); 4287 } 4288 4289 rtl::Reference<ScVbaRange> pRange = new ScVbaRange( excel::getUnoSheetModuleObj( xSheetRange ), xContext, xSheetRange ); 4290 return pRange->Range( Cell1, Cell2, true ); 4291 } 4292 4293 // Helper functions for AutoFilter 4294 static ScDBData* lcl_GetDBData_Impl( ScDocShell* pDocShell, sal_Int16 nSheet ) 4295 { 4296 ScDBData* pRet = nullptr; 4297 if (pDocShell) 4298 { 4299 pRet = pDocShell->GetDocument().GetAnonymousDBData(nSheet); 4300 } 4301 return pRet; 4302 } 4303 4304 static void lcl_SelectAll( ScDocShell* pDocShell, const ScQueryParam& aParam ) 4305 { 4306 if ( !pDocShell ) 4307 return; 4308 4309 ScViewData* pViewData = ScDocShell::GetViewData(); 4310 if ( !pViewData ) 4311 { 4312 ScTabViewShell* pViewSh = pDocShell->GetBestViewShell( true ); 4313 pViewData = pViewSh ? &pViewSh->GetViewData() : nullptr; 4314 } 4315 4316 if ( pViewData ) 4317 { 4318 pViewData->GetView()->Query( aParam, nullptr, true ); 4319 } 4320 } 4321 4322 static ScQueryParam lcl_GetQueryParam( ScDocShell* pDocShell, sal_Int16 nSheet ) 4323 { 4324 ScDBData* pDBData = lcl_GetDBData_Impl( pDocShell, nSheet ); 4325 ScQueryParam aParam; 4326 if (pDBData) 4327 { 4328 pDBData->GetQueryParam( aParam ); 4329 } 4330 return aParam; 4331 } 4332 4333 static void lcl_SetAllQueryForField( ScDocShell* pDocShell, SCCOLROW nField, sal_Int16 nSheet ) 4334 { 4335 ScQueryParam aParam = lcl_GetQueryParam( pDocShell, nSheet ); 4336 aParam.RemoveEntryByField(nField); 4337 lcl_SelectAll( pDocShell, aParam ); 4338 } 4339 4340 // Modifies sCriteria, and nOp depending on the value of sCriteria 4341 static void lcl_setTableFieldsFromCriteria( OUString& sCriteria1, const uno::Reference< beans::XPropertySet >& xDescProps, sheet::TableFilterField2& rFilterField ) 4342 { 4343 // #TODO make this more efficient and cycle through 4344 // sCriteria1 character by character to pick up <,<>,=, * etc. 4345 // right now I am more concerned with just getting it to work right 4346 4347 sCriteria1 = sCriteria1.trim(); 4348 // table of translation of criteria text to FilterOperators 4349 // <>searchtext - NOT_EQUAL 4350 // =searchtext - EQUAL 4351 // *searchtext - startwith 4352 // <>*searchtext - doesn't startwith 4353 // *searchtext* - contains 4354 // <>*searchtext* - doesn't contain 4355 // [>|>=|<=|...]searchtext for GREATER_value, GREATER_EQUAL_value etc. 4356 if ( sCriteria1.startsWith( EQUALS ) ) 4357 { 4358 if ( o3tl::make_unsigned(sCriteria1.getLength()) == strlen(EQUALS) ) 4359 rFilterField.Operator = sheet::FilterOperator2::EMPTY; 4360 else 4361 { 4362 rFilterField.Operator = sheet::FilterOperator2::EQUAL; 4363 sCriteria1 = sCriteria1.copy( strlen(EQUALS) ); 4364 sCriteria1 = VBAToRegexp( sCriteria1 ); 4365 // UseRegularExpressions 4366 if ( xDescProps.is() ) 4367 xDescProps->setPropertyValue( "UseRegularExpressions", uno::Any( true ) ); 4368 } 4369 4370 } 4371 else if ( sCriteria1.startsWith( NOTEQUALS ) ) 4372 { 4373 if ( o3tl::make_unsigned(sCriteria1.getLength()) == strlen(NOTEQUALS) ) 4374 rFilterField.Operator = sheet::FilterOperator2::NOT_EMPTY; 4375 else 4376 { 4377 rFilterField.Operator = sheet::FilterOperator2::NOT_EQUAL; 4378 sCriteria1 = sCriteria1.copy( strlen(NOTEQUALS) ); 4379 sCriteria1 = VBAToRegexp( sCriteria1 ); 4380 // UseRegularExpressions 4381 if ( xDescProps.is() ) 4382 xDescProps->setPropertyValue( "UseRegularExpressions", uno::Any( true ) ); 4383 } 4384 } 4385 else if ( sCriteria1.startsWith( GREATERTHAN ) ) 4386 { 4387 if ( sCriteria1.startsWith( GREATERTHANEQUALS ) ) 4388 { 4389 sCriteria1 = sCriteria1.copy( strlen(GREATERTHANEQUALS) ); 4390 rFilterField.Operator = sheet::FilterOperator2::GREATER_EQUAL; 4391 } 4392 else 4393 { 4394 sCriteria1 = sCriteria1.copy( strlen(GREATERTHAN) ); 4395 rFilterField.Operator = sheet::FilterOperator2::GREATER; 4396 } 4397 4398 } 4399 else if ( sCriteria1.startsWith( LESSTHAN ) ) 4400 { 4401 if ( sCriteria1.startsWith( LESSTHANEQUALS ) ) 4402 { 4403 sCriteria1 = sCriteria1.copy( strlen(LESSTHANEQUALS) ); 4404 rFilterField.Operator = sheet::FilterOperator2::LESS_EQUAL; 4405 } 4406 else 4407 { 4408 sCriteria1 = sCriteria1.copy( strlen(LESSTHAN) ); 4409 rFilterField.Operator = sheet::FilterOperator2::LESS; 4410 } 4411 4412 } 4413 else 4414 rFilterField.Operator = sheet::FilterOperator2::EQUAL; 4415 4416 // tdf#107885 - check if criteria is numeric using locale dependent settings without group separator 4417 // or, if the decimal separator is different from the English locale, without any locale. 4418 sal_Int32 nParseEnd = 0; 4419 rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok; 4420 double fValue = ScGlobal::getLocaleData().stringToDouble( sCriteria1, false, &eStatus, &nParseEnd ); 4421 if ( nParseEnd == sCriteria1.getLength() && eStatus == rtl_math_ConversionStatus_Ok ) 4422 { 4423 rFilterField.IsNumeric = true; 4424 rFilterField.NumericValue = fValue; 4425 } 4426 else if ( ScGlobal::getLocaleData().getNumDecimalSep().toChar() != '.' ) 4427 { 4428 eStatus = rtl_math_ConversionStatus_Ok; 4429 fValue = ::rtl::math::stringToDouble( sCriteria1, '.', 0, &eStatus, &nParseEnd ); 4430 if ( nParseEnd == sCriteria1.getLength() && eStatus == rtl_math_ConversionStatus_Ok ) 4431 { 4432 rFilterField.IsNumeric = true; 4433 rFilterField.NumericValue = fValue; 4434 } 4435 } 4436 4437 rFilterField.StringValue = sCriteria1; 4438 } 4439 4440 void SAL_CALL 4441 ScVbaRange::AutoFilter( const uno::Any& aField, const uno::Any& Criteria1, const uno::Any& Operator, const uno::Any& Criteria2, const uno::Any& /*VisibleDropDown*/ ) 4442 { 4443 // Is there an existing autofilter 4444 RangeHelper thisRange( mxRange ); 4445 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 4446 sal_Int16 nSheet = thisAddress.Sheet; 4447 ScDocShell* pShell = getScDocShell(); 4448 bool bHasAuto = false; 4449 uno::Reference< sheet::XDatabaseRange > xDataBaseRange = excel::GetAutoFiltRange( pShell, nSheet ); 4450 if ( xDataBaseRange.is() ) 4451 bHasAuto = true; 4452 4453 if ( !bHasAuto ) 4454 { 4455 if ( m_Areas->getCount() > 1 ) 4456 throw uno::RuntimeException( STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY ); 4457 4458 table::CellRangeAddress autoFiltAddress; 4459 //CurrentRegion() 4460 if ( isSingleCellRange() ) 4461 { 4462 uno::Reference< excel::XRange > xCurrent( CurrentRegion() ); 4463 if ( xCurrent.is() ) 4464 { 4465 ScVbaRange* pRange = getImplementation( xCurrent ); 4466 if ( pRange ) 4467 { 4468 if ( pRange->isSingleCellRange() ) 4469 throw uno::RuntimeException("Can't create AutoFilter" ); 4470 RangeHelper currentRegion( pRange->mxRange ); 4471 autoFiltAddress = currentRegion.getCellRangeAddressable()->getRangeAddress(); 4472 } 4473 } 4474 } 4475 else // multi-cell range 4476 { 4477 RangeHelper multiCellRange( mxRange ); 4478 autoFiltAddress = multiCellRange.getCellRangeAddressable()->getRangeAddress(); 4479 // #163530# Filter box shows only entry of first row 4480 ScDocument* pDocument = ( pShell ? &pShell->GetDocument() : nullptr ); 4481 if ( pDocument ) 4482 { 4483 SCCOL nStartCol = autoFiltAddress.StartColumn; 4484 SCROW nStartRow = autoFiltAddress.StartRow; 4485 SCCOL nEndCol = autoFiltAddress.EndColumn; 4486 SCROW nEndRow = autoFiltAddress.EndRow; 4487 pDocument->GetDataArea( autoFiltAddress.Sheet, nStartCol, nStartRow, nEndCol, nEndRow, true, true ); 4488 autoFiltAddress.StartColumn = nStartCol; 4489 autoFiltAddress.StartRow = nStartRow; 4490 autoFiltAddress.EndColumn = nEndCol; 4491 autoFiltAddress.EndRow = nEndRow; 4492 } 4493 } 4494 4495 uno::Reference< sheet::XUnnamedDatabaseRanges > xDBRanges = excel::GetUnnamedDataBaseRanges( pShell ); 4496 if ( xDBRanges.is() ) 4497 { 4498 if ( !xDBRanges->hasByTable( nSheet ) ) 4499 xDBRanges->setByTable( autoFiltAddress ); 4500 xDataBaseRange.set( xDBRanges->getByTable(nSheet ), uno::UNO_QUERY_THROW ); 4501 } 4502 if ( !xDataBaseRange.is() ) 4503 throw uno::RuntimeException("Failed to find the autofilter placeholder range" ); 4504 4505 uno::Reference< beans::XPropertySet > xDBRangeProps( xDataBaseRange, uno::UNO_QUERY_THROW ); 4506 // set autofilter 4507 xDBRangeProps->setPropertyValue( "AutoFilter", uno::Any(true) ); 4508 // set header (autofilter always need column headers) 4509 uno::Reference< beans::XPropertySet > xFiltProps( xDataBaseRange->getFilterDescriptor(), uno::UNO_QUERY_THROW ); 4510 xFiltProps->setPropertyValue( "ContainsHeader", uno::Any( true ) ); 4511 } 4512 4513 sal_Int32 nField = 0; // *IS* 1 based 4514 sal_Int32 nOperator = excel::XlAutoFilterOperator::xlAnd; 4515 4516 sheet::FilterConnection nConn = sheet::FilterConnection_AND; 4517 double nCriteria1 = 0; 4518 4519 bool bHasCritValue = Criteria1.hasValue(); 4520 bool bCritHasNumericValue = false; // not sure if a numeric criteria is possible 4521 if ( bHasCritValue ) 4522 bCritHasNumericValue = ( Criteria1 >>= nCriteria1 ); 4523 4524 if ( !aField.hasValue() && ( Criteria1.hasValue() || Operator.hasValue() || Criteria2.hasValue() ) ) 4525 throw uno::RuntimeException(); 4526 uno::Any Field( aField ); 4527 if ( !( Field >>= nField ) ) 4528 { 4529 const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( mxContext ); 4530 try 4531 { 4532 Field = xConverter->convertTo( aField, cppu::UnoType<sal_Int32>::get() ); 4533 } 4534 catch( uno::Exception& ) 4535 { 4536 } 4537 } 4538 // Use the normal uno api, sometimes e.g. when you want to use ALL as the filter 4539 // we can't use refresh as the uno interface doesn't have a concept of ALL 4540 // in this case we just call the core calc functionality - 4541 if ( Field >>= nField ) 4542 { 4543 uno::Reference< sheet::XSheetFilterDescriptor2 > xDesc( 4544 xDataBaseRange->getFilterDescriptor(), uno::UNO_QUERY ); 4545 if ( xDesc.is() ) 4546 { 4547 OUString sCriteria1; 4548 bool bAcceptCriteria2 = true; 4549 bool bAll = false; 4550 uno::Sequence< sheet::TableFilterField2 > sTabFilts; 4551 sheet::TableFilterField2* pTabFilts = nullptr; 4552 uno::Reference< beans::XPropertySet > xDescProps( xDesc, uno::UNO_QUERY_THROW ); 4553 if ( Criteria1.hasValue() ) 4554 { 4555 sTabFilts.realloc( 1 ); 4556 pTabFilts = sTabFilts.getArray(); 4557 pTabFilts[0].Operator = sheet::FilterOperator2::EQUAL;// sensible default 4558 if ( !bCritHasNumericValue ) 4559 { 4560 Criteria1 >>= sCriteria1; 4561 if ( sCriteria1.isEmpty() ) 4562 { 4563 uno::Sequence< OUString > aCriteria1; 4564 Criteria1 >>= aCriteria1; 4565 sal_uInt16 nLength = aCriteria1.getLength(); 4566 if ( nLength ) 4567 { 4568 // When sequence is provided for Criteria1 don't care about Criteria2 4569 bAcceptCriteria2 = false; 4570 4571 auto pCriteria1 = aCriteria1.getArray(); 4572 sTabFilts.realloc( nLength ); 4573 pTabFilts = sTabFilts.getArray(); 4574 for ( sal_uInt16 i = 0; i < nLength; ++i ) 4575 { 4576 lcl_setTableFieldsFromCriteria( pCriteria1[i], xDescProps, pTabFilts[i] ); 4577 pTabFilts[i].Connection = sheet::FilterConnection_OR; 4578 pTabFilts[i].Field = (nField - 1); 4579 } 4580 } 4581 else 4582 bAll = true; 4583 } 4584 else 4585 { 4586 pTabFilts[0].IsNumeric = bCritHasNumericValue; 4587 if ( bHasCritValue && !sCriteria1.isEmpty() ) 4588 lcl_setTableFieldsFromCriteria( sCriteria1, xDescProps, pTabFilts[0] ); 4589 else 4590 bAll = true; 4591 } 4592 } 4593 else // numeric 4594 { 4595 pTabFilts[0].IsNumeric = true; 4596 pTabFilts[0].NumericValue = nCriteria1; 4597 } 4598 } 4599 else // no value specified 4600 bAll = true; 4601 // not sure what the relationship between Criteria1 and Operator is, 4602 // e.g. can you have an Operator without a Criteria? In LibreOffice it 4603 if ( Operator.hasValue() && ( Operator >>= nOperator ) ) 4604 { 4605 // if it's a bottom/top Ten(Percent/Value) and there 4606 // is no value specified for criteria1 set it to 10 4607 if ( !bCritHasNumericValue && sCriteria1.isEmpty() && ( nOperator != excel::XlAutoFilterOperator::xlOr ) && ( nOperator != excel::XlAutoFilterOperator::xlAnd ) ) 4608 { 4609 pTabFilts[0].IsNumeric = true; 4610 pTabFilts[0].NumericValue = 10; 4611 bAll = false; 4612 } 4613 switch ( nOperator ) 4614 { 4615 case excel::XlAutoFilterOperator::xlBottom10Items: 4616 pTabFilts[0].Operator = sheet::FilterOperator2::BOTTOM_VALUES; 4617 break; 4618 case excel::XlAutoFilterOperator::xlBottom10Percent: 4619 pTabFilts[0].Operator = sheet::FilterOperator2::BOTTOM_PERCENT; 4620 break; 4621 case excel::XlAutoFilterOperator::xlTop10Items: 4622 pTabFilts[0].Operator = sheet::FilterOperator2::TOP_VALUES; 4623 break; 4624 case excel::XlAutoFilterOperator::xlTop10Percent: 4625 pTabFilts[0].Operator = sheet::FilterOperator2::TOP_PERCENT; 4626 break; 4627 case excel::XlAutoFilterOperator::xlOr: 4628 nConn = sheet::FilterConnection_OR; 4629 break; 4630 case excel::XlAutoFilterOperator::xlAnd: 4631 nConn = sheet::FilterConnection_AND; 4632 break; 4633 default: 4634 throw uno::RuntimeException("UnknownOption" ); 4635 4636 } 4637 4638 } 4639 if ( !bAll && bAcceptCriteria2 ) 4640 { 4641 pTabFilts[0].Connection = sheet::FilterConnection_AND; 4642 pTabFilts[0].Field = (nField - 1); 4643 4644 uno::Sequence< OUString > aCriteria2; 4645 if ( Criteria2.hasValue() ) // there is a Criteria2 4646 { 4647 sTabFilts.realloc(2); 4648 pTabFilts = sTabFilts.getArray(); 4649 pTabFilts[1].Field = sTabFilts[0].Field; 4650 pTabFilts[1].Connection = nConn; 4651 4652 OUString sCriteria2; 4653 if ( Criteria2 >>= sCriteria2 ) 4654 { 4655 if ( !sCriteria2.isEmpty() ) 4656 { 4657 uno::Reference< beans::XPropertySet > xProps; 4658 lcl_setTableFieldsFromCriteria( sCriteria2, xProps, pTabFilts[1] ); 4659 pTabFilts[1].IsNumeric = false; 4660 } 4661 } 4662 else if ( Criteria2 >>= aCriteria2 ) 4663 { 4664 sal_uInt16 nLength = aCriteria2.getLength(); 4665 if ( nLength ) 4666 { 4667 // For compatibility use only the last value from the sequence 4668 lcl_setTableFieldsFromCriteria( aCriteria2.getArray()[nLength - 1], xDescProps, pTabFilts[1] ); 4669 } 4670 } 4671 else // numeric 4672 { 4673 Criteria2 >>= pTabFilts[1].NumericValue; 4674 pTabFilts[1].IsNumeric = true; 4675 pTabFilts[1].Operator = sheet::FilterOperator2::EQUAL; 4676 } 4677 } 4678 } 4679 4680 xDesc->setFilterFields2( sTabFilts ); 4681 if ( !bAll ) 4682 { 4683 xDataBaseRange->refresh(); 4684 } 4685 else 4686 // was 0 based now seems to be 1 4687 lcl_SetAllQueryForField( pShell, nField, nSheet ); 4688 } 4689 } 4690 else 4691 { 4692 // this is just to toggle autofilter on and off ( not to be confused with 4693 // a VisibleDropDown option combined with a field, in that case just the 4694 // button should be disabled ) - currently we don't support that 4695 uno::Reference< beans::XPropertySet > xDBRangeProps( xDataBaseRange, uno::UNO_QUERY_THROW ); 4696 if ( bHasAuto ) 4697 { 4698 // find the any field with the query and select all 4699 ScQueryParam aParam = lcl_GetQueryParam( pShell, nSheet ); 4700 for (SCSIZE i = 0; i< aParam.GetEntryCount(); ++i) 4701 { 4702 ScQueryEntry& rEntry = aParam.GetEntry(i); 4703 if ( rEntry.bDoQuery ) 4704 lcl_SetAllQueryForField( pShell, rEntry.nField, nSheet ); 4705 } 4706 // remove existing filters 4707 uno::Reference< sheet::XSheetFilterDescriptor2 > xSheetFilterDescriptor( 4708 xDataBaseRange->getFilterDescriptor(), uno::UNO_QUERY ); 4709 if( xSheetFilterDescriptor.is() ) 4710 xSheetFilterDescriptor->setFilterFields2( uno::Sequence< sheet::TableFilterField2 >() ); 4711 } 4712 xDBRangeProps->setPropertyValue( "AutoFilter", uno::Any(!bHasAuto) ); 4713 4714 } 4715 } 4716 4717 void SAL_CALL 4718 ScVbaRange::Insert( const uno::Any& Shift, const uno::Any& /*CopyOrigin*/ ) 4719 { 4720 // It appears (from the web) that the undocumented CopyOrigin 4721 // param should contain member of enum XlInsertFormatOrigin 4722 // which can have values xlFormatFromLeftOrAbove or xlFormatFromRightOrBelow 4723 // #TODO investigate resultant behaviour using these constants 4724 // currently just processing Shift 4725 4726 sheet::CellInsertMode mode = sheet::CellInsertMode_NONE; 4727 if ( Shift.hasValue() ) 4728 { 4729 sal_Int32 nShift = 0; 4730 Shift >>= nShift; 4731 switch ( nShift ) 4732 { 4733 case excel::XlInsertShiftDirection::xlShiftToRight: 4734 mode = sheet::CellInsertMode_RIGHT; 4735 break; 4736 case excel::XlInsertShiftDirection::xlShiftDown: 4737 mode = sheet::CellInsertMode_DOWN; 4738 break; 4739 default: 4740 throw uno::RuntimeException("Illegal parameter " ); 4741 } 4742 } 4743 else 4744 { 4745 if ( getRow() >= getColumn() ) 4746 mode = sheet::CellInsertMode_DOWN; 4747 else 4748 mode = sheet::CellInsertMode_RIGHT; 4749 } 4750 RangeHelper thisRange( mxRange ); 4751 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 4752 uno::Reference< sheet::XCellRangeMovement > xCellRangeMove( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW ); 4753 xCellRangeMove->insertCells( thisAddress, mode ); 4754 4755 // Paste from clipboard only if the clipboard content was copied via VBA, and not already pasted via VBA again. 4756 // "Insert" behavior should not depend on random clipboard content previously copied by the user. 4757 ScDocShell* pDocShell = getDocShellFromRange( mxRange ); 4758 const ScTransferObj* pClipObj = pDocShell ? ScTransferObj::GetOwnClipboard(pDocShell->GetClipData()) : nullptr; 4759 if ( pClipObj && pClipObj->GetUseInApi() ) 4760 { 4761 // After the insert ( this range ) actually has moved 4762 ScRange aRange( static_cast< SCCOL >( thisAddress.StartColumn ), static_cast< SCROW >( thisAddress.StartRow ), static_cast< SCTAB >( thisAddress.Sheet ), static_cast< SCCOL >( thisAddress.EndColumn ), static_cast< SCROW >( thisAddress.EndRow ), static_cast< SCTAB >( thisAddress.Sheet ) ); 4763 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getDocShellFromRange( mxRange ) , aRange ) ); 4764 uno::Reference< excel::XRange > xVbaRange( new ScVbaRange( mxParent, mxContext, xRange, mbIsRows, mbIsColumns ) ); 4765 xVbaRange->PasteSpecial( uno::Any(), uno::Any(), uno::Any(), uno::Any() ); 4766 } 4767 } 4768 4769 void SAL_CALL 4770 ScVbaRange::Autofit() 4771 { 4772 sal_Int32 nLen = m_Areas->getCount(); 4773 if ( nLen > 1 ) 4774 { 4775 for ( sal_Int32 index = 1; index != nLen; ++index ) 4776 { 4777 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW ); 4778 xRange->Autofit(); 4779 } 4780 return; 4781 } 4782 4783 // if the range is a not a row or column range autofit will 4784 // throw an error 4785 if ( !( mbIsColumns || mbIsRows ) ) 4786 DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); 4787 ScDocShell* pDocShell = getDocShellFromRange( mxRange ); 4788 if ( !pDocShell ) 4789 return; 4790 4791 RangeHelper thisRange( mxRange ); 4792 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 4793 4794 std::vector<sc::ColRowSpan> aColArr(1, sc::ColRowSpan(thisAddress.StartColumn,thisAddress.EndColumn)); 4795 bool bDirection = true; 4796 if ( mbIsRows ) 4797 { 4798 bDirection = false; 4799 aColArr[0].mnStart = thisAddress.StartRow; 4800 aColArr[0].mnEnd = thisAddress.EndRow; 4801 } 4802 pDocShell->GetDocFunc().SetWidthOrHeight( 4803 bDirection, aColArr, thisAddress.Sheet, SC_SIZE_OPTIMAL, 0, true, true); 4804 } 4805 4806 uno::Any SAL_CALL 4807 ScVbaRange::Hyperlinks( const uno::Any& aIndex ) 4808 { 4809 /* The range object always returns a new Hyperlinks object containing a 4810 fixed list of existing hyperlinks in the range. 4811 See vbahyperlinks.hxx for more details. */ 4812 4813 // get the global hyperlink object of the sheet (sheet should always be the parent of a Range object) 4814 uno::Reference< excel::XWorksheet > xWorksheet( getParent(), uno::UNO_QUERY_THROW ); 4815 uno::Reference< excel::XHyperlinks > xSheetHlinks( xWorksheet->Hyperlinks( uno::Any() ), uno::UNO_QUERY_THROW ); 4816 ScVbaHyperlinksRef xScSheetHlinks( dynamic_cast< ScVbaHyperlinks* >( xSheetHlinks.get() ) ); 4817 if( !xScSheetHlinks.is() ) 4818 throw uno::RuntimeException("Cannot obtain hyperlinks implementation object" ); 4819 4820 // create a new local hyperlinks object based on the sheet hyperlinks 4821 ScVbaHyperlinksRef xHlinks( new ScVbaHyperlinks( getParent(), mxContext, xScSheetHlinks, getScRangeList() ) ); 4822 if( aIndex.hasValue() ) 4823 return xHlinks->Item( aIndex, uno::Any() ); 4824 return uno::Any( uno::Reference< excel::XHyperlinks >( xHlinks ) ); 4825 } 4826 4827 css::uno::Reference< excel::XValidation > SAL_CALL 4828 ScVbaRange::getValidation() 4829 { 4830 if ( !m_xValidation.is() ) 4831 m_xValidation = new ScVbaValidation( this, mxContext, mxRange ); 4832 return m_xValidation; 4833 } 4834 4835 namespace { 4836 4837 /// @throws uno::RuntimeException 4838 sal_Unicode lclGetPrefixChar( const uno::Reference< table::XCell >& rxCell ) 4839 { 4840 /* TODO/FIXME: We need an apostroph-prefix property at the cell to 4841 implement this correctly. For now, return an apostroph for every text 4842 cell. 4843 4844 TODO/FIXME: When Application.TransitionNavigKeys is supported and true, 4845 this function needs to inspect the cell formatting and return different 4846 prefixes according to the horizontal cell alignment. 4847 */ 4848 return (rxCell->getType() == table::CellContentType_TEXT) ? '\'' : 0; 4849 } 4850 4851 /// @throws uno::RuntimeException 4852 sal_Unicode lclGetPrefixChar( const uno::Reference< table::XCellRange >& rxRange ) 4853 { 4854 /* This implementation is able to handle different prefixes (needed if 4855 Application.TransitionNavigKeys is true). The function lclGetPrefixChar 4856 for single cells called from here may return any prefix. If that 4857 function returns an empty prefix (NUL character) or different non-empty 4858 prefixes for two cells, this function returns 0. 4859 */ 4860 sal_Unicode cCurrPrefix = 0; 4861 table::CellRangeAddress aRangeAddr = lclGetRangeAddress( rxRange ); 4862 sal_Int32 nEndCol = aRangeAddr.EndColumn - aRangeAddr.StartColumn; 4863 sal_Int32 nEndRow = aRangeAddr.EndRow - aRangeAddr.StartRow; 4864 for( sal_Int32 nRow = 0; nRow <= nEndRow; ++nRow ) 4865 { 4866 for( sal_Int32 nCol = 0; nCol <= nEndCol; ++nCol ) 4867 { 4868 uno::Reference< table::XCell > xCell( rxRange->getCellByPosition( nCol, nRow ), uno::UNO_SET_THROW ); 4869 sal_Unicode cNewPrefix = lclGetPrefixChar( xCell ); 4870 if( (cNewPrefix == 0) || ((cCurrPrefix != 0) && (cNewPrefix != cCurrPrefix)) ) 4871 return 0; 4872 cCurrPrefix = cNewPrefix; 4873 } 4874 } 4875 // all cells contain the same prefix - return it 4876 return cCurrPrefix; 4877 } 4878 4879 /// @throws uno::RuntimeException 4880 sal_Unicode lclGetPrefixChar( const uno::Reference< sheet::XSheetCellRangeContainer >& rxRanges ) 4881 { 4882 sal_Unicode cCurrPrefix = 0; 4883 uno::Reference< container::XEnumerationAccess > xRangesEA( rxRanges, uno::UNO_QUERY_THROW ); 4884 uno::Reference< container::XEnumeration > xRangesEnum( xRangesEA->createEnumeration(), uno::UNO_SET_THROW ); 4885 while( xRangesEnum->hasMoreElements() ) 4886 { 4887 uno::Reference< table::XCellRange > xRange( xRangesEnum->nextElement(), uno::UNO_QUERY_THROW ); 4888 sal_Unicode cNewPrefix = lclGetPrefixChar( xRange ); 4889 if( (cNewPrefix == 0) || ((cCurrPrefix != 0) && (cNewPrefix != cCurrPrefix)) ) 4890 return 0; 4891 cCurrPrefix = cNewPrefix; 4892 } 4893 // all ranges contain the same prefix - return it 4894 return cCurrPrefix; 4895 } 4896 4897 uno::Any lclGetPrefixVariant( sal_Unicode cPrefixChar ) 4898 { 4899 return uno::Any( (cPrefixChar == 0) ? OUString() : OUString( cPrefixChar ) ); 4900 } 4901 4902 } // namespace 4903 4904 uno::Any SAL_CALL ScVbaRange::getPrefixCharacter() 4905 { 4906 /* (1) If Application.TransitionNavigKeys is false, this function returns 4907 an apostroph character if the text cell begins with an apostroph 4908 character (formula return values are not taken into account); otherwise 4909 an empty string. 4910 4911 (2) If Application.TransitionNavigKeys is true, this function returns 4912 an apostroph character, if the cell is left-aligned; a double-quote 4913 character, if the cell is right-aligned; a circumflex character, if the 4914 cell is centered; a backslash character, if the cell is set to filled; 4915 or an empty string, if nothing of the above. 4916 4917 If a range or a list of ranges contains texts with leading apostroph 4918 character as well as other cells, this function returns an empty 4919 string. 4920 */ 4921 4922 if( mxRange.is() ) 4923 return lclGetPrefixVariant( lclGetPrefixChar( mxRange ) ); 4924 if( mxRanges.is() ) 4925 return lclGetPrefixVariant( lclGetPrefixChar( mxRanges ) ); 4926 throw uno::RuntimeException("Unexpected empty Range object" ); 4927 } 4928 4929 uno::Any ScVbaRange::getShowDetail() 4930 { 4931 // #FIXME, If the specified range is in a PivotTable report 4932 4933 // In MSO VBA, the specified range must be a single summary column or row in an outline. otherwise throw exception 4934 if( m_Areas->getCount() > 1 ) 4935 throw uno::RuntimeException("Can not get Range.ShowDetail attribute " ); 4936 4937 RangeHelper helper( mxRange ); 4938 uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = helper.getSheetCellCursor(); 4939 xSheetCellCursor->collapseToCurrentRegion(); 4940 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW); 4941 table::CellRangeAddress aOutlineAddress = xCellRangeAddressable->getRangeAddress(); 4942 4943 // check if the specified range is a single summary column or row. 4944 table::CellRangeAddress thisAddress = helper.getCellRangeAddressable()->getRangeAddress(); 4945 if( (thisAddress.StartRow != thisAddress.EndRow || thisAddress.EndRow != aOutlineAddress.EndRow ) && 4946 (thisAddress.StartColumn != thisAddress.EndColumn || thisAddress.EndColumn != aOutlineAddress.EndColumn )) 4947 { 4948 throw uno::RuntimeException("Can not set Range.ShowDetail attribute" ); 4949 } 4950 4951 bool bColumn = thisAddress.StartRow != thisAddress.EndRow; 4952 ScDocument& rDoc = getDocumentFromRange( mxRange ); 4953 ScOutlineTable* pOutlineTable = rDoc.GetOutlineTable(static_cast<SCTAB>(thisAddress.Sheet), true); 4954 const ScOutlineArray& rOutlineArray = bColumn ? pOutlineTable->GetColArray(): pOutlineTable->GetRowArray(); 4955 SCCOLROW nPos = bColumn ? static_cast<SCCOLROW>(thisAddress.EndColumn-1):static_cast<SCCOLROW>(thisAddress.EndRow-1); 4956 const ScOutlineEntry* pEntry = rOutlineArray.GetEntryByPos( 0, nPos ); 4957 if( pEntry ) 4958 { 4959 const bool bShowDetail = !pEntry->IsHidden(); 4960 return uno::Any( bShowDetail ); 4961 } 4962 4963 return aNULL(); 4964 } 4965 4966 void ScVbaRange::setShowDetail(const uno::Any& aShowDetail) 4967 { 4968 // #FIXME, If the specified range is in a PivotTable report 4969 4970 // In MSO VBA, the specified range must be a single summary column or row in an outline. otherwise throw exception 4971 if( m_Areas->getCount() > 1 ) 4972 throw uno::RuntimeException("Can not set Range.ShowDetail attribute" ); 4973 4974 bool bShowDetail = extractBoolFromAny( aShowDetail ); 4975 4976 RangeHelper helper( mxRange ); 4977 uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = helper.getSheetCellCursor(); 4978 xSheetCellCursor->collapseToCurrentRegion(); 4979 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW); 4980 table::CellRangeAddress aOutlineAddress = xCellRangeAddressable->getRangeAddress(); 4981 4982 // check if the specified range is a single summary column or row. 4983 table::CellRangeAddress thisAddress = helper.getCellRangeAddressable()->getRangeAddress(); 4984 if( (thisAddress.StartRow != thisAddress.EndRow || thisAddress.EndRow != aOutlineAddress.EndRow ) && 4985 (thisAddress.StartColumn != thisAddress.EndColumn || thisAddress.EndColumn != aOutlineAddress.EndColumn )) 4986 { 4987 throw uno::RuntimeException("Can not set Range.ShowDetail attribute" ); 4988 } 4989 4990 // #FIXME, seems there is a different behavior between MSO and OOo. 4991 // In OOo, the showDetail will show all the level entries, while only show the first level entry in MSO 4992 uno::Reference< sheet::XSheetOutline > xSheetOutline( helper.getSpreadSheet(), uno::UNO_QUERY_THROW ); 4993 if( bShowDetail ) 4994 xSheetOutline->showDetail( aOutlineAddress ); 4995 else 4996 xSheetOutline->hideDetail( aOutlineAddress ); 4997 4998 } 4999 5000 uno::Reference< excel::XRange > SAL_CALL 5001 ScVbaRange::MergeArea() 5002 { 5003 uno::Reference< sheet::XSheetCellRange > xMergeShellCellRange(mxRange->getCellRangeByPosition(0,0,0,0), uno::UNO_QUERY_THROW); 5004 uno::Reference< sheet::XSheetCellCursor > xMergeSheetCursor(xMergeShellCellRange->getSpreadsheet()->createCursorByRange( xMergeShellCellRange ), uno::UNO_SET_THROW); 5005 if( xMergeSheetCursor.is() ) 5006 { 5007 xMergeSheetCursor->collapseToMergedArea(); 5008 uno::Reference<sheet::XCellRangeAddressable> xMergeCellAddress(xMergeSheetCursor, uno::UNO_QUERY_THROW); 5009 table::CellRangeAddress aCellAddress = xMergeCellAddress->getRangeAddress(); 5010 if( aCellAddress.StartColumn ==0 && aCellAddress.EndColumn==0 && 5011 aCellAddress.StartRow==0 && aCellAddress.EndRow==0) 5012 { 5013 return new ScVbaRange( mxParent,mxContext,mxRange ); 5014 } 5015 else 5016 { 5017 ScRange refRange( static_cast< SCCOL >( aCellAddress.StartColumn ), static_cast< SCROW >( aCellAddress.StartRow ), static_cast< SCTAB >( aCellAddress.Sheet ), 5018 static_cast< SCCOL >( aCellAddress.EndColumn ), static_cast< SCROW >( aCellAddress.EndRow ), static_cast< SCTAB >( aCellAddress.Sheet ) ); 5019 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getScDocShell() , refRange ) ); 5020 return new ScVbaRange( mxParent, mxContext,xRange ); 5021 } 5022 } 5023 return new ScVbaRange( mxParent, mxContext, mxRange ); 5024 } 5025 5026 void SAL_CALL 5027 ScVbaRange::PrintOut( const uno::Any& From, const uno::Any& To, const uno::Any& Copies, const uno::Any& Preview, const uno::Any& ActivePrinter, const uno::Any& PrintToFile, const uno::Any& Collate, const uno::Any& PrToFileName ) 5028 { 5029 ScDocShell* pShell = nullptr; 5030 5031 sal_Int32 nItems = m_Areas->getCount(); 5032 uno::Sequence< table::CellRangeAddress > printAreas( nItems ); 5033 auto printAreasRange = asNonConstRange(printAreas); 5034 uno::Reference< sheet::XPrintAreas > xPrintAreas; 5035 for ( sal_Int32 index=1; index <= nItems; ++index ) 5036 { 5037 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); 5038 5039 RangeHelper thisRange( xRange->getCellRange() ); 5040 table::CellRangeAddress rangeAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 5041 if ( index == 1 ) 5042 { 5043 ScVbaRange* pRange = getImplementation( xRange ); 5044 // initialise the doc shell and the printareas 5045 pShell = getDocShellFromRange( pRange->mxRange ); 5046 xPrintAreas.set( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW ); 5047 } 5048 printAreasRange[ index - 1 ] = rangeAddress; 5049 } 5050 if ( pShell && xPrintAreas.is() ) 5051 { 5052 xPrintAreas->setPrintAreas( printAreas ); 5053 uno::Reference< frame::XModel > xModel = pShell->GetModel(); 5054 PrintOutHelper( excel::getBestViewShell( xModel ), From, To, Copies, Preview, ActivePrinter, PrintToFile, Collate, PrToFileName, true ); 5055 } 5056 } 5057 5058 void SAL_CALL 5059 ScVbaRange::AutoFill( const uno::Reference< excel::XRange >& Destination, const uno::Any& Type ) 5060 { 5061 uno::Reference< excel::XRange > xDest( Destination, uno::UNO_SET_THROW ); 5062 ScVbaRange* pRange = getImplementation( xDest ); 5063 RangeHelper destRangeHelper( pRange->mxRange ); 5064 table::CellRangeAddress destAddress = destRangeHelper.getCellRangeAddressable()->getRangeAddress(); 5065 5066 RangeHelper thisRange( mxRange ); 5067 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 5068 ScRange sourceRange; 5069 ScRange destRange; 5070 5071 ScUnoConversion::FillScRange( destRange, destAddress ); 5072 ScUnoConversion::FillScRange( sourceRange, thisAddress ); 5073 5074 FillDir eDir = FILL_TO_BOTTOM; 5075 double fStep = 1.0; 5076 5077 ScRange aRange( destRange ); 5078 ScRange aSourceRange( destRange ); 5079 5080 // default to include the number of Rows in the source range; 5081 SCCOLROW nSourceCount = ( sourceRange.aEnd.Row() - sourceRange.aStart.Row() ) + 1; 5082 SCCOLROW nCount = 0; 5083 5084 if ( sourceRange != destRange ) 5085 { 5086 // Find direction of fill, vertical or horizontal 5087 if ( sourceRange.aStart == destRange.aStart ) 5088 { 5089 if ( sourceRange.aEnd.Row() == destRange.aEnd.Row() ) 5090 { 5091 nSourceCount = ( sourceRange.aEnd.Col() - sourceRange.aStart.Col() + 1 ); 5092 aSourceRange.aEnd.SetCol( static_cast<SCCOL>( aSourceRange.aStart.Col() + nSourceCount - 1 ) ); 5093 eDir = FILL_TO_RIGHT; 5094 nCount = aRange.aEnd.Col() - aSourceRange.aEnd.Col(); 5095 } 5096 else if ( sourceRange.aEnd.Col() == destRange.aEnd.Col() ) 5097 { 5098 aSourceRange.aEnd.SetRow( static_cast<SCROW>( aSourceRange.aStart.Row() + nSourceCount ) - 1 ); 5099 nCount = aRange.aEnd.Row() - aSourceRange.aEnd.Row(); 5100 eDir = FILL_TO_BOTTOM; 5101 } 5102 } 5103 5104 else if ( aSourceRange.aEnd == destRange.aEnd ) 5105 { 5106 if ( sourceRange.aStart.Col() == destRange.aStart.Col() ) 5107 { 5108 aSourceRange.aStart.SetRow( static_cast<SCROW>( aSourceRange.aEnd.Row() - nSourceCount + 1 ) ); 5109 nCount = aSourceRange.aStart.Row() - aRange.aStart.Row(); 5110 eDir = FILL_TO_TOP; 5111 fStep = -fStep; 5112 } 5113 else if ( sourceRange.aStart.Row() == destRange.aStart.Row() ) 5114 { 5115 nSourceCount = ( sourceRange.aEnd.Col() - sourceRange.aStart.Col() ) + 1; 5116 aSourceRange.aStart.SetCol( static_cast<SCCOL>( aSourceRange.aEnd.Col() - nSourceCount + 1 ) ); 5117 nCount = aSourceRange.aStart.Col() - aRange.aStart.Col(); 5118 eDir = FILL_TO_LEFT; 5119 fStep = -fStep; 5120 } 5121 } 5122 } 5123 5124 FillCmd eCmd = FILL_AUTO; 5125 FillDateCmd eDateCmd = FILL_DAY; 5126 5127 if ( Type.hasValue() ) 5128 { 5129 sal_Int16 nFillType = excel::XlAutoFillType::xlFillDefault; 5130 Type >>= nFillType; 5131 switch ( nFillType ) 5132 { 5133 case excel::XlAutoFillType::xlFillCopy: 5134 eCmd = FILL_SIMPLE; 5135 fStep = 0.0; 5136 break; 5137 case excel::XlAutoFillType::xlFillDays: 5138 eCmd = FILL_DATE; 5139 break; 5140 case excel::XlAutoFillType::xlFillMonths: 5141 eCmd = FILL_DATE; 5142 eDateCmd = FILL_MONTH; 5143 break; 5144 case excel::XlAutoFillType::xlFillWeekdays: 5145 eCmd = FILL_DATE; 5146 eDateCmd = FILL_WEEKDAY; 5147 break; 5148 case excel::XlAutoFillType::xlFillYears: 5149 eCmd = FILL_DATE; 5150 eDateCmd = FILL_YEAR; 5151 break; 5152 case excel::XlAutoFillType::xlGrowthTrend: 5153 eCmd = FILL_GROWTH; 5154 break; 5155 case excel::XlAutoFillType::xlFillFormats: 5156 throw uno::RuntimeException("xlFillFormat not supported for AutoFill" ); 5157 case excel::XlAutoFillType::xlFillValues: 5158 case excel::XlAutoFillType::xlFillSeries: 5159 case excel::XlAutoFillType::xlLinearTrend: 5160 eCmd = FILL_LINEAR; 5161 break; 5162 case excel::XlAutoFillType::xlFillDefault: 5163 default: 5164 eCmd = FILL_AUTO; 5165 break; 5166 } 5167 } 5168 ScDocShell* pDocSh = getDocShellFromRange( mxRange ); 5169 pDocSh->GetDocFunc().FillAuto( aSourceRange, nullptr, eDir, eCmd, eDateCmd, 5170 nCount, fStep, MAXDOUBLE/*fEndValue*/, true, true ); 5171 } 5172 sal_Bool SAL_CALL 5173 ScVbaRange::GoalSeek( const uno::Any& Goal, const uno::Reference< excel::XRange >& ChangingCell ) 5174 { 5175 ScDocShell* pDocShell = getScDocShell(); 5176 bool bRes = true; 5177 ScVbaRange* pRange = static_cast< ScVbaRange* >( ChangingCell.get() ); 5178 if ( pDocShell && pRange ) 5179 { 5180 uno::Reference< sheet::XGoalSeek > xGoalSeek( pDocShell->GetModel(), uno::UNO_QUERY_THROW ); 5181 RangeHelper thisRange( mxRange ); 5182 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 5183 RangeHelper changingCellRange( pRange->mxRange ); 5184 table::CellRangeAddress changingCellAddr = changingCellRange.getCellRangeAddressable()->getRangeAddress(); 5185 OUString sGoal = getAnyAsString( Goal ); 5186 table::CellAddress thisCell( thisAddress.Sheet, thisAddress.StartColumn, thisAddress.StartRow ); 5187 table::CellAddress changingCell( changingCellAddr.Sheet, changingCellAddr.StartColumn, changingCellAddr.StartRow ); 5188 sheet::GoalResult res = xGoalSeek->seekGoal( thisCell, changingCell, sGoal ); 5189 ChangingCell->setValue( uno::Any( res.Result ) ); 5190 5191 // openoffice behaves differently, result is 0 if the divergence is too great 5192 // but... if it detects 0 is the value it requires then it will use that 5193 // e.g. divergence & result both = 0.0 does NOT mean there is an error 5194 if ( ( res.Divergence != 0.0 ) && ( res.Result == 0.0 ) ) 5195 bRes = false; 5196 } 5197 else 5198 bRes = false; 5199 return bRes; 5200 } 5201 5202 void 5203 ScVbaRange::Calculate( ) 5204 { 5205 getWorksheet()->Calculate(); 5206 } 5207 5208 uno::Reference< excel::XRange > SAL_CALL 5209 ScVbaRange::Item( const uno::Any& row, const uno::Any& column ) 5210 { 5211 if ( mbIsRows || mbIsColumns ) 5212 { 5213 if ( column.hasValue() ) 5214 DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} ); 5215 uno::Reference< excel::XRange > xRange; 5216 if ( mbIsColumns ) 5217 xRange = Columns( row ); 5218 else 5219 xRange = Rows( row ); 5220 return xRange; 5221 } 5222 return Cells( row, column ); 5223 } 5224 5225 void 5226 ScVbaRange::AutoOutline( ) 5227 { 5228 // #TODO #FIXME needs to check for summary row/col ( whatever they are ) 5229 // not valid for multi Area Addresses 5230 if ( m_Areas->getCount() > 1 ) 5231 DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY); 5232 // So needs to either span an entire Row or a just be a single cell 5233 // ( that contains a summary RowColumn ) 5234 // also the Single cell cause doesn't seem to be handled specially in 5235 // this code ( ported from the helperapi RangeImpl.java, 5236 // RangeRowsImpl.java, RangesImpl.java, RangeSingleCellImpl.java 5237 RangeHelper thisRange( mxRange ); 5238 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 5239 5240 if ( isSingleCellRange() || mbIsRows ) 5241 { 5242 uno::Reference< sheet::XSheetOutline > xSheetOutline( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW ); 5243 xSheetOutline->autoOutline( thisAddress ); 5244 } 5245 else 5246 DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); 5247 } 5248 5249 void SAL_CALL 5250 ScVbaRange:: ClearOutline( ) 5251 { 5252 if ( m_Areas->getCount() > 1 ) 5253 { 5254 sal_Int32 nItems = m_Areas->getCount(); 5255 for ( sal_Int32 index=1; index <= nItems; ++index ) 5256 { 5257 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); 5258 xRange->ClearOutline(); 5259 } 5260 return; 5261 } 5262 RangeHelper thisRange( mxRange ); 5263 uno::Reference< sheet::XSheetOutline > xSheetOutline( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW ); 5264 xSheetOutline->clearOutline(); 5265 } 5266 5267 void 5268 ScVbaRange::groupUnGroup( bool bUnGroup ) 5269 { 5270 if ( m_Areas->getCount() > 1 ) 5271 DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY); 5272 table::TableOrientation nOrient = table::TableOrientation_ROWS; 5273 if ( mbIsColumns ) 5274 nOrient = table::TableOrientation_COLUMNS; 5275 RangeHelper thisRange( mxRange ); 5276 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 5277 uno::Reference< sheet::XSheetOutline > xSheetOutline( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW ); 5278 if ( bUnGroup ) 5279 xSheetOutline->ungroup( thisAddress, nOrient ); 5280 else 5281 xSheetOutline->group( thisAddress, nOrient ); 5282 } 5283 5284 void SAL_CALL 5285 ScVbaRange::Group( ) 5286 { 5287 groupUnGroup(false); 5288 } 5289 void SAL_CALL 5290 ScVbaRange::Ungroup( ) 5291 { 5292 groupUnGroup(true); 5293 } 5294 5295 /// @throws uno::RuntimeException 5296 static void lcl_mergeCellsOfRange( const uno::Reference< table::XCellRange >& xCellRange, bool _bMerge ) 5297 { 5298 uno::Reference< util::XMergeable > xMergeable( xCellRange, uno::UNO_QUERY_THROW ); 5299 xMergeable->merge(_bMerge); 5300 } 5301 void SAL_CALL 5302 ScVbaRange::Merge( const uno::Any& Across ) 5303 { 5304 if ( m_Areas->getCount() > 1 ) 5305 { 5306 sal_Int32 nItems = m_Areas->getCount(); 5307 for ( sal_Int32 index=1; index <= nItems; ++index ) 5308 { 5309 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); 5310 xRange->Merge(Across); 5311 } 5312 return; 5313 } 5314 bool bAcross = false; 5315 Across >>= bAcross; 5316 if ( !bAcross ) 5317 lcl_mergeCellsOfRange( mxRange, true ); 5318 else 5319 { 5320 uno::Reference< excel::XRange > oRangeRowsImpl = Rows( uno::Any() ); 5321 // #TODO #FIXME this seems incredibly lame, this can't be right 5322 for (sal_Int32 i=1; i <= oRangeRowsImpl->getCount();i++) 5323 { 5324 oRangeRowsImpl->Cells( uno::Any( i ), uno::Any() )->Merge( uno::Any( false ) ); 5325 } 5326 } 5327 } 5328 5329 void SAL_CALL 5330 ScVbaRange::UnMerge( ) 5331 { 5332 if ( m_Areas->getCount() > 1 ) 5333 { 5334 sal_Int32 nItems = m_Areas->getCount(); 5335 for ( sal_Int32 index=1; index <= nItems; ++index ) 5336 { 5337 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); 5338 xRange->UnMerge(); 5339 } 5340 return; 5341 } 5342 lcl_mergeCellsOfRange( mxRange, false); 5343 } 5344 5345 uno::Any SAL_CALL 5346 ScVbaRange::getStyle() 5347 { 5348 if ( m_Areas->getCount() > 1 ) 5349 { 5350 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW ); 5351 return xRange->getStyle(); 5352 } 5353 uno::Reference< beans::XPropertySet > xProps( mxRange, uno::UNO_QUERY_THROW ); 5354 OUString sStyleName; 5355 xProps->getPropertyValue( CELLSTYLE ) >>= sStyleName; 5356 ScDocShell* pShell = getScDocShell(); 5357 uno::Reference< frame::XModel > xModel( pShell->GetModel() ); 5358 uno::Reference< excel::XStyle > xStyle = new ScVbaStyle( this, mxContext, sStyleName, xModel ); 5359 return uno::Any( xStyle ); 5360 } 5361 void SAL_CALL 5362 ScVbaRange::setStyle( const uno::Any& _style ) 5363 { 5364 if ( m_Areas->getCount() > 1 ) 5365 { 5366 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW ); 5367 xRange->setStyle( _style ); 5368 return; 5369 } 5370 uno::Reference< beans::XPropertySet > xProps( mxRange, uno::UNO_QUERY_THROW ); 5371 uno::Reference< excel::XStyle > xStyle; 5372 _style >>= xStyle; 5373 if ( xStyle.is() ) 5374 xProps->setPropertyValue( CELLSTYLE, uno::Any( xStyle->getName() ) ); 5375 } 5376 5377 uno::Reference< excel::XRange > 5378 ScVbaRange::PreviousNext( bool bIsPrevious ) 5379 { 5380 ScMarkData markedRange(getScDocument().GetSheetLimits()); 5381 ScRange refRange; 5382 RangeHelper thisRange( mxRange ); 5383 5384 ScUnoConversion::FillScRange( refRange, thisRange.getCellRangeAddressable()->getRangeAddress()); 5385 markedRange. SetMarkArea( refRange ); 5386 short nMove = bIsPrevious ? -1 : 1; 5387 5388 SCCOL nNewX = refRange.aStart.Col(); 5389 SCROW nNewY = refRange.aStart.Row(); 5390 SCTAB nTab = refRange.aStart.Tab(); 5391 5392 ScDocument& rDoc = getScDocument(); 5393 rDoc.GetNextPos( nNewX,nNewY, nTab, nMove,0, true,true, markedRange ); 5394 refRange.aStart.SetCol( nNewX ); 5395 refRange.aStart.SetRow( nNewY ); 5396 refRange.aStart.SetTab( nTab ); 5397 refRange.aEnd.SetCol( nNewX ); 5398 refRange.aEnd.SetRow( nNewY ); 5399 refRange.aEnd.SetTab( nTab ); 5400 5401 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getScDocShell() , refRange ) ); 5402 5403 return new ScVbaRange( mxParent, mxContext, xRange ); 5404 } 5405 5406 uno::Reference< excel::XRange > SAL_CALL 5407 ScVbaRange::Next() 5408 { 5409 if ( m_Areas->getCount() > 1 ) 5410 { 5411 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ) , uno::UNO_QUERY_THROW ); 5412 return xRange->Next(); 5413 } 5414 return PreviousNext( false ); 5415 } 5416 5417 uno::Reference< excel::XRange > SAL_CALL 5418 ScVbaRange::Previous() 5419 { 5420 if ( m_Areas->getCount() > 1 ) 5421 { 5422 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW ); 5423 return xRange->Previous(); 5424 } 5425 return PreviousNext( true ); 5426 } 5427 5428 uno::Reference< excel::XRange > SAL_CALL 5429 ScVbaRange::SpecialCells( const uno::Any& _oType, const uno::Any& _oValue) 5430 { 5431 bool bIsSingleCell = isSingleCellRange(); 5432 bool bIsMultiArea = ( m_Areas->getCount() > 1 ); 5433 ScVbaRange* pRangeToUse = this; 5434 uno::Reference< excel::XRange > xUsedRange( getWorksheet()->getUsedRange() ); 5435 sal_Int32 nType = 0; 5436 if ( !( _oType >>= nType ) ) 5437 DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} ); 5438 switch(nType) 5439 { 5440 case excel::XlCellType::xlCellTypeSameFormatConditions: 5441 case excel::XlCellType::xlCellTypeAllValidation: 5442 case excel::XlCellType::xlCellTypeSameValidation: 5443 DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {}); 5444 break; 5445 case excel::XlCellType::xlCellTypeBlanks: 5446 case excel::XlCellType::xlCellTypeComments: 5447 case excel::XlCellType::xlCellTypeConstants: 5448 case excel::XlCellType::xlCellTypeFormulas: 5449 case excel::XlCellType::xlCellTypeVisible: 5450 case excel::XlCellType::xlCellTypeLastCell: 5451 { 5452 if ( bIsMultiArea ) 5453 { 5454 // need to process each area, gather the results and 5455 // create a new range from those 5456 std::vector< table::CellRangeAddress > rangeResults; 5457 sal_Int32 nItems = m_Areas->getCount() + 1; 5458 for ( sal_Int32 index=1; index <= nItems; ++index ) 5459 { 5460 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW ); 5461 xRange = xRange->SpecialCells( _oType, _oValue); 5462 ScVbaRange* pRange = getImplementation( xRange ); 5463 if ( xRange.is() && pRange ) 5464 { 5465 sal_Int32 nElems = pRange->m_Areas->getCount() + 1; 5466 for ( sal_Int32 nArea = 1; nArea < nElems; ++nArea ) 5467 { 5468 uno::Reference< excel::XRange > xTmpRange( m_Areas->Item( uno::Any( nArea ), uno::Any() ), uno::UNO_QUERY_THROW ); 5469 RangeHelper rHelper( xTmpRange->getCellRange() ); 5470 rangeResults.push_back( rHelper.getCellRangeAddressable()->getRangeAddress() ); 5471 } 5472 } 5473 } 5474 ScRangeList aCellRanges; 5475 for ( const auto& rRangeResult : rangeResults ) 5476 { 5477 ScRange refRange; 5478 ScUnoConversion::FillScRange( refRange, rRangeResult ); 5479 aCellRanges.push_back( refRange ); 5480 } 5481 // Single range 5482 if ( aCellRanges.size() == 1 ) 5483 { 5484 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getScDocShell(), aCellRanges.front() ) ); 5485 return new ScVbaRange( mxParent, mxContext, xRange ); 5486 } 5487 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( getScDocShell(), aCellRanges ) ); 5488 5489 return new ScVbaRange( mxParent, mxContext, xRanges ); 5490 } 5491 else if ( bIsSingleCell ) 5492 { 5493 pRangeToUse = static_cast< ScVbaRange* >( xUsedRange.get() ); 5494 } 5495 5496 break; 5497 } 5498 default: 5499 DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} ); 5500 break; 5501 } 5502 if ( !pRangeToUse ) 5503 DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} ); 5504 return pRangeToUse->SpecialCellsImpl( nType, _oValue ); 5505 } 5506 5507 /// @throws script::BasicErrorException 5508 static sal_Int32 lcl_getFormulaResultFlags(const uno::Any& aType) 5509 { 5510 sal_Int32 nType = excel::XlSpecialCellsValue::xlNumbers; 5511 aType >>= nType; 5512 sal_Int32 nRes = sheet::FormulaResult::VALUE; 5513 5514 switch(nType) 5515 { 5516 case excel::XlSpecialCellsValue::xlErrors: 5517 nRes= sheet::FormulaResult::ERROR; 5518 break; 5519 case excel::XlSpecialCellsValue::xlLogical: 5520 //TODO bc93774: ask NN if this is really an appropriate substitute 5521 nRes = sheet::FormulaResult::VALUE; 5522 break; 5523 case excel::XlSpecialCellsValue::xlNumbers: 5524 nRes = sheet::FormulaResult::VALUE; 5525 break; 5526 case excel::XlSpecialCellsValue::xlTextValues: 5527 nRes = sheet::FormulaResult::STRING; 5528 break; 5529 default: 5530 DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} ); 5531 } 5532 return nRes; 5533 } 5534 5535 uno::Reference< excel::XRange > 5536 ScVbaRange::SpecialCellsImpl( sal_Int32 nType, const uno::Any& _oValue) 5537 { 5538 uno::Reference< excel::XRange > xRange; 5539 try 5540 { 5541 uno::Reference< sheet::XCellRangesQuery > xQuery( mxRange, uno::UNO_QUERY_THROW ); 5542 uno::Reference< sheet::XSheetCellRanges > xLocSheetCellRanges; 5543 switch(nType) 5544 { 5545 case excel::XlCellType::xlCellTypeAllFormatConditions: 5546 case excel::XlCellType::xlCellTypeSameFormatConditions: 5547 case excel::XlCellType::xlCellTypeAllValidation: 5548 case excel::XlCellType::xlCellTypeSameValidation: 5549 // Shouldn't get here ( should be filtered out by 5550 // ScVbaRange::SpecialCells() 5551 DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {}); 5552 break; 5553 case excel::XlCellType::xlCellTypeBlanks: 5554 xLocSheetCellRanges = xQuery->queryEmptyCells(); 5555 break; 5556 case excel::XlCellType::xlCellTypeComments: 5557 xLocSheetCellRanges = xQuery->queryContentCells(sheet::CellFlags::ANNOTATION); 5558 break; 5559 case excel::XlCellType::xlCellTypeConstants: 5560 xLocSheetCellRanges = xQuery->queryContentCells(23); 5561 break; 5562 case excel::XlCellType::xlCellTypeFormulas: 5563 { 5564 sal_Int32 nFormulaResult = lcl_getFormulaResultFlags(_oValue); 5565 xLocSheetCellRanges = xQuery->queryFormulaCells(nFormulaResult); 5566 break; 5567 } 5568 case excel::XlCellType::xlCellTypeLastCell: 5569 xRange = Cells( uno::Any( getCount() ), uno::Any() ); 5570 [[fallthrough]]; //TODO ??? 5571 case excel::XlCellType::xlCellTypeVisible: 5572 xLocSheetCellRanges = xQuery->queryVisibleCells(); 5573 break; 5574 default: 5575 DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} ); 5576 break; 5577 } 5578 if (xLocSheetCellRanges.is()) 5579 { 5580 xRange = lcl_makeXRangeFromSheetCellRanges( getParent(), mxContext, xLocSheetCellRanges, getScDocShell() ); 5581 } 5582 } 5583 catch (uno::Exception& ) 5584 { 5585 DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, u"No cells were found"); 5586 } 5587 return xRange; 5588 } 5589 5590 void SAL_CALL 5591 ScVbaRange::RemoveSubtotal( ) 5592 { 5593 uno::Reference< sheet::XSubTotalCalculatable > xSub( mxRange, uno::UNO_QUERY_THROW ); 5594 xSub->removeSubTotals(); 5595 } 5596 5597 void SAL_CALL 5598 ScVbaRange::Subtotal( ::sal_Int32 _nGroupBy, ::sal_Int32 _nFunction, const uno::Sequence< ::sal_Int32 >& _nTotalList, const uno::Any& aReplace, const uno::Any& PageBreaks, const uno::Any& /*SummaryBelowData*/ ) 5599 { 5600 try 5601 { 5602 bool bDoReplace = false; 5603 aReplace >>= bDoReplace; 5604 bool bAddPageBreaks = false; 5605 PageBreaks >>= bAddPageBreaks; 5606 5607 uno::Reference< sheet::XSubTotalCalculatable> xSub(mxRange, uno::UNO_QUERY_THROW ); 5608 uno::Reference< sheet::XSubTotalDescriptor > xSubDesc = xSub->createSubTotalDescriptor(true); 5609 uno::Reference< beans::XPropertySet > xSubDescPropertySet( xSubDesc, uno::UNO_QUERY_THROW ); 5610 xSubDescPropertySet->setPropertyValue("InsertPageBreaks", uno::Any( bAddPageBreaks)); 5611 sal_Int32 nLen = _nTotalList.getLength(); 5612 uno::Sequence< sheet::SubTotalColumn > aColumns( nLen ); 5613 auto aColumnsRange = asNonConstRange(aColumns); 5614 for (int i = 0; i < nLen; i++) 5615 { 5616 aColumnsRange[i].Column = _nTotalList[i] - 1; 5617 switch (_nFunction) 5618 { 5619 case excel::XlConsolidationFunction::xlAverage: 5620 aColumnsRange[i].Function = sheet::GeneralFunction_AVERAGE; 5621 break; 5622 case excel::XlConsolidationFunction::xlCount: 5623 aColumnsRange[i].Function = sheet::GeneralFunction_COUNT; 5624 break; 5625 case excel::XlConsolidationFunction::xlCountNums: 5626 aColumnsRange[i].Function = sheet::GeneralFunction_COUNTNUMS; 5627 break; 5628 case excel::XlConsolidationFunction::xlMax: 5629 aColumnsRange[i].Function = sheet::GeneralFunction_MAX; 5630 break; 5631 case excel::XlConsolidationFunction::xlMin: 5632 aColumnsRange[i].Function = sheet::GeneralFunction_MIN; 5633 break; 5634 case excel::XlConsolidationFunction::xlProduct: 5635 aColumnsRange[i].Function = sheet::GeneralFunction_PRODUCT; 5636 break; 5637 case excel::XlConsolidationFunction::xlStDev: 5638 aColumnsRange[i].Function = sheet::GeneralFunction_STDEV; 5639 break; 5640 case excel::XlConsolidationFunction::xlStDevP: 5641 aColumnsRange[i].Function = sheet::GeneralFunction_STDEVP; 5642 break; 5643 case excel::XlConsolidationFunction::xlSum: 5644 aColumnsRange[i].Function = sheet::GeneralFunction_SUM; 5645 break; 5646 case excel::XlConsolidationFunction::xlUnknown: 5647 aColumnsRange[i].Function = sheet::GeneralFunction_NONE; 5648 break; 5649 case excel::XlConsolidationFunction::xlVar: 5650 aColumnsRange[i].Function = sheet::GeneralFunction_VAR; 5651 break; 5652 case excel::XlConsolidationFunction::xlVarP: 5653 aColumnsRange[i].Function = sheet::GeneralFunction_VARP; 5654 break; 5655 default: 5656 DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {}) ; 5657 return; 5658 } 5659 } 5660 xSubDesc->addNew(aColumns, _nGroupBy - 1); 5661 xSub->applySubTotals(xSubDesc, bDoReplace); 5662 } 5663 catch (const uno::Exception&) 5664 { 5665 DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {}); 5666 } 5667 } 5668 5669 OUString 5670 ScVbaRange::getServiceImplName() 5671 { 5672 return "ScVbaRange"; 5673 } 5674 5675 uno::Sequence< OUString > 5676 ScVbaRange::getServiceNames() 5677 { 5678 return { "ooo.vba.excel.Range" }; 5679 } 5680 5681 sal_Bool SAL_CALL 5682 ScVbaRange::hasError() 5683 { 5684 double dResult = 0.0; 5685 uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW ); 5686 uno::Reference< script::XInvocation > xInvoc( xApplication->WorksheetFunction(), uno::UNO_QUERY_THROW ); 5687 5688 uno::Reference< excel::XRange > aRange( this ); 5689 uno::Sequence< uno::Any > Params{ uno::Any(aRange) }; 5690 uno::Sequence< sal_Int16 > OutParamIndex; 5691 uno::Sequence< uno::Any > OutParam; 5692 xInvoc->invoke( "IsError", Params, OutParamIndex, OutParam ) >>= dResult; 5693 return dResult > 0.0; 5694 } 5695 5696 5697 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* 5698 Calc_ScVbaRange_get_implementation( 5699 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args) 5700 { 5701 return cppu::acquire(new ScVbaRange(args, context)); 5702 } 5703 5704 5705 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 5706
