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