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 const OUString REPLACE_CELLS_WARNING( "ReplaceCellsWarning");
110 
111 namespace {
112 
113 class PasteCellsWarningReseter
114 {
115 private:
118  static uno::Reference< sheet::XGlobalSheetSettings > const & getGlobalSheetSettings()
119  {
120  static uno::Reference< sheet::XGlobalSheetSettings > xProps = sheet::GlobalSheetSettings::create( comphelper::getProcessComponentContext() );
121  return xProps;
122  }
123 
125  static bool getReplaceCellsWarning()
126  {
127  return getGlobalSheetSettings()->getReplaceCellsWarning();
128  }
129 
131  static void setReplaceCellsWarning( bool bState )
132  {
133  getGlobalSheetSettings()->setReplaceCellsWarning( bState );
134  }
135 public:
137  PasteCellsWarningReseter()
138  {
139  bInitialWarningState = getReplaceCellsWarning();
140  if ( bInitialWarningState )
141  setReplaceCellsWarning( false );
142  }
143  ~PasteCellsWarningReseter()
144  {
145  if ( bInitialWarningState )
146  {
147  // don't allow dtor to throw
148  try
149  {
150  setReplaceCellsWarning( true );
151  }
152  catch ( uno::Exception& /*e*/ ){}
153  }
154  }
155 };
156 
157 }
158 
159 void
160 implnPaste( const uno::Reference< frame::XModel>& xModel )
161 {
162  PasteCellsWarningReseter resetWarningBox;
163  ScTabViewShell* pViewShell = getBestViewShell( xModel );
164  if ( pViewShell )
165  {
166  pViewShell->PasteFromSystem();
167  pViewShell->CellContentChanged();
168  }
169 }
170 
171 void
172 implnCopy( const uno::Reference< frame::XModel>& xModel )
173 {
174  ScTabViewShell* pViewShell = getBestViewShell( xModel );
175  ScDocShell* pDocShell = getDocShell( xModel );
176  if ( pViewShell && pDocShell )
177  {
178  pViewShell->CopyToClip(nullptr,false,false,true);
179 
180  // mark the copied transfer object so it is used in ScVbaRange::Insert
181  uno::Reference<datatransfer::XTransferable2> xTransferable(ScTabViewShell::GetClipData(pViewShell->GetViewData().GetActiveWin()));
182  ScTransferObj* pClipObj = ScTransferObj::GetOwnClipboard(xTransferable);
183  if (pClipObj)
184  {
185  pClipObj->SetUseInApi( true );
186  pDocShell->SetClipData(xTransferable);
187  }
188  }
189 }
190 
191 void
192 implnCut( const uno::Reference< frame::XModel>& xModel )
193 {
194  ScTabViewShell* pViewShell = getBestViewShell( xModel );
195  ScDocShell* pDocShell = getDocShell( xModel );
196  if ( pViewShell && pDocShell )
197  {
198  pViewShell->CutToClip();
199 
200  // mark the copied transfer object so it is used in ScVbaRange::Insert
201  uno::Reference<datatransfer::XTransferable2> xTransferable(ScTabViewShell::GetClipData(pViewShell->GetViewData().GetActiveWin()));
202  ScTransferObj* pClipObj = ScTransferObj::GetOwnClipboard(xTransferable);
203  if (pClipObj)
204  {
205  pClipObj->SetUseInApi( true );
206  pDocShell->SetClipData(xTransferable);
207  }
208  }
209 }
210 
211 void implnPasteSpecial( const uno::Reference< frame::XModel>& xModel, InsertDeleteFlags nFlags, ScPasteFunc nFunction, bool bSkipEmpty, bool bTranspose)
212 {
213  PasteCellsWarningReseter resetWarningBox;
214 
215  ScTabViewShell* pTabViewShell = getBestViewShell( xModel );
216  ScDocShell* pDocShell = getDocShell( xModel );
217  if ( pTabViewShell && pDocShell )
218  {
219  ScViewData& rView = pTabViewShell->GetViewData();
220  vcl::Window* pWin = rView.GetActiveWin();
221  if (pWin)
222  {
223  const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(pDocShell->GetClipData());
224  ScDocument* pDoc = nullptr;
225  if ( pOwnClip )
226  pDoc = pOwnClip->GetDocument();
227  pTabViewShell->PasteFromClip( nFlags, pDoc,
228  nFunction, bSkipEmpty, bTranspose, false,
230  pTabViewShell->CellContentChanged();
231  }
232  }
233 
234 }
235 
236 ScDocShell*
237 getDocShell( const css::uno::Reference< css::frame::XModel>& xModel )
238 {
239  uno::Reference< uno::XInterface > xIf( xModel, uno::UNO_QUERY_THROW );
240  ScModelObj* pModel = dynamic_cast< ScModelObj* >( xIf.get() );
241  ScDocShell* pDocShell = nullptr;
242  if ( pModel )
243  pDocShell = static_cast<ScDocShell*>(pModel->GetEmbeddedObject());
244  return pDocShell;
245 
246 }
247 
249 getBestViewShell( const css::uno::Reference< css::frame::XModel>& xModel )
250 {
251  ScDocShell* pDocShell = getDocShell( xModel );
252  if ( pDocShell )
253  return pDocShell->GetBestViewShell();
254  return nullptr;
255 }
256 
258 getCurrentBestViewShell( const uno::Reference< uno::XComponentContext >& xContext )
259 {
260  uno::Reference< frame::XModel > xModel = getCurrentExcelDoc( xContext );
261  return getBestViewShell( xModel );
262 }
263 
265 getViewFrame( const uno::Reference< frame::XModel >& xModel )
266 {
267  ScTabViewShell* pViewShell = getBestViewShell( xModel );
268  if ( pViewShell )
269  return pViewShell->GetViewFrame();
270  return nullptr;
271 }
272 
273 uno::Reference< XHelperInterface >
274 getUnoSheetModuleObj( const uno::Reference< sheet::XSpreadsheet >& xSheet )
275 {
276  uno::Reference< beans::XPropertySet > xProps( xSheet, uno::UNO_QUERY_THROW );
277  OUString sCodeName;
278  xProps->getPropertyValue("CodeName") >>= sCodeName;
279  // #TODO #FIXME ideally we should 'throw' here if we don't get a valid parent, but... it is possible
280  // to create a module ( and use 'Option VBASupport 1' ) for a calc document, in this scenario there
281  // are *NO* special document module objects ( of course being able to switch between vba/non vba mode at
282  // the document in the future could fix this, especially IF the switching of the vba mode takes care to
283  // create the special document module objects if they don't exist.
284  return getUnoDocModule( sCodeName, GetDocShellFromRange( xSheet ) );
285 }
286 
287 uno::Reference< XHelperInterface >
288 getUnoSheetModuleObj( const uno::Reference< sheet::XSheetCellRangeContainer >& xRanges )
289 {
290  uno::Reference< container::XEnumerationAccess > xEnumAccess( xRanges, uno::UNO_QUERY_THROW );
291  uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration();
292  uno::Reference< table::XCellRange > xRange( xEnum->nextElement(), uno::UNO_QUERY_THROW );
293  return getUnoSheetModuleObj( xRange );
294 }
295 
296 uno::Reference< XHelperInterface >
297 getUnoSheetModuleObj( const uno::Reference< table::XCell >& xCell )
298 {
299  uno::Reference< sheet::XSheetCellRange > xSheetRange( xCell, uno::UNO_QUERY_THROW );
300  uno::Reference< sheet::XSpreadsheet > xSheet( xSheetRange->getSpreadsheet(), uno::UNO_SET_THROW );
301  return getUnoSheetModuleObj( xSheet );
302 }
303 
304 uno::Reference< XHelperInterface >
305 getUnoSheetModuleObj( const uno::Reference< frame::XModel >& xModel, SCTAB nTab )
306 {
307  uno::Reference< sheet::XSpreadsheetDocument > xDoc( xModel, uno::UNO_QUERY_THROW );
308  uno::Reference< container::XIndexAccess > xSheets( xDoc->getSheets(), uno::UNO_QUERY_THROW );
309  uno::Reference< sheet::XSpreadsheet > xSheet( xSheets->getByIndex( nTab ), uno::UNO_QUERY_THROW );
310  return getUnoSheetModuleObj( xSheet );
311 }
312 
313 void setUpDocumentModules( const uno::Reference< sheet::XSpreadsheetDocument >& xDoc )
314 {
315  uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY );
316  ScDocShell* pShell = excel::getDocShell( xModel );
317  if ( pShell )
318  {
319  OUString aPrjName( "Standard" );
320  pShell->GetBasicManager()->SetName( aPrjName );
321 
322  /* Set library container to VBA compatibility mode. This will create
323  the VBA Globals object and store it in the Basic manager of the
324  document. */
325  uno::Reference<script::XLibraryContainer> xLibContainer = pShell->GetBasicContainer();
326  uno::Reference<script::vba::XVBACompatibility> xVBACompat( xLibContainer, uno::UNO_QUERY_THROW );
327  xVBACompat->setVBACompatibilityMode( true );
328 
329  if( xLibContainer.is() )
330  {
331  if( !xLibContainer->hasByName( aPrjName ) )
332  xLibContainer->createLibrary( aPrjName );
333  uno::Any aLibAny = xLibContainer->getByName( aPrjName );
334  uno::Reference< container::XNameContainer > xLib;
335  aLibAny >>= xLib;
336  if( xLib.is() )
337  {
338  uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY_THROW );
339  uno::Reference< lang::XMultiServiceFactory> xSF( pShell->GetModel(), uno::UNO_QUERY_THROW);
340  uno::Reference< container::XNameAccess > xVBACodeNamedObjectAccess( xSF->createInstance("ooo.vba.VBAObjectModuleObjectProvider"), uno::UNO_QUERY_THROW );
341  // set up the module info for the workbook and sheets in the newly created
342  // spreadsheet
343  ScDocument& rDoc = pShell->GetDocument();
344  OUString sCodeName = rDoc.GetCodeName();
345  if ( sCodeName.isEmpty() )
346  {
347  sCodeName = "ThisWorkbook";
348  rDoc.SetCodeName( sCodeName );
349  }
350 
351  std::vector< OUString > sDocModuleNames;
352  sDocModuleNames.push_back( sCodeName );
353 
354  for ( SCTAB index = 0; index < rDoc.GetTableCount(); index++)
355  {
356  OUString aName;
357  rDoc.GetCodeName( index, aName );
358  sDocModuleNames.push_back( aName );
359  }
360 
361  for ( const auto& rName : sDocModuleNames )
362  {
363  script::ModuleInfo sModuleInfo;
364 
365  uno::Any aName= xVBACodeNamedObjectAccess->getByName( rName );
366  sModuleInfo.ModuleObject.set( aName, uno::UNO_QUERY );
367  sModuleInfo.ModuleType = script::ModuleType::DOCUMENT;
368  xVBAModuleInfo->insertModuleInfo( rName, sModuleInfo );
369  if( xLib->hasByName( rName ) )
370  xLib->replaceByName( rName, uno::makeAny( OUString( "Option VBASupport 1\n") ) );
371  else
372  xLib->insertByName( rName, uno::makeAny( OUString( "Option VBASupport 1\n" ) ) );
373  }
374  }
375  }
376 
377  /* Trigger the Workbook_Open event, event processor will register
378  itself as listener for specific events. */
379  try
380  {
381  uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( pShell->GetDocument().GetVbaEventProcessor(), uno::UNO_SET_THROW );
382  uno::Sequence< uno::Any > aArgs;
383  xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_OPEN, aArgs );
384  }
385  catch( uno::Exception& )
386  {
387  }
388  }
389 }
390 
391 SfxItemSet*
393 {
394  return pRangeObj ? pRangeObj->GetCurrentDataSet( true ) : nullptr;
395 }
396 
397 } // namespace ooo::vba::excel
398 
399 /* 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:422
ScDocShell * GetDocShell() const
Definition: cellsuno.hxx:242
const css::uno::Reference< css::script::vba::XVBAEventProcessor > & GetVbaEventProcessor() const
Definition: document.hxx:2440
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:483
ScViewData & GetViewData()
Definition: tabview.hxx:332
ScPasteFunc
Definition: global.hxx:189
ScDocShell * getDocShell(const css::uno::Reference< css::frame::XModel > &xModel)
InsertDeleteFlags
Definition: global.hxx:158
const OUString REPLACE_CELLS_WARNING("ReplaceCellsWarning")
SfxObjectShell * GetEmbeddedObject() const
Definition: docuno.cxx:454
SfxViewFrame * getViewFrame(const uno::Reference< frame::XModel > &xModel)
SfxItemSet * GetCurrentDataSet(bool bNoDflt=false)
Definition: cellsuno.cxx:1510
ScGridWindow * GetActiveWin()
Definition: viewdata.cxx:3069
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:876
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:625
OUString aName
static SC_DLLPUBLIC ScTransferObj * GetOwnClipboard(const css::uno::Reference< css::datatransfer::XTransferable2 > &)
Definition: transobj.cxx:196
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:1046
Reference< XModel > xModel
const OUString & GetCodeName() const
Definition: document.hxx:607
ScTabViewShell * GetBestViewShell(bool bOnlyVisible=true)
Definition: docsh4.cxx:2558
void implSetZoom(const uno::Reference< frame::XModel > &xModel, sal_Int16 nZoom, std::vector< SCTAB > &nTabs)
SC_DLLPUBLIC void CellContentChanged()
Definition: tabview3.cxx:503
BasicManager * GetBasicManager() const
sal_Int16 SCTAB
Definition: types.hxx:23
css::uno::Reference< css::script::XLibraryContainer > GetBasicContainer()
void SetName(const OUString &rName)