1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "vbarange.hxx"
22 #include <comphelper/types.hxx>
23 #include <cppuhelper/exc_hlp.hxx>
24 #include <o3tl/any.hxx>
25 #include <o3tl/safeint.hxx>
26 #include <o3tl/unit_conversion.hxx>
27 #include <rtl/math.hxx>
28 #include <comphelper/diagnose_ex.hxx>
29 #include <o3tl/string_view.hxx>
31 #include <com/sun/star/script/ArrayWrapper.hpp>
32 #include <com/sun/star/script/XTypeConverter.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/XUnnamedDatabaseRanges.hpp>
37 #include <com/sun/star/sheet/XSheetOperation.hpp>
38 #include <com/sun/star/sheet/CellFlags.hpp>
39 #include <com/sun/star/table/XColumnRowRange.hpp>
40 #include <com/sun/star/sheet/XCellAddressable.hpp>
41 #include <com/sun/star/table/CellContentType.hpp>
42 #include <com/sun/star/sheet/XCellSeries.hpp>
43 #include <com/sun/star/text/XTextRange.hpp>
44 #include <com/sun/star/sheet/XCellRangeAddressable.hpp>
45 #include <com/sun/star/table/CellAddress.hpp>
46 #include <com/sun/star/table/CellRangeAddress.hpp>
47 #include <com/sun/star/sheet/XSpreadsheetView.hpp>
48 #include <com/sun/star/sheet/XCellRangeReferrer.hpp>
49 #include <com/sun/star/sheet/XSheetCellRange.hpp>
50 #include <com/sun/star/sheet/XSpreadsheet.hpp>
51 #include <com/sun/star/sheet/XSheetCellCursor.hpp>
52 #include <com/sun/star/sheet/XArrayFormulaRange.hpp>
53 #include <com/sun/star/sheet/XNamedRange.hpp>
54 #include <com/sun/star/sheet/XNamedRanges.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/frame/XModel.hpp>
59 #include <com/sun/star/view/XSelectionSupplier.hpp>
60 #include <com/sun/star/table/XTableRows.hpp>
61 #include <com/sun/star/table/XTableColumns.hpp>
62 #include <com/sun/star/table/TableSortField.hpp>
63 #include <com/sun/star/util/XMergeable.hpp>
64 #include <com/sun/star/uno/XComponentContext.hpp>
65 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
66 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
67 #include <com/sun/star/util/XNumberFormats.hpp>
68 #include <com/sun/star/util/NumberFormat.hpp>
69 #include <com/sun/star/util/XNumberFormatTypes.hpp>
70 #include <com/sun/star/util/XReplaceable.hpp>
71 #include <com/sun/star/util/XSortable.hpp>
72 #include <com/sun/star/sheet/XCellRangeMovement.hpp>
73 #include <com/sun/star/sheet/FormulaResult.hpp>
74 #include <com/sun/star/sheet/FilterOperator2.hpp>
75 #include <com/sun/star/sheet/TableFilterField2.hpp>
76 #include <com/sun/star/sheet/XSheetFilterDescriptor2.hpp>
77 #include <com/sun/star/sheet/FilterConnection.hpp>
78 #include <com/sun/star/util/TriState.hpp>
80 #include <com/sun/star/sheet/XSubTotalCalculatable.hpp>
81 #include <com/sun/star/sheet/XSubTotalDescriptor.hpp>
82 #include <com/sun/star/sheet/GeneralFunction.hpp>
84 #include <com/sun/star/sheet/XSheetAnnotationsSupplier.hpp>
85 #include <com/sun/star/sheet/XSheetAnnotations.hpp>
87 #include <ooo/vba/excel/XlPasteSpecialOperation.hpp>
88 #include <ooo/vba/excel/XlPasteType.hpp>
89 #include <ooo/vba/excel/XlFindLookIn.hpp>
90 #include <ooo/vba/excel/XlLookAt.hpp>
91 #include <ooo/vba/excel/XlSearchOrder.hpp>
92 #include <ooo/vba/excel/XlSortOrder.hpp>
93 #include <ooo/vba/excel/XlYesNoGuess.hpp>
94 #include <ooo/vba/excel/XlSortOrientation.hpp>
95 #include <ooo/vba/excel/XlSortMethod.hpp>
96 #include <ooo/vba/excel/XlDirection.hpp>
97 #include <ooo/vba/excel/XlSortDataOption.hpp>
98 #include <ooo/vba/excel/XlDeleteShiftDirection.hpp>
99 #include <ooo/vba/excel/XlInsertShiftDirection.hpp>
100 #include <ooo/vba/excel/XlReferenceStyle.hpp>
101 #include <ooo/vba/excel/XlBordersIndex.hpp>
102 #include <ooo/vba/excel/XlPageBreak.hpp>
103 #include <ooo/vba/excel/XlAutoFilterOperator.hpp>
104 #include <ooo/vba/excel/XlAutoFillType.hpp>
105 #include <ooo/vba/excel/XlCellType.hpp>
106 #include <ooo/vba/excel/XlSpecialCellsValue.hpp>
107 #include <ooo/vba/excel/XlConsolidationFunction.hpp>
108 #include <ooo/vba/excel/XlSearchDirection.hpp>
110 #include <scitems.hxx>
111 #include <svl/srchitem.hxx>
112 #include <cellsuno.hxx>
113 #include <dbdata.hxx>
114 #include <docfunc.hxx>
115 #include <columnspanset.hxx>
116 #include <queryparam.hxx>
117 #include <sortparam.hxx>
119 #include <sfx2/dispatch.hxx>
120 #include <sfx2/app.hxx>
121 #include <sfx2/bindings.hxx>
122 #include <sfx2/viewfrm.hxx>
124 #include <unonames.hxx>
126 #include "excelvbahelper.hxx"
127 #include "vbaapplication.hxx"
128 #include "vbafont.hxx"
129 #include "vbacomment.hxx"
130 #include "vbainterior.hxx"
131 #include "vbacharacters.hxx"
132 #include "vbaborders.hxx"
133 #include "vbaworksheet.hxx"
134 #include "vbavalidation.hxx"
135 #include "vbahyperlinks.hxx"
137 #include <tabvwsh.hxx>
138 #include <rangelst.hxx>
139 #include <convuno.hxx>
140 #include <compiler.hxx>
141 #include <patattr.hxx>
142 #include <olinetab.hxx>
143 #include <transobj.hxx>
144 #include <queryentry.hxx>
145 #include <markdata.hxx>
146 #include <basic/sberrors.hxx>
147 #include <cppuhelper/implbase.hxx>
149 #include <global.hxx>
151 #include "vbastyle.hxx"
152 #include "vbaname.hxx"
155 #include <vbahelper/vbacollectionimpl.hxx>
157 #include <com/sun/star/bridge/oleautomation/Date.hpp>
158 #include <tokenarray.hxx>
159 #include <tokenuno.hxx>
163 using namespace ::ooo::vba
;
164 using namespace ::com::sun::star
;
167 // difference between VBA and file format width, in character units
168 const double fExtraWidth
= 182.0 / 256.0;
170 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
};
172 static sal_uInt16
lcl_pointsToTwips( double nVal
)
174 nVal
= nVal
* static_cast<double>(20);
175 short nTwips
= static_cast<short>(nVal
);
178 static double lcl_TwipsToPoints( sal_uInt16 nVal
)
180 double nPoints
= nVal
;
184 static double lcl_Round2DecPlaces( double nVal
)
186 nVal
= (nVal
* double(100));
187 tools::Long tmp
= static_cast<tools::Long
>(nVal
);
188 if ( ( nVal
- tmp
) >= 0.5 )
190 nVal
= double(tmp
)/100;
194 static uno::Any
lcl_makeRange( const uno::Reference
< XHelperInterface
>& rParent
, const uno::Reference
< uno::XComponentContext
>& rContext
, const uno::Any
& rAny
, bool bIsRows
, bool bIsColumns
)
196 uno::Reference
< table::XCellRange
> xCellRange(rAny
, uno::UNO_QUERY_THROW
);
197 return uno::Any( uno::Reference
< excel::XRange
>( new ScVbaRange( rParent
, rContext
, xCellRange
, bIsRows
, bIsColumns
) ) );
200 static 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
)
202 uno::Reference
< excel::XRange
> xRange
;
203 const uno::Sequence
< table::CellRangeAddress
> sAddresses
= xLocSheetCellRanges
->getRangeAddresses();
204 ScRangeList aCellRanges
;
205 if ( sAddresses
.hasElements() )
207 for ( const auto& rAddress
: sAddresses
)
210 ScUnoConversion::FillScRange( refRange
, rAddress
);
211 aCellRanges
.push_back( refRange
);
214 if ( aCellRanges
.size() == 1 )
216 uno::Reference
< table::XCellRange
> xTmpRange( new ScCellRangeObj( pDoc
, aCellRanges
.front() ) );
217 xRange
= new ScVbaRange( xParent
, xContext
, xTmpRange
);
221 uno::Reference
< sheet::XSheetCellRangeContainer
> xRanges( new ScCellRangesObj( pDoc
, aCellRanges
) );
222 xRange
= new ScVbaRange( xParent
, xContext
, xRanges
);
228 ScCellRangesBase
* ScVbaRange::getCellRangesBase()
231 return dynamic_cast<ScCellRangesBase
*>( mxRanges
.get() );
233 return dynamic_cast<ScCellRangesBase
*>( mxRange
.get() );
234 throw uno::RuntimeException(u
"General Error creating range - Unknown"_ustr
);
237 ScCellRangeObj
* ScVbaRange::getCellRangeObj()
239 return dynamic_cast< ScCellRangeObj
* >( getCellRangesBase() );
242 SfxItemSet
* ScVbaRange::getCurrentDataSet( )
244 SfxItemSet
* pDataSet
= excel::ScVbaCellRangeAccess::GetDataSet( getCellRangesBase() );
246 throw uno::RuntimeException(u
"Can't access Itemset for range"_ustr
);
250 void ScVbaRange::fireChangeEvent()
252 if( !ScVbaApplication::getDocumentEventsEnabled() )
255 ScDocument
& rDoc
= getScDocument();
256 const uno::Reference
< script::vba::XVBAEventProcessor
>& xVBAEvents
= rDoc
.GetVbaEventProcessor();
257 if( xVBAEvents
.is() ) try
259 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(uno::Reference
< excel::XRange
>( this )) };
260 xVBAEvents
->processVbaEvent( script::vba::VBAEventId::WORKSHEET_CHANGE
, aArgs
);
262 catch( uno::Exception
& )
269 class SingleRangeEnumeration
: public EnumerationHelper_BASE
271 uno::Reference
< table::XCellRange
> m_xRange
;
274 /// @throws uno::RuntimeException
275 explicit SingleRangeEnumeration( uno::Reference
< table::XCellRange
> xRange
) : m_xRange(std::move( xRange
)), bHasMore( true ) { }
276 virtual sal_Bool SAL_CALL
hasMoreElements( ) override
{ return bHasMore
; }
277 virtual uno::Any SAL_CALL
nextElement( ) override
280 throw container::NoSuchElementException();
282 return uno::Any( m_xRange
);
286 // very simple class to pass to ScVbaCollectionBaseImpl containing
289 class SingleRangeIndexAccess
: public ::cppu::WeakImplHelper
< container::XIndexAccess
,
290 container::XEnumerationAccess
>
293 uno::Reference
< table::XCellRange
> m_xRange
;
296 explicit SingleRangeIndexAccess( uno::Reference
< table::XCellRange
> xRange
) : m_xRange(std::move( xRange
)) {}
298 virtual ::sal_Int32 SAL_CALL
getCount() override
{ return 1; }
299 virtual uno::Any SAL_CALL
getByIndex( ::sal_Int32 Index
) override
302 throw lang::IndexOutOfBoundsException();
303 return uno::Any( m_xRange
);
306 virtual uno::Type SAL_CALL
getElementType() override
{ return cppu::UnoType
<table::XCellRange
>::get(); }
307 virtual sal_Bool SAL_CALL
hasElements() override
{ return true; }
308 // XEnumerationAccess
309 virtual uno::Reference
< container::XEnumeration
> SAL_CALL
createEnumeration() override
{ return new SingleRangeEnumeration( m_xRange
); }
313 class RangesEnumerationImpl
: public EnumerationHelperImpl
318 /// @throws uno::RuntimeException
319 RangesEnumerationImpl( const uno::Reference
< XHelperInterface
>& xParent
, const uno::Reference
< uno::XComponentContext
>& xContext
, const uno::Reference
< container::XEnumeration
>& xEnumeration
, bool bIsRows
, bool bIsColumns
) : EnumerationHelperImpl( xParent
, xContext
, xEnumeration
), mbIsRows( bIsRows
), mbIsColumns( bIsColumns
) {}
320 virtual uno::Any SAL_CALL
nextElement( ) override
322 return lcl_makeRange( m_xParent
, m_xContext
, m_xEnumeration
->nextElement(), mbIsRows
, mbIsColumns
);
328 class ScVbaRangeAreas
: public ScVbaCollectionBaseImpl
333 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
) {}
335 // XEnumerationAccess
336 virtual uno::Reference
< container::XEnumeration
> SAL_CALL
createEnumeration() override
;
339 virtual uno::Type SAL_CALL
getElementType() override
{ return cppu::UnoType
<excel::XRange
>::get(); }
341 virtual uno::Any
createCollectionObject( const uno::Any
& aSource
) override
;
343 virtual OUString
getServiceImplName() override
{ return OUString(); }
345 virtual uno::Sequence
< OUString
> getServiceNames() override
{ return uno::Sequence
< OUString
>(); }
349 uno::Reference
< container::XEnumeration
> SAL_CALL
350 ScVbaRangeAreas::createEnumeration()
352 uno::Reference
< container::XEnumerationAccess
> xEnumAccess( m_xIndexAccess
, uno::UNO_QUERY_THROW
);
353 return new RangesEnumerationImpl( mxParent
, mxContext
, xEnumAccess
->createEnumeration(), mbIsRows
, mbIsColumns
);
357 ScVbaRangeAreas::createCollectionObject( const uno::Any
& aSource
)
359 return lcl_makeRange( mxParent
, mxContext
, aSource
, mbIsRows
, mbIsColumns
);
362 // assume that xIf is in fact a ScCellRangesBase
363 /// @throws uno::RuntimeException
365 getDocShellFromIf( const uno::Reference
< uno::XInterface
>& xIf
)
367 ScCellRangesBase
* pUno
= dynamic_cast<ScCellRangesBase
*>( xIf
.get() );
369 throw uno::RuntimeException(u
"Failed to access underlying uno range object"_ustr
);
370 return pUno
->GetDocShell();
373 /// @throws uno::RuntimeException
375 getDocShellFromRange( const uno::Reference
< table::XCellRange
>& xRange
)
377 // need the ScCellRangesBase to get docshell
378 uno::Reference
< uno::XInterface
> xIf( xRange
);
379 return getDocShellFromIf(xIf
);
382 /// @throws uno::RuntimeException
384 getDocShellFromRanges( const uno::Reference
< sheet::XSheetCellRangeContainer
>& xRanges
)
386 // need the ScCellRangesBase to get docshell
387 uno::Reference
< uno::XInterface
> xIf( xRanges
);
388 return getDocShellFromIf(xIf
);
391 /// @throws uno::RuntimeException
392 static uno::Reference
< frame::XModel
> getModelFromXIf( const uno::Reference
< uno::XInterface
>& xIf
)
394 ScDocShell
* pDocShell
= getDocShellFromIf(xIf
);
395 return pDocShell
->GetModel();
398 /// @throws uno::RuntimeException
399 static uno::Reference
< frame::XModel
> getModelFromRange( const uno::Reference
< table::XCellRange
>& xRange
)
401 // the XInterface for getImplementation can be any derived interface, no need for queryInterface
402 uno::Reference
< uno::XInterface
> xIf( xRange
);
403 return getModelFromXIf( xIf
);
407 getDocumentFromRange( const uno::Reference
< table::XCellRange
>& xRange
)
409 ScDocShell
* pDocShell
= getDocShellFromRange( xRange
);
411 throw uno::RuntimeException(u
"Failed to access underlying docshell from uno range object"_ustr
);
412 ScDocument
& rDoc
= pDocShell
->GetDocument();
417 ScVbaRange::getScDocument()
421 uno::Reference
< container::XIndexAccess
> xIndex( mxRanges
, uno::UNO_QUERY_THROW
);
422 uno::Reference
< table::XCellRange
> xRange( xIndex
->getByIndex( 0 ), uno::UNO_QUERY_THROW
);
423 return getDocumentFromRange( xRange
);
425 return getDocumentFromRange( mxRange
);
429 ScVbaRange::getScDocShell()
433 uno::Reference
< container::XIndexAccess
> xIndex( mxRanges
, uno::UNO_QUERY_THROW
);
434 uno::Reference
< table::XCellRange
> xRange( xIndex
->getByIndex( 0 ), uno::UNO_QUERY_THROW
);
435 return getDocShellFromRange( xRange
);
437 return getDocShellFromRange( mxRange
);
440 ScVbaRange
* ScVbaRange::getImplementation( const uno::Reference
< excel::XRange
>& rxRange
)
442 // FIXME: always save to use dynamic_cast? Or better to (implement and) use XTunnel?
443 return dynamic_cast< ScVbaRange
* >( rxRange
.get() );
446 uno::Reference
< frame::XModel
> ScVbaRange::getUnoModel()
448 if( ScDocShell
* pDocShell
= getScDocShell() )
449 return pDocShell
->GetModel();
450 throw uno::RuntimeException();
453 uno::Reference
< frame::XModel
> ScVbaRange::getUnoModel( const uno::Reference
< excel::XRange
>& rxRange
)
455 if( ScVbaRange
* pScVbaRange
= getImplementation( rxRange
) )
456 return pScVbaRange
->getUnoModel();
457 throw uno::RuntimeException();
460 const ScRangeList
& ScVbaRange::getScRangeList()
462 if( ScCellRangesBase
* pScRangesBase
= getCellRangesBase() )
463 return pScRangesBase
->GetRangeList();
464 throw uno::RuntimeException(u
"Cannot obtain UNO range implementation object"_ustr
);
467 const ScRangeList
& ScVbaRange::getScRangeList( const uno::Reference
< excel::XRange
>& rxRange
)
469 if( ScVbaRange
* pScVbaRange
= getImplementation( rxRange
) )
470 return pScVbaRange
->getScRangeList();
471 throw uno::RuntimeException(u
"Cannot obtain VBA range implementation object"_ustr
);
476 class NumFormatHelper
478 uno::Reference
< util::XNumberFormatsSupplier
> mxSupplier
;
479 uno::Reference
< beans::XPropertySet
> mxRangeProps
;
480 uno::Reference
< util::XNumberFormats
> mxFormats
;
482 explicit NumFormatHelper( const uno::Reference
< table::XCellRange
>& xRange
)
484 mxSupplier
.set( getModelFromRange( xRange
), uno::UNO_QUERY_THROW
);
485 mxRangeProps
.set( xRange
, uno::UNO_QUERY_THROW
);
486 mxFormats
= mxSupplier
->getNumberFormats();
488 uno::Reference
< beans::XPropertySet
> getNumberProps()
490 tools::Long nIndexKey
= 0;
491 uno::Any aValue
= mxRangeProps
->getPropertyValue( u
"NumberFormat"_ustr
);
492 aValue
>>= nIndexKey
;
494 if ( mxFormats
.is() )
495 return mxFormats
->getByKey( nIndexKey
);
496 return uno::Reference
< beans::XPropertySet
> ();
502 return (getNumberFormat() & util::NumberFormat::LOGICAL
) != 0;
507 sal_Int16 nType
= getNumberFormat();
508 return ( nType
& util::NumberFormat::DATETIME
) != 0;
511 OUString
getNumberFormatString()
513 uno::Reference
< uno::XInterface
> xIf( mxRangeProps
, uno::UNO_QUERY_THROW
);
514 ScCellRangesBase
* pUnoCellRange
= dynamic_cast<ScCellRangesBase
*>( xIf
.get() );
518 SfxItemSet
* pDataSet
= excel::ScVbaCellRangeAccess::GetDataSet( pUnoCellRange
);
519 SfxItemState eState
= pDataSet
->GetItemState( ATTR_VALUE_FORMAT
);
520 // one of the cells in the range is not like the other ;-)
521 // so return a zero length format to indicate that
522 if ( eState
== SfxItemState::INVALID
)
526 uno::Reference
< beans::XPropertySet
> xNumberProps( getNumberProps(), uno::UNO_SET_THROW
);
527 OUString aFormatString
;
528 uno::Any aString
= xNumberProps
->getPropertyValue( u
"FormatString"_ustr
);
529 aString
>>= aFormatString
;
530 return aFormatString
;
533 sal_Int16
getNumberFormat()
535 uno::Reference
< beans::XPropertySet
> xNumberProps
= getNumberProps();
536 sal_Int16 nType
= ::comphelper::getINT16(
537 xNumberProps
->getPropertyValue( u
"Type"_ustr
) );
541 void setNumberFormat( const OUString
& rFormat
)
543 // #163288# treat "General" as "Standard" format
544 sal_Int32 nNewIndex
= 0;
545 if( !rFormat
.equalsIgnoreAsciiCase( "General" ) )
547 lang::Locale aLocale
;
548 uno::Reference
< beans::XPropertySet
> xNumProps
= getNumberProps();
549 xNumProps
->getPropertyValue( u
"Locale"_ustr
) >>= aLocale
;
550 nNewIndex
= mxFormats
->queryKey( rFormat
, aLocale
, false );
551 if ( nNewIndex
== -1 ) // format not defined
552 nNewIndex
= mxFormats
->addNew( rFormat
, aLocale
);
554 mxRangeProps
->setPropertyValue( u
"NumberFormat"_ustr
, uno::Any( nNewIndex
) );
557 void setNumberFormat( sal_Int16 nType
)
559 uno::Reference
< beans::XPropertySet
> xNumberProps
= getNumberProps();
560 lang::Locale aLocale
;
561 xNumberProps
->getPropertyValue( u
"Locale"_ustr
) >>= aLocale
;
562 uno::Reference
<util::XNumberFormatTypes
> xTypes( mxFormats
, uno::UNO_QUERY
);
565 sal_Int32 nNewIndex
= xTypes
->getStandardFormat( nType
, aLocale
);
566 mxRangeProps
->setPropertyValue( u
"NumberFormat"_ustr
, uno::Any( nNewIndex
) );
574 CellPos( sal_Int32 nRow
, sal_Int32 nCol
, sal_Int32 nArea
):m_nRow(nRow
), m_nCol(nCol
), m_nArea( nArea
) {};
582 typedef ::cppu::WeakImplHelper
< container::XEnumeration
> CellsEnumeration_BASE
;
583 typedef ::std::vector
< CellPos
> vCellPos
;
588 // we could probably could and should modify CellsEnumeration below
589 // to handle rows and columns (but I do this separately for now
590 // and... this class only handles single areas (does it have to handle
591 // multi area ranges??)
592 class ColumnsRowEnumeration
: public CellsEnumeration_BASE
594 uno::Reference
< excel::XRange
> mxRange
;
599 ColumnsRowEnumeration( uno::Reference
< excel::XRange
> xRange
, sal_Int32 nElems
) : mxRange(std::move( xRange
)), mMaxElems( nElems
), mCurElem( 0 )
603 virtual sal_Bool SAL_CALL
hasMoreElements() override
{ return mCurElem
< mMaxElems
; }
605 virtual uno::Any SAL_CALL
nextElement() override
607 if ( !hasMoreElements() )
608 throw container::NoSuchElementException();
609 sal_Int32 vbaIndex
= 1 + mCurElem
++;
610 return uno::Any( mxRange
->Item( uno::Any( vbaIndex
), uno::Any() ) );
614 class CellsEnumeration
: public CellsEnumeration_BASE
616 uno::WeakReference
< XHelperInterface
> mxParent
;
617 uno::Reference
< uno::XComponentContext
> mxContext
;
618 uno::Reference
< XCollection
> m_xAreas
;
619 vCellPos m_CellPositions
;
620 vCellPos::const_iterator m_it
;
622 /// @throws uno::RuntimeException
623 uno::Reference
< table::XCellRange
> getArea( sal_Int32 nVBAIndex
)
625 if ( nVBAIndex
< 1 || nVBAIndex
> m_xAreas
->getCount() )
626 throw uno::RuntimeException();
627 uno::Reference
< excel::XRange
> xRange( m_xAreas
->Item( uno::Any(nVBAIndex
), uno::Any() ), uno::UNO_QUERY_THROW
);
628 uno::Reference
< table::XCellRange
> xCellRange( ScVbaRange::getCellRange( xRange
), uno::UNO_QUERY_THROW
);
632 void populateArea( sal_Int32 nVBAIndex
)
634 uno::Reference
< table::XCellRange
> xRange
= getArea( nVBAIndex
);
635 uno::Reference
< table::XColumnRowRange
> xColumnRowRange(xRange
, uno::UNO_QUERY_THROW
);
636 sal_Int32 nRowCount
= xColumnRowRange
->getRows()->getCount();
637 sal_Int32 nColCount
= xColumnRowRange
->getColumns()->getCount();
638 for ( sal_Int32 i
=0; i
<nRowCount
; ++i
)
640 for ( sal_Int32 j
=0; j
<nColCount
; ++j
)
641 m_CellPositions
.emplace_back( i
,j
,nVBAIndex
);
645 CellsEnumeration( const uno::Reference
< XHelperInterface
>& xParent
, uno::Reference
< uno::XComponentContext
> xContext
, uno::Reference
< XCollection
> xAreas
): mxParent( xParent
), mxContext(std::move( xContext
)), m_xAreas(std::move( xAreas
))
647 sal_Int32 nItems
= m_xAreas
->getCount();
648 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
650 populateArea( index
);
652 m_it
= m_CellPositions
.begin();
654 virtual sal_Bool SAL_CALL
hasMoreElements() override
{ return m_it
!= m_CellPositions
.end(); }
656 virtual uno::Any SAL_CALL
nextElement() override
658 if ( !hasMoreElements() )
659 throw container::NoSuchElementException();
660 CellPos aPos
= *m_it
++;
662 uno::Reference
< table::XCellRange
> xRangeArea
= getArea( aPos
.m_nArea
);
663 uno::Reference
< table::XCellRange
> xCellRange( xRangeArea
->getCellByPosition( aPos
.m_nCol
, aPos
.m_nRow
), uno::UNO_QUERY_THROW
);
664 return uno::Any( uno::Reference
< excel::XRange
>( new ScVbaRange( mxParent
, mxContext
, xCellRange
) ) );
671 constexpr OUString ISVISIBLE
= u
"IsVisible"_ustr
;
672 const char EQUALS
[] = "=";
673 const char NOTEQUALS
[] = "<>";
674 const char GREATERTHAN
[] = ">";
675 const char GREATERTHANEQUALS
[] = ">=";
676 const char LESSTHAN
[] = "<";
677 const char LESSTHANEQUALS
[] = "<=";
678 constexpr OUString
STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY(u
"The command you chose cannot be performed with multiple selections.\nSelect a single range and click the command again"_ustr
);
679 constexpr OUString CELLSTYLE
= u
"CellStyle"_ustr
;
683 class CellValueSetter
: public ValueSetter
688 explicit CellValueSetter( uno::Any aValue
);
689 virtual bool processValue( const uno::Any
& aValue
, const uno::Reference
< table::XCell
>& xCell
) override
;
690 virtual void visitNode( sal_Int32 x
, sal_Int32 y
, const uno::Reference
< table::XCell
>& xCell
) override
;
696 CellValueSetter::CellValueSetter( uno::Any aValue
): maValue(std::move( aValue
)) {}
699 CellValueSetter::visitNode( sal_Int32
/*i*/, sal_Int32
/*j*/, const uno::Reference
< table::XCell
>& xCell
)
701 processValue( maValue
, xCell
);
705 CellValueSetter::processValue( const uno::Any
& aValue
, const uno::Reference
< table::XCell
>& xCell
)
708 bool isExtracted
= false;
709 switch ( aValue
.getValueTypeClass() )
711 case uno::TypeClass_BOOLEAN
:
714 if ( aValue
>>= bState
)
716 uno::Reference
< table::XCellRange
> xRange( xCell
, uno::UNO_QUERY_THROW
);
718 xCell
->setValue( double(1) );
720 xCell
->setValue( double(0) );
721 NumFormatHelper
cellNumFormat( xRange
);
722 cellNumFormat
.setNumberFormat( util::NumberFormat::LOGICAL
);
726 case uno::TypeClass_STRING
:
729 if ( aValue
>>= aString
)
731 // The required behavior for a string value is:
732 // 1. If the first character is a single quote, use the rest as a string cell, regardless of the cell's number format.
733 // 2. Otherwise, if the cell's number format is "text", use the string value as a string cell.
734 // 3. Otherwise, parse the string value in English locale, and apply a corresponding number format with the cell's locale
735 // if the cell's number format was "General".
736 // Case 1 is handled here, the rest in ScCellObj::InputEnglishString
738 if ( aString
.toChar() == '\'' ) // case 1 - handle with XTextRange
740 OUString
aRemainder( aString
.copy(1) ); // strip the quote
741 uno::Reference
< text::XTextRange
> xTextRange( xCell
, uno::UNO_QUERY_THROW
);
742 xTextRange
->setString( aRemainder
);
746 // call implementation method InputEnglishString
747 ScCellObj
* pCellObj
= dynamic_cast< ScCellObj
* >( xCell
.get() );
749 pCellObj
->InputEnglishString( aString
);
758 double nDouble
= 0.0;
759 if ( aValue
>>= nDouble
)
761 uno::Reference
< table::XCellRange
> xRange( xCell
, uno::UNO_QUERY_THROW
);
762 NumFormatHelper
cellFormat( xRange
);
763 // If we are setting a number and the cell types was logical
764 // then we need to reset the logical format. ( see case uno::TypeClass_BOOLEAN:
766 if ( cellFormat
.isBooleanType() )
767 cellFormat
.setNumberFormat(u
"General"_ustr
);
768 xCell
->setValue( nDouble
);
781 class CellValueGetter
: public ValueGetter
784 RangeValueType meValueType
;
787 CellValueGetter(RangeValueType eValueType
) { meValueType
= eValueType
; }
788 virtual void visitNode( sal_Int32 x
, sal_Int32 y
, const uno::Reference
< table::XCell
>& xCell
) override
;
789 virtual void processValue( const uno::Any
& aValue
) override
;
790 const uno::Any
& getValue() const override
{ return maValue
; }
796 CellValueGetter::processValue( const uno::Any
& aValue
)
800 void CellValueGetter::visitNode( sal_Int32
/*x*/, sal_Int32
/*y*/, const uno::Reference
< table::XCell
>& xCell
)
803 table::CellContentType eCellContentType
= xCell
->getType();
804 if( eCellContentType
== table::CellContentType_VALUE
|| eCellContentType
== table::CellContentType_FORMULA
)
806 if ( eCellContentType
== table::CellContentType_FORMULA
)
809 OUString sFormula
= xCell
->getFormula();
810 if ( sFormula
== "=TRUE()" )
812 else if ( sFormula
== "=FALSE()" )
816 uno::Reference
< beans::XPropertySet
> xProp( xCell
, uno::UNO_QUERY_THROW
);
818 sal_Int32 nResultType
= sheet::FormulaResult::VALUE
;
819 // some formulas give textual results
820 xProp
->getPropertyValue( u
"FormulaResultType2"_ustr
) >>= nResultType
;
822 if ( nResultType
== sheet::FormulaResult::STRING
)
824 uno::Reference
< text::XTextRange
> xTextRange(xCell
, ::uno::UNO_QUERY_THROW
);
825 aValue
<<= xTextRange
->getString();
828 aValue
<<= xCell
->getValue();
833 uno::Reference
< table::XCellRange
> xRange( xCell
, uno::UNO_QUERY_THROW
);
834 NumFormatHelper
cellFormat( xRange
);
835 if ( cellFormat
.isBooleanType() )
836 aValue
<<= ( xCell
->getValue() != 0.0 );
837 else if ( cellFormat
.isDateType() && meValueType
== RangeValueType::value
)
838 aValue
<<= bridge::oleautomation::Date( xCell
->getValue() );
840 aValue
<<= xCell
->getValue();
843 if( eCellContentType
== table::CellContentType_TEXT
)
845 uno::Reference
< text::XTextRange
> xTextRange(xCell
, ::uno::UNO_QUERY_THROW
);
846 aValue
<<= xTextRange
->getString();
848 processValue( aValue
);
853 class CellFormulaValueSetter
: public CellValueSetter
857 formula::FormulaGrammar::Grammar m_eGrammar
;
859 CellFormulaValueSetter( const uno::Any
& aValue
, ScDocument
& rDoc
, formula::FormulaGrammar::Grammar eGram
):CellValueSetter( aValue
), m_rDoc( rDoc
), m_eGrammar( eGram
){}
861 bool processValue( const uno::Any
& aValue
, const uno::Reference
< table::XCell
>& xCell
) override
864 double aDblValue
= 0.0;
865 if ( aValue
>>= sFormula
)
867 // convert to GRAM_API style grammar because XCell::setFormula
868 // always compile it in that grammar. Perhaps
869 // css.sheet.FormulaParser should be used in future to directly
870 // pass formula tokens when that API stabilizes.
871 if ( m_eGrammar
!= formula::FormulaGrammar::GRAM_API
&& ( o3tl::starts_with(o3tl::trim(sFormula
), u
"=") ) )
873 uno::Reference
< uno::XInterface
> xIf( xCell
, uno::UNO_QUERY_THROW
);
874 ScCellRangesBase
* pUnoRangesBase
875 = dynamic_cast< ScCellRangesBase
* >( xIf
.get() );
876 if ( pUnoRangesBase
)
878 const ScRangeList
& rCellRanges
= pUnoRangesBase
->GetRangeList();
879 if (!rCellRanges
.empty())
881 ScCompiler
aCompiler( m_rDoc
, rCellRanges
.front().aStart
, m_eGrammar
);
882 // compile the string in the format passed in
883 std::unique_ptr
<ScTokenArray
> pArray(aCompiler
.CompileString(sFormula
));
884 // convert to API grammar
885 aCompiler
.SetGrammar( formula::FormulaGrammar::GRAM_API
);
887 aCompiler
.CreateStringFromTokenArray(sConverted
);
888 sFormula
= EQUALS
+ sConverted
;
893 xCell
->setFormula( sFormula
);
896 else if ( aValue
>>= aDblValue
)
898 xCell
->setValue( aDblValue
);
906 class CellFormulaValueGetter
: public CellValueGetter
910 formula::FormulaGrammar::Grammar m_eGrammar
;
912 CellFormulaValueGetter(ScDocument
& rDoc
, formula::FormulaGrammar::Grammar eGram
) :
913 CellValueGetter( RangeValueType::value
), m_rDoc( rDoc
), m_eGrammar( eGram
) {}
914 virtual void visitNode( sal_Int32
/*x*/, sal_Int32
/*y*/, const uno::Reference
< table::XCell
>& xCell
) override
917 aValue
<<= xCell
->getFormula();
918 // XCell::getFormula() returns the formula in API grammar, convert.
919 if ((xCell
->getType() == table::CellContentType_FORMULA
)
920 && m_eGrammar
!= formula::FormulaGrammar::GRAM_API
)
922 uno::Reference
< uno::XInterface
> xIf( xCell
, uno::UNO_QUERY_THROW
);
923 ScCellRangesBase
* pUnoRangesBase
924 = dynamic_cast< ScCellRangesBase
* >( xIf
.get() );
929 const ScRangeList
& rCellRanges
= pUnoRangesBase
->GetRangeList();
930 if (!rCellRanges
.empty())
932 // Compile string from API grammar.
933 ScCompiler
aCompiler( m_rDoc
, rCellRanges
.front().aStart
, formula::FormulaGrammar::GRAM_API
);
934 std::unique_ptr
<ScTokenArray
> pArray(aCompiler
.CompileString(sVal
));
935 // Convert to desired grammar.
936 aCompiler
.SetGrammar( m_eGrammar
);
938 aCompiler
.CreateStringFromTokenArray(sConverted
);
939 sVal
= EQUALS
+ sConverted
;
945 processValue( aValue
);
950 class Dim2ArrayValueGetter
: public ArrayVisitor
954 ValueGetter
& mValueGetter
;
955 void processValue( sal_Int32 x
, sal_Int32 y
, const uno::Any
& aValue
)
957 uno::Sequence
< uno::Sequence
< uno::Any
> >& aMatrix
= const_cast<css::uno::Sequence
<css::uno::Sequence
<css::uno::Any
>> &>(*o3tl::doAccess
<uno::Sequence
<uno::Sequence
<uno::Any
>>>(maValue
));
958 aMatrix
.getArray()[x
].getArray()[y
] = aValue
;
962 Dim2ArrayValueGetter(sal_Int32 nRowCount
, sal_Int32 nColCount
, ValueGetter
& rValueGetter
): mValueGetter(rValueGetter
)
964 uno::Sequence
< uno::Sequence
< uno::Any
> > aMatrix
;
965 aMatrix
.realloc( nRowCount
);
966 auto pMatrix
= aMatrix
.getArray();
967 for ( sal_Int32 index
= 0; index
< nRowCount
; ++index
)
968 pMatrix
[index
].realloc( nColCount
);
971 void visitNode( sal_Int32 x
, sal_Int32 y
, const uno::Reference
< table::XCell
>& xCell
) override
974 mValueGetter
.visitNode( x
, y
, xCell
);
975 processValue( x
, y
, mValueGetter
.getValue() );
977 const uno::Any
& getValue() const { return maValue
; }
983 constexpr OUString sNA
= u
"#N/A"_ustr
;
987 class Dim1ArrayValueSetter
: public ArrayVisitor
989 uno::Sequence
< uno::Any
> aMatrix
;
991 ValueSetter
& mCellValueSetter
;
993 Dim1ArrayValueSetter( const uno::Any
& aValue
, ValueSetter
& rCellValueSetter
):mCellValueSetter( rCellValueSetter
)
996 nColCount
= aMatrix
.getLength();
998 virtual void visitNode( sal_Int32
/*x*/, sal_Int32 y
, const uno::Reference
< table::XCell
>& xCell
) override
1000 if ( y
< nColCount
)
1001 mCellValueSetter
.processValue( aMatrix
[ y
], xCell
);
1003 mCellValueSetter
.processValue( uno::Any( sNA
), xCell
);
1007 class Dim2ArrayValueSetter
: public ArrayVisitor
1009 uno::Sequence
< uno::Sequence
< uno::Any
> > aMatrix
;
1010 ValueSetter
& mCellValueSetter
;
1011 sal_Int32 nRowCount
;
1012 sal_Int32 nColCount
;
1014 Dim2ArrayValueSetter( const uno::Any
& aValue
, ValueSetter
& rCellValueSetter
) : mCellValueSetter( rCellValueSetter
)
1017 nRowCount
= aMatrix
.getLength();
1018 nColCount
= aMatrix
[0].getLength();
1021 virtual void visitNode( sal_Int32 x
, sal_Int32 y
, const uno::Reference
< table::XCell
>& xCell
) override
1023 if ( x
< nRowCount
&& y
< nColCount
)
1024 mCellValueSetter
.processValue( aMatrix
[ x
][ y
], xCell
);
1026 mCellValueSetter
.processValue( uno::Any( sNA
), xCell
);
1031 class RangeProcessor
1034 virtual void process( const uno::Reference
< excel::XRange
>& xRange
) = 0;
1037 ~RangeProcessor() {}
1040 class RangeValueProcessor
: public RangeProcessor
1042 const uno::Any
& m_aVal
;
1044 explicit RangeValueProcessor( const uno::Any
& rVal
):m_aVal( rVal
) {}
1045 virtual ~RangeValueProcessor() {}
1046 virtual void process( const uno::Reference
< excel::XRange
>& xRange
) override
1048 xRange
->setValue( m_aVal
);
1052 class RangeFormulaProcessor
: public RangeProcessor
1054 const uno::Any
& m_aVal
;
1056 explicit RangeFormulaProcessor( const uno::Any
& rVal
):m_aVal( rVal
) {}
1057 virtual ~RangeFormulaProcessor() {}
1058 virtual void process( const uno::Reference
< excel::XRange
>& xRange
) override
1060 xRange
->setFormula( m_aVal
);
1064 class RangeCountProcessor
: public RangeProcessor
1068 RangeCountProcessor():nCount(0){}
1069 virtual ~RangeCountProcessor() {}
1070 virtual void process( const uno::Reference
< excel::XRange
>& xRange
) override
1072 nCount
= nCount
+ xRange
->getCount();
1074 sal_Int32
value() { return nCount
; }
1079 uno::Reference
< XCollection
> m_Areas
;
1081 explicit AreasVisitor( uno::Reference
< XCollection
> xAreas
):m_Areas(std::move( xAreas
)){}
1083 void visit( RangeProcessor
& processor
)
1087 sal_Int32 nItems
= m_Areas
->getCount();
1088 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
1090 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(index
), uno::Any() ), uno::UNO_QUERY_THROW
);
1091 processor
.process( xRange
);
1099 uno::Reference
< table::XCellRange
> m_xCellRange
;
1102 /// @throws uno::RuntimeException
1103 explicit RangeHelper( uno::Reference
< table::XCellRange
> xCellRange
) : m_xCellRange(std::move( xCellRange
))
1105 if ( !m_xCellRange
.is() )
1106 throw uno::RuntimeException();
1108 /// @throws uno::RuntimeException
1109 explicit RangeHelper( const uno::Any
& rCellRange
)
1111 m_xCellRange
.set(rCellRange
, uno::UNO_QUERY_THROW
);
1113 /// @throws uno::RuntimeException
1114 uno::Reference
< sheet::XSheetCellRange
> getSheetCellRange() const
1116 return uno::Reference
< sheet::XSheetCellRange
>(m_xCellRange
, uno::UNO_QUERY_THROW
);
1118 /// @throws uno::RuntimeException
1119 uno::Reference
< sheet::XSpreadsheet
> getSpreadSheet() const
1121 return getSheetCellRange()->getSpreadsheet();
1124 /// @throws uno::RuntimeException
1125 uno::Reference
< table::XCellRange
> getCellRangeFromSheet() const
1127 return uno::Reference
< table::XCellRange
>(getSpreadSheet(), uno::UNO_QUERY_THROW
);
1130 /// @throws uno::RuntimeException
1131 uno::Reference
< sheet::XCellRangeAddressable
> getCellRangeAddressable() const
1133 return uno::Reference
< sheet::XCellRangeAddressable
>(m_xCellRange
, ::uno::UNO_QUERY_THROW
);
1137 /// @throws uno::RuntimeException
1138 uno::Reference
< sheet::XSheetCellCursor
> getSheetCellCursor() const
1140 return uno::Reference
< sheet::XSheetCellCursor
>( getSpreadSheet()->createCursorByRange( getSheetCellRange() ), uno::UNO_SET_THROW
);
1143 static uno::Reference
< excel::XRange
> createRangeFromRange( const uno::Reference
< XHelperInterface
>& xParent
, const uno::Reference
<uno::XComponentContext
>& xContext
,
1144 const uno::Reference
< table::XCellRange
>& xRange
, const uno::Reference
< sheet::XCellRangeAddressable
>& xCellRangeAddressable
)
1146 const table::CellRangeAddress
aRA( xCellRangeAddressable
->getRangeAddress());
1147 return uno::Reference
< excel::XRange
>( new ScVbaRange( xParent
, xContext
,
1148 xRange
->getCellRangeByPosition( aRA
.StartColumn
, aRA
.StartRow
, aRA
.EndColumn
, aRA
.EndRow
)));
1156 ScVbaRange::getCellRangesForAddress( ScRefFlags
& rResFlags
, std::u16string_view sAddress
, ScDocShell
* pDocSh
, ScRangeList
& rCellRanges
, formula::FormulaGrammar::AddressConvention eConv
, char cDelimiter
)
1161 ScDocument
& rDoc
= pDocSh
->GetDocument();
1162 rResFlags
= rCellRanges
.Parse( sAddress
, rDoc
, eConv
, 0, cDelimiter
);
1163 if ( rResFlags
& ScRefFlags::VALID
)
1171 bool getScRangeListForAddress( const OUString
& sName
, ScDocShell
* pDocSh
, const ScRange
& refRange
, ScRangeList
& aCellRanges
, formula::FormulaGrammar::AddressConvention aConv
)
1173 // see if there is a match with a named range
1174 uno::Reference
< container::XNameAccess
> xNameAccess( pDocSh
->GetModel()->getPropertyValue( u
"NamedRanges"_ustr
), uno::UNO_QUERY_THROW
);
1175 // Strange enough you can have Range( "namedRange1, namedRange2, etc," )
1176 // loop around each ',' separated name
1177 std::vector
< OUString
> vNames
;
1178 sal_Int32 nIndex
= 0;
1181 OUString aToken
= sName
.getToken( 0, ',', nIndex
);
1182 vNames
.push_back( aToken
);
1183 } while ( nIndex
>= 0 );
1185 if ( vNames
.empty() )
1186 vNames
.push_back( sName
);
1188 for ( const auto& rName
: vNames
)
1190 formula::FormulaGrammar::AddressConvention eConv
= aConv
;
1191 // spaces are illegal ( but the user of course can enter them )
1192 OUString sAddress
= rName
.trim();
1193 // if a local name ( on the active sheet ) exists this will
1194 // take precedence over a global with the same name
1195 if ( !xNameAccess
->hasByName( sAddress
) )
1198 ScDocument
& rDoc
= pDocSh
->GetDocument();
1199 SCTAB nCurTab
= ScDocShell::GetCurTab();
1200 ScRangeName
* pRangeName
= rDoc
.GetRangeName(nCurTab
);
1203 // TODO: Handle local names correctly:
1204 // bool bLocalName = pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(sAddress)) != nullptr;
1208 if ( xNameAccess
->hasByName( sAddress
) )
1210 uno::Reference
< sheet::XNamedRange
> xNamed( xNameAccess
->getByName( sAddress
), uno::UNO_QUERY_THROW
);
1211 sAddress
= xNamed
->getContent();
1212 // As the address comes from OOO, the addressing
1213 // style is may not be XL_A1
1214 eConv
= pDocSh
->GetDocument().GetAddressConvention();
1218 ScRefFlags nFlags
= ScRefFlags::ZERO
;
1219 if ( !ScVbaRange::getCellRangesForAddress( nFlags
, sAddress
, pDocSh
, aCellRanges
, eConv
, aChar
) )
1222 bool bTabFromReferrer
= !( nFlags
& ScRefFlags::TAB_3D
);
1224 for ( size_t i
= 0, nRanges
= aCellRanges
.size(); i
< nRanges
; ++i
)
1226 ScRange
& rRange
= aCellRanges
[ i
];
1227 rRange
.aStart
.SetCol( refRange
.aStart
.Col() + rRange
.aStart
.Col() );
1228 rRange
.aStart
.SetRow( refRange
.aStart
.Row() + rRange
.aStart
.Row() );
1229 rRange
.aStart
.SetTab( bTabFromReferrer
? refRange
.aStart
.Tab() : rRange
.aStart
.Tab() );
1230 rRange
.aEnd
.SetCol( refRange
.aStart
.Col() + rRange
.aEnd
.Col() );
1231 rRange
.aEnd
.SetRow( refRange
.aStart
.Row() + rRange
.aEnd
.Row() );
1232 rRange
.aEnd
.SetTab( bTabFromReferrer
? refRange
.aEnd
.Tab() : rRange
.aEnd
.Tab() );
1238 /// @throws uno::RuntimeException
1239 static rtl::Reference
<ScVbaRange
>
1240 getRangeForName( const uno::Reference
< uno::XComponentContext
>& xContext
, const OUString
& sName
, ScDocShell
* pDocSh
, const table::CellRangeAddress
& pAddr
, formula::FormulaGrammar::AddressConvention eConv
= formula::FormulaGrammar::CONV_XL_A1
)
1242 ScRangeList aCellRanges
;
1244 ScUnoConversion::FillScRange( refRange
, pAddr
);
1245 if ( !getScRangeListForAddress ( sName
, pDocSh
, refRange
, aCellRanges
, eConv
) )
1246 throw uno::RuntimeException();
1248 if ( aCellRanges
.size() == 1 )
1250 uno::Reference
< table::XCellRange
> xRange( new ScCellRangeObj( pDocSh
, aCellRanges
.front() ) );
1251 uno::Reference
< XHelperInterface
> xFixThisParent
= excel::getUnoSheetModuleObj( xRange
);
1252 return new ScVbaRange( xFixThisParent
, xContext
, xRange
);
1254 uno::Reference
< sheet::XSheetCellRangeContainer
> xRanges( new ScCellRangesObj( pDocSh
, aCellRanges
) );
1256 uno::Reference
< XHelperInterface
> xFixThisParent
= excel::getUnoSheetModuleObj( xRanges
);
1257 return new ScVbaRange( xFixThisParent
, xContext
, xRanges
);
1262 /// @throws uno::RuntimeException
1263 template< typename RangeType
>
1264 table::CellRangeAddress
lclGetRangeAddress( const uno::Reference
< RangeType
>& rxCellRange
)
1266 return uno::Reference
< sheet::XCellRangeAddressable
>( rxCellRange
, uno::UNO_QUERY_THROW
)->getRangeAddress();
1269 /// @throws uno::RuntimeException
1270 void lclClearRange( const uno::Reference
< table::XCellRange
>& rxCellRange
)
1272 using namespace ::com::sun::star::sheet::CellFlags
;
1273 sal_Int32
const nFlags
= VALUE
| DATETIME
| STRING
| ANNOTATION
| FORMULA
| HARDATTR
| STYLES
| EDITATTR
| FORMATTED
;
1274 uno::Reference
< sheet::XSheetOperation
> xSheetOperation( rxCellRange
, uno::UNO_QUERY_THROW
);
1275 xSheetOperation
->clearContents( nFlags
);
1278 /// @throws uno::RuntimeException
1279 uno::Reference
< sheet::XSheetCellRange
> lclExpandToMerged( const uno::Reference
< table::XCellRange
>& rxCellRange
, bool bRecursive
)
1281 uno::Reference
< sheet::XSheetCellRange
> xNewCellRange( rxCellRange
, uno::UNO_QUERY_THROW
);
1282 uno::Reference
< sheet::XSpreadsheet
> xSheet( xNewCellRange
->getSpreadsheet(), uno::UNO_SET_THROW
);
1283 table::CellRangeAddress aNewAddress
= lclGetRangeAddress( xNewCellRange
);
1284 table::CellRangeAddress aOldAddress
;
1285 // expand as long as there are new merged ranges included
1288 aOldAddress
= aNewAddress
;
1289 uno::Reference
< sheet::XSheetCellCursor
> xCursor( xSheet
->createCursorByRange( xNewCellRange
), uno::UNO_SET_THROW
);
1292 xCursor
->collapseToMergedArea();
1293 xNewCellRange
.set( xCursor
, uno::UNO_QUERY_THROW
);
1294 aNewAddress
= lclGetRangeAddress( xNewCellRange
);
1297 while( bRecursive
&& (aOldAddress
!= aNewAddress
) );
1298 return xNewCellRange
;
1301 /// @throws uno::RuntimeException
1302 uno::Reference
< sheet::XSheetCellRangeContainer
> lclExpandToMerged( const uno::Reference
< sheet::XSheetCellRangeContainer
>& rxCellRanges
)
1304 if( !rxCellRanges
.is() )
1305 throw uno::RuntimeException(u
"Missing cell ranges object"_ustr
);
1306 sal_Int32 nCount
= rxCellRanges
->getCount();
1308 throw uno::RuntimeException(u
"Missing cell ranges object"_ustr
);
1310 ScRangeList aScRanges
;
1311 for( sal_Int32 nIndex
= 0; nIndex
< nCount
; ++nIndex
)
1313 uno::Reference
< table::XCellRange
> xRange( rxCellRanges
->getByIndex( nIndex
), uno::UNO_QUERY_THROW
);
1314 table::CellRangeAddress aRangeAddr
= lclGetRangeAddress( lclExpandToMerged( xRange
, /*bRecursive*/true ) );
1316 ScUnoConversion::FillScRange( aScRange
, aRangeAddr
);
1317 aScRanges
.push_back( aScRange
);
1319 return new ScCellRangesObj( getDocShellFromRanges( rxCellRanges
), aScRanges
);
1322 /// @throws uno::RuntimeException
1323 void lclExpandAndMerge( const uno::Reference
< table::XCellRange
>& rxCellRange
, bool bMerge
)
1325 uno::Reference
< util::XMergeable
> xMerge( lclExpandToMerged( rxCellRange
, true ), uno::UNO_QUERY_THROW
);
1326 // Calc cannot merge over merged ranges, always unmerge first
1327 xMerge
->merge( false );
1331 // clear all contents of the covered cells (not the top-left cell)
1332 table::CellRangeAddress aRangeAddr
= lclGetRangeAddress( rxCellRange
);
1333 sal_Int32 nLastColIdx
= aRangeAddr
.EndColumn
- aRangeAddr
.StartColumn
;
1334 sal_Int32 nLastRowIdx
= aRangeAddr
.EndRow
- aRangeAddr
.StartRow
;
1335 // clear cells of top row, right of top-left cell
1336 if( nLastColIdx
> 0 )
1337 lclClearRange( rxCellRange
->getCellRangeByPosition( 1, 0, nLastColIdx
, 0 ) );
1338 // clear all rows below top row
1339 if( nLastRowIdx
> 0 )
1340 lclClearRange( rxCellRange
->getCellRangeByPosition( 0, 1, nLastColIdx
, nLastRowIdx
) );
1342 xMerge
->merge( true );
1345 /// @throws uno::RuntimeException
1346 util::TriState
lclGetMergedState( const uno::Reference
< table::XCellRange
>& rxCellRange
)
1348 /* 1) Check if range is completely inside one single merged range. To do
1349 this, try to extend from top-left cell only (not from entire range).
1350 This will exclude cases where this range consists of several merged
1351 ranges (or parts of them). */
1352 table::CellRangeAddress aRangeAddr
= lclGetRangeAddress( rxCellRange
);
1353 uno::Reference
< table::XCellRange
> xTopLeft( rxCellRange
->getCellRangeByPosition( 0, 0, 0, 0 ), uno::UNO_SET_THROW
);
1354 uno::Reference
< sheet::XSheetCellRange
> xExpanded( lclExpandToMerged( xTopLeft
, false ), uno::UNO_SET_THROW
);
1355 table::CellRangeAddress aExpAddr
= lclGetRangeAddress( xExpanded
);
1356 // check that expanded range has more than one cell (really merged)
1357 if( ((aExpAddr
.StartColumn
< aExpAddr
.EndColumn
) || (aExpAddr
.StartRow
< aExpAddr
.EndRow
)) && ScUnoConversion::Contains( aExpAddr
, aRangeAddr
) )
1358 return util::TriState_YES
;
1360 /* 2) Check if this range contains any merged cells (completely or
1361 partly). This seems to be hardly possible via API, as
1362 XMergeable::getIsMerged() returns only true, if the top-left cell of a
1363 merged range is part of this range, so cases where just the lower part
1364 of a merged range is part of this range are not covered. */
1366 ScUnoConversion::FillScRange( aScRange
, aRangeAddr
);
1367 bool bHasMerged
= getDocumentFromRange( rxCellRange
).HasAttrib( aScRange
, HasAttrFlags::Merged
| HasAttrFlags::Overlapped
);
1368 return bHasMerged
? util::TriState_INDETERMINATE
: util::TriState_NO
;
1373 css::uno::Reference
< excel::XRange
>
1374 ScVbaRange::getRangeObjectForName(
1375 const uno::Reference
< uno::XComponentContext
>& xContext
, const OUString
& sRangeName
,
1376 ScDocShell
* pDocSh
, formula::FormulaGrammar::AddressConvention eConv
)
1378 table::CellRangeAddress refAddr
;
1379 return getRangeForName( xContext
, sRangeName
, pDocSh
, refAddr
, eConv
);
1382 /// @throws uno::RuntimeException
1383 static table::CellRangeAddress
getCellRangeAddressForVBARange( const uno::Any
& aParam
, ScDocShell
* pDocSh
)
1385 uno::Reference
< table::XCellRange
> xRangeParam
;
1386 switch ( aParam
.getValueTypeClass() )
1388 case uno::TypeClass_STRING
:
1392 ScRangeList aCellRanges
;
1394 if ( getScRangeListForAddress ( rString
, pDocSh
, refRange
, aCellRanges
) )
1396 if ( aCellRanges
.size() == 1 )
1398 table::CellRangeAddress aRangeAddress
;
1399 ScUnoConversion::FillApiRange( aRangeAddress
, aCellRanges
.front() );
1400 return aRangeAddress
;
1406 case uno::TypeClass_INTERFACE
:
1408 uno::Reference
< excel::XRange
> xRange
;
1411 xRange
->getCellRange() >>= xRangeParam
;
1416 throw uno::RuntimeException(u
"Can't extract CellRangeAddress from type"_ustr
);
1418 return lclGetRangeAddress( xRangeParam
);
1421 /// @throws uno::RuntimeException
1422 static uno::Reference
< XCollection
>
1423 lcl_setupBorders( const uno::Reference
< excel::XRange
>& xParentRange
, const uno::Reference
<uno::XComponentContext
>& xContext
, const uno::Reference
< table::XCellRange
>& xRange
)
1425 uno::Reference
< XHelperInterface
> xParent( xParentRange
, uno::UNO_QUERY_THROW
);
1426 ScDocument
& rDoc
= getDocumentFromRange(xRange
);
1427 ScVbaPalette
aPalette( rDoc
.GetDocumentShell() );
1428 uno::Reference
< XCollection
> borders( new ScVbaBorders( xParent
, xContext
, xRange
, aPalette
) );
1432 ScVbaRange::ScVbaRange( uno::Sequence
< uno::Any
> const & args
,
1433 uno::Reference
< uno::XComponentContext
> const & xContext
) : ScVbaRange_BASE( getXSomethingFromArgs
< XHelperInterface
>( args
, 0 ), xContext
, getXSomethingFromArgs
< beans::XPropertySet
>( args
, 1, false ), getModelFromXIf( getXSomethingFromArgs
< uno::XInterface
>( args
, 1 ) ), true ), mbIsRows( false ), mbIsColumns( false )
1435 mxRange
.set( mxPropertySet
, uno::UNO_QUERY
);
1436 mxRanges
.set( mxPropertySet
, uno::UNO_QUERY
);
1437 uno::Reference
< container::XIndexAccess
> xIndex
;
1440 xIndex
= new SingleRangeIndexAccess( mxRange
);
1442 else if ( mxRanges
.is() )
1444 xIndex
.set( mxRanges
, uno::UNO_QUERY_THROW
);
1446 m_Areas
= new ScVbaRangeAreas( mxParent
, mxContext
, xIndex
, mbIsRows
, mbIsColumns
);
1449 ScVbaRange::ScVbaRange( const uno::Reference
< XHelperInterface
>& xParent
, const uno::Reference
< uno::XComponentContext
>& xContext
, const uno::Reference
< table::XCellRange
>& xRange
, bool bIsRows
, bool bIsColumns
)
1450 : ScVbaRange_BASE( xParent
, xContext
, uno::Reference
< beans::XPropertySet
>( xRange
, uno::UNO_QUERY_THROW
), getModelFromRange( xRange
), true ), mxRange( xRange
),
1451 mbIsRows( bIsRows
),
1452 mbIsColumns( bIsColumns
)
1454 if ( !xContext
.is() )
1455 throw lang::IllegalArgumentException(u
"context is not set "_ustr
, uno::Reference
< uno::XInterface
>() , 1 );
1457 throw lang::IllegalArgumentException(u
"range is not set "_ustr
, uno::Reference
< uno::XInterface
>() , 1 );
1459 uno::Reference
< container::XIndexAccess
> xIndex( new SingleRangeIndexAccess( xRange
) );
1460 m_Areas
= new ScVbaRangeAreas( mxParent
, mxContext
, xIndex
, mbIsRows
, mbIsColumns
);
1464 ScVbaRange::ScVbaRange(const uno::Reference
< XHelperInterface
>& xParent
, const uno::Reference
< uno::XComponentContext
>& xContext
, const uno::Reference
< sheet::XSheetCellRangeContainer
>& xRanges
, bool bIsRows
, bool bIsColumns
)
1465 : 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
)
1468 uno::Reference
< container::XIndexAccess
> xIndex( mxRanges
, uno::UNO_QUERY_THROW
);
1469 m_Areas
= new ScVbaRangeAreas( xParent
, mxContext
, xIndex
, mbIsRows
, mbIsColumns
);
1473 ScVbaRange::~ScVbaRange()
1477 uno::Reference
< XCollection
>& ScVbaRange::getBorders()
1479 if ( !m_Borders
.is() )
1481 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW
);
1482 m_Borders
= lcl_setupBorders( this, mxContext
, uno::Reference
< table::XCellRange
>( xRange
->getCellRange(), uno::UNO_QUERY_THROW
) );
1488 ScVbaRange::visitArray( ArrayVisitor
& visitor
)
1490 ScDocShell
* pDocSh
= nullptr;
1491 if(ScCellRangeObj
* range
= dynamic_cast<ScCellRangeObj
*>(mxRange
.get()))
1492 pDocSh
= range
->GetDocShell();
1494 pDocSh
->LockPaint();
1495 table::CellRangeAddress aRangeAddr
= lclGetRangeAddress( mxRange
);
1496 sal_Int32 nRowCount
= aRangeAddr
.EndRow
- aRangeAddr
.StartRow
+ 1;
1497 sal_Int32 nColCount
= aRangeAddr
.EndColumn
- aRangeAddr
.StartColumn
+ 1;
1498 for ( sal_Int32 i
=0; i
<nRowCount
; ++i
)
1500 for ( sal_Int32 j
=0; j
<nColCount
; ++j
)
1502 uno::Reference
< table::XCell
> xCell( mxRange
->getCellByPosition( j
, i
), uno::UNO_SET_THROW
);
1504 visitor
.visitNode( i
, j
, xCell
);
1508 pDocSh
->UnlockPaint();
1512 ScVbaRange::getValue( ValueGetter
& valueGetter
)
1514 uno::Reference
< table::XColumnRowRange
> xColumnRowRange(mxRange
, uno::UNO_QUERY_THROW
);
1515 // single cell range
1516 if ( isSingleCellRange() )
1518 visitArray( valueGetter
);
1519 return valueGetter
.getValue();
1521 sal_Int32 nRowCount
= xColumnRowRange
->getRows()->getCount();
1522 sal_Int32 nColCount
= xColumnRowRange
->getColumns()->getCount();
1523 // multi cell range ( return array )
1524 Dim2ArrayValueGetter
arrayGetter( nRowCount
, nColCount
, valueGetter
);
1525 visitArray( arrayGetter
);
1526 return uno::Any( script::ArrayWrapper( false, arrayGetter
.getValue() ) );
1529 css::uno::Any
ScVbaRange::DoGetValue( RangeValueType eValueType
)
1531 // #TODO code within the test below "if ( m_Areas... " can be removed
1532 // Test is performed only because m_xRange is NOT set to be
1533 // the first range in m_Areas ( to force failure while
1534 // the implementations for each method are being updated )
1535 if ( m_Areas
->getCount() > 1 )
1537 uno::Reference
< excel::XRange
> xRange( getArea( 0 ), uno::UNO_SET_THROW
);
1538 return xRange
->getValue();
1541 CellValueGetter
valueGetter( eValueType
);
1542 return getValue( valueGetter
);
1546 ScVbaRange::getValue()
1548 return DoGetValue( RangeValueType::value
);
1552 ScVbaRange::getValue2()
1554 return DoGetValue( RangeValueType::value2
);
1559 ScVbaRange::setValue( const uno::Any
& aValue
, ValueSetter
& valueSetter
)
1561 uno::TypeClass aClass
= aValue
.getValueTypeClass();
1562 if ( aClass
== uno::TypeClass_SEQUENCE
)
1564 const uno::Reference
< script::XTypeConverter
>& xConverter
= getTypeConverter( mxContext
);
1565 uno::Any aConverted
;
1568 // test for single dimension, could do
1569 // with a better test than this
1570 if ( aValue
.getValueTypeName().indexOf('[') == aValue
.getValueTypeName().lastIndexOf('[') )
1572 aConverted
= xConverter
->convertTo( aValue
, cppu::UnoType
<uno::Sequence
< uno::Any
>>::get() );
1573 Dim1ArrayValueSetter
setter( aConverted
, valueSetter
);
1574 visitArray( setter
);
1578 aConverted
= xConverter
->convertTo( aValue
, cppu::UnoType
<uno::Sequence
< uno::Sequence
< uno::Any
> >>::get() );
1579 Dim2ArrayValueSetter
setter( aConverted
, valueSetter
);
1580 visitArray( setter
);
1583 catch ( const uno::Exception
& )
1585 TOOLS_WARN_EXCEPTION("sc", "Bahhh, caught" );
1590 visitArray( valueSetter
);
1596 ScVbaRange::setValue( const uno::Any
&aValue
)
1598 // If this is a multiple selection apply setValue over all areas
1599 if ( m_Areas
->getCount() > 1 )
1601 AreasVisitor
aVisitor( m_Areas
);
1602 RangeValueProcessor
valueProcessor( aValue
);
1603 aVisitor
.visit( valueProcessor
);
1606 CellValueSetter
valueSetter( aValue
);
1607 setValue( aValue
, valueSetter
);
1611 ScVbaRange::setValue2( const uno::Any
&aValue
)
1613 return setValue( aValue
);
1620 using namespace ::com::sun::star::sheet::CellFlags
;
1621 sal_Int32
const nFlags
= VALUE
| DATETIME
| STRING
| FORMULA
| HARDATTR
| EDITATTR
| FORMATTED
;
1622 ClearContents( nFlags
, true );
1625 //helper ClearContent
1627 ScVbaRange::ClearContents( sal_Int32 nFlags
, bool bFireEvent
)
1629 // #TODO code within the test below "if ( m_Areas... " can be removed
1630 // Test is performed only because m_xRange is NOT set to be
1631 // the first range in m_Areas ( to force failure while
1632 // the implementations for each method are being updated )
1633 if ( m_Areas
->getCount() > 1 )
1635 sal_Int32 nItems
= m_Areas
->getCount();
1636 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
1638 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(index
), uno::Any() ), uno::UNO_QUERY_THROW
);
1639 ScVbaRange
* pRange
= getImplementation( xRange
);
1641 pRange
->ClearContents( nFlags
, false ); // do not fire for single ranges
1643 // fire change event for the entire range list
1644 if( bFireEvent
) fireChangeEvent();
1648 uno::Reference
< sheet::XSheetOperation
> xSheetOperation(mxRange
, uno::UNO_QUERY_THROW
);
1649 xSheetOperation
->clearContents( nFlags
);
1650 if( bFireEvent
) fireChangeEvent();
1654 ScVbaRange::ClearComments()
1656 ClearContents( sheet::CellFlags::ANNOTATION
, false );
1660 ScVbaRange::ClearContents()
1662 using namespace ::com::sun::star::sheet::CellFlags
;
1663 sal_Int32
const nFlags
= VALUE
| DATETIME
| STRING
| FORMULA
;
1664 ClearContents( nFlags
, true );
1668 ScVbaRange::ClearFormats()
1670 // FIXME: need to check if we need to combine FORMATTED
1671 using namespace ::com::sun::star::sheet::CellFlags
;
1672 sal_Int32
const nFlags
= HARDATTR
| FORMATTED
| EDITATTR
;
1673 ClearContents( nFlags
, false );
1677 ScVbaRange::setFormulaValue( const uno::Any
& rFormula
, formula::FormulaGrammar::Grammar eGram
)
1679 // If this is a multiple selection apply setFormula over all areas
1680 if ( m_Areas
->getCount() > 1 )
1682 AreasVisitor
aVisitor( m_Areas
);
1683 RangeFormulaProcessor
valueProcessor( rFormula
);
1684 aVisitor
.visit( valueProcessor
);
1687 CellFormulaValueSetter
formulaValueSetter( rFormula
, getScDocument(), eGram
);
1688 setValue( rFormula
, formulaValueSetter
);
1692 ScVbaRange::getFormulaValue( formula::FormulaGrammar::Grammar eGram
)
1694 // #TODO code within the test below "if ( m_Areas... " can be removed
1695 // Test is performed only because m_xRange is NOT set to be
1696 // the first range in m_Areas ( to force failure while
1697 // the implementations for each method are being updated )
1698 if ( m_Areas
->getCount() > 1 )
1700 uno::Reference
< excel::XRange
> xRange( getArea( 0 ), uno::UNO_SET_THROW
);
1701 return xRange
->getFormula();
1703 CellFormulaValueGetter
valueGetter( getScDocument(), eGram
);
1704 return getValue( valueGetter
);
1709 ScVbaRange::getFormula()
1711 return getFormulaValue( formula::FormulaGrammar::GRAM_ENGLISH_XL_A1
);
1715 ScVbaRange::setFormula(const uno::Any
&rFormula
)
1717 setFormulaValue( rFormula
, formula::FormulaGrammar::GRAM_ENGLISH_XL_A1
);
1721 ScVbaRange::getFormulaR1C1()
1723 return getFormulaValue( formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
1727 ScVbaRange::setFormulaR1C1(const uno::Any
& rFormula
)
1729 setFormulaValue( rFormula
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
1733 ScVbaRange::getFormulaLocal()
1735 return getFormulaValue( formula::FormulaGrammar::GRAM_NATIVE_XL_A1
);
1739 ScVbaRange::setFormulaLocal(const uno::Any
&rFormula
)
1741 setFormulaValue( rFormula
, formula::FormulaGrammar::GRAM_NATIVE_XL_A1
);
1745 ScVbaRange::getFormulaR1C1Local()
1747 return getFormulaValue( formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1
);
1751 ScVbaRange::setFormulaR1C1Local(const uno::Any
& rFormula
)
1753 setFormulaValue( rFormula
, formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1
);
1757 ScVbaRange::getCount()
1759 // If this is a multiple selection apply setValue over all areas
1760 if ( m_Areas
->getCount() > 1 )
1762 AreasVisitor
aVisitor( m_Areas
);
1763 RangeCountProcessor valueProcessor
;
1764 aVisitor
.visit( valueProcessor
);
1765 return valueProcessor
.value();
1767 sal_Int32 rowCount
= 0;
1768 sal_Int32 colCount
= 0;
1769 uno::Reference
< table::XColumnRowRange
> xColumnRowRange(mxRange
, uno::UNO_QUERY_THROW
);
1770 rowCount
= xColumnRowRange
->getRows()->getCount();
1771 colCount
= xColumnRowRange
->getColumns()->getCount();
1777 return rowCount
* colCount
;
1781 ScVbaRange::getRow()
1783 // #TODO code within the test below "if ( m_Areas... " can be removed
1784 // Test is performed only because m_xRange is NOT set to be
1785 // the first range in m_Areas ( to force failure while
1786 // the implementations for each method are being updated )
1787 if ( m_Areas
->getCount() > 1 )
1789 uno::Reference
< excel::XRange
> xRange( getArea( 0 ), uno::UNO_SET_THROW
);
1790 return xRange
->getRow();
1792 uno::Reference
< sheet::XCellAddressable
> xCellAddressable(mxRange
->getCellByPosition(0, 0), uno::UNO_QUERY_THROW
);
1793 return xCellAddressable
->getCellAddress().Row
+ 1; // Zero value indexing
1797 ScVbaRange::getColumn()
1799 // #TODO code within the test below "if ( m_Areas... " can be removed
1800 // Test is performed only because m_xRange is NOT set to be
1801 // the first range in m_Areas ( to force failure while
1802 // the implementations for each method are being updated )
1803 if ( m_Areas
->getCount() > 1 )
1805 uno::Reference
< excel::XRange
> xRange( getArea( 0 ), uno::UNO_SET_THROW
);
1806 return xRange
->getColumn();
1808 uno::Reference
< sheet::XCellAddressable
> xCellAddressable(mxRange
->getCellByPosition(0, 0), uno::UNO_QUERY_THROW
);
1809 return xCellAddressable
->getCellAddress().Column
+ 1; // Zero value indexing
1813 ScVbaRange::HasFormula()
1815 if ( m_Areas
->getCount() > 1 )
1817 sal_Int32 nItems
= m_Areas
->getCount();
1818 uno::Any aResult
= aNULL();
1819 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
1821 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(index
), uno::Any() ), uno::UNO_QUERY_THROW
);
1822 // if the HasFormula for any area is different to another
1825 if ( aResult
!= xRange
->HasFormula() )
1827 aResult
= xRange
->HasFormula();
1828 if ( aNULL() == aResult
)
1833 uno::Reference
< uno::XInterface
> xIf( mxRange
, uno::UNO_QUERY_THROW
);
1834 ScCellRangesBase
* pThisRanges
= dynamic_cast< ScCellRangesBase
* > ( xIf
.get() );
1837 uno::Reference
<uno::XInterface
> xRanges( pThisRanges
->queryFormulaCells( sheet::FormulaResult::ERROR
| sheet::FormulaResult::VALUE
| sheet::FormulaResult::STRING
), uno::UNO_QUERY_THROW
);
1838 ScCellRangesBase
* pFormulaRanges
1839 = dynamic_cast< ScCellRangesBase
* > ( xRanges
.get() );
1840 assert(pFormulaRanges
);
1841 // check if there are no formula cell, return false
1842 if ( pFormulaRanges
->GetRangeList().empty() )
1843 return uno::Any(false);
1845 // check if there are holes (where some cells are not formulas)
1846 // or returned range is not equal to this range
1847 if ( ( pFormulaRanges
->GetRangeList().size() > 1 )
1848 || ( pFormulaRanges
->GetRangeList().front().aStart
!= pThisRanges
->GetRangeList().front().aStart
)
1849 || ( pFormulaRanges
->GetRangeList().front().aEnd
!= pThisRanges
->GetRangeList().front().aEnd
)
1851 return aNULL(); // should return aNULL;
1853 return uno::Any( true );
1856 ScVbaRange::fillSeries( sheet::FillDirection nFillDirection
, sheet::FillMode nFillMode
, sheet::FillDateMode nFillDateMode
, double fStep
, double fEndValue
)
1858 if ( m_Areas
->getCount() > 1 )
1861 uno::Reference
< XCollection
> xCollection( m_Areas
, uno::UNO_SET_THROW
);
1862 for ( sal_Int32 index
= 1; index
<= xCollection
->getCount(); ++index
)
1864 uno::Reference
< excel::XRange
> xRange( xCollection
->Item( uno::Any( index
), uno::Any() ), uno::UNO_QUERY_THROW
);
1865 ScVbaRange
* pThisRange
= getImplementation( xRange
);
1866 pThisRange
->fillSeries( nFillDirection
, nFillMode
, nFillDateMode
, fStep
, fEndValue
);
1872 uno::Reference
< sheet::XCellSeries
> xCellSeries(mxRange
, uno::UNO_QUERY_THROW
);
1873 xCellSeries
->fillSeries( nFillDirection
, nFillMode
, nFillDateMode
, fStep
, fEndValue
);
1878 ScVbaRange::FillLeft()
1880 fillSeries(sheet::FillDirection_TO_LEFT
,
1881 sheet::FillMode_SIMPLE
, sheet::FillDateMode_FILL_DATE_DAY
, 0, 0x7FFFFFFF);
1885 ScVbaRange::FillRight()
1887 fillSeries(sheet::FillDirection_TO_RIGHT
,
1888 sheet::FillMode_SIMPLE
, sheet::FillDateMode_FILL_DATE_DAY
, 0, 0x7FFFFFFF);
1892 ScVbaRange::FillUp()
1894 fillSeries(sheet::FillDirection_TO_TOP
,
1895 sheet::FillMode_SIMPLE
, sheet::FillDateMode_FILL_DATE_DAY
, 0, 0x7FFFFFFF);
1899 ScVbaRange::FillDown()
1901 fillSeries(sheet::FillDirection_TO_BOTTOM
,
1902 sheet::FillMode_SIMPLE
, sheet::FillDateMode_FILL_DATE_DAY
, 0, 0x7FFFFFFF);
1906 ScVbaRange::getText()
1908 // #TODO code within the test below "if ( m_Areas... " can be removed
1909 // Test is performed only because m_xRange is NOT set to be
1910 // the first range in m_Areas ( to force failure while
1911 // the implementations for each method are being updated )
1912 if ( m_Areas
->getCount() > 1 )
1914 uno::Reference
< excel::XRange
> xRange( getArea( 0 ), uno::UNO_SET_THROW
);
1915 return xRange
->getText();
1917 uno::Reference
< text::XTextRange
> xTextRange(mxRange
->getCellByPosition(0,0), uno::UNO_QUERY_THROW
);
1918 return xTextRange
->getString();
1921 uno::Reference
< excel::XRange
>
1922 ScVbaRange::Offset( const ::uno::Any
&nRowOff
, const uno::Any
&nColOff
)
1924 SCROW nRowOffset
= 0;
1925 SCCOL nColOffset
= 0;
1926 bool bIsRowOffset
= ( nRowOff
>>= nRowOffset
);
1927 bool bIsColumnOffset
= ( nColOff
>>= nColOffset
);
1928 ScCellRangesBase
* pUnoRangesBase
= getCellRangesBase();
1930 ScRangeList aCellRanges
= pUnoRangesBase
->GetRangeList();
1932 for ( size_t i
= 0, nRanges
= aCellRanges
.size(); i
< nRanges
; ++i
)
1934 ScRange
& rRange
= aCellRanges
[ i
];
1935 if ( bIsColumnOffset
)
1937 rRange
.aStart
.SetCol( rRange
.aStart
.Col() + nColOffset
);
1938 rRange
.aEnd
.SetCol( rRange
.aEnd
.Col() + nColOffset
);
1942 rRange
.aStart
.SetRow( rRange
.aStart
.Row() + nRowOffset
);
1943 rRange
.aEnd
.SetRow( rRange
.aEnd
.Row() + nRowOffset
);
1947 if ( aCellRanges
.size() > 1 ) // Multi-Area
1949 uno::Reference
< sheet::XSheetCellRangeContainer
> xRanges( new ScCellRangesObj( pUnoRangesBase
->GetDocShell(), aCellRanges
) );
1950 return new ScVbaRange( mxParent
, mxContext
, xRanges
);
1953 const ScRange
aRange( obtainRangeEvenIfRangeListIsEmpty( aCellRanges
));
1954 uno::Reference
< table::XCellRange
> xRange( new ScCellRangeObj( pUnoRangesBase
->GetDocShell(), aRange
));
1955 return new ScVbaRange( mxParent
, mxContext
, xRange
);
1958 uno::Reference
< excel::XRange
>
1959 ScVbaRange::CurrentRegion()
1961 // #TODO code within the test below "if ( m_Areas... " can be removed
1962 // Test is performed only because m_xRange is NOT set to be
1963 // the first range in m_Areas ( to force failure while
1964 // the implementations for each method are being updated )
1965 if ( m_Areas
->getCount() > 1 )
1967 uno::Reference
< excel::XRange
> xRange( getArea( 0 ), uno::UNO_SET_THROW
);
1968 return xRange
->CurrentRegion();
1971 RangeHelper
helper( mxRange
);
1972 uno::Reference
< sheet::XSheetCellCursor
> xSheetCellCursor
=
1973 helper
.getSheetCellCursor();
1974 xSheetCellCursor
->collapseToCurrentRegion();
1975 uno::Reference
< sheet::XCellRangeAddressable
> xCellRangeAddressable(xSheetCellCursor
, uno::UNO_QUERY_THROW
);
1976 return RangeHelper::createRangeFromRange( mxParent
, mxContext
, helper
.getCellRangeFromSheet(), xCellRangeAddressable
);
1979 uno::Reference
< excel::XRange
>
1980 ScVbaRange::CurrentArray()
1982 // #TODO code within the test below "if ( m_Areas... " can be removed
1983 // Test is performed only because m_xRange is NOT set to be
1984 // the first range in m_Areas ( to force failure while
1985 // the implementations for each method are being updated )
1986 if ( m_Areas
->getCount() > 1 )
1988 uno::Reference
< excel::XRange
> xRange( getArea( 0 ), uno::UNO_SET_THROW
);
1989 return xRange
->CurrentArray();
1991 RangeHelper
helper( mxRange
);
1992 uno::Reference
< sheet::XSheetCellCursor
> xSheetCellCursor
=
1993 helper
.getSheetCellCursor();
1994 xSheetCellCursor
->collapseToCurrentArray();
1995 uno::Reference
< sheet::XCellRangeAddressable
> xCellRangeAddressable(xSheetCellCursor
, uno::UNO_QUERY_THROW
);
1996 return RangeHelper::createRangeFromRange( mxParent
, mxContext
, helper
.getCellRangeFromSheet(), xCellRangeAddressable
);
2000 ScVbaRange::getFormulaArray()
2002 // #TODO code within the test below "if ( m_Areas... " can be removed
2003 // Test is performed only because m_xRange is NOT set to be
2004 // the first range in m_Areas ( to force failure while
2005 // the implementations for each method are being updated )
2006 if ( m_Areas
->getCount() > 1 )
2008 uno::Reference
< excel::XRange
> xRange( getArea( 0 ), uno::UNO_SET_THROW
);
2009 return xRange
->getFormulaArray();
2012 // return a formula if there is one or else an array
2013 // still not sure when the return as array code should run
2014 // ( I think it is if there is more than one formula ) at least
2015 // that is what the doc says ( but I am not even sure how to detect that )
2016 // for the moment any tests we have pass
2017 uno::Reference
< sheet::XArrayFormulaRange
> xFormulaArray( mxRange
, uno::UNO_QUERY_THROW
);
2018 if ( !xFormulaArray
->getArrayFormula().isEmpty() )
2019 return uno::Any( xFormulaArray
->getArrayFormula() );
2021 uno::Reference
< sheet::XCellRangeFormula
> xCellRangeFormula( mxRange
, uno::UNO_QUERY_THROW
);
2022 const uno::Reference
< script::XTypeConverter
>& xConverter
= getTypeConverter( mxContext
);
2023 uno::Any aSingleValueOrMatrix
;
2024 // When dealing with a single element ( embedded in the sequence of sequence ) unwrap and return
2026 uno::Sequence
< uno::Sequence
<OUString
> > aTmpSeq
= xCellRangeFormula
->getFormulaArray();
2027 if ( aTmpSeq
.getLength() == 1 )
2029 if ( aTmpSeq
[ 0 ].getLength() == 1 )
2030 aSingleValueOrMatrix
<<= aTmpSeq
[ 0 ][ 0 ];
2033 aSingleValueOrMatrix
= xConverter
->convertTo( uno::Any( aTmpSeq
) , cppu::UnoType
<uno::Sequence
< uno::Sequence
< uno::Any
> >>::get() ) ;
2034 return aSingleValueOrMatrix
;
2038 ScVbaRange::setFormulaArray(const uno::Any
& rFormula
)
2040 // #TODO code within the test below "if ( m_Areas... " can be removed
2041 // Test is performed only because m_xRange is NOT set to be
2042 // the first range in m_Areas ( to force failure while
2043 // the implementations for each method are being updated )
2044 if ( m_Areas
->getCount() > 1 )
2046 uno::Reference
< excel::XRange
> xRange( getArea( 0 ), uno::UNO_SET_THROW
);
2047 return xRange
->setFormulaArray( rFormula
);
2049 // #TODO need to distinguish between getFormula and getFormulaArray e.g. (R1C1)
2050 // but for the moment it's just easier to treat them the same for setting
2052 uno::Reference
< lang::XMultiServiceFactory
> xModelFactory( getUnoModel(), uno::UNO_QUERY_THROW
);
2053 uno::Reference
< sheet::XFormulaParser
> xParser( xModelFactory
->createInstance( u
"com.sun.star.sheet.FormulaParser"_ustr
), uno::UNO_QUERY_THROW
);
2054 uno::Reference
< sheet::XCellRangeAddressable
> xSource( mxRange
, uno::UNO_QUERY_THROW
);
2056 table::CellRangeAddress aRangeAddress
= xSource
->getRangeAddress();
2057 // #TODO check if api orders the address
2058 // e.g. do we need to order the RangeAddress to get the topleft ( or can we assume it
2059 // is in the correct order )
2060 table::CellAddress aAddress
;
2061 aAddress
.Sheet
= aRangeAddress
.Sheet
;
2062 aAddress
.Column
= aRangeAddress
.StartColumn
;
2063 aAddress
.Row
= aRangeAddress
.StartRow
;
2065 rFormula
>>= sFormula
;
2066 uno::Sequence
<sheet::FormulaToken
> aTokens
= xParser
->parseFormula( sFormula
, aAddress
);
2067 ScTokenArray
aTokenArray(getScDocument());
2068 (void)ScTokenConversion::ConvertToTokenArray( getScDocument(), aTokenArray
, aTokens
);
2070 getScDocShell()->GetDocFunc().EnterMatrix( getScRangeList()[0], nullptr, &aTokenArray
, OUString(), true, true, OUString(), formula::FormulaGrammar::GRAM_API
);
2074 ScVbaRange::Characters(const uno::Any
& Start
, const uno::Any
& Length
)
2076 // #TODO code within the test below "if ( m_Areas... " can be removed
2077 // Test is performed only because m_xRange is NOT set to be
2078 // the first range in m_Areas ( to force failure while
2079 // the implementations for each method are being updated )
2080 if ( m_Areas
->getCount() > 1 )
2082 uno::Reference
< excel::XRange
> xRange( getArea( 0 ), uno::UNO_SET_THROW
);
2083 return xRange
->Characters( Start
, Length
);
2086 tools::Long nIndex
= 0, nCount
= 0;
2088 uno::Reference
< text::XTextRange
> xTextRange(mxRange
, ::uno::UNO_QUERY_THROW
);
2089 rString
= xTextRange
->getString();
2090 if( !( Start
>>= nIndex
) && !( Length
>>= nCount
) )
2092 if(!( Start
>>= nIndex
) )
2094 if(!( Length
>>= nCount
) )
2095 nIndex
= rString
.getLength();
2096 return rString
.copy( --nIndex
, nCount
); // Zero value indexing
2100 ScVbaRange::Address( const uno::Any
& RowAbsolute
, const uno::Any
& ColumnAbsolute
, const uno::Any
& ReferenceStyle
, const uno::Any
& External
, const uno::Any
& RelativeTo
)
2102 if ( m_Areas
->getCount() > 1 )
2105 OUStringBuffer sAddress
;
2106 uno::Reference
< XCollection
> xCollection( m_Areas
, uno::UNO_SET_THROW
);
2107 uno::Any aExternalCopy
= External
;
2108 for ( sal_Int32 index
= 1; index
<= xCollection
->getCount(); ++index
)
2110 uno::Reference
< excel::XRange
> xRange( xCollection
->Item( uno::Any( index
), uno::Any() ), uno::UNO_QUERY_THROW
);
2113 sAddress
.append(",");
2114 // force external to be false
2115 // only first address should have the
2116 // document and sheet specifications
2117 aExternalCopy
<<= false;
2119 sAddress
.append(xRange
->Address( RowAbsolute
, ColumnAbsolute
, ReferenceStyle
, aExternalCopy
, RelativeTo
));
2121 return sAddress
.makeStringAndClear();
2124 ScAddress::Details
dDetails( formula::FormulaGrammar::CONV_XL_A1
, 0, 0 );
2125 if ( ReferenceStyle
.hasValue() )
2127 sal_Int32 refStyle
= excel::XlReferenceStyle::xlA1
;
2128 ReferenceStyle
>>= refStyle
;
2129 if ( refStyle
== excel::XlReferenceStyle::xlR1C1
)
2130 dDetails
= ScAddress::Details( formula::FormulaGrammar::CONV_XL_R1C1
, 0, 0 );
2133 ScRefFlags nFlags
= ScRefFlags::RANGE_ABS
;
2134 ScDocShell
* pDocShell
= getScDocShell();
2135 ScDocument
& rDoc
= pDocShell
->GetDocument();
2137 RangeHelper
thisRange( mxRange
);
2138 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
2139 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
) );
2140 constexpr ScRefFlags ROW_ABS
= ScRefFlags::ROW_ABS
| ScRefFlags::ROW2_ABS
;
2141 constexpr ScRefFlags COL_ABS
= ScRefFlags::COL_ABS
| ScRefFlags::COL2_ABS
;
2143 if ( RowAbsolute
.hasValue() )
2146 RowAbsolute
>>= bVal
;
2150 if ( ColumnAbsolute
.hasValue() )
2153 ColumnAbsolute
>>= bVal
;
2157 if ( External
.hasValue() )
2159 bool bLocal
= false;
2160 External
>>= bLocal
;
2162 nFlags
|= ScRefFlags::TAB_3D
| ScRefFlags::FORCE_DOC
;
2164 if ( RelativeTo
.hasValue() )
2166 // #TODO should I throw an error if R1C1 is not set?
2168 table::CellRangeAddress refAddress
= getCellRangeAddressForVBARange( RelativeTo
, pDocShell
);
2169 dDetails
= ScAddress::Details( formula::FormulaGrammar::CONV_XL_R1C1
, static_cast< SCROW
>( refAddress
.StartRow
), static_cast< SCCOL
>( refAddress
.StartColumn
) );
2171 return aRange
.Format(rDoc
, nFlags
, dDetails
);
2174 uno::Reference
< excel::XFont
>
2177 uno::Reference
< beans::XPropertySet
> xProps(mxRange
, ::uno::UNO_QUERY
);
2178 ScDocument
& rDoc
= getScDocument();
2180 xProps
.set(mxRange
, ::uno::UNO_QUERY
);
2181 else if ( mxRanges
.is() )
2182 xProps
.set(mxRanges
, ::uno::UNO_QUERY
);
2184 ScVbaPalette
aPalette( rDoc
.GetDocumentShell() );
2185 ScCellRangeObj
* pRangeObj
= nullptr;
2188 pRangeObj
= getCellRangeObj();
2190 catch( uno::Exception
& )
2193 return new ScVbaFont( this, mxContext
, aPalette
, xProps
, pRangeObj
);
2196 uno::Reference
< excel::XRange
>
2197 ScVbaRange::Cells( const uno::Any
&nRowIndex
, const uno::Any
&nColumnIndex
)
2199 // #TODO code within the test below "if ( m_Areas... " can be removed
2200 // Test is performed only because m_xRange is NOT set to be
2201 // the first range in m_Areas ( to force failure while
2202 // the implementations for each method are being updated )
2203 if ( m_Areas
->getCount() > 1 )
2205 uno::Reference
< excel::XRange
> xRange( getArea( 0 ), uno::UNO_SET_THROW
);
2206 return xRange
->Cells( nRowIndex
, nColumnIndex
);
2209 // Performance: Use a common helper method for ScVbaRange::Cells and ScVbaWorksheet::Cells,
2210 // instead of creating a new ScVbaRange object in often-called ScVbaWorksheet::Cells
2211 return CellsHelper( getScDocument(), mxParent
, mxContext
, mxRange
, nRowIndex
, nColumnIndex
);
2215 uno::Reference
< excel::XRange
>
2216 ScVbaRange::CellsHelper( const ScDocument
& rDoc
,
2217 const uno::Reference
< ov::XHelperInterface
>& xParent
,
2218 const uno::Reference
< uno::XComponentContext
>& xContext
,
2219 const uno::Reference
< css::table::XCellRange
>& xRange
,
2220 const uno::Any
&nRowIndex
, const uno::Any
&nColumnIndex
)
2222 sal_Int32 nRow
= 0, nColumn
= 0;
2224 bool bIsIndex
= nRowIndex
.hasValue();
2225 bool bIsColumnIndex
= nColumnIndex
.hasValue();
2227 // Sometimes we might get a float or a double or whatever
2228 // set in the Any, we should convert as appropriate
2229 // #FIXME - perhaps worth turning this into some sort of
2230 // conversion routine e.g. bSuccess = getValueFromAny( nRow, nRowIndex, cppu::UnoType<sal_Int32>::get() )
2231 if ( nRowIndex
.hasValue() && !( nRowIndex
>>= nRow
) )
2233 const uno::Reference
< script::XTypeConverter
>& xConverter
= getTypeConverter( xContext
);
2234 uno::Any aConverted
;
2237 aConverted
= xConverter
->convertTo( nRowIndex
, cppu::UnoType
<sal_Int32
>::get() );
2238 bIsIndex
= ( aConverted
>>= nRow
);
2240 catch( uno::Exception
& ) {} // silence any errors
2243 if ( bIsColumnIndex
)
2245 // Column index can be a col address e.g Cells( 1, "B" ) etc.
2247 if ( nColumnIndex
>>= sCol
)
2249 ScAddress::Details
dDetails( formula::FormulaGrammar::CONV_XL_A1
, 0, 0 );
2251 ScRefFlags flags
= tmpRange
.ParseCols( rDoc
, sCol
, dDetails
);
2252 if ( (flags
& ScRefFlags::COL_VALID
) == ScRefFlags::ZERO
)
2253 throw uno::RuntimeException();
2254 nColumn
= tmpRange
.aStart
.Col() + 1;
2258 if ( !( nColumnIndex
>>= nColumn
) )
2260 const uno::Reference
< script::XTypeConverter
>& xConverter
= getTypeConverter( xContext
);
2261 uno::Any aConverted
;
2264 aConverted
= xConverter
->convertTo( nColumnIndex
, cppu::UnoType
<sal_Int32
>::get() );
2265 bIsColumnIndex
= ( aConverted
>>= nColumn
);
2267 catch( uno::Exception
& ) {} // silence any errors
2271 RangeHelper
thisRange( xRange
);
2272 table::CellRangeAddress thisRangeAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
2273 uno::Reference
< table::XCellRange
> xSheetRange
= thisRange
.getCellRangeFromSheet();
2274 if( !bIsIndex
&& !bIsColumnIndex
) // .Cells
2275 // #FIXME needs proper parent ( Worksheet )
2276 return uno::Reference
< excel::XRange
>( new ScVbaRange( xParent
, xContext
, xRange
) );
2278 sal_Int32 nIndex
= --nRow
;
2279 if( bIsIndex
&& !bIsColumnIndex
) // .Cells(n)
2281 uno::Reference
< table::XColumnRowRange
> xColumnRowRange(xRange
, ::uno::UNO_QUERY_THROW
);
2282 sal_Int32 nColCount
= xColumnRowRange
->getColumns()->getCount();
2284 if ( !nIndex
|| nIndex
< 0 )
2287 nRow
= nIndex
/ nColCount
;
2288 nColumn
= nIndex
% nColCount
;
2292 nRow
= nRow
+ thisRangeAddress
.StartRow
;
2293 nColumn
= nColumn
+ thisRangeAddress
.StartColumn
;
2294 return new ScVbaRange( xParent
, xContext
, xSheetRange
->getCellRangeByPosition( nColumn
, nRow
, nColumn
, nRow
) );
2298 ScVbaRange::Select()
2300 ScCellRangesBase
* pUnoRangesBase
= getCellRangesBase();
2301 if ( !pUnoRangesBase
)
2302 throw uno::RuntimeException(u
"Failed to access underlying uno range object"_ustr
);
2303 ScDocShell
* pShell
= pUnoRangesBase
->GetDocShell();
2307 uno::Reference
< frame::XModel
> xModel( pShell
->GetModel(), uno::UNO_SET_THROW
);
2308 uno::Reference
< view::XSelectionSupplier
> xSelection( xModel
->getCurrentController(), uno::UNO_QUERY_THROW
);
2309 if ( mxRanges
.is() )
2310 xSelection
->select( uno::Any( lclExpandToMerged( mxRanges
) ) );
2312 xSelection
->select( uno::Any( lclExpandToMerged( mxRange
, true ) ) );
2313 // set focus on document e.g.
2314 // ThisComponent.CurrentController.Frame.getContainerWindow.SetFocus
2317 uno::Reference
< frame::XController
> xController( xModel
->getCurrentController(), uno::UNO_SET_THROW
);
2318 uno::Reference
< frame::XFrame
> xFrame( xController
->getFrame(), uno::UNO_SET_THROW
);
2319 uno::Reference
< awt::XWindow
> xWin( xFrame
->getContainerWindow(), uno::UNO_SET_THROW
);
2322 catch( uno::Exception
& )
2327 static bool cellInRange( const table::CellRangeAddress
& rAddr
, sal_Int32 nCol
, sal_Int32 nRow
)
2329 return nCol
>= rAddr
.StartColumn
&& nCol
<= rAddr
.EndColumn
&&
2330 nRow
>= rAddr
.StartRow
&& nRow
<= rAddr
.EndRow
;
2333 static void setCursor( SCCOL nCol
, SCROW nRow
, const uno::Reference
< frame::XModel
>& xModel
, bool bInSel
= true )
2335 ScTabViewShell
* pShell
= excel::getBestViewShell( xModel
);
2339 pShell
->SetCursor( nCol
, nRow
);
2341 pShell
->MoveCursorAbs( nCol
, nRow
, SC_FOLLOW_NONE
, false, false, true );
2346 ScVbaRange::Activate()
2348 // get first cell of current range
2349 uno::Reference
< table::XCellRange
> xCellRange
;
2350 if ( mxRanges
.is() )
2352 uno::Reference
< container::XIndexAccess
> xIndex( mxRanges
, uno::UNO_QUERY_THROW
);
2353 xCellRange
.set( xIndex
->getByIndex( 0 ), uno::UNO_QUERY_THROW
);
2356 xCellRange
.set( mxRange
, uno::UNO_SET_THROW
);
2358 RangeHelper
thisRange( xCellRange
);
2359 uno::Reference
< sheet::XCellRangeAddressable
> xThisRangeAddress
= thisRange
.getCellRangeAddressable();
2360 table::CellRangeAddress thisRangeAddress
= xThisRangeAddress
->getRangeAddress();
2361 uno::Reference
< frame::XModel
> xModel
;
2362 ScDocShell
* pShell
= getScDocShell();
2365 xModel
= pShell
->GetModel();
2368 throw uno::RuntimeException();
2370 // get current selection
2371 uno::Reference
< sheet::XCellRangeAddressable
> xRange( xModel
->getCurrentSelection(), ::uno::UNO_QUERY
);
2373 uno::Reference
< sheet::XSheetCellRanges
> xRanges( xModel
->getCurrentSelection(), ::uno::UNO_QUERY
);
2377 const uno::Sequence
< table::CellRangeAddress
> nAddrs
= xRanges
->getRangeAddresses();
2378 for ( const auto& rAddr
: nAddrs
)
2380 if ( cellInRange( rAddr
, thisRangeAddress
.StartColumn
, thisRangeAddress
.StartRow
) )
2382 setCursor( static_cast< SCCOL
>( thisRangeAddress
.StartColumn
), static_cast< SCROW
>( thisRangeAddress
.StartRow
), xModel
);
2389 if ( xRange
.is() && cellInRange( xRange
->getRangeAddress(), thisRangeAddress
.StartColumn
, thisRangeAddress
.StartRow
) )
2390 setCursor( static_cast< SCCOL
>( thisRangeAddress
.StartColumn
), static_cast< SCROW
>( thisRangeAddress
.StartRow
), xModel
);
2393 // if this range is multi cell select the range other
2394 // wise just position the cell at this single range position
2395 if ( isSingleCellRange() )
2396 // This top-leftmost cell of this Range is not in the current
2397 // selection so just select this range
2398 setCursor( static_cast< SCCOL
>( thisRangeAddress
.StartColumn
), static_cast< SCROW
>( thisRangeAddress
.StartRow
), xModel
, false );
2405 ScRange
ScVbaRange::obtainRangeEvenIfRangeListIsEmpty( const ScRangeList
& rCellRanges
) const
2407 // XXX It may be that using the current range list was never correct, but
2408 // always the initial sheet range would be instead, history is unclear.
2410 if (!rCellRanges
.empty())
2411 return rCellRanges
.front();
2413 table::CellRangeAddress
aRA( lclGetRangeAddress( mxRange
));
2414 return ScRange( aRA
.StartColumn
, aRA
.StartRow
, aRA
.Sheet
, aRA
.EndColumn
, aRA
.EndRow
, aRA
.Sheet
);
2417 uno::Reference
< excel::XRange
>
2418 ScVbaRange::Rows(const uno::Any
& aIndex
)
2420 if ( aIndex
.hasValue() )
2422 ScCellRangesBase
* pUnoRangesBase
= getCellRangesBase();
2423 ScRange
aRange( obtainRangeEvenIfRangeListIsEmpty( pUnoRangesBase
->GetRangeList()));
2425 sal_Int32 nValue
= 0;
2427 if( aIndex
>>= nValue
)
2429 aRange
.aStart
.SetRow( aRange
.aStart
.Row() + --nValue
);
2430 aRange
.aEnd
.SetRow( aRange
.aStart
.Row() );
2432 else if ( aIndex
>>= sAddress
)
2434 ScAddress::Details
dDetails( formula::FormulaGrammar::CONV_XL_A1
, 0, 0 );
2436 tmpRange
.ParseRows( getScDocument(), sAddress
, dDetails
);
2437 SCROW nStartRow
= tmpRange
.aStart
.Row();
2438 SCROW nEndRow
= tmpRange
.aEnd
.Row();
2440 aRange
.aStart
.SetRow( aRange
.aStart
.Row() + nStartRow
);
2441 aRange
.aEnd
.SetRow( aRange
.aStart
.Row() + ( nEndRow
- nStartRow
));
2444 throw uno::RuntimeException(u
"Illegal param"_ustr
);
2446 if ( aRange
.aStart
.Row() < 0 || aRange
.aEnd
.Row() < 0 )
2447 throw uno::RuntimeException(u
"Internal failure, illegal param"_ustr
);
2448 // return a normal range ( even for multi-selection
2449 uno::Reference
< table::XCellRange
> xRange( new ScCellRangeObj( pUnoRangesBase
->GetDocShell(), aRange
) );
2450 return new ScVbaRange( mxParent
, mxContext
, xRange
, true );
2452 // Rows() - no params
2453 if ( m_Areas
->getCount() > 1 )
2454 return new ScVbaRange( mxParent
, mxContext
, mxRanges
, true );
2455 return new ScVbaRange( mxParent
, mxContext
, mxRange
, true );
2458 uno::Reference
< excel::XRange
>
2459 ScVbaRange::Columns(const uno::Any
& aIndex
)
2461 ScCellRangesBase
* pUnoRangesBase
= getCellRangesBase();
2462 ScRange
aRange( obtainRangeEvenIfRangeListIsEmpty( pUnoRangesBase
->GetRangeList()));
2464 if ( aIndex
.hasValue() )
2467 sal_Int32 nValue
= 0;
2468 if ( aIndex
>>= nValue
)
2470 aRange
.aStart
.SetCol( aRange
.aStart
.Col() + static_cast< SCCOL
> ( --nValue
) );
2471 aRange
.aEnd
.SetCol( aRange
.aStart
.Col() );
2474 else if ( aIndex
>>= sAddress
)
2476 ScAddress::Details
dDetails( formula::FormulaGrammar::CONV_XL_A1
, 0, 0 );
2478 tmpRange
.ParseCols( getScDocument(), sAddress
, dDetails
);
2479 SCCOL nStartCol
= tmpRange
.aStart
.Col();
2480 SCCOL nEndCol
= tmpRange
.aEnd
.Col();
2482 aRange
.aStart
.SetCol( aRange
.aStart
.Col() + nStartCol
);
2483 aRange
.aEnd
.SetCol( aRange
.aStart
.Col() + ( nEndCol
- nStartCol
));
2486 throw uno::RuntimeException(u
"Illegal param"_ustr
);
2488 if ( aRange
.aStart
.Col() < 0 || aRange
.aEnd
.Col() < 0 )
2489 throw uno::RuntimeException(u
"Internal failure, illegal param"_ustr
);
2491 // Columns() - no params
2492 uno::Reference
< table::XCellRange
> xRange( new ScCellRangeObj( pUnoRangesBase
->GetDocShell(), aRange
) );
2493 return new ScVbaRange( mxParent
, mxContext
, xRange
, false, true );
2497 ScVbaRange::setMergeCells( const uno::Any
& aIsMerged
)
2499 bool bMerge
= extractBoolFromAny( aIsMerged
);
2503 sal_Int32 nCount
= mxRanges
->getCount();
2505 // VBA does nothing (no error) if the own ranges overlap somehow
2506 ::std::vector
< table::CellRangeAddress
> aList
;
2507 for( sal_Int32 nIndex
= 0; nIndex
< nCount
; ++nIndex
)
2509 uno::Reference
< sheet::XCellRangeAddressable
> xRangeAddr( mxRanges
->getByIndex( nIndex
), uno::UNO_QUERY_THROW
);
2510 table::CellRangeAddress aAddress
= xRangeAddr
->getRangeAddress();
2511 if (std::any_of(aList
.begin(), aList
.end(),
2512 [&aAddress
](const table::CellRangeAddress
& rAddress
)
2513 { return ScUnoConversion::Intersects( rAddress
, aAddress
); }))
2515 aList
.push_back( aAddress
);
2518 // (un)merge every range after it has been extended to intersecting merged ranges from sheet
2519 for( sal_Int32 nIndex
= 0; nIndex
< nCount
; ++nIndex
)
2521 uno::Reference
< table::XCellRange
> xRange( mxRanges
->getByIndex( nIndex
), uno::UNO_QUERY_THROW
);
2522 lclExpandAndMerge( xRange
, bMerge
);
2527 // otherwise, merge single range
2528 lclExpandAndMerge( mxRange
, bMerge
);
2532 ScVbaRange::getMergeCells()
2536 sal_Int32 nCount
= mxRanges
->getCount();
2537 for( sal_Int32 nIndex
= 0; nIndex
< nCount
; ++nIndex
)
2539 uno::Reference
< table::XCellRange
> xRange( mxRanges
->getByIndex( nIndex
), uno::UNO_QUERY_THROW
);
2540 util::TriState eMerged
= lclGetMergedState( xRange
);
2541 /* Excel always returns NULL, if one range of the range list is
2542 partly or completely merged. Even if all ranges are completely
2543 merged, the return value is still NULL. */
2544 if( eMerged
!= util::TriState_NO
)
2547 // no range is merged anyhow, return false
2548 return uno::Any( false );
2551 // otherwise, check single range
2552 switch( lclGetMergedState( mxRange
) )
2554 case util::TriState_YES
: return uno::Any( true );
2555 case util::TriState_NO
: return uno::Any( false );
2556 default: return aNULL();
2561 ScVbaRange::Copy(const ::uno::Any
& Destination
)
2563 if ( Destination
.hasValue() )
2565 // TODO copy with multiple selections should work here too
2566 if ( m_Areas
->getCount() > 1 )
2567 throw uno::RuntimeException(u
"That command cannot be used on multiple selections"_ustr
);
2568 uno::Reference
< excel::XRange
> xRange( Destination
, uno::UNO_QUERY_THROW
);
2569 uno::Any aRange
= xRange
->getCellRange();
2570 uno::Reference
< table::XCellRange
> xCellRange
;
2571 aRange
>>= xCellRange
;
2572 uno::Reference
< sheet::XSheetCellRange
> xSheetCellRange(xCellRange
, ::uno::UNO_QUERY_THROW
);
2573 uno::Reference
< sheet::XSpreadsheet
> xSheet
= xSheetCellRange
->getSpreadsheet();
2574 uno::Reference
< table::XCellRange
> xDest( xSheet
, uno::UNO_QUERY_THROW
);
2575 uno::Reference
< sheet::XCellRangeMovement
> xMover( xSheet
, uno::UNO_QUERY_THROW
);
2576 uno::Reference
< sheet::XCellAddressable
> xDestination( xDest
->getCellByPosition(
2577 xRange
->getColumn()-1,xRange
->getRow()-1), uno::UNO_QUERY_THROW
);
2578 uno::Reference
< sheet::XCellRangeAddressable
> xSource( mxRange
, uno::UNO_QUERY
);
2579 xMover
->copyRange( xDestination
->getCellAddress(), xSource
->getRangeAddress() );
2580 if ( ScVbaRange
* pRange
= getImplementation( xRange
) )
2581 pRange
->fireChangeEvent();
2586 excel::implnCopy(getUnoModel());
2591 ScVbaRange::Cut(const ::uno::Any
& Destination
)
2593 if ( m_Areas
->getCount() > 1 )
2594 throw uno::RuntimeException(u
"That command cannot be used on multiple selections"_ustr
);
2595 if (Destination
.hasValue())
2597 uno::Reference
< excel::XRange
> xRange( Destination
, uno::UNO_QUERY_THROW
);
2598 uno::Reference
< table::XCellRange
> xCellRange( xRange
->getCellRange(), uno::UNO_QUERY_THROW
);
2599 uno::Reference
< sheet::XSheetCellRange
> xSheetCellRange(xCellRange
, ::uno::UNO_QUERY_THROW
);
2600 uno::Reference
< sheet::XSpreadsheet
> xSheet
= xSheetCellRange
->getSpreadsheet();
2601 uno::Reference
< table::XCellRange
> xDest( xSheet
, uno::UNO_QUERY_THROW
);
2602 uno::Reference
< sheet::XCellRangeMovement
> xMover( xSheet
, uno::UNO_QUERY_THROW
);
2603 uno::Reference
< sheet::XCellAddressable
> xDestination( xDest
->getCellByPosition(
2604 xRange
->getColumn()-1,xRange
->getRow()-1), uno::UNO_QUERY
);
2605 uno::Reference
< sheet::XCellRangeAddressable
> xSource( mxRange
, uno::UNO_QUERY
);
2606 xMover
->moveRange( xDestination
->getCellAddress(), xSource
->getRangeAddress() );
2610 uno::Reference
< frame::XModel
> xModel
= getModelFromRange( mxRange
);
2612 excel::implnCut( xModel
);
2617 ScVbaRange::setNumberFormat( const uno::Any
& aFormat
)
2620 aFormat
>>= sFormat
;
2621 if ( m_Areas
->getCount() > 1 )
2623 sal_Int32 nItems
= m_Areas
->getCount();
2624 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
2626 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(index
), uno::Any() ), uno::UNO_QUERY_THROW
);
2627 xRange
->setNumberFormat( aFormat
);
2631 NumFormatHelper
numFormat( mxRange
);
2632 numFormat
.setNumberFormat( sFormat
);
2636 ScVbaRange::getNumberFormat()
2639 if ( m_Areas
->getCount() > 1 )
2641 sal_Int32 nItems
= m_Areas
->getCount();
2642 uno::Any aResult
= aNULL();
2643 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
2645 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(index
), uno::Any() ), uno::UNO_QUERY_THROW
);
2646 // if the numberformat of one area is different to another
2649 if ( aResult
!= xRange
->getNumberFormat() )
2651 aResult
= xRange
->getNumberFormat();
2652 if ( aNULL() == aResult
)
2657 NumFormatHelper
numFormat( mxRange
);
2658 OUString sFormat
= numFormat
.getNumberFormatString();
2659 if ( !sFormat
.isEmpty() )
2660 return uno::Any( sFormat
);
2664 uno::Reference
< excel::XRange
>
2665 ScVbaRange::Resize( const uno::Any
&RowSize
, const uno::Any
&ColumnSize
)
2667 tools::Long nRowSize
= 0, nColumnSize
= 0;
2668 bool bIsRowChanged
= ( RowSize
>>= nRowSize
), bIsColumnChanged
= ( ColumnSize
>>= nColumnSize
);
2669 uno::Reference
< table::XColumnRowRange
> xColumnRowRange(mxRange
, ::uno::UNO_QUERY_THROW
);
2670 uno::Reference
< sheet::XSheetCellRange
> xSheetRange(mxRange
, ::uno::UNO_QUERY_THROW
);
2671 uno::Reference
< sheet::XSheetCellCursor
> xCursor( xSheetRange
->getSpreadsheet()->createCursorByRange(xSheetRange
), ::uno::UNO_SET_THROW
);
2673 if( !bIsRowChanged
)
2674 nRowSize
= xColumnRowRange
->getRows()->getCount();
2675 if( !bIsColumnChanged
)
2676 nColumnSize
= xColumnRowRange
->getColumns()->getCount();
2678 xCursor
->collapseToSize( nColumnSize
, nRowSize
);
2679 uno::Reference
< sheet::XCellRangeAddressable
> xCellRangeAddressable(xCursor
, ::uno::UNO_QUERY_THROW
);
2680 uno::Reference
< table::XCellRange
> xRange( xSheetRange
->getSpreadsheet(), ::uno::UNO_QUERY_THROW
);
2681 const table::CellRangeAddress
aRA( xCellRangeAddressable
->getRangeAddress());
2682 return new ScVbaRange( mxParent
, mxContext
, xRange
->getCellRangeByPosition( aRA
.StartColumn
, aRA
.StartRow
, aRA
.EndColumn
, aRA
.EndRow
));
2686 ScVbaRange::setWrapText( const uno::Any
& aIsWrapped
)
2688 if ( m_Areas
->getCount() > 1 )
2690 sal_Int32 nItems
= m_Areas
->getCount();
2691 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
2693 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(index
), uno::Any() ), uno::UNO_QUERY_THROW
);
2694 xRange
->setWrapText( aIsWrapped
);
2699 uno::Reference
< beans::XPropertySet
> xProps(mxRange
, ::uno::UNO_QUERY_THROW
);
2700 bool bIsWrapped
= extractBoolFromAny( aIsWrapped
);
2701 xProps
->setPropertyValue( u
"IsTextWrapped"_ustr
, uno::Any( bIsWrapped
) );
2705 ScVbaRange::getWrapText()
2707 if ( m_Areas
->getCount() > 1 )
2709 sal_Int32 nItems
= m_Areas
->getCount();
2711 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
2713 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(index
), uno::Any() ), uno::UNO_QUERY_THROW
);
2715 if ( aResult
!= xRange
->getWrapText() )
2717 aResult
= xRange
->getWrapText();
2722 SfxItemSet
* pDataSet
= getCurrentDataSet();
2724 SfxItemState eState
= pDataSet
->GetItemState( ATTR_LINEBREAK
);
2725 if ( eState
== SfxItemState::INVALID
)
2728 uno::Reference
< beans::XPropertySet
> xProps(mxRange
, ::uno::UNO_QUERY_THROW
);
2729 uno::Any aValue
= xProps
->getPropertyValue( u
"IsTextWrapped"_ustr
);
2733 uno::Reference
< excel::XInterior
> ScVbaRange::Interior( )
2735 uno::Reference
< beans::XPropertySet
> xProps( mxRange
, uno::UNO_QUERY_THROW
);
2736 return new ScVbaInterior ( this, mxContext
, xProps
, &getScDocument() );
2738 uno::Reference
< excel::XRange
>
2739 ScVbaRange::Range( const uno::Any
&Cell1
, const uno::Any
&Cell2
)
2741 return Range( Cell1
, Cell2
, false );
2743 uno::Reference
< excel::XRange
>
2744 ScVbaRange::Range( const uno::Any
&Cell1
, const uno::Any
&Cell2
, bool bForceUseInpuRangeTab
)
2747 uno::Reference
< table::XCellRange
> xCellRange
= mxRange
;
2749 if ( m_Areas
->getCount() > 1 )
2751 uno::Reference
< container::XIndexAccess
> xIndex( mxRanges
, uno::UNO_QUERY_THROW
);
2752 xCellRange
.set( xIndex
->getByIndex( 0 ), uno::UNO_QUERY_THROW
);
2755 xCellRange
.set( mxRange
);
2757 RangeHelper
thisRange( xCellRange
);
2758 uno::Reference
< table::XCellRange
> xRanges
= thisRange
.getCellRangeFromSheet();
2759 uno::Reference
< sheet::XCellRangeAddressable
> xAddressable( xRanges
, uno::UNO_QUERY_THROW
);
2761 uno::Reference
< table::XCellRange
> xReferrer
=
2762 xRanges
->getCellRangeByPosition( getColumn()-1, getRow()-1,
2763 xAddressable
->getRangeAddress().EndColumn
,
2764 xAddressable
->getRangeAddress().EndRow
);
2765 // xAddressable now for this range
2766 xAddressable
.set( xReferrer
, uno::UNO_QUERY_THROW
);
2768 if( !Cell1
.hasValue() )
2769 throw uno::RuntimeException( u
"Invalid Argument"_ustr
);
2771 table::CellRangeAddress parentRangeAddress
= xAddressable
->getRangeAddress();
2774 // Cell1 defined only
2775 if ( !Cell2
.hasValue() )
2779 RangeHelper
referRange( xReferrer
);
2780 table::CellRangeAddress referAddress
= referRange
.getCellRangeAddressable()->getRangeAddress();
2781 return getRangeForName( mxContext
, sName
, getScDocShell(), referAddress
);
2786 table::CellRangeAddress cell1
, cell2
;
2787 cell1
= getCellRangeAddressForVBARange( Cell1
, getScDocShell() );
2788 // Cell1 & Cell2 defined
2789 // Excel seems to combine the range as the range defined by
2790 // the combination of Cell1 & Cell2
2792 cell2
= getCellRangeAddressForVBARange( Cell2
, getScDocShell() );
2794 table::CellRangeAddress resultAddress
;
2795 resultAddress
.StartColumn
= ( cell1
.StartColumn
< cell2
.StartColumn
) ? cell1
.StartColumn
: cell2
.StartColumn
;
2796 resultAddress
.StartRow
= ( cell1
.StartRow
< cell2
.StartRow
) ? cell1
.StartRow
: cell2
.StartRow
;
2797 resultAddress
.EndColumn
= std::max( cell1
.EndColumn
, cell2
.EndColumn
);
2798 resultAddress
.EndRow
= std::max( cell1
.EndRow
, cell2
.EndRow
);
2799 if ( bForceUseInpuRangeTab
)
2801 // this is a call from Application.Range( x,y )
2802 // it's possible for x or y to specify a different sheet from
2803 // the current or active on ( but they must be the same )
2804 if ( cell1
.Sheet
!= cell2
.Sheet
)
2805 throw uno::RuntimeException();
2806 parentRangeAddress
.Sheet
= cell1
.Sheet
;
2810 // this is not a call from Application.Range( x,y )
2811 // if a different sheet from this range is specified it's
2813 if ( parentRangeAddress
.Sheet
!= cell1
.Sheet
2814 || parentRangeAddress
.Sheet
!= cell2
.Sheet
2816 throw uno::RuntimeException();
2819 ScUnoConversion::FillScRange( aRange
, resultAddress
);
2821 ScRange parentAddress
;
2822 ScUnoConversion::FillScRange( parentAddress
, parentRangeAddress
);
2823 if ( aRange
.aStart
.Col() >= 0 && aRange
.aStart
.Row() >= 0 && aRange
.aEnd
.Col() >= 0 && aRange
.aEnd
.Row() >= 0 )
2825 sal_Int32 nStartX
= parentAddress
.aStart
.Col() + aRange
.aStart
.Col();
2826 sal_Int32 nStartY
= parentAddress
.aStart
.Row() + aRange
.aStart
.Row();
2827 sal_Int32 nEndX
= parentAddress
.aStart
.Col() + aRange
.aEnd
.Col();
2828 sal_Int32 nEndY
= parentAddress
.aStart
.Row() + aRange
.aEnd
.Row();
2830 if ( nStartX
<= nEndX
&& nEndX
<= parentAddress
.aEnd
.Col() &&
2831 nStartY
<= nEndY
&& nEndY
<= parentAddress
.aEnd
.Row() )
2833 ScRange
aNew( static_cast<SCCOL
>(nStartX
), static_cast<SCROW
>(nStartY
), parentAddress
.aStart
.Tab(),
2834 static_cast<SCCOL
>(nEndX
), static_cast<SCROW
>(nEndY
), parentAddress
.aEnd
.Tab() );
2835 xCellRange
= new ScCellRangeObj( getScDocShell(), aNew
);
2839 return new ScVbaRange( mxParent
, mxContext
, xCellRange
);
2843 // Allow access to underlying openoffice uno api ( useful for debugging
2844 // with openoffice basic )
2845 uno::Any SAL_CALL
ScVbaRange::getCellRange( )
2848 if ( mxRanges
.is() )
2850 else if ( mxRange
.is() )
2855 uno::Any
ScVbaRange::getCellRange( const uno::Reference
< excel::XRange
>& rxRange
)
2857 if( ScVbaRange
* pVbaRange
= getImplementation( rxRange
) )
2858 return pVbaRange
->getCellRange();
2859 throw uno::RuntimeException();
2862 static InsertDeleteFlags
getPasteFlags (sal_Int32 Paste
)
2864 InsertDeleteFlags nFlags
= InsertDeleteFlags::NONE
;
2866 case excel::XlPasteType::xlPasteComments
:
2867 nFlags
= InsertDeleteFlags::NOTE
;break;
2868 case excel::XlPasteType::xlPasteFormats
:
2869 nFlags
= InsertDeleteFlags::ATTRIB
;break;
2870 case excel::XlPasteType::xlPasteFormulas
:
2871 nFlags
= InsertDeleteFlags::FORMULA
;break;
2872 case excel::XlPasteType::xlPasteFormulasAndNumberFormats
:
2873 case excel::XlPasteType::xlPasteValues
:
2874 nFlags
= ( InsertDeleteFlags::VALUE
| InsertDeleteFlags::DATETIME
| InsertDeleteFlags::STRING
| InsertDeleteFlags::SPECIAL_BOOLEAN
); break;
2875 case excel::XlPasteType::xlPasteValuesAndNumberFormats
:
2876 nFlags
= InsertDeleteFlags::VALUE
| InsertDeleteFlags::ATTRIB
; break;
2877 case excel::XlPasteType::xlPasteColumnWidths
:
2878 case excel::XlPasteType::xlPasteValidation
:
2879 nFlags
= InsertDeleteFlags::NONE
;break;
2880 case excel::XlPasteType::xlPasteAll
:
2881 case excel::XlPasteType::xlPasteAllExceptBorders
:
2883 nFlags
= InsertDeleteFlags::ALL
;break;
2889 getPasteFormulaBits( sal_Int32 Operation
)
2891 ScPasteFunc nFormulaBits
= ScPasteFunc::NONE
;
2894 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationAdd
:
2895 nFormulaBits
= ScPasteFunc::ADD
; break;
2896 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationSubtract
:
2897 nFormulaBits
= ScPasteFunc::SUB
;break;
2898 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationMultiply
:
2899 nFormulaBits
= ScPasteFunc::MUL
;break;
2900 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationDivide
:
2901 nFormulaBits
= ScPasteFunc::DIV
;break;
2903 case excel::XlPasteSpecialOperation::xlPasteSpecialOperationNone
:
2905 nFormulaBits
= ScPasteFunc::NONE
; break;
2908 return nFormulaBits
;
2911 ScVbaRange::PasteSpecial( const uno::Any
& Paste
, const uno::Any
& Operation
, const uno::Any
& SkipBlanks
, const uno::Any
& Transpose
)
2913 if ( m_Areas
->getCount() > 1 )
2914 throw uno::RuntimeException(u
"That command cannot be used on multiple selections"_ustr
);
2915 ScDocShell
* pShell
= getScDocShell();
2918 throw uno::RuntimeException(u
"That command cannot be used with no ScDocShell"_ustr
);
2920 uno::Reference
< frame::XModel
> xModel(pShell
->GetModel(), uno::UNO_SET_THROW
);
2921 uno::Reference
< view::XSelectionSupplier
> xSelection( xModel
->getCurrentController(), uno::UNO_QUERY_THROW
);
2922 // select this range
2923 xSelection
->select( uno::Any( mxRange
) );
2925 sal_Int32 nPaste
= excel::XlPasteType::xlPasteAll
;
2926 sal_Int32 nOperation
= excel::XlPasteSpecialOperation::xlPasteSpecialOperationNone
;
2927 bool bTranspose
= false;
2928 bool bSkipBlanks
= false;
2930 if ( Paste
.hasValue() )
2932 if ( Operation
.hasValue() )
2933 Operation
>>= nOperation
;
2934 if ( SkipBlanks
.hasValue() )
2935 SkipBlanks
>>= bSkipBlanks
;
2936 if ( Transpose
.hasValue() )
2937 Transpose
>>= bTranspose
;
2939 InsertDeleteFlags nFlags
= getPasteFlags(nPaste
);
2940 ScPasteFunc nFormulaBits
= getPasteFormulaBits(nOperation
);
2942 excel::implnPasteSpecial(xModel
, nFlags
, nFormulaBits
, bSkipBlanks
, bTranspose
);
2945 uno::Reference
< excel::XRange
>
2946 ScVbaRange::getEntireColumnOrRow( bool bColumn
)
2948 ScCellRangesBase
* pUnoRangesBase
= getCellRangesBase();
2949 // copy the range list
2950 ScRangeList aCellRanges
= pUnoRangesBase
->GetRangeList();
2951 ScDocument
& rDoc
= getScDocument();
2953 for ( size_t i
= 0, nRanges
= aCellRanges
.size(); i
< nRanges
; ++i
)
2955 ScRange
& rRange
= aCellRanges
[ i
];
2958 rRange
.aStart
.SetRow( 0 );
2959 rRange
.aEnd
.SetRow( rDoc
.MaxRow() );
2963 rRange
.aStart
.SetCol( 0 );
2964 rRange
.aEnd
.SetCol( rDoc
.MaxCol() );
2967 if ( aCellRanges
.size() > 1 ) // Multi-Area
2969 uno::Reference
< sheet::XSheetCellRangeContainer
> xRanges( new ScCellRangesObj( pUnoRangesBase
->GetDocShell(), aCellRanges
) );
2971 return new ScVbaRange( mxParent
, mxContext
, xRanges
, !bColumn
, bColumn
);
2973 const ScRange
aRange( obtainRangeEvenIfRangeListIsEmpty( aCellRanges
));
2974 uno::Reference
< table::XCellRange
> xRange( new ScCellRangeObj( pUnoRangesBase
->GetDocShell(), aRange
));
2975 return new ScVbaRange( mxParent
, mxContext
, xRange
, !bColumn
, bColumn
);
2978 uno::Reference
< excel::XRange
> SAL_CALL
2979 ScVbaRange::getEntireRow()
2981 return getEntireColumnOrRow(false);
2984 uno::Reference
< excel::XRange
> SAL_CALL
2985 ScVbaRange::getEntireColumn()
2987 return getEntireColumnOrRow(true);
2990 uno::Reference
< excel::XComment
> SAL_CALL
2991 ScVbaRange::AddComment( const uno::Any
& Text
)
2993 // if there is already a comment in the top-left cell then throw
2994 if( getComment().is() )
2995 throw uno::RuntimeException();
2997 // workaround: Excel allows to create empty comment, Calc does not
2999 if( Text
.hasValue() && !(Text
>>= aNoteText
) )
3000 throw uno::RuntimeException();
3001 if( aNoteText
.isEmpty() )
3004 // try to create a new annotation
3005 table::CellRangeAddress aRangePos
= lclGetRangeAddress( mxRange
);
3006 table::CellAddress
aNotePos( aRangePos
.Sheet
, aRangePos
.StartColumn
, aRangePos
.StartRow
);
3007 uno::Reference
< sheet::XSheetCellRange
> xCellRange( mxRange
, uno::UNO_QUERY_THROW
);
3008 uno::Reference
< sheet::XSheetAnnotationsSupplier
> xAnnosSupp( xCellRange
->getSpreadsheet(), uno::UNO_QUERY_THROW
);
3009 uno::Reference
< sheet::XSheetAnnotations
> xAnnos( xAnnosSupp
->getAnnotations(), uno::UNO_SET_THROW
);
3010 xAnnos
->insertNew( aNotePos
, aNoteText
);
3011 return new ScVbaComment( this, mxContext
, getUnoModel(), mxRange
);
3014 uno::Reference
< excel::XComment
> SAL_CALL
3015 ScVbaRange::getComment()
3017 // intentional behavior to return a null object if no
3019 uno::Reference
< excel::XComment
> xComment( new ScVbaComment( this, mxContext
, getUnoModel(), mxRange
) );
3020 if ( xComment
->Text( uno::Any(), uno::Any(), uno::Any() ).isEmpty() )
3026 /// @throws uno::RuntimeException
3027 static uno::Reference
< beans::XPropertySet
>
3028 getRowOrColumnProps( const uno::Reference
< table::XCellRange
>& xCellRange
, bool bRows
)
3030 uno::Reference
< table::XColumnRowRange
> xColRow( xCellRange
, uno::UNO_QUERY_THROW
);
3031 uno::Reference
< beans::XPropertySet
> xProps
;
3033 xProps
.set( xColRow
->getRows(), uno::UNO_QUERY_THROW
);
3035 xProps
.set( xColRow
->getColumns(), uno::UNO_QUERY_THROW
);
3040 ScVbaRange::getHidden()
3042 // if multi-area result is the result of the
3044 if ( m_Areas
->getCount() > 1 )
3046 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(sal_Int32(1)), uno::Any() ), uno::UNO_QUERY_THROW
);
3047 return xRange
->getHidden();
3049 bool bIsVisible
= false;
3052 uno::Reference
< beans::XPropertySet
> xProps
= getRowOrColumnProps( mxRange
, mbIsRows
);
3053 if ( !( xProps
->getPropertyValue( ISVISIBLE
) >>= bIsVisible
) )
3054 throw uno::RuntimeException(u
"Failed to get IsVisible property"_ustr
);
3056 catch( const uno::Exception
& e
)
3058 css::uno::Any anyEx
= cppu::getCaughtException();
3059 throw css::lang::WrappedTargetRuntimeException( e
.Message
,
3062 return uno::Any( !bIsVisible
);
3066 ScVbaRange::setHidden( const uno::Any
& _hidden
)
3068 if ( m_Areas
->getCount() > 1 )
3070 sal_Int32 nItems
= m_Areas
->getCount();
3071 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
3073 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(index
), uno::Any() ), uno::UNO_QUERY_THROW
);
3074 xRange
->setHidden( _hidden
);
3079 bool bHidden
= extractBoolFromAny( _hidden
);
3082 uno::Reference
< beans::XPropertySet
> xProps
= getRowOrColumnProps( mxRange
, mbIsRows
);
3083 xProps
->setPropertyValue( ISVISIBLE
, uno::Any( !bHidden
) );
3085 catch( const uno::Exception
& e
)
3087 css::uno::Any anyEx
= cppu::getCaughtException();
3088 throw css::lang::WrappedTargetRuntimeException( e
.Message
,
3094 ScVbaRange::Replace( const OUString
& What
, const 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
)
3096 if ( m_Areas
->getCount() > 1 )
3098 for ( sal_Int32 index
= 1; index
<= m_Areas
->getCount(); ++index
)
3100 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( index
), uno::Any() ), uno::UNO_QUERY_THROW
);
3101 xRange
->Replace( What
, Replacement
, LookAt
, SearchOrder
, MatchCase
, MatchByte
, SearchFormat
, ReplaceFormat
);
3103 return true; // seems to return true always ( or at least I haven't found the trick of
3106 // sanity check required params
3107 if ( What
.isEmpty() )
3108 throw uno::RuntimeException(u
"Range::Replace, missing params"_ustr
);
3109 // #TODO #FIXME SearchFormat & ReplacesFormat are not processed
3110 // What do we do about MatchByte... we don't seem to support that
3111 const SvxSearchItem
& globalSearchOptions
= ScGlobal::GetSearchItem();
3112 SvxSearchItem
newOptions( globalSearchOptions
);
3114 uno::Reference
< util::XReplaceable
> xReplace( mxRange
, uno::UNO_QUERY
);
3115 if ( xReplace
.is() )
3117 uno::Reference
< util::XReplaceDescriptor
> xDescriptor
=
3118 xReplace
->createReplaceDescriptor();
3120 xDescriptor
->setSearchString(What
);
3121 xDescriptor
->setPropertyValue(SC_UNO_SRCHWILDCARD
, uno::Any(true));
3122 xDescriptor
->setPropertyValue(SC_UNO_SRCHWCESCCHAR
, uno::Any(sal_Int32('~')));
3123 xDescriptor
->setReplaceString( Replacement
);
3124 if ( LookAt
.hasValue() )
3126 // sets SearchWords ( true is Cell match )
3127 sal_Int16 nLook
= ::comphelper::getINT16( LookAt
);
3128 bool bSearchWords
= false;
3129 if ( nLook
== excel::XlLookAt::xlPart
)
3130 bSearchWords
= false;
3131 else if ( nLook
== excel::XlLookAt::xlWhole
)
3132 bSearchWords
= true;
3134 throw uno::RuntimeException(u
"Range::Replace, illegal value for LookAt"_ustr
);
3135 // set global search props ( affects the find dialog
3136 // and of course the defaults for this method
3137 newOptions
.SetWordOnly( bSearchWords
);
3138 xDescriptor
->setPropertyValue( SC_UNO_SRCHWORDS
, uno::Any( bSearchWords
) );
3140 // sets SearchByRow ( true for Rows )
3141 if ( SearchOrder
.hasValue() )
3143 sal_Int16 nSearchOrder
= ::comphelper::getINT16( SearchOrder
);
3144 bool bSearchByRow
= false;
3145 if ( nSearchOrder
== excel::XlSearchOrder::xlByColumns
)
3146 bSearchByRow
= false;
3147 else if ( nSearchOrder
== excel::XlSearchOrder::xlByRows
)
3148 bSearchByRow
= true;
3150 throw uno::RuntimeException(u
"Range::Replace, illegal value for SearchOrder"_ustr
);
3152 newOptions
.SetRowDirection( bSearchByRow
);
3153 xDescriptor
->setPropertyValue( SC_UNO_SRCHBYROW
, uno::Any( bSearchByRow
) );
3155 if ( MatchCase
.hasValue() )
3157 bool bMatchCase
= false;
3159 // SearchCaseSensitive
3160 MatchCase
>>= bMatchCase
;
3161 xDescriptor
->setPropertyValue( SC_UNO_SRCHCASE
, uno::Any( bMatchCase
) );
3164 ScGlobal::SetSearchItem( newOptions
);
3165 // ignore MatchByte for the moment, it's not supported in
3168 uno::Reference
< container::XIndexAccess
> xIndexAccess
= xReplace
->findAll( xDescriptor
);
3169 xReplace
->replaceAll( xDescriptor
);
3170 if ( xIndexAccess
.is() && xIndexAccess
->getCount() > 0 )
3172 for ( sal_Int32 i
= 0; i
< xIndexAccess
->getCount(); ++i
)
3174 uno::Reference
< table::XCellRange
> xCellRange( xIndexAccess
->getByIndex( i
), uno::UNO_QUERY
);
3175 if ( xCellRange
.is() )
3177 uno::Reference
< excel::XRange
> xRange( new ScVbaRange( mxParent
, mxContext
, xCellRange
) );
3178 uno::Reference
< container::XEnumerationAccess
> xEnumAccess( xRange
, uno::UNO_QUERY_THROW
);
3179 uno::Reference
< container::XEnumeration
> xEnum
= xEnumAccess
->createEnumeration();
3180 while ( xEnum
->hasMoreElements() )
3182 uno::Reference
< excel::XRange
> xNextRange( xEnum
->nextElement(), uno::UNO_QUERY_THROW
);
3183 ScVbaRange
* pRange
= dynamic_cast< ScVbaRange
* > ( xNextRange
.get() );
3185 pRange
->fireChangeEvent();
3191 return true; // always
3194 uno::Reference
< excel::XRange
> SAL_CALL
3195 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*/ )
3197 // return a Range object that represents the first cell where that information is found.
3199 sal_Int32 nWhat
= 0;
3203 if( What
>>= sWhat
)
3205 else if( What
>>= nWhat
)
3207 sWhat
= OUString::number( nWhat
);
3209 else if( What
>>= fWhat
)
3211 sWhat
= OUString::number( fWhat
);
3214 throw uno::RuntimeException(u
"Range::Find, missing search-for-what param"_ustr
);
3216 const SvxSearchItem
& globalSearchOptions
= ScGlobal::GetSearchItem();
3217 SvxSearchItem
newOptions( globalSearchOptions
);
3219 uno::Reference
< util::XSearchable
> xSearch( mxRange
, uno::UNO_QUERY
);
3222 uno::Reference
< util::XSearchDescriptor
> xDescriptor
= xSearch
->createSearchDescriptor();
3223 xDescriptor
->setSearchString(sWhat
);
3224 xDescriptor
->setPropertyValue(SC_UNO_SRCHWILDCARD
, uno::Any(true));
3225 xDescriptor
->setPropertyValue(SC_UNO_SRCHWCESCCHAR
, uno::Any(sal_Int32('~')));
3227 uno::Reference
< excel::XRange
> xAfterRange
;
3228 uno::Reference
< table::XCellRange
> xStartCell
;
3229 if( After
>>= xAfterRange
)
3231 // After must be a single cell in the range
3232 if( xAfterRange
->getCount() > 1 )
3233 throw uno::RuntimeException(u
"After must be a single cell."_ustr
);
3234 uno::Reference
< excel::XRange
> xCell( Cells( uno::Any( xAfterRange
->getRow() ), uno::Any( xAfterRange
->getColumn() ) ), uno::UNO_SET_THROW
);
3235 xStartCell
.set( xAfterRange
->getCellRange(), uno::UNO_QUERY_THROW
);
3239 if( LookIn
.hasValue() )
3241 sal_Int32 nLookIn
= 0;
3242 if( LookIn
>>= nLookIn
)
3244 SvxSearchCellType nSearchType
;
3247 case excel::XlFindLookIn::xlComments
:
3248 nSearchType
= SvxSearchCellType::NOTE
; // Notes
3250 case excel::XlFindLookIn::xlFormulas
:
3251 nSearchType
= SvxSearchCellType::FORMULA
;
3253 case excel::XlFindLookIn::xlValues
:
3254 nSearchType
= SvxSearchCellType::VALUE
;
3257 throw uno::RuntimeException(u
"Range::Find, illegal value for LookIn."_ustr
);
3259 newOptions
.SetCellType( nSearchType
);
3260 xDescriptor
->setPropertyValue( u
"SearchType"_ustr
, uno::Any( static_cast<sal_uInt16
>(nSearchType
) ) );
3265 if ( LookAt
.hasValue() )
3267 sal_Int16 nLookAt
= ::comphelper::getINT16( LookAt
);
3268 bool bSearchWords
= false;
3269 if ( nLookAt
== excel::XlLookAt::xlPart
)
3270 bSearchWords
= false;
3271 else if ( nLookAt
== excel::XlLookAt::xlWhole
)
3272 bSearchWords
= true;
3274 throw uno::RuntimeException(u
"Range::Find, illegal value for LookAt"_ustr
);
3275 newOptions
.SetWordOnly( bSearchWords
);
3276 xDescriptor
->setPropertyValue( SC_UNO_SRCHWORDS
, uno::Any( bSearchWords
) );
3280 if ( SearchOrder
.hasValue() )
3282 sal_Int16 nSearchOrder
= ::comphelper::getINT16( SearchOrder
);
3283 bool bSearchByRow
= false;
3284 if ( nSearchOrder
== excel::XlSearchOrder::xlByColumns
)
3285 bSearchByRow
= false;
3286 else if ( nSearchOrder
== excel::XlSearchOrder::xlByRows
)
3287 bSearchByRow
= true;
3289 throw uno::RuntimeException(u
"Range::Find, illegal value for SearchOrder"_ustr
);
3291 newOptions
.SetRowDirection( bSearchByRow
);
3292 xDescriptor
->setPropertyValue( SC_UNO_SRCHBYROW
, uno::Any( bSearchByRow
) );
3296 if ( SearchDirection
.hasValue() )
3298 sal_Int32 nSearchDirection
= 0;
3299 if( SearchDirection
>>= nSearchDirection
)
3301 bool bSearchBackwards
= false;
3302 if ( nSearchDirection
== excel::XlSearchDirection::xlNext
)
3303 bSearchBackwards
= false;
3304 else if( nSearchDirection
== excel::XlSearchDirection::xlPrevious
)
3305 bSearchBackwards
= true;
3307 throw uno::RuntimeException(u
"Range::Find, illegal value for SearchDirection"_ustr
);
3308 newOptions
.SetBackward( bSearchBackwards
);
3309 xDescriptor
->setPropertyValue( u
"SearchBackwards"_ustr
, uno::Any( bSearchBackwards
) );
3314 bool bMatchCase
= false;
3315 if ( MatchCase
.hasValue() )
3317 // SearchCaseSensitive
3318 if( !( MatchCase
>>= bMatchCase
) )
3319 throw uno::RuntimeException(u
"Range::Find illegal value for MatchCase"_ustr
);
3321 xDescriptor
->setPropertyValue( SC_UNO_SRCHCASE
, uno::Any( bMatchCase
) );
3327 ScGlobal::SetSearchItem( newOptions
);
3329 uno::Reference
< uno::XInterface
> xInterface
= xStartCell
.is() ? xSearch
->findNext( xStartCell
, xDescriptor
) : xSearch
->findFirst( xDescriptor
);
3330 uno::Reference
< table::XCellRange
> xCellRange( xInterface
, uno::UNO_QUERY
);
3331 // if we are searching from a starting cell and failed to find a match
3332 // then try from the beginning
3333 if ( !xCellRange
.is() && xStartCell
.is() )
3335 xInterface
= xSearch
->findFirst( xDescriptor
);
3336 xCellRange
.set( xInterface
, uno::UNO_QUERY
);
3338 if ( xCellRange
.is() )
3340 uno::Reference
< excel::XRange
> xResultRange
= new ScVbaRange( mxParent
, mxContext
, xCellRange
);
3341 if( xResultRange
.is() )
3343 return xResultRange
;
3349 return uno::Reference
< excel::XRange
>();
3352 static uno::Reference
< table::XCellRange
> processKey( const uno::Any
& Key
, const uno::Reference
< uno::XComponentContext
>& xContext
, ScDocShell
* pDocSh
)
3354 uno::Reference
< excel::XRange
> xKeyRange
;
3355 if (Key
.getValueTypeClass() == css::uno::TypeClass_INTERFACE
)
3357 xKeyRange
.set( Key
, uno::UNO_QUERY_THROW
);
3359 else if ( Key
.getValueType() == ::cppu::UnoType
<OUString
>::get() )
3362 OUString sRangeName
= ::comphelper::getString( Key
);
3363 table::CellRangeAddress aRefAddr
;
3365 throw uno::RuntimeException(u
"Range::Sort no docshell to calculate key param"_ustr
);
3366 xKeyRange
= getRangeForName( xContext
, sRangeName
, pDocSh
, aRefAddr
);
3369 throw uno::RuntimeException(u
"Range::Sort illegal type value for key param"_ustr
);
3370 uno::Reference
< table::XCellRange
> xKey
;
3371 xKey
.set( xKeyRange
->getCellRange(), uno::UNO_QUERY_THROW
);
3375 // helper method for Sort
3376 /// @throws uno::RuntimeException
3377 static sal_Int32
findSortPropertyIndex( const uno::Sequence
< beans::PropertyValue
>& props
,
3378 const OUString
& sPropName
)
3380 const beans::PropertyValue
* pProp
= std::find_if(props
.begin(), props
.end(),
3381 [&sPropName
](const beans::PropertyValue
& rProp
) { return rProp
.Name
== sPropName
; });
3383 if ( pProp
== props
.end() )
3384 throw uno::RuntimeException(u
"Range::Sort unknown sort property"_ustr
);
3385 return static_cast<sal_Int32
>(std::distance(props
.begin(), pProp
));
3388 // helper method for Sort
3389 /// @throws uno::RuntimeException
3390 static void updateTableSortField( const uno::Reference
< table::XCellRange
>& xParentRange
,
3391 const uno::Reference
< table::XCellRange
>& xColRowKey
, sal_Int16 nOrder
,
3392 table::TableSortField
& aTableField
, bool bIsSortColumn
, bool bMatchCase
)
3394 RangeHelper
parentRange( xParentRange
);
3395 RangeHelper
colRowRange( xColRowKey
);
3397 table::CellRangeAddress parentRangeAddress
= parentRange
.getCellRangeAddressable()->getRangeAddress();
3399 table::CellRangeAddress colRowKeyAddress
= colRowRange
.getCellRangeAddressable()->getRangeAddress();
3401 // make sure that upper left point of key range is within the
3404 ( bIsSortColumn
|| colRowKeyAddress
.StartColumn
< parentRangeAddress
.StartColumn
||
3405 colRowKeyAddress
.StartColumn
> parentRangeAddress
.EndColumn
)
3407 ( !bIsSortColumn
|| colRowKeyAddress
.StartRow
< parentRangeAddress
.StartRow
||
3408 colRowKeyAddress
.StartRow
> parentRangeAddress
.EndRow
)
3410 throw uno::RuntimeException(u
"Illegal Key param"_ustr
);
3412 //determine col/row index
3413 if ( bIsSortColumn
)
3414 aTableField
.Field
= colRowKeyAddress
.StartRow
- parentRangeAddress
.StartRow
;
3416 aTableField
.Field
= colRowKeyAddress
.StartColumn
- parentRangeAddress
.StartColumn
;
3417 aTableField
.IsCaseSensitive
= bMatchCase
;
3419 if ( nOrder
== excel::XlSortOrder::xlAscending
)
3420 aTableField
.IsAscending
= true;
3422 aTableField
.IsAscending
= false;
3428 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
)
3430 // #TODO# #FIXME# can we do something with Type
3431 if ( m_Areas
->getCount() > 1 )
3432 throw uno::RuntimeException(u
"That command cannot be used on multiple selections"_ustr
);
3434 sal_Int16 nDataOption1
= excel::XlSortDataOption::xlSortNormal
;
3435 sal_Int16 nDataOption2
= excel::XlSortDataOption::xlSortNormal
;
3436 sal_Int16 nDataOption3
= excel::XlSortDataOption::xlSortNormal
;
3438 ScDocument
& rDoc
= getScDocument();
3440 uno::Reference
< table::XCellRange
> xRangeCurrent
;
3441 if (isSingleCellRange())
3443 // Expand to CurrentRegion
3444 uno::Reference
< excel::XRange
> xCurrent( CurrentRegion());
3447 const ScVbaRange
* pRange
= getImplementation( xCurrent
);
3449 xRangeCurrent
= pRange
->mxRange
;
3452 if (!xRangeCurrent
.is())
3453 xRangeCurrent
= mxRange
;
3454 RangeHelper
thisRange( xRangeCurrent
);
3455 table::CellRangeAddress thisRangeAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
3457 ScSortParam aSortParam
;
3458 SCTAB nTab
= thisRangeAddress
.Sheet
;
3459 rDoc
.GetSortParam( aSortParam
, nTab
);
3461 if ( DataOption1
.hasValue() )
3462 DataOption1
>>= nDataOption1
;
3463 if ( DataOption2
.hasValue() )
3464 DataOption2
>>= nDataOption2
;
3465 if ( DataOption3
.hasValue() )
3466 DataOption3
>>= nDataOption3
;
3468 // 1) #TODO #FIXME need to process DataOption[1..3] not used currently
3469 // 2) #TODO #FIXME need to refactor this ( below ) into an IsSingleCell() method
3470 uno::Reference
< table::XColumnRowRange
> xColumnRowRange(xRangeCurrent
, uno::UNO_QUERY_THROW
);
3474 sal_Int16 nOrder1
= aSortParam
.maKeyState
[0].bAscending
? excel::XlSortOrder::xlAscending
: excel::XlSortOrder::xlDescending
;
3475 sal_Int16 nOrder2
= aSortParam
.maKeyState
[1].bAscending
? excel::XlSortOrder::xlAscending
: excel::XlSortOrder::xlDescending
;
3476 sal_Int16 nOrder3
= aSortParam
.maKeyState
[2].bAscending
? excel::XlSortOrder::xlAscending
: excel::XlSortOrder::xlDescending
;
3478 sal_Int16 nCustom
= aSortParam
.nUserIndex
;
3479 sal_Int16 nSortMethod
= excel::XlSortMethod::xlPinYin
;
3480 bool bMatchCase
= aSortParam
.bCaseSens
;
3482 // seems to work opposite to expected, see below
3483 sal_Int16 nOrientation
= aSortParam
.bByRow
? excel::XlSortOrientation::xlSortColumns
: excel::XlSortOrientation::xlSortRows
;
3485 if ( Orientation
.hasValue() )
3487 // Documentation says xlSortRows is default but that doesn't appear to be
3488 // the case. Also it appears that xlSortColumns is the default which
3489 // strangely enough sorts by Row
3490 nOrientation
= ::comphelper::getINT16( Orientation
);
3491 // persist new option to be next calls default
3492 if ( nOrientation
== excel::XlSortOrientation::xlSortRows
)
3493 aSortParam
.bByRow
= false;
3495 aSortParam
.bByRow
= true;
3499 bool bIsSortColumns
=false; // sort by row
3501 if ( nOrientation
== excel::XlSortOrientation::xlSortRows
)
3502 bIsSortColumns
= true;
3503 sal_Int16 nHeader
= aSortParam
.nCompatHeader
;
3504 bool bContainsHeader
= false;
3506 if ( Header
.hasValue() )
3508 nHeader
= ::comphelper::getINT16( Header
);
3509 aSortParam
.nCompatHeader
= nHeader
;
3512 if ( nHeader
== excel::XlYesNoGuess::xlGuess
)
3514 bool bHasColHeader
= rDoc
.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
));
3515 bool bHasRowHeader
= rDoc
.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
) );
3516 if ( bHasColHeader
|| bHasRowHeader
)
3517 nHeader
= excel::XlYesNoGuess::xlYes
;
3519 nHeader
= excel::XlYesNoGuess::xlNo
;
3520 aSortParam
.nCompatHeader
= nHeader
;
3523 if ( nHeader
== excel::XlYesNoGuess::xlYes
)
3524 bContainsHeader
= true;
3526 if ( SortMethod
.hasValue() )
3528 nSortMethod
= ::comphelper::getINT16( SortMethod
);
3531 if ( OrderCustom
.hasValue() )
3533 OrderCustom
>>= nCustom
;
3534 --nCustom
; // 0-based in OOo
3535 aSortParam
.nUserIndex
= nCustom
;
3538 if ( MatchCase
.hasValue() )
3540 MatchCase
>>= bMatchCase
;
3541 aSortParam
.bCaseSens
= bMatchCase
;
3544 if ( Order1
.hasValue() )
3546 nOrder1
= ::comphelper::getINT16(Order1
);
3547 if ( nOrder1
== excel::XlSortOrder::xlAscending
)
3548 aSortParam
.maKeyState
[0].bAscending
= true;
3550 aSortParam
.maKeyState
[0].bAscending
= false;
3553 if ( Order2
.hasValue() )
3555 nOrder2
= ::comphelper::getINT16(Order2
);
3556 if ( nOrder2
== excel::XlSortOrder::xlAscending
)
3557 aSortParam
.maKeyState
[1].bAscending
= true;
3559 aSortParam
.maKeyState
[1].bAscending
= false;
3561 if ( Order3
.hasValue() )
3563 nOrder3
= ::comphelper::getINT16(Order3
);
3564 if ( nOrder3
== excel::XlSortOrder::xlAscending
)
3565 aSortParam
.maKeyState
[2].bAscending
= true;
3567 aSortParam
.maKeyState
[2].bAscending
= false;
3570 uno::Reference
< table::XCellRange
> xKey1
;
3571 uno::Reference
< table::XCellRange
> xKey2
;
3572 uno::Reference
< table::XCellRange
> xKey3
;
3573 ScDocShell
* pDocShell
= getScDocShell();
3574 xKey1
= processKey( Key1
, mxContext
, pDocShell
);
3576 throw uno::RuntimeException(u
"Range::Sort needs a key1 param"_ustr
);
3578 if ( Key2
.hasValue() )
3579 xKey2
= processKey( Key2
, mxContext
, pDocShell
);
3580 if ( Key3
.hasValue() )
3581 xKey3
= processKey( Key3
, mxContext
, pDocShell
);
3583 uno::Reference
< util::XSortable
> xSort( xRangeCurrent
, uno::UNO_QUERY_THROW
);
3584 uno::Sequence
< beans::PropertyValue
> sortDescriptor
= xSort
->createSortDescriptor();
3585 auto psortDescriptor
= sortDescriptor
.getArray();
3586 sal_Int32 nTableSortFieldIndex
= findSortPropertyIndex( sortDescriptor
, u
"SortFields"_ustr
);
3588 uno::Sequence
< table::TableSortField
> sTableFields(1);
3589 sal_Int32 nTableIndex
= 0;
3590 updateTableSortField( xRangeCurrent
, xKey1
, nOrder1
, sTableFields
.getArray()[ nTableIndex
++ ], bIsSortColumns
, bMatchCase
);
3594 sTableFields
.realloc( sTableFields
.getLength() + 1 );
3595 updateTableSortField( xRangeCurrent
, xKey2
, nOrder2
, sTableFields
.getArray()[ nTableIndex
++ ], bIsSortColumns
, bMatchCase
);
3599 sTableFields
.realloc( sTableFields
.getLength() + 1 );
3600 updateTableSortField( xRangeCurrent
, xKey3
, nOrder3
, sTableFields
.getArray()[ nTableIndex
++ ], bIsSortColumns
, bMatchCase
);
3602 psortDescriptor
[ nTableSortFieldIndex
].Value
<<= sTableFields
;
3604 sal_Int32 nIndex
= findSortPropertyIndex( sortDescriptor
, u
"IsSortColumns"_ustr
);
3605 psortDescriptor
[ nIndex
].Value
<<= bIsSortColumns
;
3607 nIndex
= findSortPropertyIndex( sortDescriptor
, u
"ContainsHeader"_ustr
);
3608 psortDescriptor
[ nIndex
].Value
<<= bContainsHeader
;
3610 rDoc
.SetSortParam( aSortParam
, nTab
);
3611 xSort
->sort( sortDescriptor
);
3614 // The SortMethod param is not processed ( not sure what its all about, need to
3618 uno::Reference
< excel::XRange
> SAL_CALL
3619 ScVbaRange::End( ::sal_Int32 Direction
)
3621 if ( m_Areas
->getCount() > 1 )
3623 uno::Reference
< excel::XRange
> xRange( getArea( 0 ), uno::UNO_SET_THROW
);
3624 return xRange
->End( Direction
);
3628 // euch! found my orig implementation sucked, so
3629 // trying this even sucker one (really need to use/expose code in
3630 // around ScTabView::MoveCursorArea(), that's the bit that calculates
3631 // where the cursor should go)
3632 // Main problem with this method is the ultra hacky attempt to preserve
3633 // the ActiveCell, there should be no need to go to these extremes
3635 // Save ActiveSheet/ActiveCell pos (to restore later)
3637 uno::Reference
< excel::XApplication
> xApplication( Application(), uno::UNO_QUERY_THROW
);
3638 uno::Reference
< excel::XWorksheet
> sActiveSheet
= xApplication
->getActiveSheet();
3639 OUString sActiveCell
= xApplication
->getActiveCell()->Address(aDft
, aDft
, aDft
, aDft
, aDft
);
3641 // position current cell upper left of this range
3642 Cells( uno::Any( sal_Int32(1) ), uno::Any( sal_Int32(1) ) )->Select();
3644 uno::Reference
< frame::XModel
> xModel
= getModelFromRange( mxRange
);
3646 SfxViewFrame
* pViewFrame
= excel::getViewFrame( xModel
);
3649 SfxAllItemSet
aArgs( SfxGetpApp()->GetPool() );
3650 // Hoping this will make sure this slot is called
3652 SfxBoolItem
sfxAsync( SID_ASYNCHRON
, false );
3653 aArgs
.Put( sfxAsync
);
3654 SfxDispatcher
* pDispatcher
= pViewFrame
->GetDispatcher();
3656 sal_uInt16 nSID
= 0;
3660 case excel::XlDirection::xlDown
:
3661 nSID
= SID_CURSORBLKDOWN
;
3663 case excel::XlDirection::xlUp
:
3664 nSID
= SID_CURSORBLKUP
;
3666 case excel::XlDirection::xlToLeft
:
3667 nSID
= SID_CURSORBLKLEFT
;
3669 case excel::XlDirection::xlToRight
:
3670 nSID
= SID_CURSORBLKRIGHT
;
3673 throw uno::RuntimeException(u
": Invalid ColumnIndex"_ustr
);
3677 pDispatcher
->Execute( nSID
, SfxCallMode::SYNCHRON
, aArgs
);
3681 // result is the ActiveCell
3682 OUString sMoved
= xApplication
->getActiveCell()->Address(aDft
, aDft
, aDft
, aDft
, aDft
);
3685 uno::Reference
< excel::XRange
> resultCell
;
3686 resultCell
.set( xApplication
->getActiveSheet()->Range( uno::Any( sMoved
), aVoid
), uno::UNO_SET_THROW
);
3688 // restore old ActiveCell
3689 uno::Reference
< excel::XRange
> xOldActiveCell( sActiveSheet
->Range( uno::Any( sActiveCell
), aVoid
), uno::UNO_SET_THROW
);
3690 xOldActiveCell
->Select();
3698 ScVbaRange::isSingleCellRange() const
3700 uno::Reference
< sheet::XCellRangeAddressable
> xAddressable( mxRange
, uno::UNO_QUERY
);
3701 if ( xAddressable
.is() )
3703 table::CellRangeAddress aRangeAddr
= xAddressable
->getRangeAddress();
3704 return ( aRangeAddr
.EndColumn
== aRangeAddr
.StartColumn
&& aRangeAddr
.EndRow
== aRangeAddr
.StartRow
);
3709 uno::Reference
< excel::XCharacters
> SAL_CALL
3710 ScVbaRange::characters( const uno::Any
& Start
, const uno::Any
& Length
)
3712 if ( !isSingleCellRange() )
3713 throw uno::RuntimeException(u
"Can't create Characters property for multicell range "_ustr
);
3714 uno::Reference
< text::XSimpleText
> xSimple(mxRange
->getCellByPosition(0,0) , uno::UNO_QUERY_THROW
);
3715 ScDocument
& rDoc
= getDocumentFromRange(mxRange
);
3717 ScVbaPalette
aPalette( rDoc
.GetDocumentShell() );
3718 return new ScVbaCharacters( this, mxContext
, aPalette
, xSimple
, Start
, Length
);
3722 ScVbaRange::Delete( const uno::Any
& Shift
)
3724 if ( m_Areas
->getCount() > 1 )
3726 sal_Int32 nItems
= m_Areas
->getCount();
3727 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
3729 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(index
), uno::Any() ), uno::UNO_QUERY_THROW
);
3730 xRange
->Delete( Shift
);
3734 sheet::CellDeleteMode mode
= sheet::CellDeleteMode_NONE
;
3735 RangeHelper
thisRange( mxRange
);
3736 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
3737 if ( Shift
.hasValue() )
3739 sal_Int32 nShift
= 0;
3743 case excel::XlDeleteShiftDirection::xlShiftUp
:
3744 mode
= sheet::CellDeleteMode_UP
;
3746 case excel::XlDeleteShiftDirection::xlShiftToLeft
:
3747 mode
= sheet::CellDeleteMode_LEFT
;
3750 throw uno::RuntimeException(u
"Illegal parameter "_ustr
);
3755 ScDocument
& rDoc
= getScDocument();
3756 bool bFullRow
= ( thisAddress
.StartColumn
== 0 && thisAddress
.EndColumn
== rDoc
.MaxCol() );
3757 sal_Int32 nCols
= thisAddress
.EndColumn
- thisAddress
.StartColumn
;
3758 sal_Int32 nRows
= thisAddress
.EndRow
- thisAddress
.StartRow
;
3759 if ( mbIsRows
|| bFullRow
|| ( nCols
>= nRows
) )
3760 mode
= sheet::CellDeleteMode_UP
;
3762 mode
= sheet::CellDeleteMode_LEFT
;
3764 uno::Reference
< sheet::XCellRangeMovement
> xCellRangeMove( thisRange
.getSpreadSheet(), uno::UNO_QUERY_THROW
);
3765 xCellRangeMove
->removeRange( thisAddress
, mode
);
3771 ScVbaRange::hasElements()
3773 uno::Reference
< table::XColumnRowRange
> xColumnRowRange(mxRange
, uno::UNO_QUERY
);
3774 if ( xColumnRowRange
.is() )
3775 if ( xColumnRowRange
->getRows()->getCount() ||
3776 xColumnRowRange
->getColumns()->getCount() )
3781 // XEnumerationAccess
3782 uno::Reference
< container::XEnumeration
> SAL_CALL
3783 ScVbaRange::createEnumeration()
3785 if ( mbIsColumns
|| mbIsRows
)
3787 uno::Reference
< table::XColumnRowRange
> xColumnRowRange(mxRange
, uno::UNO_QUERY
);
3788 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW
);
3789 sal_Int32 nElems
= 0;
3791 nElems
= xColumnRowRange
->getColumns()->getCount();
3793 nElems
= xColumnRowRange
->getRows()->getCount();
3794 return new ColumnsRowEnumeration( xRange
, nElems
);
3797 return new CellsEnumeration( mxParent
, mxContext
, m_Areas
);
3801 ScVbaRange::getDefaultMethodName( )
3803 return u
"Item"_ustr
;
3806 // returns calc internal col. width ( in points )
3808 ScVbaRange::getCalcColWidth(const table::CellRangeAddress
& rAddress
)
3810 ScDocument
& rDoc
= getScDocument();
3811 sal_uInt16 nWidth
= rDoc
.GetOriginalWidth( static_cast< SCCOL
>( rAddress
.StartColumn
), static_cast< SCTAB
>( rAddress
.Sheet
) );
3812 double nPoints
= lcl_TwipsToPoints( nWidth
);
3813 nPoints
= lcl_Round2DecPlaces( nPoints
);
3818 ScVbaRange::getCalcRowHeight(const table::CellRangeAddress
& rAddress
)
3820 ScDocument
& rDoc
= getDocumentFromRange( mxRange
);
3821 sal_uInt16 nWidth
= rDoc
.GetOriginalHeight( rAddress
.StartRow
, rAddress
.Sheet
);
3822 double nPoints
= lcl_TwipsToPoints( nWidth
);
3823 nPoints
= lcl_Round2DecPlaces( nPoints
);
3827 // return Char Width in points
3828 static double getDefaultCharWidth( ScDocShell
* pDocShell
)
3830 ScDocument
& rDoc
= pDocShell
->GetDocument();
3831 OutputDevice
* pRefDevice
= rDoc
.GetRefDevice();
3833 rDoc
.getCellAttributeHelper().getDefaultCellAttribute().fillFontOnly(aDefFont
, pRefDevice
);
3834 pRefDevice
->SetFont(aDefFont
);
3835 tools::Long nCharWidth
= pRefDevice
->GetTextWidth( OUString( '0' ) ); // 1/100th mm
3836 return o3tl::convert
<double>(nCharWidth
, o3tl::Length::mm100
, o3tl::Length::pt
);
3840 ScVbaRange::getColumnWidth()
3842 sal_Int32 nLen
= m_Areas
->getCount();
3845 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW
);
3846 return xRange
->getColumnWidth();
3849 double nColWidth
= 0;
3850 ScDocShell
* pShell
= getScDocShell();
3853 double defaultCharWidth
= getDefaultCharWidth( pShell
);
3854 RangeHelper
thisRange( mxRange
);
3855 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
3856 sal_Int32 nStartCol
= thisAddress
.StartColumn
;
3857 sal_Int32 nEndCol
= thisAddress
.EndColumn
;
3858 sal_uInt16 nColTwips
= 0;
3859 for( sal_Int32 nCol
= nStartCol
; nCol
<= nEndCol
; ++nCol
)
3861 thisAddress
.StartColumn
= nCol
;
3862 sal_uInt16 nCurTwips
= pShell
->GetDocument().GetOriginalWidth( static_cast< SCCOL
>( thisAddress
.StartColumn
), static_cast< SCTAB
>( thisAddress
.Sheet
) );
3863 if ( nCol
== nStartCol
)
3864 nColTwips
= nCurTwips
;
3865 if ( nColTwips
!= nCurTwips
)
3868 nColWidth
= lcl_TwipsToPoints( nColTwips
);
3869 if ( nColWidth
!= 0.0 )
3870 nColWidth
= ( nColWidth
/ defaultCharWidth
) - fExtraWidth
;
3872 nColWidth
= lcl_Round2DecPlaces( nColWidth
);
3873 return uno::Any( nColWidth
);
3877 ScVbaRange::setColumnWidth( const uno::Any
& _columnwidth
)
3879 sal_Int32 nLen
= m_Areas
->getCount();
3882 for ( sal_Int32 index
= 1; index
!= nLen
; ++index
)
3884 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( index
), uno::Any() ), uno::UNO_QUERY_THROW
);
3885 xRange
->setColumnWidth( _columnwidth
);
3889 double nColWidth
= 0;
3890 _columnwidth
>>= nColWidth
;
3891 nColWidth
= lcl_Round2DecPlaces( nColWidth
);
3892 ScDocShell
* pDocShell
= getScDocShell();
3896 if ( nColWidth
!= 0.0 )
3897 nColWidth
= ( nColWidth
+ fExtraWidth
) * getDefaultCharWidth( pDocShell
);
3898 RangeHelper
thisRange( mxRange
);
3899 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
3900 sal_uInt16 nTwips
= lcl_pointsToTwips( nColWidth
);
3902 std::vector
<sc::ColRowSpan
> aColArr(1, sc::ColRowSpan(thisAddress
.StartColumn
, thisAddress
.EndColumn
));
3903 // #163561# use mode SC_SIZE_DIRECT: hide for width 0, show for other values
3904 pDocShell
->GetDocFunc().SetWidthOrHeight(
3905 true, aColArr
, thisAddress
.Sheet
, SC_SIZE_DIRECT
, nTwips
, true, true);
3909 ScVbaRange::getWidth()
3911 if ( m_Areas
->getCount() > 1 )
3913 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW
);
3914 return xRange
->getWidth();
3916 uno::Reference
< table::XColumnRowRange
> xColRowRange( mxRange
, uno::UNO_QUERY_THROW
);
3917 uno::Reference
< container::XIndexAccess
> xIndexAccess( xColRowRange
->getColumns(), uno::UNO_QUERY_THROW
);
3918 sal_Int32 nElems
= xIndexAccess
->getCount();
3920 for ( sal_Int32 index
=0; index
<nElems
; ++index
)
3922 uno::Reference
< sheet::XCellRangeAddressable
> xAddressable( xIndexAccess
->getByIndex( index
), uno::UNO_QUERY_THROW
);
3923 double nTmpWidth
= getCalcColWidth( xAddressable
->getRangeAddress() );
3924 nWidth
+= nTmpWidth
;
3926 return uno::Any( nWidth
);
3930 ScVbaRange::Areas( const uno::Any
& item
)
3932 if ( !item
.hasValue() )
3933 return uno::Any( uno::Reference
< ov::XCollection
>(m_Areas
) );
3934 return m_Areas
->Item( item
, uno::Any() );
3937 uno::Reference
< excel::XRange
>
3938 ScVbaRange::getArea( sal_Int32 nIndex
)
3940 if ( !m_Areas
.is() )
3941 throw uno::RuntimeException(u
"No areas available"_ustr
);
3942 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( ++nIndex
), uno::Any() ), uno::UNO_QUERY_THROW
);
3947 ScVbaRange::Borders( const uno::Any
& item
)
3949 if ( !item
.hasValue() )
3950 return uno::Any( getBorders() );
3951 return getBorders()->Item( item
, uno::Any() );
3955 ScVbaRange::BorderAround( const css::uno::Any
& LineStyle
, const css::uno::Any
& Weight
,
3956 const css::uno::Any
& ColorIndex
, const css::uno::Any
& Color
)
3958 sal_Int32 nCount
= getBorders()->getCount();
3960 for( sal_Int32 i
= 0; i
< nCount
; i
++ )
3962 const sal_Int32 nLineType
= supportedIndexTable
[i
];
3965 case excel::XlBordersIndex::xlEdgeLeft
:
3966 case excel::XlBordersIndex::xlEdgeTop
:
3967 case excel::XlBordersIndex::xlEdgeBottom
:
3968 case excel::XlBordersIndex::xlEdgeRight
:
3970 uno::Reference
< excel::XBorder
> xBorder( m_Borders
->Item( uno::Any( nLineType
), uno::Any() ), uno::UNO_QUERY_THROW
);
3971 if( LineStyle
.hasValue() )
3973 xBorder
->setLineStyle( LineStyle
);
3975 if( Weight
.hasValue() )
3977 xBorder
->setWeight( Weight
);
3979 if( ColorIndex
.hasValue() )
3981 xBorder
->setColorIndex( ColorIndex
);
3983 if( Color
.hasValue() )
3985 xBorder
->setColor( Color
);
3989 case excel::XlBordersIndex::xlInsideVertical
:
3990 case excel::XlBordersIndex::xlInsideHorizontal
:
3991 case excel::XlBordersIndex::xlDiagonalDown
:
3992 case excel::XlBordersIndex::xlDiagonalUp
:
3995 return uno::Any( false );
3998 return uno::Any( true );
4002 ScVbaRange::getRowHeight()
4004 sal_Int32 nLen
= m_Areas
->getCount();
4007 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW
);
4008 return xRange
->getRowHeight();
4011 // if any row's RowHeight in the
4012 // range is different from any other, then return NULL
4013 RangeHelper
thisRange( mxRange
);
4014 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
4016 sal_Int32 nStartRow
= thisAddress
.StartRow
;
4017 sal_Int32 nEndRow
= thisAddress
.EndRow
;
4018 sal_uInt16 nRowTwips
= 0;
4019 // #TODO probably possible to use the SfxItemSet (and see if
4020 // SfxItemState::INVALID is set) to improve performance
4021 // #CHECKME looks like this is general behaviour not just row Range specific
4023 ScDocShell
* pShell
= getScDocShell();
4026 for ( sal_Int32 nRow
= nStartRow
; nRow
<= nEndRow
; ++nRow
)
4028 thisAddress
.StartRow
= nRow
;
4029 sal_uInt16 nCurTwips
= pShell
->GetDocument().GetOriginalHeight( thisAddress
.StartRow
, thisAddress
.Sheet
);
4030 if ( nRow
== nStartRow
)
4031 nRowTwips
= nCurTwips
;
4032 if ( nRowTwips
!= nCurTwips
)
4036 double nHeight
= lcl_Round2DecPlaces( lcl_TwipsToPoints( nRowTwips
) );
4037 return uno::Any( nHeight
);
4041 ScVbaRange::setRowHeight( const uno::Any
& _rowheight
)
4043 sal_Int32 nLen
= m_Areas
->getCount();
4046 for ( sal_Int32 index
= 1; index
!= nLen
; ++index
)
4048 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( index
), uno::Any() ), uno::UNO_QUERY_THROW
);
4049 xRange
->setRowHeight( _rowheight
);
4053 double nHeight
= 0; // Incoming height is in points
4054 _rowheight
>>= nHeight
;
4055 nHeight
= lcl_Round2DecPlaces( nHeight
);
4056 RangeHelper
thisRange( mxRange
);
4057 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
4058 sal_uInt16 nTwips
= lcl_pointsToTwips( nHeight
);
4060 ScDocShell
* pDocShell
= getDocShellFromRange( mxRange
);
4061 std::vector
<sc::ColRowSpan
> aRowArr(1, sc::ColRowSpan(thisAddress
.StartRow
, thisAddress
.EndRow
));
4062 pDocShell
->GetDocFunc().SetWidthOrHeight(
4063 false, aRowArr
, thisAddress
.Sheet
, SC_SIZE_ORIGINAL
, nTwips
, true, true);
4067 ScVbaRange::getPageBreak()
4069 sal_Int32 nPageBreak
= excel::XlPageBreak::xlPageBreakNone
;
4070 ScDocShell
* pShell
= getDocShellFromRange( mxRange
);
4073 RangeHelper
thisRange( mxRange
);
4074 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
4075 bool bColumn
= false;
4077 if (thisAddress
.StartRow
==0)
4080 uno::Reference
< frame::XModel
> xModel
= pShell
->GetModel();
4083 ScDocument
& rDoc
= getDocumentFromRange( mxRange
);
4085 ScBreakType nBreak
= ScBreakType::NONE
;
4087 nBreak
= rDoc
.HasRowBreak(thisAddress
.StartRow
, thisAddress
.Sheet
);
4089 nBreak
= rDoc
.HasColBreak(thisAddress
.StartColumn
, thisAddress
.Sheet
);
4091 if (nBreak
& ScBreakType::Page
)
4092 nPageBreak
= excel::XlPageBreak::xlPageBreakAutomatic
;
4094 if (nBreak
& ScBreakType::Manual
)
4095 nPageBreak
= excel::XlPageBreak::xlPageBreakManual
;
4099 return uno::Any( nPageBreak
);
4103 ScVbaRange::setPageBreak( const uno::Any
& _pagebreak
)
4105 sal_Int32 nPageBreak
= 0;
4106 _pagebreak
>>= nPageBreak
;
4108 ScDocShell
* pShell
= getDocShellFromRange( mxRange
);
4112 RangeHelper
thisRange( mxRange
);
4113 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
4114 if ((thisAddress
.StartColumn
==0) && (thisAddress
.StartRow
==0))
4116 bool bColumn
= false;
4118 if (thisAddress
.StartRow
==0)
4121 ScAddress
aAddr( static_cast<SCCOL
>(thisAddress
.StartColumn
), thisAddress
.StartRow
, thisAddress
.Sheet
);
4122 uno::Reference
< frame::XModel
> xModel
= pShell
->GetModel();
4125 ScTabViewShell
* pViewShell
= excel::getBestViewShell( xModel
);
4126 if ( nPageBreak
== excel::XlPageBreak::xlPageBreakManual
)
4127 pViewShell
->InsertPageBreak( bColumn
, true, &aAddr
);
4128 else if ( nPageBreak
== excel::XlPageBreak::xlPageBreakNone
)
4129 pViewShell
->DeletePageBreak( bColumn
, true, &aAddr
);
4134 ScVbaRange::getHeight()
4136 if ( m_Areas
->getCount() > 1 )
4138 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW
);
4139 return xRange
->getHeight();
4142 uno::Reference
< table::XColumnRowRange
> xColRowRange( mxRange
, uno::UNO_QUERY_THROW
);
4143 uno::Reference
< container::XIndexAccess
> xIndexAccess( xColRowRange
->getRows(), uno::UNO_QUERY_THROW
);
4144 sal_Int32 nElems
= xIndexAccess
->getCount();
4146 for ( sal_Int32 index
=0; index
<nElems
; ++index
)
4148 uno::Reference
< sheet::XCellRangeAddressable
> xAddressable( xIndexAccess
->getByIndex( index
), uno::UNO_QUERY_THROW
);
4149 nHeight
+= getCalcRowHeight(xAddressable
->getRangeAddress() );
4151 return uno::Any( nHeight
);
4155 ScVbaRange::getPosition() const
4158 uno::Reference
< beans::XPropertySet
> xProps
;
4160 xProps
.set( mxRange
, uno::UNO_QUERY_THROW
);
4162 xProps
.set( mxRanges
, uno::UNO_QUERY_THROW
);
4163 xProps
->getPropertyValue( u
"Position"_ustr
) >>= aPoint
;
4167 ScVbaRange::getLeft()
4169 // helperapi returns the first ranges left ( and top below )
4170 if ( m_Areas
->getCount() > 1 )
4171 return getArea( 0 )->getLeft();
4172 awt::Point aPoint
= getPosition();
4173 return uno::Any(o3tl::convert
<double>(aPoint
.X
, o3tl::Length::mm100
, o3tl::Length::pt
));
4177 ScVbaRange::getTop()
4179 // helperapi returns the first ranges top
4180 if ( m_Areas
->getCount() > 1 )
4181 return getArea( 0 )->getTop();
4182 awt::Point aPoint
= getPosition();
4183 return uno::Any(o3tl::convert
<double>(aPoint
.Y
, o3tl::Length::mm100
, o3tl::Length::pt
));
4186 static uno::Reference
< sheet::XCellRangeReferrer
> getNamedRange( const uno::Reference
< uno::XInterface
>& xIf
, const uno::Reference
< table::XCellRange
>& thisRange
)
4188 uno::Reference
< beans::XPropertySet
> xProps( xIf
, uno::UNO_QUERY_THROW
);
4189 uno::Reference
< container::XNameAccess
> xNameAccess( xProps
->getPropertyValue( u
"NamedRanges"_ustr
), uno::UNO_QUERY_THROW
);
4191 const uno::Sequence
< OUString
> sNames
= xNameAccess
->getElementNames();
4192 // uno::Reference< table::XCellRange > thisRange( getCellRange(), uno::UNO_QUERY_THROW );
4193 uno::Reference
< sheet::XCellRangeReferrer
> xNamedRange
;
4194 for ( const auto& rName
: sNames
)
4196 uno::Reference
< sheet::XCellRangeReferrer
> xName( xNameAccess
->getByName( rName
), uno::UNO_QUERY
);
4199 if ( thisRange
== xName
->getReferredCells() )
4201 xNamedRange
= std::move(xName
);
4209 uno::Reference
< excel::XName
>
4210 ScVbaRange::getName()
4212 uno::Reference
< beans::XPropertySet
> xProps( getUnoModel(), uno::UNO_QUERY
);
4213 uno::Reference
< table::XCellRange
> thisRange( getCellRange(), uno::UNO_QUERY_THROW
);
4214 // Application range
4215 uno::Reference
< sheet::XCellRangeReferrer
> xNamedRange
= getNamedRange( xProps
, thisRange
);
4217 if ( !xNamedRange
.is() )
4219 // not in application range then assume it might be in
4220 // sheet namedranges
4221 RangeHelper
aRange( thisRange
);
4222 uno::Reference
< sheet::XSpreadsheet
> xSheet
= aRange
.getSpreadSheet();
4223 xProps
.set( xSheet
, uno::UNO_QUERY
);
4225 xNamedRange
= getNamedRange( xProps
, thisRange
);
4227 if ( xProps
.is() && xNamedRange
.is() )
4229 uno::Reference
< sheet::XNamedRanges
> xNamedRanges( xProps
, uno::UNO_QUERY_THROW
);
4230 uno::Reference
< sheet::XNamedRange
> xName( xNamedRange
, uno::UNO_QUERY_THROW
);
4231 return new ScVbaName( mxParent
, mxContext
, xName
, xNamedRanges
, getUnoModel() );
4233 return uno::Reference
< excel::XName
>();
4236 uno::Reference
< excel::XWorksheet
>
4237 ScVbaRange::getWorksheet()
4239 // #TODO #FIXME parent should always be set up ( currently that's not
4241 uno::Reference
< excel::XWorksheet
> xSheet( getParent(), uno::UNO_QUERY
);
4244 uno::Reference
< table::XCellRange
> xRange
= mxRange
;
4246 if ( mxRanges
.is() ) // assign xRange to first range
4248 uno::Reference
< container::XIndexAccess
> xIndex( mxRanges
, uno::UNO_QUERY_THROW
);
4249 xRange
.set( xIndex
->getByIndex( 0 ), uno::UNO_QUERY_THROW
);
4251 ScDocShell
* pDocShell
= getDocShellFromRange(xRange
);
4252 RangeHelper
rHelper(xRange
);
4253 // parent should be Thisworkbook
4254 xSheet
.set( new ScVbaWorksheet( uno::Reference
< XHelperInterface
>(), mxContext
,rHelper
.getSpreadSheet(),pDocShell
->GetModel()) );
4259 // #TODO remove this ugly application processing
4260 // Process an application Range request e.g. 'Range("a1,b2,a4:b6")
4261 uno::Reference
< excel::XRange
>
4262 ScVbaRange::ApplicationRange( const uno::Reference
< uno::XComponentContext
>& xContext
, const css::uno::Any
&Cell1
, const css::uno::Any
&Cell2
)
4264 // Although the documentation seems clear that Range without a
4265 // qualifier then it's a shortcut for ActiveSheet.Range
4266 // however, similarly Application.Range is apparently also a
4267 // shortcut for ActiveSheet.Range
4268 // The is however a subtle behavioural difference I've come across
4269 // wrt to named ranges.
4270 // If a named range "test" exists { Sheet1!$A1 } and the active sheet
4271 // is Sheet2 then the following will fail
4272 // msgbox ActiveSheet.Range("test").Address ' fails
4273 // msgbox WorkSheets("Sheet2").Range("test").Address
4275 // msgbox Range("test").Address ' works
4276 // msgbox Application.Range("test").Address ' works
4278 // Single param Range
4279 OUString sRangeName
;
4280 Cell1
>>= sRangeName
;
4281 if ( Cell1
.hasValue() && !Cell2
.hasValue() && !sRangeName
.isEmpty() )
4283 uno::Reference
< beans::XPropertySet
> xPropSet( getCurrentExcelDoc(xContext
), uno::UNO_QUERY_THROW
);
4285 uno::Reference
< container::XNameAccess
> xNamed( xPropSet
->getPropertyValue( u
"NamedRanges"_ustr
), uno::UNO_QUERY_THROW
);
4286 uno::Reference
< sheet::XCellRangeReferrer
> xReferrer
;
4289 xReferrer
.set ( xNamed
->getByName( sRangeName
), uno::UNO_QUERY
);
4291 catch( uno::Exception
& /*e*/ )
4295 if ( xReferrer
.is() )
4297 uno::Reference
< table::XCellRange
> xRange
= xReferrer
->getReferredCells();
4300 uno::Reference
< excel::XRange
> xVbRange
= new ScVbaRange( excel::getUnoSheetModuleObj( xRange
), xContext
, xRange
);
4306 uno::Reference
<table::XCellRange
> xSheetRange
;
4310 uno::Reference
<sheet::XSpreadsheetView
> xView(
4311 getCurrentExcelDoc(xContext
)->getCurrentController(), uno::UNO_QUERY_THROW
);
4313 xSheetRange
.set(xView
->getActiveSheet(), uno::UNO_QUERY_THROW
);
4315 catch (const uno::Exception
&)
4317 return uno::Reference
<excel::XRange
>();
4320 rtl::Reference
<ScVbaRange
> pRange
= new ScVbaRange( excel::getUnoSheetModuleObj( xSheetRange
), xContext
, xSheetRange
);
4321 return pRange
->Range( Cell1
, Cell2
, true );
4324 // Helper functions for AutoFilter
4325 static ScDBData
* lcl_GetDBData_Impl( ScDocShell
* pDocShell
, sal_Int16 nSheet
)
4327 ScDBData
* pRet
= nullptr;
4330 pRet
= pDocShell
->GetDocument().GetAnonymousDBData(nSheet
);
4335 static void lcl_SelectAll( ScDocShell
* pDocShell
, const ScQueryParam
& aParam
)
4340 ScViewData
* pViewData
= ScDocShell::GetViewData();
4343 ScTabViewShell
* pViewSh
= pDocShell
->GetBestViewShell( true );
4344 pViewData
= pViewSh
? &pViewSh
->GetViewData() : nullptr;
4349 pViewData
->GetView()->Query( aParam
, nullptr, true );
4353 static ScQueryParam
lcl_GetQueryParam( ScDocShell
* pDocShell
, sal_Int16 nSheet
)
4355 ScDBData
* pDBData
= lcl_GetDBData_Impl( pDocShell
, nSheet
);
4356 ScQueryParam aParam
;
4359 pDBData
->GetQueryParam( aParam
);
4364 static void lcl_SetAllQueryForField( ScDocShell
* pDocShell
, SCCOLROW nField
, sal_Int16 nSheet
)
4366 ScQueryParam aParam
= lcl_GetQueryParam( pDocShell
, nSheet
);
4367 aParam
.RemoveEntryByField(nField
);
4368 lcl_SelectAll( pDocShell
, aParam
);
4371 // Modifies sCriteria, and nOp depending on the value of sCriteria
4372 static void lcl_setTableFieldsFromCriteria( OUString
& sCriteria1
, const uno::Reference
< beans::XPropertySet
>& xDescProps
, sheet::TableFilterField2
& rFilterField
)
4374 // #TODO make this more efficient and cycle through
4375 // sCriteria1 character by character to pick up <,<>,=, * etc.
4376 // right now I am more concerned with just getting it to work right
4378 sCriteria1
= sCriteria1
.trim();
4379 // table of translation of criteria text to FilterOperators
4380 // <>searchtext - NOT_EQUAL
4381 // =searchtext - EQUAL
4382 // *searchtext - startwith
4383 // <>*searchtext - doesn't startwith
4384 // *searchtext* - contains
4385 // <>*searchtext* - doesn't contain
4386 // [>|>=|<=|...]searchtext for GREATER_value, GREATER_EQUAL_value etc.
4387 if ( sCriteria1
.startsWith( EQUALS
) )
4389 if ( o3tl::make_unsigned(sCriteria1
.getLength()) == strlen(EQUALS
) )
4390 rFilterField
.Operator
= sheet::FilterOperator2::EMPTY
;
4393 rFilterField
.Operator
= sheet::FilterOperator2::EQUAL
;
4394 sCriteria1
= sCriteria1
.copy( strlen(EQUALS
) );
4395 sCriteria1
= VBAToRegexp( sCriteria1
);
4396 // UseRegularExpressions
4397 if ( xDescProps
.is() )
4398 xDescProps
->setPropertyValue( u
"UseRegularExpressions"_ustr
, uno::Any( true ) );
4402 else if ( sCriteria1
.startsWith( NOTEQUALS
) )
4404 if ( o3tl::make_unsigned(sCriteria1
.getLength()) == strlen(NOTEQUALS
) )
4405 rFilterField
.Operator
= sheet::FilterOperator2::NOT_EMPTY
;
4408 rFilterField
.Operator
= sheet::FilterOperator2::NOT_EQUAL
;
4409 sCriteria1
= sCriteria1
.copy( strlen(NOTEQUALS
) );
4410 sCriteria1
= VBAToRegexp( sCriteria1
);
4411 // UseRegularExpressions
4412 if ( xDescProps
.is() )
4413 xDescProps
->setPropertyValue( u
"UseRegularExpressions"_ustr
, uno::Any( true ) );
4416 else if ( sCriteria1
.startsWith( GREATERTHAN
) )
4418 if ( sCriteria1
.startsWith( GREATERTHANEQUALS
) )
4420 sCriteria1
= sCriteria1
.copy( strlen(GREATERTHANEQUALS
) );
4421 rFilterField
.Operator
= sheet::FilterOperator2::GREATER_EQUAL
;
4425 sCriteria1
= sCriteria1
.copy( strlen(GREATERTHAN
) );
4426 rFilterField
.Operator
= sheet::FilterOperator2::GREATER
;
4430 else if ( sCriteria1
.startsWith( LESSTHAN
) )
4432 if ( sCriteria1
.startsWith( LESSTHANEQUALS
) )
4434 sCriteria1
= sCriteria1
.copy( strlen(LESSTHANEQUALS
) );
4435 rFilterField
.Operator
= sheet::FilterOperator2::LESS_EQUAL
;
4439 sCriteria1
= sCriteria1
.copy( strlen(LESSTHAN
) );
4440 rFilterField
.Operator
= sheet::FilterOperator2::LESS
;
4445 rFilterField
.Operator
= sheet::FilterOperator2::EQUAL
;
4447 // tdf#107885 - check if criteria is numeric using locale dependent settings without group separator
4448 // or, if the decimal separator is different from the English locale, without any locale.
4449 sal_Int32 nParseEnd
= 0;
4450 rtl_math_ConversionStatus eStatus
= rtl_math_ConversionStatus_Ok
;
4451 double fValue
= ScGlobal::getLocaleData().stringToDouble( sCriteria1
, false, &eStatus
, &nParseEnd
);
4452 if ( nParseEnd
== sCriteria1
.getLength() && eStatus
== rtl_math_ConversionStatus_Ok
)
4454 rFilterField
.IsNumeric
= true;
4455 rFilterField
.NumericValue
= fValue
;
4457 else if ( ScGlobal::getLocaleData().getNumDecimalSep().toChar() != '.' )
4459 eStatus
= rtl_math_ConversionStatus_Ok
;
4460 fValue
= ::rtl::math::stringToDouble( sCriteria1
, '.', 0, &eStatus
, &nParseEnd
);
4461 if ( nParseEnd
== sCriteria1
.getLength() && eStatus
== rtl_math_ConversionStatus_Ok
)
4463 rFilterField
.IsNumeric
= true;
4464 rFilterField
.NumericValue
= fValue
;
4468 rFilterField
.StringValue
= sCriteria1
;
4472 ScVbaRange::AutoFilter( const uno::Any
& aField
, const uno::Any
& Criteria1
, const uno::Any
& Operator
, const uno::Any
& Criteria2
, const uno::Any
& /*VisibleDropDown*/ )
4474 // Is there an existing autofilter
4475 RangeHelper
thisRange( mxRange
);
4476 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
4477 sal_Int16 nSheet
= thisAddress
.Sheet
;
4478 ScDocShell
* pShell
= getScDocShell();
4479 bool bHasAuto
= false;
4480 uno::Reference
< sheet::XDatabaseRange
> xDataBaseRange
= excel::GetAutoFiltRange( pShell
, nSheet
);
4481 if ( xDataBaseRange
.is() )
4486 if ( m_Areas
->getCount() > 1 )
4487 throw uno::RuntimeException( STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY
);
4489 table::CellRangeAddress autoFiltAddress
;
4491 if ( isSingleCellRange() )
4493 uno::Reference
< excel::XRange
> xCurrent( CurrentRegion() );
4494 if ( xCurrent
.is() )
4496 ScVbaRange
* pRange
= getImplementation( xCurrent
);
4499 if ( pRange
->isSingleCellRange() )
4500 throw uno::RuntimeException(u
"Can't create AutoFilter"_ustr
);
4501 RangeHelper
currentRegion( pRange
->mxRange
);
4502 autoFiltAddress
= currentRegion
.getCellRangeAddressable()->getRangeAddress();
4506 else // multi-cell range
4508 RangeHelper
multiCellRange( mxRange
);
4509 autoFiltAddress
= multiCellRange
.getCellRangeAddressable()->getRangeAddress();
4510 // #163530# Filter box shows only entry of first row
4511 ScDocument
* pDocument
= ( pShell
? &pShell
->GetDocument() : nullptr );
4514 SCCOL nStartCol
= autoFiltAddress
.StartColumn
;
4515 SCROW nStartRow
= autoFiltAddress
.StartRow
;
4516 SCCOL nEndCol
= autoFiltAddress
.EndColumn
;
4517 SCROW nEndRow
= autoFiltAddress
.EndRow
;
4518 pDocument
->GetDataArea( autoFiltAddress
.Sheet
, nStartCol
, nStartRow
, nEndCol
, nEndRow
, true, true );
4519 autoFiltAddress
.StartColumn
= nStartCol
;
4520 autoFiltAddress
.StartRow
= nStartRow
;
4521 autoFiltAddress
.EndColumn
= nEndCol
;
4522 autoFiltAddress
.EndRow
= nEndRow
;
4526 uno::Reference
< sheet::XUnnamedDatabaseRanges
> xDBRanges
= excel::GetUnnamedDataBaseRanges( pShell
);
4527 if ( xDBRanges
.is() )
4529 if ( !xDBRanges
->hasByTable( nSheet
) )
4530 xDBRanges
->setByTable( autoFiltAddress
);
4531 xDataBaseRange
.set( xDBRanges
->getByTable(nSheet
), uno::UNO_QUERY_THROW
);
4533 if ( !xDataBaseRange
.is() )
4534 throw uno::RuntimeException(u
"Failed to find the autofilter placeholder range"_ustr
);
4536 uno::Reference
< beans::XPropertySet
> xDBRangeProps( xDataBaseRange
, uno::UNO_QUERY_THROW
);
4538 xDBRangeProps
->setPropertyValue( u
"AutoFilter"_ustr
, uno::Any(true) );
4539 // set header (autofilter always need column headers)
4540 uno::Reference
< beans::XPropertySet
> xFiltProps( xDataBaseRange
->getFilterDescriptor(), uno::UNO_QUERY_THROW
);
4541 xFiltProps
->setPropertyValue( u
"ContainsHeader"_ustr
, uno::Any( true ) );
4544 sal_Int32 nField
= 0; // *IS* 1 based
4545 sal_Int32 nOperator
= excel::XlAutoFilterOperator::xlAnd
;
4547 sheet::FilterConnection nConn
= sheet::FilterConnection_AND
;
4548 double nCriteria1
= 0;
4550 bool bHasCritValue
= Criteria1
.hasValue();
4551 bool bCritHasNumericValue
= false; // not sure if a numeric criteria is possible
4552 if ( bHasCritValue
)
4553 bCritHasNumericValue
= ( Criteria1
>>= nCriteria1
);
4555 if ( !aField
.hasValue() && ( Criteria1
.hasValue() || Operator
.hasValue() || Criteria2
.hasValue() ) )
4556 throw uno::RuntimeException();
4557 uno::Any
Field( aField
);
4558 if ( !( Field
>>= nField
) )
4560 const uno::Reference
< script::XTypeConverter
>& xConverter
= getTypeConverter( mxContext
);
4563 Field
= xConverter
->convertTo( aField
, cppu::UnoType
<sal_Int32
>::get() );
4565 catch( uno::Exception
& )
4569 // Use the normal uno api, sometimes e.g. when you want to use ALL as the filter
4570 // we can't use refresh as the uno interface doesn't have a concept of ALL
4571 // in this case we just call the core calc functionality -
4572 if ( Field
>>= nField
)
4574 uno::Reference
< sheet::XSheetFilterDescriptor2
> xDesc(
4575 xDataBaseRange
->getFilterDescriptor(), uno::UNO_QUERY
);
4578 OUString sCriteria1
;
4579 bool bAcceptCriteria2
= true;
4581 uno::Sequence
< sheet::TableFilterField2
> sTabFilts
;
4582 sheet::TableFilterField2
* pTabFilts
= nullptr;
4583 uno::Reference
< beans::XPropertySet
> xDescProps( xDesc
, uno::UNO_QUERY_THROW
);
4584 if ( Criteria1
.hasValue() )
4586 sTabFilts
.realloc( 1 );
4587 pTabFilts
= sTabFilts
.getArray();
4588 pTabFilts
[0].Operator
= sheet::FilterOperator2::EQUAL
;// sensible default
4589 if ( !bCritHasNumericValue
)
4591 Criteria1
>>= sCriteria1
;
4592 if ( sCriteria1
.isEmpty() )
4594 uno::Sequence
< OUString
> aCriteria1
;
4595 Criteria1
>>= aCriteria1
;
4596 sal_uInt16 nLength
= aCriteria1
.getLength();
4599 // When sequence is provided for Criteria1 don't care about Criteria2
4600 bAcceptCriteria2
= false;
4602 auto pCriteria1
= aCriteria1
.getArray();
4603 sTabFilts
.realloc( nLength
);
4604 pTabFilts
= sTabFilts
.getArray();
4605 for ( sal_uInt16 i
= 0; i
< nLength
; ++i
)
4607 lcl_setTableFieldsFromCriteria( pCriteria1
[i
], xDescProps
, pTabFilts
[i
] );
4608 pTabFilts
[i
].Connection
= sheet::FilterConnection_OR
;
4609 pTabFilts
[i
].Field
= (nField
- 1);
4617 pTabFilts
[0].IsNumeric
= bCritHasNumericValue
;
4618 if ( bHasCritValue
&& !sCriteria1
.isEmpty() )
4619 lcl_setTableFieldsFromCriteria( sCriteria1
, xDescProps
, pTabFilts
[0] );
4626 pTabFilts
[0].IsNumeric
= true;
4627 pTabFilts
[0].NumericValue
= nCriteria1
;
4630 else // no value specified
4632 // not sure what the relationship between Criteria1 and Operator is,
4633 // e.g. can you have an Operator without a Criteria? In LibreOffice it
4634 if ( Operator
.hasValue() && ( Operator
>>= nOperator
) )
4637 // if it's a bottom/top Ten(Percent/Value) and there
4638 // is no value specified for criteria1 set it to 10
4639 if ( !bCritHasNumericValue
&& sCriteria1
.isEmpty() && ( nOperator
!= excel::XlAutoFilterOperator::xlOr
) && ( nOperator
!= excel::XlAutoFilterOperator::xlAnd
) )
4641 pTabFilts
[0].IsNumeric
= true;
4642 pTabFilts
[0].NumericValue
= 10;
4645 switch ( nOperator
)
4647 case excel::XlAutoFilterOperator::xlBottom10Items
:
4648 pTabFilts
[0].Operator
= sheet::FilterOperator2::BOTTOM_VALUES
;
4650 case excel::XlAutoFilterOperator::xlBottom10Percent
:
4651 pTabFilts
[0].Operator
= sheet::FilterOperator2::BOTTOM_PERCENT
;
4653 case excel::XlAutoFilterOperator::xlTop10Items
:
4654 pTabFilts
[0].Operator
= sheet::FilterOperator2::TOP_VALUES
;
4656 case excel::XlAutoFilterOperator::xlTop10Percent
:
4657 pTabFilts
[0].Operator
= sheet::FilterOperator2::TOP_PERCENT
;
4659 case excel::XlAutoFilterOperator::xlOr
:
4660 nConn
= sheet::FilterConnection_OR
;
4662 case excel::XlAutoFilterOperator::xlAnd
:
4663 nConn
= sheet::FilterConnection_AND
;
4666 throw uno::RuntimeException(u
"UnknownOption"_ustr
);
4671 if ( !bAll
&& bAcceptCriteria2
)
4674 pTabFilts
[0].Connection
= sheet::FilterConnection_AND
;
4675 pTabFilts
[0].Field
= (nField
- 1);
4677 uno::Sequence
< OUString
> aCriteria2
;
4678 if ( Criteria2
.hasValue() ) // there is a Criteria2
4680 sTabFilts
.realloc(2);
4681 pTabFilts
= sTabFilts
.getArray();
4682 pTabFilts
[1].Field
= sTabFilts
[0].Field
;
4683 pTabFilts
[1].Connection
= nConn
;
4685 OUString sCriteria2
;
4686 if ( Criteria2
>>= sCriteria2
)
4688 if ( !sCriteria2
.isEmpty() )
4690 uno::Reference
< beans::XPropertySet
> xProps
;
4691 lcl_setTableFieldsFromCriteria( sCriteria2
, xProps
, pTabFilts
[1] );
4692 pTabFilts
[1].IsNumeric
= false;
4695 else if ( Criteria2
>>= aCriteria2
)
4697 sal_uInt16 nLength
= aCriteria2
.getLength();
4700 // For compatibility use only the last value from the sequence
4701 lcl_setTableFieldsFromCriteria( aCriteria2
.getArray()[nLength
- 1], xDescProps
, pTabFilts
[1] );
4706 Criteria2
>>= pTabFilts
[1].NumericValue
;
4707 pTabFilts
[1].IsNumeric
= true;
4708 pTabFilts
[1].Operator
= sheet::FilterOperator2::EQUAL
;
4713 xDesc
->setFilterFields2( sTabFilts
);
4716 xDataBaseRange
->refresh();
4719 // was 0 based now seems to be 1
4720 lcl_SetAllQueryForField( pShell
, nField
, nSheet
);
4725 // this is just to toggle autofilter on and off ( not to be confused with
4726 // a VisibleDropDown option combined with a field, in that case just the
4727 // button should be disabled ) - currently we don't support that
4728 uno::Reference
< beans::XPropertySet
> xDBRangeProps( xDataBaseRange
, uno::UNO_QUERY_THROW
);
4731 // find the any field with the query and select all
4732 ScQueryParam aParam
= lcl_GetQueryParam( pShell
, nSheet
);
4733 for (SCSIZE i
= 0; i
< aParam
.GetEntryCount(); ++i
)
4735 ScQueryEntry
& rEntry
= aParam
.GetEntry(i
);
4736 if ( rEntry
.bDoQuery
)
4737 lcl_SetAllQueryForField( pShell
, rEntry
.nField
, nSheet
);
4739 // remove existing filters
4740 uno::Reference
< sheet::XSheetFilterDescriptor2
> xSheetFilterDescriptor(
4741 xDataBaseRange
->getFilterDescriptor(), uno::UNO_QUERY
);
4742 if( xSheetFilterDescriptor
.is() )
4743 xSheetFilterDescriptor
->setFilterFields2( uno::Sequence
< sheet::TableFilterField2
>() );
4745 xDBRangeProps
->setPropertyValue( u
"AutoFilter"_ustr
, uno::Any(!bHasAuto
) );
4751 ScVbaRange::Insert( const uno::Any
& Shift
, const uno::Any
& /*CopyOrigin*/ )
4753 // It appears (from the web) that the undocumented CopyOrigin
4754 // param should contain member of enum XlInsertFormatOrigin
4755 // which can have values xlFormatFromLeftOrAbove or xlFormatFromRightOrBelow
4756 // #TODO investigate resultant behaviour using these constants
4757 // currently just processing Shift
4759 sheet::CellInsertMode mode
= sheet::CellInsertMode_NONE
;
4760 if ( Shift
.hasValue() )
4762 sal_Int32 nShift
= 0;
4766 case excel::XlInsertShiftDirection::xlShiftToRight
:
4767 mode
= sheet::CellInsertMode_RIGHT
;
4769 case excel::XlInsertShiftDirection::xlShiftDown
:
4770 mode
= sheet::CellInsertMode_DOWN
;
4773 throw uno::RuntimeException(u
"Illegal parameter "_ustr
);
4778 if ( getRow() >= getColumn() )
4779 mode
= sheet::CellInsertMode_DOWN
;
4781 mode
= sheet::CellInsertMode_RIGHT
;
4783 RangeHelper
thisRange( mxRange
);
4784 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
4785 uno::Reference
< sheet::XCellRangeMovement
> xCellRangeMove( thisRange
.getSpreadSheet(), uno::UNO_QUERY_THROW
);
4786 xCellRangeMove
->insertCells( thisAddress
, mode
);
4788 // Paste from clipboard only if the clipboard content was copied via VBA, and not already pasted via VBA again.
4789 // "Insert" behavior should not depend on random clipboard content previously copied by the user.
4790 ScDocShell
* pDocShell
= getDocShellFromRange( mxRange
);
4791 const ScTransferObj
* pClipObj
= pDocShell
? ScTransferObj::GetOwnClipboard(pDocShell
->GetClipData()) : nullptr;
4792 if ( pClipObj
&& pClipObj
->GetUseInApi() )
4794 // After the insert ( this range ) actually has moved
4795 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
) );
4796 uno::Reference
< table::XCellRange
> xRange( new ScCellRangeObj( getDocShellFromRange( mxRange
) , aRange
) );
4797 uno::Reference
< excel::XRange
> xVbaRange( new ScVbaRange( mxParent
, mxContext
, xRange
, mbIsRows
, mbIsColumns
) );
4798 xVbaRange
->PasteSpecial( uno::Any(), uno::Any(), uno::Any(), uno::Any() );
4803 ScVbaRange::Autofit()
4805 sal_Int32 nLen
= m_Areas
->getCount();
4808 for ( sal_Int32 index
= 1; index
!= nLen
; ++index
)
4810 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( index
), uno::Any() ), uno::UNO_QUERY_THROW
);
4816 // if the range is a not a row or column range autofit will
4818 if ( !( mbIsColumns
|| mbIsRows
) )
4819 DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED
, {});
4820 ScDocShell
* pDocShell
= getDocShellFromRange( mxRange
);
4824 RangeHelper
thisRange( mxRange
);
4825 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
4827 std::vector
<sc::ColRowSpan
> aColArr(1, sc::ColRowSpan(thisAddress
.StartColumn
,thisAddress
.EndColumn
));
4828 bool bDirection
= true;
4832 aColArr
[0].mnStart
= thisAddress
.StartRow
;
4833 aColArr
[0].mnEnd
= thisAddress
.EndRow
;
4835 pDocShell
->GetDocFunc().SetWidthOrHeight(
4836 bDirection
, aColArr
, thisAddress
.Sheet
, SC_SIZE_OPTIMAL
, 0, true, true);
4840 ScVbaRange::Hyperlinks( const uno::Any
& aIndex
)
4842 /* The range object always returns a new Hyperlinks object containing a
4843 fixed list of existing hyperlinks in the range.
4844 See vbahyperlinks.hxx for more details. */
4846 // get the global hyperlink object of the sheet (sheet should always be the parent of a Range object)
4847 uno::Reference
< excel::XWorksheet
> xWorksheet( getParent(), uno::UNO_QUERY_THROW
);
4848 uno::Reference
< excel::XHyperlinks
> xSheetHlinks( xWorksheet
->Hyperlinks( uno::Any() ), uno::UNO_QUERY_THROW
);
4849 ScVbaHyperlinksRef
xScSheetHlinks( dynamic_cast< ScVbaHyperlinks
* >( xSheetHlinks
.get() ) );
4850 if( !xScSheetHlinks
.is() )
4851 throw uno::RuntimeException(u
"Cannot obtain hyperlinks implementation object"_ustr
);
4853 // create a new local hyperlinks object based on the sheet hyperlinks
4854 ScVbaHyperlinksRef
xHlinks( new ScVbaHyperlinks( getParent(), mxContext
, xScSheetHlinks
, getScRangeList() ) );
4855 if( aIndex
.hasValue() )
4856 return xHlinks
->Item( aIndex
, uno::Any() );
4857 return uno::Any( uno::Reference
< excel::XHyperlinks
>( xHlinks
) );
4860 css::uno::Reference
< excel::XValidation
> SAL_CALL
4861 ScVbaRange::getValidation()
4863 if ( !m_xValidation
.is() )
4864 m_xValidation
= new ScVbaValidation( this, mxContext
, mxRange
);
4865 return m_xValidation
;
4870 /// @throws uno::RuntimeException
4871 sal_Unicode
lclGetPrefixChar( const uno::Reference
< table::XCell
>& rxCell
)
4873 /* TODO/FIXME: We need an apostroph-prefix property at the cell to
4874 implement this correctly. For now, return an apostroph for every text
4877 TODO/FIXME: When Application.TransitionNavigKeys is supported and true,
4878 this function needs to inspect the cell formatting and return different
4879 prefixes according to the horizontal cell alignment.
4881 return (rxCell
->getType() == table::CellContentType_TEXT
) ? '\'' : 0;
4884 /// @throws uno::RuntimeException
4885 sal_Unicode
lclGetPrefixChar( const uno::Reference
< table::XCellRange
>& rxRange
)
4887 /* This implementation is able to handle different prefixes (needed if
4888 Application.TransitionNavigKeys is true). The function lclGetPrefixChar
4889 for single cells called from here may return any prefix. If that
4890 function returns an empty prefix (NUL character) or different non-empty
4891 prefixes for two cells, this function returns 0.
4893 sal_Unicode cCurrPrefix
= 0;
4894 table::CellRangeAddress aRangeAddr
= lclGetRangeAddress( rxRange
);
4895 sal_Int32 nEndCol
= aRangeAddr
.EndColumn
- aRangeAddr
.StartColumn
;
4896 sal_Int32 nEndRow
= aRangeAddr
.EndRow
- aRangeAddr
.StartRow
;
4897 for( sal_Int32 nRow
= 0; nRow
<= nEndRow
; ++nRow
)
4899 for( sal_Int32 nCol
= 0; nCol
<= nEndCol
; ++nCol
)
4901 uno::Reference
< table::XCell
> xCell( rxRange
->getCellByPosition( nCol
, nRow
), uno::UNO_SET_THROW
);
4902 sal_Unicode cNewPrefix
= lclGetPrefixChar( xCell
);
4903 if( (cNewPrefix
== 0) || ((cCurrPrefix
!= 0) && (cNewPrefix
!= cCurrPrefix
)) )
4905 cCurrPrefix
= cNewPrefix
;
4908 // all cells contain the same prefix - return it
4912 /// @throws uno::RuntimeException
4913 sal_Unicode
lclGetPrefixChar( const uno::Reference
< sheet::XSheetCellRangeContainer
>& rxRanges
)
4915 sal_Unicode cCurrPrefix
= 0;
4916 uno::Reference
< container::XEnumerationAccess
> xRangesEA( rxRanges
, uno::UNO_QUERY_THROW
);
4917 uno::Reference
< container::XEnumeration
> xRangesEnum( xRangesEA
->createEnumeration(), uno::UNO_SET_THROW
);
4918 while( xRangesEnum
->hasMoreElements() )
4920 uno::Reference
< table::XCellRange
> xRange( xRangesEnum
->nextElement(), uno::UNO_QUERY_THROW
);
4921 sal_Unicode cNewPrefix
= lclGetPrefixChar( xRange
);
4922 if( (cNewPrefix
== 0) || ((cCurrPrefix
!= 0) && (cNewPrefix
!= cCurrPrefix
)) )
4924 cCurrPrefix
= cNewPrefix
;
4926 // all ranges contain the same prefix - return it
4930 uno::Any
lclGetPrefixVariant( sal_Unicode cPrefixChar
)
4932 return uno::Any( (cPrefixChar
== 0) ? OUString() : OUString( cPrefixChar
) );
4937 uno::Any SAL_CALL
ScVbaRange::getPrefixCharacter()
4939 /* (1) If Application.TransitionNavigKeys is false, this function returns
4940 an apostroph character if the text cell begins with an apostroph
4941 character (formula return values are not taken into account); otherwise
4944 (2) If Application.TransitionNavigKeys is true, this function returns
4945 an apostroph character, if the cell is left-aligned; a double-quote
4946 character, if the cell is right-aligned; a circumflex character, if the
4947 cell is centered; a backslash character, if the cell is set to filled;
4948 or an empty string, if nothing of the above.
4950 If a range or a list of ranges contains texts with leading apostroph
4951 character as well as other cells, this function returns an empty
4956 return lclGetPrefixVariant( lclGetPrefixChar( mxRange
) );
4958 return lclGetPrefixVariant( lclGetPrefixChar( mxRanges
) );
4959 throw uno::RuntimeException(u
"Unexpected empty Range object"_ustr
);
4962 uno::Any
ScVbaRange::getShowDetail()
4964 // #FIXME, If the specified range is in a PivotTable report
4966 // In MSO VBA, the specified range must be a single summary column or row in an outline. otherwise throw exception
4967 if( m_Areas
->getCount() > 1 )
4968 throw uno::RuntimeException(u
"Can not get Range.ShowDetail attribute "_ustr
);
4970 RangeHelper
helper( mxRange
);
4971 uno::Reference
< sheet::XSheetCellCursor
> xSheetCellCursor
= helper
.getSheetCellCursor();
4972 xSheetCellCursor
->collapseToCurrentRegion();
4973 uno::Reference
< sheet::XCellRangeAddressable
> xCellRangeAddressable(xSheetCellCursor
, uno::UNO_QUERY_THROW
);
4974 table::CellRangeAddress aOutlineAddress
= xCellRangeAddressable
->getRangeAddress();
4976 // check if the specified range is a single summary column or row.
4977 table::CellRangeAddress thisAddress
= helper
.getCellRangeAddressable()->getRangeAddress();
4978 if( (thisAddress
.StartRow
!= thisAddress
.EndRow
|| thisAddress
.EndRow
!= aOutlineAddress
.EndRow
) &&
4979 (thisAddress
.StartColumn
!= thisAddress
.EndColumn
|| thisAddress
.EndColumn
!= aOutlineAddress
.EndColumn
))
4981 throw uno::RuntimeException(u
"Can not set Range.ShowDetail attribute"_ustr
);
4984 bool bColumn
= thisAddress
.StartRow
!= thisAddress
.EndRow
;
4985 ScDocument
& rDoc
= getDocumentFromRange( mxRange
);
4986 ScOutlineTable
* pOutlineTable
= rDoc
.GetOutlineTable(static_cast<SCTAB
>(thisAddress
.Sheet
), true);
4987 const ScOutlineArray
& rOutlineArray
= bColumn
? pOutlineTable
->GetColArray(): pOutlineTable
->GetRowArray();
4988 SCCOLROW nPos
= bColumn
? static_cast<SCCOLROW
>(thisAddress
.EndColumn
-1):static_cast<SCCOLROW
>(thisAddress
.EndRow
-1);
4989 const ScOutlineEntry
* pEntry
= rOutlineArray
.GetEntryByPos( 0, nPos
);
4992 const bool bShowDetail
= !pEntry
->IsHidden();
4993 return uno::Any( bShowDetail
);
4999 void ScVbaRange::setShowDetail(const uno::Any
& aShowDetail
)
5001 // #FIXME, If the specified range is in a PivotTable report
5003 // In MSO VBA, the specified range must be a single summary column or row in an outline. otherwise throw exception
5004 if( m_Areas
->getCount() > 1 )
5005 throw uno::RuntimeException(u
"Can not set Range.ShowDetail attribute"_ustr
);
5007 bool bShowDetail
= extractBoolFromAny( aShowDetail
);
5009 RangeHelper
helper( mxRange
);
5010 uno::Reference
< sheet::XSheetCellCursor
> xSheetCellCursor
= helper
.getSheetCellCursor();
5011 xSheetCellCursor
->collapseToCurrentRegion();
5012 uno::Reference
< sheet::XCellRangeAddressable
> xCellRangeAddressable(xSheetCellCursor
, uno::UNO_QUERY_THROW
);
5013 table::CellRangeAddress aOutlineAddress
= xCellRangeAddressable
->getRangeAddress();
5015 // check if the specified range is a single summary column or row.
5016 table::CellRangeAddress thisAddress
= helper
.getCellRangeAddressable()->getRangeAddress();
5017 if( (thisAddress
.StartRow
!= thisAddress
.EndRow
|| thisAddress
.EndRow
!= aOutlineAddress
.EndRow
) &&
5018 (thisAddress
.StartColumn
!= thisAddress
.EndColumn
|| thisAddress
.EndColumn
!= aOutlineAddress
.EndColumn
))
5020 throw uno::RuntimeException(u
"Can not set Range.ShowDetail attribute"_ustr
);
5023 // #FIXME, seems there is a different behavior between MSO and OOo.
5024 // In OOo, the showDetail will show all the level entries, while only show the first level entry in MSO
5025 uno::Reference
< sheet::XSheetOutline
> xSheetOutline( helper
.getSpreadSheet(), uno::UNO_QUERY_THROW
);
5027 xSheetOutline
->showDetail( aOutlineAddress
);
5029 xSheetOutline
->hideDetail( aOutlineAddress
);
5033 uno::Reference
< excel::XRange
> SAL_CALL
5034 ScVbaRange::MergeArea()
5036 uno::Reference
< sheet::XSheetCellRange
> xMergeShellCellRange(mxRange
->getCellRangeByPosition(0,0,0,0), uno::UNO_QUERY_THROW
);
5037 uno::Reference
< sheet::XSheetCellCursor
> xMergeSheetCursor(xMergeShellCellRange
->getSpreadsheet()->createCursorByRange( xMergeShellCellRange
), uno::UNO_SET_THROW
);
5038 if( xMergeSheetCursor
.is() )
5040 xMergeSheetCursor
->collapseToMergedArea();
5041 uno::Reference
<sheet::XCellRangeAddressable
> xMergeCellAddress(xMergeSheetCursor
, uno::UNO_QUERY_THROW
);
5042 table::CellRangeAddress aCellAddress
= xMergeCellAddress
->getRangeAddress();
5043 if( aCellAddress
.StartColumn
==0 && aCellAddress
.EndColumn
==0 &&
5044 aCellAddress
.StartRow
==0 && aCellAddress
.EndRow
==0)
5046 return new ScVbaRange( mxParent
,mxContext
,mxRange
);
5050 ScRange
refRange( static_cast< SCCOL
>( aCellAddress
.StartColumn
), static_cast< SCROW
>( aCellAddress
.StartRow
), static_cast< SCTAB
>( aCellAddress
.Sheet
),
5051 static_cast< SCCOL
>( aCellAddress
.EndColumn
), static_cast< SCROW
>( aCellAddress
.EndRow
), static_cast< SCTAB
>( aCellAddress
.Sheet
) );
5052 uno::Reference
< table::XCellRange
> xRange( new ScCellRangeObj( getScDocShell() , refRange
) );
5053 return new ScVbaRange( mxParent
, mxContext
,xRange
);
5056 return new ScVbaRange( mxParent
, mxContext
, mxRange
);
5060 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
)
5062 ScDocShell
* pShell
= nullptr;
5064 sal_Int32 nItems
= m_Areas
->getCount();
5065 uno::Sequence
< table::CellRangeAddress
> printAreas( nItems
);
5066 auto printAreasRange
= asNonConstRange(printAreas
);
5067 uno::Reference
< sheet::XPrintAreas
> xPrintAreas
;
5068 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
5070 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(index
), uno::Any() ), uno::UNO_QUERY_THROW
);
5072 RangeHelper
thisRange( xRange
->getCellRange() );
5073 table::CellRangeAddress rangeAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
5076 ScVbaRange
* pRange
= getImplementation( xRange
);
5077 // initialise the doc shell and the printareas
5078 pShell
= getDocShellFromRange( pRange
->mxRange
);
5079 xPrintAreas
.set( thisRange
.getSpreadSheet(), uno::UNO_QUERY_THROW
);
5081 printAreasRange
[ index
- 1 ] = rangeAddress
;
5083 if ( pShell
&& xPrintAreas
.is() )
5085 xPrintAreas
->setPrintAreas( printAreas
);
5086 uno::Reference
< frame::XModel
> xModel
= pShell
->GetModel();
5087 PrintOutHelper( excel::getBestViewShell( xModel
), From
, To
, Copies
, Preview
, ActivePrinter
, PrintToFile
, Collate
, PrToFileName
, true );
5092 ScVbaRange::AutoFill( const uno::Reference
< excel::XRange
>& Destination
, const uno::Any
& Type
)
5094 uno::Reference
< excel::XRange
> xDest( Destination
, uno::UNO_SET_THROW
);
5095 ScVbaRange
* pRange
= getImplementation( xDest
);
5096 RangeHelper
destRangeHelper( pRange
->mxRange
);
5097 table::CellRangeAddress destAddress
= destRangeHelper
.getCellRangeAddressable()->getRangeAddress();
5099 RangeHelper
thisRange( mxRange
);
5100 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
5101 ScRange sourceRange
;
5104 ScUnoConversion::FillScRange( destRange
, destAddress
);
5105 ScUnoConversion::FillScRange( sourceRange
, thisAddress
);
5107 FillDir eDir
= FILL_TO_BOTTOM
;
5110 ScRange
aRange( destRange
);
5111 ScRange
aSourceRange( destRange
);
5113 // default to include the number of Rows in the source range;
5114 SCCOLROW nSourceCount
= ( sourceRange
.aEnd
.Row() - sourceRange
.aStart
.Row() ) + 1;
5115 SCCOLROW nCount
= 0;
5117 if ( sourceRange
!= destRange
)
5119 // Find direction of fill, vertical or horizontal
5120 if ( sourceRange
.aStart
== destRange
.aStart
)
5122 if ( sourceRange
.aEnd
.Row() == destRange
.aEnd
.Row() )
5124 nSourceCount
= ( sourceRange
.aEnd
.Col() - sourceRange
.aStart
.Col() + 1 );
5125 aSourceRange
.aEnd
.SetCol( static_cast<SCCOL
>( aSourceRange
.aStart
.Col() + nSourceCount
- 1 ) );
5126 eDir
= FILL_TO_RIGHT
;
5127 nCount
= aRange
.aEnd
.Col() - aSourceRange
.aEnd
.Col();
5129 else if ( sourceRange
.aEnd
.Col() == destRange
.aEnd
.Col() )
5131 aSourceRange
.aEnd
.SetRow( static_cast<SCROW
>( aSourceRange
.aStart
.Row() + nSourceCount
) - 1 );
5132 nCount
= aRange
.aEnd
.Row() - aSourceRange
.aEnd
.Row();
5133 eDir
= FILL_TO_BOTTOM
;
5137 else if ( aSourceRange
.aEnd
== destRange
.aEnd
)
5139 if ( sourceRange
.aStart
.Col() == destRange
.aStart
.Col() )
5141 aSourceRange
.aStart
.SetRow( static_cast<SCROW
>( aSourceRange
.aEnd
.Row() - nSourceCount
+ 1 ) );
5142 nCount
= aSourceRange
.aStart
.Row() - aRange
.aStart
.Row();
5146 else if ( sourceRange
.aStart
.Row() == destRange
.aStart
.Row() )
5148 nSourceCount
= ( sourceRange
.aEnd
.Col() - sourceRange
.aStart
.Col() ) + 1;
5149 aSourceRange
.aStart
.SetCol( static_cast<SCCOL
>( aSourceRange
.aEnd
.Col() - nSourceCount
+ 1 ) );
5150 nCount
= aSourceRange
.aStart
.Col() - aRange
.aStart
.Col();
5151 eDir
= FILL_TO_LEFT
;
5157 FillCmd eCmd
= FILL_AUTO
;
5158 FillDateCmd eDateCmd
= FILL_DAY
;
5160 if ( Type
.hasValue() )
5162 sal_Int16 nFillType
= excel::XlAutoFillType::xlFillDefault
;
5164 switch ( nFillType
)
5166 case excel::XlAutoFillType::xlFillCopy
:
5170 case excel::XlAutoFillType::xlFillDays
:
5173 case excel::XlAutoFillType::xlFillMonths
:
5175 eDateCmd
= FILL_MONTH
;
5177 case excel::XlAutoFillType::xlFillWeekdays
:
5179 eDateCmd
= FILL_WEEKDAY
;
5181 case excel::XlAutoFillType::xlFillYears
:
5183 eDateCmd
= FILL_YEAR
;
5185 case excel::XlAutoFillType::xlGrowthTrend
:
5188 case excel::XlAutoFillType::xlFillFormats
:
5189 throw uno::RuntimeException(u
"xlFillFormat not supported for AutoFill"_ustr
);
5190 case excel::XlAutoFillType::xlFillValues
:
5191 case excel::XlAutoFillType::xlFillSeries
:
5192 case excel::XlAutoFillType::xlLinearTrend
:
5195 case excel::XlAutoFillType::xlFillDefault
:
5201 ScDocShell
* pDocSh
= getDocShellFromRange( mxRange
);
5202 pDocSh
->GetDocFunc().FillAuto( aSourceRange
, nullptr, eDir
, eCmd
, eDateCmd
,
5203 nCount
, fStep
, MAXDOUBLE
/*fEndValue*/, true, true );
5206 ScVbaRange::GoalSeek( const uno::Any
& Goal
, const uno::Reference
< excel::XRange
>& ChangingCell
)
5208 ScDocShell
* pDocShell
= getScDocShell();
5210 ScVbaRange
* pRange
= static_cast< ScVbaRange
* >( ChangingCell
.get() );
5211 if ( pDocShell
&& pRange
)
5213 RangeHelper
thisRange( mxRange
);
5214 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
5215 RangeHelper
changingCellRange( pRange
->mxRange
);
5216 table::CellRangeAddress changingCellAddr
= changingCellRange
.getCellRangeAddressable()->getRangeAddress();
5217 OUString sGoal
= getAnyAsString( Goal
);
5218 table::CellAddress
thisCell( thisAddress
.Sheet
, thisAddress
.StartColumn
, thisAddress
.StartRow
);
5219 table::CellAddress
changingCell( changingCellAddr
.Sheet
, changingCellAddr
.StartColumn
, changingCellAddr
.StartRow
);
5220 sheet::GoalResult res
= pDocShell
->GetModel()->seekGoal( thisCell
, changingCell
, sGoal
);
5221 ChangingCell
->setValue( uno::Any( res
.Result
) );
5223 // openoffice behaves differently, result is 0 if the divergence is too great
5224 // but... if it detects 0 is the value it requires then it will use that
5225 // e.g. divergence & result both = 0.0 does NOT mean there is an error
5226 if ( ( res
.Divergence
!= 0.0 ) && ( res
.Result
== 0.0 ) )
5235 ScVbaRange::Calculate( )
5237 getWorksheet()->Calculate();
5240 uno::Reference
< excel::XRange
> SAL_CALL
5241 ScVbaRange::Item( const uno::Any
& row
, const uno::Any
& column
)
5243 if ( mbIsRows
|| mbIsColumns
)
5245 if ( column
.hasValue() )
5246 DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER
, {} );
5247 uno::Reference
< excel::XRange
> xRange
;
5249 xRange
= Columns( row
);
5251 xRange
= Rows( row
);
5254 return Cells( row
, column
);
5258 ScVbaRange::AutoOutline( )
5260 // #TODO #FIXME needs to check for summary row/col ( whatever they are )
5261 // not valid for multi Area Addresses
5262 if ( m_Areas
->getCount() > 1 )
5263 DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED
, STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY
);
5264 // So needs to either span an entire Row or a just be a single cell
5265 // ( that contains a summary RowColumn )
5266 // also the Single cell cause doesn't seem to be handled specially in
5267 // this code ( ported from the helperapi RangeImpl.java,
5268 // RangeRowsImpl.java, RangesImpl.java, RangeSingleCellImpl.java
5269 RangeHelper
thisRange( mxRange
);
5270 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
5272 if ( isSingleCellRange() || mbIsRows
)
5274 uno::Reference
< sheet::XSheetOutline
> xSheetOutline( thisRange
.getSpreadSheet(), uno::UNO_QUERY_THROW
);
5275 xSheetOutline
->autoOutline( thisAddress
);
5278 DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED
, {});
5282 ScVbaRange:: ClearOutline( )
5284 if ( m_Areas
->getCount() > 1 )
5286 sal_Int32 nItems
= m_Areas
->getCount();
5287 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
5289 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(index
), uno::Any() ), uno::UNO_QUERY_THROW
);
5290 xRange
->ClearOutline();
5294 RangeHelper
thisRange( mxRange
);
5295 uno::Reference
< sheet::XSheetOutline
> xSheetOutline( thisRange
.getSpreadSheet(), uno::UNO_QUERY_THROW
);
5296 xSheetOutline
->clearOutline();
5300 ScVbaRange::groupUnGroup( bool bUnGroup
)
5302 if ( m_Areas
->getCount() > 1 )
5303 DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED
, STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY
);
5304 table::TableOrientation nOrient
= table::TableOrientation_ROWS
;
5306 nOrient
= table::TableOrientation_COLUMNS
;
5307 RangeHelper
thisRange( mxRange
);
5308 table::CellRangeAddress thisAddress
= thisRange
.getCellRangeAddressable()->getRangeAddress();
5309 uno::Reference
< sheet::XSheetOutline
> xSheetOutline( thisRange
.getSpreadSheet(), uno::UNO_QUERY_THROW
);
5311 xSheetOutline
->ungroup( thisAddress
, nOrient
);
5313 xSheetOutline
->group( thisAddress
, nOrient
);
5317 ScVbaRange::Group( )
5319 groupUnGroup(false);
5322 ScVbaRange::Ungroup( )
5327 /// @throws uno::RuntimeException
5328 static void lcl_mergeCellsOfRange( const uno::Reference
< table::XCellRange
>& xCellRange
, bool _bMerge
)
5330 uno::Reference
< util::XMergeable
> xMergeable( xCellRange
, uno::UNO_QUERY_THROW
);
5331 xMergeable
->merge(_bMerge
);
5334 ScVbaRange::Merge( const uno::Any
& Across
)
5336 if ( m_Areas
->getCount() > 1 )
5338 sal_Int32 nItems
= m_Areas
->getCount();
5339 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
5341 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(index
), uno::Any() ), uno::UNO_QUERY_THROW
);
5342 xRange
->Merge(Across
);
5346 bool bAcross
= false;
5349 lcl_mergeCellsOfRange( mxRange
, true );
5352 uno::Reference
< excel::XRange
> oRangeRowsImpl
= Rows( uno::Any() );
5353 // #TODO #FIXME this seems incredibly lame, this can't be right
5354 for (sal_Int32 i
=1; i
<= oRangeRowsImpl
->getCount();i
++)
5356 oRangeRowsImpl
->Cells( uno::Any( i
), uno::Any() )->Merge( uno::Any( false ) );
5362 ScVbaRange::UnMerge( )
5364 if ( m_Areas
->getCount() > 1 )
5366 sal_Int32 nItems
= m_Areas
->getCount();
5367 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
5369 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(index
), uno::Any() ), uno::UNO_QUERY_THROW
);
5374 lcl_mergeCellsOfRange( mxRange
, false);
5378 ScVbaRange::getStyle()
5380 if ( m_Areas
->getCount() > 1 )
5382 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW
);
5383 return xRange
->getStyle();
5385 uno::Reference
< beans::XPropertySet
> xProps( mxRange
, uno::UNO_QUERY_THROW
);
5386 OUString sStyleName
;
5387 xProps
->getPropertyValue( CELLSTYLE
) >>= sStyleName
;
5388 ScDocShell
* pShell
= getScDocShell();
5389 uno::Reference
< frame::XModel
> xModel( pShell
->GetModel() );
5390 uno::Reference
< excel::XStyle
> xStyle
= new ScVbaStyle( this, mxContext
, sStyleName
, xModel
);
5391 return uno::Any( xStyle
);
5394 ScVbaRange::setStyle( const uno::Any
& _style
)
5396 if ( m_Areas
->getCount() > 1 )
5398 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW
);
5399 xRange
->setStyle( _style
);
5402 uno::Reference
< beans::XPropertySet
> xProps( mxRange
, uno::UNO_QUERY_THROW
);
5403 uno::Reference
< excel::XStyle
> xStyle
;
5406 xProps
->setPropertyValue( CELLSTYLE
, uno::Any( xStyle
->getName() ) );
5409 uno::Reference
< excel::XRange
>
5410 ScVbaRange::PreviousNext( bool bIsPrevious
)
5412 ScMarkData
markedRange(getScDocument().GetSheetLimits());
5414 RangeHelper
thisRange( mxRange
);
5416 ScUnoConversion::FillScRange( refRange
, thisRange
.getCellRangeAddressable()->getRangeAddress());
5417 markedRange
. SetMarkArea( refRange
);
5418 short nMove
= bIsPrevious
? -1 : 1;
5420 SCCOL nNewX
= refRange
.aStart
.Col();
5421 SCROW nNewY
= refRange
.aStart
.Row();
5422 SCTAB nTab
= refRange
.aStart
.Tab();
5424 ScDocument
& rDoc
= getScDocument();
5425 rDoc
.GetNextPos( nNewX
,nNewY
, nTab
, nMove
,0, true,true, markedRange
);
5426 refRange
.aStart
.SetCol( nNewX
);
5427 refRange
.aStart
.SetRow( nNewY
);
5428 refRange
.aStart
.SetTab( nTab
);
5429 refRange
.aEnd
.SetCol( nNewX
);
5430 refRange
.aEnd
.SetRow( nNewY
);
5431 refRange
.aEnd
.SetTab( nTab
);
5433 uno::Reference
< table::XCellRange
> xRange( new ScCellRangeObj( getScDocShell() , refRange
) );
5435 return new ScVbaRange( mxParent
, mxContext
, xRange
);
5438 uno::Reference
< excel::XRange
> SAL_CALL
5441 if ( m_Areas
->getCount() > 1 )
5443 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ) , uno::UNO_QUERY_THROW
);
5444 return xRange
->Next();
5446 return PreviousNext( false );
5449 uno::Reference
< excel::XRange
> SAL_CALL
5450 ScVbaRange::Previous()
5452 if ( m_Areas
->getCount() > 1 )
5454 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW
);
5455 return xRange
->Previous();
5457 return PreviousNext( true );
5460 uno::Reference
< excel::XRange
> SAL_CALL
5461 ScVbaRange::SpecialCells( const uno::Any
& _oType
, const uno::Any
& _oValue
)
5463 bool bIsSingleCell
= isSingleCellRange();
5464 bool bIsMultiArea
= ( m_Areas
->getCount() > 1 );
5465 ScVbaRange
* pRangeToUse
= this;
5466 uno::Reference
< excel::XRange
> xUsedRange( getWorksheet()->getUsedRange() );
5467 sal_Int32 nType
= 0;
5468 if ( !( _oType
>>= nType
) )
5469 DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER
, {} );
5472 case excel::XlCellType::xlCellTypeSameFormatConditions
:
5473 case excel::XlCellType::xlCellTypeAllValidation
:
5474 case excel::XlCellType::xlCellTypeSameValidation
:
5475 DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED
, {});
5477 case excel::XlCellType::xlCellTypeBlanks
:
5478 case excel::XlCellType::xlCellTypeComments
:
5479 case excel::XlCellType::xlCellTypeConstants
:
5480 case excel::XlCellType::xlCellTypeFormulas
:
5481 case excel::XlCellType::xlCellTypeVisible
:
5482 case excel::XlCellType::xlCellTypeLastCell
:
5486 // need to process each area, gather the results and
5487 // create a new range from those
5488 std::vector
< table::CellRangeAddress
> rangeResults
;
5489 sal_Int32 nItems
= m_Areas
->getCount() + 1;
5490 for ( sal_Int32 index
=1; index
<= nItems
; ++index
)
5492 uno::Reference
< excel::XRange
> xRange( m_Areas
->Item( uno::Any(index
), uno::Any() ), uno::UNO_QUERY_THROW
);
5493 xRange
= xRange
->SpecialCells( _oType
, _oValue
);
5494 ScVbaRange
* pRange
= getImplementation( xRange
);
5495 if ( xRange
.is() && pRange
)
5497 sal_Int32 nElems
= pRange
->m_Areas
->getCount() + 1;
5498 for ( sal_Int32 nArea
= 1; nArea
< nElems
; ++nArea
)
5500 uno::Reference
< excel::XRange
> xTmpRange( m_Areas
->Item( uno::Any( nArea
), uno::Any() ), uno::UNO_QUERY_THROW
);
5501 RangeHelper
rHelper( xTmpRange
->getCellRange() );
5502 rangeResults
.push_back( rHelper
.getCellRangeAddressable()->getRangeAddress() );
5506 ScRangeList aCellRanges
;
5507 for ( const auto& rRangeResult
: rangeResults
)
5510 ScUnoConversion::FillScRange( refRange
, rRangeResult
);
5511 aCellRanges
.push_back( refRange
);
5514 if ( aCellRanges
.size() == 1 )
5516 uno::Reference
< table::XCellRange
> xRange( new ScCellRangeObj( getScDocShell(), aCellRanges
.front() ) );
5517 return new ScVbaRange( mxParent
, mxContext
, xRange
);
5519 uno::Reference
< sheet::XSheetCellRangeContainer
> xRanges( new ScCellRangesObj( getScDocShell(), aCellRanges
) );
5521 return new ScVbaRange( mxParent
, mxContext
, xRanges
);
5523 else if ( bIsSingleCell
)
5525 pRangeToUse
= static_cast< ScVbaRange
* >( xUsedRange
.get() );
5531 DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER
, {} );
5535 DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED
, {} );
5536 return pRangeToUse
->SpecialCellsImpl( nType
, _oValue
);
5539 static sal_Int32
getContentResultFlags(const uno::Any
& aValue
)
5541 if (sal_Int32 aType
; aValue
>>= aType
)
5545 case excel::XlSpecialCellsValue::xlNumbers
:
5546 return sheet::CellFlags::VALUE
| sheet::CellFlags::DATETIME
;
5547 case excel::XlSpecialCellsValue::xlTextValues
:
5548 return sheet::CellFlags::STRING
;
5549 case excel::XlSpecialCellsValue::xlLogical
:
5550 return sheet::CellFlags::VALUE
| sheet::CellFlags::DATETIME
;
5551 case excel::XlSpecialCellsValue::xlErrors
:
5554 DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER
, {});
5557 return sheet::CellFlags::VALUE
| sheet::CellFlags::STRING
| sheet::CellFlags::DATETIME
;
5560 /// @throws script::BasicErrorException
5561 static sal_Int32
lcl_getFormulaResultFlags(const uno::Any
& aType
)
5563 sal_Int32 nType
= excel::XlSpecialCellsValue::xlNumbers
;
5565 sal_Int32 nRes
= sheet::FormulaResult::VALUE
;
5569 case excel::XlSpecialCellsValue::xlErrors
:
5570 nRes
= sheet::FormulaResult::ERROR
;
5572 case excel::XlSpecialCellsValue::xlLogical
:
5573 //TODO bc93774: ask NN if this is really an appropriate substitute
5574 nRes
= sheet::FormulaResult::VALUE
;
5576 case excel::XlSpecialCellsValue::xlNumbers
:
5577 nRes
= sheet::FormulaResult::VALUE
;
5579 case excel::XlSpecialCellsValue::xlTextValues
:
5580 nRes
= sheet::FormulaResult::STRING
;
5583 DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER
, {} );
5588 uno::Reference
< excel::XRange
>
5589 ScVbaRange::SpecialCellsImpl( sal_Int32 nType
, const uno::Any
& _oValue
)
5591 uno::Reference
< excel::XRange
> xRange
;
5594 uno::Reference
< sheet::XCellRangesQuery
> xQuery( mxRange
, uno::UNO_QUERY_THROW
);
5595 uno::Reference
< sheet::XSheetCellRanges
> xLocSheetCellRanges
;
5598 case excel::XlCellType::xlCellTypeAllFormatConditions
:
5599 case excel::XlCellType::xlCellTypeSameFormatConditions
:
5600 case excel::XlCellType::xlCellTypeAllValidation
:
5601 case excel::XlCellType::xlCellTypeSameValidation
:
5602 // Shouldn't get here ( should be filtered out by
5603 // ScVbaRange::SpecialCells()
5604 DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED
, {});
5606 case excel::XlCellType::xlCellTypeBlanks
:
5607 xLocSheetCellRanges
= xQuery
->queryEmptyCells();
5609 case excel::XlCellType::xlCellTypeComments
:
5610 xLocSheetCellRanges
= xQuery
->queryContentCells(sheet::CellFlags::ANNOTATION
);
5612 case excel::XlCellType::xlCellTypeConstants
:
5613 xLocSheetCellRanges
= xQuery
->queryContentCells(getContentResultFlags(_oValue
));
5615 case excel::XlCellType::xlCellTypeFormulas
:
5617 sal_Int32 nFormulaResult
= lcl_getFormulaResultFlags(_oValue
);
5618 xLocSheetCellRanges
= xQuery
->queryFormulaCells(nFormulaResult
);
5621 case excel::XlCellType::xlCellTypeLastCell
:
5622 xRange
= Cells( uno::Any( getCount() ), uno::Any() );
5623 [[fallthrough
]]; //TODO ???
5624 case excel::XlCellType::xlCellTypeVisible
:
5625 xLocSheetCellRanges
= xQuery
->queryVisibleCells();
5628 DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER
, {} );
5631 if (xLocSheetCellRanges
.is())
5633 xRange
= lcl_makeXRangeFromSheetCellRanges( getParent(), mxContext
, xLocSheetCellRanges
, getScDocShell() );
5636 catch (uno::Exception
& )
5638 DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED
, u
"No cells were found");
5644 ScVbaRange::RemoveSubtotal( )
5646 uno::Reference
< sheet::XSubTotalCalculatable
> xSub( mxRange
, uno::UNO_QUERY_THROW
);
5647 xSub
->removeSubTotals();
5651 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*/ )
5655 bool bDoReplace
= false;
5656 aReplace
>>= bDoReplace
;
5657 bool bAddPageBreaks
= false;
5658 PageBreaks
>>= bAddPageBreaks
;
5660 uno::Reference
< sheet::XSubTotalCalculatable
> xSub(mxRange
, uno::UNO_QUERY_THROW
);
5661 uno::Reference
< sheet::XSubTotalDescriptor
> xSubDesc
= xSub
->createSubTotalDescriptor(true);
5662 uno::Reference
< beans::XPropertySet
> xSubDescPropertySet( xSubDesc
, uno::UNO_QUERY_THROW
);
5663 xSubDescPropertySet
->setPropertyValue(u
"InsertPageBreaks"_ustr
, uno::Any( bAddPageBreaks
));
5664 sal_Int32 nLen
= _nTotalList
.getLength();
5665 uno::Sequence
< sheet::SubTotalColumn
> aColumns( nLen
);
5666 auto aColumnsRange
= asNonConstRange(aColumns
);
5667 for (int i
= 0; i
< nLen
; i
++)
5669 aColumnsRange
[i
].Column
= _nTotalList
[i
] - 1;
5672 case excel::XlConsolidationFunction::xlAverage
:
5673 aColumnsRange
[i
].Function
= sheet::GeneralFunction_AVERAGE
;
5675 case excel::XlConsolidationFunction::xlCount
:
5676 aColumnsRange
[i
].Function
= sheet::GeneralFunction_COUNT
;
5678 case excel::XlConsolidationFunction::xlCountNums
:
5679 aColumnsRange
[i
].Function
= sheet::GeneralFunction_COUNTNUMS
;
5681 case excel::XlConsolidationFunction::xlMax
:
5682 aColumnsRange
[i
].Function
= sheet::GeneralFunction_MAX
;
5684 case excel::XlConsolidationFunction::xlMin
:
5685 aColumnsRange
[i
].Function
= sheet::GeneralFunction_MIN
;
5687 case excel::XlConsolidationFunction::xlProduct
:
5688 aColumnsRange
[i
].Function
= sheet::GeneralFunction_PRODUCT
;
5690 case excel::XlConsolidationFunction::xlStDev
:
5691 aColumnsRange
[i
].Function
= sheet::GeneralFunction_STDEV
;
5693 case excel::XlConsolidationFunction::xlStDevP
:
5694 aColumnsRange
[i
].Function
= sheet::GeneralFunction_STDEVP
;
5696 case excel::XlConsolidationFunction::xlSum
:
5697 aColumnsRange
[i
].Function
= sheet::GeneralFunction_SUM
;
5699 case excel::XlConsolidationFunction::xlUnknown
:
5700 aColumnsRange
[i
].Function
= sheet::GeneralFunction_NONE
;
5702 case excel::XlConsolidationFunction::xlVar
:
5703 aColumnsRange
[i
].Function
= sheet::GeneralFunction_VAR
;
5705 case excel::XlConsolidationFunction::xlVarP
:
5706 aColumnsRange
[i
].Function
= sheet::GeneralFunction_VARP
;
5709 DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER
, {}) ;
5713 xSubDesc
->addNew(aColumns
, _nGroupBy
- 1);
5714 xSub
->applySubTotals(xSubDesc
, bDoReplace
);
5716 catch (const uno::Exception
&)
5718 DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED
, {});
5723 ScVbaRange::ExportAsFixedFormat(const css::uno::Any
& Type
, const css::uno::Any
& FileName
, const css::uno::Any
& Quality
,
5724 const css::uno::Any
& IncludeDocProperties
, const css::uno::Any
& /*IgnorePrintAreas*/, const css::uno::Any
& From
,
5725 const css::uno::Any
& To
, const css::uno::Any
& OpenAfterPublish
, const css::uno::Any
& /*FixedFormatExtClassPtr*/)
5727 ScCellRangesBase
* pUnoRangesBase
= getCellRangesBase();
5728 if (!pUnoRangesBase
)
5729 throw uno::RuntimeException(u
"Failed to access underlying uno range object"_ustr
);
5730 ScDocShell
* pShell
= pUnoRangesBase
->GetDocShell();
5734 uno::Reference
< frame::XModel
> xModel(pShell
->GetModel(), uno::UNO_SET_THROW
);
5735 uno::Reference
< excel::XApplication
> xApplication(Application(), uno::UNO_QUERY_THROW
);
5737 excel::ExportAsFixedFormatHelper(xModel
, xApplication
, Type
, FileName
, Quality
,
5738 IncludeDocProperties
, From
, To
, OpenAfterPublish
);
5742 ScVbaRange::getServiceImplName()
5744 return u
"ScVbaRange"_ustr
;
5747 uno::Sequence
< OUString
>
5748 ScVbaRange::getServiceNames()
5750 return { u
"ooo.vba.excel.Range"_ustr
};
5754 ScVbaRange::hasError()
5756 double dResult
= 0.0;
5757 uno::Reference
< excel::XApplication
> xApplication( Application(), uno::UNO_QUERY_THROW
);
5758 uno::Reference
< script::XInvocation
> xInvoc( xApplication
->WorksheetFunction(), uno::UNO_QUERY_THROW
);
5760 uno::Reference
< excel::XRange
> aRange( this );
5761 uno::Sequence
< uno::Any
> Params
{ uno::Any(aRange
) };
5762 uno::Sequence
< sal_Int16
> OutParamIndex
;
5763 uno::Sequence
< uno::Any
> OutParam
;
5764 xInvoc
->invoke( u
"IsError"_ustr
, Params
, OutParamIndex
, OutParam
) >>= dResult
;
5765 return dResult
> 0.0;
5769 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
5770 Calc_ScVbaRange_get_implementation(
5771 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const& args
)
5773 return cppu::acquire(new ScVbaRange(args
, context
));
5777 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */