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