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