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