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