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