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>
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
46using namespace ::com::sun::star;
47using namespace ::ooo::vba;
48
49namespace ooo::vba::excel {
50
51uno::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
64uno::Reference< sheet::XDatabaseRange >
65GetAutoFiltRange( 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
83ScDocShell* GetDocShellFromRange( const uno::Reference< uno::XInterface >& xRange )
84{
85 ScCellRangesBase* pScCellRangesBase = comphelper::getFromUnoTunnel<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
93uno::Reference< XHelperInterface >
94getUnoSheetModuleObj( 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
101void implSetZoom( const uno::Reference< frame::XModel >& xModel, sal_Int16 nZoom, std::vector< SCTAB >& nTabs )
102{
104 Fraction aFract( nZoom, 100 );
105 pViewSh->GetViewData().SetZoom( aFract, aFract, nTabs );
106 pViewSh->RefreshZoom();
107}
108
109namespace {
110
111class PasteCellsWarningReseter
112{
113private:
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 }
133public:
135 PasteCellsWarningReseter()
136 {
137 bInitialWarningState = getReplaceCellsWarning();
139 setReplaceCellsWarning( false );
140 }
141 ~PasteCellsWarningReseter()
142 {
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
157void
158implnPaste( 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
169void
170implnCopy( 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
189void
190implnCut( 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
209void 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 if (!pTabViewShell)
215 return;
216
217 ScDocShell* pDocShell = getDocShell(xModel);
218 if (!pDocShell)
219 return;
220
221 ScViewData& rView = pTabViewShell->GetViewData();
222 vcl::Window* pWin = rView.GetActiveWin();
223 if (!pWin)
224 return;
225
227 if (pOwnClip)
228 {
229 pTabViewShell->PasteFromClip(nFlags, pOwnClip->GetDocument(),
230 nFunction, bSkipEmpty, bTranspose, false,
232
233 pTabViewShell->CellContentChanged();
234 }
235}
236
238getDocShell( const css::uno::Reference< css::frame::XModel>& xModel )
239{
240 uno::Reference< uno::XInterface > xIf( xModel, uno::UNO_QUERY_THROW );
241 ScModelObj* pModel = dynamic_cast< ScModelObj* >( xIf.get() );
242 ScDocShell* pDocShell = nullptr;
243 if ( pModel )
244 pDocShell = static_cast<ScDocShell*>(pModel->GetEmbeddedObject());
245 return pDocShell;
246
247}
248
250getBestViewShell( const css::uno::Reference< css::frame::XModel>& xModel )
251{
252 ScDocShell* pDocShell = getDocShell( xModel );
253 if ( pDocShell )
254 return pDocShell->GetBestViewShell();
255 return nullptr;
256}
257
259getCurrentBestViewShell( const uno::Reference< uno::XComponentContext >& xContext )
260{
261 uno::Reference< frame::XModel > xModel = getCurrentExcelDoc( xContext );
262 return getBestViewShell( xModel );
263}
264
266getViewFrame( const uno::Reference< frame::XModel >& xModel )
267{
268 ScTabViewShell* pViewShell = getBestViewShell( xModel );
269 if ( pViewShell )
270 return pViewShell->GetViewFrame();
271 return nullptr;
272}
273
274uno::Reference< XHelperInterface >
275getUnoSheetModuleObj( const uno::Reference< sheet::XSpreadsheet >& xSheet )
276{
277 uno::Reference< beans::XPropertySet > xProps( xSheet, uno::UNO_QUERY_THROW );
278 OUString sCodeName;
279 xProps->getPropertyValue("CodeName") >>= sCodeName;
280 // #TODO #FIXME ideally we should 'throw' here if we don't get a valid parent, but... it is possible
281 // to create a module ( and use 'Option VBASupport 1' ) for a calc document, in this scenario there
282 // are *NO* special document module objects ( of course being able to switch between vba/non vba mode at
283 // the document in the future could fix this, especially IF the switching of the vba mode takes care to
284 // create the special document module objects if they don't exist.
285 return getUnoDocModule( sCodeName, GetDocShellFromRange( xSheet ) );
286}
287
288uno::Reference< XHelperInterface >
289getUnoSheetModuleObj( const uno::Reference< sheet::XSheetCellRangeContainer >& xRanges )
290{
291 uno::Reference< container::XEnumerationAccess > xEnumAccess( xRanges, uno::UNO_QUERY_THROW );
292 uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration();
293 uno::Reference< table::XCellRange > xRange( xEnum->nextElement(), uno::UNO_QUERY_THROW );
294 return getUnoSheetModuleObj( xRange );
295}
296
297uno::Reference< XHelperInterface >
298getUnoSheetModuleObj( const uno::Reference< table::XCell >& xCell )
299{
300 uno::Reference< sheet::XSheetCellRange > xSheetRange( xCell, uno::UNO_QUERY_THROW );
301 uno::Reference< sheet::XSpreadsheet > xSheet( xSheetRange->getSpreadsheet(), uno::UNO_SET_THROW );
302 return getUnoSheetModuleObj( xSheet );
303}
304
305uno::Reference< XHelperInterface >
306getUnoSheetModuleObj( const uno::Reference< frame::XModel >& xModel, SCTAB nTab )
307{
308 uno::Reference< sheet::XSpreadsheetDocument > xDoc( xModel, uno::UNO_QUERY_THROW );
309 uno::Reference< container::XIndexAccess > xSheets( xDoc->getSheets(), uno::UNO_QUERY_THROW );
310 uno::Reference< sheet::XSpreadsheet > xSheet( xSheets->getByIndex( nTab ), uno::UNO_QUERY_THROW );
311 return getUnoSheetModuleObj( xSheet );
312}
313
314void setUpDocumentModules( const uno::Reference< sheet::XSpreadsheetDocument >& xDoc )
315{
316 uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY );
318 if ( !pShell )
319 return;
320
321 OUString aPrjName( "Standard" );
322 pShell->GetBasicManager()->SetName( aPrjName );
323
324 /* Set library container to VBA compatibility mode. This will create
325 the VBA Globals object and store it in the Basic manager of the
326 document. */
327 uno::Reference<script::XLibraryContainer> xLibContainer = pShell->GetBasicContainer();
328 uno::Reference<script::vba::XVBACompatibility> xVBACompat( xLibContainer, uno::UNO_QUERY_THROW );
329 xVBACompat->setVBACompatibilityMode( true );
330
331 if( xLibContainer.is() )
332 {
333 if( !xLibContainer->hasByName( aPrjName ) )
334 xLibContainer->createLibrary( aPrjName );
335 uno::Any aLibAny = xLibContainer->getByName( aPrjName );
336 uno::Reference< container::XNameContainer > xLib;
337 aLibAny >>= xLib;
338 if( xLib.is() )
339 {
340 uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY_THROW );
341 uno::Reference< lang::XMultiServiceFactory> xSF( pShell->GetModel(), uno::UNO_QUERY_THROW);
342 uno::Reference< container::XNameAccess > xVBACodeNamedObjectAccess( xSF->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
393{
394 return pRangeObj ? pRangeObj->GetCurrentDataSet( true ) : nullptr;
395}
396
397} // namespace ooo::vba::excel
398
399/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SfxItemSet * GetCurrentDataSet(bool bNoDflt=false)
Definition: cellsuno.cxx:1474
ScDocShell * GetDocShell() const
Definition: cellsuno.hxx:241
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:2608
void SetCodeName(const OUString &r)
Definition: document.hxx:609
const css::uno::Reference< css::script::vba::XVBAEventProcessor > & GetVbaEventProcessor() const
Definition: document.hxx:2530
const OUString & GetCodeName() const
Definition: document.hxx:608
SC_DLLPUBLIC SCTAB GetTableCount() const
Definition: document.cxx:316
SfxObjectShell * GetEmbeddedObject() const
Definition: docuno.cxx:445
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:335
SC_DLLPUBLIC void CellContentChanged()
Definition: tabview3.cxx:513
ScDocument * GetDocument() const
Definition: transobj.hxx:80
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:624
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:872
css::uno::Reference< css::script::XLibraryContainer > GetBasicContainer()
BasicManager * GetBasicManager() const
css::uno::Reference< css::frame::XModel3 > GetModel() 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