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 .
19 #include "vbaworksheets.hxx"
21 #include <sfx2/viewfrm.hxx>
23 #include <cppuhelper/implbase.hxx>
25 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
26 #include <com/sun/star/container/XEnumerationAccess.hpp>
27 #include <com/sun/star/sheet/XSpreadsheet.hpp>
28 #include <com/sun/star/container/XNamed.hpp>
29 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
30 #include <com/sun/star/script/XTypeConverter.hpp>
32 #include <ooo/vba/excel/XApplication.hpp>
33 #include <tabvwsh.hxx>
35 #include "excelvbahelper.hxx"
36 #include "vbaworksheet.hxx"
37 #include <markdata.hxx>
41 #include <prevwsh.hxx>
42 #include <preview.hxx>
43 using namespace ::ooo::vba
;
44 using namespace ::com::sun::star
;
46 // a map ( or hashmap ) won't do as we need also to preserve the order
47 // (as added ) of the items
48 typedef std::vector
< uno::Reference
< sheet::XSpreadsheet
> > SheetMap
;
50 // #FIXME #TODO the implementation of the Sheets collections sucks,
51 // e.g. there is no support for tracking sheets added/removed from the collection
55 class WorkSheetsEnumeration
: public ::cppu::WeakImplHelper
< container::XEnumeration
>
58 SheetMap::iterator mIt
;
60 explicit WorkSheetsEnumeration( SheetMap
&& sMap
) : mSheetMap( std::move(sMap
) ), mIt( mSheetMap
.begin() ) {}
61 virtual sal_Bool SAL_CALL
hasMoreElements( ) override
63 return ( mIt
!= mSheetMap
.end() );
65 virtual uno::Any SAL_CALL
nextElement( ) override
67 if ( !hasMoreElements() )
68 throw container::NoSuchElementException();
69 uno::Reference
< sheet::XSpreadsheet
> xSheet( *mIt
++ );
70 return uno::Any( xSheet
) ;
74 class SheetCollectionHelper
: public ::cppu::WeakImplHelper
< container::XNameAccess
,
75 container::XIndexAccess
,
76 container::XEnumerationAccess
>
79 SheetMap::iterator cachePos
;
81 explicit SheetCollectionHelper( SheetMap
&& sMap
) : mSheetMap( std::move(sMap
) ), cachePos(mSheetMap
.begin()) {}
83 virtual uno::Type SAL_CALL
getElementType( ) override
{ return cppu::UnoType
<sheet::XSpreadsheet
>::get(); }
84 virtual sal_Bool SAL_CALL
hasElements( ) override
{ return ( !mSheetMap
.empty() ); }
86 virtual uno::Any SAL_CALL
getByName( const OUString
& aName
) override
88 if ( !hasByName(aName
) )
89 throw container::NoSuchElementException();
90 return uno::Any( *cachePos
);
92 virtual uno::Sequence
< OUString
> SAL_CALL
getElementNames( ) override
94 uno::Sequence
< OUString
> sNames( mSheetMap
.size() );
95 OUString
* pString
= sNames
.getArray();
97 for ( const auto& rItem
: mSheetMap
)
99 uno::Reference
< container::XNamed
> xName( rItem
, uno::UNO_QUERY_THROW
);
100 *pString
= xName
->getName();
105 virtual sal_Bool SAL_CALL
hasByName( const OUString
& aName
) override
107 cachePos
= mSheetMap
.begin();
108 SheetMap::iterator it_end
= mSheetMap
.end();
109 for ( ; cachePos
!= it_end
; ++cachePos
)
111 uno::Reference
< container::XNamed
> xName( *cachePos
, uno::UNO_QUERY_THROW
);
112 if ( aName
== xName
->getName() )
115 return ( cachePos
!= it_end
);
119 virtual ::sal_Int32 SAL_CALL
getCount( ) override
{ return mSheetMap
.size(); }
120 virtual uno::Any SAL_CALL
getByIndex( ::sal_Int32 Index
) override
122 if ( Index
< 0 || Index
>= getCount() )
123 throw lang::IndexOutOfBoundsException();
125 return uno::Any( mSheetMap
[ Index
] );
128 // XEnumerationAccess
129 virtual uno::Reference
< container::XEnumeration
> SAL_CALL
createEnumeration( ) override
131 return new WorkSheetsEnumeration( std::vector(mSheetMap
) );
135 class SheetsEnumeration
: public EnumerationHelperImpl
137 uno::Reference
< frame::XModel
> m_xModel
;
139 /// @throws uno::RuntimeException
140 SheetsEnumeration( const uno::Reference
< XHelperInterface
>& xParent
, const uno::Reference
< uno::XComponentContext
>& xContext
, const uno::Reference
< container::XEnumeration
>& xEnumeration
, uno::Reference
< frame::XModel
> xModel
) : EnumerationHelperImpl( xParent
, xContext
, xEnumeration
), m_xModel(std::move( xModel
)) {}
142 virtual uno::Any SAL_CALL
nextElement( ) override
144 uno::Reference
< sheet::XSpreadsheet
> xSheet( m_xEnumeration
->nextElement(), uno::UNO_QUERY_THROW
);
145 uno::Reference
< XHelperInterface
> xIf
= excel::getUnoSheetModuleObj( xSheet
);
149 // if the Sheet is in a document created by the api unfortunately ( at the
150 // moment, it actually won't have the special Document modules
151 uno::Reference
< excel::XWorksheet
> xNewSheet( new ScVbaWorksheet( m_xParent
, m_xContext
, xSheet
, m_xModel
) );
163 ScVbaWorksheets::ScVbaWorksheets( const uno::Reference
< XHelperInterface
>& xParent
, const uno::Reference
< css::uno::XComponentContext
> & xContext
, const uno::Reference
< container::XIndexAccess
>& xSheets
, uno::Reference
< frame::XModel
> xModel
): ScVbaWorksheets_BASE( xParent
, xContext
, xSheets
), mxModel(std::move( xModel
)), m_xSheets( uno::Reference
< sheet::XSpreadsheets
>( xSheets
, uno::UNO_QUERY
) )
167 ScVbaWorksheets::ScVbaWorksheets( const uno::Reference
< XHelperInterface
>& xParent
, const uno::Reference
< css::uno::XComponentContext
> & xContext
, const uno::Reference
< container::XEnumerationAccess
>& xEnumAccess
, uno::Reference
< frame::XModel
> xModel
): ScVbaWorksheets_BASE( xParent
, xContext
, uno::Reference
< container::XIndexAccess
>( xEnumAccess
, uno::UNO_QUERY
) ), mxModel(std::move(xModel
))
171 // XEnumerationAccess
173 ScVbaWorksheets::getElementType()
175 return cppu::UnoType
<excel::XWorksheet
>::get();
178 uno::Reference
< container::XEnumeration
>
179 ScVbaWorksheets::createEnumeration()
181 if ( !m_xSheets
.is() )
183 uno::Reference
< container::XEnumerationAccess
> xAccess( m_xIndexAccess
, uno::UNO_QUERY_THROW
);
184 return xAccess
->createEnumeration();
186 uno::Reference
< container::XEnumerationAccess
> xEnumAccess( m_xSheets
, uno::UNO_QUERY_THROW
);
187 return new SheetsEnumeration( this, mxContext
, xEnumAccess
->createEnumeration(), mxModel
);
191 ScVbaWorksheets::createCollectionObject( const uno::Any
& aSource
)
193 uno::Reference
< sheet::XSpreadsheet
> xSheet( aSource
, uno::UNO_QUERY
);
194 uno::Reference
< XHelperInterface
> xIf
= excel::getUnoSheetModuleObj( xSheet
);
198 // if the Sheet is in a document created by the api unfortunately ( at the
199 // moment, it actually won't have the special Document modules
200 uno::Reference
< excel::XWorksheet
> xNewSheet( new ScVbaWorksheet( getParent(), mxContext
, xSheet
, mxModel
) );
210 ScVbaWorksheets::Add( const uno::Any
& Before
, const uno::Any
& After
,
211 const uno::Any
& Count
, const uno::Any
& Type
)
213 if ( isSelectedSheets() )
214 return uno::Any(); // or should we throw?
216 OUString aStringSheet
;
218 SCTAB nSheetIndex
= 0;
219 SCTAB nNewSheets
= 1, nType
= 0;
220 Count
>>= nNewSheets
;
224 uno::Reference
< excel::XWorksheet
> xBeforeAfterSheet
;
226 if ( Before
.hasValue() )
228 if ( Before
>>= xBeforeAfterSheet
)
229 aStringSheet
= xBeforeAfterSheet
->getName();
231 Before
>>= aStringSheet
;
234 if (aStringSheet
.isEmpty() && After
.hasValue() )
236 if ( After
>>= xBeforeAfterSheet
)
237 aStringSheet
= xBeforeAfterSheet
->getName();
239 After
>>= aStringSheet
;
242 if (aStringSheet
.isEmpty())
244 uno::Reference
< excel::XApplication
> xApplication( Application(), uno::UNO_QUERY_THROW
);
245 aStringSheet
= xApplication
->getActiveWorkbook()->getActiveSheet()->getName();
248 nCount
= static_cast< SCTAB
>( m_xIndexAccess
->getCount() );
249 for (SCTAB i
=0; i
< nCount
; i
++)
251 uno::Reference
< sheet::XSpreadsheet
> xSheet(m_xIndexAccess
->getByIndex(i
), uno::UNO_QUERY
);
252 uno::Reference
< container::XNamed
> xNamed( xSheet
, uno::UNO_QUERY_THROW
);
253 if (xNamed
->getName() == aStringSheet
)
263 SCTAB nSheetName
= nCount
+ 1;
264 OUString
aStringBase( u
"Sheet"_ustr
);
266 for (SCTAB i
=0; i
< nNewSheets
; i
++, nSheetName
++)
268 OUString aStringName
= aStringBase
+ OUString::number(nSheetName
);
269 while (m_xNameAccess
->hasByName(aStringName
))
272 aStringName
= aStringBase
+ OUString::number(nSheetName
);
274 m_xSheets
->insertNewByName(aStringName
, nSheetIndex
+ i
);
275 result
= getItemByStringIndex( aStringName
);
277 uno::Reference
< excel::XWorksheet
> xNewSheet( result
, uno::UNO_QUERY
);
278 if ( xNewSheet
.is() )
279 xNewSheet
->Activate();
284 ScVbaWorksheets::Delete()
286 // #TODO #INVESTIGATE
287 // mmm this method could be trouble if the underlying
288 // uno objects ( the m_xIndexAccess etc ) aren't aware of the
289 // contents that are deleted
290 sal_Int32 nElems
= getCount();
291 for ( sal_Int32 nItem
= 1; nItem
<= nElems
; ++nItem
)
293 uno::Reference
< excel::XWorksheet
> xSheet( Item( uno::Any( nItem
), uno::Any() ), uno::UNO_QUERY_THROW
);
299 ScVbaWorksheets::isSelectedSheets() const
301 return !m_xSheets
.is();
305 ScVbaWorksheets::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
)
309 bool bSelection
= false;
313 if ( !( nFrom
|| nTo
) )
314 if ( isSelectedSheets() )
317 PrintOutHelper( excel::getBestViewShell( mxModel
), From
, To
, Copies
, Preview
, ActivePrinter
, PrintToFile
, Collate
, PrToFileName
, bSelection
);
321 ScVbaWorksheets::getVisible()
323 bool bVisible
= true;
324 uno::Reference
< container::XEnumeration
> xEnum( createEnumeration(), uno::UNO_SET_THROW
);
325 while ( xEnum
->hasMoreElements() )
327 uno::Reference
< excel::XWorksheet
> xSheet( xEnum
->nextElement(), uno::UNO_QUERY_THROW
);
328 if ( xSheet
->getVisible() == 0 )
334 return uno::Any( bVisible
);
338 ScVbaWorksheets::setVisible( const uno::Any
& _visible
)
341 if ( !(_visible
>>= bState
) )
342 throw uno::RuntimeException(u
"Visible property doesn't support non boolean #FIXME"_ustr
);
344 uno::Reference
< container::XEnumeration
> xEnum( createEnumeration(), uno::UNO_SET_THROW
);
345 while ( xEnum
->hasMoreElements() )
347 uno::Reference
< excel::XWorksheet
> xSheet( xEnum
->nextElement(), uno::UNO_QUERY_THROW
);
348 xSheet
->setVisible( bState
? 1 : 0 );
354 ScVbaWorksheets::Select( const uno::Any
& Replace
)
356 ScTabViewShell
* pViewShell
= excel::getBestViewShell( mxModel
);
358 throw uno::RuntimeException(u
"Cannot obtain view shell"_ustr
);
360 ScMarkData
& rMarkData
= pViewShell
->GetViewData().GetMarkData();
361 bool bReplace
= true;
362 Replace
>>= bReplace
;
363 // Replace is defaulted to True, meaning this current collection
364 // becomes the Selection, if it were false then the current selection would
366 bool bSelectSingle
= bReplace
;
367 sal_Int32 nElems
= getCount();
368 for ( sal_Int32 nItem
= 1; nItem
<= nElems
; ++nItem
)
370 uno::Reference
< excel::XWorksheet
> xSheet( Item( uno::Any( nItem
), uno::Any() ), uno::UNO_QUERY_THROW
);
371 ScVbaWorksheet
* pSheet
= excel::getImplFromDocModuleWrapper
<ScVbaWorksheet
>( xSheet
);
374 rMarkData
.SelectOneTable( static_cast< SCTAB
>( pSheet
->getSheetID() ) );
375 bSelectSingle
= false;
378 rMarkData
.SelectTable( static_cast< SCTAB
>( pSheet
->getSheetID() ), true );
384 ScVbaWorksheets::Copy ( const uno::Any
& Before
, const uno::Any
& After
)
386 uno::Reference
<excel::XWorksheet
> xSheet
;
387 sal_Int32 nElems
= getCount();
388 bool bAfter
= After
.hasValue();
389 std::vector
< uno::Reference
< excel::XWorksheet
> > Sheets
;
392 for ( nItem
= 1; nItem
<= nElems
; ++nItem
)
394 uno::Reference
<excel::XWorksheet
> xWorksheet(Item( uno::Any( nItem
), uno::Any() ), uno::UNO_QUERY_THROW
);
395 Sheets
.push_back(xWorksheet
);
397 bool bNewDoc
= (!(Before
>>= xSheet
) && !(After
>>=xSheet
)&& !(Before
.hasValue()) && !(After
.hasValue()));
399 uno::Reference
< excel::XWorksheet
> xSrcSheet
;
403 xSrcSheet
= Sheets
.at(0);
404 ScVbaWorksheet
* pSrcSheet
= excel::getImplFromDocModuleWrapper
<ScVbaWorksheet
>( xSrcSheet
);
405 xSheet
= pSrcSheet
->createSheetCopyInNewDoc(xSrcSheet
->getName());
413 for (; nItem
< nElems
; ++nItem
)
415 xSrcSheet
= Sheets
[nItem
];
416 ScVbaWorksheet
* pSrcSheet
= excel::getImplFromDocModuleWrapper
<ScVbaWorksheet
>( xSrcSheet
);
418 xSheet
= pSrcSheet
->createSheetCopy(xSheet
, bAfter
);
420 pSrcSheet
->createSheetCopy(xSheet
, bAfter
);
424 //ScVbaCollectionBaseImpl
426 ScVbaWorksheets::Item(const uno::Any
& Index
, const uno::Any
& Index2
)
428 if ( Index
.getValueTypeClass() == uno::TypeClass_SEQUENCE
)
430 const uno::Reference
< script::XTypeConverter
>& xConverter
= getTypeConverter(mxContext
);
431 uno::Any aConverted
= xConverter
->convertTo( Index
, cppu::UnoType
<uno::Sequence
< uno::Any
>>::get() );
433 uno::Sequence
< uno::Any
> sIndices
;
434 aConverted
>>= sIndices
;
435 for (const auto& rIndex
: sIndices
)
437 uno::Reference
< excel::XWorksheet
> xWorkSheet( ScVbaWorksheets_BASE::Item( rIndex
, Index2
), uno::UNO_QUERY_THROW
);
438 ScVbaWorksheet
* pWorkSheet
= excel::getImplFromDocModuleWrapper
<ScVbaWorksheet
>( xWorkSheet
);
439 uno::Reference
< sheet::XSpreadsheet
> xSheet( pWorkSheet
->getSheet() , uno::UNO_SET_THROW
);
440 uno::Reference
< container::XNamed
> xName( xSheet
, uno::UNO_QUERY_THROW
);
441 aSheets
.push_back( xSheet
);
443 uno::Reference
< container::XIndexAccess
> xIndexAccess
= new SheetCollectionHelper( std::move(aSheets
) );
444 uno::Reference
< XCollection
> xSelectedSheets( new ScVbaWorksheets( getParent(), mxContext
, xIndexAccess
, mxModel
) );
445 return uno::Any( xSelectedSheets
);
447 return ScVbaWorksheets_BASE::Item( Index
, Index2
);
451 ScVbaWorksheets::getServiceImplName()
453 return u
"ScVbaWorksheets"_ustr
;
456 css::uno::Sequence
<OUString
>
457 ScVbaWorksheets::getServiceNames()
459 static uno::Sequence
< OUString
> const sNames
461 u
"ooo.vba.excel.Worksheets"_ustr
466 bool ScVbaWorksheets::nameExists( const uno::Reference
<sheet::XSpreadsheetDocument
>& xSpreadDoc
, std::u16string_view name
, SCTAB
& nTab
)
468 if (!xSpreadDoc
.is())
469 throw lang::IllegalArgumentException( u
"nameExists() xSpreadDoc is null"_ustr
, uno::Reference
< uno::XInterface
>(), 1 );
470 uno::Reference
<container::XIndexAccess
> xIndex( xSpreadDoc
->getSheets(), uno::UNO_QUERY
);
473 SCTAB nCount
= static_cast< SCTAB
>( xIndex
->getCount() );
474 for (SCTAB i
=0; i
< nCount
; i
++)
476 uno::Reference
< container::XNamed
> xNamed( xIndex
->getByIndex(i
), uno::UNO_QUERY_THROW
);
477 if (xNamed
->getName() == name
)
487 void ScVbaWorksheets::PrintPreview( const css::uno::Any
& /*EnableChanges*/ )
489 // need test, print preview current active sheet
490 // !! TODO !! get view shell from controller
491 ScTabViewShell
* pViewShell
= excel::getBestViewShell( mxModel
);
492 SfxViewFrame
* pViewFrame
= nullptr;
494 pViewFrame
= &pViewShell
->GetViewFrame();
498 if ( pViewFrame
->GetFrame().IsInPlace() )
501 dispatchExecute( pViewShell
, SID_VIEWSHELL1
);
502 SfxViewShell
* pShell
= SfxViewShell::Get( pViewFrame
->GetFrame().GetFrameInterface()->getController() );
504 ScPreviewShell
* pPrvShell
= dynamic_cast< ScPreviewShell
* >( pShell
);
508 ScPreview
* pPrvView
= pPrvShell
->GetPreview();
509 const ScDocument
& rDoc
= pViewShell
->GetViewData().GetDocument();
510 ScMarkData
aMarkData(rDoc
.GetSheetLimits());
511 sal_Int32 nElems
= getCount();
512 for ( sal_Int32 nItem
= 1; nItem
<= nElems
; ++nItem
)
514 uno::Reference
< excel::XWorksheet
> xSheet( Item( uno::Any( nItem
), uno::Any() ), uno::UNO_QUERY_THROW
);
515 ScVbaWorksheet
* pSheet
= excel::getImplFromDocModuleWrapper
<ScVbaWorksheet
>( xSheet
);
517 aMarkData
.SelectTable(static_cast< SCTAB
>( pSheet
->getSheetID() ), true );
519 // save old selection, setting the selectedtabs in the preview
520 // can affect the current selection when preview has been
522 ScMarkData::MarkedTabsType aOldTabs
= pPrvView
->GetSelectedTabs();
523 pPrvView
->SetSelectedTabs( aMarkData
);
525 pPrvView
->DataChanged(false);
526 // set sensible first page
527 tools::Long nPage
= pPrvView
->GetFirstPage( 1 );
528 pPrvView
->SetPageNo( nPage
);
529 WaitUntilPreviewIsClosed( pViewFrame
);
530 // restore old tab selection
531 pViewShell
= excel::getBestViewShell( mxModel
);
532 pViewShell
->GetViewData().GetMarkData().SetSelectedTabs(aOldTabs
);
536 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */