xref: /AOO41X/main/sc/source/ui/vba/vbarange.cxx (revision 86d5ef3b70a994e620d076c47aeb929b123c141c)
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 seperately 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     // Strangly enough you can have Range( "namedRange1, namedRange2, etc," )
1177     // loop around each ',' seperated 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 OOO, 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         // chech 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     // convertion 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         // #FIXE 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             // its possiblefor 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, its not supported in
3075         // OOo.org 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 poing 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 enought 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 OOo
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 its all about, need to
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(), thats the bit that calcutes
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 extreems
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 paramater ") ), 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 behaviour not just row Range specific
3938 //  if ( mbIsRows )
3939     ScDocShell* pShell = getScDocShell();
3940     if ( pShell )
3941     {
3942         for ( sal_Int32 nRow = nStartRow ; nRow <= nEndRow; ++nRow )
3943         {
3944             thisAddress.StartRow = nRow;
3945             sal_uInt16 nCurTwips = pShell->GetDocument()->GetOriginalHeight( thisAddress.StartRow, thisAddress.Sheet );
3946             if ( nRow == nStartRow )
3947                 nRowTwips = nCurTwips;
3948             if ( nRowTwips != nCurTwips )
3949                 return aNULL();
3950         }
3951     }
3952     double nHeight = lcl_Round2DecPlaces( lcl_TwipsToPoints( nRowTwips ) );
3953     return uno::makeAny( nHeight );
3954 }
3955 
3956 void SAL_CALL
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; // Incomming 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 thats 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     // Althought 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 exising 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 behaviour 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 paramater ") ), 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 assosiate 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 OOo.
5036         //  In OOo, the showDetail will show all the level entrys, 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             // initialise 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