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