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