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 <sfx2/objsh.hxx> 28 #include <sal/log.hxx> 29 30 #include <com/sun/star/script/ArrayWrapper.hpp> 31 #include <com/sun/star/script/XTypeConverter.hpp> 32 #include <com/sun/star/script/vba/VBAEventId.hpp> 33 #include <com/sun/star/script/vba/XVBAEventProcessor.hpp> 34 #include <com/sun/star/sheet/XDatabaseRange.hpp> 35 #include <com/sun/star/sheet/XUnnamedDatabaseRanges.hpp> 36 #include <com/sun/star/sheet/XGoalSeek.hpp> 37 #include <com/sun/star/sheet/XSheetOperation.hpp> 38 #include <com/sun/star/sheet/CellFlags.hpp> 39 #include <com/sun/star/table/XColumnRowRange.hpp> 40 #include <com/sun/star/sheet/XCellAddressable.hpp> 41 #include <com/sun/star/table/CellContentType.hpp> 42 #include <com/sun/star/sheet/XCellSeries.hpp> 43 #include <com/sun/star/text/XTextRange.hpp> 44 #include <com/sun/star/sheet/XCellRangeAddressable.hpp> 45 #include <com/sun/star/table/CellAddress.hpp> 46 #include <com/sun/star/table/CellRangeAddress.hpp> 47 #include <com/sun/star/sheet/XSpreadsheetView.hpp> 48 #include <com/sun/star/sheet/XCellRangeReferrer.hpp> 49 #include <com/sun/star/sheet/XSheetCellRange.hpp> 50 #include <com/sun/star/sheet/XSpreadsheet.hpp> 51 #include <com/sun/star/sheet/XSheetCellCursor.hpp> 52 #include <com/sun/star/sheet/XArrayFormulaRange.hpp> 53 #include <com/sun/star/sheet/XNamedRange.hpp> 54 #include <com/sun/star/sheet/XNamedRanges.hpp> 55 #include <com/sun/star/sheet/XPrintAreas.hpp> 56 #include <com/sun/star/sheet/XCellRangesQuery.hpp> 57 #include <com/sun/star/beans/XPropertySet.hpp> 58 #include <com/sun/star/sheet/XFunctionAccess.hpp> 59 #include <com/sun/star/frame/XModel.hpp> 60 #include <com/sun/star/view/XSelectionSupplier.hpp> 61 #include <com/sun/star/table/XCellCursor.hpp> 62 #include <com/sun/star/table/XTableRows.hpp> 63 #include <com/sun/star/table/XTableColumns.hpp> 64 #include <com/sun/star/table/TableSortField.hpp> 65 #include <com/sun/star/util/XMergeable.hpp> 66 #include <com/sun/star/uno/XComponentContext.hpp> 67 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> 68 #include <com/sun/star/lang/XMultiComponentFactory.hpp> 69 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp> 70 #include <com/sun/star/util/XNumberFormatsSupplier.hpp> 71 #include <com/sun/star/util/XNumberFormats.hpp> 72 #include <com/sun/star/util/NumberFormat.hpp> 73 #include <com/sun/star/util/XNumberFormatTypes.hpp> 74 #include <com/sun/star/util/XReplaceable.hpp> 75 #include <com/sun/star/util/XSortable.hpp> 76 #include <com/sun/star/sheet/XCellRangeMovement.hpp> 77 #include <com/sun/star/sheet/XCellRangeData.hpp> 78 #include <com/sun/star/sheet/FormulaResult.hpp> 79 #include <com/sun/star/sheet/FilterOperator2.hpp> 80 #include <com/sun/star/sheet/TableFilterField.hpp> 81 #include <com/sun/star/sheet/TableFilterField2.hpp> 82 #include <com/sun/star/sheet/XSheetFilterDescriptor2.hpp> 83 #include <com/sun/star/sheet/XSheetFilterable.hpp> 84 #include <com/sun/star/sheet/FilterConnection.hpp> 85 #include <com/sun/star/util/CellProtection.hpp> 86 #include <com/sun/star/util/TriState.hpp> 87 88 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> 89 #include <com/sun/star/awt/XDevice.hpp> 90 91 #include <com/sun/star/sheet/XSubTotalCalculatable.hpp> 92 #include <com/sun/star/sheet/XSubTotalDescriptor.hpp> 93 #include <com/sun/star/sheet/GeneralFunction.hpp> 94 95 #include <com/sun/star/sheet/XSheetAnnotationsSupplier.hpp> 96 #include <com/sun/star/sheet/XSheetAnnotations.hpp> 97 98 #include <ooo/vba/excel/XlPasteSpecialOperation.hpp> 99 #include <ooo/vba/excel/XlPasteType.hpp> 100 #include <ooo/vba/excel/Constants.hpp> 101 #include <ooo/vba/excel/XlFindLookIn.hpp> 102 #include <ooo/vba/excel/XlLookAt.hpp> 103 #include <ooo/vba/excel/XlSearchOrder.hpp> 104 #include <ooo/vba/excel/XlSortOrder.hpp> 105 #include <ooo/vba/excel/XlYesNoGuess.hpp> 106 #include <ooo/vba/excel/XlSortOrientation.hpp> 107 #include <ooo/vba/excel/XlSortMethod.hpp> 108 #include <ooo/vba/excel/XlDirection.hpp> 109 #include <ooo/vba/excel/XlSortDataOption.hpp> 110 #include <ooo/vba/excel/XlDeleteShiftDirection.hpp> 111 #include <ooo/vba/excel/XlInsertShiftDirection.hpp> 112 #include <ooo/vba/excel/XlReferenceStyle.hpp> 113 #include <ooo/vba/excel/XlBordersIndex.hpp> 114 #include <ooo/vba/excel/XlPageBreak.hpp> 115 #include <ooo/vba/excel/XlAutoFilterOperator.hpp> 116 #include <ooo/vba/excel/XlAutoFillType.hpp> 117 #include <ooo/vba/excel/XlTextParsingType.hpp> 118 #include <ooo/vba/excel/XlTextQualifier.hpp> 119 #include <ooo/vba/excel/XlCellType.hpp> 120 #include <ooo/vba/excel/XlSpecialCellsValue.hpp> 121 #include <ooo/vba/excel/XlConsolidationFunction.hpp> 122 #include <ooo/vba/excel/XlSearchDirection.hpp> 123 124 #include <scitems.hxx> 125 #include <svl/srchitem.hxx> 126 #include <cellsuno.hxx> 127 #include <dbdata.hxx> 128 #include <docfunc.hxx> 129 #include <docuno.hxx> 130 #include <columnspanset.hxx> 131 #include <sortparam.hxx> 132 133 #include <sfx2/dispatch.hxx> 134 #include <sfx2/app.hxx> 135 #include <sfx2/bindings.hxx> 136 #include <sfx2/request.hxx> 137 #include <sfx2/viewfrm.hxx> 138 #include <sc.hrc> 139 #include <unonames.hxx> 140 141 #include "excelvbahelper.hxx" 142 #include "service.hxx" 143 #include "vbaapplication.hxx" 144 #include "vbafont.hxx" 145 #include "vbacomment.hxx" 146 #include "vbainterior.hxx" 147 #include "vbacharacters.hxx" 148 #include "vbaborders.hxx" 149 #include "vbaworksheet.hxx" 150 #include "vbavalidation.hxx" 151 #include "vbahyperlinks.hxx" 152 153 #include <tabvwsh.hxx> 154 #include <rangelst.hxx> 155 #include <convuno.hxx> 156 #include <compiler.hxx> 157 #include <attrib.hxx> 158 #include <undodat.hxx> 159 #include <dbdocfun.hxx> 160 #include <patattr.hxx> 161 #include <olinetab.hxx> 162 #include <transobj.hxx> 163 #include <queryentry.hxx> 164 #include <markdata.hxx> 165 #include <basic/sberrors.hxx> 166 #include <cppuhelper/implbase.hxx> 167 168 #include <global.hxx> 169 170 #include "vbaglobals.hxx" 171 #include "vbastyle.hxx" 172 #include "vbaname.hxx" 173 #include <vector> 174 #include <vbahelper/vbacollectionimpl.hxx> 175 // begin test includes 176 #include <com/sun/star/sheet/FunctionArgument.hpp> 177 // end test includes 178 179 #include <ooo/vba/excel/Range.hpp> 180 #include <com/sun/star/bridge/oleautomation/Date.hpp> 181 #include <tokenarray.hxx> 182 #include <tokenuno.hxx> 183 184 #include <memory> 185 186 using namespace ::ooo::vba; 187 using namespace ::com::sun::star; 188 using ::std::vector; 189 190 // difference between VBA and file format width, in character units 191 const double fExtraWidth = 182.0 / 256.0; 192 193 // * 1 point = 1/72 inch = 20 twips 194 // * 1 inch = 72 points = 1440 twips 195 // * 1 cm = 567 twips 196 static double lcl_hmmToPoints( double nVal ) { return nVal / 1000 * 567 / 20; } 197 198 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 }; 199 200 static sal_uInt16 lcl_pointsToTwips( double nVal ) 201 { 202 nVal = nVal * static_cast<double>(20); 203 short nTwips = static_cast<short>(nVal); 204 return nTwips; 205 } 206 static double lcl_TwipsToPoints( sal_uInt16 nVal ) 207 { 208 double nPoints = nVal; 209 return nPoints / 20; 210 } 211 212 static double lcl_Round2DecPlaces( double nVal ) 213 { 214 nVal = (nVal * double(100)); 215 long tmp = static_cast<long>(nVal); 216 if ( ( nVal - tmp ) >= 0.5 ) 217 ++tmp; 218 nVal = tmp; 219 nVal = nVal/100; 220 return nVal; 221 } 222 223 static uno::Any lcl_makeRange( const uno::Reference< XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, const uno::Any& rAny, bool bIsRows, bool bIsColumns ) 224 { 225 uno::Reference< table::XCellRange > xCellRange(rAny, uno::UNO_QUERY_THROW); 226 return uno::makeAny( uno::Reference< excel::XRange >( new ScVbaRange( rParent, rContext, xCellRange, bIsRows, bIsColumns ) ) ); 227 } 228 229 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 ) 230 { 231 uno::Reference< excel::XRange > xRange; 232 uno::Sequence< table::CellRangeAddress > sAddresses = xLocSheetCellRanges->getRangeAddresses(); 233 ScRangeList aCellRanges; 234 sal_Int32 nLen = sAddresses.getLength(); 235 if ( nLen ) 236 { 237 for ( sal_Int32 index = 0; index < nLen; ++index ) 238 { 239 ScRange refRange; 240 ScUnoConversion::FillScRange( refRange, sAddresses[ index ] ); 241 aCellRanges.push_back( refRange ); 242 } 243 // Single range 244 if ( aCellRanges.size() == 1 ) 245 { 246 uno::Reference< table::XCellRange > xTmpRange( new ScCellRangeObj( pDoc, aCellRanges.front() ) ); 247 xRange = new ScVbaRange( xParent, xContext, xTmpRange ); 248 } 249 else 250 { 251 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pDoc, aCellRanges ) ); 252 xRange = new ScVbaRange( xParent, xContext, xRanges ); 253 } 254 } 255 return xRange; 256 } 257 258 ScCellRangesBase* ScVbaRange::getCellRangesBase() 259 { 260 if( mxRanges.is() ) 261 return ScCellRangesBase::getImplementation( mxRanges ); 262 if( mxRange.is() ) 263 return ScCellRangesBase::getImplementation( mxRange ); 264 throw uno::RuntimeException("General Error creating range - Unknown" ); 265 } 266 267 ScCellRangeObj* ScVbaRange::getCellRangeObj() 268 { 269 return dynamic_cast< ScCellRangeObj* >( getCellRangesBase() ); 270 } 271 272 SfxItemSet* ScVbaRange::getCurrentDataSet( ) 273 { 274 SfxItemSet* pDataSet = excel::ScVbaCellRangeAccess::GetDataSet( getCellRangesBase() ); 275 if ( !pDataSet ) 276 throw uno::RuntimeException("Can't access Itemset for range" ); 277 return pDataSet; 278 } 279 280 void ScVbaRange::fireChangeEvent() 281 { 282 if( ScVbaApplication::getDocumentEventsEnabled() ) 283 { 284 ScDocument& rDoc = getScDocument(); 285 const uno::Reference< script::vba::XVBAEventProcessor >& xVBAEvents = rDoc.GetVbaEventProcessor(); 286 if( xVBAEvents.is() ) try 287 { 288 uno::Sequence< uno::Any > aArgs( 1 ); 289 aArgs[ 0 ] <<= uno::Reference< excel::XRange >( this ); 290 xVBAEvents->processVbaEvent( script::vba::VBAEventId::WORKSHEET_CHANGE, aArgs ); 291 } 292 catch( uno::Exception& ) 293 { 294 } 295 } 296 } 297 298 class SingleRangeEnumeration : public EnumerationHelper_BASE 299 { 300 uno::Reference< table::XCellRange > m_xRange; 301 bool bHasMore; 302 public: 303 /// @throws uno::RuntimeException 304 explicit SingleRangeEnumeration( const uno::Reference< table::XCellRange >& xRange ) : m_xRange( xRange ), bHasMore( true ) { } 305 virtual sal_Bool SAL_CALL hasMoreElements( ) override { return bHasMore; } 306 virtual uno::Any SAL_CALL nextElement( ) override 307 { 308 if ( !bHasMore ) 309 throw container::NoSuchElementException(); 310 bHasMore = false; 311 return uno::makeAny( m_xRange ); 312 } 313 }; 314 315 // very simple class to pass to ScVbaCollectionBaseImpl containing 316 // just one item 317 318 class SingleRangeIndexAccess : public ::cppu::WeakImplHelper< container::XIndexAccess, 319 container::XEnumerationAccess > 320 { 321 private: 322 uno::Reference< table::XCellRange > m_xRange; 323 324 public: 325 explicit SingleRangeIndexAccess( const uno::Reference< table::XCellRange >& xRange ) : m_xRange( xRange ) {} 326 // XIndexAccess 327 virtual ::sal_Int32 SAL_CALL getCount() override { return 1; } 328 virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override 329 { 330 if ( Index != 0 ) 331 throw lang::IndexOutOfBoundsException(); 332 return uno::makeAny( m_xRange ); 333 } 334 // XElementAccess 335 virtual uno::Type SAL_CALL getElementType() override { return cppu::UnoType<table::XCellRange>::get(); } 336 virtual sal_Bool SAL_CALL hasElements() override { return true; } 337 // XEnumerationAccess 338 virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration() override { return new SingleRangeEnumeration( m_xRange ); } 339 340 }; 341 342 class RangesEnumerationImpl : public EnumerationHelperImpl 343 { 344 bool const mbIsRows; 345 bool const mbIsColumns; 346 public: 347 /// @throws uno::RuntimeException 348 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 ) {} 349 virtual uno::Any SAL_CALL nextElement( ) override 350 { 351 return lcl_makeRange( m_xParent, m_xContext, m_xEnumeration->nextElement(), mbIsRows, mbIsColumns ); 352 } 353 }; 354 355 class ScVbaRangeAreas : public ScVbaCollectionBaseImpl 356 { 357 bool const mbIsRows; 358 bool const mbIsColumns; 359 public: 360 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 ) {} 361 362 // XEnumerationAccess 363 virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration() override; 364 365 // XElementAccess 366 virtual uno::Type SAL_CALL getElementType() override { return cppu::UnoType<excel::XRange>::get(); } 367 368 virtual uno::Any createCollectionObject( const uno::Any& aSource ) override; 369 370 virtual OUString getServiceImplName() override { return OUString(); } 371 372 virtual uno::Sequence< OUString > getServiceNames() override { return uno::Sequence< OUString >(); } 373 374 }; 375 376 uno::Reference< container::XEnumeration > SAL_CALL 377 ScVbaRangeAreas::createEnumeration() 378 { 379 uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); 380 return new RangesEnumerationImpl( mxParent, mxContext, xEnumAccess->createEnumeration(), mbIsRows, mbIsColumns ); 381 } 382 383 uno::Any 384 ScVbaRangeAreas::createCollectionObject( const uno::Any& aSource ) 385 { 386 return lcl_makeRange( mxParent, mxContext, aSource, mbIsRows, mbIsColumns ); 387 } 388 389 // assume that xIf is infact a ScCellRangesBase 390 /// @throws uno::RuntimeException 391 static ScDocShell* 392 getDocShellFromIf( const uno::Reference< uno::XInterface >& xIf ) 393 { 394 ScCellRangesBase* pUno = ScCellRangesBase::getImplementation( xIf ); 395 if ( !pUno ) 396 throw uno::RuntimeException("Failed to access underlying uno range object" ); 397 return pUno->GetDocShell(); 398 } 399 400 /// @throws uno::RuntimeException 401 static ScDocShell* 402 getDocShellFromRange( const uno::Reference< table::XCellRange >& xRange ) 403 { 404 // need the ScCellRangesBase to get docshell 405 uno::Reference< uno::XInterface > xIf( xRange ); 406 return getDocShellFromIf(xIf ); 407 } 408 409 /// @throws uno::RuntimeException 410 static ScDocShell* 411 getDocShellFromRanges( const uno::Reference< sheet::XSheetCellRangeContainer >& xRanges ) 412 { 413 // need the ScCellRangesBase to get docshell 414 uno::Reference< uno::XInterface > xIf( xRanges ); 415 return getDocShellFromIf(xIf ); 416 } 417 418 /// @throws uno::RuntimeException 419 static uno::Reference< frame::XModel > getModelFromXIf( const uno::Reference< uno::XInterface >& xIf ) 420 { 421 ScDocShell* pDocShell = getDocShellFromIf(xIf ); 422 return pDocShell->GetModel(); 423 } 424 425 /// @throws uno::RuntimeException 426 static uno::Reference< frame::XModel > getModelFromRange( const uno::Reference< table::XCellRange >& xRange ) 427 { 428 // the XInterface for getImplementation can be any derived interface, no need for queryInterface 429 uno::Reference< uno::XInterface > xIf( xRange ); 430 return getModelFromXIf( xIf ); 431 } 432 433 static ScDocument& 434 getDocumentFromRange( const uno::Reference< table::XCellRange >& xRange ) 435 { 436 ScDocShell* pDocShell = getDocShellFromRange( xRange ); 437 if ( !pDocShell ) 438 throw uno::RuntimeException("Failed to access underlying docshell from uno range object" ); 439 ScDocument& rDoc = pDocShell->GetDocument(); 440 return rDoc; 441 } 442 443 ScDocument& 444 ScVbaRange::getScDocument() 445 { 446 if ( mxRanges.is() ) 447 { 448 uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); 449 uno::Reference< table::XCellRange > xRange( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW ); 450 return getDocumentFromRange( xRange ); 451 } 452 return getDocumentFromRange( mxRange ); 453 } 454 455 ScDocShell* 456 ScVbaRange::getScDocShell() 457 { 458 if ( mxRanges.is() ) 459 { 460 uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); 461 uno::Reference< table::XCellRange > xRange( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW ); 462 return getDocShellFromRange( xRange ); 463 } 464 return getDocShellFromRange( mxRange ); 465 } 466 467 ScVbaRange* ScVbaRange::getImplementation( const uno::Reference< excel::XRange >& rxRange ) 468 { 469 // FIXME: always save to use dynamic_cast? Or better to (implement and) use XTunnel? 470 return dynamic_cast< ScVbaRange* >( rxRange.get() ); 471 } 472 473 uno::Reference< frame::XModel > ScVbaRange::getUnoModel() 474 { 475 if( ScDocShell* pDocShell = getScDocShell() ) 476 return pDocShell->GetModel(); 477 throw uno::RuntimeException(); 478 } 479 480 uno::Reference< frame::XModel > ScVbaRange::getUnoModel( const uno::Reference< excel::XRange >& rxRange ) 481 { 482 if( ScVbaRange* pScVbaRange = getImplementation( rxRange ) ) 483 return pScVbaRange->getUnoModel(); 484 throw uno::RuntimeException(); 485 } 486 487 const ScRangeList& ScVbaRange::getScRangeList() 488 { 489 if( ScCellRangesBase* pScRangesBase = getCellRangesBase() ) 490 return pScRangesBase->GetRangeList(); 491 throw uno::RuntimeException("Cannot obtain UNO range implementation object" ); 492 } 493 494 const ScRangeList& ScVbaRange::getScRangeList( const uno::Reference< excel::XRange >& rxRange ) 495 { 496 if( ScVbaRange* pScVbaRange = getImplementation( rxRange ) ) 497 return pScVbaRange->getScRangeList(); 498 throw uno::RuntimeException("Cannot obtain VBA range implementation object" ); 499 } 500 501 class NumFormatHelper 502 { 503 uno::Reference< util::XNumberFormatsSupplier > mxSupplier; 504 uno::Reference< beans::XPropertySet > mxRangeProps; 505 uno::Reference< util::XNumberFormats > mxFormats; 506 public: 507 explicit NumFormatHelper( const uno::Reference< table::XCellRange >& xRange ) 508 { 509 mxSupplier.set( getModelFromRange( xRange ), uno::UNO_QUERY_THROW ); 510 mxRangeProps.set( xRange, uno::UNO_QUERY_THROW); 511 mxFormats = mxSupplier->getNumberFormats(); 512 } 513 uno::Reference< beans::XPropertySet > getNumberProps() 514 { 515 long nIndexKey = 0; 516 uno::Any aValue = mxRangeProps->getPropertyValue( "NumberFormat" ); 517 aValue >>= nIndexKey; 518 519 if ( mxFormats.is() ) 520 return mxFormats->getByKey( nIndexKey ); 521 return uno::Reference< beans::XPropertySet > (); 522 } 523 524 bool isBooleanType() 525 { 526 527 return (getNumberFormat() & util::NumberFormat::LOGICAL) != 0; 528 } 529 530 bool isDateType() 531 { 532 sal_Int16 nType = getNumberFormat(); 533 return ( nType & util::NumberFormat::DATETIME ) != 0; 534 } 535 536 OUString getNumberFormatString() 537 { 538 uno::Reference< uno::XInterface > xIf( mxRangeProps, uno::UNO_QUERY_THROW ); 539 ScCellRangesBase* pUnoCellRange = ScCellRangesBase::getImplementation( xIf ); 540 if ( pUnoCellRange ) 541 { 542 543 SfxItemSet* pDataSet = excel::ScVbaCellRangeAccess::GetDataSet( pUnoCellRange ); 544 SfxItemState eState = pDataSet->GetItemState( ATTR_VALUE_FORMAT); 545 // one of the cells in the range is not like the other ;-) 546 // so return a zero length format to indicate that 547 if ( eState == SfxItemState::DONTCARE ) 548 return OUString(); 549 } 550 551 uno::Reference< beans::XPropertySet > xNumberProps( getNumberProps(), uno::UNO_QUERY_THROW ); 552 OUString aFormatString; 553 uno::Any aString = xNumberProps->getPropertyValue( "FormatString" ); 554 aString >>= aFormatString; 555 return aFormatString; 556 } 557 558 sal_Int16 getNumberFormat() 559 { 560 uno::Reference< beans::XPropertySet > xNumberProps = getNumberProps(); 561 sal_Int16 nType = ::comphelper::getINT16( 562 xNumberProps->getPropertyValue( "Type" ) ); 563 return nType; 564 } 565 566 void setNumberFormat( const OUString& rFormat ) 567 { 568 // #163288# treat "General" as "Standard" format 569 sal_Int32 nNewIndex = 0; 570 if( !rFormat.equalsIgnoreAsciiCase( "General" ) ) 571 { 572 lang::Locale aLocale; 573 uno::Reference< beans::XPropertySet > xNumProps = getNumberProps(); 574 xNumProps->getPropertyValue( "Locale" ) >>= aLocale; 575 nNewIndex = mxFormats->queryKey( rFormat, aLocale, false ); 576 if ( nNewIndex == -1 ) // format not defined 577 nNewIndex = mxFormats->addNew( rFormat, aLocale ); 578 } 579 mxRangeProps->setPropertyValue( "NumberFormat", uno::makeAny( nNewIndex ) ); 580 } 581 582 void setNumberFormat( sal_Int16 nType ) 583 { 584 uno::Reference< beans::XPropertySet > xNumberProps = getNumberProps(); 585 lang::Locale aLocale; 586 xNumberProps->getPropertyValue( "Locale" ) >>= aLocale; 587 uno::Reference<util::XNumberFormatTypes> xTypes( mxFormats, uno::UNO_QUERY ); 588 if ( xTypes.is() ) 589 { 590 sal_Int32 nNewIndex = xTypes->getStandardFormat( nType, aLocale ); 591 mxRangeProps->setPropertyValue( "NumberFormat", uno::makeAny( nNewIndex ) ); 592 } 593 } 594 595 }; 596 597 struct CellPos 598 { 599 CellPos( sal_Int32 nRow, sal_Int32 nCol, sal_Int32 nArea ):m_nRow(nRow), m_nCol(nCol), m_nArea( nArea ) {}; 600 sal_Int32 const m_nRow; 601 sal_Int32 const m_nCol; 602 sal_Int32 const m_nArea; 603 }; 604 605 typedef ::cppu::WeakImplHelper< container::XEnumeration > CellsEnumeration_BASE; 606 typedef ::std::vector< CellPos > vCellPos; 607 608 // #FIXME - QUICK 609 // we could probably could and should modify CellsEnumeration below 610 // to handle rows and columns (but I do this separately for now 611 // and... this class only handles single areas (does it have to handle 612 // multi area ranges??) 613 class ColumnsRowEnumeration: public CellsEnumeration_BASE 614 { 615 uno::Reference< excel::XRange > mxRange; 616 sal_Int32 const mMaxElems; 617 sal_Int32 mCurElem; 618 619 public: 620 ColumnsRowEnumeration( const uno::Reference< excel::XRange >& xRange, sal_Int32 nElems ) : mxRange( xRange ), mMaxElems( nElems ), mCurElem( 0 ) 621 { 622 } 623 624 virtual sal_Bool SAL_CALL hasMoreElements() override { return mCurElem < mMaxElems; } 625 626 virtual uno::Any SAL_CALL nextElement() override 627 { 628 if ( !hasMoreElements() ) 629 throw container::NoSuchElementException(); 630 sal_Int32 vbaIndex = 1 + mCurElem++; 631 return uno::makeAny( mxRange->Item( uno::makeAny( vbaIndex ), uno::Any() ) ); 632 } 633 }; 634 635 class CellsEnumeration : public CellsEnumeration_BASE 636 { 637 uno::WeakReference< XHelperInterface > mxParent; 638 uno::Reference< uno::XComponentContext > mxContext; 639 uno::Reference< XCollection > m_xAreas; 640 vCellPos m_CellPositions; 641 vCellPos::const_iterator m_it; 642 643 /// @throws uno::RuntimeException 644 uno::Reference< table::XCellRange > getArea( sal_Int32 nVBAIndex ) 645 { 646 if ( nVBAIndex < 1 || nVBAIndex > m_xAreas->getCount() ) 647 throw uno::RuntimeException(); 648 uno::Reference< excel::XRange > xRange( m_xAreas->Item( uno::makeAny(nVBAIndex), uno::Any() ), uno::UNO_QUERY_THROW ); 649 uno::Reference< table::XCellRange > xCellRange( ScVbaRange::getCellRange( xRange ), uno::UNO_QUERY_THROW ); 650 return xCellRange; 651 } 652 653 void populateArea( sal_Int32 nVBAIndex ) 654 { 655 uno::Reference< table::XCellRange > xRange = getArea( nVBAIndex ); 656 uno::Reference< table::XColumnRowRange > xColumnRowRange(xRange, uno::UNO_QUERY_THROW ); 657 sal_Int32 nRowCount = xColumnRowRange->getRows()->getCount(); 658 sal_Int32 nColCount = xColumnRowRange->getColumns()->getCount(); 659 for ( sal_Int32 i=0; i<nRowCount; ++i ) 660 { 661 for ( sal_Int32 j=0; j<nColCount; ++j ) 662 m_CellPositions.emplace_back( i,j,nVBAIndex ); 663 } 664 } 665 public: 666 CellsEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< XCollection >& xAreas ): mxParent( xParent ), mxContext( xContext ), m_xAreas( xAreas ) 667 { 668 sal_Int32 nItems = m_xAreas->getCount(); 669 for ( sal_Int32 index=1; index <= nItems; ++index ) 670 { 671 populateArea( index ); 672 } 673 m_it = m_CellPositions.begin(); 674 } 675 virtual sal_Bool SAL_CALL hasMoreElements() override { return m_it != m_CellPositions.end(); } 676 677 virtual uno::Any SAL_CALL nextElement() override 678 { 679 if ( !hasMoreElements() ) 680 throw container::NoSuchElementException(); 681 CellPos aPos = *(m_it)++; 682 683 uno::Reference< table::XCellRange > xRangeArea = getArea( aPos.m_nArea ); 684 uno::Reference< table::XCellRange > xCellRange( xRangeArea->getCellByPosition( aPos.m_nCol, aPos.m_nRow ), uno::UNO_QUERY_THROW ); 685 return uno::makeAny( uno::Reference< excel::XRange >( new ScVbaRange( mxParent, mxContext, xCellRange ) ) ); 686 687 } 688 }; 689 690 static const char ISVISIBLE[] = "IsVisible"; 691 static const char EQUALS[] = "="; 692 static const char NOTEQUALS[] = "<>"; 693 static const char GREATERTHAN[] = ">"; 694 static const char GREATERTHANEQUALS[] = ">="; 695 static const char LESSTHAN[] = "<"; 696 static const char LESSTHANEQUALS[] = "<="; 697 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"; 698 static const char CELLSTYLE[] = "CellStyle"; 699 700 class CellValueSetter : public ValueSetter 701 { 702 protected: 703 uno::Any const maValue; 704 public: 705 explicit CellValueSetter( const uno::Any& aValue ); 706 virtual bool processValue( const uno::Any& aValue, const uno::Reference< table::XCell >& xCell ) override; 707 virtual void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override; 708 709 }; 710 711 CellValueSetter::CellValueSetter( const uno::Any& aValue ): maValue( aValue ) {} 712 713 void 714 CellValueSetter::visitNode( sal_Int32 /*i*/, sal_Int32 /*j*/, const uno::Reference< table::XCell >& xCell ) 715 { 716 processValue( maValue, xCell ); 717 } 718 719 bool 720 CellValueSetter::processValue( const uno::Any& aValue, const uno::Reference< table::XCell >& xCell ) 721 { 722 723 bool isExtracted = false; 724 switch ( aValue.getValueTypeClass() ) 725 { 726 case uno::TypeClass_BOOLEAN: 727 { 728 bool bState = false; 729 if ( aValue >>= bState ) 730 { 731 uno::Reference< table::XCellRange > xRange( xCell, uno::UNO_QUERY_THROW ); 732 if ( bState ) 733 xCell->setValue( double(1) ); 734 else 735 xCell->setValue( double(0) ); 736 NumFormatHelper cellNumFormat( xRange ); 737 cellNumFormat.setNumberFormat( util::NumberFormat::LOGICAL ); 738 } 739 break; 740 } 741 case uno::TypeClass_STRING: 742 { 743 OUString aString; 744 if ( aValue >>= aString ) 745 { 746 // The required behavior for a string value is: 747 // 1. If the first character is a single quote, use the rest as a string cell, regardless of the cell's number format. 748 // 2. Otherwise, if the cell's number format is "text", use the string value as a string cell. 749 // 3. Otherwise, parse the string value in English locale, and apply a corresponding number format with the cell's locale 750 // if the cell's number format was "General". 751 // Case 1 is handled here, the rest in ScCellObj::InputEnglishString 752 753 if ( aString.toChar() == '\'' ) // case 1 - handle with XTextRange 754 { 755 OUString aRemainder( aString.copy(1) ); // strip the quote 756 uno::Reference< text::XTextRange > xTextRange( xCell, uno::UNO_QUERY_THROW ); 757 xTextRange->setString( aRemainder ); 758 } 759 else 760 { 761 // call implementation method InputEnglishString 762 ScCellObj* pCellObj = dynamic_cast< ScCellObj* >( xCell.get() ); 763 if ( pCellObj ) 764 pCellObj->InputEnglishString( aString ); 765 } 766 } 767 else 768 isExtracted = false; 769 break; 770 } 771 default: 772 { 773 double nDouble = 0.0; 774 if ( aValue >>= nDouble ) 775 { 776 uno::Reference< table::XCellRange > xRange( xCell, uno::UNO_QUERY_THROW ); 777 NumFormatHelper cellFormat( xRange ); 778 // If we are setting a number and the cell types was logical 779 // then we need to reset the logical format. ( see case uno::TypeClass_BOOLEAN: 780 // handling above ) 781 if ( cellFormat.isBooleanType() ) 782 cellFormat.setNumberFormat("General"); 783 xCell->setValue( nDouble ); 784 } 785 else 786 isExtracted = false; 787 break; 788 } 789 } 790 return isExtracted; 791 792 } 793 794 class CellValueGetter : public ValueGetter 795 { 796 protected: 797 uno::Any maValue; 798 public: 799 CellValueGetter() {} 800 virtual void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override; 801 virtual void processValue( sal_Int32 x, sal_Int32 y, const uno::Any& aValue ) override; 802 const uno::Any& getValue() const override { return maValue; } 803 804 }; 805 806 void 807 CellValueGetter::processValue( sal_Int32 /*x*/, sal_Int32 /*y*/, const uno::Any& aValue ) 808 { 809 maValue = aValue; 810 } 811 void CellValueGetter::visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) 812 { 813 uno::Any aValue; 814 table::CellContentType eType = xCell->getType(); 815 if( eType == table::CellContentType_VALUE || eType == table::CellContentType_FORMULA ) 816 { 817 if ( eType == table::CellContentType_FORMULA ) 818 { 819 820 OUString sFormula = xCell->getFormula(); 821 if ( sFormula == "=TRUE()" ) 822 aValue <<= true; 823 else if ( sFormula == "=FALSE()" ) 824 aValue <<= false; 825 else 826 { 827 uno::Reference< beans::XPropertySet > xProp( xCell, uno::UNO_QUERY_THROW ); 828 829 sal_Int32 nResultType = sheet::FormulaResult::VALUE; 830 // some formulas give textual results 831 xProp->getPropertyValue( "FormulaResultType2" ) >>= nResultType; 832 833 if ( nResultType == sheet::FormulaResult::STRING ) 834 { 835 uno::Reference< text::XTextRange > xTextRange(xCell, ::uno::UNO_QUERY_THROW); 836 aValue <<= xTextRange->getString(); 837 } 838 else 839 aValue <<= xCell->getValue(); 840 } 841 } 842 else 843 { 844 uno::Reference< table::XCellRange > xRange( xCell, uno::UNO_QUERY_THROW ); 845 NumFormatHelper cellFormat( xRange ); 846 if ( cellFormat.isBooleanType() ) 847 aValue <<= ( xCell->getValue() != 0.0 ); 848 else if ( cellFormat.isDateType() ) 849 aValue <<= bridge::oleautomation::Date( xCell->getValue() ); 850 else 851 aValue <<= xCell->getValue(); 852 } 853 } 854 if( eType == table::CellContentType_TEXT ) 855 { 856 uno::Reference< text::XTextRange > xTextRange(xCell, ::uno::UNO_QUERY_THROW); 857 aValue <<= xTextRange->getString(); 858 } 859 processValue( x,y,aValue ); 860 } 861 862 class CellFormulaValueSetter : public CellValueSetter 863 { 864 private: 865 ScDocument* const m_pDoc; 866 formula::FormulaGrammar::Grammar const m_eGrammar; 867 public: 868 CellFormulaValueSetter( const uno::Any& aValue, ScDocument* pDoc, formula::FormulaGrammar::Grammar eGram ):CellValueSetter( aValue ), m_pDoc( pDoc ), m_eGrammar( eGram ){} 869 protected: 870 bool processValue( const uno::Any& aValue, const uno::Reference< table::XCell >& xCell ) override 871 { 872 OUString sFormula; 873 double aDblValue = 0.0; 874 if ( aValue >>= sFormula ) 875 { 876 // convert to GRAM_API style grammar because XCell::setFormula 877 // always compile it in that grammar. Perhaps 878 // css.sheet.FormulaParser should be used in future to directly 879 // pass formula tokens when that API stabilizes. 880 if ( m_eGrammar != formula::FormulaGrammar::GRAM_API && ( sFormula.trim().startsWith("=") ) ) 881 { 882 uno::Reference< uno::XInterface > xIf( xCell, uno::UNO_QUERY_THROW ); 883 ScCellRangesBase* pUnoRangesBase = dynamic_cast< ScCellRangesBase* >( xIf.get() ); 884 if ( pUnoRangesBase ) 885 { 886 ScRangeList aCellRanges = pUnoRangesBase->GetRangeList(); 887 ScCompiler aCompiler( m_pDoc, aCellRanges.front().aStart, m_eGrammar ); 888 // compile the string in the format passed in 889 std::unique_ptr<ScTokenArray> pArray(aCompiler.CompileString(sFormula)); 890 // set desired convention to that of the document 891 aCompiler.SetGrammar( formula::FormulaGrammar::GRAM_API ); 892 OUString sConverted; 893 aCompiler.CreateStringFromTokenArray(sConverted); 894 sFormula = EQUALS + sConverted; 895 } 896 } 897 898 xCell->setFormula( sFormula ); 899 return true; 900 } 901 else if ( aValue >>= aDblValue ) 902 { 903 xCell->setValue( aDblValue ); 904 return true; 905 } 906 return false; 907 } 908 909 }; 910 911 class CellFormulaValueGetter : public CellValueGetter 912 { 913 private: 914 ScDocument* const m_pDoc; 915 formula::FormulaGrammar::Grammar const m_eGrammar; 916 public: 917 CellFormulaValueGetter(ScDocument* pDoc, formula::FormulaGrammar::Grammar eGram ) : CellValueGetter( ), m_pDoc( pDoc ), m_eGrammar( eGram ) {} 918 virtual void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override 919 { 920 uno::Any aValue; 921 aValue <<= xCell->getFormula(); 922 OUString sVal; 923 aValue >>= sVal; 924 uno::Reference< uno::XInterface > xIf( xCell, uno::UNO_QUERY_THROW ); 925 ScCellRangesBase* pUnoRangesBase = dynamic_cast< ScCellRangesBase* >( xIf.get() ); 926 if ( ( xCell->getType() == table::CellContentType_FORMULA ) && 927 pUnoRangesBase ) 928 { 929 ScRangeList aCellRanges = pUnoRangesBase->GetRangeList(); 930 ScCompiler aCompiler( m_pDoc, aCellRanges.front().aStart, formula::FormulaGrammar::GRAM_DEFAULT ); 931 std::unique_ptr<ScTokenArray> pArray(aCompiler.CompileString(sVal)); 932 // set desired convention 933 aCompiler.SetGrammar( m_eGrammar ); 934 OUString sConverted; 935 aCompiler.CreateStringFromTokenArray(sConverted); 936 sVal = EQUALS + sConverted; 937 aValue <<= sVal; 938 } 939 940 processValue( x,y,aValue ); 941 } 942 943 }; 944 945 class Dim2ArrayValueGetter : public ArrayVisitor 946 { 947 protected: 948 uno::Any maValue; 949 ValueGetter& mValueGetter; 950 void processValue( sal_Int32 x, sal_Int32 y, const uno::Any& aValue ) 951 { 952 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)); 953 aMatrix[x][y] = aValue; 954 } 955 956 public: 957 Dim2ArrayValueGetter(sal_Int32 nRowCount, sal_Int32 nColCount, ValueGetter& rValueGetter ): mValueGetter(rValueGetter) 958 { 959 uno::Sequence< uno::Sequence< uno::Any > > aMatrix; 960 aMatrix.realloc( nRowCount ); 961 for ( sal_Int32 index = 0; index < nRowCount; ++index ) 962 aMatrix[index].realloc( nColCount ); 963 maValue <<= aMatrix; 964 } 965 void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override 966 967 { 968 mValueGetter.visitNode( x, y, xCell ); 969 processValue( x, y, mValueGetter.getValue() ); 970 } 971 const uno::Any& getValue() const { return maValue; } 972 973 }; 974 975 static const char sNA[] = "#N/A"; 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() 1105 { 1106 return uno::Reference< sheet::XSheetCellRange >(m_xCellRange, uno::UNO_QUERY_THROW); 1107 } 1108 /// @throws uno::RuntimeException 1109 uno::Reference< sheet::XSpreadsheet > getSpreadSheet() 1110 { 1111 return getSheetCellRange()->getSpreadsheet(); 1112 } 1113 1114 /// @throws uno::RuntimeException 1115 uno::Reference< table::XCellRange > getCellRangeFromSheet() 1116 { 1117 return uno::Reference< table::XCellRange >(getSpreadSheet(), uno::UNO_QUERY_THROW ); 1118 } 1119 1120 /// @throws uno::RuntimeException 1121 uno::Reference< sheet::XCellRangeAddressable > getCellRangeAddressable() 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() 1129 { 1130 return uno::Reference< sheet::XSheetCellCursor >( getSpreadSheet()->createCursorByRange( getSheetCellRange() ), uno::UNO_QUERY_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 bool 1147 ScVbaRange::getCellRangesForAddress( ScRefFlags& rResFlags, const OUString& sAddress, ScDocShell* pDocSh, ScRangeList& rCellRanges, formula::FormulaGrammar::AddressConvention eConv, char cDelimiter ) 1148 { 1149 1150 if ( pDocSh ) 1151 { 1152 ScDocument& rDoc = pDocSh->GetDocument(); 1153 rResFlags = rCellRanges.Parse( sAddress, &rDoc, eConv, 0, cDelimiter ); 1154 if ( rResFlags & ScRefFlags::VALID ) 1155 { 1156 return true; 1157 } 1158 } 1159 return false; 1160 } 1161 1162 bool getScRangeListForAddress( const OUString& sName, ScDocShell* pDocSh, const ScRange& refRange, ScRangeList& aCellRanges, formula::FormulaGrammar::AddressConvention aConv ) 1163 { 1164 // see if there is a match with a named range 1165 uno::Reference< beans::XPropertySet > xProps( pDocSh->GetModel(), uno::UNO_QUERY_THROW ); 1166 uno::Reference< container::XNameAccess > xNameAccess( xProps->getPropertyValue( "NamedRanges" ), uno::UNO_QUERY_THROW ); 1167 // Strange enough you can have Range( "namedRange1, namedRange2, etc," ) 1168 // loop around each ',' separated name 1169 std::vector< OUString > vNames; 1170 sal_Int32 nIndex = 0; 1171 do 1172 { 1173 OUString aToken = sName.getToken( 0, ',', nIndex ); 1174 vNames.push_back( aToken ); 1175 } while ( nIndex >= 0 ); 1176 1177 if ( vNames.empty() ) 1178 vNames.push_back( sName ); 1179 1180 for ( const auto& rName : vNames ) 1181 { 1182 formula::FormulaGrammar::AddressConvention eConv = aConv; 1183 // spaces are illegal ( but the user of course can enter them ) 1184 OUString sAddress = rName.trim(); 1185 // if a local name ( on the active sheet ) exists this will 1186 // take precedence over a global with the same name 1187 if ( !xNameAccess->hasByName( sAddress ) ) 1188 { 1189 // try a local name 1190 ScDocument& rDoc = pDocSh->GetDocument(); 1191 SCTAB nCurTab = ScDocShell::GetCurTab(); 1192 ScRangeName* pRangeName = rDoc.GetRangeName(nCurTab); 1193 if (pRangeName) 1194 { 1195 // TODO: Handle local names correctly: 1196 // bool bLocalName = pRangeName->findByUpperName(ScGlobal::pCharClass->uppercase(sAddress)) != nullptr; 1197 } 1198 } 1199 char aChar = 0; 1200 if ( xNameAccess->hasByName( sAddress ) ) 1201 { 1202 uno::Reference< sheet::XNamedRange > xNamed( xNameAccess->getByName( sAddress ), uno::UNO_QUERY_THROW ); 1203 sAddress = xNamed->getContent(); 1204 // As the address comes from OOO, the addressing 1205 // style is may not be XL_A1 1206 eConv = pDocSh->GetDocument().GetAddressConvention(); 1207 aChar = ';'; 1208 } 1209 1210 ScRefFlags nFlags = ScRefFlags::ZERO; 1211 if ( !ScVbaRange::getCellRangesForAddress( nFlags, sAddress, pDocSh, aCellRanges, eConv, aChar ) ) 1212 return false; 1213 1214 bool bTabFromReferrer = !( nFlags & ScRefFlags::TAB_3D ); 1215 1216 for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i ) 1217 { 1218 ScRange & rRange = aCellRanges[ i ]; 1219 rRange.aStart.SetCol( refRange.aStart.Col() + rRange.aStart.Col() ); 1220 rRange.aStart.SetRow( refRange.aStart.Row() + rRange.aStart.Row() ); 1221 rRange.aStart.SetTab( bTabFromReferrer ? refRange.aStart.Tab() : rRange.aStart.Tab() ); 1222 rRange.aEnd.SetCol( refRange.aStart.Col() + rRange.aEnd.Col() ); 1223 rRange.aEnd.SetRow( refRange.aStart.Row() + rRange.aEnd.Row() ); 1224 rRange.aEnd.SetTab( bTabFromReferrer ? refRange.aEnd.Tab() : rRange.aEnd.Tab() ); 1225 } 1226 } 1227 return true; 1228 } 1229 1230 /// @throws uno::RuntimeException 1231 static ScVbaRange* 1232 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 ) 1233 { 1234 ScRangeList aCellRanges; 1235 ScRange refRange; 1236 ScUnoConversion::FillScRange( refRange, pAddr ); 1237 if ( !getScRangeListForAddress ( sName, pDocSh, refRange, aCellRanges, eConv ) ) 1238 throw uno::RuntimeException(); 1239 // Single range 1240 if ( aCellRanges.size() == 1 ) 1241 { 1242 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pDocSh, aCellRanges.front() ) ); 1243 uno::Reference< XHelperInterface > xFixThisParent = excel::getUnoSheetModuleObj( xRange ); 1244 return new ScVbaRange( xFixThisParent, xContext, xRange ); 1245 } 1246 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pDocSh, aCellRanges ) ); 1247 1248 uno::Reference< XHelperInterface > xFixThisParent = excel::getUnoSheetModuleObj( xRanges ); 1249 return new ScVbaRange( xFixThisParent, xContext, xRanges ); 1250 } 1251 1252 namespace { 1253 1254 /// @throws uno::RuntimeException 1255 template< typename RangeType > 1256 table::CellRangeAddress lclGetRangeAddress( const uno::Reference< RangeType >& rxCellRange ) 1257 { 1258 return uno::Reference< sheet::XCellRangeAddressable >( rxCellRange, uno::UNO_QUERY_THROW )->getRangeAddress(); 1259 } 1260 1261 /// @throws uno::RuntimeException 1262 void lclClearRange( const uno::Reference< table::XCellRange >& rxCellRange ) 1263 { 1264 using namespace ::com::sun::star::sheet::CellFlags; 1265 sal_Int32 const nFlags = VALUE | DATETIME | STRING | ANNOTATION | FORMULA | HARDATTR | STYLES | EDITATTR | FORMATTED; 1266 uno::Reference< sheet::XSheetOperation > xSheetOperation( rxCellRange, uno::UNO_QUERY_THROW ); 1267 xSheetOperation->clearContents( nFlags ); 1268 } 1269 1270 /// @throws uno::RuntimeException 1271 uno::Reference< sheet::XSheetCellRange > lclExpandToMerged( const uno::Reference< table::XCellRange >& rxCellRange, bool bRecursive ) 1272 { 1273 uno::Reference< sheet::XSheetCellRange > xNewCellRange( rxCellRange, uno::UNO_QUERY_THROW ); 1274 uno::Reference< sheet::XSpreadsheet > xSheet( xNewCellRange->getSpreadsheet(), uno::UNO_SET_THROW ); 1275 table::CellRangeAddress aNewAddress = lclGetRangeAddress( xNewCellRange ); 1276 table::CellRangeAddress aOldAddress; 1277 // expand as long as there are new merged ranges included 1278 do 1279 { 1280 aOldAddress = aNewAddress; 1281 uno::Reference< sheet::XSheetCellCursor > xCursor( xSheet->createCursorByRange( xNewCellRange ), uno::UNO_SET_THROW ); 1282 xCursor->collapseToMergedArea(); 1283 xNewCellRange.set( xCursor, uno::UNO_QUERY_THROW ); 1284 aNewAddress = lclGetRangeAddress( xNewCellRange ); 1285 } 1286 while( bRecursive && (aOldAddress != aNewAddress) ); 1287 return xNewCellRange; 1288 } 1289 1290 /// @throws uno::RuntimeException 1291 uno::Reference< sheet::XSheetCellRangeContainer > lclExpandToMerged( const uno::Reference< sheet::XSheetCellRangeContainer >& rxCellRanges ) 1292 { 1293 if( !rxCellRanges.is() ) 1294 throw uno::RuntimeException("Missing cell ranges object" ); 1295 sal_Int32 nCount = rxCellRanges->getCount(); 1296 if( nCount < 1 ) 1297 throw uno::RuntimeException("Missing cell ranges object" ); 1298 1299 ScRangeList aScRanges; 1300 for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) 1301 { 1302 uno::Reference< table::XCellRange > xRange( rxCellRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); 1303 table::CellRangeAddress aRangeAddr = lclGetRangeAddress( lclExpandToMerged( xRange, /*bRecursive*/true ) ); 1304 ScRange aScRange; 1305 ScUnoConversion::FillScRange( aScRange, aRangeAddr ); 1306 aScRanges.push_back( aScRange ); 1307 } 1308 return new ScCellRangesObj( getDocShellFromRanges( rxCellRanges ), aScRanges ); 1309 } 1310 1311 /// @throws uno::RuntimeException 1312 void lclExpandAndMerge( const uno::Reference< table::XCellRange >& rxCellRange, bool bMerge ) 1313 { 1314 uno::Reference< util::XMergeable > xMerge( lclExpandToMerged( rxCellRange, true ), uno::UNO_QUERY_THROW ); 1315 // Calc cannot merge over merged ranges, always unmerge first 1316 xMerge->merge( false ); 1317 if( bMerge ) 1318 { 1319 // clear all contents of the covered cells (not the top-left cell) 1320 table::CellRangeAddress aRangeAddr = lclGetRangeAddress( rxCellRange ); 1321 sal_Int32 nLastColIdx = aRangeAddr.EndColumn - aRangeAddr.StartColumn; 1322 sal_Int32 nLastRowIdx = aRangeAddr.EndRow - aRangeAddr.StartRow; 1323 // clear cells of top row, right of top-left cell 1324 if( nLastColIdx > 0 ) 1325 lclClearRange( rxCellRange->getCellRangeByPosition( 1, 0, nLastColIdx, 0 ) ); 1326 // clear all rows below top row 1327 if( nLastRowIdx > 0 ) 1328 lclClearRange( rxCellRange->getCellRangeByPosition( 0, 1, nLastColIdx, nLastRowIdx ) ); 1329 // merge the range 1330 xMerge->merge( true ); 1331 } 1332 } 1333 1334 /// @throws uno::RuntimeException 1335 util::TriState lclGetMergedState( const uno::Reference< table::XCellRange >& rxCellRange ) 1336 { 1337 /* 1) Check if range is completely inside one single merged range. To do 1338 this, try to extend from top-left cell only (not from entire range). 1339 This will exclude cases where this range consists of several merged 1340 ranges (or parts of them). */ 1341 table::CellRangeAddress aRangeAddr = lclGetRangeAddress( rxCellRange ); 1342 uno::Reference< table::XCellRange > xTopLeft( rxCellRange->getCellRangeByPosition( 0, 0, 0, 0 ), uno::UNO_SET_THROW ); 1343 uno::Reference< sheet::XSheetCellRange > xExpanded( lclExpandToMerged( xTopLeft, false ), uno::UNO_SET_THROW ); 1344 table::CellRangeAddress aExpAddr = lclGetRangeAddress( xExpanded ); 1345 // check that expanded range has more than one cell (really merged) 1346 if( ((aExpAddr.StartColumn < aExpAddr.EndColumn) || (aExpAddr.StartRow < aExpAddr.EndRow)) && ScUnoConversion::Contains( aExpAddr, aRangeAddr ) ) 1347 return util::TriState_YES; 1348 1349 /* 2) Check if this range contains any merged cells (completely or 1350 partly). This seems to be hardly possible via API, as 1351 XMergeable::getIsMerged() returns only true, if the top-left cell of a 1352 merged range is part of this range, so cases where just the lower part 1353 of a merged range is part of this range are not covered. */ 1354 ScRange aScRange; 1355 ScUnoConversion::FillScRange( aScRange, aRangeAddr ); 1356 bool bHasMerged = getDocumentFromRange( rxCellRange ).HasAttrib( aScRange, HasAttrFlags::Merged | HasAttrFlags::Overlapped ); 1357 return bHasMerged ? util::TriState_INDETERMINATE : util::TriState_NO; 1358 } 1359 1360 } // namespace 1361 1362 css::uno::Reference< excel::XRange > 1363 ScVbaRange::getRangeObjectForName( 1364 const uno::Reference< uno::XComponentContext >& xContext, const OUString& sRangeName, 1365 ScDocShell* pDocSh, formula::FormulaGrammar::AddressConvention eConv ) 1366 { 1367 table::CellRangeAddress refAddr; 1368 return getRangeForName( xContext, sRangeName, pDocSh, refAddr, eConv ); 1369 } 1370 1371 /// @throws uno::RuntimeException 1372 static table::CellRangeAddress getCellRangeAddressForVBARange( const uno::Any& aParam, ScDocShell* pDocSh ) 1373 { 1374 uno::Reference< table::XCellRange > xRangeParam; 1375 switch ( aParam.getValueTypeClass() ) 1376 { 1377 case uno::TypeClass_STRING: 1378 { 1379 OUString rString; 1380 aParam >>= rString; 1381 ScRangeList aCellRanges; 1382 ScRange refRange; 1383 if ( getScRangeListForAddress ( rString, pDocSh, refRange, aCellRanges ) ) 1384 { 1385 if ( aCellRanges.size() == 1 ) 1386 { 1387 table::CellRangeAddress aRangeAddress; 1388 ScUnoConversion::FillApiRange( aRangeAddress, aCellRanges.front() ); 1389 return aRangeAddress; 1390 } 1391 } 1392 } 1393 break; 1394 1395 case uno::TypeClass_INTERFACE: 1396 { 1397 uno::Reference< excel::XRange > xRange; 1398 aParam >>= xRange; 1399 if ( xRange.is() ) 1400 xRange->getCellRange() >>= xRangeParam; 1401 } 1402 break; 1403 1404 default: 1405 throw uno::RuntimeException("Can't extract CellRangeAddress from type" ); 1406 } 1407 return lclGetRangeAddress( xRangeParam ); 1408 } 1409 1410 /// @throws uno::RuntimeException 1411 static uno::Reference< XCollection > 1412 lcl_setupBorders( const uno::Reference< excel::XRange >& xParentRange, const uno::Reference<uno::XComponentContext>& xContext, const uno::Reference< table::XCellRange >& xRange ) 1413 { 1414 uno::Reference< XHelperInterface > xParent( xParentRange, uno::UNO_QUERY_THROW ); 1415 ScDocument& rDoc = getDocumentFromRange(xRange); 1416 ScVbaPalette aPalette( rDoc.GetDocumentShell() ); 1417 uno::Reference< XCollection > borders( new ScVbaBorders( xParent, xContext, xRange, aPalette ) ); 1418 return borders; 1419 } 1420 1421 ScVbaRange::ScVbaRange( uno::Sequence< uno::Any> const & args, 1422 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 ) 1423 { 1424 mxRange.set( mxPropertySet, uno::UNO_QUERY ); 1425 mxRanges.set( mxPropertySet, uno::UNO_QUERY ); 1426 uno::Reference< container::XIndexAccess > xIndex; 1427 if ( mxRange.is() ) 1428 { 1429 xIndex = new SingleRangeIndexAccess( mxRange ); 1430 } 1431 else if ( mxRanges.is() ) 1432 { 1433 xIndex.set( mxRanges, uno::UNO_QUERY_THROW ); 1434 } 1435 m_Areas = new ScVbaRangeAreas( mxParent, mxContext, xIndex, mbIsRows, mbIsColumns ); 1436 } 1437 1438 ScVbaRange::ScVbaRange( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< table::XCellRange >& xRange, bool bIsRows, bool bIsColumns ) 1439 : ScVbaRange_BASE( xParent, xContext, uno::Reference< beans::XPropertySet >( xRange, uno::UNO_QUERY_THROW ), getModelFromRange( xRange), true ), mxRange( xRange ), 1440 mbIsRows( bIsRows ), 1441 mbIsColumns( bIsColumns ) 1442 { 1443 if ( !xContext.is() ) 1444 throw lang::IllegalArgumentException("context is not set ", uno::Reference< uno::XInterface >() , 1 ); 1445 if ( !xRange.is() ) 1446 throw lang::IllegalArgumentException("range is not set ", uno::Reference< uno::XInterface >() , 1 ); 1447 1448 uno::Reference< container::XIndexAccess > xIndex( new SingleRangeIndexAccess( xRange ) ); 1449 m_Areas = new ScVbaRangeAreas( mxParent, mxContext, xIndex, mbIsRows, mbIsColumns ); 1450 1451 } 1452 1453 ScVbaRange::ScVbaRange(const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< sheet::XSheetCellRangeContainer >& xRanges, bool bIsRows, bool bIsColumns) 1454 : 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 ) 1455 1456 { 1457 uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); 1458 m_Areas = new ScVbaRangeAreas( xParent, mxContext, xIndex, mbIsRows, mbIsColumns ); 1459 1460 } 1461 1462 ScVbaRange::~ScVbaRange() 1463 { 1464 } 1465 1466 uno::Reference< XCollection >& ScVbaRange::getBorders() 1467 { 1468 if ( !m_Borders.is() ) 1469 { 1470 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW ); 1471 m_Borders = lcl_setupBorders( this, mxContext, uno::Reference< table::XCellRange >( xRange->getCellRange(), uno::UNO_QUERY_THROW ) ); 1472 } 1473 return m_Borders; 1474 } 1475 1476 void 1477 ScVbaRange::visitArray( ArrayVisitor& visitor ) 1478 { 1479 table::CellRangeAddress aRangeAddr = lclGetRangeAddress( mxRange ); 1480 sal_Int32 nRowCount = aRangeAddr.EndRow - aRangeAddr.StartRow + 1; 1481 sal_Int32 nColCount = aRangeAddr.EndColumn - aRangeAddr.StartColumn + 1; 1482 for ( sal_Int32 i=0; i<nRowCount; ++i ) 1483 { 1484 for ( sal_Int32 j=0; j<nColCount; ++j ) 1485 { 1486 uno::Reference< table::XCell > xCell( mxRange->getCellByPosition( j, i ), uno::UNO_QUERY_THROW ); 1487 1488 visitor.visitNode( i, j, xCell ); 1489 } 1490 } 1491 } 1492 1493 uno::Any 1494 ScVbaRange::getValue( ValueGetter& valueGetter) 1495 { 1496 uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY_THROW ); 1497 // single cell range 1498 if ( isSingleCellRange() ) 1499 { 1500 visitArray( valueGetter ); 1501 return valueGetter.getValue(); 1502 } 1503 sal_Int32 nRowCount = xColumnRowRange->getRows()->getCount(); 1504 sal_Int32 nColCount = xColumnRowRange->getColumns()->getCount(); 1505 // multi cell range ( return array ) 1506 Dim2ArrayValueGetter arrayGetter( nRowCount, nColCount, valueGetter ); 1507 visitArray( arrayGetter ); 1508 return uno::makeAny( script::ArrayWrapper( false, arrayGetter.getValue() ) ); 1509 } 1510 1511 uno::Any SAL_CALL 1512 ScVbaRange::getValue() 1513 { 1514 // #TODO code within the test below "if ( m_Areas.... " can be removed 1515 // Test is performed only because m_xRange is NOT set to be 1516 // the first range in m_Areas ( to force failure while 1517 // the implementations for each method are being updated ) 1518 if ( m_Areas->getCount() > 1 ) 1519 { 1520 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_QUERY_THROW ); 1521 return xRange->getValue(); 1522 } 1523 1524 CellValueGetter valueGetter; 1525 return getValue( valueGetter ); 1526 1527 } 1528 1529 void 1530 ScVbaRange::setValue( const uno::Any& aValue, ValueSetter& valueSetter ) 1531 { 1532 uno::TypeClass aClass = aValue.getValueTypeClass(); 1533 if ( aClass == uno::TypeClass_SEQUENCE ) 1534 { 1535 const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( mxContext ); 1536 uno::Any aConverted; 1537 try 1538 { 1539 // test for single dimension, could do 1540 // with a better test than this 1541 if ( aValue.getValueTypeName().indexOf('[') == aValue.getValueTypeName().lastIndexOf('[') ) 1542 { 1543 aConverted = xConverter->convertTo( aValue, cppu::UnoType<uno::Sequence< uno::Any >>::get() ); 1544 Dim1ArrayValueSetter setter( aConverted, valueSetter ); 1545 visitArray( setter ); 1546 } 1547 else 1548 { 1549 aConverted = xConverter->convertTo( aValue, cppu::UnoType<uno::Sequence< uno::Sequence< uno::Any > >>::get() ); 1550 Dim2ArrayValueSetter setter( aConverted, valueSetter ); 1551 visitArray( setter ); 1552 } 1553 } 1554 catch ( const uno::Exception& e ) 1555 { 1556 SAL_WARN("sc", "Bahhh, caught " << e ); 1557 } 1558 } 1559 else 1560 { 1561 visitArray( valueSetter ); 1562 } 1563 fireChangeEvent(); 1564 } 1565 1566 void SAL_CALL 1567 ScVbaRange::setValue( const uno::Any &aValue ) 1568 { 1569 // If this is a multiple selection apply setValue over all areas 1570 if ( m_Areas->getCount() > 1 ) 1571 { 1572 AreasVisitor aVisitor( m_Areas ); 1573 RangeValueProcessor valueProcessor( aValue ); 1574 aVisitor.visit( valueProcessor ); 1575 return; 1576 } 1577 CellValueSetter valueSetter( aValue ); 1578 setValue( aValue, valueSetter ); 1579 } 1580 1581 void SAL_CALL 1582 ScVbaRange::Clear() 1583 { 1584 using namespace ::com::sun::star::sheet::CellFlags; 1585 sal_Int32 const nFlags = VALUE | DATETIME | STRING | FORMULA | HARDATTR | EDITATTR | FORMATTED; 1586 ClearContents( nFlags, true ); 1587 } 1588 1589 //helper ClearContent 1590 void 1591 ScVbaRange::ClearContents( sal_Int32 nFlags, bool bFireEvent ) 1592 { 1593 // #TODO code within the test below "if ( m_Areas.... " can be removed 1594 // Test is performed only because m_xRange is NOT set to be 1595 // the first range in m_Areas ( to force failure while 1596 // the implementations for each method are being updated ) 1597 if ( m_Areas->getCount() > 1 ) 1598 { 1599 sal_Int32 nItems = m_Areas->getCount(); 1600 for ( sal_Int32 index=1; index <= nItems; ++index ) 1601 { 1602 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW ); 1603 ScVbaRange* pRange = getImplementation( xRange ); 1604 if ( pRange ) 1605 pRange->ClearContents( nFlags, false ); // do not fire for single ranges 1606 } 1607 // fire change event for the entire range list 1608 if( bFireEvent ) fireChangeEvent(); 1609 return; 1610 } 1611 1612 uno::Reference< sheet::XSheetOperation > xSheetOperation(mxRange, uno::UNO_QUERY_THROW); 1613 xSheetOperation->clearContents( nFlags ); 1614 if( bFireEvent ) fireChangeEvent(); 1615 } 1616 1617 void SAL_CALL 1618 ScVbaRange::ClearComments() 1619 { 1620 ClearContents( sheet::CellFlags::ANNOTATION, false ); 1621 } 1622 1623 void SAL_CALL 1624 ScVbaRange::ClearContents() 1625 { 1626 using namespace ::com::sun::star::sheet::CellFlags; 1627 sal_Int32 const nFlags = VALUE | DATETIME | STRING | FORMULA; 1628 ClearContents( nFlags, true ); 1629 } 1630 1631 void SAL_CALL 1632 ScVbaRange::ClearFormats() 1633 { 1634 // FIXME: need to check if we need to combine FORMATTED 1635 using namespace ::com::sun::star::sheet::CellFlags; 1636 sal_Int32 const nFlags = HARDATTR | FORMATTED | EDITATTR; 1637 ClearContents( nFlags, false ); 1638 } 1639 1640 void 1641 ScVbaRange::setFormulaValue( const uno::Any& rFormula, formula::FormulaGrammar::Grammar eGram ) 1642 { 1643 // If this is a multiple selection apply setFormula over all areas 1644 if ( m_Areas->getCount() > 1 ) 1645 { 1646 AreasVisitor aVisitor( m_Areas ); 1647 RangeFormulaProcessor valueProcessor( rFormula ); 1648 aVisitor.visit( valueProcessor ); 1649 return; 1650 } 1651 CellFormulaValueSetter formulaValueSetter( rFormula, &getScDocument(), eGram ); 1652 setValue( rFormula, formulaValueSetter ); 1653 } 1654 1655 uno::Any 1656 ScVbaRange::getFormulaValue( formula::FormulaGrammar::Grammar eGram ) 1657 { 1658 // #TODO code within the test below "if ( m_Areas.... " can be removed 1659 // Test is performed only because m_xRange is NOT set to be 1660 // the first range in m_Areas ( to force failure while 1661 // the implementations for each method are being updated ) 1662 if ( m_Areas->getCount() > 1 ) 1663 { 1664 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_QUERY_THROW ); 1665 return xRange->getFormula(); 1666 } 1667 CellFormulaValueGetter valueGetter( &getScDocument(), eGram ); 1668 return getValue( valueGetter ); 1669 1670 } 1671 1672 void 1673 ScVbaRange::setFormula(const uno::Any &rFormula ) 1674 { 1675 // #FIXME converting "=$a$1" e.g. CONV_XL_A1 -> CONV_OOO // results in "=$a$1:a1", temporarily disable conversion 1676 setFormulaValue( rFormula,formula::FormulaGrammar::GRAM_NATIVE_XL_A1 ); 1677 } 1678 1679 uno::Any 1680 ScVbaRange::getFormulaR1C1() 1681 { 1682 return getFormulaValue( formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1 ); 1683 } 1684 1685 void 1686 ScVbaRange::setFormulaR1C1(const uno::Any& rFormula ) 1687 { 1688 setFormulaValue( rFormula,formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1 ); 1689 } 1690 1691 uno::Any 1692 ScVbaRange::getFormula() 1693 { 1694 return getFormulaValue( formula::FormulaGrammar::GRAM_NATIVE_XL_A1 ); 1695 } 1696 1697 sal_Int32 1698 ScVbaRange::getCount() 1699 { 1700 // If this is a multiple selection apply setValue over all areas 1701 if ( m_Areas->getCount() > 1 ) 1702 { 1703 AreasVisitor aVisitor( m_Areas ); 1704 RangeCountProcessor valueProcessor; 1705 aVisitor.visit( valueProcessor ); 1706 return valueProcessor.value(); 1707 } 1708 sal_Int32 rowCount = 0; 1709 sal_Int32 colCount = 0; 1710 uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY_THROW ); 1711 rowCount = xColumnRowRange->getRows()->getCount(); 1712 colCount = xColumnRowRange->getColumns()->getCount(); 1713 1714 if( mbIsRows ) 1715 return rowCount; 1716 if( mbIsColumns ) 1717 return colCount; 1718 return rowCount * colCount; 1719 } 1720 1721 sal_Int32 1722 ScVbaRange::getRow() 1723 { 1724 // #TODO code within the test below "if ( m_Areas.... " can be removed 1725 // Test is performed only because m_xRange is NOT set to be 1726 // the first range in m_Areas ( to force failure while 1727 // the implementations for each method are being updated ) 1728 if ( m_Areas->getCount() > 1 ) 1729 { 1730 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_QUERY_THROW ); 1731 return xRange->getRow(); 1732 } 1733 uno::Reference< sheet::XCellAddressable > xCellAddressable(mxRange->getCellByPosition(0, 0), uno::UNO_QUERY_THROW ); 1734 return xCellAddressable->getCellAddress().Row + 1; // Zero value indexing 1735 } 1736 1737 sal_Int32 1738 ScVbaRange::getColumn() 1739 { 1740 // #TODO code within the test below "if ( m_Areas.... " can be removed 1741 // Test is performed only because m_xRange is NOT set to be 1742 // the first range in m_Areas ( to force failure while 1743 // the implementations for each method are being updated ) 1744 if ( m_Areas->getCount() > 1 ) 1745 { 1746 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_QUERY_THROW ); 1747 return xRange->getColumn(); 1748 } 1749 uno::Reference< sheet::XCellAddressable > xCellAddressable(mxRange->getCellByPosition(0, 0), uno::UNO_QUERY_THROW ); 1750 return xCellAddressable->getCellAddress().Column + 1; // Zero value indexing 1751 } 1752 1753 uno::Any 1754 ScVbaRange::HasFormula() 1755 { 1756 if ( m_Areas->getCount() > 1 ) 1757 { 1758 sal_Int32 nItems = m_Areas->getCount(); 1759 uno::Any aResult = aNULL(); 1760 for ( sal_Int32 index=1; index <= nItems; ++index ) 1761 { 1762 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW ); 1763 // if the HasFormula for any area is different to another 1764 // return null 1765 if ( index > 1 ) 1766 if ( aResult != xRange->HasFormula() ) 1767 return aNULL(); 1768 aResult = xRange->HasFormula(); 1769 if ( aNULL() == aResult ) 1770 return aNULL(); 1771 } 1772 return aResult; 1773 } 1774 uno::Reference< uno::XInterface > xIf( mxRange, uno::UNO_QUERY_THROW ); 1775 ScCellRangesBase* pThisRanges = dynamic_cast< ScCellRangesBase * > ( xIf.get() ); 1776 if ( pThisRanges ) 1777 { 1778 uno::Reference<uno::XInterface> xRanges( pThisRanges->queryFormulaCells( sheet::FormulaResult::ERROR | sheet::FormulaResult::VALUE | sheet::FormulaResult::STRING ), uno::UNO_QUERY_THROW ); 1779 ScCellRangesBase* pFormulaRanges = dynamic_cast< ScCellRangesBase * > ( xRanges.get() ); 1780 // check if there are no formula cell, return false 1781 if ( pFormulaRanges->GetRangeList().empty() ) 1782 return uno::makeAny(false); 1783 1784 // check if there are holes (where some cells are not formulas) 1785 // or returned range is not equal to this range 1786 if ( ( pFormulaRanges->GetRangeList().size() > 1 ) 1787 || ( pFormulaRanges->GetRangeList().front().aStart != pThisRanges->GetRangeList().front().aStart ) 1788 || ( pFormulaRanges->GetRangeList().front().aEnd != pThisRanges->GetRangeList().front().aEnd ) 1789 ) 1790 return aNULL(); // should return aNULL; 1791 } 1792 return uno::makeAny( true ); 1793 } 1794 void 1795 ScVbaRange::fillSeries( sheet::FillDirection nFillDirection, sheet::FillMode nFillMode, sheet::FillDateMode nFillDateMode, double fStep, double fEndValue ) 1796 { 1797 if ( m_Areas->getCount() > 1 ) 1798 { 1799 // Multi-Area Range 1800 uno::Reference< XCollection > xCollection( m_Areas, uno::UNO_QUERY_THROW ); 1801 for ( sal_Int32 index = 1; index <= xCollection->getCount(); ++index ) 1802 { 1803 uno::Reference< excel::XRange > xRange( xCollection->Item( uno::makeAny( index ), uno::Any() ), uno::UNO_QUERY_THROW ); 1804 ScVbaRange* pThisRange = getImplementation( xRange ); 1805 pThisRange->fillSeries( nFillDirection, nFillMode, nFillDateMode, fStep, fEndValue ); 1806 1807 } 1808 return; 1809 } 1810 1811 uno::Reference< sheet::XCellSeries > xCellSeries(mxRange, uno::UNO_QUERY_THROW ); 1812 xCellSeries->fillSeries( nFillDirection, nFillMode, nFillDateMode, fStep, fEndValue ); 1813 fireChangeEvent(); 1814 } 1815 1816 void 1817 ScVbaRange::FillLeft() 1818 { 1819 fillSeries(sheet::FillDirection_TO_LEFT, 1820 sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF); 1821 } 1822 1823 void 1824 ScVbaRange::FillRight() 1825 { 1826 fillSeries(sheet::FillDirection_TO_RIGHT, 1827 sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF); 1828 } 1829 1830 void 1831 ScVbaRange::FillUp() 1832 { 1833 fillSeries(sheet::FillDirection_TO_TOP, 1834 sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF); 1835 } 1836 1837 void 1838 ScVbaRange::FillDown() 1839 { 1840 fillSeries(sheet::FillDirection_TO_BOTTOM, 1841 sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF); 1842 } 1843 1844 OUString 1845 ScVbaRange::getText() 1846 { 1847 // #TODO code within the test below "if ( m_Areas.... " can be removed 1848 // Test is performed only because m_xRange is NOT set to be 1849 // the first range in m_Areas ( to force failure while 1850 // the implementations for each method are being updated ) 1851 if ( m_Areas->getCount() > 1 ) 1852 { 1853 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_QUERY_THROW ); 1854 return xRange->getText(); 1855 } 1856 uno::Reference< text::XTextRange > xTextRange(mxRange->getCellByPosition(0,0), uno::UNO_QUERY_THROW ); 1857 return xTextRange->getString(); 1858 } 1859 1860 uno::Reference< excel::XRange > 1861 ScVbaRange::Offset( const ::uno::Any &nRowOff, const uno::Any &nColOff ) 1862 { 1863 SCROW nRowOffset = 0; 1864 SCCOL nColOffset = 0; 1865 bool bIsRowOffset = ( nRowOff >>= nRowOffset ); 1866 bool bIsColumnOffset = ( nColOff >>= nColOffset ); 1867 ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); 1868 1869 ScRangeList aCellRanges = pUnoRangesBase->GetRangeList(); 1870 1871 for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i ) 1872 { 1873 ScRange & rRange = aCellRanges[ i ]; 1874 if ( bIsColumnOffset ) 1875 { 1876 rRange.aStart.SetCol( rRange.aStart.Col() + nColOffset ); 1877 rRange.aEnd.SetCol( rRange.aEnd.Col() + nColOffset ); 1878 } 1879 if ( bIsRowOffset ) 1880 { 1881 rRange.aStart.SetRow( rRange.aStart.Row() + nRowOffset ); 1882 rRange.aEnd.SetRow( rRange.aEnd.Row() + nRowOffset ); 1883 } 1884 } 1885 1886 if ( aCellRanges.size() > 1 ) // Multi-Area 1887 { 1888 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pUnoRangesBase->GetDocShell(), aCellRanges ) ); 1889 return new ScVbaRange( mxParent, mxContext, xRanges ); 1890 } 1891 // normal range 1892 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aCellRanges.front() ) ); 1893 return new ScVbaRange( mxParent, mxContext, xRange ); 1894 } 1895 1896 uno::Reference< excel::XRange > 1897 ScVbaRange::CurrentRegion() 1898 { 1899 // #TODO code within the test below "if ( m_Areas.... " can be removed 1900 // Test is performed only because m_xRange is NOT set to be 1901 // the first range in m_Areas ( to force failure while 1902 // the implementations for each method are being updated ) 1903 if ( m_Areas->getCount() > 1 ) 1904 { 1905 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_QUERY_THROW ); 1906 return xRange->CurrentRegion(); 1907 } 1908 1909 RangeHelper helper( mxRange ); 1910 uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = 1911 helper.getSheetCellCursor(); 1912 xSheetCellCursor->collapseToCurrentRegion(); 1913 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW); 1914 return RangeHelper::createRangeFromRange( mxParent, mxContext, helper.getCellRangeFromSheet(), xCellRangeAddressable ); 1915 } 1916 1917 uno::Reference< excel::XRange > 1918 ScVbaRange::CurrentArray() 1919 { 1920 // #TODO code within the test below "if ( m_Areas.... " can be removed 1921 // Test is performed only because m_xRange is NOT set to be 1922 // the first range in m_Areas ( to force failure while 1923 // the implementations for each method are being updated ) 1924 if ( m_Areas->getCount() > 1 ) 1925 { 1926 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_QUERY_THROW ); 1927 return xRange->CurrentArray(); 1928 } 1929 RangeHelper helper( mxRange ); 1930 uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = 1931 helper.getSheetCellCursor(); 1932 xSheetCellCursor->collapseToCurrentArray(); 1933 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW); 1934 return RangeHelper::createRangeFromRange( mxParent, mxContext, helper.getCellRangeFromSheet(), xCellRangeAddressable ); 1935 } 1936 1937 uno::Any 1938 ScVbaRange::getFormulaArray() 1939 { 1940 // #TODO code within the test below "if ( m_Areas.... " can be removed 1941 // Test is performed only because m_xRange is NOT set to be 1942 // the first range in m_Areas ( to force failure while 1943 // the implementations for each method are being updated ) 1944 if ( m_Areas->getCount() > 1 ) 1945 { 1946 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_QUERY_THROW ); 1947 return xRange->getFormulaArray(); 1948 } 1949 1950 // return a formula if there is one or else an array 1951 // still not sure when the return as array code should run 1952 // ( I think it is if there is more than one formula ) at least 1953 // that is what the doc says ( but I am not even sure how to detect that ) 1954 // for the moment any tests we have pass 1955 uno::Reference< sheet::XArrayFormulaRange> xFormulaArray( mxRange, uno::UNO_QUERY_THROW ); 1956 if ( !xFormulaArray->getArrayFormula().isEmpty() ) 1957 return uno::makeAny( xFormulaArray->getArrayFormula() ); 1958 1959 uno::Reference< sheet::XCellRangeFormula> xCellRangeFormula( mxRange, uno::UNO_QUERY_THROW ); 1960 const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( mxContext ); 1961 uno::Any aSingleValueOrMatrix; 1962 // When dealing with a single element ( embedded in the sequence of sequence ) unwrap and return 1963 // that value 1964 uno::Sequence< uno::Sequence<OUString> > aTmpSeq = xCellRangeFormula->getFormulaArray(); 1965 if ( aTmpSeq.getLength() == 1 ) 1966 { 1967 if ( aTmpSeq[ 0 ].getLength() == 1 ) 1968 aSingleValueOrMatrix <<= aTmpSeq[ 0 ][ 0 ]; 1969 } 1970 else 1971 aSingleValueOrMatrix = xConverter->convertTo( uno::makeAny( aTmpSeq ) , cppu::UnoType<uno::Sequence< uno::Sequence< uno::Any > >>::get() ) ; 1972 return aSingleValueOrMatrix; 1973 } 1974 1975 void 1976 ScVbaRange::setFormulaArray(const uno::Any& rFormula) 1977 { 1978 // #TODO code within the test below "if ( m_Areas.... " can be removed 1979 // Test is performed only because m_xRange is NOT set to be 1980 // the first range in m_Areas ( to force failure while 1981 // the implementations for each method are being updated ) 1982 if ( m_Areas->getCount() > 1 ) 1983 { 1984 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_QUERY_THROW ); 1985 return xRange->setFormulaArray( rFormula ); 1986 } 1987 // #TODO need to distinguish between getFormula and getFormulaArray e.g. (R1C1) 1988 // but for the moment it's just easier to treat them the same for setting 1989 // seems 1990 uno::Reference< lang::XMultiServiceFactory > xModelFactory( getUnoModel(), uno::UNO_QUERY_THROW ); 1991 uno::Reference< sheet::XFormulaParser > xParser( xModelFactory->createInstance( "com.sun.star.sheet.FormulaParser" ), uno::UNO_QUERY_THROW ); 1992 uno::Reference< sheet::XCellRangeAddressable > xSource( mxRange, uno::UNO_QUERY_THROW); 1993 1994 table::CellRangeAddress aRangeAddress = xSource->getRangeAddress(); 1995 // #TODO check if api orders the address 1996 // e.g. do we need to order the RangeAddress to get the topleft ( or can we assume it 1997 // is in the correct order ) 1998 table::CellAddress aAddress; 1999 aAddress.Sheet = aRangeAddress.Sheet; 2000 aAddress.Column = aRangeAddress.StartColumn; 2001 aAddress.Row = aRangeAddress.StartRow; 2002 OUString sFormula; 2003 rFormula >>= sFormula; 2004 uno::Sequence<sheet::FormulaToken> aTokens = xParser->parseFormula( sFormula, aAddress ); 2005 ScTokenArray aTokenArray; 2006 (void)ScTokenConversion::ConvertToTokenArray( getScDocument(), aTokenArray, aTokens ); 2007 2008 getScDocShell()->GetDocFunc().EnterMatrix( getScRangeList()[0], nullptr, &aTokenArray, OUString(), true, true, EMPTY_OUSTRING, formula::FormulaGrammar::GRAM_API ); 2009 } 2010 2011 OUString 2012 ScVbaRange::Characters(const uno::Any& Start, const uno::Any& Length) 2013 { 2014 // #TODO code within the test below "if ( m_Areas.... " can be removed 2015 // Test is performed only because m_xRange is NOT set to be 2016 // the first range in m_Areas ( to force failure while 2017 // the implementations for each method are being updated ) 2018 if ( m_Areas->getCount() > 1 ) 2019 { 2020 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_QUERY_THROW ); 2021 return xRange->Characters( Start, Length ); 2022 } 2023 2024 long nIndex = 0, nCount = 0; 2025 OUString rString; 2026 uno::Reference< text::XTextRange > xTextRange(mxRange, ::uno::UNO_QUERY_THROW ); 2027 rString = xTextRange->getString(); 2028 if( !( Start >>= nIndex ) && !( Length >>= nCount ) ) 2029 return rString; 2030 if(!( Start >>= nIndex ) ) 2031 nIndex = 1; 2032 if(!( Length >>= nCount ) ) 2033 nIndex = rString.getLength(); 2034 return rString.copy( --nIndex, nCount ); // Zero value indexing 2035 } 2036 2037 OUString 2038 ScVbaRange::Address( const uno::Any& RowAbsolute, const uno::Any& ColumnAbsolute, const uno::Any& ReferenceStyle, const uno::Any& External, const uno::Any& RelativeTo ) 2039 { 2040 if ( m_Areas->getCount() > 1 ) 2041 { 2042 // Multi-Area Range 2043 OUStringBuffer sAddress; 2044 uno::Reference< XCollection > xCollection( m_Areas, uno::UNO_QUERY_THROW ); 2045 uno::Any aExternalCopy = External; 2046 for ( sal_Int32 index = 1; index <= xCollection->getCount(); ++index ) 2047 { 2048 uno::Reference< excel::XRange > xRange( xCollection->Item( uno::makeAny( index ), uno::Any() ), uno::UNO_QUERY_THROW ); 2049 if ( index > 1 ) 2050 { 2051 sAddress.append(","); 2052 // force external to be false 2053 // only first address should have the 2054 // document and sheet specifications 2055 aExternalCopy <<= false; 2056 } 2057 sAddress.append(xRange->Address( RowAbsolute, ColumnAbsolute, ReferenceStyle, aExternalCopy, RelativeTo )); 2058 } 2059 return sAddress.makeStringAndClear(); 2060 2061 } 2062 ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 ); 2063 if ( ReferenceStyle.hasValue() ) 2064 { 2065 sal_Int32 refStyle = excel::XlReferenceStyle::xlA1; 2066 ReferenceStyle >>= refStyle; 2067 if ( refStyle == excel::XlReferenceStyle::xlR1C1 ) 2068 dDetails = ScAddress::Details( formula::FormulaGrammar::CONV_XL_R1C1, 0, 0 ); 2069 } 2070 // default 2071 ScRefFlags nFlags = ScRefFlags::RANGE_ABS; 2072 ScDocShell* pDocShell = getScDocShell(); 2073 ScDocument& rDoc = pDocShell->GetDocument(); 2074 2075 RangeHelper thisRange( mxRange ); 2076 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 2077 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 ) ); 2078 ScRefFlags const ROW_ABS = ScRefFlags::ROW_ABS | ScRefFlags::ROW2_ABS; 2079 ScRefFlags const COL_ABS = ScRefFlags::COL_ABS | ScRefFlags::COL2_ABS; 2080 2081 if ( RowAbsolute.hasValue() ) 2082 { 2083 bool bVal = true; 2084 RowAbsolute >>= bVal; 2085 if ( !bVal ) 2086 nFlags &= ~ROW_ABS; 2087 } 2088 if ( ColumnAbsolute.hasValue() ) 2089 { 2090 bool bVal = true; 2091 ColumnAbsolute >>= bVal; 2092 if ( !bVal ) 2093 nFlags &= ~COL_ABS; 2094 } 2095 if ( External.hasValue() ) 2096 { 2097 bool bLocal = false; 2098 External >>= bLocal; 2099 if ( bLocal ) 2100 nFlags |= ScRefFlags::TAB_3D | ScRefFlags::FORCE_DOC; 2101 } 2102 if ( RelativeTo.hasValue() ) 2103 { 2104 // #TODO should I throw an error if R1C1 is not set? 2105 2106 table::CellRangeAddress refAddress = getCellRangeAddressForVBARange( RelativeTo, pDocShell ); 2107 dDetails = ScAddress::Details( formula::FormulaGrammar::CONV_XL_R1C1, static_cast< SCROW >( refAddress.StartRow ), static_cast< SCCOL >( refAddress.StartColumn ) ); 2108 } 2109 return aRange.Format(nFlags, &rDoc, dDetails); 2110 } 2111 2112 uno::Reference < excel::XFont > 2113 ScVbaRange::Font() 2114 { 2115 uno::Reference< beans::XPropertySet > xProps(mxRange, ::uno::UNO_QUERY ); 2116 ScDocument& rDoc = getScDocument(); 2117 if ( mxRange.is() ) 2118 xProps.set(mxRange, ::uno::UNO_QUERY ); 2119 else if ( mxRanges.is() ) 2120 xProps.set(mxRanges, ::uno::UNO_QUERY ); 2121 2122 ScVbaPalette aPalette( rDoc.GetDocumentShell() ); 2123 ScCellRangeObj* pRangeObj = nullptr; 2124 try 2125 { 2126 pRangeObj = getCellRangeObj(); 2127 } 2128 catch( uno::Exception& ) 2129 { 2130 } 2131 return new ScVbaFont( this, mxContext, aPalette, xProps, pRangeObj ); 2132 } 2133 2134 uno::Reference< excel::XRange > 2135 ScVbaRange::Cells( const uno::Any &nRowIndex, const uno::Any &nColumnIndex ) 2136 { 2137 // #TODO code within the test below "if ( m_Areas.... " can be removed 2138 // Test is performed only because m_xRange is NOT set to be 2139 // the first range in m_Areas ( to force failure while 2140 // the implementations for each method are being updated ) 2141 if ( m_Areas->getCount() > 1 ) 2142 { 2143 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_QUERY_THROW ); 2144 return xRange->Cells( nRowIndex, nColumnIndex ); 2145 } 2146 2147 // Performance: Use a common helper method for ScVbaRange::Cells and ScVbaWorksheet::Cells, 2148 // instead of creating a new ScVbaRange object in often-called ScVbaWorksheet::Cells 2149 return CellsHelper( mxParent, mxContext, mxRange, nRowIndex, nColumnIndex ); 2150 } 2151 2152 // static 2153 uno::Reference< excel::XRange > 2154 ScVbaRange::CellsHelper( const uno::Reference< ov::XHelperInterface >& xParent, 2155 const uno::Reference< uno::XComponentContext >& xContext, 2156 const uno::Reference< css::table::XCellRange >& xRange, 2157 const uno::Any &nRowIndex, const uno::Any &nColumnIndex ) 2158 { 2159 sal_Int32 nRow = 0, nColumn = 0; 2160 2161 bool bIsIndex = nRowIndex.hasValue(); 2162 bool bIsColumnIndex = nColumnIndex.hasValue(); 2163 2164 // Sometimes we might get a float or a double or whatever 2165 // set in the Any, we should convert as appropriate 2166 // #FIXME - perhaps worth turning this into some sort of 2167 // conversion routine e.g. bSuccess = getValueFromAny( nRow, nRowIndex, cppu::UnoType<sal_Int32>::get() ) 2168 if ( nRowIndex.hasValue() && !( nRowIndex >>= nRow ) ) 2169 { 2170 const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( xContext ); 2171 uno::Any aConverted; 2172 try 2173 { 2174 aConverted = xConverter->convertTo( nRowIndex, cppu::UnoType<sal_Int32>::get() ); 2175 bIsIndex = ( aConverted >>= nRow ); 2176 } 2177 catch( uno::Exception& ) {} // silence any errors 2178 } 2179 2180 if ( bIsColumnIndex ) 2181 { 2182 // Column index can be a col address e.g Cells( 1, "B" ) etc. 2183 OUString sCol; 2184 if ( nColumnIndex >>= sCol ) 2185 { 2186 ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 ); 2187 ScRange tmpRange; 2188 ScRefFlags flags = tmpRange.ParseCols( sCol, dDetails ); 2189 if ( (flags & ScRefFlags::COL_VALID) == ScRefFlags::ZERO ) 2190 throw uno::RuntimeException(); 2191 nColumn = tmpRange.aStart.Col() + 1; 2192 } 2193 else 2194 { 2195 if ( !( nColumnIndex >>= nColumn ) ) 2196 { 2197 const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( xContext ); 2198 uno::Any aConverted; 2199 try 2200 { 2201 aConverted = xConverter->convertTo( nColumnIndex, cppu::UnoType<sal_Int32>::get() ); 2202 bIsColumnIndex = ( aConverted >>= nColumn ); 2203 } 2204 catch( uno::Exception& ) {} // silence any errors 2205 } 2206 } 2207 } 2208 RangeHelper thisRange( xRange ); 2209 table::CellRangeAddress thisRangeAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 2210 uno::Reference< table::XCellRange > xSheetRange = thisRange.getCellRangeFromSheet(); 2211 if( !bIsIndex && !bIsColumnIndex ) // .Cells 2212 // #FIXE needs proper parent ( Worksheet ) 2213 return uno::Reference< excel::XRange >( new ScVbaRange( xParent, xContext, xRange ) ); 2214 2215 sal_Int32 nIndex = --nRow; 2216 if( bIsIndex && !bIsColumnIndex ) // .Cells(n) 2217 { 2218 uno::Reference< table::XColumnRowRange > xColumnRowRange(xRange, ::uno::UNO_QUERY_THROW); 2219 sal_Int32 nColCount = xColumnRowRange->getColumns()->getCount(); 2220 2221 if ( !nIndex || nIndex < 0 ) 2222 nRow = 0; 2223 else 2224 nRow = nIndex / nColCount; 2225 nColumn = nIndex % nColCount; 2226 } 2227 else 2228 --nColumn; 2229 nRow = nRow + thisRangeAddress.StartRow; 2230 nColumn = nColumn + thisRangeAddress.StartColumn; 2231 return new ScVbaRange( xParent, xContext, xSheetRange->getCellRangeByPosition( nColumn, nRow, nColumn, nRow ) ); 2232 } 2233 2234 void 2235 ScVbaRange::Select() 2236 { 2237 ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); 2238 if ( !pUnoRangesBase ) 2239 throw uno::RuntimeException("Failed to access underlying uno range object" ); 2240 ScDocShell* pShell = pUnoRangesBase->GetDocShell(); 2241 if ( pShell ) 2242 { 2243 uno::Reference< frame::XModel > xModel( pShell->GetModel(), uno::UNO_QUERY_THROW ); 2244 uno::Reference< view::XSelectionSupplier > xSelection( xModel->getCurrentController(), uno::UNO_QUERY_THROW ); 2245 if ( mxRanges.is() ) 2246 xSelection->select( uno::Any( lclExpandToMerged( mxRanges ) ) ); 2247 else 2248 xSelection->select( uno::Any( lclExpandToMerged( mxRange, true ) ) ); 2249 // set focus on document e.g. 2250 // ThisComponent.CurrentController.Frame.getContainerWindow.SetFocus 2251 try 2252 { 2253 uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_QUERY_THROW ); 2254 uno::Reference< frame::XFrame > xFrame( xController->getFrame(), uno::UNO_QUERY_THROW ); 2255 uno::Reference< awt::XWindow > xWin( xFrame->getContainerWindow(), uno::UNO_QUERY_THROW ); 2256 xWin->setFocus(); 2257 } 2258 catch( uno::Exception& ) 2259 { 2260 } 2261 } 2262 } 2263 2264 static bool cellInRange( const table::CellRangeAddress& rAddr, sal_Int32 nCol, sal_Int32 nRow ) 2265 { 2266 return nCol >= rAddr.StartColumn && nCol <= rAddr.EndColumn && 2267 nRow >= rAddr.StartRow && nRow <= rAddr.EndRow; 2268 } 2269 2270 static void setCursor( SCCOL nCol, SCROW nRow, const uno::Reference< frame::XModel >& xModel, bool bInSel = true ) 2271 { 2272 ScTabViewShell* pShell = excel::getBestViewShell( xModel ); 2273 if ( pShell ) 2274 { 2275 if ( bInSel ) 2276 pShell->SetCursor( nCol, nRow ); 2277 else 2278 pShell->MoveCursorAbs( nCol, nRow, SC_FOLLOW_NONE, false, false, true ); 2279 } 2280 } 2281 2282 void 2283 ScVbaRange::Activate() 2284 { 2285 // get first cell of current range 2286 uno::Reference< table::XCellRange > xCellRange; 2287 if ( mxRanges.is() ) 2288 { 2289 uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); 2290 xCellRange.set( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW ); 2291 } 2292 else 2293 xCellRange.set( mxRange, uno::UNO_QUERY_THROW ); 2294 2295 RangeHelper thisRange( xCellRange ); 2296 uno::Reference< sheet::XCellRangeAddressable > xThisRangeAddress = thisRange.getCellRangeAddressable(); 2297 table::CellRangeAddress thisRangeAddress = xThisRangeAddress->getRangeAddress(); 2298 uno::Reference< frame::XModel > xModel; 2299 ScDocShell* pShell = getScDocShell(); 2300 2301 if ( pShell ) 2302 xModel = pShell->GetModel(); 2303 2304 if ( !xModel.is() ) 2305 throw uno::RuntimeException(); 2306 2307 // get current selection 2308 uno::Reference< sheet::XCellRangeAddressable > xRange( xModel->getCurrentSelection(), ::uno::UNO_QUERY); 2309 2310 uno::Reference< sheet::XSheetCellRanges > xRanges( xModel->getCurrentSelection(), ::uno::UNO_QUERY); 2311 2312 if ( xRanges.is() ) 2313 { 2314 uno::Sequence< table::CellRangeAddress > nAddrs = xRanges->getRangeAddresses(); 2315 for ( sal_Int32 index = 0; index < nAddrs.getLength(); ++index ) 2316 { 2317 if ( cellInRange( nAddrs[index], thisRangeAddress.StartColumn, thisRangeAddress.StartRow ) ) 2318 { 2319 setCursor( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), xModel ); 2320 return; 2321 } 2322 2323 } 2324 } 2325 2326 if ( xRange.is() && cellInRange( xRange->getRangeAddress(), thisRangeAddress.StartColumn, thisRangeAddress.StartRow ) ) 2327 setCursor( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), xModel ); 2328 else 2329 { 2330 // if this range is multi cell select the range other 2331 // wise just position the cell at this single range position 2332 if ( isSingleCellRange() ) 2333 // This top-leftmost cell of this Range is not in the current 2334 // selection so just select this range 2335 setCursor( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), xModel, false ); 2336 else 2337 Select(); 2338 } 2339 2340 } 2341 2342 uno::Reference< excel::XRange > 2343 ScVbaRange::Rows(const uno::Any& aIndex ) 2344 { 2345 OUString sAddress; 2346 2347 if ( aIndex.hasValue() ) 2348 { 2349 sal_Int32 nValue = 0; 2350 ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); 2351 ScRangeList aCellRanges = pUnoRangesBase->GetRangeList(); 2352 2353 ScRange aRange = aCellRanges.front(); 2354 if( aIndex >>= nValue ) 2355 { 2356 aRange.aStart.SetRow( aRange.aStart.Row() + --nValue ); 2357 aRange.aEnd.SetRow( aRange.aStart.Row() ); 2358 } 2359 else if ( aIndex >>= sAddress ) 2360 { 2361 ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 ); 2362 ScRange tmpRange; 2363 tmpRange.ParseRows( sAddress, dDetails ); 2364 SCROW nStartRow = tmpRange.aStart.Row(); 2365 SCROW nEndRow = tmpRange.aEnd.Row(); 2366 2367 aRange.aStart.SetRow( aRange.aStart.Row() + nStartRow ); 2368 aRange.aEnd.SetRow( aRange.aStart.Row() + ( nEndRow - nStartRow )); 2369 } 2370 else 2371 throw uno::RuntimeException("Illegal param" ); 2372 2373 if ( aRange.aStart.Row() < 0 || aRange.aEnd.Row() < 0 ) 2374 throw uno::RuntimeException("Internal failure, illegal param" ); 2375 // return a normal range ( even for multi-selection 2376 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange ) ); 2377 return new ScVbaRange( mxParent, mxContext, xRange, true ); 2378 } 2379 // Rows() - no params 2380 if ( m_Areas->getCount() > 1 ) 2381 return new ScVbaRange( mxParent, mxContext, mxRanges, true ); 2382 return new ScVbaRange( mxParent, mxContext, mxRange, true ); 2383 } 2384 2385 uno::Reference< excel::XRange > 2386 ScVbaRange::Columns(const uno::Any& aIndex ) 2387 { 2388 OUString sAddress; 2389 2390 ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); 2391 ScRangeList aCellRanges = pUnoRangesBase->GetRangeList(); 2392 2393 ScRange aRange = aCellRanges.front(); 2394 if ( aIndex.hasValue() ) 2395 { 2396 sal_Int32 nValue = 0; 2397 if ( aIndex >>= nValue ) 2398 { 2399 aRange.aStart.SetCol( aRange.aStart.Col() + static_cast< SCCOL > ( --nValue ) ); 2400 aRange.aEnd.SetCol( aRange.aStart.Col() ); 2401 } 2402 2403 else if ( aIndex >>= sAddress ) 2404 { 2405 ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 ); 2406 ScRange tmpRange; 2407 tmpRange.ParseCols( sAddress, dDetails ); 2408 SCCOL nStartCol = tmpRange.aStart.Col(); 2409 SCCOL nEndCol = tmpRange.aEnd.Col(); 2410 2411 aRange.aStart.SetCol( aRange.aStart.Col() + nStartCol ); 2412 aRange.aEnd.SetCol( aRange.aStart.Col() + ( nEndCol - nStartCol )); 2413 } 2414 else 2415 throw uno::RuntimeException("Illegal param" ); 2416 2417 if ( aRange.aStart.Col() < 0 || aRange.aEnd.Col() < 0 ) 2418 throw uno::RuntimeException("Internal failure, illegal param" ); 2419 } 2420 // Columns() - no params 2421 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange ) ); 2422 return new ScVbaRange( mxParent, mxContext, xRange, false, true ); 2423 } 2424 2425 void 2426 ScVbaRange::setMergeCells( const uno::Any& aIsMerged ) 2427 { 2428 bool bMerge = extractBoolFromAny( aIsMerged ); 2429 2430 if( mxRanges.is() ) 2431 { 2432 sal_Int32 nCount = mxRanges->getCount(); 2433 2434 // VBA does nothing (no error) if the own ranges overlap somehow 2435 ::std::vector< table::CellRangeAddress > aList; 2436 for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) 2437 { 2438 uno::Reference< sheet::XCellRangeAddressable > xRangeAddr( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); 2439 table::CellRangeAddress aAddress = xRangeAddr->getRangeAddress(); 2440 if (std::any_of(aList.begin(), aList.end(), 2441 [&aAddress](const table::CellRangeAddress& rAddress) 2442 { return ScUnoConversion::Intersects( rAddress, aAddress ); })) 2443 return; 2444 aList.push_back( aAddress ); 2445 } 2446 2447 // (un)merge every range after it has been extended to intersecting merged ranges from sheet 2448 for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) 2449 { 2450 uno::Reference< table::XCellRange > xRange( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); 2451 lclExpandAndMerge( xRange, bMerge ); 2452 } 2453 return; 2454 } 2455 2456 // otherwise, merge single range 2457 lclExpandAndMerge( mxRange, bMerge ); 2458 } 2459 2460 uno::Any 2461 ScVbaRange::getMergeCells() 2462 { 2463 if( mxRanges.is() ) 2464 { 2465 sal_Int32 nCount = mxRanges->getCount(); 2466 for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) 2467 { 2468 uno::Reference< table::XCellRange > xRange( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW ); 2469 util::TriState eMerged = lclGetMergedState( xRange ); 2470 /* Excel always returns NULL, if one range of the range list is 2471 partly or completely merged. Even if all ranges are completely 2472 merged, the return value is still NULL. */ 2473 if( eMerged != util::TriState_NO ) 2474 return aNULL(); 2475 } 2476 // no range is merged anyhow, return false 2477 return uno::Any( false ); 2478 } 2479 2480 // otherwise, check single range 2481 switch( lclGetMergedState( mxRange ) ) 2482 { 2483 case util::TriState_YES: return uno::Any( true ); 2484 case util::TriState_NO: return uno::Any( false ); 2485 default: return aNULL(); 2486 } 2487 } 2488 2489 void 2490 ScVbaRange::Copy(const ::uno::Any& Destination) 2491 { 2492 if ( Destination.hasValue() ) 2493 { 2494 // TODO copy with multiple selections should work here too 2495 if ( m_Areas->getCount() > 1 ) 2496 throw uno::RuntimeException("That command cannot be used on multiple selections" ); 2497 uno::Reference< excel::XRange > xRange( Destination, uno::UNO_QUERY_THROW ); 2498 uno::Any aRange = xRange->getCellRange(); 2499 uno::Reference< table::XCellRange > xCellRange; 2500 aRange >>= xCellRange; 2501 uno::Reference< sheet::XSheetCellRange > xSheetCellRange(xCellRange, ::uno::UNO_QUERY_THROW); 2502 uno::Reference< sheet::XSpreadsheet > xSheet = xSheetCellRange->getSpreadsheet(); 2503 uno::Reference< table::XCellRange > xDest( xSheet, uno::UNO_QUERY_THROW ); 2504 uno::Reference< sheet::XCellRangeMovement > xMover( xSheet, uno::UNO_QUERY_THROW); 2505 uno::Reference< sheet::XCellAddressable > xDestination( xDest->getCellByPosition( 2506 xRange->getColumn()-1,xRange->getRow()-1), uno::UNO_QUERY_THROW ); 2507 uno::Reference< sheet::XCellRangeAddressable > xSource( mxRange, uno::UNO_QUERY); 2508 xMover->copyRange( xDestination->getCellAddress(), xSource->getRangeAddress() ); 2509 if ( ScVbaRange* pRange = getImplementation( xRange ) ) 2510 pRange->fireChangeEvent(); 2511 } 2512 else 2513 { 2514 excel::implnCopy( getUnoModel() ); 2515 } 2516 } 2517 2518 void 2519 ScVbaRange::Cut(const ::uno::Any& Destination) 2520 { 2521 if ( m_Areas->getCount() > 1 ) 2522 throw uno::RuntimeException("That command cannot be used on multiple selections" ); 2523 if (Destination.hasValue()) 2524 { 2525 uno::Reference< excel::XRange > xRange( Destination, uno::UNO_QUERY_THROW ); 2526 uno::Reference< table::XCellRange > xCellRange( xRange->getCellRange(), uno::UNO_QUERY_THROW ); 2527 uno::Reference< sheet::XSheetCellRange > xSheetCellRange(xCellRange, ::uno::UNO_QUERY_THROW ); 2528 uno::Reference< sheet::XSpreadsheet > xSheet = xSheetCellRange->getSpreadsheet(); 2529 uno::Reference< table::XCellRange > xDest( xSheet, uno::UNO_QUERY_THROW ); 2530 uno::Reference< sheet::XCellRangeMovement > xMover( xSheet, uno::UNO_QUERY_THROW); 2531 uno::Reference< sheet::XCellAddressable > xDestination( xDest->getCellByPosition( 2532 xRange->getColumn()-1,xRange->getRow()-1), uno::UNO_QUERY); 2533 uno::Reference< sheet::XCellRangeAddressable > xSource( mxRange, uno::UNO_QUERY); 2534 xMover->moveRange( xDestination->getCellAddress(), xSource->getRangeAddress() ); 2535 } 2536 else 2537 { 2538 uno::Reference< frame::XModel > xModel = getModelFromRange( mxRange ); 2539 Select(); 2540 excel::implnCut( xModel ); 2541 } 2542 } 2543 2544 void 2545 ScVbaRange::setNumberFormat( const uno::Any& aFormat ) 2546 { 2547 OUString sFormat; 2548 aFormat >>= sFormat; 2549 if ( m_Areas->getCount() > 1 ) 2550 { 2551 sal_Int32 nItems = m_Areas->getCount(); 2552 for ( sal_Int32 index=1; index <= nItems; ++index ) 2553 { 2554 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW ); 2555 xRange->setNumberFormat( aFormat ); 2556 } 2557 return; 2558 } 2559 NumFormatHelper numFormat( mxRange ); 2560 numFormat.setNumberFormat( sFormat ); 2561 } 2562 2563 uno::Any 2564 ScVbaRange::getNumberFormat() 2565 { 2566 2567 if ( m_Areas->getCount() > 1 ) 2568 { 2569 sal_Int32 nItems = m_Areas->getCount(); 2570 uno::Any aResult = aNULL(); 2571 for ( sal_Int32 index=1; index <= nItems; ++index ) 2572 { 2573 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW ); 2574 // if the numberformat of one area is different to another 2575 // return null 2576 if ( index > 1 ) 2577 if ( aResult != xRange->getNumberFormat() ) 2578 return aNULL(); 2579 aResult = xRange->getNumberFormat(); 2580 if ( aNULL() == aResult ) 2581 return aNULL(); 2582 } 2583 return aResult; 2584 } 2585 NumFormatHelper numFormat( mxRange ); 2586 OUString sFormat = numFormat.getNumberFormatString(); 2587 if ( !sFormat.isEmpty() ) 2588 return uno::makeAny( sFormat ); 2589 return aNULL(); 2590 } 2591 2592 uno::Reference< excel::XRange > 2593 ScVbaRange::Resize( const uno::Any &RowSize, const uno::Any &ColumnSize ) 2594 { 2595 long nRowSize = 0, nColumnSize = 0; 2596 bool bIsRowChanged = ( RowSize >>= nRowSize ), bIsColumnChanged = ( ColumnSize >>= nColumnSize ); 2597 uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, ::uno::UNO_QUERY_THROW); 2598 uno::Reference< sheet::XSheetCellRange > xSheetRange(mxRange, ::uno::UNO_QUERY_THROW); 2599 uno::Reference< sheet::XSheetCellCursor > xCursor( xSheetRange->getSpreadsheet()->createCursorByRange(xSheetRange), ::uno::UNO_QUERY_THROW ); 2600 2601 if( !bIsRowChanged ) 2602 nRowSize = xColumnRowRange->getRows()->getCount(); 2603 if( !bIsColumnChanged ) 2604 nColumnSize = xColumnRowRange->getColumns()->getCount(); 2605 2606 xCursor->collapseToSize( nColumnSize, nRowSize ); 2607 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xCursor, ::uno::UNO_QUERY_THROW ); 2608 uno::Reference< table::XCellRange > xRange( xSheetRange->getSpreadsheet(), ::uno::UNO_QUERY_THROW ); 2609 return new ScVbaRange( mxParent, mxContext,xRange->getCellRangeByPosition( 2610 xCellRangeAddressable->getRangeAddress().StartColumn, 2611 xCellRangeAddressable->getRangeAddress().StartRow, 2612 xCellRangeAddressable->getRangeAddress().EndColumn, 2613 xCellRangeAddressable->getRangeAddress().EndRow ) ); 2614 } 2615 2616 void 2617 ScVbaRange::setWrapText( const uno::Any& aIsWrapped ) 2618 { 2619 if ( m_Areas->getCount() > 1 ) 2620 { 2621 sal_Int32 nItems = m_Areas->getCount(); 2622 for ( sal_Int32 index=1; index <= nItems; ++index ) 2623 { 2624 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW ); 2625 xRange->setWrapText( aIsWrapped ); 2626 } 2627 return; 2628 } 2629 2630 uno::Reference< beans::XPropertySet > xProps(mxRange, ::uno::UNO_QUERY_THROW ); 2631 bool bIsWrapped = extractBoolFromAny( aIsWrapped ); 2632 xProps->setPropertyValue( "IsTextWrapped", uno::Any( bIsWrapped ) ); 2633 } 2634 2635 uno::Any 2636 ScVbaRange::getWrapText() 2637 { 2638 if ( m_Areas->getCount() > 1 ) 2639 { 2640 sal_Int32 nItems = m_Areas->getCount(); 2641 uno::Any aResult; 2642 for ( sal_Int32 index=1; index <= nItems; ++index ) 2643 { 2644 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW ); 2645 if ( index > 1 ) 2646 if ( aResult != xRange->getWrapText() ) 2647 return aNULL(); 2648 aResult = xRange->getWrapText(); 2649 } 2650 return aResult; 2651 } 2652 2653 SfxItemSet* pDataSet = getCurrentDataSet(); 2654 2655 SfxItemState eState = pDataSet->GetItemState( ATTR_LINEBREAK); 2656 if ( eState == SfxItemState::DONTCARE ) 2657 return aNULL(); 2658 2659 uno::Reference< beans::XPropertySet > xProps(mxRange, ::uno::UNO_QUERY_THROW ); 2660 uno::Any aValue = xProps->getPropertyValue( "IsTextWrapped" ); 2661 return aValue; 2662 } 2663 2664 uno::Reference< excel::XInterior > ScVbaRange::Interior( ) 2665 { 2666 uno::Reference< beans::XPropertySet > xProps( mxRange, uno::UNO_QUERY_THROW ); 2667 return new ScVbaInterior ( this, mxContext, xProps, &getScDocument() ); 2668 } 2669 uno::Reference< excel::XRange > 2670 ScVbaRange::Range( const uno::Any &Cell1, const uno::Any &Cell2 ) 2671 { 2672 return Range( Cell1, Cell2, false ); 2673 } 2674 uno::Reference< excel::XRange > 2675 ScVbaRange::Range( const uno::Any &Cell1, const uno::Any &Cell2, bool bForceUseInpuRangeTab ) 2676 2677 { 2678 uno::Reference< table::XCellRange > xCellRange = mxRange; 2679 2680 if ( m_Areas->getCount() > 1 ) 2681 { 2682 uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW ); 2683 xCellRange.set( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW ); 2684 } 2685 else 2686 xCellRange.set( mxRange ); 2687 2688 RangeHelper thisRange( xCellRange ); 2689 uno::Reference< table::XCellRange > xRanges = thisRange.getCellRangeFromSheet(); 2690 uno::Reference< sheet::XCellRangeAddressable > xAddressable( xRanges, uno::UNO_QUERY_THROW ); 2691 2692 uno::Reference< table::XCellRange > xReferrer = 2693 xRanges->getCellRangeByPosition( getColumn()-1, getRow()-1, 2694 xAddressable->getRangeAddress().EndColumn, 2695 xAddressable->getRangeAddress().EndRow ); 2696 // xAddressable now for this range 2697 xAddressable.set( xReferrer, uno::UNO_QUERY_THROW ); 2698 2699 if( !Cell1.hasValue() ) 2700 throw uno::RuntimeException( "Invalid Argument" ); 2701 2702 table::CellRangeAddress resultAddress; 2703 table::CellRangeAddress parentRangeAddress = xAddressable->getRangeAddress(); 2704 2705 ScRange aRange; 2706 // Cell1 defined only 2707 if ( !Cell2.hasValue() ) 2708 { 2709 OUString sName; 2710 Cell1 >>= sName; 2711 RangeHelper referRange( xReferrer ); 2712 table::CellRangeAddress referAddress = referRange.getCellRangeAddressable()->getRangeAddress(); 2713 return getRangeForName( mxContext, sName, getScDocShell(), referAddress ); 2714 2715 } 2716 else 2717 { 2718 table::CellRangeAddress cell1, cell2; 2719 cell1 = getCellRangeAddressForVBARange( Cell1, getScDocShell() ); 2720 // Cell1 & Cell2 defined 2721 // Excel seems to combine the range as the range defined by 2722 // the combination of Cell1 & Cell2 2723 2724 cell2 = getCellRangeAddressForVBARange( Cell2, getScDocShell() ); 2725 2726 resultAddress.StartColumn = ( cell1.StartColumn < cell2.StartColumn ) ? cell1.StartColumn : cell2.StartColumn; 2727 resultAddress.StartRow = ( cell1.StartRow < cell2.StartRow ) ? cell1.StartRow : cell2.StartRow; 2728 resultAddress.EndColumn = std::max( cell1.EndColumn, cell2.EndColumn ); 2729 resultAddress.EndRow = std::max( cell1.EndRow, cell2.EndRow ); 2730 if ( bForceUseInpuRangeTab ) 2731 { 2732 // this is a call from Application.Range( x,y ) 2733 // it's possible for x or y to specify a different sheet from 2734 // the current or active on ( but they must be the same ) 2735 if ( cell1.Sheet != cell2.Sheet ) 2736 throw uno::RuntimeException(); 2737 parentRangeAddress.Sheet = cell1.Sheet; 2738 } 2739 else 2740 { 2741 // this is not a call from Application.Range( x,y ) 2742 // if a different sheet from this range is specified it's 2743 // an error 2744 if ( parentRangeAddress.Sheet != cell1.Sheet 2745 || parentRangeAddress.Sheet != cell2.Sheet 2746 ) 2747 throw uno::RuntimeException(); 2748 2749 } 2750 ScUnoConversion::FillScRange( aRange, resultAddress ); 2751 } 2752 ScRange parentAddress; 2753 ScUnoConversion::FillScRange( parentAddress, parentRangeAddress); 2754 if ( aRange.aStart.Col() >= 0 && aRange.aStart.Row() >= 0 && aRange.aEnd.Col() >= 0 && aRange.aEnd.Row() >= 0 ) 2755 { 2756 sal_Int32 nStartX = parentAddress.aStart.Col() + aRange.aStart.Col(); 2757 sal_Int32 nStartY = parentAddress.aStart.Row() + aRange.aStart.Row(); 2758 sal_Int32 nEndX = parentAddress.aStart.Col() + aRange.aEnd.Col(); 2759 sal_Int32 nEndY = parentAddress.aStart.Row() + aRange.aEnd.Row(); 2760 2761 if ( nStartX <= nEndX && nEndX <= parentAddress.aEnd.Col() && 2762 nStartY <= nEndY && nEndY <= parentAddress.aEnd.Row() ) 2763 { 2764 ScRange aNew( static_cast<SCCOL>(nStartX), static_cast<SCROW>(nStartY), parentAddress.aStart.Tab(), 2765 static_cast<SCCOL>(nEndX), static_cast<SCROW>(nEndY), parentAddress.aEnd.Tab() ); 2766 xCellRange = new ScCellRangeObj( getScDocShell(), aNew ); 2767 } 2768 } 2769 2770 return new ScVbaRange( mxParent, mxContext, xCellRange ); 2771 2772 } 2773 2774 // Allow access to underlying openoffice uno api ( useful for debugging 2775 // with openoffice basic ) 2776 uno::Any SAL_CALL ScVbaRange::getCellRange( ) 2777 { 2778 uno::Any aAny; 2779 if ( mxRanges.is() ) 2780 aAny <<= mxRanges; 2781 else if ( mxRange.is() ) 2782 aAny <<= mxRange; 2783 return aAny; 2784 } 2785 2786 uno::Any ScVbaRange::getCellRange( const uno::Reference< excel::XRange >& rxRange ) 2787 { 2788 if( ScVbaRange* pVbaRange = getImplementation( rxRange ) ) 2789 return pVbaRange->getCellRange(); 2790 throw uno::RuntimeException(); 2791 } 2792 2793 static InsertDeleteFlags getPasteFlags (sal_Int32 Paste) 2794 { 2795 InsertDeleteFlags nFlags = InsertDeleteFlags::NONE; 2796 switch (Paste) { 2797 case excel::XlPasteType::xlPasteComments: 2798 nFlags = InsertDeleteFlags::NOTE;break; 2799 case excel::XlPasteType::xlPasteFormats: 2800 nFlags = InsertDeleteFlags::ATTRIB;break; 2801 case excel::XlPasteType::xlPasteFormulas: 2802 nFlags = InsertDeleteFlags::FORMULA;break; 2803 case excel::XlPasteType::xlPasteFormulasAndNumberFormats : 2804 case excel::XlPasteType::xlPasteValues: 2805 nFlags = ( InsertDeleteFlags::VALUE | InsertDeleteFlags::DATETIME | InsertDeleteFlags::STRING | InsertDeleteFlags::SPECIAL_BOOLEAN ); break; 2806 case excel::XlPasteType::xlPasteValuesAndNumberFormats: 2807 nFlags = InsertDeleteFlags::VALUE | InsertDeleteFlags::ATTRIB; break; 2808 case excel::XlPasteType::xlPasteColumnWidths: 2809 case excel::XlPasteType::xlPasteValidation: 2810 nFlags = InsertDeleteFlags::NONE;break; 2811 case excel::XlPasteType::xlPasteAll: 2812 case excel::XlPasteType::xlPasteAllExceptBorders: 2813 default: 2814 nFlags = InsertDeleteFlags::ALL;break; 2815 } 2816 return nFlags; 2817 } 2818 2819 static ScPasteFunc 2820 getPasteFormulaBits( sal_Int32 Operation) 2821 { 2822 ScPasteFunc nFormulaBits = ScPasteFunc::NONE; 2823 switch (Operation) 2824 { 2825 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationAdd: 2826 nFormulaBits = ScPasteFunc::ADD; break; 2827 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationSubtract: 2828 nFormulaBits = ScPasteFunc::SUB;break; 2829 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationMultiply: 2830 nFormulaBits = ScPasteFunc::MUL;break; 2831 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationDivide: 2832 nFormulaBits = ScPasteFunc::DIV;break; 2833 2834 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationNone: 2835 default: 2836 nFormulaBits = ScPasteFunc::NONE; break; 2837 } 2838 2839 return nFormulaBits; 2840 } 2841 void SAL_CALL 2842 ScVbaRange::PasteSpecial( const uno::Any& Paste, const uno::Any& Operation, const uno::Any& SkipBlanks, const uno::Any& Transpose ) 2843 { 2844 if ( m_Areas->getCount() > 1 ) 2845 throw uno::RuntimeException("That command cannot be used on multiple selections" ); 2846 ScDocShell* pShell = getScDocShell(); 2847 2848 if (!pShell) 2849 throw uno::RuntimeException("That command cannot be used with no ScDocShell" ); 2850 2851 uno::Reference< frame::XModel > xModel(pShell->GetModel(), uno::UNO_QUERY_THROW); 2852 uno::Reference< view::XSelectionSupplier > xSelection( xModel->getCurrentController(), uno::UNO_QUERY_THROW ); 2853 // select this range 2854 xSelection->select( uno::makeAny( mxRange ) ); 2855 // set up defaults 2856 sal_Int32 nPaste = excel::XlPasteType::xlPasteAll; 2857 sal_Int32 nOperation = excel::XlPasteSpecialOperation::xlPasteSpecialOperationNone; 2858 bool bTranspose = false; 2859 bool bSkipBlanks = false; 2860 2861 if ( Paste.hasValue() ) 2862 Paste >>= nPaste; 2863 if ( Operation.hasValue() ) 2864 Operation >>= nOperation; 2865 if ( SkipBlanks.hasValue() ) 2866 SkipBlanks >>= bSkipBlanks; 2867 if ( Transpose.hasValue() ) 2868 Transpose >>= bTranspose; 2869 2870 InsertDeleteFlags nFlags = getPasteFlags(nPaste); 2871 ScPasteFunc nFormulaBits = getPasteFormulaBits(nOperation); 2872 excel::implnPasteSpecial(pShell->GetModel(), nFlags,nFormulaBits,bSkipBlanks,bTranspose); 2873 } 2874 2875 uno::Reference< excel::XRange > 2876 ScVbaRange::getEntireColumnOrRow( bool bColumn ) 2877 { 2878 ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); 2879 // copy the range list 2880 ScRangeList aCellRanges = pUnoRangesBase->GetRangeList(); 2881 2882 for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i ) 2883 { 2884 ScRange & rRange = aCellRanges[ i ]; 2885 if ( bColumn ) 2886 { 2887 rRange.aStart.SetRow( 0 ); 2888 rRange.aEnd.SetRow( MAXROW ); 2889 } 2890 else 2891 { 2892 rRange.aStart.SetCol( 0 ); 2893 rRange.aEnd.SetCol( MAXCOL ); 2894 } 2895 } 2896 if ( aCellRanges.size() > 1 ) // Multi-Area 2897 { 2898 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pUnoRangesBase->GetDocShell(), aCellRanges ) ); 2899 2900 return new ScVbaRange( mxParent, mxContext, xRanges, !bColumn, bColumn ); 2901 } 2902 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aCellRanges.front() ) ); 2903 return new ScVbaRange( mxParent, mxContext, xRange, !bColumn, bColumn ); 2904 } 2905 2906 uno::Reference< excel::XRange > SAL_CALL 2907 ScVbaRange::getEntireRow() 2908 { 2909 return getEntireColumnOrRow(false); 2910 } 2911 2912 uno::Reference< excel::XRange > SAL_CALL 2913 ScVbaRange::getEntireColumn() 2914 { 2915 return getEntireColumnOrRow(true); 2916 } 2917 2918 uno::Reference< excel::XComment > SAL_CALL 2919 ScVbaRange::AddComment( const uno::Any& Text ) 2920 { 2921 // if there is already a comment in the top-left cell then throw 2922 if( getComment().is() ) 2923 throw uno::RuntimeException(); 2924 2925 // workaround: Excel allows to create empty comment, Calc does not 2926 OUString aNoteText; 2927 if( Text.hasValue() && !(Text >>= aNoteText) ) 2928 throw uno::RuntimeException(); 2929 if( aNoteText.isEmpty() ) 2930 aNoteText = " "; 2931 2932 // try to create a new annotation 2933 table::CellRangeAddress aRangePos = lclGetRangeAddress( mxRange ); 2934 table::CellAddress aNotePos( aRangePos.Sheet, aRangePos.StartColumn, aRangePos.StartRow ); 2935 uno::Reference< sheet::XSheetCellRange > xCellRange( mxRange, uno::UNO_QUERY_THROW ); 2936 uno::Reference< sheet::XSheetAnnotationsSupplier > xAnnosSupp( xCellRange->getSpreadsheet(), uno::UNO_QUERY_THROW ); 2937 uno::Reference< sheet::XSheetAnnotations > xAnnos( xAnnosSupp->getAnnotations(), uno::UNO_SET_THROW ); 2938 xAnnos->insertNew( aNotePos, aNoteText ); 2939 return new ScVbaComment( this, mxContext, getUnoModel(), mxRange ); 2940 } 2941 2942 uno::Reference< excel::XComment > SAL_CALL 2943 ScVbaRange::getComment() 2944 { 2945 // intentional behavior to return a null object if no 2946 // comment defined 2947 uno::Reference< excel::XComment > xComment( new ScVbaComment( this, mxContext, getUnoModel(), mxRange ) ); 2948 if ( xComment->Text( uno::Any(), uno::Any(), uno::Any() ).isEmpty() ) 2949 return nullptr; 2950 return xComment; 2951 2952 } 2953 2954 /// @throws uno::RuntimeException 2955 static uno::Reference< beans::XPropertySet > 2956 getRowOrColumnProps( const uno::Reference< table::XCellRange >& xCellRange, bool bRows ) 2957 { 2958 uno::Reference< table::XColumnRowRange > xColRow( xCellRange, uno::UNO_QUERY_THROW ); 2959 uno::Reference< beans::XPropertySet > xProps; 2960 if ( bRows ) 2961 xProps.set( xColRow->getRows(), uno::UNO_QUERY_THROW ); 2962 else 2963 xProps.set( xColRow->getColumns(), uno::UNO_QUERY_THROW ); 2964 return xProps; 2965 } 2966 2967 uno::Any SAL_CALL 2968 ScVbaRange::getHidden() 2969 { 2970 // if multi-area result is the result of the 2971 // first area 2972 if ( m_Areas->getCount() > 1 ) 2973 { 2974 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(sal_Int32(1)), uno::Any() ), uno::UNO_QUERY_THROW ); 2975 return xRange->getHidden(); 2976 } 2977 bool bIsVisible = false; 2978 try 2979 { 2980 uno::Reference< beans::XPropertySet > xProps = getRowOrColumnProps( mxRange, mbIsRows ); 2981 if ( !( xProps->getPropertyValue( ISVISIBLE ) >>= bIsVisible ) ) 2982 throw uno::RuntimeException("Failed to get IsVisible property" ); 2983 } 2984 catch( const uno::Exception& e ) 2985 { 2986 css::uno::Any anyEx = cppu::getCaughtException(); 2987 throw css::lang::WrappedTargetRuntimeException( e.Message, 2988 nullptr, anyEx ); 2989 } 2990 return uno::makeAny( !bIsVisible ); 2991 } 2992 2993 void SAL_CALL 2994 ScVbaRange::setHidden( const uno::Any& _hidden ) 2995 { 2996 if ( m_Areas->getCount() > 1 ) 2997 { 2998 sal_Int32 nItems = m_Areas->getCount(); 2999 for ( sal_Int32 index=1; index <= nItems; ++index ) 3000 { 3001 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW ); 3002 xRange->setHidden( _hidden ); 3003 } 3004 return; 3005 } 3006 3007 bool bHidden = extractBoolFromAny( _hidden ); 3008 try 3009 { 3010 uno::Reference< beans::XPropertySet > xProps = getRowOrColumnProps( mxRange, mbIsRows ); 3011 xProps->setPropertyValue( ISVISIBLE, uno::Any( !bHidden ) ); 3012 } 3013 catch( const uno::Exception& e ) 3014 { 3015 css::uno::Any anyEx = cppu::getCaughtException(); 3016 throw css::lang::WrappedTargetRuntimeException( e.Message, 3017 nullptr, anyEx ); 3018 } 3019 } 3020 3021 sal_Bool SAL_CALL 3022 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 ) 3023 { 3024 if ( m_Areas->getCount() > 1 ) 3025 { 3026 for ( sal_Int32 index = 1; index <= m_Areas->getCount(); ++index ) 3027 { 3028 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( index ), uno::Any() ), uno::UNO_QUERY_THROW ); 3029 xRange->Replace( What, Replacement, LookAt, SearchOrder, MatchCase, MatchByte, SearchFormat, ReplaceFormat ); 3030 } 3031 return true; // seems to return true always ( or at least I haven't found the trick of 3032 } 3033 3034 // sanity check required params 3035 if ( What.isEmpty() ) 3036 throw uno::RuntimeException("Range::Replace, missing params" ); 3037 OUString sWhat = VBAToRegexp( What); 3038 // #TODO #FIXME SearchFormat & ReplacesFormat are not processed 3039 // What do we do about MatchByte.. we don't seem to support that 3040 const SvxSearchItem& globalSearchOptions = ScGlobal::GetSearchItem(); 3041 SvxSearchItem newOptions( globalSearchOptions ); 3042 3043 uno::Reference< util::XReplaceable > xReplace( mxRange, uno::UNO_QUERY ); 3044 if ( xReplace.is() ) 3045 { 3046 uno::Reference< util::XReplaceDescriptor > xDescriptor = 3047 xReplace->createReplaceDescriptor(); 3048 3049 xDescriptor->setSearchString( sWhat); 3050 xDescriptor->setPropertyValue( SC_UNO_SRCHREGEXP, uno::makeAny( true ) ); 3051 xDescriptor->setReplaceString( Replacement); 3052 if ( LookAt.hasValue() ) 3053 { 3054 // sets SearchWords ( true is Cell match ) 3055 sal_Int16 nLook = ::comphelper::getINT16( LookAt ); 3056 bool bSearchWords = false; 3057 if ( nLook == excel::XlLookAt::xlPart ) 3058 bSearchWords = false; 3059 else if ( nLook == excel::XlLookAt::xlWhole ) 3060 bSearchWords = true; 3061 else 3062 throw uno::RuntimeException("Range::Replace, illegal value for LookAt" ); 3063 // set global search props ( affects the find dialog 3064 // and of course the defaults for this method 3065 newOptions.SetWordOnly( bSearchWords ); 3066 xDescriptor->setPropertyValue( SC_UNO_SRCHWORDS, uno::makeAny( bSearchWords ) ); 3067 } 3068 // sets SearchByRow ( true for Rows ) 3069 if ( SearchOrder.hasValue() ) 3070 { 3071 sal_Int16 nSearchOrder = ::comphelper::getINT16( SearchOrder ); 3072 bool bSearchByRow = false; 3073 if ( nSearchOrder == excel::XlSearchOrder::xlByColumns ) 3074 bSearchByRow = false; 3075 else if ( nSearchOrder == excel::XlSearchOrder::xlByRows ) 3076 bSearchByRow = true; 3077 else 3078 throw uno::RuntimeException("Range::Replace, illegal value for SearchOrder" ); 3079 3080 newOptions.SetRowDirection( bSearchByRow ); 3081 xDescriptor->setPropertyValue( SC_UNO_SRCHBYROW, uno::makeAny( bSearchByRow ) ); 3082 } 3083 if ( MatchCase.hasValue() ) 3084 { 3085 bool bMatchCase = false; 3086 3087 // SearchCaseSensitive 3088 MatchCase >>= bMatchCase; 3089 xDescriptor->setPropertyValue( SC_UNO_SRCHCASE, uno::makeAny( bMatchCase ) ); 3090 } 3091 3092 ScGlobal::SetSearchItem( newOptions ); 3093 // ignore MatchByte for the moment, it's not supported in 3094 // OOo.org afaik 3095 3096 uno::Reference< util::XSearchDescriptor > xSearch( xDescriptor, uno::UNO_QUERY ); 3097 uno::Reference< container::XIndexAccess > xIndexAccess = xReplace->findAll( xSearch ); 3098 xReplace->replaceAll( xSearch ); 3099 if ( xIndexAccess.is() && xIndexAccess->getCount() > 0 ) 3100 { 3101 for ( sal_Int32 i = 0; i < xIndexAccess->getCount(); ++i ) 3102 { 3103 uno::Reference< table::XCellRange > xCellRange( xIndexAccess->getByIndex( i ), uno::UNO_QUERY ); 3104 if ( xCellRange.is() ) 3105 { 3106 uno::Reference< excel::XRange > xRange( new ScVbaRange( mxParent, mxContext, xCellRange ) ); 3107 uno::Reference< container::XEnumerationAccess > xEnumAccess( xRange, uno::UNO_QUERY_THROW ); 3108 uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration(); 3109 while ( xEnum->hasMoreElements() ) 3110 { 3111 uno::Reference< excel::XRange > xNextRange( xEnum->nextElement(), uno::UNO_QUERY_THROW ); 3112 ScVbaRange* pRange = dynamic_cast< ScVbaRange * > ( xNextRange.get() ); 3113 if ( pRange ) 3114 pRange->fireChangeEvent(); 3115 } 3116 } 3117 } 3118 } 3119 } 3120 return true; // always 3121 } 3122 3123 uno::Reference< excel::XRange > SAL_CALL 3124 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*/ ) 3125 { 3126 // return a Range object that represents the first cell where that information is found. 3127 OUString sWhat; 3128 sal_Int32 nWhat = 0; 3129 double fWhat = 0.0; 3130 3131 // string. 3132 if( What >>= sWhat ) 3133 {} 3134 else if( What >>= nWhat ) 3135 { 3136 sWhat = OUString::number( nWhat ); 3137 } 3138 else if( What >>= fWhat ) 3139 { 3140 sWhat = OUString::number( fWhat ); 3141 } 3142 else 3143 throw uno::RuntimeException("Range::Find, missing search-for-what param" ); 3144 3145 OUString sSearch = VBAToRegexp( sWhat ); 3146 3147 const SvxSearchItem& globalSearchOptions = ScGlobal::GetSearchItem(); 3148 SvxSearchItem newOptions( globalSearchOptions ); 3149 3150 uno::Reference< util::XSearchable > xSearch( mxRange, uno::UNO_QUERY ); 3151 if( xSearch.is() ) 3152 { 3153 uno::Reference< util::XSearchDescriptor > xDescriptor = xSearch->createSearchDescriptor(); 3154 xDescriptor->setSearchString( sSearch ); 3155 xDescriptor->setPropertyValue( SC_UNO_SRCHREGEXP, uno::Any( true ) ); 3156 3157 uno::Reference< excel::XRange > xAfterRange; 3158 uno::Reference< table::XCellRange > xStartCell; 3159 if( After >>= xAfterRange ) 3160 { 3161 // After must be a single cell in the range 3162 if( xAfterRange->getCount() > 1 ) 3163 throw uno::RuntimeException("After must be a single cell." ); 3164 uno::Reference< excel::XRange > xCell( Cells( uno::makeAny( xAfterRange->getRow() ), uno::makeAny( xAfterRange->getColumn() ) ), uno::UNO_QUERY_THROW ); 3165 xStartCell.set( xAfterRange->getCellRange(), uno::UNO_QUERY_THROW ); 3166 } 3167 3168 // LookIn 3169 if( LookIn.hasValue() ) 3170 { 3171 sal_Int32 nLookIn = 0; 3172 if( LookIn >>= nLookIn ) 3173 { 3174 SvxSearchCellType nSearchType; 3175 switch( nLookIn ) 3176 { 3177 case excel::XlFindLookIn::xlComments : 3178 nSearchType = SvxSearchCellType::NOTE; // Notes 3179 break; 3180 case excel::XlFindLookIn::xlFormulas : 3181 nSearchType = SvxSearchCellType::FORMULA; 3182 break; 3183 case excel::XlFindLookIn::xlValues : 3184 nSearchType = SvxSearchCellType::VALUE; 3185 break; 3186 default: 3187 throw uno::RuntimeException("Range::Find, illegal value for LookIn." ); 3188 } 3189 newOptions.SetCellType( nSearchType ); 3190 xDescriptor->setPropertyValue( "SearchType", uno::makeAny( static_cast<sal_uInt16>(nSearchType) ) ); 3191 } 3192 } 3193 3194 // LookAt 3195 if ( LookAt.hasValue() ) 3196 { 3197 sal_Int16 nLookAt = ::comphelper::getINT16( LookAt ); 3198 bool bSearchWords = false; 3199 if ( nLookAt == excel::XlLookAt::xlPart ) 3200 bSearchWords = false; 3201 else if ( nLookAt == excel::XlLookAt::xlWhole ) 3202 bSearchWords = true; 3203 else 3204 throw uno::RuntimeException("Range::Find, illegal value for LookAt" ); 3205 newOptions.SetWordOnly( bSearchWords ); 3206 xDescriptor->setPropertyValue( SC_UNO_SRCHWORDS, uno::makeAny( bSearchWords ) ); 3207 } 3208 3209 // SearchOrder 3210 if ( SearchOrder.hasValue() ) 3211 { 3212 sal_Int16 nSearchOrder = ::comphelper::getINT16( SearchOrder ); 3213 bool bSearchByRow = false; 3214 if ( nSearchOrder == excel::XlSearchOrder::xlByColumns ) 3215 bSearchByRow = false; 3216 else if ( nSearchOrder == excel::XlSearchOrder::xlByRows ) 3217 bSearchByRow = true; 3218 else 3219 throw uno::RuntimeException("Range::Find, illegal value for SearchOrder" ); 3220 3221 newOptions.SetRowDirection( bSearchByRow ); 3222 xDescriptor->setPropertyValue( SC_UNO_SRCHBYROW, uno::makeAny( bSearchByRow ) ); 3223 } 3224 3225 // SearchDirection 3226 if ( SearchDirection.hasValue() ) 3227 { 3228 sal_Int32 nSearchDirection = 0; 3229 if( SearchDirection >>= nSearchDirection ) 3230 { 3231 bool bSearchBackwards = false; 3232 if ( nSearchDirection == excel::XlSearchDirection::xlNext ) 3233 bSearchBackwards = false; 3234 else if( nSearchDirection == excel::XlSearchDirection::xlPrevious ) 3235 bSearchBackwards = true; 3236 else 3237 throw uno::RuntimeException("Range::Find, illegal value for SearchDirection" ); 3238 newOptions.SetBackward( bSearchBackwards ); 3239 xDescriptor->setPropertyValue( "SearchBackwards", uno::makeAny( bSearchBackwards ) ); 3240 } 3241 } 3242 3243 // MatchCase 3244 bool bMatchCase = false; 3245 if ( MatchCase.hasValue() ) 3246 { 3247 // SearchCaseSensitive 3248 if( !( MatchCase >>= bMatchCase ) ) 3249 throw uno::RuntimeException("Range::Find illegal value for MatchCase" ); 3250 } 3251 xDescriptor->setPropertyValue( SC_UNO_SRCHCASE, uno::makeAny( bMatchCase ) ); 3252 3253 // MatchByte 3254 // SearchFormat 3255 // ignore 3256 3257 ScGlobal::SetSearchItem( newOptions ); 3258 3259 uno::Reference< uno::XInterface > xInterface = xStartCell.is() ? xSearch->findNext( xStartCell, xDescriptor) : xSearch->findFirst( xDescriptor ); 3260 uno::Reference< table::XCellRange > xCellRange( xInterface, uno::UNO_QUERY ); 3261 // if we are searching from a starting cell and failed to find a match 3262 // then try from the beginning 3263 if ( !xCellRange.is() && xStartCell.is() ) 3264 { 3265 xInterface = xSearch->findFirst( xDescriptor ); 3266 xCellRange.set( xInterface, uno::UNO_QUERY ); 3267 } 3268 if ( xCellRange.is() ) 3269 { 3270 uno::Reference< excel::XRange > xResultRange = new ScVbaRange( mxParent, mxContext, xCellRange ); 3271 if( xResultRange.is() ) 3272 { 3273 return xResultRange; 3274 } 3275 } 3276 3277 } 3278 3279 return uno::Reference< excel::XRange >(); 3280 } 3281 3282 static uno::Reference< table::XCellRange > processKey( const uno::Any& Key, const uno::Reference< uno::XComponentContext >& xContext, ScDocShell* pDocSh ) 3283 { 3284 uno::Reference< excel::XRange > xKeyRange; 3285 if ( Key.getValueType() == cppu::UnoType<excel::XRange>::get() ) 3286 { 3287 xKeyRange.set( Key, uno::UNO_QUERY_THROW ); 3288 } 3289 else if ( Key.getValueType() == ::cppu::UnoType<OUString>::get() ) 3290 3291 { 3292 OUString sRangeName = ::comphelper::getString( Key ); 3293 table::CellRangeAddress aRefAddr; 3294 if ( !pDocSh ) 3295 throw uno::RuntimeException("Range::Sort no docshell to calculate key param" ); 3296 xKeyRange = getRangeForName( xContext, sRangeName, pDocSh, aRefAddr ); 3297 } 3298 else 3299 throw uno::RuntimeException("Range::Sort illegal type value for key param" ); 3300 uno::Reference< table::XCellRange > xKey; 3301 xKey.set( xKeyRange->getCellRange(), uno::UNO_QUERY_THROW ); 3302 return xKey; 3303 } 3304 3305 // helper method for Sort 3306 /// @throws uno::RuntimeException 3307 static sal_Int32 findSortPropertyIndex( const uno::Sequence< beans::PropertyValue >& props, 3308 const OUString& sPropName ) 3309 { 3310 const beans::PropertyValue* pProp = props.getConstArray(); 3311 sal_Int32 nItems = props.getLength(); 3312 3313 sal_Int32 count=0; 3314 for ( ; count < nItems; ++count, ++pProp ) 3315 if ( pProp->Name == sPropName ) 3316 return count; 3317 if ( count == nItems ) 3318 throw uno::RuntimeException("Range::Sort unknown sort property" ); 3319 return -1; //should never reach here ( satisfy compiler ) 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 a 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 = 0; 3423 nHeader = aSortParam.nCompatHeader; 3424 bool bContainsHeader = false; 3425 3426 if ( Header.hasValue() ) 3427 { 3428 nHeader = ::comphelper::getINT16( Header ); 3429 aSortParam.nCompatHeader = nHeader; 3430 } 3431 3432 if ( nHeader == excel::XlYesNoGuess::xlGuess ) 3433 { 3434 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 )); 3435 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 ) ); 3436 if ( bHasColHeader || bHasRowHeader ) 3437 nHeader = excel::XlYesNoGuess::xlYes; 3438 else 3439 nHeader = excel::XlYesNoGuess::xlNo; 3440 aSortParam.nCompatHeader = nHeader; 3441 } 3442 3443 if ( nHeader == excel::XlYesNoGuess::xlYes ) 3444 bContainsHeader = true; 3445 3446 if ( SortMethod.hasValue() ) 3447 { 3448 nSortMethod = ::comphelper::getINT16( SortMethod ); 3449 } 3450 3451 if ( OrderCustom.hasValue() ) 3452 { 3453 OrderCustom >>= nCustom; 3454 --nCustom; // 0-based in OOo 3455 aSortParam.nUserIndex = nCustom; 3456 } 3457 3458 if ( MatchCase.hasValue() ) 3459 { 3460 MatchCase >>= bMatchCase; 3461 aSortParam.bCaseSens = bMatchCase; 3462 } 3463 3464 if ( Order1.hasValue() ) 3465 { 3466 nOrder1 = ::comphelper::getINT16(Order1); 3467 if ( nOrder1 == excel::XlSortOrder::xlAscending ) 3468 aSortParam.maKeyState[0].bAscending = true; 3469 else 3470 aSortParam.maKeyState[0].bAscending = false; 3471 3472 } 3473 if ( Order2.hasValue() ) 3474 { 3475 nOrder2 = ::comphelper::getINT16(Order2); 3476 if ( nOrder2 == excel::XlSortOrder::xlAscending ) 3477 aSortParam.maKeyState[1].bAscending = true; 3478 else 3479 aSortParam.maKeyState[1].bAscending = false; 3480 } 3481 if ( Order3.hasValue() ) 3482 { 3483 nOrder3 = ::comphelper::getINT16(Order3); 3484 if ( nOrder3 == excel::XlSortOrder::xlAscending ) 3485 aSortParam.maKeyState[2].bAscending = true; 3486 else 3487 aSortParam.maKeyState[2].bAscending = false; 3488 } 3489 3490 uno::Reference< table::XCellRange > xKey1; 3491 uno::Reference< table::XCellRange > xKey2; 3492 uno::Reference< table::XCellRange > xKey3; 3493 ScDocShell* pDocShell = getScDocShell(); 3494 xKey1 = processKey( Key1, mxContext, pDocShell ); 3495 if ( !xKey1.is() ) 3496 throw uno::RuntimeException("Range::Sort needs a key1 param" ); 3497 3498 if ( Key2.hasValue() ) 3499 xKey2 = processKey( Key2, mxContext, pDocShell ); 3500 if ( Key3.hasValue() ) 3501 xKey3 = processKey( Key3, mxContext, pDocShell ); 3502 3503 uno::Reference< util::XSortable > xSort( mxRange, uno::UNO_QUERY_THROW ); 3504 uno::Sequence< beans::PropertyValue > sortDescriptor = xSort->createSortDescriptor(); 3505 sal_Int32 nTableSortFieldIndex = findSortPropertyIndex( sortDescriptor, "SortFields" ); 3506 3507 uno::Sequence< table::TableSortField > sTableFields(1); 3508 sal_Int32 nTableIndex = 0; 3509 updateTableSortField( mxRange, xKey1, nOrder1, sTableFields[ nTableIndex++ ], bIsSortColumns, bMatchCase ); 3510 3511 if ( xKey2.is() ) 3512 { 3513 sTableFields.realloc( sTableFields.getLength() + 1 ); 3514 updateTableSortField( mxRange, xKey2, nOrder2, sTableFields[ nTableIndex++ ], bIsSortColumns, bMatchCase ); 3515 } 3516 if ( xKey3.is() ) 3517 { 3518 sTableFields.realloc( sTableFields.getLength() + 1 ); 3519 updateTableSortField( mxRange, xKey3, nOrder3, sTableFields[ nTableIndex++ ], bIsSortColumns, bMatchCase ); 3520 } 3521 sortDescriptor[ nTableSortFieldIndex ].Value <<= sTableFields; 3522 3523 sal_Int32 nIndex = findSortPropertyIndex( sortDescriptor, "IsSortColumns" ); 3524 sortDescriptor[ nIndex ].Value <<= bIsSortColumns; 3525 3526 nIndex = findSortPropertyIndex( sortDescriptor, "ContainsHeader" ); 3527 sortDescriptor[ nIndex ].Value <<= bContainsHeader; 3528 3529 rDoc.SetSortParam( aSortParam, nTab ); 3530 xSort->sort( sortDescriptor ); 3531 3532 // #FIXME #TODO 3533 // The SortMethod param is not processed ( not sure what its all about, need to 3534 (void)nSortMethod; 3535 } 3536 3537 uno::Reference< excel::XRange > SAL_CALL 3538 ScVbaRange::End( ::sal_Int32 Direction ) 3539 { 3540 if ( m_Areas->getCount() > 1 ) 3541 { 3542 uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_QUERY_THROW ); 3543 return xRange->End( Direction ); 3544 } 3545 3546 // #FIXME #TODO 3547 // euch! found my orig implementation sucked, so 3548 // trying this even sucker one (really need to use/expose code in 3549 // around ScTabView::MoveCursorArea(), that's the bit that calculates 3550 // where the cursor should go) 3551 // Main problem with this method is the ultra hacky attempt to preserve 3552 // the ActiveCell, there should be no need to go to these extremes 3553 3554 // Save ActiveSheet/ActiveCell pos (to restore later) 3555 uno::Any aDft; 3556 uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW ); 3557 uno::Reference< excel::XWorksheet > sActiveSheet = xApplication->getActiveSheet(); 3558 OUString sActiveCell = xApplication->getActiveCell()->Address(aDft, aDft, aDft, aDft, aDft ); 3559 3560 // position current cell upper left of this range 3561 Cells( uno::makeAny( sal_Int32(1) ), uno::makeAny( sal_Int32(1) ) )->Select(); 3562 3563 uno::Reference< frame::XModel > xModel = getModelFromRange( mxRange ); 3564 3565 SfxViewFrame* pViewFrame = excel::getViewFrame( xModel ); 3566 if ( pViewFrame ) 3567 { 3568 SfxAllItemSet aArgs( SfxGetpApp()->GetPool() ); 3569 // Hoping this will make sure this slot is called 3570 // synchronously 3571 SfxBoolItem sfxAsync( SID_ASYNCHRON, false ); 3572 aArgs.Put( sfxAsync, sfxAsync.Which() ); 3573 SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher(); 3574 3575 sal_uInt16 nSID = 0; 3576 3577 switch( Direction ) 3578 { 3579 case excel::XlDirection::xlDown: 3580 nSID = SID_CURSORBLKDOWN; 3581 break; 3582 case excel::XlDirection::xlUp: 3583 nSID = SID_CURSORBLKUP; 3584 break; 3585 case excel::XlDirection::xlToLeft: 3586 nSID = SID_CURSORBLKLEFT; 3587 break; 3588 case excel::XlDirection::xlToRight: 3589 nSID = SID_CURSORBLKRIGHT; 3590 break; 3591 default: 3592 throw uno::RuntimeException(": Invalid ColumnIndex" ); 3593 } 3594 if ( pDispatcher ) 3595 { 3596 pDispatcher->Execute( nSID, SfxCallMode::SYNCHRON, aArgs ); 3597 } 3598 } 3599 3600 // result is the ActiveCell 3601 OUString sMoved = xApplication->getActiveCell()->Address(aDft, aDft, aDft, aDft, aDft ); 3602 3603 uno::Any aVoid; 3604 uno::Reference< excel::XRange > resultCell; 3605 resultCell.set( xApplication->getActiveSheet()->Range( uno::makeAny( sMoved ), aVoid ), uno::UNO_QUERY_THROW ); 3606 3607 // restore old ActiveCell 3608 uno::Reference< excel::XRange > xOldActiveCell( sActiveSheet->Range( uno::makeAny( sActiveCell ), aVoid ), uno::UNO_QUERY_THROW ); 3609 xOldActiveCell->Select(); 3610 3611 3612 // return result 3613 return resultCell; 3614 } 3615 3616 bool 3617 ScVbaRange::isSingleCellRange() 3618 { 3619 uno::Reference< sheet::XCellRangeAddressable > xAddressable( mxRange, uno::UNO_QUERY ); 3620 if ( xAddressable.is() ) 3621 { 3622 table::CellRangeAddress aRangeAddr = xAddressable->getRangeAddress(); 3623 return ( aRangeAddr.EndColumn == aRangeAddr.StartColumn && aRangeAddr.EndRow == aRangeAddr.StartRow ); 3624 } 3625 return false; 3626 } 3627 3628 uno::Reference< excel::XCharacters > SAL_CALL 3629 ScVbaRange::characters( const uno::Any& Start, const uno::Any& Length ) 3630 { 3631 if ( !isSingleCellRange() ) 3632 throw uno::RuntimeException("Can't create Characters property for multicell range " ); 3633 uno::Reference< text::XSimpleText > xSimple(mxRange->getCellByPosition(0,0) , uno::UNO_QUERY_THROW ); 3634 ScDocument& rDoc = getDocumentFromRange(mxRange); 3635 3636 ScVbaPalette aPalette( rDoc.GetDocumentShell() ); 3637 return new ScVbaCharacters( this, mxContext, aPalette, xSimple, Start, Length ); 3638 } 3639 3640 void SAL_CALL 3641 ScVbaRange::Delete( const uno::Any& Shift ) 3642 { 3643 if ( m_Areas->getCount() > 1 ) 3644 { 3645 sal_Int32 nItems = m_Areas->getCount(); 3646 for ( sal_Int32 index=1; index <= nItems; ++index ) 3647 { 3648 uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW ); 3649 xRange->Delete( Shift ); 3650 } 3651 return; 3652 } 3653 sheet::CellDeleteMode mode = sheet::CellDeleteMode_NONE ; 3654 RangeHelper thisRange( mxRange ); 3655 table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress(); 3656 if ( Shift.hasValue() ) 3657 { 3658 sal_Int32 nShift = 0; 3659 Shift >>= nShift; 3660 switch ( nShift ) 3661 { 3662 case excel::XlDeleteShiftDirection::xlShiftUp: 3663 mode = sheet::CellDeleteMode_UP; 3664 break; 3665 case excel::XlDeleteShiftDirection::xlShiftToLeft: 3666 mode = sheet::CellDeleteMode_LEFT; 3667 break; 3668 default: 3669 throw uno::RuntimeException("Illegal parameter " ); 3670 } 3671 } 3672 else 3673 { 3674 bool bFullRow = ( thisAddress.StartColumn == 0 && thisAddress.EndColumn == 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 OUString( "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() 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 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 ( sal_Int32 i=0; i < sNames.getLength(); ++i ) 4114 { 4115 uno::Reference< sheet::XCellRangeReferrer > xName( xNameAccess->getByName( sNames[ i ] ), 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 ' failes 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 a Operator without a Criteria ? in openoffice 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 form 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_QUERY_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_QUERY_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; 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 OUString("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
