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 #include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
20 #include <com/sun/star/lang/XServiceInfo.hpp>
21 #include <com/sun/star/lang/XInitialization.hpp>
22 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
23 #include <com/sun/star/beans/IntrospectionException.hpp>
24 #include <com/sun/star/beans/theIntrospection.hpp>
25 #include <com/sun/star/beans/MethodConcept.hpp>
26 #include <com/sun/star/script/CannotConvertException.hpp>
27 #include <com/sun/star/script/CannotCreateAdapterException.hpp>
28 #include <com/sun/star/script/XEventAttacher2.hpp>
29 #include <com/sun/star/script/Converter.hpp>
30 #include <com/sun/star/script/XAllListener.hpp>
31 #include <com/sun/star/script/InvocationAdapterFactory.hpp>
32 #include <com/sun/star/reflection/theCoreReflection.hpp>
33 #include <com/sun/star/reflection/XIdlReflection.hpp>
34 
35 // InvocationToAllListenerMapper
36 #include <com/sun/star/script/XInvocation.hpp>
37 #include <comphelper/processfactory.hxx>
38 #include <cppuhelper/exc_hlp.hxx>
39 #include <cppuhelper/weak.hxx>
40 #include <cppuhelper/factory.hxx>
41 #include <cppuhelper/implbase.hxx>
42 #include <cppuhelper/supportsservice.hxx>
43 
44 namespace com::sun::star::lang { class XMultiServiceFactory; }
45 
46 using namespace com::sun::star::uno;
47 using namespace com::sun::star::registry;
48 using namespace com::sun::star::lang;
49 using namespace com::sun::star::beans;
50 using namespace com::sun::star::script;
51 using namespace com::sun::star::reflection;
52 using namespace cppu;
53 using namespace osl;
54 
55 
56 #define SERVICENAME "com.sun.star.script.EventAttacher"
57 #define IMPLNAME    "com.sun.star.comp.EventAttacher"
58 
59 namespace comp_EventAttacher {
60 
61 
62 //  class InvocationToAllListenerMapper
63 //  helper class to map XInvocation to XAllListener
64 
65 class InvocationToAllListenerMapper : public WeakImplHelper< XInvocation >
66 {
67 public:
68     InvocationToAllListenerMapper( const Reference< XIdlClass >& ListenerType,
69         const Reference< XAllListener >& AllListener, const Any& Helper );
70 
71     // XInvocation
72     virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() override;
73     virtual Any SAL_CALL invoke(const OUString& FunctionName, const Sequence< Any >& Params, Sequence< sal_Int16 >& OutParamIndex, Sequence< Any >& OutParam) override;
74     virtual void SAL_CALL setValue(const OUString& PropertyName, const Any& Value) override;
75     virtual Any SAL_CALL getValue(const OUString& PropertyName) override;
76     virtual sal_Bool SAL_CALL hasMethod(const OUString& Name) override;
77     virtual sal_Bool SAL_CALL hasProperty(const OUString& Name) override;
78 
79 private:
80     Reference< XAllListener >    m_xAllListener;
81     Reference< XIdlClass >       m_xListenerType;
82     Any                          m_Helper;
83 };
84 
85 
86 // Function to replace AllListenerAdapterService::createAllListerAdapter
createAllListenerAdapter(const Reference<XInvocationAdapterFactory2> & xInvocationAdapterFactory,const Reference<XIdlClass> & xListenerType,const Reference<XAllListener> & xListener,const Any & Helper)87 static Reference< XInterface > createAllListenerAdapter
88 (
89     const Reference< XInvocationAdapterFactory2 >& xInvocationAdapterFactory,
90     const Reference< XIdlClass >& xListenerType,
91     const Reference< XAllListener >& xListener,
92     const Any& Helper
93 )
94 {
95     Reference< XInterface > xAdapter;
96     if( xInvocationAdapterFactory.is() && xListenerType.is() && xListener.is() )
97     {
98         Reference< XInvocation > xInvocationToAllListenerMapper =
99             new InvocationToAllListenerMapper(xListenerType, xListener, Helper);
100         Type aListenerType( xListenerType->getTypeClass(), xListenerType->getName());
101         Sequence<Type> arg2(1);
102         arg2[0] = aListenerType;
103         xAdapter = xInvocationAdapterFactory->createAdapter( xInvocationToAllListenerMapper, arg2 );
104     }
105     return xAdapter;
106 }
107 
108 
109 // InvocationToAllListenerMapper
InvocationToAllListenerMapper(const Reference<XIdlClass> & ListenerType,const Reference<XAllListener> & AllListener,const Any & Helper)110 InvocationToAllListenerMapper::InvocationToAllListenerMapper
111     ( const Reference< XIdlClass >& ListenerType, const Reference< XAllListener >& AllListener, const Any& Helper )
112         : m_xAllListener( AllListener )
113         , m_xListenerType( ListenerType )
114         , m_Helper( Helper )
115 {
116 }
117 
118 
getIntrospection()119 Reference< XIntrospectionAccess > SAL_CALL InvocationToAllListenerMapper::getIntrospection()
120 {
121     return Reference< XIntrospectionAccess >();
122 }
123 
124 
invoke(const OUString & FunctionName,const Sequence<Any> & Params,Sequence<sal_Int16> &,Sequence<Any> &)125 Any SAL_CALL InvocationToAllListenerMapper::invoke(const OUString& FunctionName, const Sequence< Any >& Params,
126     Sequence< sal_Int16 >& , Sequence< Any >& )
127 {
128     Any aRet;
129 
130     // Check if to firing or approveFiring has to be called
131     Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( FunctionName );
132     bool bApproveFiring = false;
133     if( !xMethod.is() )
134         return aRet;
135     Reference< XIdlClass > xReturnType = xMethod->getReturnType();
136     Sequence< Reference< XIdlClass > > aExceptionSeq = xMethod->getExceptionTypes();
137     if( ( xReturnType.is() && xReturnType->getTypeClass() != TypeClass_VOID ) ||
138         aExceptionSeq.hasElements() )
139     {
140         bApproveFiring = true;
141     }
142     else
143     {
144         Sequence< ParamInfo > aParamSeq = xMethod->getParameterInfos();
145         sal_uInt32 nParamCount = aParamSeq.getLength();
146         if( nParamCount > 1 )
147         {
148             const ParamInfo* pInfo = aParamSeq.getConstArray();
149             for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
150             {
151                 if( pInfo[ i ].aMode != ParamMode_IN )
152                 {
153                     bApproveFiring = true;
154                     break;
155                 }
156             }
157         }
158     }
159 
160     AllEventObject aAllEvent;
161     aAllEvent.Source = static_cast<OWeakObject*>(this);
162     aAllEvent.Helper = m_Helper;
163     aAllEvent.ListenerType = Type(m_xListenerType->getTypeClass(), m_xListenerType->getName());
164     aAllEvent.MethodName = FunctionName;
165     aAllEvent.Arguments = Params;
166     if( bApproveFiring )
167         aRet = m_xAllListener->approveFiring( aAllEvent );
168     else
169         m_xAllListener->firing( aAllEvent );
170     return aRet;
171 }
172 
173 
setValue(const OUString &,const Any &)174 void SAL_CALL InvocationToAllListenerMapper::setValue(const OUString& , const Any& )
175 {
176 }
177 
178 
getValue(const OUString &)179 Any SAL_CALL InvocationToAllListenerMapper::getValue(const OUString& )
180 {
181     return Any();
182 }
183 
184 
hasMethod(const OUString & Name)185 sal_Bool SAL_CALL InvocationToAllListenerMapper::hasMethod(const OUString& Name)
186 {
187     Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( Name );
188     return xMethod.is();
189 }
190 
191 
hasProperty(const OUString & Name)192 sal_Bool SAL_CALL InvocationToAllListenerMapper::hasProperty(const OUString& Name)
193 {
194     Reference< XIdlField > xField = m_xListenerType->getField( Name );
195     return xField.is();
196 }
197 
198 
199 //  class EventAttacherImpl
200 //  represents an implementation of the EventAttacher service
201 
202 class EventAttacherImpl : public WeakImplHelper < XEventAttacher2, XInitialization, XServiceInfo >
203 {
204 public:
205     explicit EventAttacherImpl( const Reference< XComponentContext >& );
206 
207     // XServiceInfo
208     virtual OUString SAL_CALL getImplementationName(  ) override;
209     virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
210     virtual Sequence< OUString > SAL_CALL getSupportedServiceNames(  ) override;
211     static Sequence< OUString > getSupportedServiceNames_Static(  );
212 
213     // XInitialization
214     virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
215 
216     // methods of XEventAttacher
217     virtual Reference< XEventListener > SAL_CALL attachListener(const Reference< XInterface >& xObject,
218             const Reference< XAllListener >& AllListener, const Any& Helper,
219             const OUString& ListenerType, const OUString& AddListenerParam) override;
220     virtual Reference< XEventListener > SAL_CALL attachSingleEventListener(const Reference< XInterface >& xObject,
221             const Reference< XAllListener >& AllListener, const Any& Helper,
222             const OUString& ListenerType, const OUString& AddListenerParam,
223             const OUString& EventMethod) override;
224     virtual void SAL_CALL removeListener(const Reference< XInterface >& xObject,
225             const OUString& ListenerType, const OUString& AddListenerParam,
226             const Reference< XEventListener >& aToRemoveListener) override;
227 
228     // XEventAttacher2
229     virtual Sequence< Reference<XEventListener> > SAL_CALL attachMultipleEventListeners(
230         const Reference<XInterface>& xObject, const Sequence<css::script::EventListener>& aListeners ) override;
231 
232     // used by FilterAllListener_Impl
233     /// @throws Exception
234     Reference< XTypeConverter > getConverter();
235 
236     friend class FilterAllListenerImpl;
237 
238 private:
239     static Reference<XEventListener> attachListenerForTarget(
240         const Reference<XIntrospectionAccess>& xAccess,
241         const Reference<XInvocationAdapterFactory2>& xInvocationAdapterFactory,
242         const Reference<XAllListener>& xAllListener,
243         const Any& aObject,
244         const Any& aHelper,
245         const OUString& aListenerType,
246         const OUString& aAddListenerParam );
247 
248     Sequence< Reference<XEventListener> > attachListeners(
249         const Reference<XInterface>& xObject,
250         const Sequence< Reference<XAllListener> >& AllListeners,
251         const Sequence<css::script::EventListener>& aListeners );
252 
253 private:
254     Mutex                               m_aMutex;
255     Reference< XComponentContext >      m_xContext;
256 
257     // Save Services
258     Reference< XIntrospection >             m_xIntrospection;
259     Reference< XIdlReflection >             m_xReflection;
260     Reference< XTypeConverter >             m_xConverter;
261     Reference< XInvocationAdapterFactory2 >  m_xInvocationAdapterFactory;
262 
263     // needed services
264     /// @throws Exception
265     Reference< XIntrospection >             getIntrospection();
266     /// @throws Exception
267     Reference< XIdlReflection >             getReflection();
268     /// @throws Exception
269     Reference< XInvocationAdapterFactory2 >  getInvocationAdapterService();
270 };
271 
272 
EventAttacherImpl(const Reference<XComponentContext> & rxContext)273 EventAttacherImpl::EventAttacherImpl( const Reference< XComponentContext >& rxContext )
274     : m_xContext( rxContext )
275 {
276 }
277 
278 /// @throws Exception
EventAttacherImpl_CreateInstance(const Reference<XMultiServiceFactory> & rSMgr)279 static Reference< XInterface > EventAttacherImpl_CreateInstance( const Reference< XMultiServiceFactory >& rSMgr )
280 {
281     XEventAttacher* pEventAttacher = new EventAttacherImpl(comphelper::getComponentContext(rSMgr));
282 
283     Reference< XInterface > xRet(pEventAttacher, UNO_QUERY);
284 
285     return xRet;
286 }
287 
288 
getImplementationName()289 OUString SAL_CALL EventAttacherImpl::getImplementationName(  )
290 {
291     return IMPLNAME;
292 }
293 
supportsService(const OUString & ServiceName)294 sal_Bool SAL_CALL EventAttacherImpl::supportsService( const OUString& ServiceName )
295 {
296     return cppu::supportsService(this, ServiceName);
297 }
298 
getSupportedServiceNames()299 Sequence<OUString> SAL_CALL EventAttacherImpl::getSupportedServiceNames(  )
300 {
301     return getSupportedServiceNames_Static();
302 }
303 
304 
getSupportedServiceNames_Static()305 Sequence<OUString> EventAttacherImpl::getSupportedServiceNames_Static(  )
306 {
307     return { SERVICENAME };
308 }
309 
initialize(const Sequence<Any> & Arguments)310 void SAL_CALL EventAttacherImpl::initialize(const Sequence< Any >& Arguments)
311 {
312     // get services from the argument list
313     const Any * pArray = Arguments.getConstArray();
314     for( sal_Int32 i = 0; i < Arguments.getLength(); i++ )
315     {
316         if( pArray[i].getValueType().getTypeClass() != TypeClass_INTERFACE )
317             throw IllegalArgumentException();
318 
319         // InvocationAdapter service ?
320         Reference< XInvocationAdapterFactory2 > xALAS;
321         pArray[i] >>= xALAS;
322         if( xALAS.is() )
323         {
324             Guard< Mutex > aGuard( m_aMutex );
325             m_xInvocationAdapterFactory = xALAS;
326         }
327         // Introspection service ?
328         Reference< XIntrospection > xI;
329         pArray[i] >>= xI;
330         if( xI.is() )
331         {
332             Guard< Mutex > aGuard( m_aMutex );
333             m_xIntrospection = xI;
334         }
335         // Reflection service ?
336         Reference< XIdlReflection > xIdlR;
337         pArray[i] >>= xIdlR;
338         if( xIdlR.is() )
339         {
340             Guard< Mutex > aGuard( m_aMutex );
341             m_xReflection = xIdlR;
342         }
343         // Converter Service ?
344         Reference< XTypeConverter > xC;
345         pArray[i] >>= xC;
346         if( xC.is() )
347         {
348             Guard< Mutex > aGuard( m_aMutex );
349             m_xConverter = xC;
350         }
351 
352         // no right interface
353         if( !xALAS.is() && !xI.is() && !xIdlR.is() && !xC.is() )
354             throw IllegalArgumentException();
355     }
356 }
357 
358 
359 //*** Private helper methods ***
getIntrospection()360 Reference< XIntrospection > EventAttacherImpl::getIntrospection()
361 {
362     Guard< Mutex > aGuard( m_aMutex );
363     if( !m_xIntrospection.is() )
364     {
365         m_xIntrospection = theIntrospection::get( m_xContext );
366     }
367     return m_xIntrospection;
368 }
369 
370 
371 //*** Private helper methods ***
getReflection()372 Reference< XIdlReflection > EventAttacherImpl::getReflection()
373 {
374     Guard< Mutex > aGuard( m_aMutex );
375     if( !m_xReflection.is() )
376     {
377         m_xReflection = theCoreReflection::get(m_xContext);
378     }
379     return m_xReflection;
380 }
381 
382 
383 //*** Private helper methods ***
getInvocationAdapterService()384 Reference< XInvocationAdapterFactory2 > EventAttacherImpl::getInvocationAdapterService()
385 {
386     Guard< Mutex > aGuard( m_aMutex );
387     if( !m_xInvocationAdapterFactory.is() )
388     {
389         m_xInvocationAdapterFactory = InvocationAdapterFactory::create(m_xContext);
390     }
391     return m_xInvocationAdapterFactory;
392 }
393 
394 
395 //*** Private helper methods ***
getConverter()396 Reference< XTypeConverter > EventAttacherImpl::getConverter()
397 {
398     Guard< Mutex > aGuard( m_aMutex );
399     if( !m_xConverter.is() )
400     {
401         m_xConverter = Converter::create(m_xContext);
402     }
403     return m_xConverter;
404 }
405 
406 
407 // Implementation of an EventAttacher-related AllListeners, which brings
408 // a few Events to a general AllListener
409 class FilterAllListenerImpl : public WeakImplHelper< XAllListener  >
410 {
411 public:
412     FilterAllListenerImpl( EventAttacherImpl * pEA_, const OUString& EventMethod_,
413                            const Reference< XAllListener >& AllListener_ );
414 
415     // XAllListener
416     virtual void SAL_CALL firing(const AllEventObject& Event) override;
417     virtual Any SAL_CALL approveFiring(const AllEventObject& Event) override;
418 
419     // XEventListener
420     virtual void SAL_CALL disposing(const EventObject& Source) override;
421 
422 private:
423     // convert
424     /// @throws CannotConvertException
425     /// @throws RuntimeException
426     void convertToEventReturn( Any & rRet, const Type& rRetType );
427 
428     EventAttacherImpl *         m_pEA;
429     OUString                    m_EventMethod;
430     Reference< XAllListener >   m_AllListener;
431 };
432 
433 
FilterAllListenerImpl(EventAttacherImpl * pEA_,const OUString & EventMethod_,const Reference<XAllListener> & AllListener_)434 FilterAllListenerImpl::FilterAllListenerImpl( EventAttacherImpl * pEA_, const OUString& EventMethod_,
435                                               const Reference< XAllListener >& AllListener_ )
436         : m_pEA( pEA_ )
437         , m_EventMethod( EventMethod_ )
438         , m_AllListener( AllListener_ )
439 {
440 }
441 
442 
firing(const AllEventObject & Event)443 void SAL_CALL FilterAllListenerImpl::firing(const AllEventObject& Event)
444 {
445     if( Event.MethodName == m_EventMethod && m_AllListener.is() )
446         m_AllListener->firing( Event );
447 }
448 
449 // Convert to the standard event return
convertToEventReturn(Any & rRet,const Type & rRetType)450 void FilterAllListenerImpl::convertToEventReturn( Any & rRet, const Type & rRetType )
451 {
452     // no return value? Set to the specified values
453     if( rRet.getValueType().getTypeClass() == TypeClass_VOID )
454     {
455         switch( rRetType.getTypeClass()  )
456         {
457             case TypeClass_INTERFACE:
458                 {
459                 rRet <<= Reference< XInterface >();
460                 }
461                 break;
462 
463             case TypeClass_BOOLEAN:
464                 rRet <<= true;
465                 break;
466 
467             case TypeClass_STRING:
468                 rRet <<= OUString();
469                 break;
470 
471             case TypeClass_FLOAT:           rRet <<= float(0);  break;
472             case TypeClass_DOUBLE:          rRet <<= 0.0;   break;
473             case TypeClass_BYTE:            rRet <<= sal_uInt8( 0 );    break;
474             case TypeClass_SHORT:           rRet <<= sal_Int16( 0 );    break;
475             case TypeClass_LONG:            rRet <<= sal_Int32( 0 );    break;
476             case TypeClass_UNSIGNED_SHORT:  rRet <<= sal_uInt16( 0 );   break;
477             case TypeClass_UNSIGNED_LONG:   rRet <<= sal_uInt32( 0 );   break;
478                      default:
479             break;
480         }
481     }
482     else if( !rRet.getValueType().equals( rRetType ) )
483     {
484         Reference< XTypeConverter > xConverter = m_pEA->getConverter();
485         if( !xConverter.is() )
486             throw CannotConvertException(); // TODO TypeConversionException
487         rRet = xConverter->convertTo( rRet, rRetType );
488     }
489 }
490 
491 
approveFiring(const AllEventObject & Event)492 Any SAL_CALL FilterAllListenerImpl::approveFiring( const AllEventObject& Event )
493 {
494     Any aRet;
495 
496     if( Event.MethodName == m_EventMethod && m_AllListener.is() )
497         aRet = m_AllListener->approveFiring( Event );
498     else
499     {
500         // Convert to the standard event return
501         try
502         {
503             Reference< XIdlClass > xListenerType = m_pEA->getReflection()->
504                         forName( Event.ListenerType.getTypeName() );
505             Reference< XIdlMethod > xMeth = xListenerType->getMethod( Event.MethodName );
506             if( xMeth.is() )
507             {
508                 Reference< XIdlClass > xRetType = xMeth->getReturnType();
509                 Type aRetType( xRetType->getTypeClass(), xRetType->getName() );
510                 convertToEventReturn( aRet, aRetType );
511             }
512         }
513         catch( const CannotConvertException& )
514         {
515             css::uno::Any anyEx = cppu::getCaughtException();
516             throw InvocationTargetException( OUString(), Reference< XInterface >(), anyEx );
517         }
518     }
519     return aRet;
520 }
521 
522 
disposing(const EventObject &)523 void FilterAllListenerImpl::disposing(const EventObject& )
524 {
525     // TODO: ???
526 }
527 
528 
attachListener(const Reference<XInterface> & xObject,const Reference<XAllListener> & AllListener,const Any & Helper,const OUString & ListenerType,const OUString & AddListenerParam)529 Reference< XEventListener > EventAttacherImpl::attachListener
530 (
531     const Reference< XInterface >& xObject,
532     const Reference< XAllListener >& AllListener,
533     const Any& Helper,
534     const OUString& ListenerType,
535     const OUString& AddListenerParam
536 )
537 {
538     if( !xObject.is() || !AllListener.is() )
539         throw IllegalArgumentException();
540 
541     Reference< XInvocationAdapterFactory2 > xInvocationAdapterFactory = getInvocationAdapterService();
542     if( !xInvocationAdapterFactory.is() )
543         throw ServiceNotRegisteredException();
544 
545     Reference< XIdlReflection > xReflection = getReflection();
546     if( !xReflection.is() )
547         throw ServiceNotRegisteredException();
548 
549     // Sign in, Call the fitting addListener method
550     // First Introspection, as the Methods can be analyzed in the same way
551     // For better performance it is implemented here again or make the Impl-Method
552     // of the Introspection configurable for this purpose.
553     Reference< XIntrospection > xIntrospection = getIntrospection();
554     if( !xIntrospection.is() )
555         return Reference<XEventListener>();
556 
557     // Inspect Introspection
558     Any aObjAny( &xObject, cppu::UnoType<XInterface>::get());
559 
560     Reference< XIntrospectionAccess > xAccess = xIntrospection->inspect( aObjAny );
561     if( !xAccess.is() )
562         return Reference<XEventListener>();
563 
564     return attachListenerForTarget(
565         xAccess, xInvocationAdapterFactory, AllListener, aObjAny, Helper,
566         ListenerType, AddListenerParam);
567 }
568 
attachListenerForTarget(const Reference<XIntrospectionAccess> & xAccess,const Reference<XInvocationAdapterFactory2> & xInvocationAdapterFactory,const Reference<XAllListener> & xAllListener,const Any & aObject,const Any & aHelper,const OUString & aListenerType,const OUString & aAddListenerParam)569 Reference<XEventListener> EventAttacherImpl::attachListenerForTarget(
570     const Reference<XIntrospectionAccess>& xAccess,
571     const Reference<XInvocationAdapterFactory2>& xInvocationAdapterFactory,
572     const Reference<XAllListener>& xAllListener,
573     const Any& aObject,
574     const Any& aHelper,
575     const OUString& aListenerType,
576     const OUString& aAddListenerParam)
577 {
578     Reference< XEventListener > xRet;
579 
580     // Construct the name of the addListener-Method.
581     sal_Int32 nIndex = aListenerType.lastIndexOf('.');
582     // set index to the interface name without package name
583     if( nIndex == -1 )
584         // not found
585         nIndex = 0;
586     else
587         nIndex++;
588 
589     OUString aListenerName = (!aListenerType.isEmpty() && aListenerType[nIndex] == 'X') ? aListenerType.copy(nIndex+1) : aListenerType;
590     OUString aAddListenerName = "add" + aListenerName;
591 
592     // Send Methods to the correct addListener-Method
593     Sequence< Reference< XIdlMethod > > aMethodSeq = xAccess->getMethods( MethodConcept::LISTENER );
594     const Reference< XIdlMethod >* pMethods = aMethodSeq.getConstArray();
595     for (sal_Int32 i = 0, n = aMethodSeq.getLength(); i < n ; ++i)
596     {
597         const Reference< XIdlMethod >& rxMethod = pMethods[i];
598 
599         // Is it the correct method?
600         OUString aMethName = rxMethod->getName();
601 
602         if (aAddListenerName != aMethName)
603             continue;
604 
605         Sequence< Reference< XIdlClass > > params = rxMethod->getParameterTypes();
606         sal_uInt32 nParamCount = params.getLength();
607 
608         Reference< XIdlClass > xListenerType;
609         if( nParamCount == 1 )
610             xListenerType = params.getConstArray()[0];
611         else if( nParamCount == 2 )
612             xListenerType = params.getConstArray()[1];
613 
614         // Request Adapter for the actual Listener type
615         Reference< XInterface > xAdapter = createAllListenerAdapter(
616             xInvocationAdapterFactory, xListenerType, xAllListener, aHelper );
617 
618         if( !xAdapter.is() )
619             throw CannotCreateAdapterException();
620         xRet.set( xAdapter, UNO_QUERY );
621 
622         // Just the Listener as parameter?
623         if( nParamCount == 1 )
624         {
625             Sequence< Any > args( 1 );
626             args.getArray()[0] <<= xAdapter;
627             try
628             {
629                 rxMethod->invoke( aObject, args );
630             }
631             catch( const InvocationTargetException& )
632             {
633                 throw IntrospectionException();
634             }
635         }
636         // Else, pass the other parameter now
637         else if( nParamCount == 2 )
638         {
639             Sequence< Any > args( 2 );
640             Any* pAnys = args.getArray();
641 
642             // Check the type of the 1st parameter
643             Reference< XIdlClass > xParamClass = params.getConstArray()[0];
644             if( xParamClass->getTypeClass() == TypeClass_STRING )
645             {
646                 pAnys[0] <<= aAddListenerParam;
647             }
648 
649             // 2nd Parameter == Listener? TODO: Test!
650             pAnys[1] <<= xAdapter;
651 
652             // TODO: Convert String -> ?
653             // else
654             try
655             {
656                 rxMethod->invoke( aObject, args );
657             }
658             catch( const InvocationTargetException& )
659             {
660                 throw IntrospectionException();
661             }
662         }
663         break;
664         // else...
665         // Anything else is not supported
666     }
667 
668     return xRet;
669 }
670 
attachListeners(const Reference<XInterface> & xObject,const Sequence<Reference<XAllListener>> & AllListeners,const Sequence<css::script::EventListener> & aListeners)671 Sequence< Reference<XEventListener> > EventAttacherImpl::attachListeners(
672     const Reference<XInterface>& xObject,
673     const Sequence< Reference<XAllListener> >& AllListeners,
674     const Sequence<css::script::EventListener>& aListeners )
675 {
676     sal_Int32 nCount = aListeners.getLength();
677     if (nCount != AllListeners.getLength())
678         // This is a prerequisite!
679         throw RuntimeException();
680 
681     if (!xObject.is())
682         throw IllegalArgumentException();
683 
684     Reference< XInvocationAdapterFactory2 > xInvocationAdapterFactory = getInvocationAdapterService();
685     if( !xInvocationAdapterFactory.is() )
686         throw ServiceNotRegisteredException();
687 
688     Reference< XIdlReflection > xReflection = getReflection();
689     if( !xReflection.is() )
690         throw ServiceNotRegisteredException();
691 
692     // Sign in, Call the fitting addListener method
693     // First Introspection, as the Methods can be analyzed in the same way
694     // For better performance it is implemented here again or make the Impl-Method
695     // of the Introspection configurable for this purpose.
696     Reference< XIntrospection > xIntrospection = getIntrospection();
697     if( !xIntrospection.is() )
698         return Sequence< Reference<XEventListener> >();
699 
700     // Inspect Introspection
701     Any aObjAny( &xObject, cppu::UnoType<XInterface>::get() );
702 
703     Reference<XIntrospectionAccess> xAccess = xIntrospection->inspect(aObjAny);
704     if (!xAccess.is())
705         return Sequence< Reference<XEventListener> >();
706 
707     Sequence< Reference<XEventListener> > aRet(nCount);
708     Reference<XEventListener>* pArray = aRet.getArray();
709 
710     for (sal_Int32 i = 0; i < nCount; ++i)
711     {
712         pArray[i] = attachListenerForTarget(
713             xAccess, xInvocationAdapterFactory, AllListeners[ i ],
714             aObjAny, aListeners[i].Helper, aListeners[i].ListenerType, aListeners[i].AddListenerParam);
715     }
716 
717     return aRet;
718 }
719 
720 // XEventAttacher
attachSingleEventListener(const Reference<XInterface> & xObject,const Reference<XAllListener> & AllListener,const Any & Helper,const OUString & ListenerType,const OUString & AddListenerParam,const OUString & EventMethod)721 Reference< XEventListener > EventAttacherImpl::attachSingleEventListener
722 (
723     const Reference< XInterface >& xObject,
724     const Reference< XAllListener >& AllListener,
725     const Any& Helper,
726     const OUString& ListenerType,
727     const OUString& AddListenerParam,
728     const OUString& EventMethod
729 )
730 {
731     // Subscribe FilterListener
732     Reference<XAllListener> aFilterListener
733         = new FilterAllListenerImpl(this, EventMethod, AllListener);
734     return attachListener( xObject, aFilterListener, Helper, ListenerType, AddListenerParam);
735 }
736 
737 // XEventAttacher
removeListener(const Reference<XInterface> & xObject,const OUString & ListenerType,const OUString & AddListenerParam,const Reference<XEventListener> & aToRemoveListener)738 void EventAttacherImpl::removeListener
739 (
740     const Reference< XInterface >& xObject,
741     const OUString& ListenerType,
742     const OUString& AddListenerParam,
743     const Reference< XEventListener >& aToRemoveListener
744 )
745 {
746     if( !xObject.is() || !aToRemoveListener.is() )
747         throw IllegalArgumentException();
748 
749     Reference< XIdlReflection > xReflection = getReflection();
750     if( !xReflection.is() )
751         throw IntrospectionException();
752 
753     // Sign off, Call the fitting removeListener method
754     // First Introspection, as the Methods can be analyzed in the same way
755     // For better performance it is implemented here again or make the Impl-Method
756     // of the Introspection configurable for this purpose.
757     Reference< XIntrospection > xIntrospection = getIntrospection();
758     if( !xIntrospection.is() )
759         throw IntrospectionException();
760 
761     //Inspect Introspection
762     Any aObjAny( &xObject, cppu::UnoType<XInterface>::get());
763     Reference< XIntrospectionAccess > xAccess = xIntrospection->inspect( aObjAny );
764     if( !xAccess.is() )
765         throw IntrospectionException();
766 
767     // Create name of the removeListener-Method
768     OUString aRemoveListenerName;
769     OUString aListenerName( ListenerType );
770     sal_Int32 nIndex = aListenerName.lastIndexOf( '.' );
771     // set index to the interface name without package name
772     if( nIndex == -1 )
773         // not found
774         nIndex = 0;
775     else
776         nIndex++;
777     if( aListenerName[nIndex] == 'X' )
778         // erase X from the interface name
779         aListenerName = aListenerName.copy( nIndex +1 );
780     aRemoveListenerName = "remove" + aListenerName;
781 
782     // Search methods for the correct removeListener method
783     Sequence< Reference< XIdlMethod > > aMethodSeq = xAccess->getMethods( MethodConcept::LISTENER );
784     sal_uInt32 i, nLen = aMethodSeq.getLength();
785     const Reference< XIdlMethod >* pMethods = aMethodSeq.getConstArray();
786     for( i = 0 ; i < nLen ; i++ )
787     {
788         // Call Method
789         const Reference< XIdlMethod >& rxMethod = pMethods[i];
790 
791         // Is it the right method?
792         if( aRemoveListenerName == rxMethod->getName() )
793         {
794             Sequence< Reference< XIdlClass > > params = rxMethod->getParameterTypes();
795             sal_uInt32 nParamCount = params.getLength();
796 
797             // Just the Listener as parameter?
798             if( nParamCount == 1 )
799             {
800                 Sequence< Any > args( 1 );
801                 args.getArray()[0] <<= aToRemoveListener;
802                 try
803                 {
804                     rxMethod->invoke( aObjAny, args );
805                 }
806                 catch( const InvocationTargetException& )
807                 {
808                     throw IntrospectionException();
809                 }
810             }
811             // Else pass the other parameter
812             else if( nParamCount == 2 )
813             {
814                 Sequence< Any > args( 2 );
815                 Any* pAnys = args.getArray();
816 
817                 // Check the type of the 1st parameter
818                 Reference< XIdlClass > xParamClass = params.getConstArray()[0];
819                 if( xParamClass->getTypeClass() == TypeClass_STRING )
820                     pAnys[0] <<= AddListenerParam;
821 
822                 // 2nd parameter == Listener? TODO: Test!
823                 pAnys[1] <<= aToRemoveListener;
824 
825                 // TODO: Convert String -> ?
826                 // else
827                 try
828                 {
829                     rxMethod->invoke( aObjAny, args );
830                 }
831                 catch( const InvocationTargetException& )
832                 {
833                     throw IntrospectionException();
834                 }
835             }
836             break;
837         }
838     }
839 }
840 
attachMultipleEventListeners(const Reference<XInterface> & xObject,const Sequence<css::script::EventListener> & aListeners)841 Sequence< Reference<XEventListener> > EventAttacherImpl::attachMultipleEventListeners(
842     const Reference<XInterface>& xObject, const Sequence<css::script::EventListener>& aListeners )
843 {
844     sal_Int32 nCount = aListeners.getLength();
845     Sequence< Reference<XAllListener> > aFilterListeners(nCount);
846     for (sal_Int32 i = 0; i < nCount; ++i)
847     {
848         aFilterListeners[i]
849             = new FilterAllListenerImpl(this, aListeners[i].EventMethod, aListeners[i].AllListener);
850     }
851 
852     return attachListeners(xObject, aFilterListeners, aListeners);
853 }
854 
855 }
856 
857 extern "C"
858 {
evtatt_component_getFactory(const sal_Char * pImplName,void * pServiceManager,void *)859 SAL_DLLPUBLIC_EXPORT void * evtatt_component_getFactory(
860     const sal_Char * pImplName, void * pServiceManager, void * )
861 {
862     void * pRet = nullptr;
863 
864     if (pServiceManager && rtl_str_compare( pImplName, IMPLNAME ) == 0)
865     {
866         Reference< XSingleServiceFactory > xFactory( createOneInstanceFactory(
867             static_cast< XMultiServiceFactory * >( pServiceManager ),
868             IMPLNAME,
869             ::comp_EventAttacher::EventAttacherImpl_CreateInstance,
870             ::comp_EventAttacher::EventAttacherImpl::getSupportedServiceNames_Static() ) );
871 
872         if (xFactory.is())
873         {
874             xFactory->acquire();
875             pRet = xFactory.get();
876         }
877     }
878 
879     return pRet;
880 }
881 }
882 
883 
884 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
885