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 <sal/config.h>
21
22 #include <o3tl/any.hxx>
23 #include <o3tl/safeint.hxx>
24 #include <osl/mutex.hxx>
25 #include <osl/diagnose.h>
26 #include <comphelper/eventattachermgr.hxx>
27 #include <comphelper/sequence.hxx>
28 #include <com/sun/star/beans/theIntrospection.hpp>
29 #include <com/sun/star/io/XObjectInputStream.hpp>
30 #include <com/sun/star/io/XPersistObject.hpp>
31 #include <com/sun/star/io/XObjectOutputStream.hpp>
32 #include <com/sun/star/io/XMarkableStream.hpp>
33 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
34 #include <com/sun/star/lang/XInitialization.hpp>
35 #include <com/sun/star/reflection/theCoreReflection.hpp>
36 #include <com/sun/star/reflection/XIdlClass.hpp>
37 #include <com/sun/star/reflection/XIdlReflection.hpp>
38 #include <com/sun/star/reflection/XIdlMethod.hpp>
39 #include <com/sun/star/script/CannotConvertException.hpp>
40 #include <com/sun/star/script/Converter.hpp>
41 #include <com/sun/star/script/XEventAttacher2.hpp>
42 #include <com/sun/star/script/XEventAttacherManager.hpp>
43 #include <com/sun/star/script/XScriptListener.hpp>
44 #include <cppuhelper/weak.hxx>
45 #include <comphelper/interfacecontainer2.hxx>
46 #include <cppuhelper/exc_hlp.hxx>
47 #include <cppuhelper/implbase.hxx>
48 #include <rtl/ref.hxx>
49
50 #include <deque>
51 #include <algorithm>
52
53 using namespace com::sun::star::uno;
54 using namespace com::sun::star::io;
55 using namespace com::sun::star::lang;
56 using namespace com::sun::star::beans;
57 using namespace com::sun::star::script;
58 using namespace com::sun::star::reflection;
59 using namespace cppu;
60 using namespace osl;
61
62
63 namespace comphelper
64 {
65
66 namespace {
67
68 struct AttachedObject_Impl
69 {
70 Reference< XInterface > xTarget;
71 std::vector< Reference< XEventListener > > aAttachedListenerSeq;
72 Any aHelper;
73 };
74
75 struct AttacherIndex_Impl
76 {
77 std::deque< ScriptEventDescriptor > aEventList;
78 std::deque< AttachedObject_Impl > aObjList;
79 };
80
81
82 class ImplEventAttacherManager
83 : public WeakImplHelper< XEventAttacherManager, XPersistObject >
84 {
85 friend class AttacherAllListener_Impl;
86 std::deque< AttacherIndex_Impl > aIndex;
87 Mutex aLock;
88 // Container for the ScriptListener
89 OInterfaceContainerHelper2 aScriptListeners;
90 // Instance of EventAttacher
91 Reference< XEventAttacher2 > xAttacher;
92 Reference< XComponentContext > mxContext;
93 Reference< XIdlReflection > mxCoreReflection;
94 Reference< XTypeConverter > xConverter;
95 sal_Int16 nVersion;
96 public:
97 ImplEventAttacherManager( const Reference< XIntrospection > & rIntrospection,
98 const Reference< XComponentContext >& rContext );
99
100 // Methods of XEventAttacherManager
101 virtual void SAL_CALL registerScriptEvent(sal_Int32 Index, const ScriptEventDescriptor& ScriptEvent) override;
102 virtual void SAL_CALL registerScriptEvents(sal_Int32 Index, const Sequence< ScriptEventDescriptor >& ScriptEvents) override;
103 virtual void SAL_CALL revokeScriptEvent(sal_Int32 Index, const OUString& ListenerType, const OUString& EventMethod, const OUString& removeListenerParam) override;
104 virtual void SAL_CALL revokeScriptEvents(sal_Int32 Index) override;
105 virtual void SAL_CALL insertEntry(sal_Int32 Index) override;
106 virtual void SAL_CALL removeEntry(sal_Int32 Index) override;
107 virtual Sequence< ScriptEventDescriptor > SAL_CALL getScriptEvents(sal_Int32 Index) override;
108 virtual void SAL_CALL attach(sal_Int32 Index, const Reference< XInterface >& Object, const Any& Helper) override;
109 virtual void SAL_CALL detach(sal_Int32 nIndex, const Reference< XInterface >& xObject) override;
110 virtual void SAL_CALL addScriptListener(const Reference< XScriptListener >& aListener) override;
111 virtual void SAL_CALL removeScriptListener(const Reference< XScriptListener >& Listener) override;
112
113 // Methods of XPersistObject
114 virtual OUString SAL_CALL getServiceName() override;
115 virtual void SAL_CALL write(const Reference< XObjectOutputStream >& OutStream) override;
116 virtual void SAL_CALL read(const Reference< XObjectInputStream >& InStream) override;
117
118 private:
119 /// @throws Exception
120 Reference< XIdlReflection > getReflection();
121
122 /** checks if <arg>_nIndex</arg> is a valid index, throws an <type>IllegalArgumentException</type> if not
123 @param _nIndex
124 the index to check
125 @return
126 the iterator pointing to the position indicated by the index
127 */
128 std::deque<AttacherIndex_Impl>::iterator implCheckIndex( sal_Int32 _nIndex );
129 };
130
131
132 // Implementation of an EventAttacher-subclass 'AllListeners', which
133 // only passes individual events of the general AllListeners.
134 class AttacherAllListener_Impl : public WeakImplHelper< XAllListener >
135 {
136 rtl::Reference<ImplEventAttacherManager> mxManager;
137 OUString const aScriptType;
138 OUString const aScriptCode;
139
140 /// @throws CannotConvertException
141 void convertToEventReturn( Any & rRet, const Type & rRetType );
142 public:
143 AttacherAllListener_Impl( ImplEventAttacherManager* pManager_, const OUString &rScriptType_,
144 const OUString & rScriptCode_ );
145
146 // Methods of XAllListener
147 virtual void SAL_CALL firing(const AllEventObject& Event) override;
148 virtual Any SAL_CALL approveFiring(const AllEventObject& Event) override;
149
150 // Methods of XEventListener
151 virtual void SAL_CALL disposing(const EventObject& Source) override;
152 };
153
154 }
155
AttacherAllListener_Impl(ImplEventAttacherManager * pManager_,const OUString & rScriptType_,const OUString & rScriptCode_)156 AttacherAllListener_Impl::AttacherAllListener_Impl
157 (
158 ImplEventAttacherManager* pManager_,
159 const OUString & rScriptType_,
160 const OUString & rScriptCode_
161 )
162 : mxManager( pManager_ )
163 , aScriptType( rScriptType_ )
164 , aScriptCode( rScriptCode_ )
165 {
166 }
167
168
169 // Methods of XAllListener
firing(const AllEventObject & Event)170 void SAL_CALL AttacherAllListener_Impl::firing(const AllEventObject& Event)
171 {
172 ScriptEvent aScriptEvent;
173 aScriptEvent.Source = static_cast<OWeakObject *>(mxManager.get()); // get correct XInterface
174 aScriptEvent.ListenerType = Event.ListenerType;
175 aScriptEvent.MethodName = Event.MethodName;
176 aScriptEvent.Arguments = Event.Arguments;
177 aScriptEvent.Helper = Event.Helper;
178 aScriptEvent.ScriptType = aScriptType;
179 aScriptEvent.ScriptCode = aScriptCode;
180
181 // Iterate over all listeners and pass events.
182 OInterfaceIteratorHelper2 aIt( mxManager->aScriptListeners );
183 while( aIt.hasMoreElements() )
184 static_cast<XScriptListener *>(aIt.next())->firing( aScriptEvent );
185 }
186
187
188 // Convert to the standard event return
convertToEventReturn(Any & rRet,const Type & rRetType)189 void AttacherAllListener_Impl::convertToEventReturn( Any & rRet, const Type & rRetType )
190 {
191 // no return value? Set to the specified values
192 if( rRet.getValueType().getTypeClass() == TypeClass_VOID )
193 {
194 switch( rRetType.getTypeClass() )
195 {
196 case TypeClass_INTERFACE:
197 {
198 rRet <<= Reference< XInterface >();
199 }
200 break;
201
202 case TypeClass_BOOLEAN:
203 rRet <<= true;
204 break;
205
206 case TypeClass_STRING:
207 rRet <<= OUString();
208 break;
209
210 case TypeClass_FLOAT: rRet <<= float(0); break;
211 case TypeClass_DOUBLE: rRet <<= 0.0; break;
212 case TypeClass_BYTE: rRet <<= sal_uInt8(0); break;
213 case TypeClass_SHORT: rRet <<= sal_Int16( 0 ); break;
214 case TypeClass_LONG: rRet <<= sal_Int32( 0 ); break;
215 case TypeClass_UNSIGNED_SHORT: rRet <<= sal_uInt16( 0 ); break;
216 case TypeClass_UNSIGNED_LONG: rRet <<= sal_uInt32( 0 ); break;
217
218 default:
219 OSL_ASSERT(false);
220 break;
221 }
222 }
223 else if( !rRet.getValueType().equals( rRetType ) )
224 {
225 if( !mxManager->xConverter.is() )
226 throw CannotConvertException();
227 rRet = mxManager->xConverter->convertTo( rRet, rRetType );
228 }
229 }
230
231 // Methods of XAllListener
approveFiring(const AllEventObject & Event)232 Any SAL_CALL AttacherAllListener_Impl::approveFiring( const AllEventObject& Event )
233 {
234 ScriptEvent aScriptEvent;
235 aScriptEvent.Source = static_cast<OWeakObject *>(mxManager.get()); // get correct XInterface
236 aScriptEvent.ListenerType = Event.ListenerType;
237 aScriptEvent.MethodName = Event.MethodName;
238 aScriptEvent.Arguments = Event.Arguments;
239 aScriptEvent.Helper = Event.Helper;
240 aScriptEvent.ScriptType = aScriptType;
241 aScriptEvent.ScriptCode = aScriptCode;
242
243 Any aRet;
244 // Iterate over all listeners and pass events.
245 OInterfaceIteratorHelper2 aIt( mxManager->aScriptListeners );
246 while( aIt.hasMoreElements() )
247 {
248 aRet = static_cast<XScriptListener *>(aIt.next())->approveFiring( aScriptEvent );
249 try
250 {
251 Reference< XIdlClass > xListenerType = mxManager->getReflection()->
252 forName( Event.ListenerType.getTypeName() );
253 Reference< XIdlMethod > xMeth = xListenerType->getMethod( Event.MethodName );
254 if( xMeth.is() )
255 {
256 Reference< XIdlClass > xRetType = xMeth->getReturnType();
257 Type aRetType(xRetType->getTypeClass(), xRetType->getName());
258 convertToEventReturn( aRet, aRetType );
259 }
260
261 switch( aRet.getValueType().getTypeClass() )
262 {
263 case TypeClass_INTERFACE:
264 {
265 // Interface not null, return
266 Reference< XInterface > x;
267 aRet >>= x;
268 if( x.is() )
269 return aRet;
270 }
271 break;
272
273 case TypeClass_BOOLEAN:
274 // FALSE -> Return
275 if( !(*o3tl::forceAccess<bool>(aRet)) )
276 return aRet;
277 break;
278
279 case TypeClass_STRING:
280 // none empty string -> return
281 if( !o3tl::forceAccess<OUString>(aRet)->isEmpty() )
282 return aRet;
283 break;
284
285 // none zero number -> return
286 case TypeClass_FLOAT: if( *o3tl::forceAccess<float>(aRet) ) return aRet; break;
287 case TypeClass_DOUBLE: if( *o3tl::forceAccess<double>(aRet) ) return aRet; break;
288 case TypeClass_BYTE: if( *o3tl::forceAccess<sal_Int8>(aRet) ) return aRet; break;
289 case TypeClass_SHORT: if( *o3tl::forceAccess<sal_Int16>(aRet) ) return aRet; break;
290 case TypeClass_LONG: if( *o3tl::forceAccess<sal_Int32>(aRet) ) return aRet; break;
291 case TypeClass_UNSIGNED_SHORT: if( *o3tl::forceAccess<sal_uInt16>(aRet) ) return aRet; break;
292 case TypeClass_UNSIGNED_LONG: if( *o3tl::forceAccess<sal_uInt32>(aRet) ) return aRet; break;
293
294 default:
295 OSL_ASSERT(false);
296 break;
297 }
298 }
299 catch (const CannotConvertException&)
300 {
301 // silent ignore conversions errors from a script call
302 Reference< XIdlClass > xListenerType = mxManager->getReflection()->
303 forName( Event.ListenerType.getTypeName() );
304 Reference< XIdlMethod > xMeth = xListenerType->getMethod( Event.MethodName );
305 if( xMeth.is() )
306 {
307 Reference< XIdlClass > xRetType = xMeth->getReturnType();
308 Type aRetType(xRetType->getTypeClass(), xRetType->getName());
309 aRet.clear();
310 try
311 {
312 convertToEventReturn( aRet, aRetType );
313 }
314 catch (const CannotConvertException& e)
315 {
316 css::uno::Any anyEx = cppu::getCaughtException();
317 throw css::lang::WrappedTargetRuntimeException(
318 "wrapped CannotConvertException " + e.Message,
319 css::uno::Reference<css::uno::XInterface>(), anyEx);
320 }
321 }
322 }
323 }
324 return aRet;
325 }
326
327 // Methods of XEventListener
disposing(const EventObject &)328 void SAL_CALL AttacherAllListener_Impl::disposing(const EventObject& )
329 {
330 // It is up to the container to release the object
331 }
332
333 // Constructor method for EventAttacherManager
createEventAttacherManager(const Reference<XComponentContext> & rxContext)334 Reference< XEventAttacherManager > createEventAttacherManager( const Reference< XComponentContext > & rxContext )
335 {
336 Reference< XIntrospection > xIntrospection = theIntrospection::get( rxContext );
337 return new ImplEventAttacherManager( xIntrospection, rxContext );
338 }
339
340
ImplEventAttacherManager(const Reference<XIntrospection> & rIntrospection,const Reference<XComponentContext> & rContext)341 ImplEventAttacherManager::ImplEventAttacherManager( const Reference< XIntrospection > & rIntrospection,
342 const Reference< XComponentContext >& rContext )
343 : aScriptListeners( aLock )
344 , mxContext( rContext )
345 , nVersion(0)
346 {
347 if ( rContext.is() )
348 {
349 Reference< XInterface > xIFace( rContext->getServiceManager()->createInstanceWithContext(
350 "com.sun.star.script.EventAttacher", rContext) );
351 if ( xIFace.is() )
352 {
353 xAttacher.set( xIFace, UNO_QUERY );
354 }
355 xConverter = Converter::create(rContext);
356 }
357
358 Reference< XInitialization > xInit( xAttacher, UNO_QUERY );
359 if( xInit.is() )
360 {
361 Sequence< Any > Arguments( 1 );
362 Arguments[0] <<= rIntrospection;
363 xInit->initialize( Arguments );
364 }
365 }
366
getReflection()367 Reference< XIdlReflection > ImplEventAttacherManager::getReflection()
368 {
369 Guard< Mutex > aGuard( aLock );
370 // Do we already have a service? If not, create one.
371 if( !mxCoreReflection.is() )
372 {
373 mxCoreReflection = theCoreReflection::get(mxContext);
374 }
375 return mxCoreReflection;
376 }
377
378
implCheckIndex(sal_Int32 _nIndex)379 std::deque< AttacherIndex_Impl >::iterator ImplEventAttacherManager::implCheckIndex( sal_Int32 _nIndex )
380 {
381 if ( (_nIndex < 0) || (o3tl::make_unsigned(_nIndex) >= aIndex.size()) )
382 throw IllegalArgumentException("wrong index", static_cast<cppu::OWeakObject*>(this), 1);
383
384 std::deque<AttacherIndex_Impl>::iterator aIt = aIndex.begin() + _nIndex;
385 return aIt;
386 }
387
388 // Methods of XEventAttacherManager
registerScriptEvent(sal_Int32 nIndex,const ScriptEventDescriptor & ScriptEvent)389 void SAL_CALL ImplEventAttacherManager::registerScriptEvent
390 (
391 sal_Int32 nIndex,
392 const ScriptEventDescriptor& ScriptEvent
393 )
394 {
395 Guard< Mutex > aGuard( aLock );
396
397 // Examine the index and apply the array
398 std::deque<AttacherIndex_Impl>::iterator aIt = implCheckIndex( nIndex );
399
400 ScriptEventDescriptor aEvt = ScriptEvent;
401 sal_Int32 nLastDot = aEvt.ListenerType.lastIndexOf('.');
402 if (nLastDot != -1)
403 aEvt.ListenerType = aEvt.ListenerType.copy(nLastDot+1);
404 aIt->aEventList.push_back( aEvt );
405
406 // register new Event
407 for( auto& rObj : aIt->aObjList )
408 {
409 Reference< XAllListener > xAll =
410 new AttacherAllListener_Impl( this, ScriptEvent.ScriptType, ScriptEvent.ScriptCode );
411 try
412 {
413 rObj.aAttachedListenerSeq.push_back( xAttacher->attachSingleEventListener( rObj.xTarget, xAll,
414 rObj.aHelper, ScriptEvent.ListenerType,
415 ScriptEvent.AddListenerParam, ScriptEvent.EventMethod ) );
416 }
417 catch( Exception& )
418 {
419 }
420 }
421 }
422
423
registerScriptEvents(sal_Int32 nIndex,const Sequence<ScriptEventDescriptor> & ScriptEvents)424 void SAL_CALL ImplEventAttacherManager::registerScriptEvents
425 (
426 sal_Int32 nIndex,
427 const Sequence< ScriptEventDescriptor >& ScriptEvents
428 )
429 {
430 Guard< Mutex > aGuard( aLock );
431
432 // Examine the index and apply the array
433 std::deque< AttachedObject_Impl > aList = implCheckIndex( nIndex )->aObjList;
434 for( const auto& rObj : aList )
435 detach( nIndex, rObj.xTarget );
436
437 const ScriptEventDescriptor* pArray = ScriptEvents.getConstArray();
438 sal_Int32 nLen = ScriptEvents.getLength();
439 for( sal_Int32 i = 0 ; i < nLen ; i++ )
440 registerScriptEvent( nIndex, pArray[ i ] );
441
442 for( const auto& rObj : aList )
443 attach( nIndex, rObj.xTarget, rObj.aHelper );
444 }
445
446
revokeScriptEvent(sal_Int32 nIndex,const OUString & ListenerType,const OUString & EventMethod,const OUString & ToRemoveListenerParam)447 void SAL_CALL ImplEventAttacherManager::revokeScriptEvent
448 (
449 sal_Int32 nIndex,
450 const OUString& ListenerType,
451 const OUString& EventMethod,
452 const OUString& ToRemoveListenerParam
453 )
454 {
455 Guard< Mutex > aGuard( aLock );
456
457 std::deque<AttacherIndex_Impl>::iterator aIt = implCheckIndex( nIndex );
458
459 std::deque< AttachedObject_Impl > aList = aIt->aObjList;
460 for( const auto& rObj : aList )
461 detach( nIndex, rObj.xTarget );
462
463 OUString aLstType = ListenerType;
464 sal_Int32 nLastDot = aLstType.lastIndexOf('.');
465 if (nLastDot != -1)
466 aLstType = aLstType.copy(nLastDot+1);
467
468 auto aEvtIt = std::find_if(aIt->aEventList.begin(), aIt->aEventList.end(),
469 [&aLstType, &EventMethod, &ToRemoveListenerParam](const ScriptEventDescriptor& rEvent) {
470 return aLstType == rEvent.ListenerType
471 && EventMethod == rEvent.EventMethod
472 && ToRemoveListenerParam == rEvent.AddListenerParam;
473 });
474 if (aEvtIt != aIt->aEventList.end())
475 aIt->aEventList.erase( aEvtIt );
476
477 for( const auto& rObj : aList )
478 attach( nIndex, rObj.xTarget, rObj.aHelper );
479 }
480
481
revokeScriptEvents(sal_Int32 nIndex)482 void SAL_CALL ImplEventAttacherManager::revokeScriptEvents(sal_Int32 nIndex )
483 {
484 Guard< Mutex > aGuard( aLock );
485 std::deque<AttacherIndex_Impl>::iterator aIt = implCheckIndex( nIndex );
486
487 std::deque< AttachedObject_Impl > aList = aIt->aObjList;
488 for( const auto& rObj : aList )
489 detach( nIndex, rObj.xTarget );
490 aIt->aEventList.clear();
491 for( const auto& rObj : aList )
492 attach( nIndex, rObj.xTarget, rObj.aHelper );
493 }
494
495
insertEntry(sal_Int32 nIndex)496 void SAL_CALL ImplEventAttacherManager::insertEntry(sal_Int32 nIndex)
497 {
498 Guard< Mutex > aGuard( aLock );
499 if( nIndex < 0 )
500 throw IllegalArgumentException("negative index", static_cast<cppu::OWeakObject*>(this), 1);
501
502 if ( o3tl::make_unsigned(nIndex) >= aIndex.size() )
503 aIndex.resize(nIndex+1);
504
505 AttacherIndex_Impl aTmp;
506 aIndex.insert( aIndex.begin() + nIndex, aTmp );
507 }
508
509
removeEntry(sal_Int32 nIndex)510 void SAL_CALL ImplEventAttacherManager::removeEntry(sal_Int32 nIndex)
511 {
512 Guard< Mutex > aGuard( aLock );
513 std::deque<AttacherIndex_Impl>::iterator aIt = implCheckIndex( nIndex );
514
515 std::deque< AttachedObject_Impl > aList = aIt->aObjList;
516 for( const auto& rObj : aList )
517 detach( nIndex, rObj.xTarget );
518
519 aIndex.erase( aIt );
520 }
521
522
getScriptEvents(sal_Int32 nIndex)523 Sequence< ScriptEventDescriptor > SAL_CALL ImplEventAttacherManager::getScriptEvents(sal_Int32 nIndex)
524 {
525 Guard< Mutex > aGuard( aLock );
526 std::deque<AttacherIndex_Impl>::iterator aIt = implCheckIndex( nIndex );
527 return comphelper::containerToSequence(aIt->aEventList);
528 }
529
530
attach(sal_Int32 nIndex,const Reference<XInterface> & xObject,const Any & Helper)531 void SAL_CALL ImplEventAttacherManager::attach(sal_Int32 nIndex, const Reference< XInterface >& xObject, const Any & Helper)
532 {
533 Guard< Mutex > aGuard( aLock );
534 if( nIndex < 0 || !xObject.is() )
535 throw IllegalArgumentException("negative index, or null object", static_cast<cppu::OWeakObject*>(this), -1);
536
537 if( o3tl::make_unsigned(nIndex) >= aIndex.size() )
538 {
539 // read older files
540 if( nVersion != 1 )
541 throw IllegalArgumentException();
542 insertEntry( nIndex );
543 attach( nIndex, xObject, Helper );
544 return;
545 }
546
547 std::deque< AttacherIndex_Impl >::iterator aCurrentPosition = aIndex.begin() + nIndex;
548
549 AttachedObject_Impl aTmp;
550 aTmp.xTarget = xObject;
551 aTmp.aHelper = Helper;
552 aCurrentPosition->aObjList.push_back( aTmp );
553
554 AttachedObject_Impl & rCurObj = aCurrentPosition->aObjList.back();
555 rCurObj.aAttachedListenerSeq = std::vector< Reference< XEventListener > >( aCurrentPosition->aEventList.size() );
556
557 if (aCurrentPosition->aEventList.empty())
558 return;
559
560 Sequence<css::script::EventListener> aEvents(aCurrentPosition->aEventList.size());
561 css::script::EventListener* p = aEvents.getArray();
562 size_t i = 0;
563 for (const auto& rEvent : aCurrentPosition->aEventList)
564 {
565 css::script::EventListener aListener;
566 aListener.AllListener =
567 new AttacherAllListener_Impl(this, rEvent.ScriptType, rEvent.ScriptCode);
568 aListener.Helper = rCurObj.aHelper;
569 aListener.ListenerType = rEvent.ListenerType;
570 aListener.EventMethod = rEvent.EventMethod;
571 aListener.AddListenerParam = rEvent.AddListenerParam;
572 p[i++] = aListener;
573 }
574
575 try
576 {
577 rCurObj.aAttachedListenerSeq = comphelper::sequenceToContainer<std::vector<Reference< XEventListener >>>(
578 xAttacher->attachMultipleEventListeners(rCurObj.xTarget, aEvents));
579 }
580 catch (const Exception&)
581 {
582 // Fail gracefully.
583 }
584 }
585
586
detach(sal_Int32 nIndex,const Reference<XInterface> & xObject)587 void SAL_CALL ImplEventAttacherManager::detach(sal_Int32 nIndex, const Reference< XInterface >& xObject)
588 {
589 Guard< Mutex > aGuard( aLock );
590 //return;
591 if( nIndex < 0 || o3tl::make_unsigned(nIndex) >= aIndex.size() || !xObject.is() )
592 throw IllegalArgumentException("bad index or null object", static_cast<cppu::OWeakObject*>(this), 1);
593
594 std::deque< AttacherIndex_Impl >::iterator aCurrentPosition = aIndex.begin() + nIndex;
595 auto aObjIt = std::find_if(aCurrentPosition->aObjList.begin(), aCurrentPosition->aObjList.end(),
596 [&xObject](const AttachedObject_Impl& rObj) { return rObj.xTarget == xObject; });
597 if (aObjIt == aCurrentPosition->aObjList.end())
598 return;
599
600 sal_Int32 i = 0;
601 for( const auto& rEvt : aCurrentPosition->aEventList )
602 {
603 if( aObjIt->aAttachedListenerSeq[i].is() )
604 {
605 try
606 {
607 xAttacher->removeListener( aObjIt->xTarget, rEvt.ListenerType,
608 rEvt.AddListenerParam, aObjIt->aAttachedListenerSeq[i] );
609 }
610 catch( Exception& )
611 {
612 }
613 }
614 ++i;
615 }
616 aCurrentPosition->aObjList.erase( aObjIt );
617 }
618
addScriptListener(const Reference<XScriptListener> & aListener)619 void SAL_CALL ImplEventAttacherManager::addScriptListener(const Reference< XScriptListener >& aListener)
620 {
621 Guard< Mutex > aGuard( aLock );
622 aScriptListeners.addInterface( aListener );
623 }
624
removeScriptListener(const Reference<XScriptListener> & aListener)625 void SAL_CALL ImplEventAttacherManager::removeScriptListener(const Reference< XScriptListener >& aListener)
626 {
627 Guard< Mutex > aGuard( aLock );
628 aScriptListeners.removeInterface( aListener );
629 }
630
631
632 // Methods of XPersistObject
getServiceName()633 OUString SAL_CALL ImplEventAttacherManager::getServiceName()
634 {
635 return "com.sun.star.uno.script.EventAttacherManager";
636 }
637
write(const Reference<XObjectOutputStream> & OutStream)638 void SAL_CALL ImplEventAttacherManager::write(const Reference< XObjectOutputStream >& OutStream)
639 {
640 Guard< Mutex > aGuard( aLock );
641 // Don't run without XMarkableStream
642 Reference< XMarkableStream > xMarkStream( OutStream, UNO_QUERY );
643 if( !xMarkStream.is() )
644 return;
645
646 // Write out the version
647 OutStream->writeShort( 2 );
648
649 // Remember position for length
650 sal_Int32 nObjLenMark = xMarkStream->createMark();
651 OutStream->writeLong( 0 );
652
653 OutStream->writeLong( aIndex.size() );
654
655 // Write out sequences
656 for( const auto& rIx : aIndex )
657 {
658 OutStream->writeLong( rIx.aEventList.size() );
659 for( const auto& rDesc : rIx.aEventList )
660 {
661 OutStream->writeUTF( rDesc.ListenerType );
662 OutStream->writeUTF( rDesc.EventMethod );
663 OutStream->writeUTF( rDesc.AddListenerParam );
664 OutStream->writeUTF( rDesc.ScriptType );
665 OutStream->writeUTF( rDesc.ScriptCode );
666 }
667 }
668
669 // The length is now known
670 sal_Int32 nObjLen = xMarkStream->offsetToMark( nObjLenMark ) -4;
671 xMarkStream->jumpToMark( nObjLenMark );
672 OutStream->writeLong( nObjLen );
673 xMarkStream->jumpToFurthest();
674 xMarkStream->deleteMark( nObjLenMark );
675 }
676
read(const Reference<XObjectInputStream> & InStream)677 void SAL_CALL ImplEventAttacherManager::read(const Reference< XObjectInputStream >& InStream)
678 {
679 Guard< Mutex > aGuard( aLock );
680 // Don't run without XMarkableStream
681 Reference< XMarkableStream > xMarkStream( InStream, UNO_QUERY );
682 if( !xMarkStream.is() )
683 return;
684
685 // Read in the version
686 nVersion = InStream->readShort();
687
688 // At first there's the data according to version 1 --
689 // this part needs to be kept in later versions.
690 sal_Int32 nLen = InStream->readLong();
691
692 // Position for comparative purposes
693 sal_Int32 nObjLenMark = xMarkStream->createMark();
694
695 // Number of read sequences
696 sal_Int32 nItemCount = InStream->readLong();
697
698 for( sal_Int32 i = 0 ; i < nItemCount ; i++ )
699 {
700 insertEntry( i );
701 // Read the length of the sequence
702 sal_Int32 nSeqLen = InStream->readLong();
703
704 // Display the sequences and read the descriptions
705 Sequence< ScriptEventDescriptor > aSEDSeq( nSeqLen );
706 ScriptEventDescriptor* pArray = aSEDSeq.getArray();
707 for( sal_Int32 j = 0 ; j < nSeqLen ; j++ )
708 {
709 ScriptEventDescriptor& rDesc = pArray[ j ];
710 rDesc.ListenerType = InStream->readUTF();
711 rDesc.EventMethod = InStream->readUTF();
712 rDesc.AddListenerParam = InStream->readUTF();
713 rDesc.ScriptType = InStream->readUTF();
714 rDesc.ScriptCode = InStream->readUTF();
715 }
716 registerScriptEvents( i, aSEDSeq );
717 }
718
719 // Have we read the specified length?
720 sal_Int32 nRealLen = xMarkStream->offsetToMark( nObjLenMark );
721 if( nRealLen != nLen )
722 {
723 // Only if the StreamVersion is > 1 and the date still follows, can
724 // this be true. Otherwise, something is completely gone.
725 if( nRealLen > nLen || nVersion == 1 )
726 {
727 OSL_FAIL( "ImplEventAttacherManager::read(): Fatal Error, wrong object length" );
728 }
729 else
730 { // TODO: Examine if caching the dates would be useful
731 // But for now, it's easier to skip it.
732 sal_Int32 nSkipCount = nLen - nRealLen;
733 InStream->skipBytes( nSkipCount );
734 }
735 }
736 xMarkStream->jumpToFurthest();
737 xMarkStream->deleteMark( nObjLenMark );
738 }
739
740 } // namespace comphelper
741
742
743 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
744