LibreOffice Module sc (master)  1
excelvbahelper.cxx
Go to the documentation of this file.
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 
20 #include "excelvbahelper.hxx"
21 
22 #include <basic/basmgr.hxx>
24 #include <vbahelper/vbahelper.hxx>
25 #include <com/sun/star/frame/XModel.hpp>
26 #include <com/sun/star/sheet/XSheetCellRange.hpp>
27 #include <com/sun/star/sheet/GlobalSheetSettings.hpp>
28 #include <com/sun/star/sheet/XUnnamedDatabaseRanges.hpp>
29 #include <com/sun/star/sheet/XSpreadsheet.hpp>
30 #include <com/sun/star/sheet/XDatabaseRange.hpp>
31 
32 #include <document.hxx>
33 #include <docuno.hxx>
34 #include <tabvwsh.hxx>
35 #include <transobj.hxx>
36 #include <cellsuno.hxx>
37 #include <gridwin.hxx>
38 
39 #include <com/sun/star/script/vba/VBAEventId.hpp>
40 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
41 #include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
42 #include <com/sun/star/script/vba/XVBAModuleInfo.hpp>
43 #include <com/sun/star/script/ModuleInfo.hpp>
44 #include <com/sun/star/script/ModuleType.hpp>
45 
46 using namespace ::com::sun::star;
47 using namespace ::ooo::vba;
48 
49 namespace ooo::vba::excel {
50 
51 uno::Reference< sheet::XUnnamedDatabaseRanges >
53 {
54  uno::Reference< frame::XModel > xModel;
55  if ( pShell )
56  xModel.set( pShell->GetModel(), uno::UNO_SET_THROW );
57  uno::Reference< beans::XPropertySet > xModelProps( xModel, uno::UNO_QUERY_THROW );
58  uno::Reference< sheet::XUnnamedDatabaseRanges > xUnnamedDBRanges( xModelProps->getPropertyValue("UnnamedDatabaseRanges"), uno::UNO_QUERY_THROW );
59  return xUnnamedDBRanges;
60 }
61 
62 // returns the XDatabaseRange for the autofilter on sheet (nSheet)
63 // also populates sName with the name of range
64 uno::Reference< sheet::XDatabaseRange >
65 GetAutoFiltRange( const ScDocShell* pShell, sal_Int16 nSheet )
66 {
67  uno::Reference< sheet::XUnnamedDatabaseRanges > xUnnamedDBRanges( GetUnnamedDataBaseRanges( pShell ), uno::UNO_SET_THROW );
68  uno::Reference< sheet::XDatabaseRange > xDataBaseRange;
69  if (xUnnamedDBRanges->hasByTable( nSheet ) )
70  {
71  uno::Reference< sheet::XDatabaseRange > xDBRange( xUnnamedDBRanges->getByTable( nSheet ) , uno::UNO_QUERY_THROW );
72  bool bHasAuto = false;
73  uno::Reference< beans::XPropertySet > xProps( xDBRange, uno::UNO_QUERY_THROW );
74  xProps->getPropertyValue("AutoFilter") >>= bHasAuto;
75  if ( bHasAuto )
76  {
77  xDataBaseRange=xDBRange;
78  }
79  }
80  return xDataBaseRange;
81 }
82 
83 ScDocShell* GetDocShellFromRange( const uno::Reference< uno::XInterface >& xRange )
84 {
85  ScCellRangesBase* pScCellRangesBase = comphelper::getUnoTunnelImplementation<ScCellRangesBase>( xRange );
86  if ( !pScCellRangesBase )
87  {
88  throw uno::RuntimeException("Failed to access underlying doc shell uno range object" );
89  }
90  return pScCellRangesBase->GetDocShell();
91 }
92 
93 uno::Reference< XHelperInterface >
94 getUnoSheetModuleObj( const uno::Reference< table::XCellRange >& xRange )
95 {
96  uno::Reference< sheet::XSheetCellRange > xSheetRange( xRange, uno::UNO_QUERY_THROW );
97  uno::Reference< sheet::XSpreadsheet > xSheet( xSheetRange->getSpreadsheet(), uno::UNO_SET_THROW );
98  return getUnoSheetModuleObj( xSheet );
99 }
100 
101 void implSetZoom( const uno::Reference< frame::XModel >& xModel, sal_Int16 nZoom, std::vector< SCTAB >& nTabs )
102 {
103  ScTabViewShell* pViewSh = excel::getBestViewShell( xModel );
104  Fraction aFract( nZoom, 100 );
105  pViewSh->GetViewData().SetZoom( aFract, aFract, nTabs );
106  pViewSh->RefreshZoom();
107 }
108 
109 namespace {
110 
111 class PasteCellsWarningReseter
112 {
113 private:
116  static uno::Reference< sheet::XGlobalSheetSettings > const & getGlobalSheetSettings()
117  {
118  static uno::Reference< sheet::XGlobalSheetSettings > xProps = sheet::GlobalSheetSettings::create( comphelper::getProcessComponentContext() );
119  return xProps;
120  }
121 
123  static bool getReplaceCellsWarning()
124  {
125  return getGlobalSheetSettings()->getReplaceCellsWarning();
126  }
127 
129  static void setReplaceCellsWarning( bool bState )
130  {
131  getGlobalSheetSettings()->setReplaceCellsWarning( bState );
132  }
133 public:
135  PasteCellsWarningReseter()
136  {
137  bInitialWarningState = getReplaceCellsWarning();
138  if ( bInitialWarningState )
139  setReplaceCellsWarning( false );
140  }
141  ~PasteCellsWarningReseter()
142  {
143  if ( bInitialWarningState )
144  {
145  // don't allow dtor to throw
146  try
147  {
148  setReplaceCellsWarning( true );
149  }
150  catch ( uno::Exception& /*e*/ ){}
151  }
152  }
153 };
154 
155 }
156 
157 void
158 implnPaste( const uno::Reference< frame::XModel>& xModel )
159 {
160  PasteCellsWarningReseter resetWarningBox;
161  ScTabViewShell* pViewShell = getBestViewShell( xModel );
162  if ( pViewShell )
163  {
164  pViewShell->PasteFromSystem();
165  pViewShell->CellContentChanged();
166  }
167 }
168 
169 void
170 implnCopy( const uno::Reference< frame::XModel>& xModel )
171 {
172  ScTabViewShell* pViewShell = getBestViewShell( xModel );
173  ScDocShell* pDocShell = getDocShell( xModel );
174  if ( !(pViewShell && pDocShell) )
175  return;
176 
177  pViewShell->CopyToClip(nullptr,false,false,true);
178 
179  // mark the copied transfer object so it is used in ScVbaRange::Insert
180  uno::Reference<datatransfer::XTransferable2> xTransferable(ScTabViewShell::GetClipData(pViewShell->GetViewData().GetActiveWin()));
181  ScTransferObj* pClipObj = ScTransferObj::GetOwnClipboard(xTransferable);
182  if (pClipObj)
183  {
184  pClipObj->SetUseInApi( true );
185  pDocShell->SetClipData(xTransferable);
186  }
187 }
188 
189 void
190 implnCut( const uno::Reference< frame::XModel>& xModel )
191 {
192  ScTabViewShell* pViewShell = getBestViewShell( xModel );
193  ScDocShell* pDocShell = getDocShell( xModel );
194  if ( !(pViewShell && pDocShell) )
195  return;
196 
197  pViewShell->CutToClip();
198 
199  // mark the copied transfer object so it is used in ScVbaRange::Insert
200  uno::Reference<datatransfer::XTransferable2> xTransferable(ScTabViewShell::GetClipData(pViewShell->GetViewData().GetActiveWin()));
201  ScTransferObj* pClipObj = ScTransferObj::GetOwnClipboard(xTransferable);
202  if (pClipObj)
203  {
204  pClipObj->SetUseInApi( true );
205  pDocShell->SetClipData(xTransferable);
206  }
207 }
208 
209 void implnPasteSpecial( const uno::Reference< frame::XModel>& xModel, InsertDeleteFlags nFlags, ScPasteFunc nFunction, bool bSkipEmpty, bool bTranspose)
210 {
211  PasteCellsWarningReseter resetWarningBox;
212 
213  ScTabViewShell* pTabViewShell = getBestViewShell( xModel );
214  ScDocShell* pDocShell = getDocShell( xModel );
215  if ( !(pTabViewShell && pDocShell) )
216  return;
217 
218  ScViewData& rView = pTabViewShell->GetViewData();
219  vcl::Window* pWin = rView.GetActiveWin();
220  if (pWin)
221  {
222  const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(pDocShell->GetClipData());
223  ScDocument* pDoc = nullptr;
224  if ( pOwnClip )
225  pDoc = pOwnClip->GetDocument();
226  pTabViewShell->PasteFromClip( nFlags, pDoc,
227  nFunction, bSkipEmpty, bTranspose, false,
229  pTabViewShell->CellContentChanged();
230  }
231 
232 }
233 
234 ScDocShell*
235 getDocShell( const css::uno::Reference< css::frame::XModel>& xModel )
236 {
237  uno::Reference< uno::XInterface > xIf( xModel, uno::UNO_QUERY_THROW );
238  ScModelObj* pModel = dynamic_cast< ScModelObj* >( xIf.get() );
239  ScDocShell* pDocShell = nullptr;
240  if ( pModel )
241  pDocShell = static_cast<ScDocShell*>(pModel->GetEmbeddedObject());
242  return pDocShell;
243 
244 }
245 
247 getBestViewShell( const css::uno::Reference< css::frame::XModel>& xModel )
248 {
249  ScDocShell* pDocShell = getDocShell( xModel );
250  if ( pDocShell )
251  return pDocShell->GetBestViewShell();
252  return nullptr;
253 }
254 
256 getCurrentBestViewShell( const uno::Reference< uno::XComponentContext >& xContext )
257 {
258  uno::Reference< frame::XModel > xModel = getCurrentExcelDoc( xContext );
259  return getBestViewShell( xModel );
260 }
261 
263 getViewFrame( const uno::Reference< frame::XModel >& xModel )
264 {
265  ScTabViewShell* pViewShell = getBestViewShell( xModel );
266  if ( pViewShell )
267  return pViewShell->GetViewFrame();
268  return nullptr;
269 }
270 
271 uno::Reference< XHelperInterface >
272 getUnoSheetModuleObj( const uno::Reference< sheet::XSpreadsheet >& xSheet )
273 {
274  uno::Reference< beans::XPropertySet > xProps( xSheet, uno::UNO_QUERY_THROW );
275  OUString sCodeName;
276  xProps->getPropertyValue("CodeName") >>= sCodeName;
277  // #TODO #FIXME ideally we should 'throw' here if we don't get a valid parent, but... it is possible
278  // to create a module ( and use 'Option VBASupport 1' ) for a calc document, in this scenario there
279  // are *NO* special document module objects ( of course being able to switch between vba/non vba mode at
280  // the document in the future could fix this, especially IF the switching of the vba mode takes care to
281  // create the special document module objects if they don't exist.
282  return getUnoDocModule( sCodeName, GetDocShellFromRange( xSheet ) );
283 }
284 
285 uno::Reference< XHelperInterface >
286 getUnoSheetModuleObj( const uno::Reference< sheet::XSheetCellRangeContainer >& xRanges )
287 {
288  uno::Reference< container::XEnumerationAccess > xEnumAccess( xRanges, uno::UNO_QUERY_THROW );
289  uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration();
290  uno::Reference< table::XCellRange > xRange( xEnum->nextElement(), uno::UNO_QUERY_THROW );
291  return getUnoSheetModuleObj( xRange );
292 }
293 
294 uno::Reference< XHelperInterface >
295 getUnoSheetModuleObj( const uno::Reference< table::XCell >& xCell )
296 {
297  uno::Reference< sheet::XSheetCellRange > xSheetRange( xCell, uno::UNO_QUERY_THROW );
298  uno::Reference< sheet::XSpreadsheet > xSheet( xSheetRange->getSpreadsheet(), uno::UNO_SET_THROW );
299  return getUnoSheetModuleObj( xSheet );
300 }
301 
302 uno::Reference< XHelperInterface >
303 getUnoSheetModuleObj( const uno::Reference< frame::XModel >& xModel, SCTAB nTab )
304 {
305  uno::Reference< sheet::XSpreadsheetDocument > xDoc( xModel, uno::UNO_QUERY_THROW );
306  uno::Reference< container::XIndexAccess > xSheets( xDoc->getSheets(), uno::UNO_QUERY_THROW );
307  uno::Reference< sheet::XSpreadsheet > xSheet( xSheets->getByIndex( nTab ), uno::UNO_QUERY_THROW );
308  return getUnoSheetModuleObj( xSheet );
309 }
310 
311 void setUpDocumentModules( const uno::Reference< sheet::XSpreadsheetDocument >& xDoc )
312 {
313  uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY );
314  ScDocShell* pShell = excel::getDocShell( xModel );
315  if ( !pShell )
316  return;
317 
318  OUString aPrjName( "Standard" );
319  pShell->GetBasicManager()->SetName( aPrjName );
320 
321  /* Set library container to VBA compatibility mode. This will create
322  the VBA Globals object and store it in the Basic manager of the
323  document. */
324  uno::Reference<script::XLibraryContainer> xLibContainer = pShell->GetBasicContainer();
325  uno::Reference<script::vba::XVBACompatibility> xVBACompat( xLibContainer, uno::UNO_QUERY_THROW );
326  xVBACompat->setVBACompatibilityMode( true );
327 
328  if( xLibContainer.is() )
329  {
330  if( !xLibContainer->hasByName( aPrjName ) )
331  xLibContainer->createLibrary( aPrjName );
332  uno::Any aLibAny = xLibContainer->getByName( aPrjName );
333  uno::Reference< container::XNameContainer > xLib;
334  aLibAny >>= xLib;
335  if( xLib.is() )
336  {
337  uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY_THROW );
338  uno::Reference< lang::XMultiServiceFactory> xSF( pShell->GetModel(), uno::UNO_QUERY_THROW);
339  uno::Reference< container::XNameAccess > xVBACodeNamedObjectAccess( xSF->createInstance("ooo.vba.VBAObjectModuleObjectProvider"), uno::UNO_QUERY_THROW );
340  // set up the module info for the workbook and sheets in the newly created
341  // spreadsheet
342  ScDocument& rDoc = pShell->GetDocument();
343  OUString sCodeName = rDoc.GetCodeName();
344  if ( sCodeName.isEmpty() )
345  {
346  sCodeName = "ThisWorkbook";
347  rDoc.SetCodeName( sCodeName );
348  }
349 
350  std::vector< OUString > sDocModuleNames;
351  sDocModuleNames.push_back( sCodeName );
352 
353  for ( SCTAB index = 0; index < rDoc.GetTableCount(); index++)
354  {
355  OUString aName;
356  rDoc.GetCodeName( index, aName );
357  sDocModuleNames.push_back( aName );
358  }
359 
360  for ( const auto& rName : sDocModuleNames )
361  {
362  script::ModuleInfo sModuleInfo;
363 
364  uno::Any aName= xVBACodeNamedObjectAccess->getByName( rName );
365  sModuleInfo.ModuleObject.set( aName, uno::UNO_QUERY );
366  sModuleInfo.ModuleType = script::ModuleType::DOCUMENT;
367  xVBAModuleInfo->insertModuleInfo( rName, sModuleInfo );
368  if( xLib->hasByName( rName ) )
369  xLib->replaceByName( rName, uno::makeAny( OUString( "Option VBASupport 1\n") ) );
370  else
371  xLib->insertByName( rName, uno::makeAny( OUString( "Option VBASupport 1\n" ) ) );
372  }
373  }
374  }
375 
376  /* Trigger the Workbook_Open event, event processor will register
377  itself as listener for specific events. */
378  try
379  {
380  uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( pShell->GetDocument().GetVbaEventProcessor(), uno::UNO_SET_THROW );
381  uno::Sequence< uno::Any > aArgs;
382  xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_OPEN, aArgs );
383  }
384  catch( uno::Exception& )
385  {
386  }
387 }
388 
389 SfxItemSet*
391 {
392  return pRangeObj ? pRangeObj->GetCurrentDataSet( true ) : nullptr;
393 }
394 
395 } // namespace ooo::vba::excel
396 
397 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SfxViewFrame * GetViewFrame() const
void setUpDocumentModules(const uno::Reference< sheet::XSpreadsheetDocument > &xDoc)
SC_DLLPUBLIC bool CopyToClip(ScDocument *pClipDoc, bool bCut, bool bApi=false, bool bIncludeObjects=false, bool bStopEdit=true)
Definition: viewfun3.cxx:165
uno::Reference< sheet::XUnnamedDatabaseRanges > GetUnnamedDataBaseRanges(const ScDocShell *pShell)
SC_DLLPUBLIC void RefreshZoom()
Definition: tabview5.cxx:421
ScDocShell * GetDocShell() const
Definition: cellsuno.hxx:242
const css::uno::Reference< css::script::vba::XVBAEventProcessor > & GetVbaEventProcessor() const
Definition: document.hxx:2435
ScDocShell * GetDocShellFromRange(const uno::Reference< uno::XInterface > &xRange)
css::uno::Reference< css::datatransfer::XTransferable2 > const & GetClipData() const
Definition: docsh.hxx:220
static css::uno::Reference< css::datatransfer::XTransferable2 > GetClipData(vcl::Window *pWin)
Definition: tabvwshc.cxx:483
css::uno::Reference< css::frame::XModel > GetModel() const
void implnCopy(const uno::Reference< frame::XModel > &xModel)
bool bInitialWarningState
static SfxItemSet * GetDataSet(ScCellRangesBase *pRangeObj)
SC_DLLPUBLIC void CutToClip()
Not used?
Definition: viewfun3.cxx:87
uno::Reference< XHelperInterface > getUnoSheetModuleObj(const uno::Reference< table::XCellRange > &xRange)
void SetClipData(const css::uno::Reference< css::datatransfer::XTransferable2 > &xTransferable)
Definition: docsh.hxx:221
ScDocument * GetDocument() const
Definition: transobj.hxx:81
SC_DLLPUBLIC void PasteFromSystem()
Definition: viewfun3.cxx:482
ScViewData & GetViewData()
Definition: tabview.hxx:332
ScPasteFunc
Definition: global.hxx:190
ScDocShell * getDocShell(const css::uno::Reference< css::frame::XModel > &xModel)
InsertDeleteFlags
Definition: global.hxx:159
SfxObjectShell * GetEmbeddedObject() const
Definition: docuno.cxx:455
SfxViewFrame * getViewFrame(const uno::Reference< frame::XModel > &xModel)
SfxItemSet * GetCurrentDataSet(bool bNoDflt=false)
Definition: cellsuno.cxx:1510
ScGridWindow * GetActiveWin()
Definition: viewdata.cxx:3062
tuple index
uno::Reference< XHelperInterface > getUnoDocModule(const OUString &aModName, SfxObjectShell const *pShell)
SC_DLLPUBLIC bool PasteFromClip(InsertDeleteFlags nFlags, ScDocument *pClipDoc, ScPasteFunc nFunction=ScPasteFunc::NONE, bool bSkipEmpty=false, bool bTranspose=false, bool bAsLink=false, InsCellCmd eMoveMode=INS_NONE, InsertDeleteFlags nUndoExtraFlags=InsertDeleteFlags::NONE, bool bAllowDialogs=false)
Definition: viewfun3.cxx:875
void implnCut(const uno::Reference< frame::XModel > &xModel)
uno::Reference< sheet::XDatabaseRange > GetAutoFiltRange(const ScDocShell *pShell, sal_Int16 nSheet)
ScTabViewShell * getBestViewShell(const css::uno::Reference< css::frame::XModel > &xModel)
void implnPasteSpecial(const uno::Reference< frame::XModel > &xModel, InsertDeleteFlags nFlags, ScPasteFunc nFunction, bool bSkipEmpty, bool bTranspose)
ScTabViewShell * getCurrentBestViewShell(const uno::Reference< uno::XComponentContext > &xContext)
SC_DLLPUBLIC void SetUseInApi(bool bSet)
Definition: transobj.cxx:621
OUString aName
static SC_DLLPUBLIC ScTransferObj * GetOwnClipboard(const css::uno::Reference< css::datatransfer::XTransferable2 > &)
Definition: transobj.cxx:192
Reference< XComponentContext > getProcessComponentContext()
const ScDocument & GetDocument() const
Definition: docsh.hxx:216
uno::Reference< frame::XModel > getCurrentExcelDoc(const uno::Reference< uno::XComponentContext > &xContext)
void implnPaste(const uno::Reference< frame::XModel > &xModel)
void SetZoom(const Fraction &rNewX, const Fraction &rNewY, std::vector< SCTAB > &tabs)
Definition: viewdata.cxx:1024
Reference< XModel > xModel
const OUString & GetCodeName() const
Definition: document.hxx:604
ScTabViewShell * GetBestViewShell(bool bOnlyVisible=true)
Definition: docsh4.cxx:2556
void implSetZoom(const uno::Reference< frame::XModel > &xModel, sal_Int16 nZoom, std::vector< SCTAB > &nTabs)
SC_DLLPUBLIC void CellContentChanged()
Definition: tabview3.cxx:509
BasicManager * GetBasicManager() const
sal_Int16 SCTAB
Definition: types.hxx:23
css::uno::Reference< css::script::XLibraryContainer > GetBasicContainer()
void SetName(const OUString &rName)