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