1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_extensions.hxx"
26 
27 #include "eventhandler.hxx"
28 #include "propctrlr.hrc"
29 #include "formbrowsertools.hxx"
30 #include "formresid.hrc"
31 #include "formstrings.hxx"
32 #include "handlerhelper.hxx"
33 #include "modulepcr.hxx"
34 #include "pcrcommon.hxx"
35 #include "pcrstrings.hxx"
36 #include "propertycontrolextender.hxx"
37 
38 /** === begin UNO includes === **/
39 #include <com/sun/star/awt/XTabControllerModel.hpp>
40 #include <com/sun/star/beans/PropertyAttribute.hpp>
41 #include <com/sun/star/beans/UnknownPropertyException.hpp>
42 #include <com/sun/star/beans/XIntrospection.hpp>
43 #include <com/sun/star/beans/XIntrospectionAccess.hpp>
44 #include <com/sun/star/container/NoSuchElementException.hpp>
45 #include <com/sun/star/container/XChild.hpp>
46 #include <com/sun/star/container/XIndexAccess.hpp>
47 #include <com/sun/star/container/XNameContainer.hpp>
48 #include <com/sun/star/container/XNameReplace.hpp>
49 #include <com/sun/star/form/FormComponentType.hpp>
50 #include <com/sun/star/form/XForm.hpp>
51 #include <com/sun/star/form/runtime/XFormController.hpp>
52 #include <com/sun/star/inspection/PropertyControlType.hpp>
53 #include <com/sun/star/lang/NullPointerException.hpp>
54 #include <com/sun/star/script/XEventAttacherManager.hpp>
55 #include <com/sun/star/script/XScriptEventsSupplier.hpp>
56 #include <com/sun/star/util/XModifiable.hpp>
57 #include <com/sun/star/uri/UriReferenceFactory.hpp>
58 #include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp>
59 /** === end UNO includes === **/
60 
61 #include <comphelper/namedvaluecollection.hxx>
62 #include <comphelper/evtmethodhelper.hxx>
63 #include <comphelper/types.hxx>
64 #include <cppuhelper/implbase1.hxx>
65 #include <rtl/ref.hxx>
66 #include <rtl/ustrbuf.hxx>
67 #include <sfx2/app.hxx>
68 #include <svl/eitem.hxx>
69 #include <svl/itemset.hxx>
70 #include <svx/svxdlg.hxx>
71 #include <svx/svxids.hrc>
72 #include <tools/diagnose_ex.h>
73 #include <vcl/msgbox.hxx>
74 
75 #include <map>
76 #include <algorithm>
77 
78 //------------------------------------------------------------------------
createRegistryInfo_EventHandler()79 extern "C" void SAL_CALL createRegistryInfo_EventHandler()
80 {
81 	::pcr::OAutoRegistration< ::pcr::EventHandler > aAutoRegistration;
82 }
83 
84 //........................................................................
85 namespace pcr
86 {
87 //........................................................................
88 
89     /** === begin UNO using === **/
90     using ::com::sun::star::uno::Reference;
91     using ::com::sun::star::uno::XComponentContext;
92     using ::com::sun::star::beans::XPropertySet;
93     using ::com::sun::star::uno::Any;
94     using ::com::sun::star::uno::TypeClass_STRING;
95     using ::com::sun::star::uno::Type;
96     using ::com::sun::star::beans::XPropertyChangeListener;
97     using ::com::sun::star::beans::Property;
98     using ::com::sun::star::beans::PropertyState;
99     using ::com::sun::star::beans::PropertyState_DIRECT_VALUE;
100     using ::com::sun::star::uno::Sequence;
101     using ::com::sun::star::script::ScriptEventDescriptor;
102     using ::com::sun::star::script::XScriptEventsSupplier;
103     using ::com::sun::star::lang::NullPointerException;
104     using ::com::sun::star::uno::Exception;
105     using ::com::sun::star::container::XChild;
106     using ::com::sun::star::container::XIndexAccess;
107     using ::com::sun::star::script::XEventAttacherManager;
108     using ::com::sun::star::uno::UNO_QUERY;
109     using ::com::sun::star::uno::UNO_QUERY_THROW;
110     using ::com::sun::star::uno::XInterface;
111     using ::com::sun::star::beans::XIntrospection;
112     using ::com::sun::star::beans::XIntrospectionAccess;
113     using ::com::sun::star::container::XNameContainer;
114     using ::com::sun::star::awt::XTabControllerModel;
115     using ::com::sun::star::form::XForm;
116     using ::com::sun::star::form::runtime::XFormController;
117     using ::com::sun::star::beans::UnknownPropertyException;
118     using ::com::sun::star::uno::makeAny;
119     using ::com::sun::star::container::NoSuchElementException;
120     using ::com::sun::star::beans::XPropertySetInfo;
121     using ::com::sun::star::container::XNameReplace;
122     using ::com::sun::star::lang::IllegalArgumentException;
123     using ::com::sun::star::lang::WrappedTargetException;
124     using ::com::sun::star::uno::RuntimeException;
125     using ::com::sun::star::beans::PropertyValue;
126     using ::com::sun::star::inspection::LineDescriptor;
127     using ::com::sun::star::inspection::XPropertyControlFactory;
128     using ::com::sun::star::inspection::InteractiveSelectionResult;
129     using ::com::sun::star::inspection::InteractiveSelectionResult_Cancelled;
130     using ::com::sun::star::inspection::InteractiveSelectionResult_Success;
131     using ::com::sun::star::inspection::XObjectInspectorUI;
132     using ::com::sun::star::util::XModifiable;
133     using ::com::sun::star::beans::PropertyChangeEvent;
134     using ::com::sun::star::frame::XFrame;
135     using ::com::sun::star::frame::XModel;
136     using ::com::sun::star::frame::XController;
137     using ::com::sun::star::uno::UNO_SET_THROW;
138     using com::sun::star::uri::UriReferenceFactory;
139     using com::sun::star::uri::XUriReferenceFactory;
140     using com::sun::star::uri::XVndSunStarScriptUrlReference;
141     using ::com::sun::star::lang::XEventListener;
142     /** === end UNO using === **/
143     namespace PropertyControlType = ::com::sun::star::inspection::PropertyControlType;
144     namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
145     namespace FormComponentType = ::com::sun::star::form::FormComponentType;
146 
147     //====================================================================
148     //= EventDescription
149     //====================================================================
EventDescription(EventId _nId,const sal_Char * _pListenerNamespaceAscii,const sal_Char * _pListenerClassAsciiName,const sal_Char * _pListenerMethodAsciiName,sal_uInt16 _nDisplayNameResId,const rtl::OString & _sHelpId,const rtl::OString & _sUniqueBrowseId)150     EventDescription::EventDescription( EventId _nId, const sal_Char* _pListenerNamespaceAscii, const sal_Char* _pListenerClassAsciiName,
151             const sal_Char* _pListenerMethodAsciiName, sal_uInt16 _nDisplayNameResId, const rtl::OString& _sHelpId, const rtl::OString& _sUniqueBrowseId )
152         :sDisplayName( String( PcrRes( _nDisplayNameResId ) ) )
153         ,sListenerMethodName( ::rtl::OUString::createFromAscii( _pListenerMethodAsciiName ) )
154         ,sHelpId( _sHelpId )
155         ,sUniqueBrowseId( _sUniqueBrowseId )
156         ,nId( _nId )
157     {
158         ::rtl::OUStringBuffer aQualifiedListenerClass;
159         aQualifiedListenerClass.appendAscii( "com.sun.star." );
160         aQualifiedListenerClass.appendAscii( _pListenerNamespaceAscii );
161         aQualifiedListenerClass.appendAscii( "." );
162         aQualifiedListenerClass.appendAscii( _pListenerClassAsciiName );
163         sListenerClassName = aQualifiedListenerClass.makeStringAndClear();
164     }
165 
166     //========================================================================
167     //= helper
168     //========================================================================
169     namespace
170     {
171         //....................................................................
172         #define DESCRIBE_EVENT( asciinamespace, asciilistener, asciimethod, id_postfix ) \
173             s_aKnownEvents.insert( EventMap::value_type( \
174                 ::rtl::OUString::createFromAscii( asciimethod ), \
175                 EventDescription( ++nEventId, asciinamespace, asciilistener, asciimethod, RID_STR_EVT_##id_postfix, HID_EVT_##id_postfix, UID_BRWEVT_##id_postfix ) ) )
176 
177         //....................................................................
lcl_getEventDescriptionForMethod(const::rtl::OUString & _rMethodName,EventDescription & _out_rDescription)178         bool lcl_getEventDescriptionForMethod( const ::rtl::OUString& _rMethodName, EventDescription& _out_rDescription )
179         {
180             static EventMap s_aKnownEvents;
181             if ( s_aKnownEvents.empty() )
182             {
183                 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
184                 if ( s_aKnownEvents.empty() )
185                 {
186                     static sal_Int32 nEventId = 0;
187 
188                     DESCRIBE_EVENT( "form", "XApproveActionListener",       "approveAction",            APPROVEACTIONPERFORMED );
189                     DESCRIBE_EVENT( "awt",  "XActionListener",              "actionPerformed",          ACTIONPERFORMED );
190                     DESCRIBE_EVENT( "form", "XChangeListener",              "changed",                  CHANGED );
191                     DESCRIBE_EVENT( "awt",  "XTextListener",                "textChanged",              TEXTCHANGED );
192                     DESCRIBE_EVENT( "awt",  "XItemListener",                "itemStateChanged",         ITEMSTATECHANGED );
193                     DESCRIBE_EVENT( "awt",  "XFocusListener",               "focusGained",              FOCUSGAINED );
194                     DESCRIBE_EVENT( "awt",  "XFocusListener",               "focusLost",                FOCUSLOST );
195                     DESCRIBE_EVENT( "awt",  "XKeyListener",                 "keyPressed",               KEYTYPED );
196                     DESCRIBE_EVENT( "awt",  "XKeyListener",                 "keyReleased",              KEYUP );
197                     DESCRIBE_EVENT( "awt",  "XMouseListener",               "mouseEntered",             MOUSEENTERED );
198                     DESCRIBE_EVENT( "awt",  "XMouseMotionListener",         "mouseDragged",             MOUSEDRAGGED );
199                     DESCRIBE_EVENT( "awt",  "XMouseMotionListener",         "mouseMoved",               MOUSEMOVED );
200                     DESCRIBE_EVENT( "awt",  "XMouseListener",               "mousePressed",             MOUSEPRESSED );
201                     DESCRIBE_EVENT( "awt",  "XMouseListener",               "mouseReleased",            MOUSERELEASED );
202                     DESCRIBE_EVENT( "awt",  "XMouseListener",               "mouseExited",              MOUSEEXITED );
203                     DESCRIBE_EVENT( "form", "XResetListener",               "approveReset",             APPROVERESETTED );
204                     DESCRIBE_EVENT( "form", "XResetListener",               "resetted",                 RESETTED );
205                     DESCRIBE_EVENT( "form", "XSubmitListener",              "approveSubmit",            SUBMITTED );
206                     DESCRIBE_EVENT( "form", "XUpdateListener",              "approveUpdate",            BEFOREUPDATE );
207                     DESCRIBE_EVENT( "form", "XUpdateListener",              "updated",                  AFTERUPDATE );
208                     DESCRIBE_EVENT( "form", "XLoadListener",                "loaded",                   LOADED );
209                     DESCRIBE_EVENT( "form", "XLoadListener",                "reloading",                RELOADING );
210                     DESCRIBE_EVENT( "form", "XLoadListener",                "reloaded",                 RELOADED );
211                     DESCRIBE_EVENT( "form", "XLoadListener",                "unloading",                UNLOADING );
212                     DESCRIBE_EVENT( "form", "XLoadListener",                "unloaded",                 UNLOADED );
213                     DESCRIBE_EVENT( "form", "XConfirmDeleteListener",       "confirmDelete",            CONFIRMDELETE );
214                     DESCRIBE_EVENT( "sdb",  "XRowSetApproveListener",       "approveRowChange",         APPROVEROWCHANGE );
215                     DESCRIBE_EVENT( "sdbc", "XRowSetListener",              "rowChanged",               ROWCHANGE );
216                     DESCRIBE_EVENT( "sdb",  "XRowSetApproveListener",       "approveCursorMove",        POSITIONING );
217                     DESCRIBE_EVENT( "sdbc", "XRowSetListener",              "cursorMoved",              POSITIONED );
218                     DESCRIBE_EVENT( "form", "XDatabaseParameterListener",   "approveParameter",         APPROVEPARAMETER );
219                     DESCRIBE_EVENT( "sdb",  "XSQLErrorListener",            "errorOccured",             ERROROCCURED );
220                     DESCRIBE_EVENT( "awt",  "XAdjustmentListener",          "adjustmentValueChanged",   ADJUSTMENTVALUECHANGED );
221                 }
222             }
223 
224             EventMap::const_iterator pos = s_aKnownEvents.find( _rMethodName );
225             if ( pos == s_aKnownEvents.end() )
226                 return false;
227 
228             _out_rDescription = pos->second;
229             return true;
230         }
231 
232         //....................................................................
lcl_getEventPropertyName(const::rtl::OUString & _rListenerClassName,const::rtl::OUString & _rMethodName)233         ::rtl::OUString lcl_getEventPropertyName( const ::rtl::OUString& _rListenerClassName, const ::rtl::OUString& _rMethodName )
234         {
235             ::rtl::OUStringBuffer aPropertyName;
236             aPropertyName.append( _rListenerClassName );
237             aPropertyName.append( (sal_Unicode)';' );
238             aPropertyName.append( _rMethodName.getStr() );
239             return aPropertyName.makeStringAndClear();
240         }
241 
242         //................................................................
lcl_getAssignedScriptEvent(const EventDescription & _rEvent,const Sequence<ScriptEventDescriptor> & _rAllAssignedMacros)243         ScriptEventDescriptor lcl_getAssignedScriptEvent( const EventDescription& _rEvent, const Sequence< ScriptEventDescriptor >& _rAllAssignedMacros )
244         {
245             ScriptEventDescriptor aScriptEvent;
246             // for the case there is actually no event assigned, initialize at least ListenerType and MethodName,
247             //  so this ScriptEventDescriptor properly describes the given event
248             aScriptEvent.ListenerType = _rEvent.sListenerClassName;
249             aScriptEvent.EventMethod = _rEvent.sListenerMethodName;
250 
251             const ScriptEventDescriptor* pAssignedEvent = _rAllAssignedMacros.getConstArray();
252             sal_Int32 assignedEventCount( _rAllAssignedMacros.getLength() );
253             for ( sal_Int32 assignedEvent = 0; assignedEvent < assignedEventCount; ++assignedEvent, ++pAssignedEvent )
254             {
255                 if  (   ( pAssignedEvent->ListenerType != _rEvent.sListenerClassName )
256                     ||  ( pAssignedEvent->EventMethod != _rEvent.sListenerMethodName )
257                     )
258                     continue;
259 
260                 if  (   ( pAssignedEvent->ScriptCode.getLength() == 0 )
261                     ||  ( pAssignedEvent->ScriptType.getLength() == 0 )
262                     )
263                 {
264                     DBG_ERROR( "lcl_getAssignedScriptEvent: me thinks this should not happen!" );
265                     continue;
266                 }
267 
268                 aScriptEvent = *pAssignedEvent;
269 
270                 if ( !aScriptEvent.ScriptType.equalsAscii( "StarBasic" ) )
271                     continue;
272 
273                 // this is an old-style macro specification:
274                 // [document|application]:Library.Module.Function
275                 // we need to translate this to the new-style macro specification
276                 // vnd.sun.star.script:Library.Module.Function?language=Basic&location=[document|application]
277 
278                 sal_Int32 nPrefixLen = aScriptEvent.ScriptCode.indexOf( ':' );
279                 OSL_ENSURE( nPrefixLen > 0, "lcl_getAssignedScriptEvent: illegal location!" );
280                 ::rtl::OUString sLocation = aScriptEvent.ScriptCode.copy( 0, nPrefixLen );
281                 ::rtl::OUString sMacroPath = aScriptEvent.ScriptCode.copy( nPrefixLen + 1 );
282 
283                 ::rtl::OUStringBuffer aNewStyleSpec;
284                 aNewStyleSpec.appendAscii( "vnd.sun.star.script:" );
285                 aNewStyleSpec.append     ( sMacroPath );
286                 aNewStyleSpec.appendAscii( "?language=Basic&location=" );
287                 aNewStyleSpec.append     ( sLocation );
288 
289                 aScriptEvent.ScriptCode = aNewStyleSpec.makeStringAndClear();
290 
291                 // also, this new-style spec requires the script code to be "Script" instead of "StarBasic"
292                 aScriptEvent.ScriptType = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Script" ) );
293             }
294             return aScriptEvent;
295         }
296 
297         //................................................................
lcl_getQualifiedKnownListenerName(const ScriptEventDescriptor & _rFormComponentEventDescriptor)298         ::rtl::OUString lcl_getQualifiedKnownListenerName( const ScriptEventDescriptor& _rFormComponentEventDescriptor )
299         {
300             EventDescription aKnownEvent;
301             if ( lcl_getEventDescriptionForMethod( _rFormComponentEventDescriptor.EventMethod, aKnownEvent ) )
302                 return aKnownEvent.sListenerClassName;
303             DBG_ERROR( "lcl_getQualifiedKnownListenerName: unknown method name!" );
304                 // somebody assigned an script to a form component event which we don't know
305                 // Speaking strictly, this is not really an error - it is possible to do
306                 // this programmatically -, but it should rarely happen, since it's not possible
307                 // via UI
308             return _rFormComponentEventDescriptor.ListenerType;
309         }
310 
311         //................................................................
312         typedef ::std::set< Type, TypeLessByName > TypeBag;
313 
314         //................................................................
lcl_addListenerTypesFor_throw(const Reference<XInterface> & _rxComponent,const Reference<XIntrospection> & _rxIntrospection,TypeBag & _out_rTypes)315         void lcl_addListenerTypesFor_throw( const Reference< XInterface >& _rxComponent,
316             const Reference< XIntrospection >& _rxIntrospection, TypeBag& _out_rTypes )
317         {
318             if ( !_rxComponent.is() )
319                 return;
320             OSL_PRECOND( _rxIntrospection.is(), "lcl_addListenerTypesFor_throw: this will crash!" );
321 
322             Reference< XIntrospectionAccess > xIntrospectionAccess(
323                 _rxIntrospection->inspect( makeAny( _rxComponent ) ), UNO_QUERY_THROW );
324 
325             Sequence< Type > aListeners( xIntrospectionAccess->getSupportedListeners() );
326 
327             ::std::copy( aListeners.getConstArray(), aListeners.getConstArray() + aListeners.getLength(),
328                 ::std::insert_iterator< TypeBag >( _out_rTypes, _out_rTypes.begin() ) );
329         }
330 
331         //................................................................
operator ==(const ScriptEventDescriptor _lhs,const ScriptEventDescriptor _rhs)332         bool operator ==( const ScriptEventDescriptor _lhs, const ScriptEventDescriptor _rhs )
333         {
334             return  (   ( _lhs.ListenerType         == _rhs.ListenerType        )
335                     &&  ( _lhs.EventMethod          == _rhs.EventMethod         )
336                     &&  ( _lhs.AddListenerParam     == _rhs.AddListenerParam    )
337                     &&  ( _lhs.ScriptType           == _rhs.ScriptType          )
338                     &&  ( _lhs.ScriptCode           == _rhs.ScriptCode          )
339                     );
340         }
341     }
342 
343     //====================================================================
344     //= EventHandler
345     //====================================================================
346     typedef ::cppu::WeakImplHelper1 <   ::com::sun::star::container::XNameReplace
347                                     >   EventHolder_Base;
348     /** a UNO component holding assigned event descriptions, for use with a SvxMacroAssignDlg
349     */
350     class EventHolder : public EventHolder_Base
351     {
352     private:
353         typedef ::std::hash_map< ::rtl::OUString, ScriptEventDescriptor, ::rtl::OUStringHash >  EventMap;
354         typedef ::std::map< EventId, EventMap::iterator >                                       EventMapIndexAccess;
355 
356         EventMap            m_aEventNameAccess;
357         EventMapIndexAccess m_aEventIndexAccess;
358 
359     public:
360         EventHolder( );
361 
362         void addEvent( EventId _nId, const ::rtl::OUString& _rEventName, const ScriptEventDescriptor& _rScriptEvent );
363 
364         /** effectively the same as getByName, but instead of converting the ScriptEventDescriptor to the weird
365             format used by the macro assignment dialog, it is returned directly
366         */
367         ScriptEventDescriptor getNormalizedDescriptorByName( const ::rtl::OUString& _rEventName ) const;
368 
369         // XNameReplace
370         virtual void SAL_CALL replaceByName( const ::rtl::OUString& _rName, const Any& aElement ) throw (IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException);
371         virtual Any SAL_CALL getByName( const ::rtl::OUString& _rName ) throw (NoSuchElementException, WrappedTargetException, RuntimeException);
372         virtual Sequence< ::rtl::OUString > SAL_CALL getElementNames(  ) throw (RuntimeException);
373         virtual ::sal_Bool SAL_CALL hasByName( const ::rtl::OUString& _rName ) throw (RuntimeException);
374         virtual Type SAL_CALL getElementType(  ) throw (RuntimeException);
375         virtual ::sal_Bool SAL_CALL hasElements(  ) throw (RuntimeException);
376 
377     protected:
378         ~EventHolder( );
379 
380     private:
381         ScriptEventDescriptor impl_getDescriptor_throw( const ::rtl::OUString& _rEventName ) const;
382     };
383 
DBG_NAME(EventHolder)384     DBG_NAME( EventHolder )
385 	//------------------------------------------------------------------------
386     EventHolder::EventHolder()
387     {
388         DBG_CTOR( EventHolder, NULL );
389     }
390 
391 	//------------------------------------------------------------------------
~EventHolder()392     EventHolder::~EventHolder()
393     {
394         m_aEventNameAccess.clear();
395         m_aEventIndexAccess.clear();
396         DBG_DTOR( EventHolder, NULL );
397     }
398 
399 	//------------------------------------------------------------------------
addEvent(EventId _nId,const::rtl::OUString & _rEventName,const ScriptEventDescriptor & _rScriptEvent)400     void EventHolder::addEvent( EventId _nId, const ::rtl::OUString& _rEventName, const ScriptEventDescriptor& _rScriptEvent )
401     {
402         ::std::pair< EventMap::iterator, bool > insertionResult =
403             m_aEventNameAccess.insert( EventMap::value_type( _rEventName, _rScriptEvent ) );
404         OSL_ENSURE( insertionResult.second, "EventHolder::addEvent: there already was a MacroURL for this event!" );
405         m_aEventIndexAccess[ _nId ] = insertionResult.first;
406     }
407 
408     //------------------------------------------------------------------------
getNormalizedDescriptorByName(const::rtl::OUString & _rEventName) const409     ScriptEventDescriptor EventHolder::getNormalizedDescriptorByName( const ::rtl::OUString& _rEventName ) const
410     {
411         return impl_getDescriptor_throw( _rEventName );
412     }
413 
414     //------------------------------------------------------------------------
impl_getDescriptor_throw(const::rtl::OUString & _rEventName) const415     ScriptEventDescriptor EventHolder::impl_getDescriptor_throw( const ::rtl::OUString& _rEventName ) const
416     {
417         EventMap::const_iterator pos = m_aEventNameAccess.find( _rEventName );
418         if ( pos == m_aEventNameAccess.end() )
419             throw NoSuchElementException( ::rtl::OUString(), *const_cast< EventHolder* >( this ) );
420         return pos->second;
421     }
422 
423 	//------------------------------------------------------------------------
replaceByName(const::rtl::OUString & _rName,const Any & _rElement)424     void SAL_CALL EventHolder::replaceByName( const ::rtl::OUString& _rName, const Any& _rElement ) throw (IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException)
425     {
426         EventMap::iterator pos = m_aEventNameAccess.find( _rName );
427         if ( pos == m_aEventNameAccess.end() )
428             throw NoSuchElementException( ::rtl::OUString(), *this );
429 
430         Sequence< PropertyValue > aScriptDescriptor;
431         OSL_VERIFY( _rElement >>= aScriptDescriptor );
432 
433         ::comphelper::NamedValueCollection aExtractor( aScriptDescriptor );
434 
435         pos->second.ScriptType = aExtractor.getOrDefault( "EventType", ::rtl::OUString() );
436         pos->second.ScriptCode = aExtractor.getOrDefault( "Script", ::rtl::OUString() );
437     }
438 
439     //------------------------------------------------------------------------
getByName(const::rtl::OUString & _rName)440     Any SAL_CALL EventHolder::getByName( const ::rtl::OUString& _rName ) throw (NoSuchElementException, WrappedTargetException, RuntimeException)
441     {
442         ScriptEventDescriptor aDescriptor( impl_getDescriptor_throw( _rName ) );
443 
444         Any aRet;
445         Sequence< PropertyValue > aScriptDescriptor( 2 );
446         aScriptDescriptor[0].Name = ::rtl::OUString::createFromAscii( "EventType" );
447         aScriptDescriptor[0].Value <<= aDescriptor.ScriptType;
448         aScriptDescriptor[1].Name = ::rtl::OUString::createFromAscii( "Script" );
449         aScriptDescriptor[1].Value <<= aDescriptor.ScriptCode;
450 
451         return makeAny( aScriptDescriptor );
452     }
453 
454 	//------------------------------------------------------------------------
getElementNames()455     Sequence< ::rtl::OUString > SAL_CALL EventHolder::getElementNames(  ) throw (RuntimeException)
456     {
457         Sequence< ::rtl::OUString > aReturn( m_aEventIndexAccess.size() );
458         ::rtl::OUString* pReturn = aReturn.getArray();
459 
460         // SvxMacroAssignDlg has a weird API: It expects a XNameReplace, means a container whose
461         // main access method is by name. In it's UI, it shows the possible events in exactly the
462         // order in which XNameAccess::getElementNames returns them.
463         // However, SvxMacroAssignDlg *also* takes an index for the initial selection, which is
464         // relative to the sequence returned by XNameAccess::getElementNames.
465         // This is IMO weird, since it mixes index access with name access, which decreases efficiency
466         // of the implementation.
467         // Well, it means we're forced to return the events in getElementNames in exactly the same as they
468         // appear in the property browser UI.
469         for (   EventMapIndexAccess::const_iterator loop = m_aEventIndexAccess.begin();
470                 loop != m_aEventIndexAccess.end();
471                 ++loop, ++pReturn
472             )
473             *pReturn = loop->second->first;
474         return aReturn;
475     }
476 
477  	//------------------------------------------------------------------------
hasByName(const::rtl::OUString & _rName)478     sal_Bool SAL_CALL EventHolder::hasByName( const ::rtl::OUString& _rName ) throw (RuntimeException)
479     {
480         EventMap::const_iterator pos = m_aEventNameAccess.find( _rName );
481         return pos != m_aEventNameAccess.end();
482     }
483 
484 	//------------------------------------------------------------------------
getElementType()485     Type SAL_CALL EventHolder::getElementType(  ) throw (RuntimeException)
486     {
487         return ::getCppuType( static_cast< Sequence< PropertyValue >* >( NULL ) );
488     }
489 
490 	//------------------------------------------------------------------------
hasElements()491     sal_Bool SAL_CALL EventHolder::hasElements(  ) throw (RuntimeException)
492     {
493         return !m_aEventNameAccess.empty();
494     }
495 
496 
497     //====================================================================
498     //= EventHandler
499     //====================================================================
DBG_NAME(EventHandler)500     DBG_NAME( EventHandler )
501     //--------------------------------------------------------------------
502     EventHandler::EventHandler( const Reference< XComponentContext >& _rxContext )
503         :EventHandler_Base( m_aMutex )
504         ,m_aContext( _rxContext )
505         ,m_aPropertyListeners( m_aMutex )
506         ,m_bEventsMapInitialized( false )
507         ,m_bIsDialogElement( false )
508         ,m_nGridColumnType( -1 )
509     {
510         DBG_CTOR( EventHandler, NULL );
511     }
512 
513     //--------------------------------------------------------------------
~EventHandler()514     EventHandler::~EventHandler()
515     {
516         DBG_DTOR( EventHandler, NULL );
517     }
518 
519     //--------------------------------------------------------------------
getImplementationName()520     ::rtl::OUString SAL_CALL EventHandler::getImplementationName(  ) throw (RuntimeException)
521     {
522         return getImplementationName_static();
523     }
524 
525     //--------------------------------------------------------------------
supportsService(const::rtl::OUString & ServiceName)526     ::sal_Bool SAL_CALL EventHandler::supportsService( const ::rtl::OUString& ServiceName ) throw (RuntimeException)
527     {
528         StlSyntaxSequence< ::rtl::OUString > aAllServices( getSupportedServiceNames() );
529         return ::std::find( aAllServices.begin(), aAllServices.end(), ServiceName ) != aAllServices.end();
530     }
531 
532     //--------------------------------------------------------------------
getSupportedServiceNames()533     Sequence< ::rtl::OUString > SAL_CALL EventHandler::getSupportedServiceNames(  ) throw (RuntimeException)
534     {
535         return getSupportedServiceNames_static();
536     }
537 
538     //--------------------------------------------------------------------
getImplementationName_static()539     ::rtl::OUString SAL_CALL EventHandler::getImplementationName_static(  ) throw (RuntimeException)
540     {
541         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.extensions.EventHandler" ) );
542     }
543 
544     //--------------------------------------------------------------------
getSupportedServiceNames_static()545     Sequence< ::rtl::OUString > SAL_CALL EventHandler::getSupportedServiceNames_static(  ) throw (RuntimeException)
546     {
547         Sequence< ::rtl::OUString > aSupported( 1 );
548         aSupported[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.inspection.EventHandler" ) );
549         return aSupported;
550     }
551 
552     //--------------------------------------------------------------------
Create(const Reference<XComponentContext> & _rxContext)553     Reference< XInterface > SAL_CALL EventHandler::Create( const Reference< XComponentContext >& _rxContext )
554     {
555         return *( new EventHandler( _rxContext ) );
556     }
557 
558     //--------------------------------------------------------------------
inspect(const Reference<XInterface> & _rxIntrospectee)559     void SAL_CALL EventHandler::inspect( const Reference< XInterface >& _rxIntrospectee ) throw (RuntimeException, NullPointerException)
560     {
561         ::osl::MutexGuard aGuard( m_aMutex );
562 
563         if ( !_rxIntrospectee.is() )
564             throw NullPointerException();
565 
566         m_xComponent = Reference< XPropertySet >( _rxIntrospectee, UNO_QUERY_THROW );
567 
568         m_bEventsMapInitialized = false;
569         EventMap aEmpty;
570         m_aEvents.swap( aEmpty );
571 
572         m_bIsDialogElement = false;
573         m_nGridColumnType = -1;
574         try
575         {
576             Reference< XPropertySetInfo > xPSI( m_xComponent->getPropertySetInfo() );
577             m_bIsDialogElement = xPSI.is()
578                               && xPSI->hasPropertyByName( PROPERTY_WIDTH )
579                               && xPSI->hasPropertyByName( PROPERTY_HEIGHT )
580                               && xPSI->hasPropertyByName( PROPERTY_POSITIONX )
581                               && xPSI->hasPropertyByName( PROPERTY_POSITIONY );
582 
583             Reference< XChild > xAsChild( _rxIntrospectee, UNO_QUERY );
584             if ( xAsChild.is() && !Reference< XForm >( _rxIntrospectee, UNO_QUERY ).is() )
585             {
586                 if ( FormComponentType::GRIDCONTROL == classifyComponent( xAsChild->getParent() ) )
587                 {
588                     m_nGridColumnType = classifyComponent( _rxIntrospectee );
589                 }
590             }
591         }
592         catch( const Exception& )
593         {
594             DBG_UNHANDLED_EXCEPTION();
595         }
596     }
597 
598     //--------------------------------------------------------------------
getPropertyValue(const::rtl::OUString & _rPropertyName)599     Any SAL_CALL EventHandler::getPropertyValue( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, RuntimeException)
600     {
601         ::osl::MutexGuard aGuard( m_aMutex );
602 
603         const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName );
604 
605         Sequence< ScriptEventDescriptor > aEvents;
606         impl_getComponentScriptEvents_nothrow( aEvents );
607 
608         sal_Int32 nEventCount = aEvents.getLength();
609         const ScriptEventDescriptor* pEvents = aEvents.getConstArray();
610 
611         ScriptEventDescriptor aPropertyValue;
612         for ( sal_Int32 event = 0; event < nEventCount; ++event, ++pEvents )
613         {
614             if  (   rEvent.sListenerClassName == pEvents->ListenerType
615                 &&  rEvent.sListenerMethodName == pEvents->EventMethod
616                 )
617             {
618                 aPropertyValue = *pEvents;
619                 break;
620             }
621         }
622 
623         return makeAny( aPropertyValue );
624     }
625 
626     //--------------------------------------------------------------------
setPropertyValue(const::rtl::OUString & _rPropertyName,const Any & _rValue)627     void SAL_CALL EventHandler::setPropertyValue( const ::rtl::OUString& _rPropertyName, const Any& _rValue ) throw (UnknownPropertyException, RuntimeException)
628     {
629         ::osl::MutexGuard aGuard( m_aMutex );
630 
631         const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName );
632 
633         ScriptEventDescriptor aNewScriptEvent;
634         OSL_VERIFY( _rValue >>= aNewScriptEvent );
635 
636         ScriptEventDescriptor aOldScriptEvent;
637         OSL_VERIFY( getPropertyValue( _rPropertyName ) >>= aOldScriptEvent );
638         if ( aOldScriptEvent == aNewScriptEvent )
639             return;
640 
641         if ( m_bIsDialogElement )
642             impl_setDialogElementScriptEvent_nothrow( aNewScriptEvent );
643         else
644             impl_setFormComponentScriptEvent_nothrow( aNewScriptEvent );
645 
646         Reference< XModifiable > xDoc( m_aContext.getContextValueByAsciiName( "ContextDocument" ), UNO_QUERY );
647         if ( xDoc.is() )
648             xDoc->setModified( sal_True );
649 
650         PropertyChangeEvent aEvent;
651         aEvent.Source = m_xComponent;
652         aEvent.PropertyHandle = rEvent.nId;
653         aEvent.PropertyName = _rPropertyName;
654         aEvent.OldValue <<= aOldScriptEvent;
655         aEvent.NewValue <<= aNewScriptEvent;
656         m_aPropertyListeners.notify( aEvent, &XPropertyChangeListener::propertyChange );
657     }
658 
659     //--------------------------------------------------------------------
convertToPropertyValue(const::rtl::OUString & _rPropertyName,const Any & _rControlValue)660     Any SAL_CALL EventHandler::convertToPropertyValue( const ::rtl::OUString& _rPropertyName, const Any& _rControlValue ) throw (UnknownPropertyException, RuntimeException)
661     {
662         ::osl::MutexGuard aGuard( m_aMutex );
663 
664         ::rtl::OUString sNewScriptCode;
665         OSL_VERIFY( _rControlValue >>= sNewScriptCode );
666 
667         Sequence< ScriptEventDescriptor > aAllAssignedEvents;
668         impl_getComponentScriptEvents_nothrow( aAllAssignedEvents );
669 
670         const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName );
671         ScriptEventDescriptor aAssignedScript = lcl_getAssignedScriptEvent( rEvent, aAllAssignedEvents );
672 
673         OSL_ENSURE( !sNewScriptCode.getLength(), "EventHandler::convertToPropertyValue: cannot convert a non-empty display name!" );
674         // Usually, there is no possibility for the user to change the content of an event binding directly in the
675         // input field, this instead is done with the macro assignment dialog.
676         // The only exception is the user pressing "DEL" while the control has the focus, in this case, we reset the
677         // control content to an empty string. So this is the only scenario where this method is allowed to be called.
678 
679         // Striclty, we would be able to convert the display value to a property value,
680         // using the "name (location, language)" format we used in convertToControlValue. However,
681         // there is no need for this code ...
682 
683         aAssignedScript.ScriptCode = sNewScriptCode;
684         return makeAny( aAssignedScript );
685     }
686 
687     //--------------------------------------------------------------------
convertToControlValue(const::rtl::OUString &,const Any & _rPropertyValue,const Type & _rControlValueType)688     Any SAL_CALL EventHandler::convertToControlValue( const ::rtl::OUString& /*_rPropertyName*/, const Any& _rPropertyValue, const Type& _rControlValueType ) throw (UnknownPropertyException, RuntimeException)
689     {
690         ::osl::MutexGuard aGuard( m_aMutex );
691 
692         ScriptEventDescriptor aScriptEvent;
693         OSL_VERIFY( _rPropertyValue >>= aScriptEvent );
694 
695         OSL_ENSURE( _rControlValueType.getTypeClass() == TypeClass_STRING,
696             "EventHandler::convertToControlValue: unexpected ControlValue type class!" );
697         (void)_rControlValueType;
698 
699         ::rtl::OUString sScript( aScriptEvent.ScriptCode );
700         if ( sScript.getLength() )
701         {
702             // format is: "name (location, language)"
703             try
704             {
705                 // parse
706                 Reference< XUriReferenceFactory > xUriRefFac = UriReferenceFactory::create( m_aContext.getUNOContext() );
707                 Reference< XVndSunStarScriptUrlReference > xScriptUri( xUriRefFac->parse( sScript ), UNO_QUERY_THROW );
708 
709                 ::rtl::OUStringBuffer aComposeBuffer;
710 
711                 // name
712                 aComposeBuffer.append( xScriptUri->getName() );
713 
714                 // location
715                 const ::rtl::OUString sLocationParamName( RTL_CONSTASCII_USTRINGPARAM( "location" ) );
716                 const ::rtl::OUString sLocation = xScriptUri->getParameter( sLocationParamName );
717                 const ::rtl::OUString sLangParamName( RTL_CONSTASCII_USTRINGPARAM( "language" ) );
718                 const ::rtl::OUString sLanguage = xScriptUri->getParameter( sLangParamName );
719 
720                 if ( sLocation.getLength() || sLanguage.getLength() )
721                 {
722                     aComposeBuffer.appendAscii( " (" );
723 
724                     // location
725                     OSL_ENSURE( sLocation.getLength(), "EventHandler::convertToControlValue: unexpected: no location!" );
726                     if ( sLocation.getLength() )
727                     {
728                         aComposeBuffer.append( sLocation );
729                         aComposeBuffer.appendAscii( ", " );
730                     }
731 
732                     // language
733                     if ( sLanguage.getLength() )
734                     {
735                         aComposeBuffer.append( sLanguage );
736                     }
737 
738                     aComposeBuffer.append( sal_Unicode( ')' ) );
739                 }
740 
741                 sScript = aComposeBuffer.makeStringAndClear();
742             }
743             catch( const Exception& )
744             {
745         	    DBG_UNHANDLED_EXCEPTION();
746             }
747         }
748 
749         return makeAny( sScript );
750     }
751 
752     //--------------------------------------------------------------------
getPropertyState(const::rtl::OUString &)753     PropertyState SAL_CALL EventHandler::getPropertyState( const ::rtl::OUString& /*_rPropertyName*/ ) throw (UnknownPropertyException, RuntimeException)
754     {
755         return PropertyState_DIRECT_VALUE;
756     }
757 
758     //--------------------------------------------------------------------
addPropertyChangeListener(const Reference<XPropertyChangeListener> & _rxListener)759     void SAL_CALL EventHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) throw (RuntimeException)
760     {
761         ::osl::MutexGuard aGuard( m_aMutex );
762         if ( !_rxListener.is() )
763             throw NullPointerException();
764         m_aPropertyListeners.addListener( _rxListener );
765     }
766 
767     //--------------------------------------------------------------------
removePropertyChangeListener(const Reference<XPropertyChangeListener> & _rxListener)768     void SAL_CALL EventHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) throw (RuntimeException)
769     {
770         ::osl::MutexGuard aGuard( m_aMutex );
771         m_aPropertyListeners.removeListener( _rxListener );
772     }
773 
774     //--------------------------------------------------------------------
getSupportedProperties()775     Sequence< Property > SAL_CALL EventHandler::getSupportedProperties() throw (RuntimeException)
776     {
777         ::osl::MutexGuard aGuard( m_aMutex );
778         if ( !m_bEventsMapInitialized )
779         {
780             const_cast< EventHandler* >( this )->m_bEventsMapInitialized = true;
781             try
782             {
783                 Sequence< Type > aListeners;
784                 impl_getCopmonentListenerTypes_nothrow( aListeners );
785                 sal_Int32 listenerCount = aListeners.getLength();
786 
787                 Property aCurrentProperty;
788                 ::rtl::OUString sListenerClassName;
789 
790                 // loop through all listeners and all methods, and see which we can present at the UI
791                 const Type* pListeners = aListeners.getConstArray();
792                 for ( sal_Int32 listener = 0; listener < listenerCount; ++listener, ++pListeners )
793                 {
794                     aCurrentProperty = Property();
795 
796                     // the programmatic name of the listener, to be used as "property" name
797                     sListenerClassName = pListeners->getTypeName();
798                     OSL_ENSURE( sListenerClassName.getLength(), "EventHandler::getSupportedProperties: strange - no listener name ..." );
799                     if ( !sListenerClassName.getLength() )
800                         continue;
801 
802                     // loop through all methods
803                     Sequence< ::rtl::OUString > aMethods( comphelper::getEventMethodsForType( *pListeners ) );
804 
805                     const ::rtl::OUString* pMethods = aMethods.getConstArray();
806                     sal_uInt32 methodCount = aMethods.getLength();
807 
808                     for (sal_uInt32 method = 0 ; method < methodCount ; ++method, ++pMethods )
809                     {
810                         EventDescription aEvent;
811                         if ( !lcl_getEventDescriptionForMethod( *pMethods, aEvent ) )
812                             continue;
813 
814                         if ( !impl_filterMethod_nothrow( aEvent ) )
815                             continue;
816 
817                         const_cast< EventHandler* >( this )->m_aEvents.insert( EventMap::value_type(
818                             lcl_getEventPropertyName( sListenerClassName, *pMethods ), aEvent ) );
819                     }
820                 }
821 
822             }
823             catch( const Exception& )
824             {
825                 DBG_UNHANDLED_EXCEPTION();
826             }
827         }
828 
829         // sort them by ID - this is the relative ordering in the UI
830         ::std::map< EventId, Property > aOrderedProperties;
831         for (   EventMap::const_iterator loop = m_aEvents.begin();
832                 loop != m_aEvents.end();
833                 ++loop
834             )
835         {
836             aOrderedProperties[ loop->second.nId ] = Property(
837                 loop->first, loop->second.nId,
838                 ::getCppuType( static_cast< const ::rtl::OUString* >( NULL ) ),
839                 PropertyAttribute::BOUND );
840         }
841 
842         StlSyntaxSequence< Property > aReturn( aOrderedProperties.size() );
843         ::std::transform( aOrderedProperties.begin(), aOrderedProperties.end(), aReturn.begin(),
844             ::std::select2nd< ::std::map< EventId, Property >::value_type >() );
845         return aReturn;
846     }
847 
848     //--------------------------------------------------------------------
getSupersededProperties()849     Sequence< ::rtl::OUString > SAL_CALL EventHandler::getSupersededProperties( ) throw (RuntimeException)
850     {
851         // none
852         return Sequence< ::rtl::OUString >( );
853     }
854 
855     //--------------------------------------------------------------------
getActuatingProperties()856     Sequence< ::rtl::OUString > SAL_CALL EventHandler::getActuatingProperties( ) throw (RuntimeException)
857     {
858         // none
859         return Sequence< ::rtl::OUString >( );
860     }
861 
862     //--------------------------------------------------------------------
describePropertyLine(const::rtl::OUString & _rPropertyName,const Reference<XPropertyControlFactory> & _rxControlFactory)863     LineDescriptor SAL_CALL EventHandler::describePropertyLine( const ::rtl::OUString& _rPropertyName,
864         const Reference< XPropertyControlFactory >& _rxControlFactory )
865         throw (UnknownPropertyException, NullPointerException, RuntimeException)
866     {
867         if ( !_rxControlFactory.is() )
868             throw NullPointerException();
869 
870         ::osl::MutexGuard aGuard( m_aMutex );
871 
872         LineDescriptor aDescriptor;
873 
874         aDescriptor.Control = _rxControlFactory->createPropertyControl( PropertyControlType::TextField, sal_True );
875         Reference< XEventListener > xControlExtender = new PropertyControlExtender( aDescriptor.Control );
876 
877         const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName );
878         aDescriptor.DisplayName = rEvent.sDisplayName;
879         aDescriptor.HelpURL = HelpIdUrl::getHelpURL( rEvent.sHelpId );
880         aDescriptor.PrimaryButtonId = rtl::OStringToOUString(rEvent.sUniqueBrowseId, RTL_TEXTENCODING_UTF8);
881         aDescriptor.HasPrimaryButton = sal_True;
882         aDescriptor.Category = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Events" ) );
883         return aDescriptor;
884     }
885 
886     //--------------------------------------------------------------------
isComposable(const::rtl::OUString &)887     ::sal_Bool SAL_CALL EventHandler::isComposable( const ::rtl::OUString& /*_rPropertyName*/ ) throw (UnknownPropertyException, RuntimeException)
888     {
889         return sal_False;
890     }
891 
892     //--------------------------------------------------------------------
onInteractivePropertySelection(const::rtl::OUString & _rPropertyName,sal_Bool,Any &,const Reference<XObjectInspectorUI> & _rxInspectorUI)893     InteractiveSelectionResult SAL_CALL EventHandler::onInteractivePropertySelection( const ::rtl::OUString& _rPropertyName, sal_Bool /*_bPrimary*/, Any& /*_rData*/, const Reference< XObjectInspectorUI >& _rxInspectorUI ) throw (UnknownPropertyException, NullPointerException, RuntimeException)
894     {
895         if ( !_rxInspectorUI.is() )
896             throw NullPointerException();
897 
898         ::osl::MutexGuard aGuard( m_aMutex );
899         const EventDescription& rForEvent = impl_getEventForName_throw( _rPropertyName );
900 
901         Sequence< ScriptEventDescriptor > aAllAssignedEvents;
902         impl_getComponentScriptEvents_nothrow( aAllAssignedEvents );
903 
904         // SvxMacroAssignDlg-compatible structure holding all event/assignments
905         ::rtl::Reference< EventHolder >  pEventHolder( new EventHolder );
906 
907         for (   EventMap::const_iterator event = m_aEvents.begin();
908                 event != m_aEvents.end();
909                 ++event
910             )
911         {
912             // the script which is assigned to the current event (if any)
913             ScriptEventDescriptor aAssignedScript = lcl_getAssignedScriptEvent( event->second, aAllAssignedEvents );
914             pEventHolder->addEvent( event->second.nId, event->second.sListenerMethodName, aAssignedScript );
915         }
916 
917         // the inital selection in the dialog
918         Sequence< ::rtl::OUString > aNames( pEventHolder->getElementNames() );
919         const ::rtl::OUString* pChosenEvent = ::std::find( aNames.getConstArray(), aNames.getConstArray() + aNames.getLength(), rForEvent.sListenerMethodName );
920         sal_uInt16 nInitialSelection = (sal_uInt16)( pChosenEvent - aNames.getConstArray() );
921 
922         // the dialog
923         SvxAbstractDialogFactory* pFactory = SvxAbstractDialogFactory::Create();
924         if ( !pFactory )
925             return InteractiveSelectionResult_Cancelled;
926 
927         ::std::auto_ptr< VclAbstractDialog > pDialog( pFactory->CreateSvxMacroAssignDlg(
928             PropertyHandlerHelper::getDialogParentWindow( m_aContext ),
929             impl_getContextFrame_nothrow(),
930             m_bIsDialogElement,
931             pEventHolder.get(),
932             nInitialSelection
933         ) );
934 
935         if ( !pDialog.get() )
936             return InteractiveSelectionResult_Cancelled;
937 
938         // DF definite problem here
939         // OK & Cancel seem to be both returning 0
940         if ( pDialog->Execute() == RET_CANCEL )
941             return InteractiveSelectionResult_Cancelled;
942 
943         try
944         {
945             for (   EventMap::const_iterator event = m_aEvents.begin();
946                     event != m_aEvents.end();
947                     ++event
948                 )
949             {
950                 ScriptEventDescriptor aScriptDescriptor( pEventHolder->getNormalizedDescriptorByName( event->second.sListenerMethodName ) );
951 
952                 // set the new "property value"
953                 setPropertyValue(
954                     lcl_getEventPropertyName( event->second.sListenerClassName, event->second.sListenerMethodName ),
955                     makeAny( aScriptDescriptor )
956                 );
957             }
958         }
959         catch( const Exception& )
960         {
961             DBG_UNHANDLED_EXCEPTION();
962         }
963 
964         return InteractiveSelectionResult_Success;
965     }
966 
967     //--------------------------------------------------------------------
actuatingPropertyChanged(const::rtl::OUString &,const Any &,const Any &,const Reference<XObjectInspectorUI> &,sal_Bool)968     void SAL_CALL EventHandler::actuatingPropertyChanged( const ::rtl::OUString& /*_rActuatingPropertyName*/, const Any& /*_rNewValue*/, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& /*_rxInspectorUI*/, sal_Bool /*_bFirstTimeInit*/ ) throw (NullPointerException, RuntimeException)
969     {
970         DBG_ERROR( "EventHandler::actuatingPropertyChanged: no actuating properties -> no callback (well, this is how it *should* be!)" );
971     }
972 
973     //--------------------------------------------------------------------
IMPLEMENT_FORWARD_XCOMPONENT(EventHandler,EventHandler_Base)974     IMPLEMENT_FORWARD_XCOMPONENT( EventHandler, EventHandler_Base )
975 
976     //--------------------------------------------------------------------
977     void SAL_CALL EventHandler::disposing()
978     {
979         EventMap aEmpty;
980         m_aEvents.swap( aEmpty );
981         m_xComponent.clear();
982     }
983 
984     //--------------------------------------------------------------------
suspend(sal_Bool)985     sal_Bool SAL_CALL EventHandler::suspend( sal_Bool /*_bSuspend*/ ) throw (RuntimeException)
986     {
987         return sal_True;
988     }
989 
990     //------------------------------------------------------------------------
impl_getContextFrame_nothrow() const991     Reference< XFrame > EventHandler::impl_getContextFrame_nothrow() const
992     {
993         Reference< XFrame > xContextFrame;
994 
995         try
996         {
997             Reference< XModel > xContextDocument( m_aContext.getContextValueByAsciiName( "ContextDocument" ), UNO_QUERY_THROW );
998             Reference< XController > xController( xContextDocument->getCurrentController(), UNO_SET_THROW );
999             xContextFrame.set( xController->getFrame(), UNO_SET_THROW );
1000         }
1001         catch( const Exception& )
1002         {
1003         	DBG_UNHANDLED_EXCEPTION();
1004         }
1005 
1006         return xContextFrame;
1007     }
1008 
1009     //--------------------------------------------------------------------
impl_getComponentIndexInParent_throw() const1010     sal_Int32 EventHandler::impl_getComponentIndexInParent_throw() const
1011     {
1012         Reference< XChild > xChild( m_xComponent, UNO_QUERY_THROW );
1013         Reference< XIndexAccess > xParentAsIndexAccess( xChild->getParent(), UNO_QUERY_THROW );
1014 
1015         // get the index of the inspected object within it's parent container
1016         sal_Int32 nElements = xParentAsIndexAccess->getCount();
1017         for ( sal_Int32 i=0; i<nElements; ++i )
1018         {
1019             Reference< XInterface > xElement( xParentAsIndexAccess->getByIndex( i ), UNO_QUERY_THROW );
1020             if ( xElement == m_xComponent )
1021                 return i;
1022         }
1023         throw NoSuchElementException();
1024     }
1025 
1026     //--------------------------------------------------------------------
impl_getFormComponentScriptEvents_nothrow(Sequence<ScriptEventDescriptor> & _out_rEvents) const1027     void EventHandler::impl_getFormComponentScriptEvents_nothrow( Sequence < ScriptEventDescriptor >& _out_rEvents ) const
1028     {
1029         _out_rEvents = Sequence < ScriptEventDescriptor >();
1030         try
1031         {
1032             Reference< XChild > xChild( m_xComponent, UNO_QUERY_THROW );
1033             Reference< XEventAttacherManager > xEventManager( xChild->getParent(), UNO_QUERY_THROW );
1034             _out_rEvents = xEventManager->getScriptEvents( impl_getComponentIndexInParent_throw() );
1035 
1036             // the form component script API has unqualified listener names, but for normalization
1037             // purpose, we want fully qualified ones
1038             ScriptEventDescriptor* pEvents = _out_rEvents.getArray();
1039             ScriptEventDescriptor* pEventsEnd = _out_rEvents.getArray() + _out_rEvents.getLength();
1040             while ( pEvents != pEventsEnd )
1041             {
1042                 pEvents->ListenerType = lcl_getQualifiedKnownListenerName( *pEvents );
1043                 ++pEvents;
1044             }
1045         }
1046         catch( const Exception& )
1047         {
1048             DBG_UNHANDLED_EXCEPTION();
1049         }
1050     }
1051 
1052     //--------------------------------------------------------------------
impl_getCopmonentListenerTypes_nothrow(Sequence<Type> & _out_rTypes) const1053     void EventHandler::impl_getCopmonentListenerTypes_nothrow( Sequence< Type >& _out_rTypes ) const
1054     {
1055         _out_rTypes.realloc( 0 );
1056         try
1057         {
1058             // we use a set to avoid duplicates
1059             TypeBag aListeners;
1060 
1061             Reference< XIntrospection > xIntrospection( m_aContext.createComponent( "com.sun.star.beans.Introspection" ), UNO_QUERY_THROW );
1062 
1063             // --- model listeners
1064             lcl_addListenerTypesFor_throw(
1065                 m_xComponent, xIntrospection, aListeners );
1066 
1067             // --- "secondary component" (usually: "control" listeners)
1068             {
1069                 Reference< XInterface > xSecondaryComponent( impl_getSecondaryComponentForEventInspection_throw() );
1070                 lcl_addListenerTypesFor_throw( xSecondaryComponent, xIntrospection, aListeners );
1071                 ::comphelper::disposeComponent( xSecondaryComponent );
1072             }
1073 
1074             // now that they're disambiguated, copy these types into our member
1075             _out_rTypes.realloc( aListeners.size() );
1076             ::std::copy( aListeners.begin(), aListeners.end(), _out_rTypes.getArray() );
1077         }
1078         catch( const Exception& )
1079         {
1080             DBG_UNHANDLED_EXCEPTION();
1081         }
1082     }
1083 
1084     //--------------------------------------------------------------------
impl_getDialogElementScriptEvents_nothrow(Sequence<ScriptEventDescriptor> & _out_rEvents) const1085     void EventHandler::impl_getDialogElementScriptEvents_nothrow( Sequence < ScriptEventDescriptor >& _out_rEvents ) const
1086     {
1087         _out_rEvents = Sequence < ScriptEventDescriptor >();
1088         try
1089         {
1090             Reference< XScriptEventsSupplier > xEventsSupplier( m_xComponent, UNO_QUERY_THROW );
1091             Reference< XNameContainer > xEvents( xEventsSupplier->getEvents(), UNO_QUERY_THROW );
1092             Sequence< ::rtl::OUString > aEventNames( xEvents->getElementNames() );
1093 
1094             sal_Int32 nEventCount = aEventNames.getLength();
1095             _out_rEvents.realloc( nEventCount );
1096 
1097             const ::rtl::OUString* pNames = aEventNames.getConstArray();
1098             ScriptEventDescriptor* pDescs = _out_rEvents.getArray();
1099 
1100             for( sal_Int32 i = 0 ; i < nEventCount ; ++i, ++pNames, ++pDescs )
1101                 OSL_VERIFY( xEvents->getByName( *pNames ) >>= *pDescs );
1102         }
1103         catch( const Exception& )
1104         {
1105             DBG_UNHANDLED_EXCEPTION();
1106         }
1107     }
1108 
1109     //--------------------------------------------------------------------
impl_getSecondaryComponentForEventInspection_throw() const1110     Reference< XInterface > EventHandler::impl_getSecondaryComponentForEventInspection_throw( ) const
1111     {
1112         Reference< XInterface > xReturn;
1113 
1114         // if it's a form, create a form controller for the additional events
1115         Reference< XForm > xComponentAsForm( m_xComponent, UNO_QUERY );
1116         if ( xComponentAsForm.is() )
1117         {
1118             Reference< XTabControllerModel > xComponentAsTCModel( m_xComponent, UNO_QUERY_THROW );
1119             Reference< XFormController > xController(
1120                 m_aContext.createComponent( "com.sun.star.form.runtime.FormController" ), UNO_QUERY_THROW );
1121             xController->setModel( xComponentAsTCModel );
1122 
1123             xReturn = xController;
1124         }
1125         else
1126         {
1127             ::rtl::OUString sControlService;
1128             OSL_VERIFY( m_xComponent->getPropertyValue( PROPERTY_DEFAULTCONTROL ) >>= sControlService );
1129 
1130             xReturn = m_aContext.createComponent( sControlService );
1131         }
1132         return xReturn;
1133     }
1134 
1135     //--------------------------------------------------------------------
impl_getEventForName_throw(const::rtl::OUString & _rPropertyName) const1136     const EventDescription& EventHandler::impl_getEventForName_throw( const ::rtl::OUString& _rPropertyName ) const
1137     {
1138         EventMap::const_iterator pos = m_aEvents.find( _rPropertyName );
1139         if ( pos == m_aEvents.end() )
1140             throw UnknownPropertyException();
1141         return pos->second;
1142     }
1143 
1144     //--------------------------------------------------------------------
1145     namespace
1146     {
lcl_endsWith(const::rtl::OUString & _rText,const::rtl::OUString & _rCheck)1147         static bool lcl_endsWith( const ::rtl::OUString& _rText, const ::rtl::OUString& _rCheck )
1148         {
1149             sal_Int32 nTextLen = _rText.getLength();
1150             sal_Int32 nCheckLen = _rCheck.getLength();
1151             if ( nCheckLen > nTextLen )
1152                 return false;
1153 
1154             return _rText.indexOf( _rCheck ) == ( nTextLen - nCheckLen );
1155         }
1156     }
1157     //--------------------------------------------------------------------
impl_setFormComponentScriptEvent_nothrow(const ScriptEventDescriptor & _rScriptEvent)1158     void EventHandler::impl_setFormComponentScriptEvent_nothrow( const ScriptEventDescriptor& _rScriptEvent )
1159     {
1160         try
1161         {
1162             ::rtl::OUString sScriptCode( _rScriptEvent.ScriptCode );
1163             ::rtl::OUString sScriptType( _rScriptEvent.ScriptType );
1164             bool bResetScript = ( sScriptCode.getLength() == 0 );
1165 
1166             sal_Int32 nObjectIndex = impl_getComponentIndexInParent_throw();
1167             Reference< XChild > xChild( m_xComponent, UNO_QUERY_THROW );
1168             Reference< XEventAttacherManager > xEventManager( xChild->getParent(), UNO_QUERY_THROW );
1169             Sequence< ScriptEventDescriptor > aEvents( xEventManager->getScriptEvents( nObjectIndex ) );
1170 
1171             // is there already a registered script for this event?
1172             ScriptEventDescriptor* pEvent = aEvents.getArray();
1173             sal_Int32 eventCount = aEvents.getLength(), event = 0;
1174             for ( event = 0; event < eventCount; ++event, ++pEvent )
1175             {
1176                 if  (   ( pEvent->EventMethod == _rScriptEvent.EventMethod )
1177                     &&  ( lcl_endsWith( _rScriptEvent.ListenerType, pEvent->ListenerType ) )
1178                           // (strange enough, the events we get from getScriptEvents are not fully qualified)
1179                     )
1180                 {
1181                     // yes
1182                     if ( !bResetScript )
1183                     {
1184                         // set to something non-empty -> overwrite
1185                         pEvent->ScriptCode = sScriptCode;
1186                         pEvent->ScriptType = sScriptType;
1187                     }
1188                     else
1189                     {
1190                         // set to empty -> remove from sequence
1191                         ::std::copy( pEvent + 1, aEvents.getArray() + eventCount, pEvent );
1192                         aEvents.realloc( eventCount - 1 );
1193                         --eventCount;
1194                     }
1195                     break;
1196                 }
1197             }
1198             if ( ( event >= eventCount ) && !bResetScript )
1199             {
1200                 // no, did not find it -> append
1201                 aEvents.realloc( eventCount + 1 );
1202                 aEvents[ eventCount ] = _rScriptEvent;
1203             }
1204 
1205             xEventManager->revokeScriptEvents( nObjectIndex );
1206             xEventManager->registerScriptEvents( nObjectIndex, aEvents );
1207 
1208             PropertyHandlerHelper::setContextDocumentModified( m_aContext );
1209         }
1210         catch( const Exception& )
1211         {
1212             DBG_UNHANDLED_EXCEPTION();
1213         }
1214     }
1215 
1216     //--------------------------------------------------------------------
impl_setDialogElementScriptEvent_nothrow(const ScriptEventDescriptor & _rScriptEvent)1217     void EventHandler::impl_setDialogElementScriptEvent_nothrow( const ScriptEventDescriptor& _rScriptEvent )
1218     {
1219         try
1220         {
1221             ::rtl::OUString sScriptCode( _rScriptEvent.ScriptCode );
1222             bool bResetScript = ( sScriptCode.getLength() == 0 );
1223 
1224             Reference< XScriptEventsSupplier > xEventsSupplier( m_xComponent, UNO_QUERY_THROW );
1225             Reference< XNameContainer > xEvents( xEventsSupplier->getEvents(), UNO_QUERY_THROW );
1226 
1227             ::rtl::OUStringBuffer aCompleteName;
1228             aCompleteName.append( _rScriptEvent.ListenerType );
1229             aCompleteName.appendAscii( "::" );
1230             aCompleteName.append( _rScriptEvent.EventMethod );
1231             ::rtl::OUString sCompleteName( aCompleteName.makeStringAndClear() );
1232 
1233             bool bExists = xEvents->hasByName( sCompleteName );
1234 
1235             if ( bResetScript )
1236             {
1237                 if ( bExists )
1238                     xEvents->removeByName( sCompleteName );
1239             }
1240             else
1241             {
1242                 Any aNewValue; aNewValue <<= _rScriptEvent;
1243 
1244                 if ( bExists )
1245                     xEvents->replaceByName( sCompleteName, aNewValue );
1246                 else
1247                     xEvents->insertByName( sCompleteName, aNewValue );
1248             }
1249         }
1250         catch( const Exception& )
1251         {
1252             DBG_UNHANDLED_EXCEPTION();
1253         }
1254     }
1255 
1256     //--------------------------------------------------------------------
impl_filterMethod_nothrow(const EventDescription & _rEvent) const1257     bool EventHandler::impl_filterMethod_nothrow( const EventDescription& _rEvent ) const
1258     {
1259         // some (control-triggered) events do not make sense for certain grid control columns. However,
1260         // our mechnism to retrieve control-triggered events does not know about this, so we do some
1261         // late filtering here.
1262         switch ( m_nGridColumnType )
1263         {
1264         case FormComponentType::COMBOBOX:
1265             if ( UID_BRWEVT_ACTIONPERFORMED == _rEvent.sUniqueBrowseId )
1266                 return false;
1267             break;
1268         case FormComponentType::LISTBOX:
1269             if  (   ( UID_BRWEVT_CHANGED == _rEvent.sUniqueBrowseId )
1270                 ||  ( UID_BRWEVT_ACTIONPERFORMED == _rEvent.sUniqueBrowseId )
1271                 )
1272                 return false;
1273             break;
1274         }
1275 
1276         return true;
1277     }
1278 
1279 //........................................................................
1280 } // namespace pcr
1281 //........................................................................
1282 
1283