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