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  {
255  ScDocument& rDoc = getScDocument();
256  const uno::Reference< script::vba::XVBAEventProcessor >& xVBAEvents = rDoc.GetVbaEventProcessor();
257  if( xVBAEvents.is() ) try
258  {
259  uno::Sequence< uno::Any > aArgs( 1 );
260  aArgs[ 0 ] <<= uno::Reference< excel::XRange >( this );
261  xVBAEvents->processVbaEvent( script::vba::VBAEventId::WORKSHEET_CHANGE, aArgs );
262  }
263  catch( uno::Exception& )
264  {
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* pDoc, formula::FormulaGrammar::Grammar eGram ):CellValueSetter( aValue ), m_pDoc( pDoc ), 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_pDoc, 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_pDoc;
909 public:
910  CellFormulaValueGetter(ScDocument* pDoc, formula::FormulaGrammar::Grammar eGram ) : CellValueGetter( ), m_pDoc( pDoc ), 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_pDoc, 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  {
1318  // clear all contents of the covered cells (not the top-left cell)
1319  table::CellRangeAddress aRangeAddr = lclGetRangeAddress( rxCellRange );
1320  sal_Int32 nLastColIdx = aRangeAddr.EndColumn - aRangeAddr.StartColumn;
1321  sal_Int32 nLastRowIdx = aRangeAddr.EndRow - aRangeAddr.StartRow;
1322  // clear cells of top row, right of top-left cell
1323  if( nLastColIdx > 0 )
1324  lclClearRange( rxCellRange->getCellRangeByPosition( 1, 0, nLastColIdx, 0 ) );
1325  // clear all rows below top row
1326  if( nLastRowIdx > 0 )
1327  lclClearRange( rxCellRange->getCellRangeByPosition( 0, 1, nLastColIdx, nLastRowIdx ) );
1328  // merge the range
1329  xMerge->merge( true );
1330  }
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( pDoc, 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  {
2244  uno::Reference< frame::XModel > xModel( pShell->GetModel(), uno::UNO_SET_THROW );
2245  uno::Reference< view::XSelectionSupplier > xSelection( xModel->getCurrentController(), uno::UNO_QUERY_THROW );
2246  if ( mxRanges.is() )
2247  xSelection->select( uno::Any( lclExpandToMerged( mxRanges ) ) );
2248  else
2249  xSelection->select( uno::Any( lclExpandToMerged( mxRange, true ) ) );
2250  // set focus on document e.g.
2251  // ThisComponent.CurrentController.Frame.getContainerWindow.SetFocus
2252  try
2253  {
2254  uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW );
2255  uno::Reference< frame::XFrame > xFrame( xController->getFrame(), uno::UNO_SET_THROW );
2256  uno::Reference< awt::XWindow > xWin( xFrame->getContainerWindow(), uno::UNO_SET_THROW );
2257  xWin->setFocus();
2258  }
2259  catch( uno::Exception& )
2260  {
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  OUString sAddress;
2347 
2348  if ( aIndex.hasValue() )
2349  {
2350  sal_Int32 nValue = 0;
2351  ScCellRangesBase* pUnoRangesBase = getCellRangesBase();
2352  ScRangeList aCellRanges = pUnoRangesBase->GetRangeList();
2353 
2354  ScRange aRange = aCellRanges.front();
2355  if( aIndex >>= nValue )
2356  {
2357  aRange.aStart.SetRow( aRange.aStart.Row() + --nValue );
2358  aRange.aEnd.SetRow( aRange.aStart.Row() );
2359  }
2360  else if ( aIndex >>= sAddress )
2361  {
2363  ScRange tmpRange;
2364  tmpRange.ParseRows( &getScDocument(), sAddress, dDetails );
2365  SCROW nStartRow = tmpRange.aStart.Row();
2366  SCROW nEndRow = tmpRange.aEnd.Row();
2367 
2368  aRange.aStart.SetRow( aRange.aStart.Row() + nStartRow );
2369  aRange.aEnd.SetRow( aRange.aStart.Row() + ( nEndRow - nStartRow ));
2370  }
2371  else
2372  throw uno::RuntimeException("Illegal param" );
2373 
2374  if ( aRange.aStart.Row() < 0 || aRange.aEnd.Row() < 0 )
2375  throw uno::RuntimeException("Internal failure, illegal param" );
2376  // return a normal range ( even for multi-selection
2377  uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange ) );
2378  return new ScVbaRange( mxParent, mxContext, xRange, true );
2379  }
2380  // Rows() - no params
2381  if ( m_Areas->getCount() > 1 )
2382  return new ScVbaRange( mxParent, mxContext, mxRanges, true );
2383  return new ScVbaRange( mxParent, mxContext, mxRange, true );
2384 }
2385 
2386 uno::Reference< excel::XRange >
2388 {
2389  OUString sAddress;
2390 
2391  ScCellRangesBase* pUnoRangesBase = getCellRangesBase();
2392  ScRangeList aCellRanges = pUnoRangesBase->GetRangeList();
2393 
2394  ScRange aRange = aCellRanges.front();
2395  if ( aIndex.hasValue() )
2396  {
2397  sal_Int32 nValue = 0;
2398  if ( aIndex >>= nValue )
2399  {
2400  aRange.aStart.SetCol( aRange.aStart.Col() + static_cast< SCCOL > ( --nValue ) );
2401  aRange.aEnd.SetCol( aRange.aStart.Col() );
2402  }
2403 
2404  else if ( aIndex >>= sAddress )
2405  {
2407  ScRange tmpRange;
2408  tmpRange.ParseCols( &getScDocument(), sAddress, dDetails );
2409  SCCOL nStartCol = tmpRange.aStart.Col();
2410  SCCOL nEndCol = tmpRange.aEnd.Col();
2411 
2412  aRange.aStart.SetCol( aRange.aStart.Col() + nStartCol );
2413  aRange.aEnd.SetCol( aRange.aStart.Col() + ( nEndCol - nStartCol ));
2414  }
2415  else
2416  throw uno::RuntimeException("Illegal param" );
2417 
2418  if ( aRange.aStart.Col() < 0 || aRange.aEnd.Col() < 0 )
2419  throw uno::RuntimeException("Internal failure, illegal param" );
2420  }
2421  // Columns() - no params
2422  uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange ) );
2423  return new ScVbaRange( mxParent, mxContext, xRange, false, true );
2424 }
2425 
2426 void
2428 {
2429  bool bMerge = extractBoolFromAny( aIsMerged );
2430 
2431  if( mxRanges.is() )
2432  {
2433  sal_Int32 nCount = mxRanges->getCount();
2434 
2435  // VBA does nothing (no error) if the own ranges overlap somehow
2436  ::std::vector< table::CellRangeAddress > aList;
2437  for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
2438  {
2439  uno::Reference< sheet::XCellRangeAddressable > xRangeAddr( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW );
2440  table::CellRangeAddress aAddress = xRangeAddr->getRangeAddress();
2441  if (std::any_of(aList.begin(), aList.end(),
2442  [&aAddress](const table::CellRangeAddress& rAddress)
2443  { return ScUnoConversion::Intersects( rAddress, aAddress ); }))
2444  return;
2445  aList.push_back( aAddress );
2446  }
2447 
2448  // (un)merge every range after it has been extended to intersecting merged ranges from sheet
2449  for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
2450  {
2451  uno::Reference< table::XCellRange > xRange( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW );
2452  lclExpandAndMerge( xRange, bMerge );
2453  }
2454  return;
2455  }
2456 
2457  // otherwise, merge single range
2458  lclExpandAndMerge( mxRange, bMerge );
2459 }
2460 
2461 uno::Any
2463 {
2464  if( mxRanges.is() )
2465  {
2466  sal_Int32 nCount = mxRanges->getCount();
2467  for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
2468  {
2469  uno::Reference< table::XCellRange > xRange( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW );
2470  util::TriState eMerged = lclGetMergedState( xRange );
2471  /* Excel always returns NULL, if one range of the range list is
2472  partly or completely merged. Even if all ranges are completely
2473  merged, the return value is still NULL. */
2474  if( eMerged != util::TriState_NO )
2475  return aNULL();
2476  }
2477  // no range is merged anyhow, return false
2478  return uno::Any( false );
2479  }
2480 
2481  // otherwise, check single range
2482  switch( lclGetMergedState( mxRange ) )
2483  {
2484  case util::TriState_YES: return uno::Any( true );
2485  case util::TriState_NO: return uno::Any( false );
2486  default: return aNULL();
2487  }
2488 }
2489 
2490 void
2491 ScVbaRange::Copy(const ::uno::Any& Destination)
2492 {
2493  if ( Destination.hasValue() )
2494  {
2495  // TODO copy with multiple selections should work here too
2496  if ( m_Areas->getCount() > 1 )
2497  throw uno::RuntimeException("That command cannot be used on multiple selections" );
2498  uno::Reference< excel::XRange > xRange( Destination, uno::UNO_QUERY_THROW );
2499  uno::Any aRange = xRange->getCellRange();
2500  uno::Reference< table::XCellRange > xCellRange;
2501  aRange >>= xCellRange;
2502  uno::Reference< sheet::XSheetCellRange > xSheetCellRange(xCellRange, ::uno::UNO_QUERY_THROW);
2503  uno::Reference< sheet::XSpreadsheet > xSheet = xSheetCellRange->getSpreadsheet();
2504  uno::Reference< table::XCellRange > xDest( xSheet, uno::UNO_QUERY_THROW );
2505  uno::Reference< sheet::XCellRangeMovement > xMover( xSheet, uno::UNO_QUERY_THROW);
2506  uno::Reference< sheet::XCellAddressable > xDestination( xDest->getCellByPosition(
2507  xRange->getColumn()-1,xRange->getRow()-1), uno::UNO_QUERY_THROW );
2508  uno::Reference< sheet::XCellRangeAddressable > xSource( mxRange, uno::UNO_QUERY);
2509  xMover->copyRange( xDestination->getCellAddress(), xSource->getRangeAddress() );
2510  if ( ScVbaRange* pRange = getImplementation( xRange ) )
2511  pRange->fireChangeEvent();
2512  }
2513  else
2514  {
2516  }
2517 }
2518 
2519 void
2520 ScVbaRange::Cut(const ::uno::Any& Destination)
2521 {
2522  if ( m_Areas->getCount() > 1 )
2523  throw uno::RuntimeException("That command cannot be used on multiple selections" );
2524  if (Destination.hasValue())
2525  {
2526  uno::Reference< excel::XRange > xRange( Destination, uno::UNO_QUERY_THROW );
2527  uno::Reference< table::XCellRange > xCellRange( xRange->getCellRange(), uno::UNO_QUERY_THROW );
2528  uno::Reference< sheet::XSheetCellRange > xSheetCellRange(xCellRange, ::uno::UNO_QUERY_THROW );
2529  uno::Reference< sheet::XSpreadsheet > xSheet = xSheetCellRange->getSpreadsheet();
2530  uno::Reference< table::XCellRange > xDest( xSheet, uno::UNO_QUERY_THROW );
2531  uno::Reference< sheet::XCellRangeMovement > xMover( xSheet, uno::UNO_QUERY_THROW);
2532  uno::Reference< sheet::XCellAddressable > xDestination( xDest->getCellByPosition(
2533  xRange->getColumn()-1,xRange->getRow()-1), uno::UNO_QUERY);
2534  uno::Reference< sheet::XCellRangeAddressable > xSource( mxRange, uno::UNO_QUERY);
2535  xMover->moveRange( xDestination->getCellAddress(), xSource->getRangeAddress() );
2536  }
2537  else
2538  {
2539  uno::Reference< frame::XModel > xModel = getModelFromRange( mxRange );
2540  Select();
2541  excel::implnCut( xModel );
2542  }
2543 }
2544 
2545 void
2547 {
2548  OUString sFormat;
2549  aFormat >>= sFormat;
2550  if ( m_Areas->getCount() > 1 )
2551  {
2552  sal_Int32 nItems = m_Areas->getCount();
2553  for ( sal_Int32 index=1; index <= nItems; ++index )
2554  {
2555  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW );
2556  xRange->setNumberFormat( aFormat );
2557  }
2558  return;
2559  }
2560  NumFormatHelper numFormat( mxRange );
2561  numFormat.setNumberFormat( sFormat );
2562 }
2563 
2564 uno::Any
2566 {
2567 
2568  if ( m_Areas->getCount() > 1 )
2569  {
2570  sal_Int32 nItems = m_Areas->getCount();
2571  uno::Any aResult = aNULL();
2572  for ( sal_Int32 index=1; index <= nItems; ++index )
2573  {
2574  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW );
2575  // if the numberformat of one area is different to another
2576  // return null
2577  if ( index > 1 )
2578  if ( aResult != xRange->getNumberFormat() )
2579  return aNULL();
2580  aResult = xRange->getNumberFormat();
2581  if ( aNULL() == aResult )
2582  return aNULL();
2583  }
2584  return aResult;
2585  }
2586  NumFormatHelper numFormat( mxRange );
2587  OUString sFormat = numFormat.getNumberFormatString();
2588  if ( !sFormat.isEmpty() )
2589  return uno::makeAny( sFormat );
2590  return aNULL();
2591 }
2592 
2593 uno::Reference< excel::XRange >
2595 {
2596  long nRowSize = 0, nColumnSize = 0;
2597  bool bIsRowChanged = ( RowSize >>= nRowSize ), bIsColumnChanged = ( ColumnSize >>= nColumnSize );
2598  uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, ::uno::UNO_QUERY_THROW);
2599  uno::Reference< sheet::XSheetCellRange > xSheetRange(mxRange, ::uno::UNO_QUERY_THROW);
2600  uno::Reference< sheet::XSheetCellCursor > xCursor( xSheetRange->getSpreadsheet()->createCursorByRange(xSheetRange), ::uno::UNO_SET_THROW );
2601 
2602  if( !bIsRowChanged )
2603  nRowSize = xColumnRowRange->getRows()->getCount();
2604  if( !bIsColumnChanged )
2605  nColumnSize = xColumnRowRange->getColumns()->getCount();
2606 
2607  xCursor->collapseToSize( nColumnSize, nRowSize );
2608  uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xCursor, ::uno::UNO_QUERY_THROW );
2609  uno::Reference< table::XCellRange > xRange( xSheetRange->getSpreadsheet(), ::uno::UNO_QUERY_THROW );
2610  return new ScVbaRange( mxParent, mxContext,xRange->getCellRangeByPosition(
2611  xCellRangeAddressable->getRangeAddress().StartColumn,
2612  xCellRangeAddressable->getRangeAddress().StartRow,
2613  xCellRangeAddressable->getRangeAddress().EndColumn,
2614  xCellRangeAddressable->getRangeAddress().EndRow ) );
2615 }
2616 
2617 void
2618 ScVbaRange::setWrapText( const uno::Any& aIsWrapped )
2619 {
2620  if ( m_Areas->getCount() > 1 )
2621  {
2622  sal_Int32 nItems = m_Areas->getCount();
2623  for ( sal_Int32 index=1; index <= nItems; ++index )
2624  {
2625  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW );
2626  xRange->setWrapText( aIsWrapped );
2627  }
2628  return;
2629  }
2630 
2631  uno::Reference< beans::XPropertySet > xProps(mxRange, ::uno::UNO_QUERY_THROW );
2632  bool bIsWrapped = extractBoolFromAny( aIsWrapped );
2633  xProps->setPropertyValue( "IsTextWrapped", uno::Any( bIsWrapped ) );
2634 }
2635 
2636 uno::Any
2638 {
2639  if ( m_Areas->getCount() > 1 )
2640  {
2641  sal_Int32 nItems = m_Areas->getCount();
2642  uno::Any aResult;
2643  for ( sal_Int32 index=1; index <= nItems; ++index )
2644  {
2645  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW );
2646  if ( index > 1 )
2647  if ( aResult != xRange->getWrapText() )
2648  return aNULL();
2649  aResult = xRange->getWrapText();
2650  }
2651  return aResult;
2652  }
2653 
2654  SfxItemSet* pDataSet = getCurrentDataSet();
2655 
2656  SfxItemState eState = pDataSet->GetItemState( ATTR_LINEBREAK);
2657  if ( eState == SfxItemState::DONTCARE )
2658  return aNULL();
2659 
2660  uno::Reference< beans::XPropertySet > xProps(mxRange, ::uno::UNO_QUERY_THROW );
2661  uno::Any aValue = xProps->getPropertyValue( "IsTextWrapped" );
2662  return aValue;
2663 }
2664 
2665 uno::Reference< excel::XInterior > ScVbaRange::Interior( )
2666 {
2667  uno::Reference< beans::XPropertySet > xProps( mxRange, uno::UNO_QUERY_THROW );
2668  return new ScVbaInterior ( this, mxContext, xProps, &getScDocument() );
2669 }
2670 uno::Reference< excel::XRange >
2671 ScVbaRange::Range( const uno::Any &Cell1, const uno::Any &Cell2 )
2672 {
2673  return Range( Cell1, Cell2, false );
2674 }
2675 uno::Reference< excel::XRange >
2676 ScVbaRange::Range( const uno::Any &Cell1, const uno::Any &Cell2, bool bForceUseInpuRangeTab )
2677 
2678 {
2679  uno::Reference< table::XCellRange > xCellRange = mxRange;
2680 
2681  if ( m_Areas->getCount() > 1 )
2682  {
2683  uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW );
2684  xCellRange.set( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW );
2685  }
2686  else
2687  xCellRange.set( mxRange );
2688 
2689  RangeHelper thisRange( xCellRange );
2690  uno::Reference< table::XCellRange > xRanges = thisRange.getCellRangeFromSheet();
2691  uno::Reference< sheet::XCellRangeAddressable > xAddressable( xRanges, uno::UNO_QUERY_THROW );
2692 
2693  uno::Reference< table::XCellRange > xReferrer =
2694  xRanges->getCellRangeByPosition( getColumn()-1, getRow()-1,
2695  xAddressable->getRangeAddress().EndColumn,
2696  xAddressable->getRangeAddress().EndRow );
2697  // xAddressable now for this range
2698  xAddressable.set( xReferrer, uno::UNO_QUERY_THROW );
2699 
2700  if( !Cell1.hasValue() )
2701  throw uno::RuntimeException( "Invalid Argument" );
2702 
2703  table::CellRangeAddress resultAddress;
2704  table::CellRangeAddress parentRangeAddress = xAddressable->getRangeAddress();
2705 
2706  ScRange aRange;
2707  // Cell1 defined only
2708  if ( !Cell2.hasValue() )
2709  {
2710  OUString sName;
2711  Cell1 >>= sName;
2712  RangeHelper referRange( xReferrer );
2713  table::CellRangeAddress referAddress = referRange.getCellRangeAddressable()->getRangeAddress();
2714  return getRangeForName( mxContext, sName, getScDocShell(), referAddress );
2715 
2716  }
2717  else
2718  {
2719  table::CellRangeAddress cell1, cell2;
2720  cell1 = getCellRangeAddressForVBARange( Cell1, getScDocShell() );
2721  // Cell1 & Cell2 defined
2722  // Excel seems to combine the range as the range defined by
2723  // the combination of Cell1 & Cell2
2724 
2725  cell2 = getCellRangeAddressForVBARange( Cell2, getScDocShell() );
2726 
2727  resultAddress.StartColumn = ( cell1.StartColumn < cell2.StartColumn ) ? cell1.StartColumn : cell2.StartColumn;
2728  resultAddress.StartRow = ( cell1.StartRow < cell2.StartRow ) ? cell1.StartRow : cell2.StartRow;
2729  resultAddress.EndColumn = std::max( cell1.EndColumn, cell2.EndColumn );
2730  resultAddress.EndRow = std::max( cell1.EndRow, cell2.EndRow );
2731  if ( bForceUseInpuRangeTab )
2732  {
2733  // this is a call from Application.Range( x,y )
2734  // it's possible for x or y to specify a different sheet from
2735  // the current or active on ( but they must be the same )
2736  if ( cell1.Sheet != cell2.Sheet )
2737  throw uno::RuntimeException();
2738  parentRangeAddress.Sheet = cell1.Sheet;
2739  }
2740  else
2741  {
2742  // this is not a call from Application.Range( x,y )
2743  // if a different sheet from this range is specified it's
2744  // an error
2745  if ( parentRangeAddress.Sheet != cell1.Sheet
2746  || parentRangeAddress.Sheet != cell2.Sheet
2747  )
2748  throw uno::RuntimeException();
2749 
2750  }
2751  ScUnoConversion::FillScRange( aRange, resultAddress );
2752  }
2753  ScRange parentAddress;
2754  ScUnoConversion::FillScRange( parentAddress, parentRangeAddress);
2755  if ( aRange.aStart.Col() >= 0 && aRange.aStart.Row() >= 0 && aRange.aEnd.Col() >= 0 && aRange.aEnd.Row() >= 0 )
2756  {
2757  sal_Int32 nStartX = parentAddress.aStart.Col() + aRange.aStart.Col();
2758  sal_Int32 nStartY = parentAddress.aStart.Row() + aRange.aStart.Row();
2759  sal_Int32 nEndX = parentAddress.aStart.Col() + aRange.aEnd.Col();
2760  sal_Int32 nEndY = parentAddress.aStart.Row() + aRange.aEnd.Row();
2761 
2762  if ( nStartX <= nEndX && nEndX <= parentAddress.aEnd.Col() &&
2763  nStartY <= nEndY && nEndY <= parentAddress.aEnd.Row() )
2764  {
2765  ScRange aNew( static_cast<SCCOL>(nStartX), static_cast<SCROW>(nStartY), parentAddress.aStart.Tab(),
2766  static_cast<SCCOL>(nEndX), static_cast<SCROW>(nEndY), parentAddress.aEnd.Tab() );
2767  xCellRange = new ScCellRangeObj( getScDocShell(), aNew );
2768  }
2769  }
2770 
2771  return new ScVbaRange( mxParent, mxContext, xCellRange );
2772 
2773 }
2774 
2775 // Allow access to underlying openoffice uno api ( useful for debugging
2776 // with openoffice basic )
2778 {
2779  uno::Any aAny;
2780  if ( mxRanges.is() )
2781  aAny <<= mxRanges;
2782  else if ( mxRange.is() )
2783  aAny <<= mxRange;
2784  return aAny;
2785 }
2786 
2787 uno::Any ScVbaRange::getCellRange( const uno::Reference< excel::XRange >& rxRange )
2788 {
2789  if( ScVbaRange* pVbaRange = getImplementation( rxRange ) )
2790  return pVbaRange->getCellRange();
2791  throw uno::RuntimeException();
2792 }
2793 
2794 static InsertDeleteFlags getPasteFlags (sal_Int32 Paste)
2795 {
2797  switch (Paste) {
2798  case excel::XlPasteType::xlPasteComments:
2799  nFlags = InsertDeleteFlags::NOTE;break;
2800  case excel::XlPasteType::xlPasteFormats:
2801  nFlags = InsertDeleteFlags::ATTRIB;break;
2802  case excel::XlPasteType::xlPasteFormulas:
2803  nFlags = InsertDeleteFlags::FORMULA;break;
2804  case excel::XlPasteType::xlPasteFormulasAndNumberFormats :
2805  case excel::XlPasteType::xlPasteValues:
2807  case excel::XlPasteType::xlPasteValuesAndNumberFormats:
2809  case excel::XlPasteType::xlPasteColumnWidths:
2810  case excel::XlPasteType::xlPasteValidation:
2811  nFlags = InsertDeleteFlags::NONE;break;
2812  case excel::XlPasteType::xlPasteAll:
2813  case excel::XlPasteType::xlPasteAllExceptBorders:
2814  default:
2815  nFlags = InsertDeleteFlags::ALL;break;
2816  }
2817  return nFlags;
2818 }
2819 
2820 static ScPasteFunc
2822 {
2823  ScPasteFunc nFormulaBits = ScPasteFunc::NONE;
2824  switch (Operation)
2825  {
2826  case excel::XlPasteSpecialOperation::xlPasteSpecialOperationAdd:
2827  nFormulaBits = ScPasteFunc::ADD; break;
2828  case excel::XlPasteSpecialOperation::xlPasteSpecialOperationSubtract:
2829  nFormulaBits = ScPasteFunc::SUB;break;
2830  case excel::XlPasteSpecialOperation::xlPasteSpecialOperationMultiply:
2831  nFormulaBits = ScPasteFunc::MUL;break;
2832  case excel::XlPasteSpecialOperation::xlPasteSpecialOperationDivide:
2833  nFormulaBits = ScPasteFunc::DIV;break;
2834 
2835  case excel::XlPasteSpecialOperation::xlPasteSpecialOperationNone:
2836  default:
2837  nFormulaBits = ScPasteFunc::NONE; break;
2838  }
2839 
2840  return nFormulaBits;
2841 }
2842 void SAL_CALL
2843 ScVbaRange::PasteSpecial( const uno::Any& Paste, const uno::Any& Operation, const uno::Any& SkipBlanks, const uno::Any& Transpose )
2844 {
2845  if ( m_Areas->getCount() > 1 )
2846  throw uno::RuntimeException("That command cannot be used on multiple selections" );
2847  ScDocShell* pShell = getScDocShell();
2848 
2849  if (!pShell)
2850  throw uno::RuntimeException("That command cannot be used with no ScDocShell" );
2851 
2852  uno::Reference< frame::XModel > xModel(pShell->GetModel(), uno::UNO_SET_THROW);
2853  uno::Reference< view::XSelectionSupplier > xSelection( xModel->getCurrentController(), uno::UNO_QUERY_THROW );
2854  // select this range
2855  xSelection->select( uno::makeAny( mxRange ) );
2856  // set up defaults
2857  sal_Int32 nPaste = excel::XlPasteType::xlPasteAll;
2858  sal_Int32 nOperation = excel::XlPasteSpecialOperation::xlPasteSpecialOperationNone;
2859  bool bTranspose = false;
2860  bool bSkipBlanks = false;
2861 
2862  if ( Paste.hasValue() )
2863  Paste >>= nPaste;
2864  if ( Operation.hasValue() )
2865  Operation >>= nOperation;
2866  if ( SkipBlanks.hasValue() )
2867  SkipBlanks >>= bSkipBlanks;
2868  if ( Transpose.hasValue() )
2869  Transpose >>= bTranspose;
2870 
2871  InsertDeleteFlags nFlags = getPasteFlags(nPaste);
2872  ScPasteFunc nFormulaBits = getPasteFormulaBits(nOperation);
2873  excel::implnPasteSpecial(pShell->GetModel(), nFlags,nFormulaBits,bSkipBlanks,bTranspose);
2874 }
2875 
2876 uno::Reference< excel::XRange >
2878 {
2879  ScCellRangesBase* pUnoRangesBase = getCellRangesBase();
2880  // copy the range list
2881  ScRangeList aCellRanges = pUnoRangesBase->GetRangeList();
2882  ScDocument& rDoc = getScDocument();
2883 
2884  for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i )
2885  {
2886  ScRange & rRange = aCellRanges[ i ];
2887  if ( bColumn )
2888  {
2889  rRange.aStart.SetRow( 0 );
2890  rRange.aEnd.SetRow( rDoc.MaxRow() );
2891  }
2892  else
2893  {
2894  rRange.aStart.SetCol( 0 );
2895  rRange.aEnd.SetCol( rDoc.MaxCol() );
2896  }
2897  }
2898  if ( aCellRanges.size() > 1 ) // Multi-Area
2899  {
2900  uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pUnoRangesBase->GetDocShell(), aCellRanges ) );
2901 
2902  return new ScVbaRange( mxParent, mxContext, xRanges, !bColumn, bColumn );
2903  }
2904  uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aCellRanges.front() ) );
2905  return new ScVbaRange( mxParent, mxContext, xRange, !bColumn, bColumn );
2906 }
2907 
2908 uno::Reference< excel::XRange > SAL_CALL
2910 {
2911  return getEntireColumnOrRow(false);
2912 }
2913 
2914 uno::Reference< excel::XRange > SAL_CALL
2916 {
2917  return getEntireColumnOrRow(true);
2918 }
2919 
2920 uno::Reference< excel::XComment > SAL_CALL
2922 {
2923  // if there is already a comment in the top-left cell then throw
2924  if( getComment().is() )
2925  throw uno::RuntimeException();
2926 
2927  // workaround: Excel allows to create empty comment, Calc does not
2928  OUString aNoteText;
2929  if( Text.hasValue() && !(Text >>= aNoteText) )
2930  throw uno::RuntimeException();
2931  if( aNoteText.isEmpty() )
2932  aNoteText = " ";
2933 
2934  // try to create a new annotation
2935  table::CellRangeAddress aRangePos = lclGetRangeAddress( mxRange );
2936  table::CellAddress aNotePos( aRangePos.Sheet, aRangePos.StartColumn, aRangePos.StartRow );
2937  uno::Reference< sheet::XSheetCellRange > xCellRange( mxRange, uno::UNO_QUERY_THROW );
2938  uno::Reference< sheet::XSheetAnnotationsSupplier > xAnnosSupp( xCellRange->getSpreadsheet(), uno::UNO_QUERY_THROW );
2939  uno::Reference< sheet::XSheetAnnotations > xAnnos( xAnnosSupp->getAnnotations(), uno::UNO_SET_THROW );
2940  xAnnos->insertNew( aNotePos, aNoteText );
2941  return new ScVbaComment( this, mxContext, getUnoModel(), mxRange );
2942 }
2943 
2944 uno::Reference< excel::XComment > SAL_CALL
2946 {
2947  // intentional behavior to return a null object if no
2948  // comment defined
2949  uno::Reference< excel::XComment > xComment( new ScVbaComment( this, mxContext, getUnoModel(), mxRange ) );
2950  if ( xComment->Text( uno::Any(), uno::Any(), uno::Any() ).isEmpty() )
2951  return nullptr;
2952  return xComment;
2953 
2954 }
2955 
2957 static uno::Reference< beans::XPropertySet >
2958 getRowOrColumnProps( const uno::Reference< table::XCellRange >& xCellRange, bool bRows )
2959 {
2960  uno::Reference< table::XColumnRowRange > xColRow( xCellRange, uno::UNO_QUERY_THROW );
2961  uno::Reference< beans::XPropertySet > xProps;
2962  if ( bRows )
2963  xProps.set( xColRow->getRows(), uno::UNO_QUERY_THROW );
2964  else
2965  xProps.set( xColRow->getColumns(), uno::UNO_QUERY_THROW );
2966  return xProps;
2967 }
2968 
2969 uno::Any SAL_CALL
2971 {
2972  // if multi-area result is the result of the
2973  // first area
2974  if ( m_Areas->getCount() > 1 )
2975  {
2976  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(sal_Int32(1)), uno::Any() ), uno::UNO_QUERY_THROW );
2977  return xRange->getHidden();
2978  }
2979  bool bIsVisible = false;
2980  try
2981  {
2982  uno::Reference< beans::XPropertySet > xProps = getRowOrColumnProps( mxRange, mbIsRows );
2983  if ( !( xProps->getPropertyValue( ISVISIBLE ) >>= bIsVisible ) )
2984  throw uno::RuntimeException("Failed to get IsVisible property" );
2985  }
2986  catch( const uno::Exception& e )
2987  {
2988  css::uno::Any anyEx = cppu::getCaughtException();
2989  throw css::lang::WrappedTargetRuntimeException( e.Message,
2990  nullptr, anyEx );
2991  }
2992  return uno::makeAny( !bIsVisible );
2993 }
2994 
2995 void SAL_CALL
2997 {
2998  if ( m_Areas->getCount() > 1 )
2999  {
3000  sal_Int32 nItems = m_Areas->getCount();
3001  for ( sal_Int32 index=1; index <= nItems; ++index )
3002  {
3003  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW );
3004  xRange->setHidden( _hidden );
3005  }
3006  return;
3007  }
3008 
3009  bool bHidden = extractBoolFromAny( _hidden );
3010  try
3011  {
3012  uno::Reference< beans::XPropertySet > xProps = getRowOrColumnProps( mxRange, mbIsRows );
3013  xProps->setPropertyValue( ISVISIBLE, uno::Any( !bHidden ) );
3014  }
3015  catch( const uno::Exception& e )
3016  {
3017  css::uno::Any anyEx = cppu::getCaughtException();
3018  throw css::lang::WrappedTargetRuntimeException( e.Message,
3019  nullptr, anyEx );
3020  }
3021 }
3022 
3023 sal_Bool SAL_CALL
3024 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 )
3025 {
3026  if ( m_Areas->getCount() > 1 )
3027  {
3028  for ( sal_Int32 index = 1; index <= m_Areas->getCount(); ++index )
3029  {
3030  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( index ), uno::Any() ), uno::UNO_QUERY_THROW );
3031  xRange->Replace( What, Replacement, LookAt, SearchOrder, MatchCase, MatchByte, SearchFormat, ReplaceFormat );
3032  }
3033  return true; // seems to return true always ( or at least I haven't found the trick of
3034  }
3035 
3036  // sanity check required params
3037  if ( What.isEmpty() )
3038  throw uno::RuntimeException("Range::Replace, missing params" );
3039  OUString sWhat = VBAToRegexp( What);
3040  // #TODO #FIXME SearchFormat & ReplacesFormat are not processed
3041  // What do we do about MatchByte... we don't seem to support that
3042  const SvxSearchItem& globalSearchOptions = ScGlobal::GetSearchItem();
3043  SvxSearchItem newOptions( globalSearchOptions );
3044 
3045  uno::Reference< util::XReplaceable > xReplace( mxRange, uno::UNO_QUERY );
3046  if ( xReplace.is() )
3047  {
3048  uno::Reference< util::XReplaceDescriptor > xDescriptor =
3049  xReplace->createReplaceDescriptor();
3050 
3051  xDescriptor->setSearchString( sWhat);
3052  xDescriptor->setPropertyValue( SC_UNO_SRCHREGEXP, uno::makeAny( true ) );
3053  xDescriptor->setReplaceString( Replacement);
3054  if ( LookAt.hasValue() )
3055  {
3056  // sets SearchWords ( true is Cell match )
3057  sal_Int16 nLook = ::comphelper::getINT16( LookAt );
3058  bool bSearchWords = false;
3059  if ( nLook == excel::XlLookAt::xlPart )
3060  bSearchWords = false;
3061  else if ( nLook == excel::XlLookAt::xlWhole )
3062  bSearchWords = true;
3063  else
3064  throw uno::RuntimeException("Range::Replace, illegal value for LookAt" );
3065  // set global search props ( affects the find dialog
3066  // and of course the defaults for this method
3067  newOptions.SetWordOnly( bSearchWords );
3068  xDescriptor->setPropertyValue( SC_UNO_SRCHWORDS, uno::makeAny( bSearchWords ) );
3069  }
3070  // sets SearchByRow ( true for Rows )
3071  if ( SearchOrder.hasValue() )
3072  {
3073  sal_Int16 nSearchOrder = ::comphelper::getINT16( SearchOrder );
3074  bool bSearchByRow = false;
3075  if ( nSearchOrder == excel::XlSearchOrder::xlByColumns )
3076  bSearchByRow = false;
3077  else if ( nSearchOrder == excel::XlSearchOrder::xlByRows )
3078  bSearchByRow = true;
3079  else
3080  throw uno::RuntimeException("Range::Replace, illegal value for SearchOrder" );
3081 
3082  newOptions.SetRowDirection( bSearchByRow );
3083  xDescriptor->setPropertyValue( SC_UNO_SRCHBYROW, uno::makeAny( bSearchByRow ) );
3084  }
3085  if ( MatchCase.hasValue() )
3086  {
3087  bool bMatchCase = false;
3088 
3089  // SearchCaseSensitive
3090  MatchCase >>= bMatchCase;
3091  xDescriptor->setPropertyValue( SC_UNO_SRCHCASE, uno::makeAny( bMatchCase ) );
3092  }
3093 
3094  ScGlobal::SetSearchItem( newOptions );
3095  // ignore MatchByte for the moment, it's not supported in
3096  // OOo.org afaik
3097 
3098  uno::Reference< container::XIndexAccess > xIndexAccess = xReplace->findAll( xDescriptor );
3099  xReplace->replaceAll( xDescriptor );
3100  if ( xIndexAccess.is() && xIndexAccess->getCount() > 0 )
3101  {
3102  for ( sal_Int32 i = 0; i < xIndexAccess->getCount(); ++i )
3103  {
3104  uno::Reference< table::XCellRange > xCellRange( xIndexAccess->getByIndex( i ), uno::UNO_QUERY );
3105  if ( xCellRange.is() )
3106  {
3107  uno::Reference< excel::XRange > xRange( new ScVbaRange( mxParent, mxContext, xCellRange ) );
3108  uno::Reference< container::XEnumerationAccess > xEnumAccess( xRange, uno::UNO_QUERY_THROW );
3109  uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration();
3110  while ( xEnum->hasMoreElements() )
3111  {
3112  uno::Reference< excel::XRange > xNextRange( xEnum->nextElement(), uno::UNO_QUERY_THROW );
3113  ScVbaRange* pRange = dynamic_cast< ScVbaRange * > ( xNextRange.get() );
3114  if ( pRange )
3115  pRange->fireChangeEvent();
3116  }
3117  }
3118  }
3119  }
3120  }
3121  return true; // always
3122 }
3123 
3124 uno::Reference< excel::XRange > SAL_CALL
3125 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*/ )
3126 {
3127  // return a Range object that represents the first cell where that information is found.
3128  OUString sWhat;
3129  sal_Int32 nWhat = 0;
3130  double fWhat = 0.0;
3131 
3132  // string.
3133  if( What >>= sWhat )
3134  {}
3135  else if( What >>= nWhat )
3136  {
3137  sWhat = OUString::number( nWhat );
3138  }
3139  else if( What >>= fWhat )
3140  {
3141  sWhat = OUString::number( fWhat );
3142  }
3143  else
3144  throw uno::RuntimeException("Range::Find, missing search-for-what param" );
3145 
3146  OUString sSearch = VBAToRegexp( sWhat );
3147 
3148  const SvxSearchItem& globalSearchOptions = ScGlobal::GetSearchItem();
3149  SvxSearchItem newOptions( globalSearchOptions );
3150 
3151  uno::Reference< util::XSearchable > xSearch( mxRange, uno::UNO_QUERY );
3152  if( xSearch.is() )
3153  {
3154  uno::Reference< util::XSearchDescriptor > xDescriptor = xSearch->createSearchDescriptor();
3155  xDescriptor->setSearchString( sSearch );
3156  xDescriptor->setPropertyValue( SC_UNO_SRCHREGEXP, uno::Any( true ) );
3157 
3158  uno::Reference< excel::XRange > xAfterRange;
3159  uno::Reference< table::XCellRange > xStartCell;
3160  if( After >>= xAfterRange )
3161  {
3162  // After must be a single cell in the range
3163  if( xAfterRange->getCount() > 1 )
3164  throw uno::RuntimeException("After must be a single cell." );
3165  uno::Reference< excel::XRange > xCell( Cells( uno::makeAny( xAfterRange->getRow() ), uno::makeAny( xAfterRange->getColumn() ) ), uno::UNO_SET_THROW );
3166  xStartCell.set( xAfterRange->getCellRange(), uno::UNO_QUERY_THROW );
3167  }
3168 
3169  // LookIn
3170  if( LookIn.hasValue() )
3171  {
3172  sal_Int32 nLookIn = 0;
3173  if( LookIn >>= nLookIn )
3174  {
3175  SvxSearchCellType nSearchType;
3176  switch( nLookIn )
3177  {
3178  case excel::XlFindLookIn::xlComments :
3179  nSearchType = SvxSearchCellType::NOTE; // Notes
3180  break;
3181  case excel::XlFindLookIn::xlFormulas :
3182  nSearchType = SvxSearchCellType::FORMULA;
3183  break;
3184  case excel::XlFindLookIn::xlValues :
3185  nSearchType = SvxSearchCellType::VALUE;
3186  break;
3187  default:
3188  throw uno::RuntimeException("Range::Find, illegal value for LookIn." );
3189  }
3190  newOptions.SetCellType( nSearchType );
3191  xDescriptor->setPropertyValue( "SearchType", uno::makeAny( static_cast<sal_uInt16>(nSearchType) ) );
3192  }
3193  }
3194 
3195  // LookAt
3196  if ( LookAt.hasValue() )
3197  {
3198  sal_Int16 nLookAt = ::comphelper::getINT16( LookAt );
3199  bool bSearchWords = false;
3200  if ( nLookAt == excel::XlLookAt::xlPart )
3201  bSearchWords = false;
3202  else if ( nLookAt == excel::XlLookAt::xlWhole )
3203  bSearchWords = true;
3204  else
3205  throw uno::RuntimeException("Range::Find, illegal value for LookAt" );
3206  newOptions.SetWordOnly( bSearchWords );
3207  xDescriptor->setPropertyValue( SC_UNO_SRCHWORDS, uno::makeAny( bSearchWords ) );
3208  }
3209 
3210  // SearchOrder
3211  if ( SearchOrder.hasValue() )
3212  {
3213  sal_Int16 nSearchOrder = ::comphelper::getINT16( SearchOrder );
3214  bool bSearchByRow = false;
3215  if ( nSearchOrder == excel::XlSearchOrder::xlByColumns )
3216  bSearchByRow = false;
3217  else if ( nSearchOrder == excel::XlSearchOrder::xlByRows )
3218  bSearchByRow = true;
3219  else
3220  throw uno::RuntimeException("Range::Find, illegal value for SearchOrder" );
3221 
3222  newOptions.SetRowDirection( bSearchByRow );
3223  xDescriptor->setPropertyValue( SC_UNO_SRCHBYROW, uno::makeAny( bSearchByRow ) );
3224  }
3225 
3226  // SearchDirection
3227  if ( SearchDirection.hasValue() )
3228  {
3229  sal_Int32 nSearchDirection = 0;
3230  if( SearchDirection >>= nSearchDirection )
3231  {
3232  bool bSearchBackwards = false;
3233  if ( nSearchDirection == excel::XlSearchDirection::xlNext )
3234  bSearchBackwards = false;
3235  else if( nSearchDirection == excel::XlSearchDirection::xlPrevious )
3236  bSearchBackwards = true;
3237  else
3238  throw uno::RuntimeException("Range::Find, illegal value for SearchDirection" );
3239  newOptions.SetBackward( bSearchBackwards );
3240  xDescriptor->setPropertyValue( "SearchBackwards", uno::makeAny( bSearchBackwards ) );
3241  }
3242  }
3243 
3244  // MatchCase
3245  bool bMatchCase = false;
3246  if ( MatchCase.hasValue() )
3247  {
3248  // SearchCaseSensitive
3249  if( !( MatchCase >>= bMatchCase ) )
3250  throw uno::RuntimeException("Range::Find illegal value for MatchCase" );
3251  }
3252  xDescriptor->setPropertyValue( SC_UNO_SRCHCASE, uno::makeAny( bMatchCase ) );
3253 
3254  // MatchByte
3255  // SearchFormat
3256  // ignore
3257 
3258  ScGlobal::SetSearchItem( newOptions );
3259 
3260  uno::Reference< uno::XInterface > xInterface = xStartCell.is() ? xSearch->findNext( xStartCell, xDescriptor) : xSearch->findFirst( xDescriptor );
3261  uno::Reference< table::XCellRange > xCellRange( xInterface, uno::UNO_QUERY );
3262  // if we are searching from a starting cell and failed to find a match
3263  // then try from the beginning
3264  if ( !xCellRange.is() && xStartCell.is() )
3265  {
3266  xInterface = xSearch->findFirst( xDescriptor );
3267  xCellRange.set( xInterface, uno::UNO_QUERY );
3268  }
3269  if ( xCellRange.is() )
3270  {
3271  uno::Reference< excel::XRange > xResultRange = new ScVbaRange( mxParent, mxContext, xCellRange );
3272  if( xResultRange.is() )
3273  {
3274  return xResultRange;
3275  }
3276  }
3277 
3278  }
3279 
3280  return uno::Reference< excel::XRange >();
3281 }
3282 
3283 static uno::Reference< table::XCellRange > processKey( const uno::Any& Key, const uno::Reference< uno::XComponentContext >& xContext, ScDocShell* pDocSh )
3284 {
3285  uno::Reference< excel::XRange > xKeyRange;
3286  if ( Key.getValueType() == cppu::UnoType<excel::XRange>::get() )
3287  {
3288  xKeyRange.set( Key, uno::UNO_QUERY_THROW );
3289  }
3290  else if ( Key.getValueType() == ::cppu::UnoType<OUString>::get() )
3291 
3292  {
3293  OUString sRangeName = ::comphelper::getString( Key );
3294  table::CellRangeAddress aRefAddr;
3295  if ( !pDocSh )
3296  throw uno::RuntimeException("Range::Sort no docshell to calculate key param" );
3297  xKeyRange = getRangeForName( xContext, sRangeName, pDocSh, aRefAddr );
3298  }
3299  else
3300  throw uno::RuntimeException("Range::Sort illegal type value for key param" );
3301  uno::Reference< table::XCellRange > xKey;
3302  xKey.set( xKeyRange->getCellRange(), uno::UNO_QUERY_THROW );
3303  return xKey;
3304 }
3305 
3306 // helper method for Sort
3308 static sal_Int32 findSortPropertyIndex( const uno::Sequence< beans::PropertyValue >& props,
3309 const OUString& sPropName )
3310 {
3311  const beans::PropertyValue* pProp = std::find_if(props.begin(), props.end(),
3312  [&sPropName](const beans::PropertyValue& rProp) { return rProp.Name == sPropName; });
3313 
3314  if ( pProp == props.end() )
3315  throw uno::RuntimeException("Range::Sort unknown sort property" );
3316  return static_cast<sal_Int32>(std::distance(props.begin(), pProp));
3317 }
3318 
3319 // helper method for Sort
3321 static void updateTableSortField( const uno::Reference< table::XCellRange >& xParentRange,
3322  const uno::Reference< table::XCellRange >& xColRowKey, sal_Int16 nOrder,
3323  table::TableSortField& aTableField, bool bIsSortColumn, bool bMatchCase )
3324 {
3325  RangeHelper parentRange( xParentRange );
3326  RangeHelper colRowRange( xColRowKey );
3327 
3328  table::CellRangeAddress parentRangeAddress = parentRange.getCellRangeAddressable()->getRangeAddress();
3329 
3330  table::CellRangeAddress colRowKeyAddress = colRowRange.getCellRangeAddressable()->getRangeAddress();
3331 
3332  // make sure that upper left point of key range is within the
3333  // parent range
3334  if (
3335  ( bIsSortColumn || colRowKeyAddress.StartColumn < parentRangeAddress.StartColumn ||
3336  colRowKeyAddress.StartColumn > parentRangeAddress.EndColumn )
3337  &&
3338  ( !bIsSortColumn || colRowKeyAddress.StartRow < parentRangeAddress.StartRow ||
3339  colRowKeyAddress.StartRow > parentRangeAddress.EndRow )
3340  )
3341  throw uno::RuntimeException("Illegal Key param" );
3342 
3343  //determine col/row index
3344  if ( bIsSortColumn )
3345  aTableField.Field = colRowKeyAddress.StartRow - parentRangeAddress.StartRow;
3346  else
3347  aTableField.Field = colRowKeyAddress.StartColumn - parentRangeAddress.StartColumn;
3348  aTableField.IsCaseSensitive = bMatchCase;
3349 
3350  if ( nOrder == excel::XlSortOrder::xlAscending )
3351  aTableField.IsAscending = true;
3352  else
3353  aTableField.IsAscending = false;
3354 
3355 
3356 }
3357 
3358 void SAL_CALL
3359 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 )
3360 {
3361  // #TODO# #FIXME# can we do something with Type
3362  if ( m_Areas->getCount() > 1 )
3363  throw uno::RuntimeException("That command cannot be used on multiple selections" );
3364 
3365  sal_Int16 nDataOption1 = excel::XlSortDataOption::xlSortNormal;
3366  sal_Int16 nDataOption2 = excel::XlSortDataOption::xlSortNormal;
3367  sal_Int16 nDataOption3 = excel::XlSortDataOption::xlSortNormal;
3368 
3369  ScDocument& rDoc = getScDocument();
3370 
3371  RangeHelper thisRange( mxRange );
3372  table::CellRangeAddress thisRangeAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
3373  ScSortParam aSortParam;
3374  SCTAB nTab = thisRangeAddress.Sheet;
3375  rDoc.GetSortParam( aSortParam, nTab );
3376 
3377  if ( DataOption1.hasValue() )
3378  DataOption1 >>= nDataOption1;
3379  if ( DataOption2.hasValue() )
3380  DataOption2 >>= nDataOption2;
3381  if ( DataOption3.hasValue() )
3382  DataOption3 >>= nDataOption3;
3383 
3384  // 1) #TODO #FIXME need to process DataOption[1..3] not used currently
3385  // 2) #TODO #FIXME need to refactor this ( below ) into an IsSingleCell() method
3386  uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY_THROW );
3387 
3388  // set up defaults
3389 
3390  sal_Int16 nOrder1 = aSortParam.maKeyState[1].bAscending ? excel::XlSortOrder::xlAscending : excel::XlSortOrder::xlDescending;
3391  sal_Int16 nOrder2 = aSortParam.maKeyState[2].bAscending ? excel::XlSortOrder::xlAscending : excel::XlSortOrder::xlDescending;
3392  sal_Int16 nOrder3 = aSortParam.maKeyState[3].bAscending ? excel::XlSortOrder::xlAscending : excel::XlSortOrder::xlDescending;
3393 
3394  sal_Int16 nCustom = aSortParam.nUserIndex;
3395  sal_Int16 nSortMethod = excel::XlSortMethod::xlPinYin;
3396  bool bMatchCase = aSortParam.bCaseSens;
3397 
3398  // seems to work opposite to expected, see below
3399  sal_Int16 nOrientation = aSortParam.bByRow ? excel::XlSortOrientation::xlSortColumns : excel::XlSortOrientation::xlSortRows;
3400 
3401  if ( Orientation.hasValue() )
3402  {
3403  // Documentation says xlSortRows is default but that doesn't appear to be
3404  // the case. Also it appears that xlSortColumns is the default which
3405  // strangely enough sorts by Row
3406  nOrientation = ::comphelper::getINT16( Orientation );
3407  // persist new option to be next calls default
3408  if ( nOrientation == excel::XlSortOrientation::xlSortRows )
3409  aSortParam.bByRow = false;
3410  else
3411  aSortParam.bByRow = true;
3412 
3413  }
3414 
3415  bool bIsSortColumns=false; // sort by row
3416 
3417  if ( nOrientation == excel::XlSortOrientation::xlSortRows )
3418  bIsSortColumns = true;
3419  sal_Int16 nHeader = aSortParam.nCompatHeader;
3420  bool bContainsHeader = false;
3421 
3422  if ( Header.hasValue() )
3423  {
3424  nHeader = ::comphelper::getINT16( Header );
3425  aSortParam.nCompatHeader = nHeader;
3426  }
3427 
3428  if ( nHeader == excel::XlYesNoGuess::xlGuess )
3429  {
3430  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 ));
3431  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 ) );
3432  if ( bHasColHeader || bHasRowHeader )
3433  nHeader = excel::XlYesNoGuess::xlYes;
3434  else
3435  nHeader = excel::XlYesNoGuess::xlNo;
3436  aSortParam.nCompatHeader = nHeader;
3437  }
3438 
3439  if ( nHeader == excel::XlYesNoGuess::xlYes )
3440  bContainsHeader = true;
3441 
3442  if ( SortMethod.hasValue() )
3443  {
3444  nSortMethod = ::comphelper::getINT16( SortMethod );
3445  }
3446 
3447  if ( OrderCustom.hasValue() )
3448  {
3449  OrderCustom >>= nCustom;
3450  --nCustom; // 0-based in OOo
3451  aSortParam.nUserIndex = nCustom;
3452  }
3453 
3454  if ( MatchCase.hasValue() )
3455  {
3456  MatchCase >>= bMatchCase;
3457  aSortParam.bCaseSens = bMatchCase;
3458  }
3459 
3460  if ( Order1.hasValue() )
3461  {
3462  nOrder1 = ::comphelper::getINT16(Order1);
3463  if ( nOrder1 == excel::XlSortOrder::xlAscending )
3464  aSortParam.maKeyState[0].bAscending = true;
3465  else
3466  aSortParam.maKeyState[0].bAscending = false;
3467 
3468  }
3469  if ( Order2.hasValue() )
3470  {
3471  nOrder2 = ::comphelper::getINT16(Order2);
3472  if ( nOrder2 == excel::XlSortOrder::xlAscending )
3473  aSortParam.maKeyState[1].bAscending = true;
3474  else
3475  aSortParam.maKeyState[1].bAscending = false;
3476  }
3477  if ( Order3.hasValue() )
3478  {
3479  nOrder3 = ::comphelper::getINT16(Order3);
3480  if ( nOrder3 == excel::XlSortOrder::xlAscending )
3481  aSortParam.maKeyState[2].bAscending = true;
3482  else
3483  aSortParam.maKeyState[2].bAscending = false;
3484  }
3485 
3486  uno::Reference< table::XCellRange > xKey1;
3487  uno::Reference< table::XCellRange > xKey2;
3488  uno::Reference< table::XCellRange > xKey3;
3489  ScDocShell* pDocShell = getScDocShell();
3490  xKey1 = processKey( Key1, mxContext, pDocShell );
3491  if ( !xKey1.is() )
3492  throw uno::RuntimeException("Range::Sort needs a key1 param" );
3493 
3494  if ( Key2.hasValue() )
3495  xKey2 = processKey( Key2, mxContext, pDocShell );
3496  if ( Key3.hasValue() )
3497  xKey3 = processKey( Key3, mxContext, pDocShell );
3498 
3499  uno::Reference< util::XSortable > xSort( mxRange, uno::UNO_QUERY_THROW );
3500  uno::Sequence< beans::PropertyValue > sortDescriptor = xSort->createSortDescriptor();
3501  sal_Int32 nTableSortFieldIndex = findSortPropertyIndex( sortDescriptor, "SortFields" );
3502 
3503  uno::Sequence< table::TableSortField > sTableFields(1);
3504  sal_Int32 nTableIndex = 0;
3505  updateTableSortField( mxRange, xKey1, nOrder1, sTableFields[ nTableIndex++ ], bIsSortColumns, bMatchCase );
3506 
3507  if ( xKey2.is() )
3508  {
3509  sTableFields.realloc( sTableFields.getLength() + 1 );
3510  updateTableSortField( mxRange, xKey2, nOrder2, sTableFields[ nTableIndex++ ], bIsSortColumns, bMatchCase );
3511  }
3512  if ( xKey3.is() )
3513  {
3514  sTableFields.realloc( sTableFields.getLength() + 1 );
3515  updateTableSortField( mxRange, xKey3, nOrder3, sTableFields[ nTableIndex++ ], bIsSortColumns, bMatchCase );
3516  }
3517  sortDescriptor[ nTableSortFieldIndex ].Value <<= sTableFields;
3518 
3519  sal_Int32 nIndex = findSortPropertyIndex( sortDescriptor, "IsSortColumns" );
3520  sortDescriptor[ nIndex ].Value <<= bIsSortColumns;
3521 
3522  nIndex = findSortPropertyIndex( sortDescriptor, "ContainsHeader" );
3523  sortDescriptor[ nIndex ].Value <<= bContainsHeader;
3524 
3525  rDoc.SetSortParam( aSortParam, nTab );
3526  xSort->sort( sortDescriptor );
3527 
3528  // #FIXME #TODO
3529  // The SortMethod param is not processed ( not sure what its all about, need to
3530  (void)nSortMethod;
3531 }
3532 
3533 uno::Reference< excel::XRange > SAL_CALL
3535 {
3536  if ( m_Areas->getCount() > 1 )
3537  {
3538  uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW );
3539  return xRange->End( Direction );
3540  }
3541 
3542  // #FIXME #TODO
3543  // euch! found my orig implementation sucked, so
3544  // trying this even sucker one (really need to use/expose code in
3545  // around ScTabView::MoveCursorArea(), that's the bit that calculates
3546  // where the cursor should go)
3547  // Main problem with this method is the ultra hacky attempt to preserve
3548  // the ActiveCell, there should be no need to go to these extremes
3549 
3550  // Save ActiveSheet/ActiveCell pos (to restore later)
3551  uno::Any aDft;
3552  uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW );
3553  uno::Reference< excel::XWorksheet > sActiveSheet = xApplication->getActiveSheet();
3554  OUString sActiveCell = xApplication->getActiveCell()->Address(aDft, aDft, aDft, aDft, aDft );
3555 
3556  // position current cell upper left of this range
3557  Cells( uno::makeAny( sal_Int32(1) ), uno::makeAny( sal_Int32(1) ) )->Select();
3558 
3559  uno::Reference< frame::XModel > xModel = getModelFromRange( mxRange );
3560 
3561  SfxViewFrame* pViewFrame = excel::getViewFrame( xModel );
3562  if ( pViewFrame )
3563  {
3564  SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
3565  // Hoping this will make sure this slot is called
3566  // synchronously
3567  SfxBoolItem sfxAsync( SID_ASYNCHRON, false );
3568  aArgs.Put( sfxAsync, sfxAsync.Which() );
3569  SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher();
3570 
3571  sal_uInt16 nSID = 0;
3572 
3573  switch( Direction )
3574  {
3575  case excel::XlDirection::xlDown:
3576  nSID = SID_CURSORBLKDOWN;
3577  break;
3578  case excel::XlDirection::xlUp:
3579  nSID = SID_CURSORBLKUP;
3580  break;
3581  case excel::XlDirection::xlToLeft:
3582  nSID = SID_CURSORBLKLEFT;
3583  break;
3584  case excel::XlDirection::xlToRight:
3585  nSID = SID_CURSORBLKRIGHT;
3586  break;
3587  default:
3588  throw uno::RuntimeException(": Invalid ColumnIndex" );
3589  }
3590  if ( pDispatcher )
3591  {
3592  pDispatcher->Execute( nSID, SfxCallMode::SYNCHRON, aArgs );
3593  }
3594  }
3595 
3596  // result is the ActiveCell
3597  OUString sMoved = xApplication->getActiveCell()->Address(aDft, aDft, aDft, aDft, aDft );
3598 
3599  uno::Any aVoid;
3600  uno::Reference< excel::XRange > resultCell;
3601  resultCell.set( xApplication->getActiveSheet()->Range( uno::makeAny( sMoved ), aVoid ), uno::UNO_SET_THROW );
3602 
3603  // restore old ActiveCell
3604  uno::Reference< excel::XRange > xOldActiveCell( sActiveSheet->Range( uno::makeAny( sActiveCell ), aVoid ), uno::UNO_SET_THROW );
3605  xOldActiveCell->Select();
3606 
3607 
3608  // return result
3609  return resultCell;
3610 }
3611 
3612 bool
3614 {
3615  uno::Reference< sheet::XCellRangeAddressable > xAddressable( mxRange, uno::UNO_QUERY );
3616  if ( xAddressable.is() )
3617  {
3618  table::CellRangeAddress aRangeAddr = xAddressable->getRangeAddress();
3619  return ( aRangeAddr.EndColumn == aRangeAddr.StartColumn && aRangeAddr.EndRow == aRangeAddr.StartRow );
3620  }
3621  return false;
3622 }
3623 
3624 uno::Reference< excel::XCharacters > SAL_CALL
3625 ScVbaRange::characters( const uno::Any& Start, const uno::Any& Length )
3626 {
3627  if ( !isSingleCellRange() )
3628  throw uno::RuntimeException("Can't create Characters property for multicell range " );
3629  uno::Reference< text::XSimpleText > xSimple(mxRange->getCellByPosition(0,0) , uno::UNO_QUERY_THROW );
3631 
3632  ScVbaPalette aPalette( rDoc.GetDocumentShell() );
3633  return new ScVbaCharacters( this, mxContext, aPalette, xSimple, Start, Length );
3634 }
3635 
3636  void SAL_CALL
3638 {
3639  if ( m_Areas->getCount() > 1 )
3640  {
3641  sal_Int32 nItems = m_Areas->getCount();
3642  for ( sal_Int32 index=1; index <= nItems; ++index )
3643  {
3644  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW );
3645  xRange->Delete( Shift );
3646  }
3647  return;
3648  }
3649  sheet::CellDeleteMode mode = sheet::CellDeleteMode_NONE ;
3650  RangeHelper thisRange( mxRange );
3651  table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
3652  if ( Shift.hasValue() )
3653  {
3654  sal_Int32 nShift = 0;
3655  Shift >>= nShift;
3656  switch ( nShift )
3657  {
3658  case excel::XlDeleteShiftDirection::xlShiftUp:
3659  mode = sheet::CellDeleteMode_UP;
3660  break;
3661  case excel::XlDeleteShiftDirection::xlShiftToLeft:
3662  mode = sheet::CellDeleteMode_LEFT;
3663  break;
3664  default:
3665  throw uno::RuntimeException("Illegal parameter " );
3666  }
3667  }
3668  else
3669  {
3670  ScDocument& rDoc = getScDocument();
3671  bool bFullRow = ( thisAddress.StartColumn == 0 && thisAddress.EndColumn == rDoc.MaxCol() );
3672  sal_Int32 nCols = thisAddress.EndColumn - thisAddress.StartColumn;
3673  sal_Int32 nRows = thisAddress.EndRow - thisAddress.StartRow;
3674  if ( mbIsRows || bFullRow || ( nCols >= nRows ) )
3675  mode = sheet::CellDeleteMode_UP;
3676  else
3677  mode = sheet::CellDeleteMode_LEFT;
3678  }
3679  uno::Reference< sheet::XCellRangeMovement > xCellRangeMove( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW );
3680  xCellRangeMove->removeRange( thisAddress, mode );
3681 
3682 }
3683 
3684 //XElementAccess
3685 sal_Bool SAL_CALL
3687 {
3688  uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY );
3689  if ( xColumnRowRange.is() )
3690  if ( xColumnRowRange->getRows()->getCount() ||
3691  xColumnRowRange->getColumns()->getCount() )
3692  return true;
3693  return false;
3694 }
3695 
3696 // XEnumerationAccess
3697 uno::Reference< container::XEnumeration > SAL_CALL
3699 {
3700  if ( mbIsColumns || mbIsRows )
3701  {
3702  uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY );
3703  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW );
3704  sal_Int32 nElems = 0;
3705  if ( mbIsColumns )
3706  nElems = xColumnRowRange->getColumns()->getCount();
3707  else
3708  nElems = xColumnRowRange->getRows()->getCount();
3709  return new ColumnsRowEnumeration( xRange, nElems );
3710 
3711  }
3712  return new CellsEnumeration( mxParent, mxContext, m_Areas );
3713 }
3714 
3715 OUString SAL_CALL
3717 {
3718  return "Item";
3719 }
3720 
3721 // returns calc internal col. width ( in points )
3722 double
3723 ScVbaRange::getCalcColWidth(const table::CellRangeAddress& rAddress)
3724 {
3725  ScDocument& rDoc = getScDocument();
3726  sal_uInt16 nWidth = rDoc.GetOriginalWidth( static_cast< SCCOL >( rAddress.StartColumn ), static_cast< SCTAB >( rAddress.Sheet ) );
3727  double nPoints = lcl_TwipsToPoints( nWidth );
3728  nPoints = lcl_Round2DecPlaces( nPoints );
3729  return nPoints;
3730 }
3731 
3732 double
3733 ScVbaRange::getCalcRowHeight(const table::CellRangeAddress& rAddress)
3734 {
3736  sal_uInt16 nWidth = rDoc.GetOriginalHeight( rAddress.StartRow, rAddress.Sheet );
3737  double nPoints = lcl_TwipsToPoints( nWidth );
3738  nPoints = lcl_Round2DecPlaces( nPoints );
3739  return nPoints;
3740 }
3741 
3742 // return Char Width in points
3743 static double getDefaultCharWidth( ScDocShell* pDocShell )
3744 {
3745  ScDocument& rDoc = pDocShell->GetDocument();
3746  OutputDevice* pRefDevice = rDoc.GetRefDevice();
3747  ScPatternAttr* pAttr = rDoc.GetDefPattern();
3748  vcl::Font aDefFont;
3749  pAttr->GetFont( aDefFont, SC_AUTOCOL_BLACK, pRefDevice );
3750  pRefDevice->SetFont( aDefFont );
3751  long nCharWidth = pRefDevice->GetTextWidth( OUString( '0' ) ); // 1/100th mm
3752  return lcl_hmmToPoints( nCharWidth );
3753 }
3754 
3755 uno::Any SAL_CALL
3757 {
3758  sal_Int32 nLen = m_Areas->getCount();
3759  if ( nLen > 1 )
3760  {
3761  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW );
3762  return xRange->getColumnWidth();
3763  }
3764 
3765  double nColWidth = 0;
3766  ScDocShell* pShell = getScDocShell();
3767  if ( pShell )
3768  {
3769  double defaultCharWidth = getDefaultCharWidth( pShell );
3770  RangeHelper thisRange( mxRange );
3771  table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
3772  sal_Int32 nStartCol = thisAddress.StartColumn;
3773  sal_Int32 nEndCol = thisAddress.EndColumn;
3774  sal_uInt16 nColTwips = 0;
3775  for( sal_Int32 nCol = nStartCol ; nCol <= nEndCol; ++nCol )
3776  {
3777  thisAddress.StartColumn = nCol;
3778  sal_uInt16 nCurTwips = pShell->GetDocument().GetOriginalWidth( static_cast< SCCOL >( thisAddress.StartColumn ), static_cast< SCTAB >( thisAddress.Sheet ) );
3779  if ( nCol == nStartCol )
3780  nColTwips = nCurTwips;
3781  if ( nColTwips != nCurTwips )
3782  return aNULL();
3783  }
3784  nColWidth = lcl_TwipsToPoints( nColTwips );
3785  if ( nColWidth != 0.0 )
3786  nColWidth = ( nColWidth / defaultCharWidth ) - fExtraWidth;
3787  }
3788  nColWidth = lcl_Round2DecPlaces( nColWidth );
3789  return uno::makeAny( nColWidth );
3790 }
3791 
3792 void SAL_CALL
3793 ScVbaRange::setColumnWidth( const uno::Any& _columnwidth )
3794 {
3795  sal_Int32 nLen = m_Areas->getCount();
3796  if ( nLen > 1 )
3797  {
3798  for ( sal_Int32 index = 1; index != nLen; ++index )
3799  {
3800  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( index ), uno::Any() ), uno::UNO_QUERY_THROW );
3801  xRange->setColumnWidth( _columnwidth );
3802  }
3803  return;
3804  }
3805  double nColWidth = 0;
3806  _columnwidth >>= nColWidth;
3807  nColWidth = lcl_Round2DecPlaces( nColWidth );
3808  ScDocShell* pDocShell = getScDocShell();
3809  if ( pDocShell )
3810  {
3811  if ( nColWidth != 0.0 )
3812  nColWidth = ( nColWidth + fExtraWidth ) * getDefaultCharWidth( pDocShell );
3813  RangeHelper thisRange( mxRange );
3814  table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
3815  sal_uInt16 nTwips = lcl_pointsToTwips( nColWidth );
3816 
3817  std::vector<sc::ColRowSpan> aColArr(1, sc::ColRowSpan(thisAddress.StartColumn, thisAddress.EndColumn));
3818  // #163561# use mode SC_SIZE_DIRECT: hide for width 0, show for other values
3819  pDocShell->GetDocFunc().SetWidthOrHeight(
3820  true, aColArr, thisAddress.Sheet, SC_SIZE_DIRECT, nTwips, true, true);
3821  }
3822 }
3823 
3824 uno::Any SAL_CALL
3826 {
3827  if ( m_Areas->getCount() > 1 )
3828  {
3829  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW );
3830  return xRange->getWidth();
3831  }
3832  uno::Reference< table::XColumnRowRange > xColRowRange( mxRange, uno::UNO_QUERY_THROW );
3833  uno::Reference< container::XIndexAccess > xIndexAccess( xColRowRange->getColumns(), uno::UNO_QUERY_THROW );
3834  sal_Int32 nElems = xIndexAccess->getCount();
3835  double nWidth = 0;
3836  for ( sal_Int32 index=0; index<nElems; ++index )
3837  {
3838  uno::Reference< sheet::XCellRangeAddressable > xAddressable( xIndexAccess->getByIndex( index ), uno::UNO_QUERY_THROW );
3839  double nTmpWidth = getCalcColWidth( xAddressable->getRangeAddress() );
3840  nWidth += nTmpWidth;
3841  }
3842  return uno::makeAny( nWidth );
3843 }
3844 
3845 uno::Any SAL_CALL
3847 {
3848  if ( !item.hasValue() )
3849  return uno::makeAny( m_Areas );
3850  return m_Areas->Item( item, uno::Any() );
3851 }
3852 
3853 uno::Reference< excel::XRange >
3854 ScVbaRange::getArea( sal_Int32 nIndex )
3855 {
3856  if ( !m_Areas.is() )
3857  throw uno::RuntimeException("No areas available" );
3858  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( ++nIndex ), uno::Any() ), uno::UNO_QUERY_THROW );
3859  return xRange;
3860 }
3861 
3862 uno::Any
3864 {
3865  if ( !item.hasValue() )
3866  return uno::makeAny( getBorders() );
3867  return getBorders()->Item( item, uno::Any() );
3868 }
3869 
3870 uno::Any SAL_CALL
3871 ScVbaRange::BorderAround( const css::uno::Any& LineStyle, const css::uno::Any& Weight,
3872  const css::uno::Any& ColorIndex, const css::uno::Any& Color )
3873 {
3874  sal_Int32 nCount = getBorders()->getCount();
3875 
3876  for( sal_Int32 i = 0; i < nCount; i++ )
3877  {
3878  const sal_Int32 nLineType = supportedIndexTable[i];
3879  switch( nLineType )
3880  {
3881  case excel::XlBordersIndex::xlEdgeLeft:
3882  case excel::XlBordersIndex::xlEdgeTop:
3883  case excel::XlBordersIndex::xlEdgeBottom:
3884  case excel::XlBordersIndex::xlEdgeRight:
3885  {
3886  uno::Reference< excel::XBorder > xBorder( m_Borders->Item( uno::makeAny( nLineType ), uno::Any() ), uno::UNO_QUERY_THROW );
3887  if( LineStyle.hasValue() )
3888  {
3889  xBorder->setLineStyle( LineStyle );
3890  }
3891  if( Weight.hasValue() )
3892  {
3893  xBorder->setWeight( Weight );
3894  }
3895  if( ColorIndex.hasValue() )
3896  {
3897  xBorder->setColorIndex( ColorIndex );
3898  }
3899  if( Color.hasValue() )
3900  {
3901  xBorder->setColor( Color );
3902  }
3903  break;
3904  }
3905  case excel::XlBordersIndex::xlInsideVertical:
3906  case excel::XlBordersIndex::xlInsideHorizontal:
3907  case excel::XlBordersIndex::xlDiagonalDown:
3908  case excel::XlBordersIndex::xlDiagonalUp:
3909  break;
3910  default:
3911  return uno::makeAny( false );
3912  }
3913  }
3914  return uno::makeAny( true );
3915 }
3916 
3917 uno::Any SAL_CALL
3919 {
3920  sal_Int32 nLen = m_Areas->getCount();
3921  if ( nLen > 1 )
3922  {
3923  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW );
3924  return xRange->getRowHeight();
3925  }
3926 
3927  // if any row's RowHeight in the
3928  // range is different from any other, then return NULL
3929  RangeHelper thisRange( mxRange );
3930  table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
3931 
3932  sal_Int32 nStartRow = thisAddress.StartRow;
3933  sal_Int32 nEndRow = thisAddress.EndRow;
3934  sal_uInt16 nRowTwips = 0;
3935  // #TODO probably possible to use the SfxItemSet (and see if
3936  // SfxItemState::DONTCARE is set) to improve performance
3937 // #CHECKME looks like this is general behaviour not just row Range specific
3938 // if ( mbIsRows )
3939  ScDocShell* pShell = getScDocShell();
3940  if ( pShell )
3941  {
3942  for ( sal_Int32 nRow = nStartRow ; nRow <= nEndRow; ++nRow )
3943  {
3944  thisAddress.StartRow = nRow;
3945  sal_uInt16 nCurTwips = pShell->GetDocument().GetOriginalHeight( thisAddress.StartRow, thisAddress.Sheet );
3946  if ( nRow == nStartRow )
3947  nRowTwips = nCurTwips;
3948  if ( nRowTwips != nCurTwips )
3949  return aNULL();
3950  }
3951  }
3952  double nHeight = lcl_Round2DecPlaces( lcl_TwipsToPoints( nRowTwips ) );
3953  return uno::makeAny( nHeight );
3954 }
3955 
3956 void SAL_CALL
3958 {
3959  sal_Int32 nLen = m_Areas->getCount();
3960  if ( nLen > 1 )
3961  {
3962  for ( sal_Int32 index = 1; index != nLen; ++index )
3963  {
3964  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( index ), uno::Any() ), uno::UNO_QUERY_THROW );
3965  xRange->setRowHeight( _rowheight );
3966  }
3967  return;
3968  }
3969  double nHeight = 0; // Incoming height is in points
3970  _rowheight >>= nHeight;
3971  nHeight = lcl_Round2DecPlaces( nHeight );
3972  RangeHelper thisRange( mxRange );
3973  table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
3974  sal_uInt16 nTwips = lcl_pointsToTwips( nHeight );
3975 
3976  ScDocShell* pDocShell = getDocShellFromRange( mxRange );
3977  std::vector<sc::ColRowSpan> aRowArr(1, sc::ColRowSpan(thisAddress.StartRow, thisAddress.EndRow));
3978  pDocShell->GetDocFunc().SetWidthOrHeight(
3979  false, aRowArr, thisAddress.Sheet, SC_SIZE_ORIGINAL, nTwips, true, true);
3980 }
3981 
3982 uno::Any SAL_CALL
3984 {
3985  sal_Int32 nPageBreak = excel::XlPageBreak::xlPageBreakNone;
3987  if ( pShell )
3988  {
3989  RangeHelper thisRange( mxRange );
3990  table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
3991  bool bColumn = false;
3992 
3993  if (thisAddress.StartRow==0)
3994  bColumn = true;
3995 
3996  uno::Reference< frame::XModel > xModel = pShell->GetModel();
3997  if ( xModel.is() )
3998  {
4000 
4001  ScBreakType nBreak = ScBreakType::NONE;
4002  if ( !bColumn )
4003  nBreak = rDoc.HasRowBreak(thisAddress.StartRow, thisAddress.Sheet);
4004  else
4005  nBreak = rDoc.HasColBreak(thisAddress.StartColumn, thisAddress.Sheet);
4006 
4007  if (nBreak & ScBreakType::Page)
4008  nPageBreak = excel::XlPageBreak::xlPageBreakAutomatic;
4009 
4010  if (nBreak & ScBreakType::Manual)
4011  nPageBreak = excel::XlPageBreak::xlPageBreakManual;
4012  }
4013  }
4014 
4015  return uno::makeAny( nPageBreak );
4016 }
4017 
4018 void SAL_CALL
4020 {
4021  sal_Int32 nPageBreak = 0;
4022  _pagebreak >>= nPageBreak;
4023 
4025  if ( pShell )
4026  {
4027  RangeHelper thisRange( mxRange );
4028  table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
4029  if ((thisAddress.StartColumn==0) && (thisAddress.StartRow==0))
4030  return;
4031  bool bColumn = false;
4032 
4033  if (thisAddress.StartRow==0)
4034  bColumn = true;
4035 
4036  ScAddress aAddr( static_cast<SCCOL>(thisAddress.StartColumn), thisAddress.StartRow, thisAddress.Sheet );
4037  uno::Reference< frame::XModel > xModel = pShell->GetModel();
4038  if ( xModel.is() )
4039  {
4040  ScTabViewShell* pViewShell = excel::getBestViewShell( xModel );
4041  if ( nPageBreak == excel::XlPageBreak::xlPageBreakManual )
4042  pViewShell->InsertPageBreak( bColumn, true, &aAddr);
4043  else if ( nPageBreak == excel::XlPageBreak::xlPageBreakNone )
4044  pViewShell->DeletePageBreak( bColumn, true, &aAddr);
4045  }
4046  }
4047 }
4048 
4049 uno::Any SAL_CALL
4051 {
4052  if ( m_Areas->getCount() > 1 )
4053  {
4054  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW );
4055  return xRange->getHeight();
4056  }
4057 
4058  uno::Reference< table::XColumnRowRange > xColRowRange( mxRange, uno::UNO_QUERY_THROW );
4059  uno::Reference< container::XIndexAccess > xIndexAccess( xColRowRange->getRows(), uno::UNO_QUERY_THROW );
4060  sal_Int32 nElems = xIndexAccess->getCount();
4061  double nHeight = 0;
4062  for ( sal_Int32 index=0; index<nElems; ++index )
4063  {
4064  uno::Reference< sheet::XCellRangeAddressable > xAddressable( xIndexAccess->getByIndex( index ), uno::UNO_QUERY_THROW );
4065  nHeight += getCalcRowHeight(xAddressable->getRangeAddress() );
4066  }
4067  return uno::makeAny( nHeight );
4068 }
4069 
4070 awt::Point
4072 {
4073  awt::Point aPoint;
4074  uno::Reference< beans::XPropertySet > xProps;
4075  if ( mxRange.is() )
4076  xProps.set( mxRange, uno::UNO_QUERY_THROW );
4077  else
4078  xProps.set( mxRanges, uno::UNO_QUERY_THROW );
4079  xProps->getPropertyValue( "Position" ) >>= aPoint;
4080  return aPoint;
4081 }
4082 uno::Any SAL_CALL
4084 {
4085  // helperapi returns the first ranges left ( and top below )
4086  if ( m_Areas->getCount() > 1 )
4087  return getArea( 0 )->getLeft();
4088  awt::Point aPoint = getPosition();
4089  return uno::makeAny( lcl_hmmToPoints( aPoint.X ) );
4090 }
4091 
4092 uno::Any SAL_CALL
4094 {
4095  // helperapi returns the first ranges top
4096  if ( m_Areas->getCount() > 1 )
4097  return getArea( 0 )->getTop();
4098  awt::Point aPoint= getPosition();
4099  return uno::makeAny( lcl_hmmToPoints( aPoint.Y ) );
4100 }
4101 
4102 static uno::Reference< sheet::XCellRangeReferrer > getNamedRange( const uno::Reference< uno::XInterface >& xIf, const uno::Reference< table::XCellRange >& thisRange )
4103 {
4104  uno::Reference< beans::XPropertySet > xProps( xIf, uno::UNO_QUERY_THROW );
4105  uno::Reference< container::XNameAccess > xNameAccess( xProps->getPropertyValue( "NamedRanges" ), uno::UNO_QUERY_THROW );
4106 
4107  const uno::Sequence< OUString > sNames = xNameAccess->getElementNames();
4108 // uno::Reference< table::XCellRange > thisRange( getCellRange(), uno::UNO_QUERY_THROW );
4109  uno::Reference< sheet::XCellRangeReferrer > xNamedRange;
4110  for ( const auto& rName : sNames )
4111  {
4112  uno::Reference< sheet::XCellRangeReferrer > xName( xNameAccess->getByName( rName ), uno::UNO_QUERY );
4113  if ( xName.is() )
4114  {
4115  if ( thisRange == xName->getReferredCells() )
4116  {
4117  xNamedRange = xName;
4118  break;
4119  }
4120  }
4121  }
4122  return xNamedRange;
4123 }
4124 
4125 uno::Reference< excel::XName >
4127 {
4128  uno::Reference< beans::XPropertySet > xProps( getUnoModel(), uno::UNO_QUERY );
4129  uno::Reference< table::XCellRange > thisRange( getCellRange(), uno::UNO_QUERY_THROW );
4130  // Application range
4131  uno::Reference< sheet::XCellRangeReferrer > xNamedRange = getNamedRange( xProps, thisRange );
4132 
4133  if ( !xNamedRange.is() )
4134  {
4135  // not in application range then assume it might be in
4136  // sheet namedranges
4137  RangeHelper aRange( thisRange );
4138  uno::Reference< sheet::XSpreadsheet > xSheet = aRange.getSpreadSheet();
4139  xProps.set( xSheet, uno::UNO_QUERY );
4140  // impl here
4141  xNamedRange = getNamedRange( xProps, thisRange );
4142  }
4143  if ( xProps.is() && xNamedRange.is() )
4144  {
4145  uno::Reference< sheet::XNamedRanges > xNamedRanges( xProps, uno::UNO_QUERY_THROW );
4146  uno::Reference< sheet::XNamedRange > xName( xNamedRange, uno::UNO_QUERY_THROW );
4147  return new ScVbaName( mxParent, mxContext, xName, xNamedRanges, getUnoModel() );
4148  }
4149  return uno::Reference< excel::XName >();
4150 }
4151 
4152 uno::Reference< excel::XWorksheet >
4154 {
4155  // #TODO #FIXME parent should always be set up ( currently that's not
4156  // the case )
4157  uno::Reference< excel::XWorksheet > xSheet( getParent(), uno::UNO_QUERY );
4158  if ( !xSheet.is() )
4159  {
4160  uno::Reference< table::XCellRange > xRange = mxRange;
4161 
4162  if ( mxRanges.is() ) // assign xRange to first range
4163  {
4164  uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW );
4165  xRange.set( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW );
4166  }
4167  ScDocShell* pDocShell = getDocShellFromRange(xRange);
4168  RangeHelper rHelper(xRange);
4169  // parent should be Thisworkbook
4170  xSheet.set( new ScVbaWorksheet( uno::Reference< XHelperInterface >(), mxContext,rHelper.getSpreadSheet(),pDocShell->GetModel()) );
4171  }
4172  return xSheet;
4173 }
4174 
4175 // #TODO remove this ugly application processing
4176 // Process an application Range request e.g. 'Range("a1,b2,a4:b6")
4177 uno::Reference< excel::XRange >
4178 ScVbaRange::ApplicationRange( const uno::Reference< uno::XComponentContext >& xContext, const css::uno::Any &Cell1, const css::uno::Any &Cell2 )
4179 {
4180  // Although the documentation seems clear that Range without a
4181  // qualifier then it's a shortcut for ActiveSheet.Range
4182  // however, similarly Application.Range is apparently also a
4183  // shortcut for ActiveSheet.Range
4184  // The is however a subtle behavioural difference I've come across
4185  // wrt to named ranges.
4186  // If a named range "test" exists { Sheet1!$A1 } and the active sheet
4187  // is Sheet2 then the following will fail
4188  // msgbox ActiveSheet.Range("test").Address ' fails
4189  // msgbox WorkSheets("Sheet2").Range("test").Address
4190  // but!!!
4191  // msgbox Range("test").Address ' works
4192  // msgbox Application.Range("test").Address ' works
4193 
4194  // Single param Range
4195  OUString sRangeName;
4196  Cell1 >>= sRangeName;
4197  if ( Cell1.hasValue() && !Cell2.hasValue() && !sRangeName.isEmpty() )
4198  {
4199  uno::Reference< beans::XPropertySet > xPropSet( getCurrentExcelDoc(xContext), uno::UNO_QUERY_THROW );
4200 
4201  uno::Reference< container::XNameAccess > xNamed( xPropSet->getPropertyValue( "NamedRanges" ), uno::UNO_QUERY_THROW );
4202  uno::Reference< sheet::XCellRangeReferrer > xReferrer;
4203  try
4204  {
4205  xReferrer.set ( xNamed->getByName( sRangeName ), uno::UNO_QUERY );
4206  }
4207  catch( uno::Exception& /*e*/ )
4208  {
4209  // do nothing
4210  }
4211  if ( xReferrer.is() )
4212  {
4213  uno::Reference< table::XCellRange > xRange = xReferrer->getReferredCells();
4214  if ( xRange.is() )
4215  {
4216  uno::Reference< excel::XRange > xVbRange = new ScVbaRange( excel::getUnoSheetModuleObj( xRange ), xContext, xRange );
4217  return xVbRange;
4218  }
4219  }
4220  }
4221 
4222  uno::Reference<table::XCellRange> xSheetRange;
4223 
4224  try
4225  {
4226  uno::Reference<sheet::XSpreadsheetView> xView(
4227  getCurrentExcelDoc(xContext)->getCurrentController(), uno::UNO_QUERY_THROW);
4228 
4229  xSheetRange.set(xView->getActiveSheet(), uno::UNO_QUERY_THROW);
4230  }
4231  catch (const uno::Exception&)
4232  {
4233  return uno::Reference<excel::XRange>();
4234  }
4235 
4236  rtl::Reference<ScVbaRange> pRange = new ScVbaRange( excel::getUnoSheetModuleObj( xSheetRange ), xContext, xSheetRange );
4237  return pRange->Range( Cell1, Cell2, true );
4238 }
4239 
4240 // Helper functions for AutoFilter
4241 static ScDBData* lcl_GetDBData_Impl( ScDocShell* pDocShell, sal_Int16 nSheet )
4242 {
4243  ScDBData* pRet = nullptr;
4244  if (pDocShell)
4245  {
4246  pRet = pDocShell->GetDocument().GetAnonymousDBData(nSheet);
4247  }
4248  return pRet;
4249 }
4250 
4251 static void lcl_SelectAll( ScDocShell* pDocShell, const ScQueryParam& aParam )
4252 {
4253  if ( pDocShell )
4254  {
4255  ScViewData* pViewData = ScDocShell::GetViewData();
4256  if ( !pViewData )
4257  {
4258  ScTabViewShell* pViewSh = pDocShell->GetBestViewShell( true );
4259  pViewData = pViewSh ? &pViewSh->GetViewData() : nullptr;
4260  }
4261 
4262  if ( pViewData )
4263  {
4264  pViewData->GetView()->Query( aParam, nullptr, true );
4265  }
4266  }
4267 }
4268 
4269 static ScQueryParam lcl_GetQueryParam( ScDocShell* pDocShell, sal_Int16 nSheet )
4270 {
4271  ScDBData* pDBData = lcl_GetDBData_Impl( pDocShell, nSheet );
4272  ScQueryParam aParam;
4273  if (pDBData)
4274  {
4275  pDBData->GetQueryParam( aParam );
4276  }
4277  return aParam;
4278 }
4279 
4280 static void lcl_SetAllQueryForField( ScDocShell* pDocShell, SCCOLROW nField, sal_Int16 nSheet )
4281 {
4282  ScQueryParam aParam = lcl_GetQueryParam( pDocShell, nSheet );
4283  aParam.RemoveEntryByField(nField);
4284  lcl_SelectAll( pDocShell, aParam );
4285 }
4286 
4287 // Modifies sCriteria, and nOp depending on the value of sCriteria
4288 static void lcl_setTableFieldsFromCriteria( OUString& sCriteria1, const uno::Reference< beans::XPropertySet >& xDescProps, sheet::TableFilterField2& rFilterField )
4289 {
4290  // #TODO make this more efficient and cycle through
4291  // sCriteria1 character by character to pick up <,<>,=, * etc.
4292  // right now I am more concerned with just getting it to work right
4293 
4294  sCriteria1 = sCriteria1.trim();
4295  // table of translation of criteria text to FilterOperators
4296  // <>searchtext - NOT_EQUAL
4297  // =searchtext - EQUAL
4298  // *searchtext - startwith
4299  // <>*searchtext - doesn't startwith
4300  // *searchtext* - contains
4301  // <>*searchtext* - doesn't contain
4302  // [>|>=|<=|...]searchtext for GREATER_value, GREATER_EQUAL_value etc.
4303  if ( sCriteria1.startsWith( EQUALS ) )
4304  {
4305  if ( sCriteria1.getLength() == static_cast<sal_Int32>(strlen(EQUALS)) )
4306  rFilterField.Operator = sheet::FilterOperator2::EMPTY;
4307  else
4308  {
4309  rFilterField.Operator = sheet::FilterOperator2::EQUAL;
4310  sCriteria1 = sCriteria1.copy( strlen(EQUALS) );
4311  sCriteria1 = VBAToRegexp( sCriteria1 );
4312  // UseRegularExpressions
4313  if ( xDescProps.is() )
4314  xDescProps->setPropertyValue( "UseRegularExpressions", uno::Any( true ) );
4315  }
4316 
4317  }
4318  else if ( sCriteria1.startsWith( NOTEQUALS ) )
4319  {
4320  if ( sCriteria1.getLength() == static_cast<sal_Int32>(strlen(NOTEQUALS)) )
4321  rFilterField.Operator = sheet::FilterOperator2::NOT_EMPTY;
4322  else
4323  {
4324  rFilterField.Operator = sheet::FilterOperator2::NOT_EQUAL;
4325  sCriteria1 = sCriteria1.copy( strlen(NOTEQUALS) );
4326  sCriteria1 = VBAToRegexp( sCriteria1 );
4327  // UseRegularExpressions
4328  if ( xDescProps.is() )
4329  xDescProps->setPropertyValue( "UseRegularExpressions", uno::Any( true ) );
4330  }
4331  }
4332  else if ( sCriteria1.startsWith( GREATERTHAN ) )
4333  {
4334  if ( sCriteria1.startsWith( GREATERTHANEQUALS ) )
4335  {
4336  sCriteria1 = sCriteria1.copy( strlen(GREATERTHANEQUALS) );
4337  rFilterField.Operator = sheet::FilterOperator2::GREATER_EQUAL;
4338  }
4339  else
4340  {
4341  sCriteria1 = sCriteria1.copy( strlen(GREATERTHAN) );
4342  rFilterField.Operator = sheet::FilterOperator2::GREATER;
4343  }
4344 
4345  }
4346  else if ( sCriteria1.startsWith( LESSTHAN ) )
4347  {
4348  if ( sCriteria1.startsWith( LESSTHANEQUALS ) )
4349  {
4350  sCriteria1 = sCriteria1.copy( strlen(LESSTHANEQUALS) );
4351  rFilterField.Operator = sheet::FilterOperator2::LESS_EQUAL;
4352  }
4353  else
4354  {
4355  sCriteria1 = sCriteria1.copy( strlen(LESSTHAN) );
4356  rFilterField.Operator = sheet::FilterOperator2::LESS;
4357  }
4358 
4359  }
4360  else
4361  rFilterField.Operator = sheet::FilterOperator2::EQUAL;
4362 
4363  // tdf#107885 - check if criteria is numeric using locale dependent settings without group separator
4364  // or, if the decimal separator is different from the English locale, without any locale.
4365  sal_Int32 nParseEnd = 0;
4366  rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
4367  double fValue = ScGlobal::getLocaleDataPtr()->stringToDouble( sCriteria1, false, &eStatus, &nParseEnd );
4368  if ( nParseEnd == sCriteria1.getLength() && eStatus == rtl_math_ConversionStatus_Ok )
4369  {
4370  rFilterField.IsNumeric = true;
4371  rFilterField.NumericValue = fValue;
4372  }
4373  else if ( ScGlobal::getLocaleDataPtr()->getNumDecimalSep().toChar() != '.' )
4374  {
4375  eStatus = rtl_math_ConversionStatus_Ok;
4376  fValue = ::rtl::math::stringToDouble( sCriteria1, '.', 0, &eStatus, &nParseEnd );
4377  if ( nParseEnd == sCriteria1.getLength() && eStatus == rtl_math_ConversionStatus_Ok )
4378  {
4379  rFilterField.IsNumeric = true;
4380  rFilterField.NumericValue = fValue;
4381  }
4382  }
4383 
4384  rFilterField.StringValue = sCriteria1;
4385 }
4386 
4387 void SAL_CALL
4388 ScVbaRange::AutoFilter( const uno::Any& aField, const uno::Any& Criteria1, const uno::Any& Operator, const uno::Any& Criteria2, const uno::Any& /*VisibleDropDown*/ )
4389 {
4390  // Is there an existing autofilter
4391  RangeHelper thisRange( mxRange );
4392  table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
4393  sal_Int16 nSheet = thisAddress.Sheet;
4394  ScDocShell* pShell = getScDocShell();
4395  bool bHasAuto = false;
4396  uno::Reference< sheet::XDatabaseRange > xDataBaseRange = excel::GetAutoFiltRange( pShell, nSheet );
4397  if ( xDataBaseRange.is() )
4398  bHasAuto = true;
4399 
4400  if ( !bHasAuto )
4401  {
4402  if ( m_Areas->getCount() > 1 )
4403  throw uno::RuntimeException( STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY );
4404 
4405  table::CellRangeAddress autoFiltAddress;
4406  //CurrentRegion()
4407  if ( isSingleCellRange() )
4408  {
4409  uno::Reference< excel::XRange > xCurrent( CurrentRegion() );
4410  if ( xCurrent.is() )
4411  {
4412  ScVbaRange* pRange = getImplementation( xCurrent );
4413  if ( pRange )
4414  {
4415  if ( pRange->isSingleCellRange() )
4416  throw uno::RuntimeException("Can't create AutoFilter" );
4417  RangeHelper currentRegion( pRange->mxRange );
4418  autoFiltAddress = currentRegion.getCellRangeAddressable()->getRangeAddress();
4419  }
4420  }
4421  }
4422  else // multi-cell range
4423  {
4424  RangeHelper multiCellRange( mxRange );
4425  autoFiltAddress = multiCellRange.getCellRangeAddressable()->getRangeAddress();
4426  // #163530# Filter box shows only entry of first row
4427  ScDocument* pDocument = ( pShell ? &pShell->GetDocument() : nullptr );
4428  if ( pDocument )
4429  {
4430  SCCOL nStartCol = autoFiltAddress.StartColumn;
4431  SCROW nStartRow = autoFiltAddress.StartRow;
4432  SCCOL nEndCol = autoFiltAddress.EndColumn;
4433  SCROW nEndRow = autoFiltAddress.EndRow;
4434  pDocument->GetDataArea( autoFiltAddress.Sheet, nStartCol, nStartRow, nEndCol, nEndRow, true, true );
4435  autoFiltAddress.StartColumn = nStartCol;
4436  autoFiltAddress.StartRow = nStartRow;
4437  autoFiltAddress.EndColumn = nEndCol;
4438  autoFiltAddress.EndRow = nEndRow;
4439  }
4440  }
4441 
4442  uno::Reference< sheet::XUnnamedDatabaseRanges > xDBRanges = excel::GetUnnamedDataBaseRanges( pShell );
4443  if ( xDBRanges.is() )
4444  {
4445  if ( !xDBRanges->hasByTable( nSheet ) )
4446  xDBRanges->setByTable( autoFiltAddress );
4447  xDataBaseRange.set( xDBRanges->getByTable(nSheet ), uno::UNO_QUERY_THROW );
4448  }
4449  if ( !xDataBaseRange.is() )
4450  throw uno::RuntimeException("Failed to find the autofilter placeholder range" );
4451 
4452  uno::Reference< beans::XPropertySet > xDBRangeProps( xDataBaseRange, uno::UNO_QUERY_THROW );
4453  // set autofilter
4454  xDBRangeProps->setPropertyValue( "AutoFilter", uno::Any(true) );
4455  // set header (autofilter always need column headers)
4456  uno::Reference< beans::XPropertySet > xFiltProps( xDataBaseRange->getFilterDescriptor(), uno::UNO_QUERY_THROW );
4457  xFiltProps->setPropertyValue( "ContainsHeader", uno::Any( true ) );
4458  }
4459 
4460  sal_Int32 nField = 0; // *IS* 1 based
4461  OUString sCriteria1;
4462  sal_Int32 nOperator = excel::XlAutoFilterOperator::xlAnd;
4463 
4464  sheet::FilterConnection nConn = sheet::FilterConnection_AND;
4465  double nCriteria1 = 0;
4466 
4467  bool bHasCritValue = Criteria1.hasValue();
4468  bool bCritHasNumericValue = false; // not sure if a numeric criteria is possible
4469  if ( bHasCritValue )
4470  bCritHasNumericValue = ( Criteria1 >>= nCriteria1 );
4471 
4472  if ( !aField.hasValue() && ( Criteria1.hasValue() || Operator.hasValue() || Criteria2.hasValue() ) )
4473  throw uno::RuntimeException();
4474  uno::Any Field( aField );
4475  if ( !( Field >>= nField ) )
4476  {
4477  const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( mxContext );
4478  try
4479  {
4480  Field = xConverter->convertTo( aField, cppu::UnoType<sal_Int32>::get() );
4481  }
4482  catch( uno::Exception& )
4483  {
4484  }
4485  }
4486  // Use the normal uno api, sometimes e.g. when you want to use ALL as the filter
4487  // we can't use refresh as the uno interface doesn't have a concept of ALL
4488  // in this case we just call the core calc functionality -
4489  if ( Field >>= nField )
4490  {
4491  uno::Reference< sheet::XSheetFilterDescriptor2 > xDesc(
4492  xDataBaseRange->getFilterDescriptor(), uno::UNO_QUERY );
4493  if ( xDesc.is() )
4494  {
4495  bool bAcceptCriteria2 = true;
4496  bool bAll = false;
4497  uno::Sequence< sheet::TableFilterField2 > sTabFilts;
4498  uno::Reference< beans::XPropertySet > xDescProps( xDesc, uno::UNO_QUERY_THROW );
4499  if ( Criteria1.hasValue() )
4500  {
4501  sTabFilts.realloc( 1 );
4502  sTabFilts[0].Operator = sheet::FilterOperator2::EQUAL;// sensible default
4503  if ( !bCritHasNumericValue )
4504  {
4505  Criteria1 >>= sCriteria1;
4506  if ( sCriteria1.isEmpty() )
4507  {
4508  uno::Sequence< OUString > aCriteria1;
4509  Criteria1 >>= aCriteria1;
4510  sal_uInt16 nLength = aCriteria1.getLength();
4511  if ( nLength )
4512  {
4513  // When sequence is provided for Criteria1 don't care about Criteria2
4514  bAcceptCriteria2 = false;
4515 
4516  sTabFilts.realloc( nLength );
4517  for ( sal_uInt16 i = 0; i < nLength; ++i )
4518  {
4519  lcl_setTableFieldsFromCriteria( aCriteria1[i], xDescProps, sTabFilts[i] );
4520  sTabFilts[i].Connection = sheet::FilterConnection_OR;
4521  sTabFilts[i].Field = (nField - 1);
4522  }
4523  }
4524  else
4525  bAll = true;
4526  }
4527  else
4528  {
4529  sTabFilts[0].IsNumeric = bCritHasNumericValue;
4530  if ( bHasCritValue && !sCriteria1.isEmpty() )
4531  lcl_setTableFieldsFromCriteria( sCriteria1, xDescProps, sTabFilts[0] );
4532  else
4533  bAll = true;
4534  }
4535  }
4536  else // numeric
4537  {
4538  sTabFilts[0].IsNumeric = true;
4539  sTabFilts[0].NumericValue = nCriteria1;
4540  }
4541  }
4542  else // no value specified
4543  bAll = true;
4544  // not sure what the relationship between Criteria1 and Operator is,
4545  // e.g. can you have an Operator without a Criteria? In LibreOffice it
4546  if ( Operator.hasValue() && ( Operator >>= nOperator ) )
4547  {
4548  // if it's a bottom/top Ten(Percent/Value) and there
4549  // is no value specified for criteria1 set it to 10
4550  if ( !bCritHasNumericValue && sCriteria1.isEmpty() && ( nOperator != excel::XlAutoFilterOperator::xlOr ) && ( nOperator != excel::XlAutoFilterOperator::xlAnd ) )
4551  {
4552  sTabFilts[0].IsNumeric = true;
4553  sTabFilts[0].NumericValue = 10;
4554  bAll = false;
4555  }
4556  switch ( nOperator )
4557  {
4558  case excel::XlAutoFilterOperator::xlBottom10Items:
4559  sTabFilts[0].Operator = sheet::FilterOperator2::BOTTOM_VALUES;
4560  break;
4561  case excel::XlAutoFilterOperator::xlBottom10Percent:
4562  sTabFilts[0].Operator = sheet::FilterOperator2::BOTTOM_PERCENT;
4563  break;
4564  case excel::XlAutoFilterOperator::xlTop10Items:
4565  sTabFilts[0].Operator = sheet::FilterOperator2::TOP_VALUES;
4566  break;
4567  case excel::XlAutoFilterOperator::xlTop10Percent:
4568  sTabFilts[0].Operator = sheet::FilterOperator2::TOP_PERCENT;
4569  break;
4570  case excel::XlAutoFilterOperator::xlOr:
4571  nConn = sheet::FilterConnection_OR;
4572  break;
4573  case excel::XlAutoFilterOperator::xlAnd:
4574  nConn = sheet::FilterConnection_AND;
4575  break;
4576  default:
4577  throw uno::RuntimeException("UnknownOption" );
4578 
4579  }
4580 
4581  }
4582  if ( !bAll && bAcceptCriteria2 )
4583  {
4584  sTabFilts[0].Connection = sheet::FilterConnection_AND;
4585  sTabFilts[0].Field = (nField - 1);
4586 
4587  OUString sCriteria2;
4588  uno::Sequence< OUString > aCriteria2;
4589  if ( Criteria2.hasValue() ) // there is a Criteria2
4590  {
4591  sTabFilts.realloc(2);
4592  sTabFilts[1].Field = sTabFilts[0].Field;
4593  sTabFilts[1].Connection = nConn;
4594 
4595  if ( Criteria2 >>= sCriteria2 )
4596  {
4597  if ( !sCriteria2.isEmpty() )
4598  {
4599  uno::Reference< beans::XPropertySet > xProps;
4600  lcl_setTableFieldsFromCriteria( sCriteria2, xProps, sTabFilts[1] );
4601  sTabFilts[1].IsNumeric = false;
4602  }
4603  }
4604  else if ( Criteria2 >>= aCriteria2 )
4605  {
4606  sal_uInt16 nLength = aCriteria2.getLength();
4607  if ( nLength )
4608  {
4609  // For compatibility use only the last value from the sequence
4610  lcl_setTableFieldsFromCriteria( aCriteria2[nLength - 1], xDescProps, sTabFilts[1] );
4611  }
4612  }
4613  else // numeric
4614  {
4615  Criteria2 >>= sTabFilts[1].NumericValue;
4616  sTabFilts[1].IsNumeric = true;
4617  sTabFilts[1].Operator = sheet::FilterOperator2::EQUAL;
4618  }
4619  }
4620  }
4621 
4622  xDesc->setFilterFields2( sTabFilts );
4623  if ( !bAll )
4624  {
4625  xDataBaseRange->refresh();
4626  }
4627  else
4628  // was 0 based now seems to be 1
4629  lcl_SetAllQueryForField( pShell, nField, nSheet );
4630  }
4631  }
4632  else
4633  {
4634  // this is just to toggle autofilter on and off ( not to be confused with
4635  // a VisibleDropDown option combined with a field, in that case just the
4636  // button should be disabled ) - currently we don't support that
4637  uno::Reference< beans::XPropertySet > xDBRangeProps( xDataBaseRange, uno::UNO_QUERY_THROW );
4638  if ( bHasAuto )
4639  {
4640  // find the any field with the query and select all
4641  ScQueryParam aParam = lcl_GetQueryParam( pShell, nSheet );
4642  for (SCSIZE i = 0; i< aParam.GetEntryCount(); ++i)
4643  {
4644  ScQueryEntry& rEntry = aParam.GetEntry(i);
4645  if ( rEntry.bDoQuery )
4646  lcl_SetAllQueryForField( pShell, rEntry.nField, nSheet );
4647  }
4648  // remove existing filters
4649  uno::Reference< sheet::XSheetFilterDescriptor2 > xSheetFilterDescriptor(
4650  xDataBaseRange->getFilterDescriptor(), uno::UNO_QUERY );
4651  if( xSheetFilterDescriptor.is() )
4652  xSheetFilterDescriptor->setFilterFields2( uno::Sequence< sheet::TableFilterField2 >() );
4653  }
4654  xDBRangeProps->setPropertyValue( "AutoFilter", uno::Any(!bHasAuto) );
4655 
4656  }
4657 }
4658 
4659 void SAL_CALL
4660 ScVbaRange::Insert( const uno::Any& Shift, const uno::Any& /*CopyOrigin*/ )
4661 {
4662  // It appears (from the web) that the undocumented CopyOrigin
4663  // param should contain member of enum XlInsertFormatOrigin
4664  // which can have values xlFormatFromLeftOrAbove or xlFormatFromRightOrBelow
4665  // #TODO investigate resultant behaviour using these constants
4666  // currently just processing Shift
4667 
4668  sheet::CellInsertMode mode = sheet::CellInsertMode_NONE;
4669  if ( Shift.hasValue() )
4670  {
4671  sal_Int32 nShift = 0;
4672  Shift >>= nShift;
4673  switch ( nShift )
4674  {
4675  case excel::XlInsertShiftDirection::xlShiftToRight:
4676  mode = sheet::CellInsertMode_RIGHT;
4677  break;
4678  case excel::XlInsertShiftDirection::xlShiftDown:
4679  mode = sheet::CellInsertMode_DOWN;
4680  break;
4681  default:
4682  throw uno::RuntimeException("Illegal parameter " );
4683  }
4684  }
4685  else
4686  {
4687  if ( getRow() >= getColumn() )
4688  mode = sheet::CellInsertMode_DOWN;
4689  else
4690  mode = sheet::CellInsertMode_RIGHT;
4691  }
4692  RangeHelper thisRange( mxRange );
4693  table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
4694  uno::Reference< sheet::XCellRangeMovement > xCellRangeMove( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW );
4695  xCellRangeMove->insertCells( thisAddress, mode );
4696 
4697  // Paste from clipboard only if the clipboard content was copied via VBA, and not already pasted via VBA again.
4698  // "Insert" behavior should not depend on random clipboard content previously copied by the user.
4699  ScDocShell* pDocShell = getDocShellFromRange( mxRange );
4700  const ScTransferObj* pClipObj = pDocShell ? ScTransferObj::GetOwnClipboard(pDocShell->GetClipData()) : nullptr;
4701  if ( pClipObj && pClipObj->GetUseInApi() )
4702  {
4703  // After the insert ( this range ) actually has moved
4704  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 ) );
4705  uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getDocShellFromRange( mxRange ) , aRange ) );
4706  uno::Reference< excel::XRange > xVbaRange( new ScVbaRange( mxParent, mxContext, xRange, mbIsRows, mbIsColumns ) );
4707  xVbaRange->PasteSpecial( uno::Any(), uno::Any(), uno::Any(), uno::Any() );
4708  }
4709 }
4710 
4711 void SAL_CALL
4713 {
4714  sal_Int32 nLen = m_Areas->getCount();
4715  if ( nLen > 1 )
4716  {
4717  for ( sal_Int32 index = 1; index != nLen; ++index )
4718  {
4719  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( index ), uno::Any() ), uno::UNO_QUERY_THROW );
4720  xRange->Autofit();
4721  }
4722  return;
4723  }
4724  // if the range is a not a row or column range autofit will
4725  // throw an error
4726 
4727  if ( !( mbIsColumns || mbIsRows ) )
4728  DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, OUString());
4729  ScDocShell* pDocShell = getDocShellFromRange( mxRange );
4730  if ( pDocShell )
4731  {
4732  RangeHelper thisRange( mxRange );
4733  table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
4734 
4735  std::vector<sc::ColRowSpan> aColArr(1, sc::ColRowSpan(thisAddress.StartColumn,thisAddress.EndColumn));
4736  bool bDirection = true;
4737  if ( mbIsRows )
4738  {
4739  bDirection = false;
4740  aColArr[0].mnStart = thisAddress.StartRow;
4741  aColArr[0].mnEnd = thisAddress.EndRow;
4742  }
4743  pDocShell->GetDocFunc().SetWidthOrHeight(
4744  bDirection, aColArr, thisAddress.Sheet, SC_SIZE_OPTIMAL, 0, true, true);
4745  }
4746 }
4747 
4748 uno::Any SAL_CALL
4750 {
4751  /* The range object always returns a new Hyperlinks object containing a
4752  fixed list of existing hyperlinks in the range.
4753  See vbahyperlinks.hxx for more details. */
4754 
4755  // get the global hyperlink object of the sheet (sheet should always be the parent of a Range object)
4756  uno::Reference< excel::XWorksheet > xWorksheet( getParent(), uno::UNO_QUERY_THROW );
4757  uno::Reference< excel::XHyperlinks > xSheetHlinks( xWorksheet->Hyperlinks( uno::Any() ), uno::UNO_QUERY_THROW );
4758  ScVbaHyperlinksRef xScSheetHlinks( dynamic_cast< ScVbaHyperlinks* >( xSheetHlinks.get() ) );
4759  if( !xScSheetHlinks.is() )
4760  throw uno::RuntimeException("Cannot obtain hyperlinks implementation object" );
4761 
4762  // create a new local hyperlinks object based on the sheet hyperlinks
4763  ScVbaHyperlinksRef xHlinks( new ScVbaHyperlinks( getParent(), mxContext, xScSheetHlinks, getScRangeList() ) );
4764  if( aIndex.hasValue() )
4765  return xHlinks->Item( aIndex, uno::Any() );
4766  return uno::Any( uno::Reference< excel::XHyperlinks >( xHlinks.get() ) );
4767 }
4768 
4769 css::uno::Reference< excel::XValidation > SAL_CALL
4771 {
4772  if ( !m_xValidation.is() )
4774  return m_xValidation;
4775 }
4776 
4777 namespace {
4778 
4780 sal_Unicode lclGetPrefixChar( const uno::Reference< table::XCell >& rxCell )
4781 {
4782  /* TODO/FIXME: We need an apostroph-prefix property at the cell to
4783  implement this correctly. For now, return an apostroph for every text
4784  cell.
4785 
4786  TODO/FIXME: When Application.TransitionNavigKeys is supported and true,
4787  this function needs to inspect the cell formatting and return different
4788  prefixes according to the horizontal cell alignment.
4789  */
4790  return (rxCell->getType() == table::CellContentType_TEXT) ? '\'' : 0;
4791 }
4792 
4794 sal_Unicode lclGetPrefixChar( const uno::Reference< table::XCellRange >& rxRange )
4795 {
4796  /* This implementation is able to handle different prefixes (needed if
4797  Application.TransitionNavigKeys is true). The function lclGetPrefixChar
4798  for single cells called from here may return any prefix. If that
4799  function returns an empty prefix (NUL character) or different non-empty
4800  prefixes for two cells, this function returns 0.
4801  */
4802  sal_Unicode cCurrPrefix = 0;
4803  table::CellRangeAddress aRangeAddr = lclGetRangeAddress( rxRange );
4804  sal_Int32 nEndCol = aRangeAddr.EndColumn - aRangeAddr.StartColumn;
4805  sal_Int32 nEndRow = aRangeAddr.EndRow - aRangeAddr.StartRow;
4806  for( sal_Int32 nRow = 0; nRow <= nEndRow; ++nRow )
4807  {
4808  for( sal_Int32 nCol = 0; nCol <= nEndCol; ++nCol )
4809  {
4810  uno::Reference< table::XCell > xCell( rxRange->getCellByPosition( nCol, nRow ), uno::UNO_SET_THROW );
4811  sal_Unicode cNewPrefix = lclGetPrefixChar( xCell );
4812  if( (cNewPrefix == 0) || ((cCurrPrefix != 0) && (cNewPrefix != cCurrPrefix)) )
4813  return 0;
4814  cCurrPrefix = cNewPrefix;
4815  }
4816  }
4817  // all cells contain the same prefix - return it
4818  return cCurrPrefix;
4819 }
4820 
4822 sal_Unicode lclGetPrefixChar( const uno::Reference< sheet::XSheetCellRangeContainer >& rxRanges )
4823 {
4824  sal_Unicode cCurrPrefix = 0;
4825  uno::Reference< container::XEnumerationAccess > xRangesEA( rxRanges, uno::UNO_QUERY_THROW );
4826  uno::Reference< container::XEnumeration > xRangesEnum( xRangesEA->createEnumeration(), uno::UNO_SET_THROW );
4827  while( xRangesEnum->hasMoreElements() )
4828  {
4829  uno::Reference< table::XCellRange > xRange( xRangesEnum->nextElement(), uno::UNO_QUERY_THROW );
4830  sal_Unicode cNewPrefix = lclGetPrefixChar( xRange );
4831  if( (cNewPrefix == 0) || ((cCurrPrefix != 0) && (cNewPrefix != cCurrPrefix)) )
4832  return 0;
4833  cCurrPrefix = cNewPrefix;
4834  }
4835  // all ranges contain the same prefix - return it
4836  return cCurrPrefix;
4837 }
4838 
4839 uno::Any lclGetPrefixVariant( sal_Unicode cPrefixChar )
4840 {
4841  return uno::Any( (cPrefixChar == 0) ? OUString() : OUString( cPrefixChar ) );
4842 }
4843 
4844 } // namespace
4845 
4847 {
4848  /* (1) If Application.TransitionNavigKeys is false, this function returns
4849  an apostroph character if the text cell begins with an apostroph
4850  character (formula return values are not taken into account); otherwise
4851  an empty string.
4852 
4853  (2) If Application.TransitionNavigKeys is true, this function returns
4854  an apostroph character, if the cell is left-aligned; a double-quote
4855  character, if the cell is right-aligned; a circumflex character, if the
4856  cell is centered; a backslash character, if the cell is set to filled;
4857  or an empty string, if nothing of the above.
4858 
4859  If a range or a list of ranges contains texts with leading apostroph
4860  character as well as other cells, this function returns an empty
4861  string.
4862  */
4863 
4864  if( mxRange.is() )
4865  return lclGetPrefixVariant( lclGetPrefixChar( mxRange ) );
4866  if( mxRanges.is() )
4867  return lclGetPrefixVariant( lclGetPrefixChar( mxRanges ) );
4868  throw uno::RuntimeException("Unexpected empty Range object" );
4869 }
4870 
4872 {
4873  // #FIXME, If the specified range is in a PivotTable report
4874 
4875  // In MSO VBA, the specified range must be a single summary column or row in an outline. otherwise throw exception
4876  if( m_Areas->getCount() > 1 )
4877  throw uno::RuntimeException("Can not get Range.ShowDetail attribute " );
4878 
4879  RangeHelper helper( mxRange );
4880  uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = helper.getSheetCellCursor();
4881  xSheetCellCursor->collapseToCurrentRegion();
4882  uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW);
4883  table::CellRangeAddress aOutlineAddress = xCellRangeAddressable->getRangeAddress();
4884 
4885  // check if the specified range is a single summary column or row.
4886  table::CellRangeAddress thisAddress = helper.getCellRangeAddressable()->getRangeAddress();
4887  if( (thisAddress.StartRow != thisAddress.EndRow || thisAddress.EndRow != aOutlineAddress.EndRow ) &&
4888  (thisAddress.StartColumn != thisAddress.EndColumn || thisAddress.EndColumn != aOutlineAddress.EndColumn ))
4889  {
4890  throw uno::RuntimeException("Can not set Range.ShowDetail attribute" );
4891  }
4892 
4893  bool bColumn = thisAddress.StartRow != thisAddress.EndRow;
4895  ScOutlineTable* pOutlineTable = rDoc.GetOutlineTable(static_cast<SCTAB>(thisAddress.Sheet), true);
4896  const ScOutlineArray& rOutlineArray = bColumn ? pOutlineTable->GetColArray(): pOutlineTable->GetRowArray();
4897  SCCOLROW nPos = bColumn ? static_cast<SCCOLROW>(thisAddress.EndColumn-1):static_cast<SCCOLROW>(thisAddress.EndRow-1);
4898  const ScOutlineEntry* pEntry = rOutlineArray.GetEntryByPos( 0, nPos );
4899  if( pEntry )
4900  {
4901  const bool bShowDetail = !pEntry->IsHidden();
4902  return uno::makeAny( bShowDetail );
4903  }
4904 
4905  return aNULL();
4906 }
4907 
4908 void ScVbaRange::setShowDetail(const uno::Any& aShowDetail)
4909 {
4910  // #FIXME, If the specified range is in a PivotTable report
4911 
4912  // In MSO VBA, the specified range must be a single summary column or row in an outline. otherwise throw exception
4913  if( m_Areas->getCount() > 1 )
4914  throw uno::RuntimeException("Can not set Range.ShowDetail attribute" );
4915 
4916  bool bShowDetail = extractBoolFromAny( aShowDetail );
4917 
4918  RangeHelper helper( mxRange );
4919  uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = helper.getSheetCellCursor();
4920  xSheetCellCursor->collapseToCurrentRegion();
4921  uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW);
4922  table::CellRangeAddress aOutlineAddress = xCellRangeAddressable->getRangeAddress();
4923 
4924  // check if the specified range is a single summary column or row.
4925  table::CellRangeAddress thisAddress = helper.getCellRangeAddressable()->getRangeAddress();
4926  if( (thisAddress.StartRow != thisAddress.EndRow || thisAddress.EndRow != aOutlineAddress.EndRow ) &&
4927  (thisAddress.StartColumn != thisAddress.EndColumn || thisAddress.EndColumn != aOutlineAddress.EndColumn ))
4928  {
4929  throw uno::RuntimeException("Can not set Range.ShowDetail attribute" );
4930  }
4931 
4932  // #FIXME, seems there is a different behavior between MSO and OOo.
4933  // In OOo, the showDetail will show all the level entries, while only show the first level entry in MSO
4934  uno::Reference< sheet::XSheetOutline > xSheetOutline( helper.getSpreadSheet(), uno::UNO_QUERY_THROW );
4935  if( bShowDetail )
4936  xSheetOutline->showDetail( aOutlineAddress );
4937  else
4938  xSheetOutline->hideDetail( aOutlineAddress );
4939 
4940 }
4941 
4942 uno::Reference< excel::XRange > SAL_CALL
4944 {
4945  uno::Reference< sheet::XSheetCellRange > xMergeShellCellRange(mxRange->getCellRangeByPosition(0,0,0,0), uno::UNO_QUERY_THROW);
4946  uno::Reference< sheet::XSheetCellCursor > xMergeSheetCursor(xMergeShellCellRange->getSpreadsheet()->createCursorByRange( xMergeShellCellRange ), uno::UNO_SET_THROW);
4947  if( xMergeSheetCursor.is() )
4948  {
4949  xMergeSheetCursor->collapseToMergedArea();
4950  uno::Reference<sheet::XCellRangeAddressable> xMergeCellAddress(xMergeSheetCursor, uno::UNO_QUERY_THROW);
4951  table::CellRangeAddress aCellAddress = xMergeCellAddress->getRangeAddress();
4952  if( aCellAddress.StartColumn ==0 && aCellAddress.EndColumn==0 &&
4953  aCellAddress.StartRow==0 && aCellAddress.EndRow==0)
4954  {
4955  return new ScVbaRange( mxParent,mxContext,mxRange );
4956  }
4957  else
4958  {
4959  ScRange refRange( static_cast< SCCOL >( aCellAddress.StartColumn ), static_cast< SCROW >( aCellAddress.StartRow ), static_cast< SCTAB >( aCellAddress.Sheet ),
4960  static_cast< SCCOL >( aCellAddress.EndColumn ), static_cast< SCROW >( aCellAddress.EndRow ), static_cast< SCTAB >( aCellAddress.Sheet ) );
4961  uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getScDocShell() , refRange ) );
4962  return new ScVbaRange( mxParent, mxContext,xRange );
4963  }
4964  }
4965  return new ScVbaRange( mxParent, mxContext, mxRange );
4966 }
4967 
4968 void SAL_CALL
4969 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 )
4970 {
4971  ScDocShell* pShell = nullptr;
4972 
4973  sal_Int32 nItems = m_Areas->getCount();
4974  uno::Sequence< table::CellRangeAddress > printAreas( nItems );
4975  uno::Reference< sheet::XPrintAreas > xPrintAreas;
4976  for ( sal_Int32 index=1; index <= nItems; ++index )
4977  {
4978  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW );
4979 
4980  RangeHelper thisRange( xRange->getCellRange() );
4981  table::CellRangeAddress rangeAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
4982  if ( index == 1 )
4983  {
4984  ScVbaRange* pRange = getImplementation( xRange );
4985  // initialise the doc shell and the printareas
4986  pShell = getDocShellFromRange( pRange->mxRange );
4987  xPrintAreas.set( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW );
4988  }
4989  printAreas[ index - 1 ] = rangeAddress;
4990  }
4991  if ( pShell && xPrintAreas.is() )
4992  {
4993  xPrintAreas->setPrintAreas( printAreas );
4994  uno::Reference< frame::XModel > xModel = pShell->GetModel();
4995  PrintOutHelper( excel::getBestViewShell( xModel ), From, To, Copies, Preview, ActivePrinter, PrintToFile, Collate, PrToFileName, true );
4996  }
4997 }
4998 
4999 void SAL_CALL
5000 ScVbaRange::AutoFill( const uno::Reference< excel::XRange >& Destination, const uno::Any& Type )
5001 {
5002  uno::Reference< excel::XRange > xDest( Destination, uno::UNO_SET_THROW );
5003  ScVbaRange* pRange = getImplementation( xDest );
5004  RangeHelper destRangeHelper( pRange->mxRange );
5005  table::CellRangeAddress destAddress = destRangeHelper.getCellRangeAddressable()->getRangeAddress();
5006 
5007  RangeHelper thisRange( mxRange );
5008  table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
5009  ScRange sourceRange;
5010  ScRange destRange;
5011 
5012  ScUnoConversion::FillScRange( destRange, destAddress );
5013  ScUnoConversion::FillScRange( sourceRange, thisAddress );
5014 
5015  FillDir eDir = FILL_TO_BOTTOM;
5016  double fStep = 1.0;
5017 
5018  ScRange aRange( destRange );
5019  ScRange aSourceRange( destRange );
5020 
5021  // default to include the number of Rows in the source range;
5022  SCCOLROW nSourceCount = ( sourceRange.aEnd.Row() - sourceRange.aStart.Row() ) + 1;
5023  SCCOLROW nCount = 0;
5024 
5025  if ( sourceRange != destRange )
5026  {
5027  // Find direction of fill, vertical or horizontal
5028  if ( sourceRange.aStart == destRange.aStart )
5029  {
5030  if ( sourceRange.aEnd.Row() == destRange.aEnd.Row() )
5031  {
5032  nSourceCount = ( sourceRange.aEnd.Col() - sourceRange.aStart.Col() + 1 );
5033  aSourceRange.aEnd.SetCol( static_cast<SCCOL>( aSourceRange.aStart.Col() + nSourceCount - 1 ) );
5034  eDir = FILL_TO_RIGHT;
5035  nCount = aRange.aEnd.Col() - aSourceRange.aEnd.Col();
5036  }
5037  else if ( sourceRange.aEnd.Col() == destRange.aEnd.Col() )
5038  {
5039  aSourceRange.aEnd.SetRow( static_cast<SCROW>( aSourceRange.aStart.Row() + nSourceCount ) - 1 );
5040  nCount = aRange.aEnd.Row() - aSourceRange.aEnd.Row();
5041  eDir = FILL_TO_BOTTOM;
5042  }
5043  }
5044 
5045  else if ( aSourceRange.aEnd == destRange.aEnd )
5046  {
5047  if ( sourceRange.aStart.Col() == destRange.aStart.Col() )
5048  {
5049  aSourceRange.aStart.SetRow( static_cast<SCROW>( aSourceRange.aEnd.Row() - nSourceCount + 1 ) );
5050  nCount = aSourceRange.aStart.Row() - aRange.aStart.Row();
5051  eDir = FILL_TO_TOP;
5052  fStep = -fStep;
5053  }
5054  else if ( sourceRange.aStart.Row() == destRange.aStart.Row() )
5055  {
5056  nSourceCount = ( sourceRange.aEnd.Col() - sourceRange.aStart.Col() ) + 1;
5057  aSourceRange.aStart.SetCol( static_cast<SCCOL>( aSourceRange.aEnd.Col() - nSourceCount + 1 ) );
5058  nCount = aSourceRange.aStart.Col() - aRange.aStart.Col();
5059  eDir = FILL_TO_LEFT;
5060  fStep = -fStep;
5061  }
5062  }
5063  }
5064 
5065  FillCmd eCmd = FILL_AUTO;
5066  FillDateCmd eDateCmd = FILL_DAY;
5067 
5068  if ( Type.hasValue() )
5069  {
5070  sal_Int16 nFillType = excel::XlAutoFillType::xlFillDefault;
5071  Type >>= nFillType;
5072  switch ( nFillType )
5073  {
5074  case excel::XlAutoFillType::xlFillCopy:
5075  eCmd = FILL_SIMPLE;
5076  fStep = 0.0;
5077  break;
5078  case excel::XlAutoFillType::xlFillDays:
5079  eCmd = FILL_DATE;
5080  break;
5081  case excel::XlAutoFillType::xlFillMonths:
5082  eCmd = FILL_DATE;
5083  eDateCmd = FILL_MONTH;
5084  break;
5085  case excel::XlAutoFillType::xlFillWeekdays:
5086  eCmd = FILL_DATE;
5087  eDateCmd = FILL_WEEKDAY;
5088  break;
5089  case excel::XlAutoFillType::xlFillYears:
5090  eCmd = FILL_DATE;
5091  eDateCmd = FILL_YEAR;
5092  break;
5093  case excel::XlAutoFillType::xlGrowthTrend:
5094  eCmd = FILL_GROWTH;
5095  break;
5096  case excel::XlAutoFillType::xlFillFormats:
5097  throw uno::RuntimeException("xlFillFormat not supported for AutoFill" );
5098  case excel::XlAutoFillType::xlFillValues:
5099  case excel::XlAutoFillType::xlFillSeries:
5100  case excel::XlAutoFillType::xlLinearTrend:
5101  eCmd = FILL_LINEAR;
5102  break;
5103  case excel::XlAutoFillType::xlFillDefault:
5104  default:
5105  eCmd = FILL_AUTO;
5106  break;
5107  }
5108  }
5110  pDocSh->GetDocFunc().FillAuto( aSourceRange, nullptr, eDir, eCmd, eDateCmd,
5111  nCount, fStep, MAXDOUBLE/*fEndValue*/, true, true );
5112 }
5113 sal_Bool SAL_CALL
5114 ScVbaRange::GoalSeek( const uno::Any& Goal, const uno::Reference< excel::XRange >& ChangingCell )
5115 {
5116  ScDocShell* pDocShell = getScDocShell();
5117  bool bRes = true;
5118  ScVbaRange* pRange = static_cast< ScVbaRange* >( ChangingCell.get() );
5119  if ( pDocShell && pRange )
5120  {
5121  uno::Reference< sheet::XGoalSeek > xGoalSeek( pDocShell->GetModel(), uno::UNO_QUERY_THROW );
5122  RangeHelper thisRange( mxRange );
5123  table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
5124  RangeHelper changingCellRange( pRange->mxRange );
5125  table::CellRangeAddress changingCellAddr = changingCellRange.getCellRangeAddressable()->getRangeAddress();
5126  OUString sGoal = getAnyAsString( Goal );
5127  table::CellAddress thisCell( thisAddress.Sheet, thisAddress.StartColumn, thisAddress.StartRow );
5128  table::CellAddress changingCell( changingCellAddr.Sheet, changingCellAddr.StartColumn, changingCellAddr.StartRow );
5129  sheet::GoalResult res = xGoalSeek->seekGoal( thisCell, changingCell, sGoal );
5130  ChangingCell->setValue( uno::makeAny( res.Result ) );
5131 
5132  // openoffice behaves differently, result is 0 if the divergence is too great
5133  // but... if it detects 0 is the value it requires then it will use that
5134  // e.g. divergence & result both = 0.0 does NOT mean there is an error
5135  if ( ( res.Divergence != 0.0 ) && ( res.Result == 0.0 ) )
5136  bRes = false;
5137  }
5138  else
5139  bRes = false;
5140  return bRes;
5141 }
5142 
5143 void
5145 {
5146  getWorksheet()->Calculate();
5147 }
5148 
5149 uno::Reference< excel::XRange > SAL_CALL
5150 ScVbaRange::Item( const uno::Any& row, const uno::Any& column )
5151 {
5152  if ( mbIsRows || mbIsColumns )
5153  {
5154  if ( column.hasValue() )
5155  DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, OUString() );
5156  uno::Reference< excel::XRange > xRange;
5157  if ( mbIsColumns )
5158  xRange = Columns( row );
5159  else
5160  xRange = Rows( row );
5161  return xRange;
5162  }
5163  return Cells( row, column );
5164 }
5165 
5166 void
5168 {
5169  // #TODO #FIXME needs to check for summary row/col ( whatever they are )
5170  // not valid for multi Area Addresses
5171  if ( m_Areas->getCount() > 1 )
5172  DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY);
5173  // So needs to either span an entire Row or a just be a single cell
5174  // ( that contains a summary RowColumn )
5175  // also the Single cell cause doesn't seem to be handled specially in
5176  // this code ( ported from the helperapi RangeImpl.java,
5177  // RangeRowsImpl.java, RangesImpl.java, RangeSingleCellImpl.java
5178  RangeHelper thisRange( mxRange );
5179  table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
5180 
5181  if ( isSingleCellRange() || mbIsRows )
5182  {
5183  uno::Reference< sheet::XSheetOutline > xSheetOutline( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW );
5184  xSheetOutline->autoOutline( thisAddress );
5185  }
5186  else
5187  DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, OUString());
5188 }
5189 
5190 void SAL_CALL
5192 {
5193  if ( m_Areas->getCount() > 1 )
5194  {
5195  sal_Int32 nItems = m_Areas->getCount();
5196  for ( sal_Int32 index=1; index <= nItems; ++index )
5197  {
5198  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW );
5199  xRange->ClearOutline();
5200  }
5201  return;
5202  }
5203  RangeHelper thisRange( mxRange );
5204  uno::Reference< sheet::XSheetOutline > xSheetOutline( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW );
5205  xSheetOutline->clearOutline();
5206 }
5207 
5208 void
5210 {
5211  if ( m_Areas->getCount() > 1 )
5212  DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY);
5213  table::TableOrientation nOrient = table::TableOrientation_ROWS;
5214  if ( mbIsColumns )
5215  nOrient = table::TableOrientation_COLUMNS;
5216  RangeHelper thisRange( mxRange );
5217  table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
5218  uno::Reference< sheet::XSheetOutline > xSheetOutline( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW );
5219  if ( bUnGroup )
5220  xSheetOutline->ungroup( thisAddress, nOrient );
5221  else
5222  xSheetOutline->group( thisAddress, nOrient );
5223 }
5224 
5225 void SAL_CALL
5227 {
5228  groupUnGroup(false);
5229 }
5230 void SAL_CALL
5232 {
5233  groupUnGroup(true);
5234 }
5235 
5237 static void lcl_mergeCellsOfRange( const uno::Reference< table::XCellRange >& xCellRange, bool _bMerge )
5238 {
5239  uno::Reference< util::XMergeable > xMergeable( xCellRange, uno::UNO_QUERY_THROW );
5240  xMergeable->merge(_bMerge);
5241 }
5242 void SAL_CALL
5243 ScVbaRange::Merge( const uno::Any& Across )
5244 {
5245  if ( m_Areas->getCount() > 1 )
5246  {
5247  sal_Int32 nItems = m_Areas->getCount();
5248  for ( sal_Int32 index=1; index <= nItems; ++index )
5249  {
5250  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW );
5251  xRange->Merge(Across);
5252  }
5253  return;
5254  }
5255  bool bAcross = false;
5256  Across >>= bAcross;
5257  if ( !bAcross )
5258  lcl_mergeCellsOfRange( mxRange, true );
5259  else
5260  {
5261  uno::Reference< excel::XRange > oRangeRowsImpl = Rows( uno::Any() );
5262  // #TODO #FIXME this seems incredibly lame, this can't be right
5263  for (sal_Int32 i=1; i <= oRangeRowsImpl->getCount();i++)
5264  {
5265  oRangeRowsImpl->Cells( uno::makeAny( i ), uno::Any() )->Merge( uno::makeAny( false ) );
5266  }
5267  }
5268 }
5269 
5270 void SAL_CALL
5272 {
5273  if ( m_Areas->getCount() > 1 )
5274  {
5275  sal_Int32 nItems = m_Areas->getCount();
5276  for ( sal_Int32 index=1; index <= nItems; ++index )
5277  {
5278  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW );
5279  xRange->UnMerge();
5280  }
5281  return;
5282  }
5283  lcl_mergeCellsOfRange( mxRange, false);
5284 }
5285 
5286 uno::Any SAL_CALL
5288 {
5289  if ( m_Areas->getCount() > 1 )
5290  {
5291  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW );
5292  return xRange->getStyle();
5293  }
5294  uno::Reference< beans::XPropertySet > xProps( mxRange, uno::UNO_QUERY_THROW );
5295  OUString sStyleName;
5296  xProps->getPropertyValue( CELLSTYLE ) >>= sStyleName;
5297  ScDocShell* pShell = getScDocShell();
5298  uno::Reference< frame::XModel > xModel( pShell->GetModel() );
5299  uno::Reference< excel::XStyle > xStyle = new ScVbaStyle( this, mxContext, sStyleName, xModel );
5300  return uno::makeAny( xStyle );
5301 }
5302 void SAL_CALL
5304 {
5305  if ( m_Areas->getCount() > 1 )
5306  {
5307  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW );
5308  xRange->setStyle( _style );
5309  return;
5310  }
5311  uno::Reference< beans::XPropertySet > xProps( mxRange, uno::UNO_QUERY_THROW );
5312  uno::Reference< excel::XStyle > xStyle;
5313  _style >>= xStyle;
5314  if ( xStyle.is() )
5315  xProps->setPropertyValue( CELLSTYLE, uno::makeAny( xStyle->getName() ) );
5316 }
5317 
5318 uno::Reference< excel::XRange >
5319 ScVbaRange::PreviousNext( bool bIsPrevious )
5320 {
5321  ScMarkData markedRange(getScDocument().GetSheetLimits());
5322  ScRange refRange;
5323  RangeHelper thisRange( mxRange );
5324 
5325  ScUnoConversion::FillScRange( refRange, thisRange.getCellRangeAddressable()->getRangeAddress());
5326  markedRange. SetMarkArea( refRange );
5327  short nMove = bIsPrevious ? -1 : 1;
5328 
5329  SCCOL nNewX = refRange.aStart.Col();
5330  SCROW nNewY = refRange.aStart.Row();
5331  SCTAB nTab = refRange.aStart.Tab();
5332 
5333  ScDocument& rDoc = getScDocument();
5334  rDoc.GetNextPos( nNewX,nNewY, nTab, nMove,0, true,true, markedRange );
5335  refRange.aStart.SetCol( nNewX );
5336  refRange.aStart.SetRow( nNewY );
5337  refRange.aStart.SetTab( nTab );
5338  refRange.aEnd.SetCol( nNewX );
5339  refRange.aEnd.SetRow( nNewY );
5340  refRange.aEnd.SetTab( nTab );
5341 
5342  uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getScDocShell() , refRange ) );
5343 
5344  return new ScVbaRange( mxParent, mxContext, xRange );
5345 }
5346 
5347 uno::Reference< excel::XRange > SAL_CALL
5349 {
5350  if ( m_Areas->getCount() > 1 )
5351  {
5352  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( sal_Int32( 1 ) ), uno::Any() ) , uno::UNO_QUERY_THROW );
5353  return xRange->Next();
5354  }
5355  return PreviousNext( false );
5356 }
5357 
5358 uno::Reference< excel::XRange > SAL_CALL
5360 {
5361  if ( m_Areas->getCount() > 1 )
5362  {
5363  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW );
5364  return xRange->Previous();
5365  }
5366  return PreviousNext( true );
5367 }
5368 
5369 uno::Reference< excel::XRange > SAL_CALL
5370 ScVbaRange::SpecialCells( const uno::Any& _oType, const uno::Any& _oValue)
5371 {
5372  bool bIsSingleCell = isSingleCellRange();
5373  bool bIsMultiArea = ( m_Areas->getCount() > 1 );
5374  ScVbaRange* pRangeToUse = this;
5375  uno::Reference< excel::XRange > xUsedRange( getWorksheet()->getUsedRange() );
5376  sal_Int32 nType = 0;
5377  if ( !( _oType >>= nType ) )
5378  DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, OUString() );
5379  switch(nType)
5380  {
5381  case excel::XlCellType::xlCellTypeSameFormatConditions:
5382  case excel::XlCellType::xlCellTypeAllValidation:
5383  case excel::XlCellType::xlCellTypeSameValidation:
5384  DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, OUString());
5385  break;
5386  case excel::XlCellType::xlCellTypeBlanks:
5387  case excel::XlCellType::xlCellTypeComments:
5388  case excel::XlCellType::xlCellTypeConstants:
5389  case excel::XlCellType::xlCellTypeFormulas:
5390  case excel::XlCellType::xlCellTypeVisible:
5391  case excel::XlCellType::xlCellTypeLastCell:
5392  {
5393  if ( bIsMultiArea )
5394  {
5395  // need to process each area, gather the results and
5396  // create a new range from those
5397  std::vector< table::CellRangeAddress > rangeResults;
5398  sal_Int32 nItems = m_Areas->getCount() + 1;
5399  for ( sal_Int32 index=1; index <= nItems; ++index )
5400  {
5401  uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::makeAny(index), uno::Any() ), uno::UNO_QUERY_THROW );
5402  xRange = xRange->SpecialCells( _oType, _oValue);
5403  ScVbaRange* pRange = getImplementation( xRange );
5404  if ( xRange.is() && pRange )
5405  {
5406  sal_Int32 nElems = pRange->m_Areas->getCount() + 1;