1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 #include "vbaworksheets.hxx"
20 
21 #include <sfx2/viewfrm.hxx>
22 
23 #include <cppuhelper/implbase.hxx>
24 
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>
31 
32 #include <ooo/vba/excel/XApplication.hpp>
33 #include <tabvwsh.hxx>
34 
35 #include "excelvbahelper.hxx"
36 #include "vbaworksheet.hxx"
37 #include <markdata.hxx>
38 
39 #include <vector>
40 #include <prevwsh.hxx>
41 #include <preview.hxx>
42 using namespace ::ooo::vba;
43 using namespace ::com::sun::star;
44 
45 // a map ( or hashmap ) won't do as we need also to preserve the order
46 // (as added ) of the items
47 typedef std::vector< uno::Reference< sheet::XSpreadsheet > >  SheetMap;
48 
49 // #FIXME #TODO the implementation of the Sheets collections sucks,
50 // e.g. there is no support for tracking sheets added/removed from the collection
51 
52 class WorkSheetsEnumeration : public ::cppu::WeakImplHelper< container::XEnumeration >
53 {
54     SheetMap mSheetMap;
55     SheetMap::iterator mIt;
56 public:
WorkSheetsEnumeration(const SheetMap & sMap)57     explicit WorkSheetsEnumeration( const SheetMap& sMap ) : mSheetMap( sMap ), mIt( mSheetMap.begin() ) {}
hasMoreElements()58     virtual sal_Bool SAL_CALL hasMoreElements(  ) override
59     {
60         return ( mIt != mSheetMap.end() );
61     }
nextElement()62     virtual uno::Any SAL_CALL nextElement(  ) override
63     {
64         if ( !hasMoreElements() )
65             throw container::NoSuchElementException();
66         uno::Reference< sheet::XSpreadsheet > xSheet( *mIt++ );
67         return uno::makeAny( xSheet ) ;
68     }
69 };
70 
71 class SheetCollectionHelper : public ::cppu::WeakImplHelper< container::XNameAccess,
72                                                               container::XIndexAccess,
73                                                               container::XEnumerationAccess >
74 {
75     SheetMap mSheetMap;
76     SheetMap::iterator cachePos;
77 public:
SheetCollectionHelper(const SheetMap & sMap)78     explicit SheetCollectionHelper( const SheetMap& sMap ) : mSheetMap( sMap ), cachePos(mSheetMap.begin()) {}
79     // XElementAccess
getElementType()80     virtual uno::Type SAL_CALL getElementType(  ) override { return  cppu::UnoType<sheet::XSpreadsheet>::get(); }
hasElements()81     virtual sal_Bool SAL_CALL hasElements(  ) override { return ( !mSheetMap.empty() ); }
82     // XNameAccess
getByName(const OUString & aName)83     virtual uno::Any SAL_CALL getByName( const OUString& aName ) override
84     {
85         if ( !hasByName(aName) )
86             throw container::NoSuchElementException();
87         return uno::makeAny( *cachePos );
88     }
getElementNames()89     virtual uno::Sequence< OUString > SAL_CALL getElementNames(  ) override
90     {
91         uno::Sequence< OUString > sNames( mSheetMap.size() );
92         OUString* pString = sNames.getArray();
93 
94         for ( const auto& rItem : mSheetMap )
95         {
96             uno::Reference< container::XNamed > xName( rItem, uno::UNO_QUERY_THROW );
97             *pString = xName->getName();
98             ++pString;
99         }
100         return sNames;
101     }
hasByName(const OUString & aName)102     virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override
103     {
104         cachePos = mSheetMap.begin();
105         SheetMap::iterator it_end = mSheetMap.end();
106         for ( ; cachePos != it_end; ++cachePos )
107         {
108             uno::Reference< container::XNamed > xName( *cachePos, uno::UNO_QUERY_THROW );
109             if ( aName == xName->getName() )
110                 break;
111         }
112         return ( cachePos != it_end );
113     }
114 
115     // XElementAccess
getCount()116     virtual ::sal_Int32 SAL_CALL getCount(  ) override { return mSheetMap.size(); }
getByIndex(::sal_Int32 Index)117     virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override
118     {
119         if ( Index < 0 || Index >= getCount() )
120             throw lang::IndexOutOfBoundsException();
121 
122         return uno::makeAny( mSheetMap[ Index ] );
123 
124     }
125     // XEnumerationAccess
createEnumeration()126     virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration(  ) override
127     {
128         return new WorkSheetsEnumeration( mSheetMap );
129     }
130 };
131 
132 class SheetsEnumeration : public EnumerationHelperImpl
133 {
134     uno::Reference< frame::XModel > m_xModel;
135 public:
136     /// @throws uno::RuntimeException
SheetsEnumeration(const uno::Reference<XHelperInterface> & xParent,const uno::Reference<uno::XComponentContext> & xContext,const uno::Reference<container::XEnumeration> & xEnumeration,const uno::Reference<frame::XModel> & xModel)137     SheetsEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration,  const uno::Reference< frame::XModel >& xModel  ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ), m_xModel( xModel ) {}
138 
nextElement()139     virtual uno::Any SAL_CALL nextElement(  ) override
140     {
141         uno::Reference< sheet::XSpreadsheet > xSheet( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW );
142         uno::Reference< XHelperInterface > xIf = excel::getUnoSheetModuleObj( xSheet );
143         uno::Any aRet;
144         if ( !xIf.is() )
145         {
146             // if the Sheet is in a document created by the api unfortunately ( at the
147             // moment, it actually won't have the special Document modules
148             uno::Reference< excel::XWorksheet > xNewSheet( new ScVbaWorksheet( m_xParent, m_xContext, xSheet, m_xModel ) );
149             aRet <<= xNewSheet;
150         }
151         else
152             aRet <<= xIf;
153         return aRet;
154     }
155 
156 };
157 
ScVbaWorksheets(const uno::Reference<XHelperInterface> & xParent,const uno::Reference<css::uno::XComponentContext> & xContext,const uno::Reference<container::XIndexAccess> & xSheets,const uno::Reference<frame::XModel> & xModel)158 ScVbaWorksheets::ScVbaWorksheets( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::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 ) )
159 {
160 }
161 
ScVbaWorksheets(const uno::Reference<XHelperInterface> & xParent,const uno::Reference<css::uno::XComponentContext> & xContext,const uno::Reference<container::XEnumerationAccess> & xEnumAccess,const uno::Reference<frame::XModel> & xModel)162 ScVbaWorksheets::ScVbaWorksheets( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::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)
163 {
164 }
165 
166 // XEnumerationAccess
167 uno::Type
getElementType()168 ScVbaWorksheets::getElementType()
169 {
170     return cppu::UnoType<excel::XWorksheet>::get();
171 }
172 
173 uno::Reference< container::XEnumeration >
createEnumeration()174 ScVbaWorksheets::createEnumeration()
175 {
176     if ( !m_xSheets.is() )
177     {
178         uno::Reference< container::XEnumerationAccess > xAccess( m_xIndexAccess, uno::UNO_QUERY_THROW );
179         return xAccess->createEnumeration();
180     }
181     uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xSheets, uno::UNO_QUERY_THROW );
182     return new SheetsEnumeration( this, mxContext, xEnumAccess->createEnumeration(), mxModel );
183 }
184 
185 uno::Any
createCollectionObject(const uno::Any & aSource)186 ScVbaWorksheets::createCollectionObject( const uno::Any& aSource )
187 {
188     uno::Reference< sheet::XSpreadsheet > xSheet( aSource, uno::UNO_QUERY );
189     uno::Reference< XHelperInterface > xIf = excel::getUnoSheetModuleObj( xSheet );
190     uno::Any aRet;
191     if ( !xIf.is() )
192     {
193         // if the Sheet is in a document created by the api unfortunately ( at the
194         // moment, it actually won't have the special Document modules
195         uno::Reference< excel::XWorksheet > xNewSheet( new ScVbaWorksheet( getParent(), mxContext, xSheet, mxModel ) );
196         aRet <<= xNewSheet;
197     }
198     else
199         aRet <<= xIf;
200     return aRet;
201 }
202 
203 // XWorksheets
204 uno::Any
Add(const uno::Any & Before,const uno::Any & After,const uno::Any & Count,const uno::Any & Type)205 ScVbaWorksheets::Add( const uno::Any& Before, const uno::Any& After,
206                      const uno::Any& Count, const uno::Any& Type )
207 {
208     if ( isSelectedSheets() )
209         return uno::Any(); // or should we throw?
210 
211     OUString aStringSheet;
212     bool bBefore(true);
213     SCTAB nSheetIndex = 0;
214     SCTAB nNewSheets = 1, nType = 0;
215     Count >>= nNewSheets;
216     Type >>= nType;
217     SCTAB nCount = 0;
218 
219     uno::Reference< excel::XWorksheet > xBeforeAfterSheet;
220 
221     if ( Before.hasValue() )
222     {
223         if ( Before >>= xBeforeAfterSheet )
224             aStringSheet = xBeforeAfterSheet->getName();
225         else
226             Before >>= aStringSheet;
227     }
228 
229     if (aStringSheet.isEmpty() && After.hasValue() )
230     {
231         if ( After >>= xBeforeAfterSheet )
232             aStringSheet = xBeforeAfterSheet->getName();
233         else
234             After >>= aStringSheet;
235         bBefore = false;
236     }
237     if (aStringSheet.isEmpty())
238     {
239         uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW );
240         aStringSheet = xApplication->getActiveWorkbook()->getActiveSheet()->getName();
241         bBefore = true;
242     }
243     nCount = static_cast< SCTAB >( m_xIndexAccess->getCount() );
244     for (SCTAB i=0; i < nCount; i++)
245     {
246             uno::Reference< sheet::XSpreadsheet > xSheet(m_xIndexAccess->getByIndex(i), uno::UNO_QUERY);
247             uno::Reference< container::XNamed > xNamed( xSheet, uno::UNO_QUERY_THROW );
248             if (xNamed->getName() == aStringSheet)
249             {
250                 nSheetIndex = i;
251                 break;
252             }
253     }
254 
255     if(!bBefore)
256         nSheetIndex++;
257 
258     SCTAB nSheetName = nCount + 1;
259     OUString aStringBase( "Sheet" );
260     uno::Any result;
261     for (SCTAB i=0; i < nNewSheets; i++, nSheetName++)
262     {
263         OUString aStringName = aStringBase + OUString::number(nSheetName);
264         while (m_xNameAccess->hasByName(aStringName))
265         {
266             nSheetName++;
267             aStringName = aStringBase + OUString::number(nSheetName);
268         }
269         m_xSheets->insertNewByName(aStringName, nSheetIndex + i);
270         result = getItemByStringIndex( aStringName );
271     }
272     uno::Reference< excel::XWorksheet > xNewSheet( result, uno::UNO_QUERY );
273     if ( xNewSheet.is() )
274         xNewSheet->Activate();
275     return  result;
276 }
277 
278 void
Delete()279 ScVbaWorksheets::Delete()
280 {
281     // #TODO #INVESTIGATE
282     // mmm this method could be trouble if the underlying
283     // uno objects ( the m_xIndexAccess etc ) aren't aware of the
284     // contents that are deleted
285     sal_Int32 nElems = getCount();
286     for ( sal_Int32 nItem = 1; nItem <= nElems; ++nItem )
287     {
288         uno::Reference< excel::XWorksheet > xSheet( Item( uno::makeAny( nItem ), uno::Any() ), uno::UNO_QUERY_THROW );
289         xSheet->Delete();
290     }
291 }
292 
293 bool
isSelectedSheets() const294 ScVbaWorksheets::isSelectedSheets() const
295 {
296     return !m_xSheets.is();
297 }
298 
299 void SAL_CALL
PrintOut(const uno::Any & From,const uno::Any & To,const uno::Any & Copies,const uno::Any & Preview,const uno::Any & ActivePrinter,const uno::Any & PrintToFile,const uno::Any & Collate,const uno::Any & PrToFileName)300 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 )
301 {
302     sal_Int32 nTo = 0;
303     sal_Int32 nFrom = 0;
304     bool bSelection = false;
305     From >>= nFrom;
306     To >>= nTo;
307 
308     if ( !( nFrom || nTo ) )
309         if ( isSelectedSheets() )
310             bSelection = true;
311 
312     PrintOutHelper( excel::getBestViewShell( mxModel ), From, To, Copies, Preview, ActivePrinter, PrintToFile, Collate, PrToFileName, bSelection );
313 }
314 
315 uno::Any SAL_CALL
getVisible()316 ScVbaWorksheets::getVisible()
317 {
318     bool bVisible = true;
319     uno::Reference< container::XEnumeration > xEnum( createEnumeration(), uno::UNO_SET_THROW );
320     while ( xEnum->hasMoreElements() )
321     {
322         uno::Reference< excel::XWorksheet > xSheet( xEnum->nextElement(), uno::UNO_QUERY_THROW );
323         if ( xSheet->getVisible() == 0 )
324         {
325                 bVisible = false;
326                 break;
327         }
328     }
329     return uno::makeAny( bVisible );
330 }
331 
332 void SAL_CALL
setVisible(const uno::Any & _visible)333 ScVbaWorksheets::setVisible( const uno::Any& _visible )
334 {
335     bool bState = false;
336     if ( !(_visible >>= bState) )
337         throw uno::RuntimeException("Visible property doesn't support non boolean #FIXME" );
338 
339     uno::Reference< container::XEnumeration > xEnum( createEnumeration(), uno::UNO_SET_THROW );
340     while ( xEnum->hasMoreElements() )
341     {
342         uno::Reference< excel::XWorksheet > xSheet( xEnum->nextElement(), uno::UNO_QUERY_THROW );
343         xSheet->setVisible( bState ? 1 : 0 );
344     }
345 
346 }
347 
348 void SAL_CALL
Select(const uno::Any & Replace)349 ScVbaWorksheets::Select( const uno::Any& Replace )
350 {
351     ScTabViewShell* pViewShell = excel::getBestViewShell( mxModel );
352     if ( !pViewShell )
353         throw uno::RuntimeException("Cannot obtain view shell" );
354 
355     ScMarkData& rMarkData = pViewShell->GetViewData().GetMarkData();
356     bool bReplace = true;
357     Replace >>= bReplace;
358     // Replace is defaulted to True, meaning this current collection
359     // becomes the Selection, if it were false then the current selection would
360     // be extended
361     bool bSelectSingle = bReplace;
362     sal_Int32 nElems = getCount();
363     for ( sal_Int32 nItem = 1; nItem <= nElems; ++nItem )
364     {
365         uno::Reference< excel::XWorksheet > xSheet( Item( uno::makeAny( nItem ), uno::Any() ), uno::UNO_QUERY_THROW );
366         ScVbaWorksheet* pSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSheet );
367         if ( bSelectSingle )
368         {
369             rMarkData.SelectOneTable( static_cast< SCTAB >( pSheet->getSheetID() ) );
370             bSelectSingle = false;
371         }
372         else
373             rMarkData.SelectTable( static_cast< SCTAB >( pSheet->getSheetID() ), true );
374     }
375 
376 }
377 
378 void SAL_CALL
Copy(const uno::Any & Before,const uno::Any & After)379 ScVbaWorksheets::Copy ( const uno::Any& Before, const uno::Any& After)
380 {
381     uno::Reference<excel::XWorksheet> xSheet;
382     sal_Int32 nElems = getCount();
383     bool bAfter = After.hasValue();
384     std::vector< uno::Reference< excel::XWorksheet > > Sheets;
385     sal_Int32 nItem = 0;
386 
387     for ( nItem = 1; nItem <= nElems; ++nItem)
388     {
389         uno::Reference<excel::XWorksheet> xWorksheet(Item( uno::makeAny( nItem ), uno::Any() ), uno::UNO_QUERY_THROW );
390         Sheets.push_back(xWorksheet);
391     }
392     bool bNewDoc = (!(Before >>= xSheet) && !(After >>=xSheet)&& !(Before.hasValue()) && !(After.hasValue()));
393 
394     uno::Reference< excel::XWorksheet > xSrcSheet;
395     if ( bNewDoc )
396     {
397         bAfter = true;
398         xSrcSheet = Sheets.at(0);
399         ScVbaWorksheet* pSrcSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSrcSheet );
400         xSheet = pSrcSheet->createSheetCopyInNewDoc(xSrcSheet->getName());
401         nItem = 1;
402     }
403     else
404     {
405         nItem=0;
406     }
407 
408     for (; nItem < nElems; ++nItem )
409     {
410         xSrcSheet = Sheets[nItem];
411         ScVbaWorksheet* pSrcSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSrcSheet );
412         if ( bAfter )
413             xSheet = pSrcSheet->createSheetCopy(xSheet, bAfter);
414         else
415             pSrcSheet->createSheetCopy(xSheet, bAfter);
416     }
417 }
418 
419 //ScVbaCollectionBaseImpl
420 uno::Any SAL_CALL
Item(const uno::Any & Index,const uno::Any & Index2)421 ScVbaWorksheets::Item(const uno::Any& Index, const uno::Any& Index2)
422 {
423     if ( Index.getValueTypeClass() == uno::TypeClass_SEQUENCE )
424     {
425         const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter(mxContext);
426         uno::Any aConverted = xConverter->convertTo( Index, cppu::UnoType<uno::Sequence< uno::Any >>::get() );
427         SheetMap aSheets;
428         uno::Sequence< uno::Any > sIndices;
429         aConverted >>= sIndices;
430         for( const auto& rIndex : std::as_const(sIndices) )
431         {
432             uno::Reference< excel::XWorksheet > xWorkSheet( ScVbaWorksheets_BASE::Item( rIndex, Index2 ), uno::UNO_QUERY_THROW );
433             ScVbaWorksheet* pWorkSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xWorkSheet );
434             uno::Reference< sheet::XSpreadsheet > xSheet( pWorkSheet->getSheet() , uno::UNO_SET_THROW );
435             uno::Reference< container::XNamed > xName( xSheet, uno::UNO_QUERY_THROW );
436             aSheets.push_back( xSheet );
437         }
438         uno::Reference< container::XIndexAccess > xIndexAccess = new SheetCollectionHelper( aSheets );
439         uno::Reference< XCollection > xSelectedSheets(  new ScVbaWorksheets( getParent(), mxContext, xIndexAccess, mxModel ) );
440         return uno::makeAny( xSelectedSheets );
441     }
442     return  ScVbaWorksheets_BASE::Item( Index, Index2 );
443 }
444 
445 OUString
getServiceImplName()446 ScVbaWorksheets::getServiceImplName()
447 {
448     return "ScVbaWorksheets";
449 }
450 
451 css::uno::Sequence<OUString>
getServiceNames()452 ScVbaWorksheets::getServiceNames()
453 {
454     static uno::Sequence< OUString > const sNames
455     {
456         "ooo.vba.excel.Worksheets"
457     };
458     return sNames;
459 }
460 
nameExists(const uno::Reference<sheet::XSpreadsheetDocument> & xSpreadDoc,const OUString & name,SCTAB & nTab)461 bool ScVbaWorksheets::nameExists( const uno::Reference <sheet::XSpreadsheetDocument>& xSpreadDoc, const OUString & name, SCTAB& nTab )
462 {
463     if (!xSpreadDoc.is())
464         throw lang::IllegalArgumentException( "nameExists() xSpreadDoc is null", uno::Reference< uno::XInterface  >(), 1 );
465     uno::Reference <container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY );
466     if ( xIndex.is() )
467     {
468         SCTAB  nCount = static_cast< SCTAB >( xIndex->getCount() );
469         for (SCTAB i=0; i < nCount; i++)
470         {
471             uno::Reference< container::XNamed > xNamed( xIndex->getByIndex(i), uno::UNO_QUERY_THROW );
472             if (xNamed->getName() == name)
473             {
474                 nTab = i;
475                 return true;
476             }
477         }
478     }
479     return false;
480 }
481 
PrintPreview(const css::uno::Any &)482 void ScVbaWorksheets::PrintPreview( const css::uno::Any& /*EnableChanges*/ )
483 {
484     // need test, print preview current active sheet
485     // !! TODO !! get view shell from controller
486     ScTabViewShell* pViewShell = excel::getBestViewShell( mxModel );
487     SfxViewFrame* pViewFrame = nullptr;
488     if ( pViewShell )
489         pViewFrame = pViewShell->GetViewFrame();
490     if ( pViewFrame )
491     {
492         if ( !pViewFrame->GetFrame().IsInPlace() )
493         {
494             dispatchExecute( pViewShell, SID_VIEWSHELL1 );
495             SfxViewShell*  pShell = SfxViewShell::Get( pViewFrame->GetFrame().GetFrameInterface()->getController() );
496 
497             if (  dynamic_cast<const ScPreviewShell*>( pShell) !=  nullptr )
498             {
499                 ScPreviewShell* pPrvShell = static_cast<  ScPreviewShell* >( pShell );
500                 ScPreview* pPrvView = pPrvShell->GetPreview();
501                 const ScDocument& rDoc = *pViewShell->GetViewData().GetDocument();
502                 ScMarkData aMarkData(rDoc.MaxRow(), rDoc.MaxCol());
503                 sal_Int32 nElems = getCount();
504                 for ( sal_Int32 nItem = 1; nItem <= nElems; ++nItem )
505                 {
506                     uno::Reference< excel::XWorksheet > xSheet( Item( uno::makeAny( nItem ), uno::Any() ), uno::UNO_QUERY_THROW );
507                     ScVbaWorksheet* pSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSheet );
508                     if ( pSheet )
509                         aMarkData.SelectTable(static_cast< SCTAB >( pSheet->getSheetID() ), true );
510                 }
511                 // save old selection, setting the selectedtabs in the preview
512                 // can affect the current selection when preview has been
513                 // closed
514                 ScMarkData::MarkedTabsType aOldTabs = pPrvView->GetSelectedTabs();
515                 pPrvView->SetSelectedTabs( aMarkData );
516                 // force update
517                 pPrvView->DataChanged(false);
518                 // set sensible first page
519                 long nPage = pPrvView->GetFirstPage( 1 );
520                 pPrvView->SetPageNo( nPage );
521                 WaitUntilPreviewIsClosed( pViewFrame );
522                 // restore old tab selection
523                 pViewShell = excel::getBestViewShell( mxModel );
524                 pViewShell->GetViewData().GetMarkData().SetSelectedTabs(aOldTabs);
525             }
526         }
527     }
528 
529 }
530 
531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
532