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/dispatch.hxx>
22 #include <sfx2/app.hxx>
23 #include <sfx2/bindings.hxx>
24 #include <sfx2/request.hxx>
25 #include <sfx2/viewfrm.hxx>
26 #include <sfx2/itemwrapper.hxx>
27 #include <svl/itemset.hxx>
28 #include <svl/eitem.hxx>
30 #include <comphelper/processfactory.hxx>
31 #include <cppuhelper/implbase3.hxx>
33 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
34 #include <com/sun/star/container/XEnumerationAccess.hpp>
35 #include <com/sun/star/sheet/XSpreadsheetView.hpp>
36 #include <com/sun/star/container/XNamed.hpp>
37 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <ooo/vba/excel/XApplication.hpp>
41 #include "tabvwsh.hxx"
43 #include "vbaglobals.hxx"
44 #include "vbaworksheet.hxx"
45 #include "vbaworkbook.hxx"
46 #include "unonames.hxx"
47 #include "markdata.hxx"
50 #include "prevwsh.hxx"
51 #include "preview.hxx"
52 using namespace ::ooo::vba
;
53 using namespace ::com::sun::star
;
56 typedef ::cppu::WeakImplHelper1
< container::XEnumeration
> SheetEnumeration_BASE
;
57 typedef ::cppu::WeakImplHelper3
< container::XNameAccess
, container::XIndexAccess
, container::XEnumerationAccess
> SheetCollectionHelper_BASE
;
58 // a map ( or hashmap ) wont do as we need also to preserve the order
59 // (as added ) of the items
60 typedef std::vector
< uno::Reference
< sheet::XSpreadsheet
> > SheetMap
;
63 // #FIXME #TODO the implementation of the Sheets collections sucks,
64 // e.g. there is no support for tracking sheets added/removed from the collection
66 class WorkSheetsEnumeration
: public SheetEnumeration_BASE
69 SheetMap::iterator mIt
;
71 WorkSheetsEnumeration( const SheetMap
& sMap
) : mSheetMap( sMap
), mIt( mSheetMap
.begin() ) {}
72 virtual ::sal_Bool SAL_CALL
hasMoreElements( ) throw (uno::RuntimeException
)
74 return ( mIt
!= mSheetMap
.end() );
76 virtual uno::Any SAL_CALL
nextElement( ) throw (container::NoSuchElementException
, lang::WrappedTargetException
, uno::RuntimeException
)
78 if ( !hasMoreElements() )
79 throw container::NoSuchElementException();
80 uno::Reference
< sheet::XSpreadsheet
> xSheet( *mIt
++ );
81 return uno::makeAny( xSheet
) ;
85 class SheetCollectionHelper
: public SheetCollectionHelper_BASE
88 SheetMap::iterator cachePos
;
90 SheetCollectionHelper( const SheetMap
& sMap
) : mSheetMap( sMap
), cachePos(mSheetMap
.begin()) {}
92 virtual uno::Type SAL_CALL
getElementType( ) throw (uno::RuntimeException
) { return sheet::XSpreadsheet::static_type(0); }
93 virtual ::sal_Bool SAL_CALL
hasElements( ) throw (uno::RuntimeException
) { return ( !mSheetMap
.empty() ); }
95 virtual uno::Any SAL_CALL
getByName( const OUString
& aName
) throw (container::NoSuchElementException
, lang::WrappedTargetException
, uno::RuntimeException
)
97 if ( !hasByName(aName
) )
98 throw container::NoSuchElementException();
99 return uno::makeAny( *cachePos
);
101 virtual uno::Sequence
< OUString
> SAL_CALL
getElementNames( ) throw (uno::RuntimeException
)
103 uno::Sequence
< OUString
> sNames( mSheetMap
.size() );
104 OUString
* pString
= sNames
.getArray();
105 SheetMap::iterator it
= mSheetMap
.begin();
106 SheetMap::iterator it_end
= mSheetMap
.end();
108 for ( ; it
!= it_end
; ++it
, ++pString
)
110 uno::Reference
< container::XNamed
> xName( *it
, uno::UNO_QUERY_THROW
);
111 *pString
= xName
->getName();
115 virtual ::sal_Bool SAL_CALL
hasByName( const OUString
& aName
) throw (uno::RuntimeException
)
117 cachePos
= mSheetMap
.begin();
118 SheetMap::iterator it_end
= mSheetMap
.end();
119 for ( ; cachePos
!= it_end
; ++cachePos
)
121 uno::Reference
< container::XNamed
> xName( *cachePos
, uno::UNO_QUERY_THROW
);
122 if ( aName
.equals( xName
->getName() ) )
125 return ( cachePos
!= it_end
);
129 virtual ::sal_Int32 SAL_CALL
getCount( ) throw (uno::RuntimeException
) { return mSheetMap
.size(); }
130 virtual uno::Any SAL_CALL
getByIndex( ::sal_Int32 Index
) throw (lang::IndexOutOfBoundsException
, lang::WrappedTargetException
, uno::RuntimeException
)
132 if ( Index
< 0 || Index
>= getCount() )
133 throw lang::IndexOutOfBoundsException();
135 return uno::makeAny( mSheetMap
[ Index
] );
138 // XEnumerationAccess
139 virtual uno::Reference
< container::XEnumeration
> SAL_CALL
createEnumeration( ) throw (uno::RuntimeException
)
141 return new WorkSheetsEnumeration( mSheetMap
);
145 class SheetsEnumeration
: public EnumerationHelperImpl
147 uno::Reference
< frame::XModel
> m_xModel
;
149 SheetsEnumeration( const uno::Reference
< XHelperInterface
>& xParent
, const uno::Reference
< uno::XComponentContext
>& xContext
, const uno::Reference
< container::XEnumeration
>& xEnumeration
, const uno::Reference
< frame::XModel
>& xModel
) throw ( uno::RuntimeException
) : EnumerationHelperImpl( xParent
, xContext
, xEnumeration
), m_xModel( xModel
) {}
151 virtual uno::Any SAL_CALL
nextElement( ) throw (container::NoSuchElementException
, lang::WrappedTargetException
, uno::RuntimeException
)
153 uno::Reference
< sheet::XSpreadsheet
> xSheet( m_xEnumeration
->nextElement(), uno::UNO_QUERY_THROW
);
154 uno::Reference
< XHelperInterface
> xIf
= excel::getUnoSheetModuleObj( xSheet
);
158 // if the Sheet is in a document created by the api unfortunately ( at the
159 // moment, it actually wont have the special Document modules
160 uno::Reference
< excel::XWorksheet
> xNewSheet( new ScVbaWorksheet( m_xParent
, m_xContext
, xSheet
, m_xModel
) );
170 ScVbaWorksheets::ScVbaWorksheets( const uno::Reference
< XHelperInterface
>& xParent
, const uno::Reference
< ::com::sun::star::uno::XComponentContext
> & xContext
, const uno::Reference
< container::XIndexAccess
>& xSheets
, const uno::Reference
< frame::XModel
>& xModel
): ScVbaWorksheets_BASE( xParent
, xContext
, xSheets
), mxModel( xModel
), m_xSheets( uno::Reference
< sheet::XSpreadsheets
>( xSheets
, uno::UNO_QUERY
) )
174 ScVbaWorksheets::ScVbaWorksheets( const uno::Reference
< XHelperInterface
>& xParent
, const uno::Reference
< ::com::sun::star::uno::XComponentContext
> & xContext
, const uno::Reference
< container::XEnumerationAccess
>& xEnumAccess
, const uno::Reference
< frame::XModel
>& xModel
): ScVbaWorksheets_BASE( xParent
, xContext
, uno::Reference
< container::XIndexAccess
>( xEnumAccess
, uno::UNO_QUERY
) ), mxModel(xModel
)
178 // XEnumerationAccess
180 ScVbaWorksheets::getElementType() throw (uno::RuntimeException
)
182 return excel::XWorksheet::static_type(0);
185 uno::Reference
< container::XEnumeration
>
186 ScVbaWorksheets::createEnumeration() throw (uno::RuntimeException
)
188 if ( !m_xSheets
.is() )
190 uno::Reference
< container::XEnumerationAccess
> xAccess( m_xIndexAccess
, uno::UNO_QUERY_THROW
);
191 return xAccess
->createEnumeration();
193 uno::Reference
< container::XEnumerationAccess
> xEnumAccess( m_xSheets
, uno::UNO_QUERY_THROW
);
194 return new SheetsEnumeration( this, mxContext
, xEnumAccess
->createEnumeration(), mxModel
);
198 ScVbaWorksheets::createCollectionObject( const uno::Any
& aSource
)
200 uno::Reference
< sheet::XSpreadsheet
> xSheet( aSource
, uno::UNO_QUERY
);
201 uno::Reference
< XHelperInterface
> xIf
= excel::getUnoSheetModuleObj( xSheet
);
205 // if the Sheet is in a document created by the api unfortunately ( at the
206 // moment, it actually wont have the special Document modules
207 uno::Reference
< excel::XWorksheet
> xNewSheet( new ScVbaWorksheet( getParent(), mxContext
, xSheet
, mxModel
) );
217 ScVbaWorksheets::Add( const uno::Any
& Before
, const uno::Any
& After
,
218 const uno::Any
& Count
, const uno::Any
& Type
) throw (uno::RuntimeException
)
220 if ( isSelectedSheets() )
221 return uno::Any(); // or should we throw?
223 OUString aStringSheet
;
224 sal_Bool
bBefore(sal_True
);
225 SCTAB nSheetIndex
= 0;
226 SCTAB nNewSheets
= 1, nType
= 0;
227 Count
>>= nNewSheets
;
231 uno::Reference
< excel::XWorksheet
> xBeforeAfterSheet
;
233 if ( Before
.hasValue() )
235 if ( Before
>>= xBeforeAfterSheet
)
236 aStringSheet
= xBeforeAfterSheet
->getName();
238 Before
>>= aStringSheet
;
241 if (aStringSheet
.isEmpty() && After
.hasValue() )
243 if ( After
>>= xBeforeAfterSheet
)
244 aStringSheet
= xBeforeAfterSheet
->getName();
246 After
>>= aStringSheet
;
249 if (aStringSheet
.isEmpty())
251 uno::Reference
< excel::XApplication
> xApplication( Application(), uno::UNO_QUERY_THROW
);
252 aStringSheet
= xApplication
->getActiveWorkbook()->getActiveSheet()->getName();
255 nCount
= static_cast< SCTAB
>( m_xIndexAccess
->getCount() );
256 for (SCTAB i
=0; i
< nCount
; i
++)
258 uno::Reference
< sheet::XSpreadsheet
> xSheet(m_xIndexAccess
->getByIndex(i
), uno::UNO_QUERY
);
259 uno::Reference
< container::XNamed
> xNamed( xSheet
, uno::UNO_QUERY_THROW
);
260 if (xNamed
->getName() == aStringSheet
)
270 SCTAB nSheetName
= nCount
+ 1L;
271 OUString
aStringBase( "Sheet" );
273 for (SCTAB i
=0; i
< nNewSheets
; i
++, nSheetName
++)
275 OUString aStringName
= aStringBase
+ OUString::number(nSheetName
);
276 while (m_xNameAccess
->hasByName(aStringName
))
279 aStringName
= aStringBase
+ OUString::number(nSheetName
);
281 m_xSheets
->insertNewByName(aStringName
, nSheetIndex
+ i
);
282 result
= getItemByStringIndex( aStringName
);
284 uno::Reference
< excel::XWorksheet
> xNewSheet( result
, uno::UNO_QUERY
);
285 if ( xNewSheet
.is() )
286 xNewSheet
->Activate();
291 ScVbaWorksheets::Delete() throw (uno::RuntimeException
)
293 // #TODO #INVESTIGATE
294 // mmm this method could be trouble if the underlying
295 // uno objects ( the m_xIndexAccess etc ) aren't aware of the
296 // contents that are deleted
297 sal_Int32 nElems
= getCount();
298 for ( sal_Int32 nItem
= 1; nItem
<= nElems
; ++nItem
)
300 uno::Reference
< excel::XWorksheet
> xSheet( Item( uno::makeAny( nItem
), uno::Any() ), uno::UNO_QUERY_THROW
);
306 ScVbaWorksheets::isSelectedSheets()
308 return !m_xSheets
.is();
312 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
) throw (uno::RuntimeException
)
316 sal_Int16 nCopies
= 1;
317 sal_Bool bCollate
= false;
318 sal_Bool bSelection
= false;
322 if ( nCopies
> 1 ) // Collate only useful when more that 1 copy
323 Collate
>>= bCollate
;
325 if ( !( nFrom
|| nTo
) )
326 if ( isSelectedSheets() )
327 bSelection
= sal_True
;
329 PrintOutHelper( excel::getBestViewShell( mxModel
), From
, To
, Copies
, Preview
, ActivePrinter
, PrintToFile
, Collate
, PrToFileName
, bSelection
);
333 ScVbaWorksheets::getVisible() throw (uno::RuntimeException
)
335 sal_Bool bVisible
= sal_True
;
336 uno::Reference
< container::XEnumeration
> xEnum( createEnumeration(), uno::UNO_QUERY_THROW
);
337 while ( xEnum
->hasMoreElements() )
339 uno::Reference
< excel::XWorksheet
> xSheet( xEnum
->nextElement(), uno::UNO_QUERY_THROW
);
340 if ( xSheet
->getVisible() == false )
346 return uno::makeAny( bVisible
);
350 ScVbaWorksheets::setVisible( const uno::Any
& _visible
) throw (uno::RuntimeException
)
352 sal_Bool bState
= false;
353 if ( _visible
>>= bState
)
355 uno::Reference
< container::XEnumeration
> xEnum( createEnumeration(), uno::UNO_QUERY_THROW
);
356 while ( xEnum
->hasMoreElements() )
358 uno::Reference
< excel::XWorksheet
> xSheet( xEnum
->nextElement(), uno::UNO_QUERY_THROW
);
359 xSheet
->setVisible( bState
);
363 throw uno::RuntimeException("Visible property doesn't support non boolean #FIXME", uno::Reference
< uno::XInterface
>() );
367 ScVbaWorksheets::Select( const uno::Any
& Replace
) throw (uno::RuntimeException
)
369 ScTabViewShell
* pViewShell
= excel::getBestViewShell( mxModel
);
371 throw uno::RuntimeException("Cannot obtain view shell", uno::Reference
< uno::XInterface
>() );
373 ScMarkData
& rMarkData
= pViewShell
->GetViewData()->GetMarkData();
374 sal_Bool bReplace
= sal_True
;
375 Replace
>>= bReplace
;
376 // Replace is defaulted to True, meanining this current collection
377 // becomes the Selection, if it were false then the current selection would
379 bool bSelectSingle
= bReplace
;
380 sal_Int32 nElems
= getCount();
381 for ( sal_Int32 nItem
= 1; nItem
<= nElems
; ++nItem
)
383 uno::Reference
< excel::XWorksheet
> xSheet( Item( uno::makeAny( nItem
), uno::Any() ), uno::UNO_QUERY_THROW
);
384 ScVbaWorksheet
* pSheet
= excel::getImplFromDocModuleWrapper
<ScVbaWorksheet
>( xSheet
);
387 rMarkData
.SelectOneTable( static_cast< SCTAB
>( pSheet
->getSheetID() ) );
388 bSelectSingle
= false;
391 rMarkData
.SelectTable( static_cast< SCTAB
>( pSheet
->getSheetID() ), sal_True
);
398 ScVbaWorksheets::Copy ( const uno::Any
& Before
, const uno::Any
& After
) throw (css::uno::RuntimeException
)
400 uno::Reference
<excel::XWorksheet
> xSheet
;
401 sal_Int32 nElems
= getCount();
402 bool bAfter
= After
.hasValue();
403 std::vector
< uno::Reference
< excel::XWorksheet
> > Sheets
;
406 for ( nItem
= 1; nItem
<= nElems
; ++nItem
)
408 uno::Reference
<excel::XWorksheet
> xWorksheet(Item( uno::makeAny( nItem
), uno::Any() ), uno::UNO_QUERY_THROW
);
409 Sheets
.push_back(xWorksheet
);
411 bool bNewDoc
= (!(Before
>>= xSheet
) && !(After
>>=xSheet
)&& !(Before
.hasValue()) && !(After
.hasValue()));
413 uno::Reference
< excel::XWorksheet
> xSrcSheet
;
417 xSrcSheet
= Sheets
.at(0);
418 ScVbaWorksheet
* pSrcSheet
= excel::getImplFromDocModuleWrapper
<ScVbaWorksheet
>( xSrcSheet
);
419 xSheet
= pSrcSheet
->createSheetCopyInNewDoc(xSrcSheet
->getName());
427 for (; nItem
< nElems
; ++nItem
)
429 xSrcSheet
= Sheets
[nItem
];
430 ScVbaWorksheet
* pSrcSheet
= excel::getImplFromDocModuleWrapper
<ScVbaWorksheet
>( xSrcSheet
);
432 xSheet
= pSrcSheet
->createSheetCopy(xSheet
, bAfter
);
434 pSrcSheet
->createSheetCopy(xSheet
, bAfter
);
438 //ScVbaCollectionBaseImpl
440 ScVbaWorksheets::Item( const uno::Any
& Index
, const uno::Any
& Index2
) throw (uno::RuntimeException
)
442 if ( Index
.getValueTypeClass() == uno::TypeClass_SEQUENCE
)
444 uno::Reference
< script::XTypeConverter
> xConverter
= getTypeConverter(mxContext
);
446 aConverted
= xConverter
->convertTo( Index
, getCppuType((uno::Sequence
< uno::Any
>*)0) );
448 uno::Sequence
< uno::Any
> sIndices
;
449 aConverted
>>= sIndices
;
450 sal_Int32 nElems
= sIndices
.getLength();
451 for( sal_Int32 index
= 0; index
< nElems
; ++index
)
453 uno::Reference
< excel::XWorksheet
> xWorkSheet( ScVbaWorksheets_BASE::Item( sIndices
[ index
], Index2
), uno::UNO_QUERY_THROW
);
454 ScVbaWorksheet
* pWorkSheet
= excel::getImplFromDocModuleWrapper
<ScVbaWorksheet
>( xWorkSheet
);
455 uno::Reference
< sheet::XSpreadsheet
> xSheet( pWorkSheet
->getSheet() , uno::UNO_QUERY_THROW
);
456 uno::Reference
< container::XNamed
> xName( xSheet
, uno::UNO_QUERY_THROW
);
457 mSheets
.push_back( xSheet
);
459 uno::Reference
< container::XIndexAccess
> xIndexAccess
= new SheetCollectionHelper( mSheets
);
460 uno::Reference
< XCollection
> xSelectedSheets( new ScVbaWorksheets( this->getParent(), mxContext
, xIndexAccess
, mxModel
) );
461 return uno::makeAny( xSelectedSheets
);
463 return ScVbaWorksheets_BASE::Item( Index
, Index2
);
467 ScVbaWorksheets::getItemByStringIndex( const OUString
& sIndex
) throw (uno::RuntimeException
)
469 return ScVbaWorksheets_BASE::getItemByStringIndex( sIndex
);
473 ScVbaWorksheets::getServiceImplName()
475 return OUString("ScVbaWorksheets");
478 css::uno::Sequence
<OUString
>
479 ScVbaWorksheets::getServiceNames()
481 static uno::Sequence
< OUString
> sNames
;
482 if ( sNames
.getLength() == 0 )
485 sNames
[0] = "ooo.vba.excel.Worksheets";
490 bool ScVbaWorksheets::nameExists( uno::Reference
<sheet::XSpreadsheetDocument
>& xSpreadDoc
, const OUString
& name
, SCTAB
& nTab
) throw ( lang::IllegalArgumentException
)
492 if (!xSpreadDoc
.is())
493 throw lang::IllegalArgumentException( OUString( "nameExists() xSpreadDoc is null" ), uno::Reference
< uno::XInterface
>(), 1 );
494 uno::Reference
<container::XIndexAccess
> xIndex( xSpreadDoc
->getSheets(), uno::UNO_QUERY
);
497 SCTAB nCount
= static_cast< SCTAB
>( xIndex
->getCount() );
498 for (SCTAB i
=0; i
< nCount
; i
++)
500 uno::Reference
< container::XNamed
> xNamed( xIndex
->getByIndex(i
), uno::UNO_QUERY_THROW
);
501 if (xNamed
->getName() == name
)
511 void ScVbaWorksheets::PrintPreview( const css::uno::Any
& /*EnableChanges*/ ) throw (css::uno::RuntimeException
)
513 // need test, print preview current active sheet
514 // !! TODO !! get view shell from controller
515 ScTabViewShell
* pViewShell
= excel::getBestViewShell( mxModel
);
516 SfxViewFrame
* pViewFrame
= NULL
;
518 pViewFrame
= pViewShell
->GetViewFrame();
521 if ( !pViewFrame
->GetFrame().IsInPlace() )
523 dispatchExecute( pViewShell
, SID_VIEWSHELL1
);
524 SfxViewShell
* pShell
= SfxViewShell::Get( pViewFrame
->GetFrame().GetFrameInterface()->getController() );
526 if ( pShell
->ISA( ScPreviewShell
) )
528 ScPreviewShell
* pPrvShell
= static_cast< ScPreviewShell
* >( pShell
);
529 ScPreview
* pPrvView
= pPrvShell
->GetPreview();
530 ScMarkData aMarkData
;
531 sal_Int32 nElems
= getCount();
532 for ( sal_Int32 nItem
= 1; nItem
<= nElems
; ++nItem
)
534 uno::Reference
< excel::XWorksheet
> xSheet( Item( uno::makeAny( nItem
), uno::Any() ), uno::UNO_QUERY_THROW
);
535 ScVbaWorksheet
* pSheet
= excel::getImplFromDocModuleWrapper
<ScVbaWorksheet
>( xSheet
);
537 aMarkData
.SelectTable(static_cast< SCTAB
>( pSheet
->getSheetID() ), true );
539 // save old selection, setting the selectedtabs in the preview
540 // can affect the current selection when preview has been
542 ScMarkData::MarkedTabsType aOldTabs
= pPrvView
->GetSelectedTabs();
543 pPrvView
->SetSelectedTabs( aMarkData
);
545 pPrvView
->DataChanged();
546 // set sensible first page
547 long nPage
= pPrvView
->GetFirstPage( 1 );
548 pPrvView
->SetPageNo( nPage
);
549 WaitUntilPreviewIsClosed( pViewFrame
);
550 // restore old tab selection
551 pViewShell
= excel::getBestViewShell( mxModel
);
552 pViewShell
->GetViewData()->GetMarkData().SetSelectedTabs(aOldTabs
);
559 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */