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