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