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