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