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