xref: /trunk/main/extensions/source/propctrlr/eventhandler.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 #include <iterator>
78 
79 //------------------------------------------------------------------------
createRegistryInfo_EventHandler()80 extern "C" void SAL_CALL createRegistryInfo_EventHandler()
81 {
82     ::pcr::OAutoRegistration< ::pcr::EventHandler > aAutoRegistration;
83 }
84 
85 //........................................................................
86 namespace pcr
87 {
88 //........................................................................
89 
90     /** === begin UNO using === **/
91     using ::com::sun::star::uno::Reference;
92     using ::com::sun::star::uno::XComponentContext;
93     using ::com::sun::star::beans::XPropertySet;
94     using ::com::sun::star::uno::Any;
95     using ::com::sun::star::uno::TypeClass_STRING;
96     using ::com::sun::star::uno::Type;
97     using ::com::sun::star::beans::XPropertyChangeListener;
98     using ::com::sun::star::beans::Property;
99     using ::com::sun::star::beans::PropertyState;
100     using ::com::sun::star::beans::PropertyState_DIRECT_VALUE;
101     using ::com::sun::star::uno::Sequence;
102     using ::com::sun::star::script::ScriptEventDescriptor;
103     using ::com::sun::star::script::XScriptEventsSupplier;
104     using ::com::sun::star::lang::NullPointerException;
105     using ::com::sun::star::uno::Exception;
106     using ::com::sun::star::container::XChild;
107     using ::com::sun::star::container::XIndexAccess;
108     using ::com::sun::star::script::XEventAttacherManager;
109     using ::com::sun::star::uno::UNO_QUERY;
110     using ::com::sun::star::uno::UNO_QUERY_THROW;
111     using ::com::sun::star::uno::XInterface;
112     using ::com::sun::star::beans::XIntrospection;
113     using ::com::sun::star::beans::XIntrospectionAccess;
114     using ::com::sun::star::container::XNameContainer;
115     using ::com::sun::star::awt::XTabControllerModel;
116     using ::com::sun::star::form::XForm;
117     using ::com::sun::star::form::runtime::XFormController;
118     using ::com::sun::star::beans::UnknownPropertyException;
119     using ::com::sun::star::uno::makeAny;
120     using ::com::sun::star::container::NoSuchElementException;
121     using ::com::sun::star::beans::XPropertySetInfo;
122     using ::com::sun::star::container::XNameReplace;
123     using ::com::sun::star::lang::IllegalArgumentException;
124     using ::com::sun::star::lang::WrappedTargetException;
125     using ::com::sun::star::uno::RuntimeException;
126     using ::com::sun::star::beans::PropertyValue;
127     using ::com::sun::star::inspection::LineDescriptor;
128     using ::com::sun::star::inspection::XPropertyControlFactory;
129     using ::com::sun::star::inspection::InteractiveSelectionResult;
130     using ::com::sun::star::inspection::InteractiveSelectionResult_Cancelled;
131     using ::com::sun::star::inspection::InteractiveSelectionResult_Success;
132     using ::com::sun::star::inspection::XObjectInspectorUI;
133     using ::com::sun::star::util::XModifiable;
134     using ::com::sun::star::beans::PropertyChangeEvent;
135     using ::com::sun::star::frame::XFrame;
136     using ::com::sun::star::frame::XModel;
137     using ::com::sun::star::frame::XController;
138     using ::com::sun::star::uno::UNO_SET_THROW;
139     using com::sun::star::uri::UriReferenceFactory;
140     using com::sun::star::uri::XUriReferenceFactory;
141     using com::sun::star::uri::XVndSunStarScriptUrlReference;
142     using ::com::sun::star::lang::XEventListener;
143     /** === end UNO using === **/
144     namespace PropertyControlType = ::com::sun::star::inspection::PropertyControlType;
145     namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
146     namespace FormComponentType = ::com::sun::star::form::FormComponentType;
147 
148     //====================================================================
149     //= EventDescription
150     //====================================================================
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)151     EventDescription::EventDescription( EventId _nId, const sal_Char* _pListenerNamespaceAscii, const sal_Char* _pListenerClassAsciiName,
152             const sal_Char* _pListenerMethodAsciiName, sal_uInt16 _nDisplayNameResId, const rtl::OString& _sHelpId, const rtl::OString& _sUniqueBrowseId )
153         :sDisplayName( String( PcrRes( _nDisplayNameResId ) ) )
154         ,sListenerMethodName( ::rtl::OUString::createFromAscii( _pListenerMethodAsciiName ) )
155         ,sHelpId( _sHelpId )
156         ,sUniqueBrowseId( _sUniqueBrowseId )
157         ,nId( _nId )
158     {
159         ::rtl::OUStringBuffer aQualifiedListenerClass;
160         aQualifiedListenerClass.appendAscii( "com.sun.star." );
161         aQualifiedListenerClass.appendAscii( _pListenerNamespaceAscii );
162         aQualifiedListenerClass.appendAscii( "." );
163         aQualifiedListenerClass.appendAscii( _pListenerClassAsciiName );
164         sListenerClassName = aQualifiedListenerClass.makeStringAndClear();
165     }
166 
167     //========================================================================
168     //= helper
169     //========================================================================
170     namespace
171     {
172         //....................................................................
173         #define DESCRIBE_EVENT( asciinamespace, asciilistener, asciimethod, id_postfix ) \
174             s_aKnownEvents.insert( EventMap::value_type( \
175                 ::rtl::OUString::createFromAscii( asciimethod ), \
176                 EventDescription( ++nEventId, asciinamespace, asciilistener, asciimethod, RID_STR_EVT_##id_postfix, HID_EVT_##id_postfix, UID_BRWEVT_##id_postfix ) ) )
177 
178         //....................................................................
lcl_getEventDescriptionForMethod(const::rtl::OUString & _rMethodName,EventDescription & _out_rDescription)179         bool lcl_getEventDescriptionForMethod( const ::rtl::OUString& _rMethodName, EventDescription& _out_rDescription )
180         {
181             static EventMap s_aKnownEvents;
182             if ( s_aKnownEvents.empty() )
183             {
184                 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
185                 if ( s_aKnownEvents.empty() )
186                 {
187                     static sal_Int32 nEventId = 0;
188 
189                     DESCRIBE_EVENT( "form", "XApproveActionListener",       "approveAction",            APPROVEACTIONPERFORMED );
190                     DESCRIBE_EVENT( "awt",  "XActionListener",              "actionPerformed",          ACTIONPERFORMED );
191                     DESCRIBE_EVENT( "form", "XChangeListener",              "changed",                  CHANGED );
192                     DESCRIBE_EVENT( "awt",  "XTextListener",                "textChanged",              TEXTCHANGED );
193                     DESCRIBE_EVENT( "awt",  "XItemListener",                "itemStateChanged",         ITEMSTATECHANGED );
194                     DESCRIBE_EVENT( "awt",  "XFocusListener",               "focusGained",              FOCUSGAINED );
195                     DESCRIBE_EVENT( "awt",  "XFocusListener",               "focusLost",                FOCUSLOST );
196                     DESCRIBE_EVENT( "awt",  "XKeyListener",                 "keyPressed",               KEYTYPED );
197                     DESCRIBE_EVENT( "awt",  "XKeyListener",                 "keyReleased",              KEYUP );
198                     DESCRIBE_EVENT( "awt",  "XMouseListener",               "mouseEntered",             MOUSEENTERED );
199                     DESCRIBE_EVENT( "awt",  "XMouseMotionListener",         "mouseDragged",             MOUSEDRAGGED );
200                     DESCRIBE_EVENT( "awt",  "XMouseMotionListener",         "mouseMoved",               MOUSEMOVED );
201                     DESCRIBE_EVENT( "awt",  "XMouseListener",               "mousePressed",             MOUSEPRESSED );
202                     DESCRIBE_EVENT( "awt",  "XMouseListener",               "mouseReleased",            MOUSERELEASED );
203                     DESCRIBE_EVENT( "awt",  "XMouseListener",               "mouseExited",              MOUSEEXITED );
204                     DESCRIBE_EVENT( "form", "XResetListener",               "approveReset",             APPROVERESETTED );
205                     DESCRIBE_EVENT( "form", "XResetListener",               "resetted",                 RESETTED );
206                     DESCRIBE_EVENT( "form", "XSubmitListener",              "approveSubmit",            SUBMITTED );
207                     DESCRIBE_EVENT( "form", "XUpdateListener",              "approveUpdate",            BEFOREUPDATE );
208                     DESCRIBE_EVENT( "form", "XUpdateListener",              "updated",                  AFTERUPDATE );
209                     DESCRIBE_EVENT( "form", "XLoadListener",                "loaded",                   LOADED );
210                     DESCRIBE_EVENT( "form", "XLoadListener",                "reloading",                RELOADING );
211                     DESCRIBE_EVENT( "form", "XLoadListener",                "reloaded",                 RELOADED );
212                     DESCRIBE_EVENT( "form", "XLoadListener",                "unloading",                UNLOADING );
213                     DESCRIBE_EVENT( "form", "XLoadListener",                "unloaded",                 UNLOADED );
214                     DESCRIBE_EVENT( "form", "XConfirmDeleteListener",       "confirmDelete",            CONFIRMDELETE );
215                     DESCRIBE_EVENT( "sdb",  "XRowSetApproveListener",       "approveRowChange",         APPROVEROWCHANGE );
216                     DESCRIBE_EVENT( "sdbc", "XRowSetListener",              "rowChanged",               ROWCHANGE );
217                     DESCRIBE_EVENT( "sdb",  "XRowSetApproveListener",       "approveCursorMove",        POSITIONING );
218                     DESCRIBE_EVENT( "sdbc", "XRowSetListener",              "cursorMoved",              POSITIONED );
219                     DESCRIBE_EVENT( "form", "XDatabaseParameterListener",   "approveParameter",         APPROVEPARAMETER );
220                     DESCRIBE_EVENT( "sdb",  "XSQLErrorListener",            "errorOccured",             ERROROCCURED );
221                     DESCRIBE_EVENT( "awt",  "XAdjustmentListener",          "adjustmentValueChanged",   ADJUSTMENTVALUECHANGED );
222                 }
223             }
224 
225             EventMap::const_iterator pos = s_aKnownEvents.find( _rMethodName );
226             if ( pos == s_aKnownEvents.end() )
227                 return false;
228 
229             _out_rDescription = pos->second;
230             return true;
231         }
232 
233         //....................................................................
lcl_getEventPropertyName(const::rtl::OUString & _rListenerClassName,const::rtl::OUString & _rMethodName)234         ::rtl::OUString lcl_getEventPropertyName( const ::rtl::OUString& _rListenerClassName, const ::rtl::OUString& _rMethodName )
235         {
236             ::rtl::OUStringBuffer aPropertyName;
237             aPropertyName.append( _rListenerClassName );
238             aPropertyName.append( (sal_Unicode)';' );
239             aPropertyName.append( _rMethodName.getStr() );
240             return aPropertyName.makeStringAndClear();
241         }
242 
243         //................................................................
lcl_getAssignedScriptEvent(const EventDescription & _rEvent,const Sequence<ScriptEventDescriptor> & _rAllAssignedMacros)244         ScriptEventDescriptor lcl_getAssignedScriptEvent( const EventDescription& _rEvent, const Sequence< ScriptEventDescriptor >& _rAllAssignedMacros )
245         {
246             ScriptEventDescriptor aScriptEvent;
247             // for the case there is actually no event assigned, initialize at least ListenerType and MethodName,
248             //  so this ScriptEventDescriptor properly describes the given event
249             aScriptEvent.ListenerType = _rEvent.sListenerClassName;
250             aScriptEvent.EventMethod = _rEvent.sListenerMethodName;
251 
252             const ScriptEventDescriptor* pAssignedEvent = _rAllAssignedMacros.getConstArray();
253             sal_Int32 assignedEventCount( _rAllAssignedMacros.getLength() );
254             for ( sal_Int32 assignedEvent = 0; assignedEvent < assignedEventCount; ++assignedEvent, ++pAssignedEvent )
255             {
256                 if  (   ( pAssignedEvent->ListenerType != _rEvent.sListenerClassName )
257                     ||  ( pAssignedEvent->EventMethod != _rEvent.sListenerMethodName )
258                     )
259                     continue;
260 
261                 if  (   ( pAssignedEvent->ScriptCode.getLength() == 0 )
262                     ||  ( pAssignedEvent->ScriptType.getLength() == 0 )
263                     )
264                 {
265                     DBG_ERROR( "lcl_getAssignedScriptEvent: me thinks this should not happen!" );
266                     continue;
267                 }
268 
269                 aScriptEvent = *pAssignedEvent;
270 
271                 if ( !aScriptEvent.ScriptType.equalsAscii( "StarBasic" ) )
272                     continue;
273 
274                 // this is an old-style macro specification:
275                 // [document|application]:Library.Module.Function
276                 // we need to translate this to the new-style macro specification
277                 // vnd.sun.star.script:Library.Module.Function?language=Basic&location=[document|application]
278 
279                 sal_Int32 nPrefixLen = aScriptEvent.ScriptCode.indexOf( ':' );
280                 OSL_ENSURE( nPrefixLen > 0, "lcl_getAssignedScriptEvent: illegal location!" );
281                 ::rtl::OUString sLocation = aScriptEvent.ScriptCode.copy( 0, nPrefixLen );
282                 ::rtl::OUString sMacroPath = aScriptEvent.ScriptCode.copy( nPrefixLen + 1 );
283 
284                 ::rtl::OUStringBuffer aNewStyleSpec;
285                 aNewStyleSpec.appendAscii( "vnd.sun.star.script:" );
286                 aNewStyleSpec.append     ( sMacroPath );
287                 aNewStyleSpec.appendAscii( "?language=Basic&location=" );
288                 aNewStyleSpec.append     ( sLocation );
289 
290                 aScriptEvent.ScriptCode = aNewStyleSpec.makeStringAndClear();
291 
292                 // also, this new-style spec requires the script code to be "Script" instead of "StarBasic"
293                 aScriptEvent.ScriptType = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Script" ) );
294             }
295             return aScriptEvent;
296         }
297 
298         //................................................................
lcl_getQualifiedKnownListenerName(const ScriptEventDescriptor & _rFormComponentEventDescriptor)299         ::rtl::OUString lcl_getQualifiedKnownListenerName( const ScriptEventDescriptor& _rFormComponentEventDescriptor )
300         {
301             EventDescription aKnownEvent;
302             if ( lcl_getEventDescriptionForMethod( _rFormComponentEventDescriptor.EventMethod, aKnownEvent ) )
303                 return aKnownEvent.sListenerClassName;
304             DBG_ERROR( "lcl_getQualifiedKnownListenerName: unknown method name!" );
305                 // somebody assigned an script to a form component event which we don't know
306                 // Speaking strictly, this is not really an error - it is possible to do
307                 // this programmatically -, but it should rarely happen, since it's not possible
308                 // via UI
309             return _rFormComponentEventDescriptor.ListenerType;
310         }
311 
312         //................................................................
313         typedef ::std::set< Type, TypeLessByName > TypeBag;
314 
315         //................................................................
lcl_addListenerTypesFor_throw(const Reference<XInterface> & _rxComponent,const Reference<XIntrospection> & _rxIntrospection,TypeBag & _out_rTypes)316         void lcl_addListenerTypesFor_throw( const Reference< XInterface >& _rxComponent,
317             const Reference< XIntrospection >& _rxIntrospection, TypeBag& _out_rTypes )
318         {
319             if ( !_rxComponent.is() )
320                 return;
321             OSL_PRECOND( _rxIntrospection.is(), "lcl_addListenerTypesFor_throw: this will crash!" );
322 
323             Reference< XIntrospectionAccess > xIntrospectionAccess(
324                 _rxIntrospection->inspect( makeAny( _rxComponent ) ), UNO_QUERY_THROW );
325 
326             Sequence< Type > aListeners( xIntrospectionAccess->getSupportedListeners() );
327 
328             ::std::copy( aListeners.getConstArray(), aListeners.getConstArray() + aListeners.getLength(),
329                 ::std::insert_iterator< TypeBag >( _out_rTypes, _out_rTypes.begin() ) );
330         }
331 
332         //................................................................
operator ==(const ScriptEventDescriptor _lhs,const ScriptEventDescriptor _rhs)333         bool operator ==( const ScriptEventDescriptor _lhs, const ScriptEventDescriptor _rhs )
334         {
335             return  (   ( _lhs.ListenerType         == _rhs.ListenerType        )
336                     &&  ( _lhs.EventMethod          == _rhs.EventMethod         )
337                     &&  ( _lhs.AddListenerParam     == _rhs.AddListenerParam    )
338                     &&  ( _lhs.ScriptType           == _rhs.ScriptType          )
339                     &&  ( _lhs.ScriptCode           == _rhs.ScriptCode          )
340                     );
341         }
342     }
343 
344     //====================================================================
345     //= EventHandler
346     //====================================================================
347     typedef ::cppu::WeakImplHelper1 <   ::com::sun::star::container::XNameReplace
348                                     >   EventHolder_Base;
349     /** a UNO component holding assigned event descriptions, for use with a SvxMacroAssignDlg
350     */
351     class EventHolder : public EventHolder_Base
352     {
353     private:
354         typedef ::std::hash_map< ::rtl::OUString, ScriptEventDescriptor, ::rtl::OUStringHash >  EventMap;
355         typedef ::std::map< EventId, EventMap::iterator >                                       EventMapIndexAccess;
356 
357         EventMap            m_aEventNameAccess;
358         EventMapIndexAccess m_aEventIndexAccess;
359 
360     public:
361         EventHolder( );
362 
363         void addEvent( EventId _nId, const ::rtl::OUString& _rEventName, const ScriptEventDescriptor& _rScriptEvent );
364 
365         /** effectively the same as getByName, but instead of converting the ScriptEventDescriptor to the weird
366             format used by the macro assignment dialog, it is returned directly
367         */
368         ScriptEventDescriptor getNormalizedDescriptorByName( const ::rtl::OUString& _rEventName ) const;
369 
370         // XNameReplace
371         virtual void SAL_CALL replaceByName( const ::rtl::OUString& _rName, const Any& aElement );
372         virtual Any SAL_CALL getByName( const ::rtl::OUString& _rName );
373         virtual Sequence< ::rtl::OUString > SAL_CALL getElementNames(  );
374         virtual ::sal_Bool SAL_CALL hasByName( const ::rtl::OUString& _rName );
375         virtual Type SAL_CALL getElementType(  );
376         virtual ::sal_Bool SAL_CALL hasElements(  );
377 
378     protected:
379         ~EventHolder( );
380 
381     private:
382         ScriptEventDescriptor impl_getDescriptor_throw( const ::rtl::OUString& _rEventName ) const;
383     };
384 
DBG_NAME(EventHolder)385     DBG_NAME( EventHolder )
386     //------------------------------------------------------------------------
387     EventHolder::EventHolder()
388     {
389         DBG_CTOR( EventHolder, NULL );
390     }
391 
392     //------------------------------------------------------------------------
~EventHolder()393     EventHolder::~EventHolder()
394     {
395         m_aEventNameAccess.clear();
396         m_aEventIndexAccess.clear();
397         DBG_DTOR( EventHolder, NULL );
398     }
399 
400     //------------------------------------------------------------------------
addEvent(EventId _nId,const::rtl::OUString & _rEventName,const ScriptEventDescriptor & _rScriptEvent)401     void EventHolder::addEvent( EventId _nId, const ::rtl::OUString& _rEventName, const ScriptEventDescriptor& _rScriptEvent )
402     {
403         ::std::pair< EventMap::iterator, bool > insertionResult =
404             m_aEventNameAccess.insert( EventMap::value_type( _rEventName, _rScriptEvent ) );
405         OSL_ENSURE( insertionResult.second, "EventHolder::addEvent: there already was a MacroURL for this event!" );
406         m_aEventIndexAccess[ _nId ] = insertionResult.first;
407     }
408 
409     //------------------------------------------------------------------------
getNormalizedDescriptorByName(const::rtl::OUString & _rEventName) const410     ScriptEventDescriptor EventHolder::getNormalizedDescriptorByName( const ::rtl::OUString& _rEventName ) const
411     {
412         return impl_getDescriptor_throw( _rEventName );
413     }
414 
415     //------------------------------------------------------------------------
impl_getDescriptor_throw(const::rtl::OUString & _rEventName) const416     ScriptEventDescriptor EventHolder::impl_getDescriptor_throw( const ::rtl::OUString& _rEventName ) const
417     {
418         EventMap::const_iterator pos = m_aEventNameAccess.find( _rEventName );
419         if ( pos == m_aEventNameAccess.end() )
420             throw NoSuchElementException( ::rtl::OUString(), *const_cast< EventHolder* >( this ) );
421         return pos->second;
422     }
423 
424     //------------------------------------------------------------------------
replaceByName(const::rtl::OUString & _rName,const Any & _rElement)425     void SAL_CALL EventHolder::replaceByName( const ::rtl::OUString& _rName, const Any& _rElement )
426     {
427         EventMap::iterator pos = m_aEventNameAccess.find( _rName );
428         if ( pos == m_aEventNameAccess.end() )
429             throw NoSuchElementException( ::rtl::OUString(), *this );
430 
431         Sequence< PropertyValue > aScriptDescriptor;
432         OSL_VERIFY( _rElement >>= aScriptDescriptor );
433 
434         ::comphelper::NamedValueCollection aExtractor( aScriptDescriptor );
435 
436         pos->second.ScriptType = aExtractor.getOrDefault( "EventType", ::rtl::OUString() );
437         pos->second.ScriptCode = aExtractor.getOrDefault( "Script", ::rtl::OUString() );
438     }
439 
440     //------------------------------------------------------------------------
getByName(const::rtl::OUString & _rName)441     Any SAL_CALL EventHolder::getByName( const ::rtl::OUString& _rName )
442     {
443         ScriptEventDescriptor aDescriptor( impl_getDescriptor_throw( _rName ) );
444 
445         Any aRet;
446         Sequence< PropertyValue > aScriptDescriptor( 2 );
447         aScriptDescriptor[0].Name = ::rtl::OUString::createFromAscii( "EventType" );
448         aScriptDescriptor[0].Value <<= aDescriptor.ScriptType;
449         aScriptDescriptor[1].Name = ::rtl::OUString::createFromAscii( "Script" );
450         aScriptDescriptor[1].Value <<= aDescriptor.ScriptCode;
451 
452         return makeAny( aScriptDescriptor );
453     }
454 
455     //------------------------------------------------------------------------
getElementNames()456     Sequence< ::rtl::OUString > SAL_CALL EventHolder::getElementNames(  )
457     {
458         Sequence< ::rtl::OUString > aReturn( m_aEventIndexAccess.size() );
459         ::rtl::OUString* pReturn = aReturn.getArray();
460 
461         // SvxMacroAssignDlg has a weird API: It expects a XNameReplace, means a container whose
462         // main access method is by name. In it's UI, it shows the possible events in exactly the
463         // order in which XNameAccess::getElementNames returns them.
464         // However, SvxMacroAssignDlg *also* takes an index for the initial selection, which is
465         // relative to the sequence returned by XNameAccess::getElementNames.
466         // This is IMO weird, since it mixes index access with name access, which decreases efficiency
467         // of the implementation.
468         // Well, it means we're forced to return the events in getElementNames in exactly the same as they
469         // appear in the property browser UI.
470         for (   EventMapIndexAccess::const_iterator loop = m_aEventIndexAccess.begin();
471                 loop != m_aEventIndexAccess.end();
472                 ++loop, ++pReturn
473             )
474             *pReturn = loop->second->first;
475         return aReturn;
476     }
477 
478     //------------------------------------------------------------------------
hasByName(const::rtl::OUString & _rName)479     sal_Bool SAL_CALL EventHolder::hasByName( const ::rtl::OUString& _rName )
480     {
481         EventMap::const_iterator pos = m_aEventNameAccess.find( _rName );
482         return pos != m_aEventNameAccess.end();
483     }
484 
485     //------------------------------------------------------------------------
getElementType()486     Type SAL_CALL EventHolder::getElementType(  )
487     {
488         return ::getCppuType( static_cast< Sequence< PropertyValue >* >( NULL ) );
489     }
490 
491     //------------------------------------------------------------------------
hasElements()492     sal_Bool SAL_CALL EventHolder::hasElements(  )
493     {
494         return !m_aEventNameAccess.empty();
495     }
496 
497 
498     //====================================================================
499     //= EventHandler
500     //====================================================================
DBG_NAME(EventHandler)501     DBG_NAME( EventHandler )
502     //--------------------------------------------------------------------
503     EventHandler::EventHandler( const Reference< XComponentContext >& _rxContext )
504         :EventHandler_Base( m_aMutex )
505         ,m_aContext( _rxContext )
506         ,m_aPropertyListeners( m_aMutex )
507         ,m_bEventsMapInitialized( false )
508         ,m_bIsDialogElement( false )
509         ,m_nGridColumnType( -1 )
510     {
511         DBG_CTOR( EventHandler, NULL );
512     }
513 
514     //--------------------------------------------------------------------
~EventHandler()515     EventHandler::~EventHandler()
516     {
517         DBG_DTOR( EventHandler, NULL );
518     }
519 
520     //--------------------------------------------------------------------
getImplementationName()521     ::rtl::OUString SAL_CALL EventHandler::getImplementationName(  )
522     {
523         return getImplementationName_static();
524     }
525 
526     //--------------------------------------------------------------------
supportsService(const::rtl::OUString & ServiceName)527     ::sal_Bool SAL_CALL EventHandler::supportsService( const ::rtl::OUString& ServiceName )
528     {
529         StlSyntaxSequence< ::rtl::OUString > aAllServices( getSupportedServiceNames() );
530         return ::std::find( aAllServices.begin(), aAllServices.end(), ServiceName ) != aAllServices.end();
531     }
532 
533     //--------------------------------------------------------------------
getSupportedServiceNames()534     Sequence< ::rtl::OUString > SAL_CALL EventHandler::getSupportedServiceNames(  )
535     {
536         return getSupportedServiceNames_static();
537     }
538 
539     //--------------------------------------------------------------------
getImplementationName_static()540     ::rtl::OUString SAL_CALL EventHandler::getImplementationName_static(  )
541     {
542         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.extensions.EventHandler" ) );
543     }
544 
545     //--------------------------------------------------------------------
getSupportedServiceNames_static()546     Sequence< ::rtl::OUString > SAL_CALL EventHandler::getSupportedServiceNames_static(  )
547     {
548         Sequence< ::rtl::OUString > aSupported( 1 );
549         aSupported[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.inspection.EventHandler" ) );
550         return aSupported;
551     }
552 
553     //--------------------------------------------------------------------
Create(const Reference<XComponentContext> & _rxContext)554     Reference< XInterface > SAL_CALL EventHandler::Create( const Reference< XComponentContext >& _rxContext )
555     {
556         return *( new EventHandler( _rxContext ) );
557     }
558 
559     //--------------------------------------------------------------------
inspect(const Reference<XInterface> & _rxIntrospectee)560     void SAL_CALL EventHandler::inspect( const Reference< XInterface >& _rxIntrospectee )
561     {
562         ::osl::MutexGuard aGuard( m_aMutex );
563 
564         if ( !_rxIntrospectee.is() )
565             throw NullPointerException();
566 
567         m_xComponent = Reference< XPropertySet >( _rxIntrospectee, UNO_QUERY_THROW );
568 
569         m_bEventsMapInitialized = false;
570         EventMap aEmpty;
571         m_aEvents.swap( aEmpty );
572 
573         m_bIsDialogElement = false;
574         m_nGridColumnType = -1;
575         try
576         {
577             Reference< XPropertySetInfo > xPSI( m_xComponent->getPropertySetInfo() );
578             m_bIsDialogElement = xPSI.is()
579                               && xPSI->hasPropertyByName( PROPERTY_WIDTH )
580                               && xPSI->hasPropertyByName( PROPERTY_HEIGHT )
581                               && xPSI->hasPropertyByName( PROPERTY_POSITIONX )
582                               && xPSI->hasPropertyByName( PROPERTY_POSITIONY );
583 
584             Reference< XChild > xAsChild( _rxIntrospectee, UNO_QUERY );
585             if ( xAsChild.is() && !Reference< XForm >( _rxIntrospectee, UNO_QUERY ).is() )
586             {
587                 if ( FormComponentType::GRIDCONTROL == classifyComponent( xAsChild->getParent() ) )
588                 {
589                     m_nGridColumnType = classifyComponent( _rxIntrospectee );
590                 }
591             }
592         }
593         catch( const Exception& )
594         {
595             DBG_UNHANDLED_EXCEPTION();
596         }
597     }
598 
599     //--------------------------------------------------------------------
getPropertyValue(const::rtl::OUString & _rPropertyName)600     Any SAL_CALL EventHandler::getPropertyValue( const ::rtl::OUString& _rPropertyName )
601     {
602         ::osl::MutexGuard aGuard( m_aMutex );
603 
604         const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName );
605 
606         Sequence< ScriptEventDescriptor > aEvents;
607         impl_getComponentScriptEvents_nothrow( aEvents );
608 
609         sal_Int32 nEventCount = aEvents.getLength();
610         const ScriptEventDescriptor* pEvents = aEvents.getConstArray();
611 
612         ScriptEventDescriptor aPropertyValue;
613         for ( sal_Int32 event = 0; event < nEventCount; ++event, ++pEvents )
614         {
615             if  (   rEvent.sListenerClassName == pEvents->ListenerType
616                 &&  rEvent.sListenerMethodName == pEvents->EventMethod
617                 )
618             {
619                 aPropertyValue = *pEvents;
620                 break;
621             }
622         }
623 
624         return makeAny( aPropertyValue );
625     }
626 
627     //--------------------------------------------------------------------
setPropertyValue(const::rtl::OUString & _rPropertyName,const Any & _rValue)628     void SAL_CALL EventHandler::setPropertyValue( const ::rtl::OUString& _rPropertyName, const Any& _rValue )
629     {
630         ::osl::MutexGuard aGuard( m_aMutex );
631 
632         const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName );
633 
634         ScriptEventDescriptor aNewScriptEvent;
635         OSL_VERIFY( _rValue >>= aNewScriptEvent );
636 
637         ScriptEventDescriptor aOldScriptEvent;
638         OSL_VERIFY( getPropertyValue( _rPropertyName ) >>= aOldScriptEvent );
639         if ( aOldScriptEvent == aNewScriptEvent )
640             return;
641 
642         if ( m_bIsDialogElement )
643             impl_setDialogElementScriptEvent_nothrow( aNewScriptEvent );
644         else
645             impl_setFormComponentScriptEvent_nothrow( aNewScriptEvent );
646 
647         Reference< XModifiable > xDoc( m_aContext.getContextValueByAsciiName( "ContextDocument" ), UNO_QUERY );
648         if ( xDoc.is() )
649             xDoc->setModified( sal_True );
650 
651         PropertyChangeEvent aEvent;
652         aEvent.Source = m_xComponent;
653         aEvent.PropertyHandle = rEvent.nId;
654         aEvent.PropertyName = _rPropertyName;
655         aEvent.OldValue <<= aOldScriptEvent;
656         aEvent.NewValue <<= aNewScriptEvent;
657         m_aPropertyListeners.notify( aEvent, &XPropertyChangeListener::propertyChange );
658     }
659 
660     //--------------------------------------------------------------------
convertToPropertyValue(const::rtl::OUString & _rPropertyName,const Any & _rControlValue)661     Any SAL_CALL EventHandler::convertToPropertyValue( const ::rtl::OUString& _rPropertyName, const Any& _rControlValue )
662     {
663         ::osl::MutexGuard aGuard( m_aMutex );
664 
665         ::rtl::OUString sNewScriptCode;
666         OSL_VERIFY( _rControlValue >>= sNewScriptCode );
667 
668         Sequence< ScriptEventDescriptor > aAllAssignedEvents;
669         impl_getComponentScriptEvents_nothrow( aAllAssignedEvents );
670 
671         const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName );
672         ScriptEventDescriptor aAssignedScript = lcl_getAssignedScriptEvent( rEvent, aAllAssignedEvents );
673 
674         OSL_ENSURE( !sNewScriptCode.getLength(), "EventHandler::convertToPropertyValue: cannot convert a non-empty display name!" );
675         // Usually, there is no possibility for the user to change the content of an event binding directly in the
676         // input field, this instead is done with the macro assignment dialog.
677         // The only exception is the user pressing "DEL" while the control has the focus, in this case, we reset the
678         // control content to an empty string. So this is the only scenario where this method is allowed to be called.
679 
680         // Strictly, we would be able to convert the display value to a property value,
681         // using the "name (location, language)" format we used in convertToControlValue. However,
682         // there is no need for this code ...
683 
684         aAssignedScript.ScriptCode = sNewScriptCode;
685         return makeAny( aAssignedScript );
686     }
687 
688     //--------------------------------------------------------------------
convertToControlValue(const::rtl::OUString &,const Any & _rPropertyValue,const Type & _rControlValueType)689     Any SAL_CALL EventHandler::convertToControlValue( const ::rtl::OUString& /*_rPropertyName*/, const Any& _rPropertyValue, const Type& _rControlValueType )
690     {
691         ::osl::MutexGuard aGuard( m_aMutex );
692 
693         ScriptEventDescriptor aScriptEvent;
694         OSL_VERIFY( _rPropertyValue >>= aScriptEvent );
695 
696         OSL_ENSURE( _rControlValueType.getTypeClass() == TypeClass_STRING,
697             "EventHandler::convertToControlValue: unexpected ControlValue type class!" );
698         (void)_rControlValueType;
699 
700         ::rtl::OUString sScript( aScriptEvent.ScriptCode );
701         if ( sScript.getLength() )
702         {
703             // format is: "name (location, language)"
704             try
705             {
706                 // parse
707                 Reference< XUriReferenceFactory > xUriRefFac = UriReferenceFactory::create( m_aContext.getUNOContext() );
708                 Reference< XVndSunStarScriptUrlReference > xScriptUri( xUriRefFac->parse( sScript ), UNO_QUERY_THROW );
709 
710                 ::rtl::OUStringBuffer aComposeBuffer;
711 
712                 // name
713                 aComposeBuffer.append( xScriptUri->getName() );
714 
715                 // location
716                 const ::rtl::OUString sLocationParamName( RTL_CONSTASCII_USTRINGPARAM( "location" ) );
717                 const ::rtl::OUString sLocation = xScriptUri->getParameter( sLocationParamName );
718                 const ::rtl::OUString sLangParamName( RTL_CONSTASCII_USTRINGPARAM( "language" ) );
719                 const ::rtl::OUString sLanguage = xScriptUri->getParameter( sLangParamName );
720 
721                 if ( sLocation.getLength() || sLanguage.getLength() )
722                 {
723                     aComposeBuffer.appendAscii( " (" );
724 
725                     // location
726                     OSL_ENSURE( sLocation.getLength(), "EventHandler::convertToControlValue: unexpected: no location!" );
727                     if ( sLocation.getLength() )
728                     {
729                         aComposeBuffer.append( sLocation );
730                         aComposeBuffer.appendAscii( ", " );
731                     }
732 
733                     // language
734                     if ( sLanguage.getLength() )
735                     {
736                         aComposeBuffer.append( sLanguage );
737                     }
738 
739                     aComposeBuffer.append( sal_Unicode( ')' ) );
740                 }
741 
742                 sScript = aComposeBuffer.makeStringAndClear();
743             }
744             catch( const Exception& )
745             {
746                 DBG_UNHANDLED_EXCEPTION();
747             }
748         }
749 
750         return makeAny( sScript );
751     }
752 
753     //--------------------------------------------------------------------
getPropertyState(const::rtl::OUString &)754     PropertyState SAL_CALL EventHandler::getPropertyState( const ::rtl::OUString& /*_rPropertyName*/ )
755     {
756         return PropertyState_DIRECT_VALUE;
757     }
758 
759     //--------------------------------------------------------------------
addPropertyChangeListener(const Reference<XPropertyChangeListener> & _rxListener)760     void SAL_CALL EventHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
761     {
762         ::osl::MutexGuard aGuard( m_aMutex );
763         if ( !_rxListener.is() )
764             throw NullPointerException();
765         m_aPropertyListeners.addListener( _rxListener );
766     }
767 
768     //--------------------------------------------------------------------
removePropertyChangeListener(const Reference<XPropertyChangeListener> & _rxListener)769     void SAL_CALL EventHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener )
770     {
771         ::osl::MutexGuard aGuard( m_aMutex );
772         m_aPropertyListeners.removeListener( _rxListener );
773     }
774 
775     //--------------------------------------------------------------------
getSupportedProperties()776     Sequence< Property > SAL_CALL EventHandler::getSupportedProperties()
777     {
778         ::osl::MutexGuard aGuard( m_aMutex );
779         if ( !m_bEventsMapInitialized )
780         {
781             const_cast< EventHandler* >( this )->m_bEventsMapInitialized = true;
782             try
783             {
784                 Sequence< Type > aListeners;
785                 impl_getCopmonentListenerTypes_nothrow( aListeners );
786                 sal_Int32 listenerCount = aListeners.getLength();
787 
788                 Property aCurrentProperty;
789                 ::rtl::OUString sListenerClassName;
790 
791                 // loop through all listeners and all methods, and see which we can present at the UI
792                 const Type* pListeners = aListeners.getConstArray();
793                 for ( sal_Int32 listener = 0; listener < listenerCount; ++listener, ++pListeners )
794                 {
795                     aCurrentProperty = Property();
796 
797                     // the programmatic name of the listener, to be used as "property" name
798                     sListenerClassName = pListeners->getTypeName();
799                     OSL_ENSURE( sListenerClassName.getLength(), "EventHandler::getSupportedProperties: strange - no listener name ..." );
800                     if ( !sListenerClassName.getLength() )
801                         continue;
802 
803                     // loop through all methods
804                     Sequence< ::rtl::OUString > aMethods( comphelper::getEventMethodsForType( *pListeners ) );
805 
806                     const ::rtl::OUString* pMethods = aMethods.getConstArray();
807                     sal_uInt32 methodCount = aMethods.getLength();
808 
809                     for (sal_uInt32 method = 0 ; method < methodCount ; ++method, ++pMethods )
810                     {
811                         EventDescription aEvent;
812                         if ( !lcl_getEventDescriptionForMethod( *pMethods, aEvent ) )
813                             continue;
814 
815                         if ( !impl_filterMethod_nothrow( aEvent ) )
816                             continue;
817 
818                         const_cast< EventHandler* >( this )->m_aEvents.insert( EventMap::value_type(
819                             lcl_getEventPropertyName( sListenerClassName, *pMethods ), aEvent ) );
820                     }
821                 }
822 
823             }
824             catch( const Exception& )
825             {
826                 DBG_UNHANDLED_EXCEPTION();
827             }
828         }
829 
830         // sort them by ID - this is the relative ordering in the UI
831         ::std::map< EventId, Property > aOrderedProperties;
832         for (   EventMap::const_iterator loop = m_aEvents.begin();
833                 loop != m_aEvents.end();
834                 ++loop
835             )
836         {
837             aOrderedProperties[ loop->second.nId ] = Property(
838                 loop->first, loop->second.nId,
839                 ::getCppuType( static_cast< const ::rtl::OUString* >( NULL ) ),
840                 PropertyAttribute::BOUND );
841         }
842 
843         StlSyntaxSequence< Property > aReturn( aOrderedProperties.size() );
844         ::std::transform( aOrderedProperties.begin(), aOrderedProperties.end(), aReturn.begin(),
845             ::std::select2nd< ::std::map< EventId, Property >::value_type >() );
846         return aReturn;
847     }
848 
849     //--------------------------------------------------------------------
getSupersededProperties()850     Sequence< ::rtl::OUString > SAL_CALL EventHandler::getSupersededProperties( )
851     {
852         // none
853         return Sequence< ::rtl::OUString >( );
854     }
855 
856     //--------------------------------------------------------------------
getActuatingProperties()857     Sequence< ::rtl::OUString > SAL_CALL EventHandler::getActuatingProperties( )
858     {
859         // none
860         return Sequence< ::rtl::OUString >( );
861     }
862 
863     //--------------------------------------------------------------------
describePropertyLine(const::rtl::OUString & _rPropertyName,const Reference<XPropertyControlFactory> & _rxControlFactory)864     LineDescriptor SAL_CALL EventHandler::describePropertyLine( const ::rtl::OUString& _rPropertyName,
865         const Reference< XPropertyControlFactory >& _rxControlFactory )
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*/ )
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 )
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 initial 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*/ )
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*/ )
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 mechanism 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