File: | home/maarten/src/libreoffice/core/include/rtl/ref.hxx |
Warning: | line 113, column 13 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 "vbaeventshelper.hxx" | |||
21 | #include "excelvbahelper.hxx" | |||
22 | ||||
23 | #include <com/sun/star/awt/XTopWindow.hpp> | |||
24 | #include <com/sun/star/awt/XTopWindowListener.hpp> | |||
25 | #include <com/sun/star/awt/XWindowListener.hpp> | |||
26 | #include <com/sun/star/frame/XBorderResizeListener.hpp> | |||
27 | #include <com/sun/star/frame/XControllerBorder.hpp> | |||
28 | #include <com/sun/star/script/ModuleType.hpp> | |||
29 | #include <com/sun/star/script/vba/VBAEventId.hpp> | |||
30 | #include <com/sun/star/sheet/XCellRangeAddressable.hpp> | |||
31 | #include <com/sun/star/sheet/XSheetCellRangeContainer.hpp> | |||
32 | #include <com/sun/star/table/XCellRange.hpp> | |||
33 | #include <com/sun/star/util/XChangesListener.hpp> | |||
34 | #include <com/sun/star/util/XChangesNotifier.hpp> | |||
35 | ||||
36 | #include <cppuhelper/implbase.hxx> | |||
37 | #include <toolkit/helper/vclunohelper.hxx> | |||
38 | #include <unotools/eventcfg.hxx> | |||
39 | #include <vcl/event.hxx> | |||
40 | #include <vcl/svapp.hxx> | |||
41 | #include <vcl/window.hxx> | |||
42 | #include <vbahelper/vbaaccesshelper.hxx> | |||
43 | ||||
44 | #include <docsh.hxx> | |||
45 | #include <document.hxx> | |||
46 | #include <cellsuno.hxx> | |||
47 | #include <convuno.hxx> | |||
48 | #include "vbaapplication.hxx" | |||
49 | ||||
50 | using namespace ::com::sun::star; | |||
51 | using namespace ::com::sun::star::script::vba::VBAEventId; | |||
52 | using namespace ::ooo::vba; | |||
53 | ||||
54 | namespace { | |||
55 | ||||
56 | /** Extracts a sheet index from the specified element of the passed sequence. | |||
57 | The element may be an integer, a Calc range or ranges object, or a VBA Range object. | |||
58 | ||||
59 | @throws lang::IllegalArgumentException | |||
60 | @throws uno::RuntimeException | |||
61 | */ | |||
62 | SCTAB lclGetTabFromArgs( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) | |||
63 | { | |||
64 | VbaEventsHelperBase::checkArgument( rArgs, nIndex ); | |||
65 | ||||
66 | // first try to extract a sheet index | |||
67 | sal_Int32 nTab = -1; | |||
68 | if( rArgs[ nIndex ] >>= nTab ) | |||
69 | { | |||
70 | if( (nTab < 0) || (nTab > MAXTAB) ) | |||
71 | throw lang::IllegalArgumentException(); | |||
72 | return static_cast< SCTAB >( nTab ); | |||
73 | } | |||
74 | ||||
75 | // try VBA Range object | |||
76 | uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex ); | |||
77 | if( xVbaRange.is() ) | |||
78 | { | |||
79 | uno::Reference< XHelperInterface > xVbaHelper( xVbaRange, uno::UNO_QUERY_THROW ); | |||
80 | // TODO: in the future, the parent may be an excel::XChart (chart sheet) -> will there be a common base interface? | |||
81 | uno::Reference< excel::XWorksheet > xVbaSheet( xVbaHelper->getParent(), uno::UNO_QUERY_THROW ); | |||
82 | // VBA sheet index is 1-based | |||
83 | return static_cast< SCTAB >( xVbaSheet->getIndex() - 1 ); | |||
84 | } | |||
85 | ||||
86 | // try single UNO range object | |||
87 | uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable = getXSomethingFromArgs< sheet::XCellRangeAddressable >( rArgs, nIndex ); | |||
88 | if( xCellRangeAddressable.is() ) | |||
89 | return xCellRangeAddressable->getRangeAddress().Sheet; | |||
90 | ||||
91 | // at last, try UNO range list | |||
92 | uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex ); | |||
93 | if( xRanges.is() ) | |||
94 | { | |||
95 | uno::Sequence< table::CellRangeAddress > aRangeAddresses = xRanges->getRangeAddresses(); | |||
96 | if( aRangeAddresses.hasElements() ) | |||
97 | return aRangeAddresses[ 0 ].Sheet; | |||
98 | } | |||
99 | ||||
100 | throw lang::IllegalArgumentException(); | |||
101 | } | |||
102 | ||||
103 | /** Returns the AWT container window of the passed controller. */ | |||
104 | uno::Reference< awt::XWindow > lclGetWindowForController( const uno::Reference< frame::XController >& rxController ) | |||
105 | { | |||
106 | if( rxController.is() ) try | |||
107 | { | |||
108 | uno::Reference< frame::XFrame > xFrame( rxController->getFrame(), uno::UNO_SET_THROW ); | |||
109 | return xFrame->getContainerWindow(); | |||
110 | } | |||
111 | catch( uno::Exception& ) | |||
112 | { | |||
113 | } | |||
114 | return nullptr; | |||
115 | } | |||
116 | ||||
117 | } // namespace | |||
118 | ||||
119 | // This class is to process Workbook window related event | |||
120 | class ScVbaEventListener : public ::cppu::WeakImplHelper< awt::XTopWindowListener, | |||
121 | awt::XWindowListener, | |||
122 | frame::XBorderResizeListener, | |||
123 | util::XChangesListener > | |||
124 | { | |||
125 | public: | |||
126 | ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell ); | |||
127 | ||||
128 | /** Starts listening to the passed document controller. */ | |||
129 | void startControllerListening( const uno::Reference< frame::XController >& rxController ); | |||
130 | /** Stops listening to the passed document controller. */ | |||
131 | void stopControllerListening( const uno::Reference< frame::XController >& rxController ); | |||
132 | ||||
133 | // XTopWindowListener | |||
134 | virtual void SAL_CALL windowOpened( const lang::EventObject& rEvent ) override; | |||
135 | virtual void SAL_CALL windowClosing( const lang::EventObject& rEvent ) override; | |||
136 | virtual void SAL_CALL windowClosed( const lang::EventObject& rEvent ) override; | |||
137 | virtual void SAL_CALL windowMinimized( const lang::EventObject& rEvent ) override; | |||
138 | virtual void SAL_CALL windowNormalized( const lang::EventObject& rEvent ) override; | |||
139 | virtual void SAL_CALL windowActivated( const lang::EventObject& rEvent ) override; | |||
140 | virtual void SAL_CALL windowDeactivated( const lang::EventObject& rEvent ) override; | |||
141 | ||||
142 | // XWindowListener | |||
143 | virtual void SAL_CALL windowResized( const awt::WindowEvent& rEvent ) override; | |||
144 | virtual void SAL_CALL windowMoved( const awt::WindowEvent& rEvent ) override; | |||
145 | virtual void SAL_CALL windowShown( const lang::EventObject& rEvent ) override; | |||
146 | virtual void SAL_CALL windowHidden( const lang::EventObject& rEvent ) override; | |||
147 | ||||
148 | // XBorderResizeListener | |||
149 | virtual void SAL_CALL borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& aNewSize ) override; | |||
150 | ||||
151 | // XChangesListener | |||
152 | virtual void SAL_CALL changesOccurred( const util::ChangesEvent& rEvent ) override; | |||
153 | ||||
154 | // XEventListener | |||
155 | virtual void SAL_CALL disposing( const lang::EventObject& rEvent ) override; | |||
156 | ||||
157 | private: | |||
158 | /** Starts listening to the document model. */ | |||
159 | void startModelListening(); | |||
160 | /** Stops listening to the document model. */ | |||
161 | void stopModelListening(); | |||
162 | ||||
163 | /** Returns the controller for the passed VCL window. */ | |||
164 | uno::Reference< frame::XController > getControllerForWindow( vcl::Window* pWindow ) const; | |||
165 | ||||
166 | /** Calls the Workbook_Window[Activate|Deactivate] event handler. */ | |||
167 | void processWindowActivateEvent( vcl::Window* pWindow, bool bActivate ); | |||
168 | /** Posts a Workbook_WindowResize user event. */ | |||
169 | void postWindowResizeEvent( vcl::Window* pWindow ); | |||
170 | /** Callback link for Application::PostUserEvent(). */ | |||
171 | DECL_LINK( processWindowResizeEvent, void*, void )static void LinkStubprocessWindowResizeEvent(void *, void*); void processWindowResizeEvent(void*); | |||
172 | ||||
173 | private: | |||
174 | typedef ::std::map< VclPtr<vcl::Window>, uno::Reference< frame::XController > > WindowControllerMap; | |||
175 | ||||
176 | ::osl::Mutex maMutex; | |||
177 | ScVbaEventsHelper& mrVbaEvents; | |||
178 | uno::Reference< frame::XModel > mxModel; | |||
179 | ScDocShell* mpDocShell; | |||
180 | WindowControllerMap maControllers; /// Maps VCL top windows to their controllers. | |||
181 | std::multiset< VclPtr<vcl::Window> > m_PostedWindows; /// Keeps processWindowResizeEvent windows from being deleted between postWindowResizeEvent and processWindowResizeEvent | |||
182 | VclPtr<vcl::Window> mpActiveWindow; /// Currently activated window, to prevent multiple (de)activation. | |||
183 | bool mbWindowResized; /// True = window resize system event processed. | |||
184 | bool mbBorderChanged; /// True = borders changed system event processed. | |||
185 | bool mbDisposed; | |||
186 | }; | |||
187 | ||||
188 | ScVbaEventListener::ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell ) : | |||
189 | mrVbaEvents( rVbaEvents ), | |||
190 | mxModel( rxModel ), | |||
191 | mpDocShell( pDocShell ), | |||
192 | mpActiveWindow( nullptr ), | |||
193 | mbWindowResized( false ), | |||
194 | mbBorderChanged( false ), | |||
195 | mbDisposed( !rxModel.is() ) | |||
196 | { | |||
197 | if( !mxModel.is() ) | |||
198 | return; | |||
199 | ||||
200 | startModelListening(); | |||
201 | try | |||
202 | { | |||
203 | uno::Reference< frame::XController > xController( mxModel->getCurrentController(), uno::UNO_SET_THROW ); | |||
204 | startControllerListening( xController ); | |||
205 | } | |||
206 | catch( uno::Exception& ) | |||
207 | { | |||
208 | } | |||
209 | } | |||
210 | ||||
211 | void ScVbaEventListener::startControllerListening( const uno::Reference< frame::XController >& rxController ) | |||
212 | { | |||
213 | ::osl::MutexGuard aGuard( maMutex ); | |||
214 | ||||
215 | uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController ); | |||
216 | if( xWindow.is() ) | |||
217 | try { xWindow->addWindowListener( this ); } catch( uno::Exception& ) {} | |||
218 | ||||
219 | uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY ); | |||
220 | if( xTopWindow.is() ) | |||
221 | try { xTopWindow->addTopWindowListener( this ); } catch( uno::Exception& ) {} | |||
222 | ||||
223 | uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY ); | |||
224 | if( xControllerBorder.is() ) | |||
225 | try { xControllerBorder->addBorderResizeListener( this ); } catch( uno::Exception& ) {} | |||
226 | ||||
227 | if( VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ) ) | |||
228 | { | |||
229 | maControllers[ pWindow ] = rxController; | |||
230 | } | |||
231 | } | |||
232 | ||||
233 | void ScVbaEventListener::stopControllerListening( const uno::Reference< frame::XController >& rxController ) | |||
234 | { | |||
235 | ::osl::MutexGuard aGuard( maMutex ); | |||
236 | ||||
237 | uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController ); | |||
238 | if( xWindow.is() ) | |||
239 | try { xWindow->removeWindowListener( this ); } catch( uno::Exception& ) {} | |||
240 | ||||
241 | uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY ); | |||
242 | if( xTopWindow.is() ) | |||
243 | try { xTopWindow->removeTopWindowListener( this ); } catch( uno::Exception& ) {} | |||
244 | ||||
245 | uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY ); | |||
246 | if( xControllerBorder.is() ) | |||
247 | try { xControllerBorder->removeBorderResizeListener( this ); } catch( uno::Exception& ) {} | |||
248 | ||||
249 | if( VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ) ) | |||
250 | { | |||
251 | maControllers.erase( pWindow ); | |||
252 | if( pWindow == mpActiveWindow ) | |||
253 | mpActiveWindow = nullptr; | |||
254 | } | |||
255 | } | |||
256 | ||||
257 | void SAL_CALL ScVbaEventListener::windowOpened( const lang::EventObject& /*rEvent*/ ) | |||
258 | { | |||
259 | } | |||
260 | ||||
261 | void SAL_CALL ScVbaEventListener::windowClosing( const lang::EventObject& /*rEvent*/ ) | |||
262 | { | |||
263 | } | |||
264 | ||||
265 | void SAL_CALL ScVbaEventListener::windowClosed( const lang::EventObject& /*rEvent*/ ) | |||
266 | { | |||
267 | } | |||
268 | ||||
269 | void SAL_CALL ScVbaEventListener::windowMinimized( const lang::EventObject& /*rEvent*/ ) | |||
270 | { | |||
271 | } | |||
272 | ||||
273 | void SAL_CALL ScVbaEventListener::windowNormalized( const lang::EventObject& /*rEvent*/ ) | |||
274 | { | |||
275 | } | |||
276 | ||||
277 | void SAL_CALL ScVbaEventListener::windowActivated( const lang::EventObject& rEvent ) | |||
278 | { | |||
279 | ::osl::MutexGuard aGuard( maMutex ); | |||
280 | ||||
281 | if( mbDisposed ) | |||
282 | return; | |||
283 | ||||
284 | uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY ); | |||
285 | VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ); | |||
286 | // do not fire activation event multiple time for the same window | |||
287 | if( pWindow && (pWindow != mpActiveWindow) ) | |||
288 | { | |||
289 | // if another window is active, fire deactivation event first | |||
290 | if( mpActiveWindow ) | |||
291 | processWindowActivateEvent( mpActiveWindow, false ); | |||
292 | // fire activation event for the new window | |||
293 | processWindowActivateEvent( pWindow, true ); | |||
294 | mpActiveWindow = pWindow; | |||
295 | } | |||
296 | } | |||
297 | ||||
298 | void SAL_CALL ScVbaEventListener::windowDeactivated( const lang::EventObject& rEvent ) | |||
299 | { | |||
300 | ::osl::MutexGuard aGuard( maMutex ); | |||
301 | ||||
302 | if( !mbDisposed ) | |||
| ||||
303 | { | |||
304 | uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY ); | |||
305 | VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ); | |||
306 | // do not fire the deactivation event, if the window is not active (prevent multiple deactivation) | |||
307 | if( pWindow && (pWindow == mpActiveWindow) ) | |||
308 | processWindowActivateEvent( pWindow, false ); | |||
309 | // forget pointer to the active window | |||
310 | mpActiveWindow = nullptr; | |||
311 | } | |||
312 | } | |||
313 | ||||
314 | void SAL_CALL ScVbaEventListener::windowResized( const awt::WindowEvent& rEvent ) | |||
315 | { | |||
316 | ::osl::MutexGuard aGuard( maMutex ); | |||
317 | ||||
318 | mbWindowResized = true; | |||
319 | if( !mbDisposed && mbBorderChanged ) | |||
320 | { | |||
321 | uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY ); | |||
322 | postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) ); | |||
323 | } | |||
324 | } | |||
325 | ||||
326 | void SAL_CALL ScVbaEventListener::windowMoved( const awt::WindowEvent& /*rEvent*/ ) | |||
327 | { | |||
328 | } | |||
329 | ||||
330 | void SAL_CALL ScVbaEventListener::windowShown( const lang::EventObject& /*rEvent*/ ) | |||
331 | { | |||
332 | } | |||
333 | ||||
334 | void SAL_CALL ScVbaEventListener::windowHidden( const lang::EventObject& /*rEvent*/ ) | |||
335 | { | |||
336 | } | |||
337 | ||||
338 | void SAL_CALL ScVbaEventListener::borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& /*aNewSize*/ ) | |||
339 | { | |||
340 | ::osl::MutexGuard aGuard( maMutex ); | |||
341 | ||||
342 | mbBorderChanged = true; | |||
343 | if( !mbDisposed && mbWindowResized ) | |||
344 | { | |||
345 | uno::Reference< frame::XController > xController( rSource, uno::UNO_QUERY ); | |||
346 | uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( xController ); | |||
347 | postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) ); | |||
348 | } | |||
349 | } | |||
350 | ||||
351 | void SAL_CALL ScVbaEventListener::changesOccurred( const util::ChangesEvent& rEvent ) | |||
352 | { | |||
353 | ::osl::MutexGuard aGuard( maMutex ); | |||
354 | ||||
355 | sal_Int32 nCount = rEvent.Changes.getLength(); | |||
356 | if( mbDisposed || !mpDocShell || (nCount == 0) ) | |||
357 | return; | |||
358 | ||||
359 | util::ElementChange aChange = rEvent.Changes[ 0 ]; | |||
360 | OUString sOperation; | |||
361 | aChange.Accessor >>= sOperation; | |||
362 | if( !sOperation.equalsIgnoreAsciiCase("cell-change") ) | |||
363 | return; | |||
364 | ||||
365 | if( nCount == 1 ) | |||
366 | { | |||
367 | uno::Reference< table::XCellRange > xRangeObj; | |||
368 | aChange.ReplacedElement >>= xRangeObj; | |||
369 | if( xRangeObj.is() ) | |||
370 | { | |||
371 | uno::Sequence< uno::Any > aArgs( 1 ); | |||
372 | aArgs[0] <<= xRangeObj; | |||
373 | mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs ); | |||
374 | } | |||
375 | return; | |||
376 | } | |||
377 | ||||
378 | ScRangeList aRangeList; | |||
379 | for( const util::ElementChange& rChange : rEvent.Changes ) | |||
380 | { | |||
381 | rChange.Accessor >>= sOperation; | |||
382 | uno::Reference< table::XCellRange > xRangeObj; | |||
383 | rChange.ReplacedElement >>= xRangeObj; | |||
384 | if( xRangeObj.is() && sOperation.equalsIgnoreAsciiCase("cell-change") ) | |||
385 | { | |||
386 | uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable( xRangeObj, uno::UNO_QUERY ); | |||
387 | if( xCellRangeAddressable.is() ) | |||
388 | { | |||
389 | ScRange aRange; | |||
390 | ScUnoConversion::FillScRange( aRange, xCellRangeAddressable->getRangeAddress() ); | |||
391 | aRangeList.push_back( aRange ); | |||
392 | } | |||
393 | } | |||
394 | } | |||
395 | ||||
396 | if (!aRangeList.empty()) | |||
397 | { | |||
398 | uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( mpDocShell, aRangeList ) ); | |||
399 | uno::Sequence< uno::Any > aArgs(1); | |||
400 | aArgs[0] <<= xRanges; | |||
401 | mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs ); | |||
402 | } | |||
403 | } | |||
404 | ||||
405 | void SAL_CALL ScVbaEventListener::disposing( const lang::EventObject& rEvent ) | |||
406 | { | |||
407 | ::osl::MutexGuard aGuard( maMutex ); | |||
408 | ||||
409 | uno::Reference< frame::XModel > xModel( rEvent.Source, uno::UNO_QUERY ); | |||
410 | if( xModel.is() ) | |||
411 | { | |||
412 | OSL_ENSURE( xModel.get() == mxModel.get(), "ScVbaEventListener::disposing - disposing from unknown model" )do { if (true && (!(xModel.get() == mxModel.get()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sc/source/ui/vba/vbaeventshelper.cxx" ":" "412" ": "), "%s", "ScVbaEventListener::disposing - disposing from unknown model" ); } } while (false); | |||
413 | stopModelListening(); | |||
414 | mbDisposed = true; | |||
415 | return; | |||
416 | } | |||
417 | ||||
418 | uno::Reference< frame::XController > xController( rEvent.Source, uno::UNO_QUERY ); | |||
419 | if( xController.is() ) | |||
420 | { | |||
421 | stopControllerListening( xController ); | |||
422 | return; | |||
423 | } | |||
424 | } | |||
425 | ||||
426 | // private -------------------------------------------------------------------- | |||
427 | ||||
428 | void ScVbaEventListener::startModelListening() | |||
429 | { | |||
430 | try | |||
431 | { | |||
432 | uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW ); | |||
433 | xChangesNotifier->addChangesListener( this ); | |||
434 | } | |||
435 | catch( uno::Exception& ) | |||
436 | { | |||
437 | } | |||
438 | } | |||
439 | ||||
440 | void ScVbaEventListener::stopModelListening() | |||
441 | { | |||
442 | try | |||
443 | { | |||
444 | uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW ); | |||
445 | xChangesNotifier->removeChangesListener( this ); | |||
446 | } | |||
447 | catch( uno::Exception& ) | |||
448 | { | |||
449 | } | |||
450 | } | |||
451 | ||||
452 | uno::Reference< frame::XController > ScVbaEventListener::getControllerForWindow( vcl::Window* pWindow ) const | |||
453 | { | |||
454 | WindowControllerMap::const_iterator aIt = maControllers.find( pWindow ); | |||
455 | return (aIt == maControllers.end()) ? uno::Reference< frame::XController >() : aIt->second; | |||
456 | } | |||
457 | ||||
458 | void ScVbaEventListener::processWindowActivateEvent( vcl::Window* pWindow, bool bActivate ) | |||
459 | { | |||
460 | uno::Reference< frame::XController > xController = getControllerForWindow( pWindow ); | |||
461 | if( xController.is() ) | |||
462 | { | |||
463 | uno::Sequence< uno::Any > aArgs( 1 ); | |||
464 | aArgs[ 0 ] <<= xController; | |||
465 | mrVbaEvents.processVbaEventNoThrow( bActivate ? WORKBOOK_WINDOWACTIVATE : WORKBOOK_WINDOWDEACTIVATE, aArgs ); | |||
466 | } | |||
467 | } | |||
468 | ||||
469 | void ScVbaEventListener::postWindowResizeEvent( vcl::Window* pWindow ) | |||
470 | { | |||
471 | // check that the passed window is still alive (it must be registered in maControllers) | |||
472 | if( pWindow && (maControllers.count( pWindow ) > 0) ) | |||
473 | { | |||
474 | mbWindowResized = mbBorderChanged = false; | |||
475 | acquire(); // ensure we don't get deleted before the timer fires | |||
476 | m_PostedWindows.insert(pWindow); | |||
477 | Application::PostUserEvent( LINK( this, ScVbaEventListener, processWindowResizeEvent )::tools::detail::makeLink( ::tools::detail::castTo<ScVbaEventListener *>(this), &ScVbaEventListener::LinkStubprocessWindowResizeEvent ), pWindow ); | |||
478 | } | |||
479 | } | |||
480 | ||||
481 | IMPL_LINK( ScVbaEventListener, processWindowResizeEvent, void*, p, void )void ScVbaEventListener::LinkStubprocessWindowResizeEvent(void * instance, void* data) { return static_cast<ScVbaEventListener *>(instance)->processWindowResizeEvent(data); } void ScVbaEventListener ::processWindowResizeEvent(void* p) | |||
482 | { | |||
483 | vcl::Window* pWindow = static_cast<vcl::Window*>(p); | |||
484 | ::osl::MutexGuard aGuard( maMutex ); | |||
485 | ||||
486 | /* Check that the passed window is still alive (it must be registered in | |||
487 | maControllers). While closing a document, postWindowResizeEvent() may | |||
488 | be called on the last window which posts a user event via | |||
489 | Application::PostUserEvent to call this event handler. VCL will trigger | |||
490 | the handler some time later. Sometimes, the window gets deleted before. | |||
491 | This is handled via the disposing() function which removes the window | |||
492 | pointer from the member maControllers. Thus, checking whether | |||
493 | maControllers contains pWindow ensures that the window is still alive. */ | |||
494 | if( !mbDisposed && pWindow && !pWindow->IsDisposed() && (maControllers.count(pWindow) > 0) ) | |||
495 | { | |||
496 | // do not fire event unless all mouse buttons have been released | |||
497 | vcl::Window::PointerState aPointerState = pWindow->GetPointerState(); | |||
498 | if( (aPointerState.mnState & (MOUSE_LEFT(sal_uInt16(0x0001)) | MOUSE_MIDDLE(sal_uInt16(0x0002)) | MOUSE_RIGHT(sal_uInt16(0x0004)))) == 0 ) | |||
499 | { | |||
500 | uno::Reference< frame::XController > xController = getControllerForWindow( pWindow ); | |||
501 | if( xController.is() ) | |||
502 | { | |||
503 | uno::Sequence< uno::Any > aArgs( 1 ); | |||
504 | aArgs[ 0 ] <<= xController; | |||
505 | // #163419# do not throw exceptions into application core | |||
506 | mrVbaEvents.processVbaEventNoThrow( WORKBOOK_WINDOWRESIZE, aArgs ); | |||
507 | } | |||
508 | } | |||
509 | } | |||
510 | { | |||
511 | // note: there may be multiple processWindowResizeEvent outstanding | |||
512 | // for pWindow, so it may have been added to m_PostedWindows multiple | |||
513 | // times - so this must delete exactly one of these elements! | |||
514 | auto const iter(m_PostedWindows.find(pWindow)); | |||
515 | assert(iter != m_PostedWindows.end())(static_cast <bool> (iter != m_PostedWindows.end()) ? void (0) : __assert_fail ("iter != m_PostedWindows.end()", "/home/maarten/src/libreoffice/core/sc/source/ui/vba/vbaeventshelper.cxx" , 515, __extension__ __PRETTY_FUNCTION__)); | |||
516 | m_PostedWindows.erase(iter); | |||
517 | } | |||
518 | release(); | |||
519 | } | |||
520 | ||||
521 | ScVbaEventsHelper::ScVbaEventsHelper( const uno::Sequence< uno::Any >& rArgs ) : | |||
522 | VbaEventsHelperBase( rArgs ), | |||
523 | mbOpened( false ) | |||
524 | { | |||
525 | mpDocShell = dynamic_cast< ScDocShell* >( mpShell ); // mpShell from base class | |||
526 | mpDoc = mpDocShell ? &mpDocShell->GetDocument() : nullptr; | |||
527 | ||||
528 | if( !mxModel.is() || !mpDocShell || !mpDoc ) | |||
529 | return; | |||
530 | ||||
531 | // global | |||
532 | auto registerAutoEvent = [this](sal_Int32 nID, const char* sName) | |||
533 | { registerEventHandler(nID, script::ModuleType::NORMAL, (OString("Auto_").concat(sName)).getStr(), -1, uno::Any(false)); }; | |||
534 | registerAutoEvent(AUTO_OPEN, "Open"); | |||
535 | registerAutoEvent(AUTO_CLOSE, "Close"); | |||
536 | ||||
537 | // Workbook | |||
538 | auto registerWorkbookEvent = [this](sal_Int32 nID, const char* sName, sal_Int32 nCancelIndex) | |||
539 | { registerEventHandler(nID, script::ModuleType::DOCUMENT, (OString("Workbook_").concat(sName)).getStr(), nCancelIndex, uno::Any(false)); }; | |||
540 | registerWorkbookEvent( WORKBOOK_ACTIVATE, "Activate", -1 ); | |||
541 | registerWorkbookEvent( WORKBOOK_DEACTIVATE, "Deactivate", -1 ); | |||
542 | registerWorkbookEvent( WORKBOOK_OPEN, "Open", -1 ); | |||
543 | registerWorkbookEvent( WORKBOOK_BEFORECLOSE, "BeforeClose", 0 ); | |||
544 | registerWorkbookEvent( WORKBOOK_BEFOREPRINT, "BeforePrint", 0 ); | |||
545 | registerWorkbookEvent( WORKBOOK_BEFORESAVE, "BeforeSave", 1 ); | |||
546 | registerWorkbookEvent( WORKBOOK_AFTERSAVE, "AfterSave", -1 ); | |||
547 | registerWorkbookEvent( WORKBOOK_NEWSHEET, "NewSheet", -1 ); | |||
548 | registerWorkbookEvent( WORKBOOK_WINDOWACTIVATE, "WindowActivate", -1 ); | |||
549 | registerWorkbookEvent( WORKBOOK_WINDOWDEACTIVATE, "WindowDeactivate", -1 ); | |||
550 | registerWorkbookEvent( WORKBOOK_WINDOWRESIZE, "WindowResize", -1 ); | |||
551 | ||||
552 | // Worksheet events. All events have a corresponding workbook event. | |||
553 | auto registerWorksheetEvent = [this](sal_Int32 nID, const char* sName, sal_Int32 nCancelIndex) | |||
554 | { | |||
555 | registerEventHandler(nID, script::ModuleType::DOCUMENT, (OString("Worksheet_").concat(sName)).getStr(), | |||
556 | nCancelIndex, uno::Any(true)); | |||
557 | registerEventHandler(USERDEFINED_START + nID, script::ModuleType::DOCUMENT, | |||
558 | (OString("Workbook_Worksheet").concat(sName)).getStr(), | |||
559 | ((nCancelIndex >= 0) ? (nCancelIndex + 1) : -1), uno::Any(false)); | |||
560 | }; | |||
561 | registerWorksheetEvent( WORKSHEET_ACTIVATE, "Activate", -1 ); | |||
562 | registerWorksheetEvent( WORKSHEET_DEACTIVATE, "Deactivate", -1 ); | |||
563 | registerWorksheetEvent( WORKSHEET_BEFOREDOUBLECLICK, "BeforeDoubleClick", 1 ); | |||
564 | registerWorksheetEvent( WORKSHEET_BEFORERIGHTCLICK, "BeforeRightClick", 1 ); | |||
565 | registerWorksheetEvent( WORKSHEET_CALCULATE, "Calculate", -1 ); | |||
566 | registerWorksheetEvent( WORKSHEET_CHANGE, "Change", -1 ); | |||
567 | registerWorksheetEvent( WORKSHEET_SELECTIONCHANGE, "SelectionChange", -1 ); | |||
568 | registerWorksheetEvent( WORKSHEET_FOLLOWHYPERLINK, "FollowHyperlink", -1 ); | |||
569 | } | |||
570 | ||||
571 | ScVbaEventsHelper::~ScVbaEventsHelper() | |||
572 | { | |||
573 | } | |||
574 | ||||
575 | void SAL_CALL ScVbaEventsHelper::notifyEvent( const css::document::EventObject& rEvent ) | |||
576 | { | |||
577 | static const uno::Sequence< uno::Any > saEmptyArgs; | |||
578 | if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::OPENDOC )) || | |||
579 | (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CREATEDOC )) ) // CREATEDOC triggered e.g. during VBA Workbooks.Add | |||
580 | { | |||
581 | processVbaEventNoThrow( WORKBOOK_OPEN, saEmptyArgs ); | |||
582 | } | |||
583 | else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::ACTIVATEDOC ) ) | |||
584 | { | |||
585 | processVbaEventNoThrow( WORKBOOK_ACTIVATE, saEmptyArgs ); | |||
586 | } | |||
587 | else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::DEACTIVATEDOC ) ) | |||
588 | { | |||
589 | processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs ); | |||
590 | } | |||
591 | else if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEDOCDONE )) || | |||
592 | (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEASDOCDONE )) || | |||
593 | (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVETODOCDONE )) ) | |||
594 | { | |||
595 | uno::Sequence< uno::Any > aArgs( 1 ); | |||
596 | aArgs[ 0 ] <<= true; | |||
597 | processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs ); | |||
598 | } | |||
599 | else if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEDOCFAILED )) || | |||
600 | (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEASDOCFAILED )) || | |||
601 | (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVETODOCFAILED )) ) | |||
602 | { | |||
603 | uno::Sequence< uno::Any > aArgs( 1 ); | |||
604 | aArgs[ 0 ] <<= false; | |||
605 | processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs ); | |||
606 | } | |||
607 | else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CLOSEDOC ) ) | |||
608 | { | |||
609 | /* Trigger the WORKBOOK_WINDOWDEACTIVATE and WORKBOOK_DEACTIVATE | |||
610 | events and stop listening to the model (done in base class). */ | |||
611 | uno::Reference< frame::XController > xController( mxModel->getCurrentController() ); | |||
612 | if( xController.is() ) | |||
613 | { | |||
614 | uno::Sequence< uno::Any > aArgs( 1 ); | |||
615 | aArgs[ 0 ] <<= xController; | |||
616 | processVbaEventNoThrow( WORKBOOK_WINDOWDEACTIVATE, aArgs ); | |||
617 | } | |||
618 | processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs ); | |||
619 | } | |||
620 | else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::VIEWCREATED ) ) | |||
621 | { | |||
622 | uno::Reference< frame::XController > xController( mxModel->getCurrentController() ); | |||
623 | if( mxListener && xController.is() ) | |||
624 | mxListener->startControllerListening( xController ); | |||
625 | } | |||
626 | VbaEventsHelperBase::notifyEvent( rEvent ); | |||
627 | } | |||
628 | ||||
629 | OUString ScVbaEventsHelper::getImplementationName() | |||
630 | { | |||
631 | return "ScVbaEventsHelper"; | |||
632 | } | |||
633 | ||||
634 | css::uno::Sequence<OUString> ScVbaEventsHelper::getSupportedServiceNames() | |||
635 | { | |||
636 | return css::uno::Sequence<OUString>{ | |||
637 | "com.sun.star.script.vba.VBASpreadsheetEventProcessor"}; | |||
638 | } | |||
639 | ||||
640 | // protected ------------------------------------------------------------------ | |||
641 | ||||
642 | bool ScVbaEventsHelper::implPrepareEvent( EventQueue& rEventQueue, | |||
643 | const EventHandlerInfo& rInfo, const uno::Sequence< uno::Any >& rArgs ) | |||
644 | { | |||
645 | // document and document shell are needed during event processing | |||
646 | if( !mpShell || !mpDoc ) | |||
647 | throw uno::RuntimeException(); | |||
648 | ||||
649 | /* For document events: check if events are enabled via the | |||
650 | Application.EnableEvents symbol (this is an Excel-only attribute). | |||
651 | Check this again for every event, as the event handler may change the | |||
652 | state of the EnableEvents symbol. Global events such as AUTO_OPEN and | |||
653 | AUTO_CLOSE are always enabled. */ | |||
654 | bool bExecuteEvent = (rInfo.mnModuleType != script::ModuleType::DOCUMENT) || ScVbaApplication::getDocumentEventsEnabled(); | |||
655 | ||||
656 | // framework and Calc fire a few events before 'OnLoad', ignore them | |||
657 | if( bExecuteEvent ) | |||
658 | bExecuteEvent = (rInfo.mnEventId == WORKBOOK_OPEN) ? !mbOpened : mbOpened; | |||
659 | ||||
660 | // special handling for some events | |||
661 | if( bExecuteEvent ) switch( rInfo.mnEventId ) | |||
662 | { | |||
663 | case WORKBOOK_OPEN: | |||
664 | { | |||
665 | // execute delayed Activate event too (see above) | |||
666 | rEventQueue.emplace_back(WORKBOOK_ACTIVATE ); | |||
667 | uno::Sequence< uno::Any > aArgs( 1 ); | |||
668 | aArgs[ 0 ] <<= mxModel->getCurrentController(); | |||
669 | rEventQueue.emplace_back( WORKBOOK_WINDOWACTIVATE, aArgs ); | |||
670 | rEventQueue.emplace_back(AUTO_OPEN ); | |||
671 | // remember initial selection | |||
672 | maOldSelection <<= mxModel->getCurrentSelection(); | |||
673 | } | |||
674 | break; | |||
675 | case WORKSHEET_SELECTIONCHANGE: | |||
676 | // if selection is not changed, then do not fire the event | |||
677 | bExecuteEvent = isSelectionChanged( rArgs, 0 ); | |||
678 | break; | |||
679 | } | |||
680 | ||||
681 | if( bExecuteEvent ) | |||
682 | { | |||
683 | // add workbook event associated to a sheet event | |||
684 | bool bSheetEvent = false; | |||
685 | if( (rInfo.maUserData >>= bSheetEvent) && bSheetEvent ) | |||
686 | rEventQueue.emplace_back( rInfo.mnEventId + USERDEFINED_START, rArgs ); | |||
687 | } | |||
688 | ||||
689 | return bExecuteEvent; | |||
690 | } | |||
691 | ||||
692 | uno::Sequence< uno::Any > ScVbaEventsHelper::implBuildArgumentList( const EventHandlerInfo& rInfo, | |||
693 | const uno::Sequence< uno::Any >& rArgs ) | |||
694 | { | |||
695 | // fill arguments for workbook events associated to sheet events according to sheet events, sheet will be added below | |||
696 | bool bSheetEventAsBookEvent = rInfo.mnEventId > USERDEFINED_START; | |||
697 | sal_Int32 nEventId = bSheetEventAsBookEvent ? (rInfo.mnEventId - USERDEFINED_START) : rInfo.mnEventId; | |||
698 | ||||
699 | uno::Sequence< uno::Any > aVbaArgs; | |||
700 | switch( nEventId ) | |||
701 | { | |||
702 | // *** Workbook *** | |||
703 | ||||
704 | // no arguments | |||
705 | case WORKBOOK_ACTIVATE: | |||
706 | case WORKBOOK_DEACTIVATE: | |||
707 | case WORKBOOK_OPEN: | |||
708 | break; | |||
709 | // 1 arg: cancel | |||
710 | case WORKBOOK_BEFORECLOSE: | |||
711 | case WORKBOOK_BEFOREPRINT: | |||
712 | aVbaArgs.realloc( 1 ); | |||
713 | // current cancel state will be inserted by caller | |||
714 | break; | |||
715 | // 2 args: saveAs, cancel | |||
716 | case WORKBOOK_BEFORESAVE: | |||
717 | aVbaArgs.realloc( 2 ); | |||
718 | checkArgumentType< bool >( rArgs, 0 ); | |||
719 | aVbaArgs[ 0 ] = rArgs[ 0 ]; | |||
720 | // current cancel state will be inserted by caller | |||
721 | break; | |||
722 | // 1 arg: success | |||
723 | case WORKBOOK_AFTERSAVE: | |||
724 | aVbaArgs.realloc( 1 ); | |||
725 | checkArgumentType< bool >( rArgs, 0 ); | |||
726 | aVbaArgs[ 0 ] = rArgs[ 0 ]; | |||
727 | break; | |||
728 | // 1 arg: window | |||
729 | case WORKBOOK_WINDOWACTIVATE: | |||
730 | case WORKBOOK_WINDOWDEACTIVATE: | |||
731 | case WORKBOOK_WINDOWRESIZE: | |||
732 | aVbaArgs.realloc( 1 ); | |||
733 | aVbaArgs[ 0 ] = createWindow( rArgs, 0 ); | |||
734 | break; | |||
735 | // 1 arg: worksheet | |||
736 | case WORKBOOK_NEWSHEET: | |||
737 | aVbaArgs.realloc( 1 ); | |||
738 | aVbaArgs[ 0 ] = createWorksheet( rArgs, 0 ); | |||
739 | break; | |||
740 | ||||
741 | // *** Worksheet *** | |||
742 | ||||
743 | // no arguments | |||
744 | case WORKSHEET_ACTIVATE: | |||
745 | case WORKSHEET_CALCULATE: | |||
746 | case WORKSHEET_DEACTIVATE: | |||
747 | break; | |||
748 | // 1 arg: range | |||
749 | case WORKSHEET_CHANGE: | |||
750 | case WORKSHEET_SELECTIONCHANGE: | |||
751 | aVbaArgs.realloc( 1 ); | |||
752 | aVbaArgs[ 0 ] = createRange( rArgs, 0 ); | |||
753 | break; | |||
754 | // 2 args: range, cancel | |||
755 | case WORKSHEET_BEFOREDOUBLECLICK: | |||
756 | case WORKSHEET_BEFORERIGHTCLICK: | |||
757 | aVbaArgs.realloc( 2 ); | |||
758 | aVbaArgs[ 0 ] = createRange( rArgs, 0 ); | |||
759 | // current cancel state will be inserted by caller | |||
760 | break; | |||
761 | // 1 arg: hyperlink | |||
762 | case WORKSHEET_FOLLOWHYPERLINK: | |||
763 | aVbaArgs.realloc( 1 ); | |||
764 | aVbaArgs[ 0 ] = createHyperlink( rArgs, 0 ); | |||
765 | break; | |||
766 | } | |||
767 | ||||
768 | /* For workbook events associated to sheet events, the workbook event gets | |||
769 | the same arguments but with a Worksheet object in front of them. */ | |||
770 | if( bSheetEventAsBookEvent ) | |||
771 | { | |||
772 | sal_Int32 nLength = aVbaArgs.getLength(); | |||
773 | uno::Sequence< uno::Any > aVbaArgs2( nLength + 1 ); | |||
774 | aVbaArgs2[ 0 ] = createWorksheet( rArgs, 0 ); | |||
775 | std::copy_n(aVbaArgs.begin(), nLength, std::next(aVbaArgs2.begin())); | |||
776 | aVbaArgs = aVbaArgs2; | |||
777 | } | |||
778 | ||||
779 | return aVbaArgs; | |||
780 | } | |||
781 | ||||
782 | void ScVbaEventsHelper::implPostProcessEvent( EventQueue& rEventQueue, | |||
783 | const EventHandlerInfo& rInfo, bool bCancel ) | |||
784 | { | |||
785 | switch( rInfo.mnEventId ) | |||
786 | { | |||
787 | case WORKBOOK_OPEN: | |||
788 | mbOpened = true; | |||
789 | // register the listeners | |||
790 | if( !mxListener.is() ) | |||
791 | mxListener = new ScVbaEventListener( *this, mxModel, mpDocShell ); | |||
792 | break; | |||
793 | case WORKBOOK_BEFORECLOSE: | |||
794 | /* Execute Auto_Close only if not cancelled by event handler, but | |||
795 | before UI asks user whether to cancel closing the document. */ | |||
796 | if( !bCancel ) | |||
797 | rEventQueue.emplace_back(AUTO_CLOSE ); | |||
798 | break; | |||
799 | } | |||
800 | } | |||
801 | ||||
802 | OUString ScVbaEventsHelper::implGetDocumentModuleName( const EventHandlerInfo& rInfo, | |||
803 | const uno::Sequence< uno::Any >& rArgs ) const | |||
804 | { | |||
805 | bool bSheetEvent = false; | |||
806 | rInfo.maUserData >>= bSheetEvent; | |||
807 | SCTAB nTab = bSheetEvent ? lclGetTabFromArgs( rArgs, 0 ) : -1; | |||
808 | if( bSheetEvent && (nTab < 0) ) | |||
809 | throw lang::IllegalArgumentException(); | |||
810 | ||||
811 | OUString aCodeName; | |||
812 | if( bSheetEvent ) | |||
813 | mpDoc->GetCodeName( nTab, aCodeName ); | |||
814 | else | |||
815 | aCodeName = mpDoc->GetCodeName(); | |||
816 | return aCodeName; | |||
817 | } | |||
818 | ||||
819 | // private -------------------------------------------------------------------- | |||
820 | ||||
821 | namespace { | |||
822 | ||||
823 | /** Compares the passed range lists representing sheet selections. Ignores | |||
824 | selections that refer to different sheets (returns false in this case). */ | |||
825 | bool lclSelectionChanged( const ScRangeList& rLeft, const ScRangeList& rRight ) | |||
826 | { | |||
827 | // one of the range lists empty? -> return false, if both lists empty | |||
828 | bool bLeftEmpty = rLeft.empty(); | |||
829 | bool bRightEmpty = rRight.empty(); | |||
830 | if( bLeftEmpty || bRightEmpty ) | |||
831 | return !(bLeftEmpty && bRightEmpty); | |||
832 | ||||
833 | // check sheet indexes of the range lists (assuming that all ranges in a list are on the same sheet) | |||
834 | if (rLeft[0].aStart.Tab() != rRight[0].aStart.Tab()) | |||
835 | return false; | |||
836 | ||||
837 | // compare all ranges | |||
838 | return rLeft != rRight; | |||
839 | } | |||
840 | ||||
841 | } // namespace | |||
842 | ||||
843 | bool ScVbaEventsHelper::isSelectionChanged( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) | |||
844 | { | |||
845 | uno::Reference< uno::XInterface > xOldSelection( maOldSelection, uno::UNO_QUERY ); | |||
846 | uno::Reference< uno::XInterface > xNewSelection = getXSomethingFromArgs< uno::XInterface >( rArgs, nIndex, false ); | |||
847 | ScCellRangesBase* pOldCellRanges = comphelper::getUnoTunnelImplementation<ScCellRangesBase>( xOldSelection ); | |||
848 | ScCellRangesBase* pNewCellRanges = comphelper::getUnoTunnelImplementation<ScCellRangesBase>( xNewSelection ); | |||
849 | bool bChanged = !pOldCellRanges || !pNewCellRanges || lclSelectionChanged( pOldCellRanges->GetRangeList(), pNewCellRanges->GetRangeList() ); | |||
850 | maOldSelection <<= xNewSelection; | |||
851 | return bChanged; | |||
852 | } | |||
853 | ||||
854 | uno::Any ScVbaEventsHelper::createWorksheet( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const | |||
855 | { | |||
856 | // extract sheet index, will throw, if parameter is invalid | |||
857 | SCTAB nTab = lclGetTabFromArgs( rArgs, nIndex ); | |||
858 | return uno::Any( excel::getUnoSheetModuleObj( mxModel, nTab ) ); | |||
859 | } | |||
860 | ||||
861 | uno::Any ScVbaEventsHelper::createRange( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const | |||
862 | { | |||
863 | // it is possible to pass an existing VBA Range object | |||
864 | uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex ); | |||
865 | if( !xVbaRange.is() ) | |||
866 | { | |||
867 | uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex ); | |||
868 | uno::Reference< table::XCellRange > xRange = getXSomethingFromArgs< table::XCellRange >( rArgs, nIndex ); | |||
869 | if ( !xRanges.is() && !xRange.is() ) | |||
870 | throw lang::IllegalArgumentException(); | |||
871 | ||||
872 | uno::Sequence< uno::Any > aArgs( 2 ); | |||
873 | if ( xRanges.is() ) | |||
874 | { | |||
875 | aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xRanges ); | |||
876 | aArgs[ 1 ] <<= xRanges; | |||
877 | } | |||
878 | else | |||
879 | { | |||
880 | aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xRange ); | |||
881 | aArgs[ 1 ] <<= xRange; | |||
882 | } | |||
883 | xVbaRange.set( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Range", aArgs ), uno::UNO_QUERY_THROW ); | |||
884 | } | |||
885 | return uno::Any( xVbaRange ); | |||
886 | } | |||
887 | ||||
888 | uno::Any ScVbaEventsHelper::createHyperlink( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const | |||
889 | { | |||
890 | uno::Reference< table::XCell > xCell = getXSomethingFromArgs< table::XCell >( rArgs, nIndex, false ); | |||
891 | uno::Sequence< uno::Any > aArgs( 2 ); | |||
892 | aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xCell ); | |||
893 | aArgs[ 1 ] <<= xCell; | |||
894 | uno::Reference< uno::XInterface > xHyperlink( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Hyperlink", aArgs ), uno::UNO_SET_THROW ); | |||
895 | return uno::Any( xHyperlink ); | |||
896 | } | |||
897 | ||||
898 | uno::Any ScVbaEventsHelper::createWindow( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const | |||
899 | { | |||
900 | uno::Sequence< uno::Any > aArgs( 3 ); | |||
901 | aArgs[ 0 ] <<= getVBADocument( mxModel ); | |||
902 | aArgs[ 1 ] <<= mxModel; | |||
903 | aArgs[ 2 ] <<= getXSomethingFromArgs< frame::XController >( rArgs, nIndex, false ); | |||
904 | uno::Reference< uno::XInterface > xWindow( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Window", aArgs ), uno::UNO_SET_THROW ); | |||
905 | return uno::Any( xWindow ); | |||
906 | } | |||
907 | ||||
908 | extern "C" SAL_DLLPUBLIC_EXPORT__attribute__ ((visibility("default"))) css::uno::XInterface * | |||
909 | ScVbaEventsHelper_get_implementation( | |||
910 | css::uno::XComponentContext * /*context*/, | |||
911 | css::uno::Sequence<css::uno::Any> const &arguments) | |||
912 | { | |||
913 | return cppu::acquire(new ScVbaEventsHelper(arguments)); | |||
914 | } | |||
915 | ||||
916 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_RTL_REF_HXX | ||||||||||||
21 | #define INCLUDED_RTL_REF_HXX | ||||||||||||
22 | |||||||||||||
23 | #include "sal/config.h" | ||||||||||||
24 | |||||||||||||
25 | #include <cassert> | ||||||||||||
26 | #include <cstddef> | ||||||||||||
27 | #include <functional> | ||||||||||||
28 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||||||||
29 | #include <type_traits> | ||||||||||||
30 | #endif | ||||||||||||
31 | |||||||||||||
32 | #include "sal/types.h" | ||||||||||||
33 | |||||||||||||
34 | namespace rtl | ||||||||||||
35 | { | ||||||||||||
36 | |||||||||||||
37 | /** Template reference class for reference type. | ||||||||||||
38 | */ | ||||||||||||
39 | template <class reference_type> | ||||||||||||
40 | class Reference | ||||||||||||
41 | { | ||||||||||||
42 | /** The <b>reference_type</b> body pointer. | ||||||||||||
43 | */ | ||||||||||||
44 | reference_type * m_pBody; | ||||||||||||
45 | |||||||||||||
46 | |||||||||||||
47 | public: | ||||||||||||
48 | /** Constructor... | ||||||||||||
49 | */ | ||||||||||||
50 | Reference() | ||||||||||||
51 | : m_pBody (NULL__null) | ||||||||||||
52 | {} | ||||||||||||
53 | |||||||||||||
54 | |||||||||||||
55 | /** Constructor... | ||||||||||||
56 | */ | ||||||||||||
57 | Reference (reference_type * pBody, __sal_NoAcquire) | ||||||||||||
58 | : m_pBody (pBody) | ||||||||||||
59 | { | ||||||||||||
60 | } | ||||||||||||
61 | |||||||||||||
62 | /** Constructor... | ||||||||||||
63 | */ | ||||||||||||
64 | Reference (reference_type * pBody) | ||||||||||||
65 | : m_pBody (pBody) | ||||||||||||
66 | { | ||||||||||||
67 | if (m_pBody) | ||||||||||||
68 | m_pBody->acquire(); | ||||||||||||
69 | } | ||||||||||||
70 | |||||||||||||
71 | /** Copy constructor... | ||||||||||||
72 | */ | ||||||||||||
73 | Reference (const Reference<reference_type> & handle) | ||||||||||||
74 | : m_pBody (handle.m_pBody) | ||||||||||||
75 | { | ||||||||||||
76 | if (m_pBody) | ||||||||||||
77 | m_pBody->acquire(); | ||||||||||||
78 | } | ||||||||||||
79 | |||||||||||||
80 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||||||||
81 | /** Move constructor... | ||||||||||||
82 | */ | ||||||||||||
83 | Reference (Reference<reference_type> && handle) noexcept | ||||||||||||
84 | : m_pBody (handle.m_pBody) | ||||||||||||
85 | { | ||||||||||||
86 | handle.m_pBody = nullptr; | ||||||||||||
87 | } | ||||||||||||
88 | #endif | ||||||||||||
89 | |||||||||||||
90 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||||||
91 | /** Up-casting conversion constructor: Copies interface reference. | ||||||||||||
92 | |||||||||||||
93 | Does not work for up-casts to ambiguous bases. | ||||||||||||
94 | |||||||||||||
95 | @param rRef another reference | ||||||||||||
96 | */ | ||||||||||||
97 | template< class derived_type > | ||||||||||||
98 | inline Reference( | ||||||||||||
99 | const Reference< derived_type > & rRef, | ||||||||||||
100 | std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 ) | ||||||||||||
101 | : m_pBody (rRef.get()) | ||||||||||||
102 | { | ||||||||||||
103 | if (m_pBody) | ||||||||||||
104 | m_pBody->acquire(); | ||||||||||||
105 | } | ||||||||||||
106 | #endif | ||||||||||||
107 | |||||||||||||
108 | /** Destructor... | ||||||||||||
109 | */ | ||||||||||||
110 | ~Reference() COVERITY_NOEXCEPT_FALSE | ||||||||||||
111 | { | ||||||||||||
112 | if (m_pBody
| ||||||||||||
113 | m_pBody->release(); | ||||||||||||
| |||||||||||||
114 | } | ||||||||||||
115 | |||||||||||||
116 | /** Set... | ||||||||||||
117 | Similar to assignment. | ||||||||||||
118 | */ | ||||||||||||
119 | Reference<reference_type> & | ||||||||||||
120 | SAL_CALL set (reference_type * pBody) | ||||||||||||
121 | { | ||||||||||||
122 | if (pBody) | ||||||||||||
123 | pBody->acquire(); | ||||||||||||
124 | reference_type * const pOld = m_pBody; | ||||||||||||
125 | m_pBody = pBody; | ||||||||||||
126 | if (pOld) | ||||||||||||
127 | pOld->release(); | ||||||||||||
128 | return *this; | ||||||||||||
129 | } | ||||||||||||
130 | |||||||||||||
131 | /** Assignment. | ||||||||||||
132 | Unbinds this instance from its body (if bound) and | ||||||||||||
133 | bind it to the body represented by the handle. | ||||||||||||
134 | */ | ||||||||||||
135 | Reference<reference_type> & | ||||||||||||
136 | SAL_CALL operator= (const Reference<reference_type> & handle) | ||||||||||||
137 | { | ||||||||||||
138 | return set( handle.m_pBody ); | ||||||||||||
139 | } | ||||||||||||
140 | |||||||||||||
141 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||||||||
142 | /** Assignment. | ||||||||||||
143 | * Unbinds this instance from its body (if bound), | ||||||||||||
144 | * bind it to the body represented by the handle, and | ||||||||||||
145 | * set the body represented by the handle to nullptr. | ||||||||||||
146 | */ | ||||||||||||
147 | Reference<reference_type> & | ||||||||||||
148 | operator= (Reference<reference_type> && handle) | ||||||||||||
149 | { | ||||||||||||
150 | // self-movement guts ourself | ||||||||||||
151 | if (m_pBody) | ||||||||||||
152 | m_pBody->release(); | ||||||||||||
153 | m_pBody = handle.m_pBody; | ||||||||||||
154 | handle.m_pBody = nullptr; | ||||||||||||
155 | return *this; | ||||||||||||
156 | } | ||||||||||||
157 | #endif | ||||||||||||
158 | |||||||||||||
159 | /** Assignment... | ||||||||||||
160 | */ | ||||||||||||
161 | Reference<reference_type> & | ||||||||||||
162 | SAL_CALL operator= (reference_type * pBody) | ||||||||||||
163 | { | ||||||||||||
164 | return set( pBody ); | ||||||||||||
165 | } | ||||||||||||
166 | |||||||||||||
167 | /** Unbind the body from this handle. | ||||||||||||
168 | Note that for a handle representing a large body, | ||||||||||||
169 | "handle.clear().set(new body());" _might_ | ||||||||||||
170 | perform a little bit better than "handle.set(new body());", | ||||||||||||
171 | since in the second case two large objects exist in memory | ||||||||||||
172 | (the old body and the new body). | ||||||||||||
173 | */ | ||||||||||||
174 | Reference<reference_type> & SAL_CALL clear() | ||||||||||||
175 | { | ||||||||||||
176 | if (m_pBody) | ||||||||||||
177 | { | ||||||||||||
178 | reference_type * const pOld = m_pBody; | ||||||||||||
179 | m_pBody = NULL__null; | ||||||||||||
180 | pOld->release(); | ||||||||||||
181 | } | ||||||||||||
182 | return *this; | ||||||||||||
183 | } | ||||||||||||
184 | |||||||||||||
185 | |||||||||||||
186 | /** Get the body. Can be used instead of operator->(). | ||||||||||||
187 | I.e. handle->someBodyOp() and handle.get()->someBodyOp() | ||||||||||||
188 | are the same. | ||||||||||||
189 | */ | ||||||||||||
190 | reference_type * SAL_CALL get() const | ||||||||||||
191 | { | ||||||||||||
192 | return m_pBody; | ||||||||||||
193 | } | ||||||||||||
194 | |||||||||||||
195 | |||||||||||||
196 | /** Probably most common used: handle->someBodyOp(). | ||||||||||||
197 | */ | ||||||||||||
198 | reference_type * SAL_CALL operator->() const | ||||||||||||
199 | { | ||||||||||||
200 | assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail ("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx" , 200, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
201 | return m_pBody; | ||||||||||||
202 | } | ||||||||||||
203 | |||||||||||||
204 | |||||||||||||
205 | /** Allows (*handle).someBodyOp(). | ||||||||||||
206 | */ | ||||||||||||
207 | reference_type & SAL_CALL operator*() const | ||||||||||||
208 | { | ||||||||||||
209 | assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail ("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx" , 209, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
210 | return *m_pBody; | ||||||||||||
211 | } | ||||||||||||
212 | |||||||||||||
213 | |||||||||||||
214 | /** Returns True if the handle does point to a valid body. | ||||||||||||
215 | */ | ||||||||||||
216 | bool SAL_CALL is() const | ||||||||||||
217 | { | ||||||||||||
218 | return (m_pBody != NULL__null); | ||||||||||||
219 | } | ||||||||||||
220 | |||||||||||||
221 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||||||
222 | /** Returns True if the handle does point to a valid body. | ||||||||||||
223 | */ | ||||||||||||
224 | explicit operator bool() const | ||||||||||||
225 | { | ||||||||||||
226 | return is(); | ||||||||||||
227 | } | ||||||||||||
228 | #endif | ||||||||||||
229 | |||||||||||||
230 | /** Returns True if this points to pBody. | ||||||||||||
231 | */ | ||||||||||||
232 | bool SAL_CALL operator== (const reference_type * pBody) const | ||||||||||||
233 | { | ||||||||||||
234 | return (m_pBody == pBody); | ||||||||||||
235 | } | ||||||||||||
236 | |||||||||||||
237 | |||||||||||||
238 | /** Returns True if handle points to the same body. | ||||||||||||
239 | */ | ||||||||||||
240 | bool | ||||||||||||
241 | SAL_CALL operator== (const Reference<reference_type> & handle) const | ||||||||||||
242 | { | ||||||||||||
243 | return (m_pBody == handle.m_pBody); | ||||||||||||
244 | } | ||||||||||||
245 | |||||||||||||
246 | |||||||||||||
247 | /** Needed to place References into STL collection. | ||||||||||||
248 | */ | ||||||||||||
249 | bool | ||||||||||||
250 | SAL_CALL operator!= (const Reference<reference_type> & handle) const | ||||||||||||
251 | { | ||||||||||||
252 | return (m_pBody != handle.m_pBody); | ||||||||||||
253 | } | ||||||||||||
254 | |||||||||||||
255 | |||||||||||||
256 | /** Needed to place References into STL collection. | ||||||||||||
257 | */ | ||||||||||||
258 | bool | ||||||||||||
259 | SAL_CALL operator< (const Reference<reference_type> & handle) const | ||||||||||||
260 | { | ||||||||||||
261 | return (m_pBody < handle.m_pBody); | ||||||||||||
262 | } | ||||||||||||
263 | |||||||||||||
264 | |||||||||||||
265 | /** Needed to place References into STL collection. | ||||||||||||
266 | */ | ||||||||||||
267 | bool | ||||||||||||
268 | SAL_CALL operator> (const Reference<reference_type> & handle) const | ||||||||||||
269 | { | ||||||||||||
270 | return (m_pBody > handle.m_pBody); | ||||||||||||
271 | } | ||||||||||||
272 | }; | ||||||||||||
273 | |||||||||||||
274 | } // namespace rtl | ||||||||||||
275 | |||||||||||||
276 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||||||
277 | namespace std | ||||||||||||
278 | { | ||||||||||||
279 | |||||||||||||
280 | /// @cond INTERNAL | ||||||||||||
281 | /** | ||||||||||||
282 | Make rtl::Reference hashable by default for use in STL containers. | ||||||||||||
283 | |||||||||||||
284 | @since LibreOffice 6.3 | ||||||||||||
285 | */ | ||||||||||||
286 | template<typename T> | ||||||||||||
287 | struct hash<::rtl::Reference<T>> | ||||||||||||
288 | { | ||||||||||||
289 | std::size_t operator()(::rtl::Reference<T> const & s) const | ||||||||||||
290 | { return std::size_t(s.get()); } | ||||||||||||
291 | }; | ||||||||||||
292 | /// @endcond | ||||||||||||
293 | |||||||||||||
294 | } | ||||||||||||
295 | |||||||||||||
296 | #endif | ||||||||||||
297 | |||||||||||||
298 | #endif /* ! INCLUDED_RTL_REF_HXX */ | ||||||||||||
299 | |||||||||||||
300 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_VCL_Reference_HXX |
20 | #define INCLUDED_VCL_Reference_HXX |
21 | |
22 | #include <vcl/dllapi.h> |
23 | #include <osl/interlck.h> |
24 | |
25 | class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase |
26 | { |
27 | mutable oslInterlockedCount mnRefCnt; |
28 | |
29 | template<typename T> friend class VclPtr; |
30 | |
31 | public: |
32 | void acquire() const |
33 | { |
34 | osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1); |
35 | } |
36 | |
37 | void release() const |
38 | { |
39 | if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0) |
40 | delete this; |
41 | } |
42 | #ifdef DBG_UTIL |
43 | #ifndef _WIN32 |
44 | sal_Int32 getRefCount() const { return mnRefCnt; } |
45 | #endif |
46 | #endif |
47 | |
48 | |
49 | private: |
50 | VclReferenceBase(const VclReferenceBase&) = delete; |
51 | VclReferenceBase& operator=(const VclReferenceBase&) = delete; |
52 | |
53 | bool mbDisposed : 1; |
54 | |
55 | protected: |
56 | VclReferenceBase(); |
57 | protected: |
58 | virtual ~VclReferenceBase(); |
59 | |
60 | protected: |
61 | virtual void dispose(); |
62 | |
63 | public: |
64 | void disposeOnce(); |
65 | bool isDisposed() const { return mbDisposed; } |
66 | |
67 | }; |
68 | #endif |