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