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 <com/sun/star/frame/XDesktop.hpp>
21 #include <com/sun/star/lang/XServiceInfo.hpp>
22 #include <com/sun/star/script/BasicErrorException.hpp>
23 #include <com/sun/star/sheet/XCalculatable.hpp>
24 #include <com/sun/star/sheet/XCellRangeAddressable.hpp>
25 #include <com/sun/star/sheet/XNamedRanges.hpp>
26 #include <com/sun/star/sheet/XSpreadsheetView.hpp>
27 #include <com/sun/star/task/XStatusIndicatorSupplier.hpp>
28 #include <com/sun/star/task/XStatusIndicator.hpp>
29 #include <com/sun/star/util/PathSettings.hpp>
30 #include <com/sun/star/view/XSelectionSupplier.hpp>
31 #include <ooo/vba/XCommandBars.hpp>
32 #include <ooo/vba/excel/XApplicationOutgoing.hpp>
33 #include <ooo/vba/excel/XlCalculation.hpp>
34 #include <ooo/vba/excel/XlMousePointer.hpp>
35 #include <ooo/vba/office/MsoShapeType.hpp>
36 #include <ooo/vba/office/MsoAutoShapeType.hpp>
37 #include <ooo/vba/office/MsoFileDialogType.hpp>
38
39 #include "vbaapplication.hxx"
40 #include "vbaworkbooks.hxx"
41 #include "vbaworkbook.hxx"
42 #include "vbarange.hxx"
43 #include "vbawsfunction.hxx"
44 #include "vbadialogs.hxx"
45 #include "vbawindow.hxx"
46 #include "vbawindows.hxx"
47 #include "vbamenubars.hxx"
48 #include <tabvwsh.hxx>
49 #include <gridwin.hxx>
50 #include "vbanames.hxx"
51 #include <vbahelper/vbashape.hxx>
52 #include "vbatextboxshape.hxx"
53 #include "vbaovalshape.hxx"
54 #include "vbalineshape.hxx"
55 #include "vbaassistant.hxx"
56 #include <sc.hrc>
57 #include <macromgr.hxx>
58 #include "vbafiledialog.hxx"
59 #include "vbafiledialogitems.hxx"
60
61 #include <osl/file.hxx>
62
63 #include <sfx2/bindings.hxx>
64 #include <sfx2/request.hxx>
65 #include <sfx2/app.hxx>
66 #include <vcl/svapp.hxx>
67
68 #include <comphelper/diagnose_ex.hxx>
69
70 #include <basic/sbx.hxx>
71 #include <basic/sbstar.hxx>
72 #include <basic/sbuno.hxx>
73 #include <basic/sbmeth.hxx>
74 #include <basic/sberrors.hxx>
75 #include <comphelper/sequence.hxx>
76 #include <cppu/unotype.hxx>
77
78 #include <convuno.hxx>
79 #include <cellsuno.hxx>
80 #include <unonames.hxx>
81 #include <docsh.hxx>
82 #include "excelvbahelper.hxx"
83 #include <basic/sbxobj.hxx>
84
85 #include <viewutil.hxx>
86 #include <docoptio.hxx>
87 #include <scmod.hxx>
88 #include <scdll.hxx>
89
90 #include <list>
91
92 using namespace ::ooo::vba;
93 using namespace ::com::sun::star;
94 using ::com::sun::star::uno::Reference;
95 using ::com::sun::star::uno::UNO_QUERY_THROW;
96 using ::com::sun::star::uno::UNO_QUERY;
97
98 /** Global application settings shared by all open workbooks. */
99 struct ScVbaAppSettings
100 {
101 bool mbDisplayAlerts;
102 bool mbEnableEvents;
103 bool mbExcel4Menus;
104 bool mbDisplayNoteIndicator;
105 bool mbShowWindowsInTaskbar;
106 bool mbEnableCancelKey;
107 explicit ScVbaAppSettings();
108 };
109
ScVbaAppSettings()110 ScVbaAppSettings::ScVbaAppSettings() :
111 mbDisplayAlerts( true ),
112 mbEnableEvents( true ),
113 mbExcel4Menus( false ),
114 mbDisplayNoteIndicator( true ),
115 mbShowWindowsInTaskbar( true ),
116 mbEnableCancelKey( false )
117 {
118 }
119
120 namespace {
121
ScVbaStaticAppSettings()122 ScVbaAppSettings& ScVbaStaticAppSettings()
123 {
124 static ScVbaAppSettings SINGLETON;
125 return SINGLETON;
126 }
127
128 class ScVbaApplicationOutgoingConnectionPoint : public cppu::WeakImplHelper<XConnectionPoint>
129 {
130 private:
131 ScVbaApplication* mpApp;
132
133 public:
134 ScVbaApplicationOutgoingConnectionPoint( ScVbaApplication* pApp );
135
136 // XConnectionPoint
137 sal_uInt32 SAL_CALL Advise(const uno::Reference< XSink >& Sink ) override;
138 void SAL_CALL Unadvise( sal_uInt32 Cookie ) override;
139 };
140
141 }
142
143 sal_uInt32
AddSink(const uno::Reference<XSink> & xSink)144 ScVbaApplication::AddSink( const uno::Reference< XSink >& xSink )
145 {
146 {
147 SolarMutexGuard aGuard;
148 ScDLL::Init();
149 }
150 // No harm in potentially calling this several times
151 ScModule::get()->RegisterAutomationApplicationEventsCaller(uno::Reference<XSinkCaller>(this));
152 mvSinks.push_back(xSink);
153 return mvSinks.size();
154 }
155
156 void
RemoveSink(sal_uInt32 nNumber)157 ScVbaApplication::RemoveSink( sal_uInt32 nNumber )
158 {
159 if (nNumber < 1 || nNumber > mvSinks.size())
160 return;
161
162 mvSinks[nNumber-1] = uno::Reference< XSink >();
163 }
164
ScVbaApplication(const uno::Reference<uno::XComponentContext> & xContext)165 ScVbaApplication::ScVbaApplication( const uno::Reference<uno::XComponentContext >& xContext ) :
166 ScVbaApplication_BASE( xContext ),
167 mrAppSettings( ScVbaStaticAppSettings() ),
168 m_nDialogType(0)
169 {
170 }
171
~ScVbaApplication()172 ScVbaApplication::~ScVbaApplication()
173 {
174 }
175
getDocumentEventsEnabled()176 /*static*/ bool ScVbaApplication::getDocumentEventsEnabled()
177 {
178 return ScVbaStaticAppSettings().mbEnableEvents;
179 }
180
181 OUString SAL_CALL
getExactName(const OUString & aApproximateName)182 ScVbaApplication::getExactName( const OUString& aApproximateName )
183 {
184 uno::Reference< beans::XExactName > xWSF( new ScVbaWSFunction( this, mxContext ) );
185 return xWSF->getExactName( aApproximateName );
186 }
187
188 uno::Reference< beans::XIntrospectionAccess > SAL_CALL
getIntrospection()189 ScVbaApplication::getIntrospection()
190 {
191 uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) );
192 return xWSF->getIntrospection();
193 }
194
195 uno::Any SAL_CALL
invoke(const OUString & FunctionName,const uno::Sequence<uno::Any> & Params,uno::Sequence<sal_Int16> & OutParamIndex,uno::Sequence<uno::Any> & OutParam)196 ScVbaApplication::invoke( const OUString& FunctionName, const uno::Sequence< uno::Any >& Params, uno::Sequence< sal_Int16 >& OutParamIndex, uno::Sequence< uno::Any >& OutParam)
197 {
198 /* When calling the functions directly at the Application object, no runtime
199 errors are thrown, but the error is inserted into the return value. */
200 uno::Any aAny;
201 try
202 {
203 uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) );
204 aAny = xWSF->invoke( FunctionName, Params, OutParamIndex, OutParam );
205 }
206 catch (const uno::Exception&)
207 {
208 aAny <<= script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), 1000, OUString() );
209 }
210 return aAny;
211 }
212
213 void SAL_CALL
setValue(const OUString & PropertyName,const uno::Any & Value)214 ScVbaApplication::setValue( const OUString& PropertyName, const uno::Any& Value )
215 {
216 uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) );
217 xWSF->setValue( PropertyName, Value );
218 }
219
220 uno::Any SAL_CALL
getValue(const OUString & PropertyName)221 ScVbaApplication::getValue( const OUString& PropertyName )
222 {
223 uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) );
224 return xWSF->getValue( PropertyName );
225 }
226
227 sal_Bool SAL_CALL
hasMethod(const OUString & Name)228 ScVbaApplication::hasMethod( const OUString& Name )
229 {
230 uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) );
231 return xWSF->hasMethod( Name );
232 }
233
234 sal_Bool SAL_CALL
hasProperty(const OUString & Name)235 ScVbaApplication::hasProperty( const OUString& Name )
236 {
237 uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) );
238 return xWSF->hasProperty( Name );
239 }
240
241 uno::Reference< excel::XWorkbook >
getActiveWorkbook()242 ScVbaApplication::getActiveWorkbook()
243 {
244 uno::Reference< frame::XModel > xModel( getCurrentExcelDoc( mxContext ), uno::UNO_SET_THROW );
245 uno::Reference< excel::XWorkbook > xWorkbook( getVBADocument( xModel ), uno::UNO_QUERY );
246 if( xWorkbook.is() ) return xWorkbook;
247 // #i116936# getVBADocument() may return null in documents without global VBA mode enabled
248 return new ScVbaWorkbook( this, mxContext, xModel );
249 }
250
251 uno::Reference< excel::XWorkbook > SAL_CALL
getThisWorkbook()252 ScVbaApplication::getThisWorkbook()
253 {
254 uno::Reference< frame::XModel > xModel( getThisExcelDoc( mxContext ), uno::UNO_SET_THROW );
255 uno::Reference< excel::XWorkbook > xWorkbook( getVBADocument( xModel ), uno::UNO_QUERY );
256 if( xWorkbook.is() ) return xWorkbook;
257 // #i116936# getVBADocument() may return null in documents without global VBA mode enabled
258 return new ScVbaWorkbook( this, mxContext, xModel );
259 }
260
261 uno::Reference< XAssistant > SAL_CALL
getAssistant()262 ScVbaApplication::getAssistant()
263 {
264 return uno::Reference< XAssistant >( new ScVbaAssistant( this, mxContext ) );
265 }
266
267 uno::Any SAL_CALL
getSelection()268 ScVbaApplication::getSelection()
269 {
270 uno::Reference< frame::XModel > xModel( getCurrentDocument() );
271
272 Reference< view::XSelectionSupplier > xSelSupp( xModel->getCurrentController(), UNO_QUERY_THROW );
273 Reference< beans::XPropertySet > xPropSet( xSelSupp, UNO_QUERY_THROW );
274 OUString aPropName( SC_UNO_FILTERED_RANGE_SELECTION );
275 uno::Any aOldVal = xPropSet->getPropertyValue( aPropName );
276 uno::Any any;
277 any <<= false;
278 xPropSet->setPropertyValue( aPropName, any );
279 uno::Reference<uno::XInterface> aSelection(xSelSupp->getSelection(), uno::UNO_QUERY);
280 xPropSet->setPropertyValue( aPropName, aOldVal );
281
282 if (!aSelection.is())
283 {
284 throw uno::RuntimeException( u"failed to obtain current selection"_ustr );
285 }
286
287 uno::Reference< lang::XServiceInfo > xServiceInfo( aSelection, uno::UNO_QUERY_THROW );
288 OUString sImplementationName = xServiceInfo->getImplementationName();
289
290 if( sImplementationName.equalsIgnoreAsciiCase("com.sun.star.drawing.SvxShapeCollection") )
291 {
292 uno::Reference< drawing::XShapes > xShapes( aSelection, uno::UNO_QUERY_THROW );
293 uno::Reference< container::XIndexAccess > xIndexAccess( xShapes, uno::UNO_QUERY_THROW );
294 uno::Reference< drawing::XShape > xShape( xIndexAccess->getByIndex(0), uno::UNO_QUERY_THROW );
295 // if ScVbaShape::getType( xShape ) == office::MsoShapeType::msoAutoShape
296 // and the uno object implements the com.sun.star.drawing.Text service
297 // return a textboxshape object
298 sal_Int32 nType = ScVbaShape::getType( xShape );
299 if ( nType == office::MsoShapeType::msoAutoShape )
300 {
301 // TODO Oval with text box
302 if( ScVbaShape::getAutoShapeType( xShape ) == office::MsoAutoShapeType::msoShapeOval )
303 {
304 return uno::Any( uno::Reference< msforms::XOval >(new ScVbaOvalShape( mxContext, xShape, xShapes, xModel ) ) );
305 }
306
307
308 uno::Reference< lang::XServiceInfo > xShapeServiceInfo( xShape, uno::UNO_QUERY_THROW );
309 if ( xShapeServiceInfo->supportsService(u"com.sun.star.drawing.Text"_ustr) )
310 {
311 return uno::Any( uno::Reference< msforms::XTextBoxShape >(
312 new ScVbaTextBoxShape( mxContext, xShape, xShapes, xModel ) ) );
313 }
314 }
315 else if ( nType == office::MsoShapeType::msoLine )
316 {
317 return uno::Any( uno::Reference< msforms::XLine >( new ScVbaLineShape(
318 mxContext, xShape, xShapes, xModel ) ) );
319 }
320 return uno::Any( uno::Reference< msforms::XShape >(new ScVbaShape( this, mxContext, xShape, xShapes, xModel, ScVbaShape::getType( xShape ) ) ) );
321 }
322 else if( xServiceInfo->supportsService(u"com.sun.star.sheet.SheetCellRange"_ustr) ||
323 xServiceInfo->supportsService(u"com.sun.star.sheet.SheetCellRanges"_ustr) )
324 {
325 uno::Reference< table::XCellRange > xRange( aSelection, ::uno::UNO_QUERY);
326 if ( !xRange.is() )
327 {
328 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( aSelection, ::uno::UNO_QUERY);
329 if ( xRanges.is() )
330 return uno::Any( uno::Reference< excel::XRange >( new ScVbaRange( excel::getUnoSheetModuleObj( xRanges ), mxContext, xRanges ) ) );
331
332 }
333 return uno::Any( uno::Reference< excel::XRange >(new ScVbaRange( excel::getUnoSheetModuleObj( xRange ), mxContext, xRange ) ) );
334 }
335 else
336 {
337 throw uno::RuntimeException( sImplementationName + " not supported" );
338 }
339 }
340
341 uno::Reference< excel::XRange >
getActiveCell()342 ScVbaApplication::getActiveCell()
343 {
344 uno::Reference< sheet::XSpreadsheetView > xView( getCurrentDocument()->getCurrentController(), uno::UNO_QUERY_THROW );
345 uno::Reference< table::XCellRange > xRange( xView->getActiveSheet(), ::uno::UNO_QUERY_THROW);
346 ScTabViewShell* pViewShell = excel::getCurrentBestViewShell(mxContext);
347 if ( !pViewShell )
348 throw uno::RuntimeException(u"No ViewShell available"_ustr );
349 ScViewData& rTabView = pViewShell->GetViewData();
350
351 sal_Int32 nCursorX = rTabView.GetCurX();
352 sal_Int32 nCursorY = rTabView.GetCurY();
353
354 // #i117392# excel::getUnoSheetModuleObj() may return null in documents without global VBA mode enabled
355 return new ScVbaRange( excel::getUnoSheetModuleObj( xRange ), mxContext, xRange->getCellRangeByPosition( nCursorX, nCursorY, nCursorX, nCursorY ) );
356 }
357
358 uno::Any SAL_CALL
GetOpenFilename(const uno::Any &,const uno::Any &,const uno::Any & aTitle,const uno::Any &,const uno::Any & aMultiSelect)359 ScVbaApplication::GetOpenFilename(const uno::Any& /*aFileFilter*/, const uno::Any& /*aFilterIndex*/, const uno::Any& aTitle, const uno::Any& /*aButtonText*/, const uno::Any& aMultiSelect)
360 {
361 // TODO - take all parameters into account
362 uno::Reference<excel::XFileDialog> xDialog(new ScVbaFileDialog(this, mxContext, office::MsoFileDialogType::msoFileDialogFilePicker));
363 xDialog->setTitle(aTitle);
364 xDialog->setAllowMultiSelect(aMultiSelect);
365
366 bool bMultiSelect = false;
367 aMultiSelect >>= bMultiSelect;
368
369 if (xDialog->Show() == 0)
370 {
371 // return FALSE when canceled
372 return uno::Any(false);
373 }
374
375 uno::Reference<excel::XFileDialogSelectedItems> xItems = xDialog->getSelectedItems();
376 auto* pItems = dynamic_cast<ScVbaFileDialogSelectedItems*>(xItems.get());
377
378 // Check, if the implementation of XFileDialogSelectedItems is what we expect
379 if (!pItems)
380 throw uno::RuntimeException(u"Unexpected XFileDialogSelectedItems implementation"_ustr);
381
382 auto const & rItemVector = pItems->getItems();
383
384 if (!bMultiSelect) // only 1 selection allowed - return path
385 {
386 OUString aPath;
387 if (!rItemVector.empty())
388 aPath = rItemVector.at(0);
389 return uno::Any(aPath);
390 }
391 else
392 {
393 // convert to sequence
394 return uno::Any(comphelper::containerToSequence(rItemVector));
395 }
396 }
397
398 uno::Any SAL_CALL
International(sal_Int32)399 ScVbaApplication::International( sal_Int32 /*Index*/ )
400 {
401 // complete stub for now
402 // #TODO flesh out some of the Indices we could handle
403 uno::Any aRet;
404 return aRet;
405 }
406
407 uno::Any SAL_CALL
FileDialog(const uno::Any & DialogType)408 ScVbaApplication::FileDialog( const uno::Any& DialogType )
409 {
410 sal_Int32 nType = 0;
411 DialogType >>= nType;
412
413 if( !m_xFileDialog || nType != m_nDialogType )
414 {
415 m_nDialogType = nType;
416 m_xFileDialog = uno::Reference<excel::XFileDialog> ( new ScVbaFileDialog( this, mxContext, nType ));
417 }
418 return uno::Any( m_xFileDialog );
419 }
420
421 uno::Any SAL_CALL
Workbooks(const uno::Any & aIndex)422 ScVbaApplication::Workbooks( const uno::Any& aIndex )
423 {
424 uno::Reference< XCollection > xWorkBooks( new ScVbaWorkbooks( this, mxContext ) );
425 if ( aIndex.getValueTypeClass() == uno::TypeClass_VOID )
426 {
427 // void then somebody did Workbooks.something in vba
428 return uno::Any( xWorkBooks );
429 }
430
431 return xWorkBooks->Item( aIndex, uno::Any() );
432 }
433
434 uno::Any SAL_CALL
Worksheets(const uno::Any & aIndex)435 ScVbaApplication::Worksheets( const uno::Any& aIndex )
436 {
437 uno::Reference< excel::XWorkbook > xWorkbook( getActiveWorkbook(), uno::UNO_SET_THROW );
438 return xWorkbook->Worksheets( aIndex );
439 }
440
441 uno::Any SAL_CALL
WorksheetFunction()442 ScVbaApplication::WorksheetFunction( )
443 {
444 return uno::Any( uno::Reference< script::XInvocation >( new ScVbaWSFunction( this, mxContext ) ) );
445 }
446
447 uno::Any SAL_CALL
Evaluate(const OUString & Name)448 ScVbaApplication::Evaluate( const OUString& Name )
449 {
450 // #TODO Evaluate allows other things to be evaluated, e.g. functions
451 // I think ( like SIN(3) etc. ) need to investigate that
452 // named Ranges also? e.g. [MyRange] if so need a list of named ranges
453 uno::Any aVoid;
454 return uno::Any( getActiveWorkbook()->getActiveSheet()->Range( uno::Any( Name ), aVoid ) );
455 }
456
457 uno::Any
Dialogs(const uno::Any & aIndex)458 ScVbaApplication::Dialogs( const uno::Any &aIndex )
459 {
460 uno::Reference< excel::XDialogs > xDialogs( new ScVbaDialogs( uno::Reference< XHelperInterface >( this ), mxContext, getCurrentDocument() ) );
461 if( !aIndex.hasValue() )
462 return uno::Any( xDialogs );
463 return xDialogs->Item( aIndex );
464 }
465
466 uno::Reference< excel::XWindow > SAL_CALL
getActiveWindow()467 ScVbaApplication::getActiveWindow()
468 {
469 uno::Reference< frame::XModel > xModel = getCurrentDocument();
470 uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW );
471 uno::Reference< XHelperInterface > xParent( getActiveWorkbook(), uno::UNO_QUERY_THROW );
472 uno::Reference< excel::XWindow > xWin( new ScVbaWindow( xParent, mxContext, xModel, xController ) );
473 return xWin;
474 }
475
476 uno::Any SAL_CALL
getCutCopyMode()477 ScVbaApplication::getCutCopyMode()
478 {
479 //# FIXME TODO, implementation
480 uno::Any result;
481 result <<= false;
482 return result;
483 }
484
485 void SAL_CALL
setCutCopyMode(const uno::Any &)486 ScVbaApplication::setCutCopyMode( const uno::Any& /* _cutcopymode */ )
487 {
488 //# FIXME TODO, implementation
489 }
490
491 uno::Any SAL_CALL
getStatusBar()492 ScVbaApplication::getStatusBar()
493 {
494 return uno::Any( !getDisplayStatusBar() );
495 }
496
getWindowState()497 css::uno::Any SAL_CALL ScVbaApplication::getWindowState()
498 {
499 return getActiveWindow()->getWindowState();
500 }
501
setWindowState(const css::uno::Any & rWindowState)502 void SAL_CALL ScVbaApplication::setWindowState(const css::uno::Any& rWindowState)
503 {
504 getActiveWindow()->setWindowState(rWindowState);
505 }
506
507 void SAL_CALL
setStatusBar(const uno::Any & _statusbar)508 ScVbaApplication::setStatusBar( const uno::Any& _statusbar )
509 {
510 OUString sText;
511 bool bDefault = false;
512 uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW );
513 uno::Reference< task::XStatusIndicatorSupplier > xStatusIndicatorSupplier( xModel->getCurrentController(), uno::UNO_QUERY_THROW );
514 uno::Reference< task::XStatusIndicator > xStatusIndicator( xStatusIndicatorSupplier->getStatusIndicator(), uno::UNO_SET_THROW );
515 if( _statusbar >>= sText )
516 {
517 setDisplayStatusBar( true );
518 if ( !sText.isEmpty() )
519 xStatusIndicator->start( sText, 100 );
520 else
521 xStatusIndicator->end(); // restore normal state for empty text
522 }
523 else if( _statusbar >>= bDefault )
524 {
525 if( !bDefault )
526 {
527 xStatusIndicator->end();
528 setDisplayStatusBar( true );
529 }
530 }
531 else
532 throw uno::RuntimeException(u"Invalid parameter. It should be a string or False"_ustr );
533 }
534
535 ::sal_Int32 SAL_CALL
getCalculation()536 ScVbaApplication::getCalculation()
537 {
538 // TODO: in Excel, this is an application-wide setting
539 uno::Reference<sheet::XCalculatable> xCalc(getCurrentDocument(), uno::UNO_QUERY_THROW);
540 if(xCalc->isAutomaticCalculationEnabled())
541 return excel::XlCalculation::xlCalculationAutomatic;
542 else
543 return excel::XlCalculation::xlCalculationManual;
544 }
545
546 void SAL_CALL
setCalculation(::sal_Int32 _calculation)547 ScVbaApplication::setCalculation( ::sal_Int32 _calculation )
548 {
549 // TODO: in Excel, this is an application-wide setting
550 uno::Reference< sheet::XCalculatable > xCalc(getCurrentDocument(), uno::UNO_QUERY_THROW);
551 switch(_calculation)
552 {
553 case excel::XlCalculation::xlCalculationManual:
554 xCalc->enableAutomaticCalculation(false);
555 break;
556 case excel::XlCalculation::xlCalculationAutomatic:
557 case excel::XlCalculation::xlCalculationSemiautomatic:
558 xCalc->enableAutomaticCalculation(true);
559 break;
560 }
561 }
562
563 uno::Any SAL_CALL
Windows(const uno::Any & aIndex)564 ScVbaApplication::Windows( const uno::Any& aIndex )
565 {
566 uno::Reference< excel::XWindows > xWindows( new ScVbaWindows( this, mxContext ) );
567 if ( aIndex.getValueTypeClass() == uno::TypeClass_VOID )
568 return uno::Any( xWindows );
569 return xWindows->Item( aIndex, uno::Any() );
570 }
571 void SAL_CALL
wait(double time)572 ScVbaApplication::wait( double time )
573 {
574 StarBASIC* pBasic = SfxApplication::GetBasic();
575 SbxArrayRef aArgs = new SbxArray;
576 SbxVariableRef aRef = new SbxVariable;
577 aRef->PutDouble( time );
578 aArgs->Put(aRef.get(), 1);
579 SbMethod* pMeth = static_cast<SbMethod*>(pBasic->GetRtl()->Find( u"WaitUntil"_ustr, SbxClassType::Method ));
580
581 if ( pMeth )
582 {
583 pMeth->SetParameters( aArgs.get() );
584 SbxVariableRef refTemp = pMeth;
585 // forces a broadcast
586 SbxVariableRef pNew = new SbxMethod( *static_cast<SbxMethod*>(pMeth));
587 }
588 }
589
590 uno::Any SAL_CALL
Range(const uno::Any & Cell1,const uno::Any & Cell2)591 ScVbaApplication::Range( const uno::Any& Cell1, const uno::Any& Cell2 )
592 {
593 uno::Reference< excel::XRange > xVbRange = ScVbaRange::ApplicationRange( mxContext, Cell1, Cell2 );
594 return uno::Any( xVbRange );
595 }
596
597 uno::Any SAL_CALL
Names(const css::uno::Any & aIndex)598 ScVbaApplication::Names( const css::uno::Any& aIndex )
599 {
600 uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW );
601 uno::Reference< beans::XPropertySet > xPropertySet( xModel, uno::UNO_QUERY_THROW );
602 uno::Reference< sheet::XNamedRanges > xNamedRanges( xPropertySet->getPropertyValue(
603 u"NamedRanges"_ustr ), uno::UNO_QUERY_THROW );
604
605 css::uno::Reference< excel::XNames > xNames ( new ScVbaNames( this , mxContext , xNamedRanges , xModel ) );
606 if ( aIndex.getValueTypeClass() == uno::TypeClass_VOID )
607 {
608 return uno::Any( xNames );
609 }
610 return xNames->Item( aIndex, uno::Any() );
611 }
612
613 uno::Reference< excel::XWorksheet > SAL_CALL
getActiveSheet()614 ScVbaApplication::getActiveSheet()
615 {
616 uno::Reference< excel::XWorksheet > result;
617 uno::Reference< excel::XWorkbook > xWorkbook = getActiveWorkbook();
618 if ( xWorkbook.is() )
619 {
620 uno::Reference< excel::XWorksheet > xWorksheet =
621 xWorkbook->getActiveSheet();
622 if ( xWorksheet.is() )
623 {
624 result = std::move(xWorksheet);
625 }
626 }
627
628 if ( !result.is() )
629 {
630 // Fixme - check if this is reasonable/desired behavior
631 throw uno::RuntimeException(u"No activeSheet available"_ustr );
632 }
633 return result;
634
635 }
636
637 /*******************************************************************************
638 * In msdn:
639 * Reference Optional Variant. The destination. Can be a Range
640 * object, a string that contains a cell reference in R1C1-style notation,
641 * or a string that contains a Visual Basic procedure name.
642 * Scroll Optional Variant. True to scroll, False to not scroll through
643 * the window. The default is False.
644 * Parser is split to three parts, Range, R1C1 string and procedure name.
645 * by test excel, it seems Scroll no effect. ???
646 *******************************************************************************/
647 void SAL_CALL
GoTo(const uno::Any & Reference,const uno::Any & Scroll)648 ScVbaApplication::GoTo( const uno::Any& Reference, const uno::Any& Scroll )
649 {
650 //test Scroll is a boolean
651 bool bScroll = false;
652 //R1C1-style string or a string of procedure name.
653
654 if( Scroll.hasValue() )
655 {
656 bool aScroll = false;
657 if( !(Scroll >>= aScroll) )
658 throw uno::RuntimeException(u"second parameter should be boolean"_ustr );
659
660 bScroll = aScroll;
661
662 }
663
664 OUString sRangeName;
665 if( Reference >>= sRangeName )
666 {
667 ScTabViewShell* pShell = excel::getCurrentBestViewShell( mxContext );
668 if (!pShell)
669 return;
670
671 uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW );
672 uno::Reference< sheet::XSpreadsheetView > xSpreadsheet(
673 xModel->getCurrentController(), uno::UNO_QUERY_THROW );
674
675 ScGridWindow* gridWindow = static_cast<ScGridWindow*>(pShell->GetWindow());
676 try
677 {
678 uno::Reference< excel::XRange > xVbaSheetRange = ScVbaRange::getRangeObjectForName(
679 mxContext, sRangeName, excel::getDocShell( xModel ), formula::FormulaGrammar::CONV_XL_R1C1 );
680
681 if( bScroll )
682 {
683 xVbaSheetRange->Select();
684 uno::Reference< excel::XWindow > xWindow = getActiveWindow();
685 ScSplitPos eWhich = pShell->GetViewData().GetActivePart();
686 sal_Int32 nValueX = pShell->GetViewData().GetPosX(WhichH(eWhich));
687 sal_Int32 nValueY = pShell->GetViewData().GetPosY(WhichV(eWhich));
688 xWindow->SmallScroll( uno::Any( static_cast<sal_Int16>(xVbaSheetRange->getRow() - 1) ),
689 uno::Any( static_cast<sal_Int16>(nValueY) ),
690 uno::Any( static_cast<sal_Int16>(xVbaSheetRange->getColumn() - 1) ),
691 uno::Any( static_cast<sal_Int16>(nValueX) ) );
692 gridWindow->GrabFocus();
693 }
694 else
695 {
696 xVbaSheetRange->Select();
697 gridWindow->GrabFocus();
698 }
699 }
700 catch (const uno::RuntimeException&)
701 {
702 //maybe this should be a procedure name
703 //TODO for procedure name
704 //browse::XBrowseNodeFactory is a singleton. OUString( "/singletons/com.sun.star.script.browse.theBrowseNodeFactory")
705 //and the createView( browse::BrowseNodeFactoryViewTypes::MACROSELECTOR ) to get a root browse::XBrowseNode.
706 //for query XInvocation interface.
707 //but how to directly get the XInvocation?
708 throw uno::RuntimeException(u"invalid reference for range name, it should be procedure name"_ustr );
709 }
710 return;
711 }
712 uno::Reference< excel::XRange > xRange;
713 if( Reference >>= xRange )
714 {
715 ScTabViewShell* pShell = excel::getCurrentBestViewShell( mxContext );
716 if (!pShell)
717 return;
718
719 uno::Reference< excel::XRange > xVbaRange( Reference, uno::UNO_QUERY );
720 ScGridWindow* gridWindow = static_cast<ScGridWindow*>(pShell->GetWindow());
721 if ( xVbaRange.is() )
722 {
723 //TODO bScroll should be used. At this time, it does not have effect
724 if( bScroll )
725 {
726 xVbaRange->Select();
727 uno::Reference< excel::XWindow > xWindow = getActiveWindow();
728 ScSplitPos eWhich = pShell->GetViewData().GetActivePart();
729 sal_Int32 nValueX = pShell->GetViewData().GetPosX(WhichH(eWhich));
730 sal_Int32 nValueY = pShell->GetViewData().GetPosY(WhichV(eWhich));
731 xWindow->SmallScroll( uno::Any( static_cast<sal_Int16>(xVbaRange->getRow() - 1) ),
732 uno::Any( static_cast<sal_Int16>(nValueY) ),
733 uno::Any( static_cast<sal_Int16>(xVbaRange->getColumn() - 1) ),
734 uno::Any( static_cast<sal_Int16>(nValueX) ) );
735 gridWindow->GrabFocus();
736 }
737 else
738 {
739 xVbaRange->Select();
740 gridWindow->GrabFocus();
741 }
742 }
743 return;
744 }
745 throw uno::RuntimeException(u"invalid reference or name"_ustr );
746 }
747
748 sal_Int32 SAL_CALL
getCursor()749 ScVbaApplication::getCursor()
750 {
751 PointerStyle nPointerStyle = getPointerStyle(getCurrentDocument());
752
753 switch( nPointerStyle )
754 {
755 case PointerStyle::Arrow:
756 return excel::XlMousePointer::xlNorthwestArrow;
757 case PointerStyle::Null:
758 return excel::XlMousePointer::xlDefault;
759 case PointerStyle::Wait:
760 return excel::XlMousePointer::xlWait;
761 case PointerStyle::Text:
762 return excel::XlMousePointer::xlIBeam;
763 default:
764 return excel::XlMousePointer::xlDefault;
765 }
766 }
767
768 void SAL_CALL
setCursor(sal_Int32 _cursor)769 ScVbaApplication::setCursor( sal_Int32 _cursor )
770 {
771 try
772 {
773 uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW );
774 switch( _cursor )
775 {
776 case excel::XlMousePointer::xlNorthwestArrow:
777 {
778 setCursorHelper( xModel, PointerStyle::Arrow, false );
779 break;
780 }
781 case excel::XlMousePointer::xlWait:
782 case excel::XlMousePointer::xlIBeam:
783 {
784 PointerStyle nPointer( static_cast< PointerStyle >( _cursor ) );
785 //It will set the edit window, toobar and statusbar's mouse pointer.
786 setCursorHelper( xModel, nPointer, true );
787 break;
788 }
789 case excel::XlMousePointer::xlDefault:
790 {
791 setCursorHelper( xModel, PointerStyle::Null, false );
792 break;
793 }
794 default:
795 throw uno::RuntimeException(u"Unknown value for Cursor pointer"_ustr );
796 // TODO: isn't this a flaw in the API? It should be allowed to throw an
797 // IllegalArgumentException, or so
798 }
799 }
800 catch (const uno::Exception&)
801 {
802 DBG_UNHANDLED_EXCEPTION("sc.ui");
803 }
804 }
805
806 // #TODO perhaps we should switch the return type depending of the filter
807 // type, e.g. return Calc for Calc and Excel if it's an imported doc
808 OUString SAL_CALL
getName()809 ScVbaApplication::getName()
810 {
811 return u"Microsoft Excel"_ustr;
812 }
813
814 // #TODO #FIXME get/setDisplayAlerts are just stub impl
815 // here just the status of the switch is set
816 // the function that throws an error message needs to
817 // evaluate this switch in order to know whether it has to disable the
818 // error message thrown by OpenOffice
819
820 void SAL_CALL
setDisplayAlerts(sal_Bool displayAlerts)821 ScVbaApplication::setDisplayAlerts(sal_Bool displayAlerts)
822 {
823 mrAppSettings.mbDisplayAlerts = displayAlerts;
824 }
825
826 sal_Bool SAL_CALL
getDisplayAlerts()827 ScVbaApplication::getDisplayAlerts()
828 {
829 return mrAppSettings.mbDisplayAlerts;
830 }
831
832 void SAL_CALL
setEnableEvents(sal_Bool bEnable)833 ScVbaApplication::setEnableEvents(sal_Bool bEnable)
834 {
835 mrAppSettings.mbEnableEvents = bEnable;
836 }
837
838 sal_Bool SAL_CALL
getEnableEvents()839 ScVbaApplication::getEnableEvents()
840 {
841 return mrAppSettings.mbEnableEvents;
842 }
843
844 void SAL_CALL
setEnableCancelKey(sal_Bool bEnable)845 ScVbaApplication::setEnableCancelKey(sal_Bool bEnable)
846 {
847 // Stub, does nothing
848 mrAppSettings.mbEnableCancelKey = bEnable;
849 }
850
851 sal_Bool SAL_CALL
getEnableCancelKey()852 ScVbaApplication::getEnableCancelKey()
853 {
854 return mrAppSettings.mbEnableCancelKey;
855 }
856
857 sal_Bool SAL_CALL
getDisplayFullScreen()858 ScVbaApplication::getDisplayFullScreen()
859 {
860 SfxViewShell* pShell = excel::getCurrentBestViewShell( mxContext );
861 if ( pShell )
862 return ScViewUtil::IsFullScreen( *pShell );
863 return false;
864 }
865
866 void SAL_CALL
setDisplayFullScreen(sal_Bool bSet)867 ScVbaApplication::setDisplayFullScreen( sal_Bool bSet )
868 {
869 // #FIXME calling ScViewUtil::SetFullScreen( *pShell, bSet );
870 // directly results in a strange crash, using dispatch instead
871 if ( bSet != getDisplayFullScreen() )
872 dispatchRequests( getCurrentDocument(), u".uno:FullScreen"_ustr );
873 }
874
875 sal_Bool SAL_CALL
getDisplayScrollBars()876 ScVbaApplication::getDisplayScrollBars()
877 {
878 ScTabViewShell* pShell = excel::getCurrentBestViewShell( mxContext );
879 if ( pShell )
880 {
881 return ( pShell->GetViewData().IsHScrollMode() && pShell->GetViewData().IsVScrollMode() );
882 }
883 return true;
884 }
885
886 void SAL_CALL
setDisplayScrollBars(sal_Bool bSet)887 ScVbaApplication::setDisplayScrollBars( sal_Bool bSet )
888 {
889 // use uno here as it does all he repainting etc. magic
890 uno::Reference< sheet::XSpreadsheetView > xView( getCurrentDocument()->getCurrentController(), uno::UNO_QUERY_THROW );
891 uno::Reference< beans::XPropertySet > xProps( xView, uno::UNO_QUERY );
892 xProps->setPropertyValue(u"HasVerticalScrollBar"_ustr, uno::Any( bSet ) );
893 xProps->setPropertyValue(u"HasHorizontalScrollBar"_ustr, uno::Any( bSet ) );
894 }
895
896 sal_Bool SAL_CALL
getDisplayExcel4Menus()897 ScVbaApplication::getDisplayExcel4Menus()
898 {
899 return mrAppSettings.mbExcel4Menus;
900 }
901
902 void SAL_CALL
setDisplayExcel4Menus(sal_Bool bSet)903 ScVbaApplication::setDisplayExcel4Menus( sal_Bool bSet )
904 {
905 mrAppSettings.mbExcel4Menus = bSet;
906 }
907
908 sal_Bool SAL_CALL
getDisplayNoteIndicator()909 ScVbaApplication::getDisplayNoteIndicator()
910 {
911 return mrAppSettings.mbDisplayNoteIndicator;
912 }
913
914 void SAL_CALL
setDisplayNoteIndicator(sal_Bool bSet)915 ScVbaApplication::setDisplayNoteIndicator( sal_Bool bSet )
916 {
917 mrAppSettings.mbDisplayNoteIndicator = bSet;
918 }
919
920 sal_Bool SAL_CALL
getShowWindowsInTaskbar()921 ScVbaApplication::getShowWindowsInTaskbar()
922 {
923 return mrAppSettings.mbShowWindowsInTaskbar;
924 }
925
926 void SAL_CALL
setShowWindowsInTaskbar(sal_Bool bSet)927 ScVbaApplication::setShowWindowsInTaskbar( sal_Bool bSet )
928 {
929 mrAppSettings.mbShowWindowsInTaskbar = bSet;
930 }
931
932 sal_Bool SAL_CALL
getIteration()933 ScVbaApplication::getIteration()
934 {
935 return ScModule::get()->GetDocOptions().IsIter();
936 }
937
938 void SAL_CALL
setIteration(sal_Bool bSet)939 ScVbaApplication::setIteration( sal_Bool bSet )
940 {
941 uno::Reference< lang::XMultiComponentFactory > xSMgr(
942 mxContext->getServiceManager(), uno::UNO_SET_THROW );
943
944 uno::Reference< frame::XDesktop > xDesktop
945 (xSMgr->createInstanceWithContext( u"com.sun.star.frame.Desktop"_ustr , mxContext), uno::UNO_QUERY_THROW );
946 uno::Reference< container::XEnumeration > xComponents = xDesktop->getComponents()->createEnumeration();
947 while ( xComponents->hasMoreElements() )
948 {
949 uno::Reference< lang::XServiceInfo > xServiceInfo( xComponents->nextElement(), uno::UNO_QUERY );
950 if ( xServiceInfo.is() && xServiceInfo->supportsService( u"com.sun.star.sheet.SpreadsheetDocument"_ustr ) )
951 {
952 uno::Reference< beans::XPropertySet > xProps( xServiceInfo, uno::UNO_QUERY );
953 if ( xProps.is() )
954 xProps->setPropertyValue( SC_UNO_ITERENABLED, uno::Any( bSet ) );
955 }
956 }
957 ScModule* mod = ScModule::get();
958 ScDocOptions aOpts(mod->GetDocOptions());
959 aOpts.SetIter( bSet );
960 mod->SetDocOptions(aOpts);
961 }
962
963 void SAL_CALL
Calculate()964 ScVbaApplication::Calculate()
965 {
966 uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW );
967 uno::Reference< sheet::XCalculatable > xCalculatable( getCurrentDocument(), uno::UNO_QUERY_THROW );
968 xCalculatable->calculateAll();
969 }
970
971 /// @throws uno::RuntimeException
lcl_getPathSettingsService(const uno::Reference<uno::XComponentContext> & xContext)972 static uno::Reference< util::XPathSettings > const & lcl_getPathSettingsService( const uno::Reference< uno::XComponentContext >& xContext )
973 {
974 static uno::Reference< util::XPathSettings > xPathSettings( util::PathSettings::create( xContext ) );
975 return xPathSettings;
976 }
977
getOfficePath(const OUString & _sPathType)978 OUString ScVbaApplication::getOfficePath( const OUString& _sPathType )
979 {
980 OUString sRetPath;
981 const uno::Reference< util::XPathSettings >& xProps = lcl_getPathSettingsService( mxContext );
982 try
983 {
984 OUString sUrl;
985 xProps->getPropertyValue( _sPathType ) >>= sUrl;
986
987 // if it's a list of paths then use the last one
988 sal_Int32 nIndex = sUrl.lastIndexOf( ';' ) ;
989 if ( nIndex > 0 )
990 sUrl = sUrl.copy( nIndex + 1 );
991 ::osl::File::getSystemPathFromFileURL( sUrl, sRetPath );
992 }
993 catch (const uno::Exception&)
994 {
995 DebugHelper::runtimeexception(ERRCODE_BASIC_METHOD_FAILED);
996 }
997 return sRetPath;
998 }
999
1000 void SAL_CALL
setDefaultFilePath(const OUString & DefaultFilePath)1001 ScVbaApplication::setDefaultFilePath( const OUString& DefaultFilePath )
1002 {
1003 const uno::Reference< util::XPathSettings >& xProps = lcl_getPathSettingsService( mxContext );
1004 OUString aURL;
1005 osl::FileBase::getFileURLFromSystemPath( DefaultFilePath, aURL );
1006 xProps->setWork( aURL );
1007 }
1008
1009 OUString SAL_CALL
getDefaultFilePath()1010 ScVbaApplication::getDefaultFilePath()
1011 {
1012 return getOfficePath( u"Work"_ustr);
1013 }
1014
1015 OUString SAL_CALL
getLibraryPath()1016 ScVbaApplication::getLibraryPath()
1017 {
1018 return getOfficePath( u"Basic"_ustr);
1019 }
1020
1021 OUString SAL_CALL
getTemplatesPath()1022 ScVbaApplication::getTemplatesPath()
1023 {
1024 return getOfficePath( u"Template"_ustr);
1025 }
1026
1027 OUString SAL_CALL
getPathSeparator()1028 ScVbaApplication::getPathSeparator()
1029 {
1030 return OUString( sal_Unicode(SAL_PATHDELIMITER) );
1031 }
1032
1033 OUString SAL_CALL
getOperatingSystem()1034 ScVbaApplication::getOperatingSystem()
1035 {
1036 // TODO Solution should contain the version number of the operating system
1037 // too.
1038 #if defined(_WIN32)
1039 return "Windows";
1040 #elif defined(MACOSX)
1041 return "Macintosh";
1042 #elif defined(UNX)
1043 // M. Office is not available on Unix systems, so it is not documented.
1044 return u"Unix"_ustr;
1045 #else
1046 return OUString("Unknown");
1047 #endif
1048 }
1049
1050 // Helpers for Intersect and Union
1051
1052 namespace {
1053
1054 typedef ::std::list< ScRange > ListOfScRange;
1055
1056 /** Appends all ranges of a VBA Range object in the passed Any to the list of ranges.
1057
1058 @throws script::BasicErrorException
1059 @throws uno::RuntimeException
1060 */
lclAddToListOfScRange(ListOfScRange & rList,const uno::Any & rArg)1061 void lclAddToListOfScRange( ListOfScRange& rList, const uno::Any& rArg )
1062 {
1063 if( !rArg.hasValue() )
1064 return;
1065
1066 uno::Reference< excel::XRange > xRange( rArg, uno::UNO_QUERY_THROW );
1067 uno::Reference< XCollection > xCol( xRange->Areas( uno::Any() ), uno::UNO_QUERY_THROW );
1068 for( sal_Int32 nIdx = 1, nCount = xCol->getCount(); nIdx <= nCount; ++nIdx )
1069 {
1070 uno::Reference< excel::XRange > xAreaRange( xCol->Item( uno::Any( nIdx ), uno::Any() ), uno::UNO_QUERY_THROW );
1071 uno::Reference< sheet::XCellRangeAddressable > xAddressable( xAreaRange->getCellRange(), uno::UNO_QUERY_THROW );
1072 ScRange aScRange;
1073 ScUnoConversion::FillScRange( aScRange, xAddressable->getRangeAddress() );
1074 rList.push_back( aScRange );
1075 }
1076 }
1077
1078 /** Returns true, if the passed ranges can be expressed by a single range. The
1079 new range will be contained in r1 then, the range r2 can be removed. */
lclTryJoin(ScRange & r1,const ScRange & r2)1080 bool lclTryJoin( ScRange& r1, const ScRange& r2 )
1081 {
1082 // 1) r2 is completely inside r1
1083 if( r1.Contains( r2 ) )
1084 return true;
1085
1086 // 2) r1 is completely inside r2
1087 if( r2.Contains( r1 ) )
1088 {
1089 r1 = r2;
1090 return true;
1091 }
1092
1093 SCCOL n1L = r1.aStart.Col();
1094 SCCOL n1R = r1.aEnd.Col();
1095 SCROW n1T = r1.aStart.Row();
1096 SCROW n1B = r1.aEnd.Row();
1097 SCCOL n2L = r2.aStart.Col();
1098 SCCOL n2R = r2.aEnd.Col();
1099 SCROW n2T = r2.aStart.Row();
1100 SCROW n2B = r2.aEnd.Row();
1101
1102 // 3) r1 and r2 have equal upper and lower border
1103 if( (n1T == n2T) && (n1B == n2B) )
1104 {
1105 // check that r1 overlaps or touches r2
1106 if( ((n1L < n2L) && (n2L - 1 <= n1R)) || ((n2L < n1L) && (n1L - 1 <= n2R)) )
1107 {
1108 r1.aStart.SetCol( ::std::min( n1L, n2L ) );
1109 r1.aEnd.SetCol( ::std::max( n1R, n2R ) );
1110 return true;
1111 }
1112 return false;
1113 }
1114
1115 // 4) r1 and r2 have equal left and right border
1116 if( (n1L == n2L) && (n1R == n2R) )
1117 {
1118 // check that r1 overlaps or touches r2
1119 if( ((n1T < n2T) && (n2T + 1 <= n1B)) || ((n2T < n1T) && (n1T + 1 <= n2B)) )
1120 {
1121 r1.aStart.SetRow( ::std::min( n1T, n2T ) );
1122 r1.aEnd.SetRow( ::std::max( n1B, n2B ) );
1123 return true;
1124 }
1125 return false;
1126 }
1127
1128 // 5) cannot join these ranges
1129 return false;
1130 }
1131
1132 /** Strips out ranges that are contained by other ranges, joins ranges that can be joined
1133 together (aligned borders, e.g. A4:D10 and B4:E10 would be combined to A4:E10. */
lclJoinRanges(ListOfScRange & rList)1134 void lclJoinRanges( ListOfScRange& rList )
1135 {
1136 ListOfScRange::iterator aOuterIt = rList.begin();
1137 while( aOuterIt != rList.end() )
1138 {
1139 bool bAnyErased = false; // true = any range erased from rList
1140 ListOfScRange::iterator aInnerIt = rList.begin();
1141 while( aInnerIt != rList.end() )
1142 {
1143 bool bInnerErased = false; // true = aInnerIt erased from rList
1144 // do not compare a range with itself
1145 if( (aOuterIt != aInnerIt) && lclTryJoin( *aOuterIt, *aInnerIt ) )
1146 {
1147 // aOuterIt points to joined range, aInnerIt will be removed
1148 aInnerIt = rList.erase( aInnerIt );
1149 bInnerErased = bAnyErased = true;
1150 }
1151 /* If aInnerIt has been erased from rList, it already points to
1152 the next element (return value of list::erase()). */
1153 if( !bInnerErased )
1154 ++aInnerIt;
1155 }
1156 // if any range has been erased, repeat outer loop with the same range
1157 if( !bAnyErased )
1158 ++aOuterIt;
1159 }
1160 }
1161
1162 /** Intersects the passed list with all ranges of a VBA Range object in the passed Any.
1163
1164 @throws script::BasicErrorException
1165 @throws uno::RuntimeException
1166 */
lclIntersectRanges(ListOfScRange & rList,const uno::Any & rArg)1167 void lclIntersectRanges( ListOfScRange& rList, const uno::Any& rArg )
1168 {
1169 // extract the ranges from the passed argument, will throw on invalid data
1170 ListOfScRange aList2;
1171 lclAddToListOfScRange( aList2, rArg );
1172 // do nothing, if the passed list is already empty
1173 if( rList.empty() || aList2.empty() )
1174 return;
1175
1176 // save original list in a local
1177 ListOfScRange aList1;
1178 aList1.swap( rList );
1179 // join ranges from passed argument
1180 lclJoinRanges( aList2 );
1181 // calculate intersection of the ranges in both lists
1182 for( const auto& rOuterItem : aList1 )
1183 {
1184 for( const auto& rInnerItem : aList2 )
1185 {
1186 if( rOuterItem.Intersects( rInnerItem ) )
1187 {
1188 ScRange aIsectRange(
1189 std::max( rOuterItem.aStart.Col(), rInnerItem.aStart.Col() ),
1190 std::max( rOuterItem.aStart.Row(), rInnerItem.aStart.Row() ),
1191 std::max( rOuterItem.aStart.Tab(), rInnerItem.aStart.Tab() ),
1192 std::min( rOuterItem.aEnd.Col(), rInnerItem.aEnd.Col() ),
1193 std::min( rOuterItem.aEnd.Row(), rInnerItem.aEnd.Row() ),
1194 std::min( rOuterItem.aEnd.Tab(), rInnerItem.aEnd.Tab() ) );
1195 rList.push_back( aIsectRange );
1196 }
1197 }
1198 }
1199 // again, join the result ranges
1200 lclJoinRanges( rList );
1201 }
1202
1203 /** Creates a VBA Range object from the passed list of ranges.
1204
1205 @throws uno::RuntimeException
1206 */
lclCreateVbaRange(const uno::Reference<uno::XComponentContext> & rxContext,const uno::Reference<frame::XModel> & rxModel,const ListOfScRange & rList)1207 uno::Reference< excel::XRange > lclCreateVbaRange(
1208 const uno::Reference< uno::XComponentContext >& rxContext,
1209 const uno::Reference< frame::XModel >& rxModel,
1210 const ListOfScRange& rList )
1211 {
1212 ScDocShell* pDocShell = excel::getDocShell( rxModel );
1213 if( !pDocShell )
1214 throw uno::RuntimeException();
1215
1216 ScRangeList aCellRanges;
1217 for( const auto& rItem : rList )
1218 aCellRanges.push_back( rItem );
1219
1220 if( aCellRanges.size() == 1 )
1221 {
1222 uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pDocShell, aCellRanges.front() ) );
1223 return new ScVbaRange( excel::getUnoSheetModuleObj( xRange ), rxContext, xRange );
1224 }
1225 if( aCellRanges.size() > 1 )
1226 {
1227 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pDocShell, aCellRanges ) );
1228 return new ScVbaRange( excel::getUnoSheetModuleObj( xRanges ), rxContext, xRanges );
1229 }
1230 return nullptr;
1231 }
1232
1233 } // namespace
1234
Intersect(const uno::Reference<excel::XRange> & rArg1,const uno::Reference<excel::XRange> & rArg2,const uno::Any & rArg3,const uno::Any & rArg4,const uno::Any & rArg5,const uno::Any & rArg6,const uno::Any & rArg7,const uno::Any & rArg8,const uno::Any & rArg9,const uno::Any & rArg10,const uno::Any & rArg11,const uno::Any & rArg12,const uno::Any & rArg13,const uno::Any & rArg14,const uno::Any & rArg15,const uno::Any & rArg16,const uno::Any & rArg17,const uno::Any & rArg18,const uno::Any & rArg19,const uno::Any & rArg20,const uno::Any & rArg21,const uno::Any & rArg22,const uno::Any & rArg23,const uno::Any & rArg24,const uno::Any & rArg25,const uno::Any & rArg26,const uno::Any & rArg27,const uno::Any & rArg28,const uno::Any & rArg29,const uno::Any & rArg30)1235 uno::Reference< excel::XRange > SAL_CALL ScVbaApplication::Intersect(
1236 const uno::Reference< excel::XRange >& rArg1, const uno::Reference< excel::XRange >& rArg2,
1237 const uno::Any& rArg3, const uno::Any& rArg4, const uno::Any& rArg5, const uno::Any& rArg6,
1238 const uno::Any& rArg7, const uno::Any& rArg8, const uno::Any& rArg9, const uno::Any& rArg10,
1239 const uno::Any& rArg11, const uno::Any& rArg12, const uno::Any& rArg13, const uno::Any& rArg14,
1240 const uno::Any& rArg15, const uno::Any& rArg16, const uno::Any& rArg17, const uno::Any& rArg18,
1241 const uno::Any& rArg19, const uno::Any& rArg20, const uno::Any& rArg21, const uno::Any& rArg22,
1242 const uno::Any& rArg23, const uno::Any& rArg24, const uno::Any& rArg25, const uno::Any& rArg26,
1243 const uno::Any& rArg27, const uno::Any& rArg28, const uno::Any& rArg29, const uno::Any& rArg30 )
1244 {
1245 if( !rArg1.is() || !rArg2.is() )
1246 DebugHelper::basicexception( ERRCODE_BASIC_BAD_PARAMETER, {} );
1247
1248 // initialize the result list with 1st parameter, join its ranges together
1249 ListOfScRange aList;
1250 lclAddToListOfScRange( aList, uno::Any( rArg1 ) );
1251 lclJoinRanges( aList );
1252
1253 // process all other parameters, this updates the list with intersection
1254 lclIntersectRanges( aList, uno::Any( rArg2 ) );
1255 lclIntersectRanges( aList, rArg3 );
1256 lclIntersectRanges( aList, rArg4 );
1257 lclIntersectRanges( aList, rArg5 );
1258 lclIntersectRanges( aList, rArg6 );
1259 lclIntersectRanges( aList, rArg7 );
1260 lclIntersectRanges( aList, rArg8 );
1261 lclIntersectRanges( aList, rArg9 );
1262 lclIntersectRanges( aList, rArg10 );
1263 lclIntersectRanges( aList, rArg11 );
1264 lclIntersectRanges( aList, rArg12 );
1265 lclIntersectRanges( aList, rArg13 );
1266 lclIntersectRanges( aList, rArg14 );
1267 lclIntersectRanges( aList, rArg15 );
1268 lclIntersectRanges( aList, rArg16 );
1269 lclIntersectRanges( aList, rArg17 );
1270 lclIntersectRanges( aList, rArg18 );
1271 lclIntersectRanges( aList, rArg19 );
1272 lclIntersectRanges( aList, rArg20 );
1273 lclIntersectRanges( aList, rArg21 );
1274 lclIntersectRanges( aList, rArg22 );
1275 lclIntersectRanges( aList, rArg23 );
1276 lclIntersectRanges( aList, rArg24 );
1277 lclIntersectRanges( aList, rArg25 );
1278 lclIntersectRanges( aList, rArg26 );
1279 lclIntersectRanges( aList, rArg27 );
1280 lclIntersectRanges( aList, rArg28 );
1281 lclIntersectRanges( aList, rArg29 );
1282 lclIntersectRanges( aList, rArg30 );
1283
1284 // create the VBA Range object
1285 return lclCreateVbaRange( mxContext, getCurrentDocument(), aList );
1286 }
1287
Union(const uno::Reference<excel::XRange> & rArg1,const uno::Reference<excel::XRange> & rArg2,const uno::Any & rArg3,const uno::Any & rArg4,const uno::Any & rArg5,const uno::Any & rArg6,const uno::Any & rArg7,const uno::Any & rArg8,const uno::Any & rArg9,const uno::Any & rArg10,const uno::Any & rArg11,const uno::Any & rArg12,const uno::Any & rArg13,const uno::Any & rArg14,const uno::Any & rArg15,const uno::Any & rArg16,const uno::Any & rArg17,const uno::Any & rArg18,const uno::Any & rArg19,const uno::Any & rArg20,const uno::Any & rArg21,const uno::Any & rArg22,const uno::Any & rArg23,const uno::Any & rArg24,const uno::Any & rArg25,const uno::Any & rArg26,const uno::Any & rArg27,const uno::Any & rArg28,const uno::Any & rArg29,const uno::Any & rArg30)1288 uno::Reference< excel::XRange > SAL_CALL ScVbaApplication::Union(
1289 const uno::Reference< excel::XRange >& rArg1, const uno::Reference< excel::XRange >& rArg2,
1290 const uno::Any& rArg3, const uno::Any& rArg4, const uno::Any& rArg5, const uno::Any& rArg6,
1291 const uno::Any& rArg7, const uno::Any& rArg8, const uno::Any& rArg9, const uno::Any& rArg10,
1292 const uno::Any& rArg11, const uno::Any& rArg12, const uno::Any& rArg13, const uno::Any& rArg14,
1293 const uno::Any& rArg15, const uno::Any& rArg16, const uno::Any& rArg17, const uno::Any& rArg18,
1294 const uno::Any& rArg19, const uno::Any& rArg20, const uno::Any& rArg21, const uno::Any& rArg22,
1295 const uno::Any& rArg23, const uno::Any& rArg24, const uno::Any& rArg25, const uno::Any& rArg26,
1296 const uno::Any& rArg27, const uno::Any& rArg28, const uno::Any& rArg29, const uno::Any& rArg30 )
1297 {
1298 if( !rArg1.is() || !rArg2.is() )
1299 DebugHelper::basicexception( ERRCODE_BASIC_BAD_PARAMETER, {} );
1300
1301 ListOfScRange aList;
1302 lclAddToListOfScRange( aList, uno::Any( rArg1 ) );
1303 lclAddToListOfScRange( aList, uno::Any( rArg2 ) );
1304 lclAddToListOfScRange( aList, rArg3 );
1305 lclAddToListOfScRange( aList, rArg4 );
1306 lclAddToListOfScRange( aList, rArg5 );
1307 lclAddToListOfScRange( aList, rArg6 );
1308 lclAddToListOfScRange( aList, rArg7 );
1309 lclAddToListOfScRange( aList, rArg8 );
1310 lclAddToListOfScRange( aList, rArg9 );
1311 lclAddToListOfScRange( aList, rArg10 );
1312 lclAddToListOfScRange( aList, rArg11 );
1313 lclAddToListOfScRange( aList, rArg12 );
1314 lclAddToListOfScRange( aList, rArg13 );
1315 lclAddToListOfScRange( aList, rArg14 );
1316 lclAddToListOfScRange( aList, rArg15 );
1317 lclAddToListOfScRange( aList, rArg16 );
1318 lclAddToListOfScRange( aList, rArg17 );
1319 lclAddToListOfScRange( aList, rArg18 );
1320 lclAddToListOfScRange( aList, rArg19 );
1321 lclAddToListOfScRange( aList, rArg20 );
1322 lclAddToListOfScRange( aList, rArg21 );
1323 lclAddToListOfScRange( aList, rArg22 );
1324 lclAddToListOfScRange( aList, rArg23 );
1325 lclAddToListOfScRange( aList, rArg24 );
1326 lclAddToListOfScRange( aList, rArg25 );
1327 lclAddToListOfScRange( aList, rArg26 );
1328 lclAddToListOfScRange( aList, rArg27 );
1329 lclAddToListOfScRange( aList, rArg28 );
1330 lclAddToListOfScRange( aList, rArg29 );
1331 lclAddToListOfScRange( aList, rArg30 );
1332
1333 // simply join together all ranges as much as possible, strip out covered ranges etc.
1334 lclJoinRanges( aList );
1335
1336 // create the VBA Range object
1337 return lclCreateVbaRange( mxContext, getCurrentDocument(), aList );
1338 }
1339
1340 double SAL_CALL
InchesToPoints(double Inches)1341 ScVbaApplication::InchesToPoints( double Inches )
1342 {
1343 return o3tl::convert(Inches, o3tl::Length::in, o3tl::Length::pt);
1344 }
1345
1346 double SAL_CALL
CentimetersToPoints(double Centimeters)1347 ScVbaApplication::CentimetersToPoints( double Centimeters )
1348 {
1349 return o3tl::convert(Centimeters, o3tl::Length::cm, o3tl::Length::pt);
1350 }
1351
1352 void
Volatile(const uno::Any & aVolatile)1353 ScVbaApplication::Volatile( const uno::Any& aVolatile )
1354 {
1355 bool bVolatile = true;
1356 aVolatile >>= bVolatile;
1357 SbMethod* pMeth = StarBASIC::GetActiveMethod();
1358 if ( pMeth )
1359 {
1360 uno::Reference< frame::XModel > xModel( getCurrentDocument() );
1361 if ( ScDocShell* pShell = excel::getDocShell( xModel ))
1362 {
1363 ScDocument& rDoc = pShell->GetDocument();
1364 rDoc.GetMacroManager()->SetUserFuncVolatile( pMeth->GetName(), bVolatile);
1365 }
1366 }
1367
1368 // this is bound to break when loading the document
1369 }
1370
1371 sal_Bool SAL_CALL
getDisplayFormulaBar()1372 ScVbaApplication::getDisplayFormulaBar()
1373 {
1374 bool bRes = false;
1375 ScTabViewShell* pViewShell = excel::getCurrentBestViewShell( mxContext );
1376 if ( pViewShell )
1377 {
1378 SfxBoolItem sfxFormBar( FID_TOGGLEINPUTLINE);
1379 SfxAllItemSet reqList( SfxGetpApp()->GetPool() );
1380 reqList.Put( sfxFormBar );
1381
1382 pViewShell->GetState( reqList );
1383 if ( const SfxBoolItem *pItem = reqList.GetItemIfSet( FID_TOGGLEINPUTLINE, false ) )
1384 bRes = pItem->GetValue();
1385 }
1386 return bRes;
1387 }
1388
1389 void SAL_CALL
setDisplayFormulaBar(sal_Bool _displayformulabar)1390 ScVbaApplication::setDisplayFormulaBar( sal_Bool _displayformulabar )
1391 {
1392 ScTabViewShell* pViewShell = excel::getCurrentBestViewShell( mxContext );
1393 if ( pViewShell && ( _displayformulabar != getDisplayFormulaBar() ) )
1394 {
1395 SfxAllItemSet reqList( SfxGetpApp()->GetPool() );
1396 SfxRequest aReq( FID_TOGGLEINPUTLINE, SfxCallMode::SLOT, reqList );
1397 pViewShell->Execute( aReq );
1398 }
1399 }
1400
1401 uno::Any SAL_CALL
Caller(const uno::Any &)1402 ScVbaApplication::Caller( const uno::Any& /*aIndex*/ )
1403 {
1404 StarBASIC* pBasic = SfxApplication::GetBasic();
1405 SbMethod* pMeth = static_cast<SbMethod*>(pBasic->GetRtl()->Find( u"FuncCaller"_ustr, SbxClassType::Method ));
1406 uno::Any aRet;
1407 if ( pMeth )
1408 {
1409 SbxVariableRef refTemp = pMeth;
1410 // forces a broadcast
1411 SbxVariableRef pNew = new SbxMethod( *static_cast<SbxMethod*>(pMeth));
1412 aRet = sbxToUnoValue( pNew.get() );
1413 }
1414 return aRet;
1415 }
1416
1417 uno::Reference< frame::XModel >
getCurrentDocument()1418 ScVbaApplication::getCurrentDocument()
1419 {
1420 return getCurrentExcelDoc(mxContext);
1421 }
1422
1423 uno::Any SAL_CALL
MenuBars(const uno::Any & aIndex)1424 ScVbaApplication::MenuBars( const uno::Any& aIndex )
1425 {
1426 uno::Reference< XCommandBars > xCommandBars( CommandBars( uno::Any() ), uno::UNO_QUERY_THROW );
1427 uno::Reference< XCollection > xMenuBars( new ScVbaMenuBars( this, mxContext, xCommandBars ) );
1428 if ( aIndex.hasValue() )
1429 {
1430 return xMenuBars->Item( aIndex, uno::Any() );
1431 }
1432
1433 return uno::Any( xMenuBars );
1434 }
1435
1436 uno::Any SAL_CALL
Rows(const uno::Any & aIndex)1437 ScVbaApplication::Rows( const uno::Any& aIndex )
1438 {
1439 uno::Reference< excel::XWorksheet > xWorksheet = getActiveSheet();
1440 if ( xWorksheet.is() )
1441 return uno::Any( xWorksheet->Rows( aIndex ) );
1442 return uno::Any();
1443 }
1444
OnKey(const OUString & Key,const uno::Any & Procedure)1445 void SAL_CALL ScVbaApplication::OnKey( const OUString& Key, const uno::Any& Procedure )
1446 {
1447 try
1448 {
1449 // Perhaps we can catch some excel specific
1450 // related behaviour here
1451 VbaApplicationBase::OnKey( Key, Procedure );
1452 }
1453 catch( container::NoSuchElementException& )
1454 {
1455 // #TODO special handling for unhandled
1456 // bindings
1457 }
1458 }
1459
setScreenUpdating(sal_Bool bUpdate)1460 void SAL_CALL ScVbaApplication::setScreenUpdating(sal_Bool bUpdate)
1461 {
1462 VbaApplicationBase::setScreenUpdating( bUpdate );
1463
1464 uno::Reference< frame::XModel > xModel( getCurrentExcelDoc( mxContext ), uno::UNO_SET_THROW );
1465
1466 ScDocShell* pDocShell = excel::getDocShell( xModel );
1467 if (!pDocShell)
1468 return;
1469 ScDocument& rDoc = pDocShell->GetDocument();
1470
1471 if( bUpdate )
1472 {
1473 // Since setting ScreenUpdating from user code might be unpaired, avoid calling function,
1474 // that asserts correct lock/unlock order and number, when not locked.
1475 if(rDoc.IsAdjustHeightLocked())
1476 rDoc.UnlockAdjustHeight();
1477 if( !rDoc.IsAdjustHeightLocked() )
1478 pDocShell->UpdateAllRowHeights();
1479 }
1480 else
1481 {
1482 rDoc.LockAdjustHeight();
1483 }
1484 }
1485
Undo()1486 void SAL_CALL ScVbaApplication::Undo()
1487 {
1488 uno::Reference< frame::XModel > xModel( getThisExcelDoc( mxContext ), uno::UNO_SET_THROW );
1489
1490 ScTabViewShell* pViewShell = excel::getBestViewShell( xModel );
1491 if ( pViewShell )
1492 dispatchExecute( pViewShell, SID_UNDO );
1493 }
1494
1495 // XInterfaceWithIID
1496
1497 OUString SAL_CALL
getIID()1498 ScVbaApplication::getIID()
1499 {
1500 return u"{82154425-0FBF-11d4-8313-005004526AB4}"_ustr;
1501 }
1502
1503 // XConnectable
1504
1505 OUString SAL_CALL
GetIIDForClassItselfNotCoclass()1506 ScVbaApplication::GetIIDForClassItselfNotCoclass()
1507 {
1508 return u"{82154426-0FBF-11D4-8313-005004526AB4}"_ustr;
1509 }
1510
1511 TypeAndIID SAL_CALL
GetConnectionPoint()1512 ScVbaApplication::GetConnectionPoint()
1513 {
1514 TypeAndIID aResult =
1515 { cppu::UnoType<excel::XApplicationOutgoing>::get(),
1516 u"{82154427-0FBF-11D4-8313-005004526AB4}"_ustr
1517 };
1518
1519 return aResult;
1520 }
1521
1522 uno::Reference<XConnectionPoint> SAL_CALL
FindConnectionPoint()1523 ScVbaApplication::FindConnectionPoint()
1524 {
1525 uno::Reference<XConnectionPoint> xCP(new ScVbaApplicationOutgoingConnectionPoint(this));
1526 return xCP;
1527 }
1528
1529 // XSinkCaller
1530
1531 void SAL_CALL
CallSinks(const OUString & Method,uno::Sequence<uno::Any> & Arguments)1532 ScVbaApplication::CallSinks( const OUString& Method, uno::Sequence< uno::Any >& Arguments )
1533 {
1534 for (auto& i : mvSinks)
1535 {
1536 if (i.is())
1537 i->Call(Method, Arguments);
1538 }
1539 }
1540
1541 OUString
getServiceImplName()1542 ScVbaApplication::getServiceImplName()
1543 {
1544 return u"ScVbaApplication"_ustr;
1545 }
1546
1547 uno::Sequence< OUString >
getServiceNames()1548 ScVbaApplication::getServiceNames()
1549 {
1550 static uno::Sequence< OUString > aServiceNames
1551 {
1552 u"ooo.vba.excel.Application"_ustr
1553 };
1554 return aServiceNames;
1555 }
1556
1557
1558 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
Calc_ScVbaApplication_get_implementation(css::uno::XComponentContext * context,css::uno::Sequence<css::uno::Any> const &)1559 Calc_ScVbaApplication_get_implementation(
1560 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
1561 {
1562 return cppu::acquire(new ScVbaApplication(context));
1563 }
1564
1565
1566 // ScVbaApplicationOutgoingConnectionPoint
1567
ScVbaApplicationOutgoingConnectionPoint(ScVbaApplication * pApp)1568 ScVbaApplicationOutgoingConnectionPoint::ScVbaApplicationOutgoingConnectionPoint( ScVbaApplication* pApp ) :
1569 mpApp(pApp)
1570 {
1571 }
1572
1573 // XConnectionPoint
1574 sal_uInt32 SAL_CALL
Advise(const uno::Reference<XSink> & Sink)1575 ScVbaApplicationOutgoingConnectionPoint::Advise( const uno::Reference< XSink >& Sink )
1576 {
1577 return mpApp->AddSink(Sink);
1578 }
1579
1580 void SAL_CALL
Unadvise(sal_uInt32 Cookie)1581 ScVbaApplicationOutgoingConnectionPoint::Unadvise( sal_uInt32 Cookie )
1582 {
1583 mpApp->RemoveSink( Cookie );
1584 }
1585
1586 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1587