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