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