<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_Register" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
REM ===			The ScriptForge library and its associated libraries are part of the LibreOffice project.				===
REM	===						The SFDocuments library is one of the associated libraries.									===
REM ===					Full documentation is available on https://help.libreoffice.org/								===
REM =======================================================================================================================

Option Compatible
Option Explicit

&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
&apos;&apos;&apos;	SF_Register
&apos;&apos;&apos;	===========
&apos;&apos;&apos;		The ScriptForge framework includes
&apos;&apos;&apos;			the master ScriptForge library
&apos;&apos;&apos;			a number of &quot;associated&quot; libraries SF*
&apos;&apos;&apos;			any user/contributor extension wanting to fit into the framework 
&apos;&apos;&apos;
&apos;&apos;&apos;		The main methods in this module allow the current library to cling to ScriptForge
&apos;&apos;&apos;			- RegisterScriptServices
&apos;&apos;&apos;				Register the list of services implemented by the current library
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;

REM ================================================================== EXCEPTIONS

REM ================================================================= DEFINITIONS

&apos;&apos;&apos;	Strategy for management of Form and FormControl events:
&apos;&apos;&apos;	------------------------------------------------------
&apos;&apos;&apos;	At the contrary of Dialogs and DialogControls, which are always started from some code,
&apos;&apos;&apos;	Forms and FormControls will be initiated most often by the user, even if the SFDocuments library
&apos;&apos;&apos;	allows to start forms programmatically
&apos;&apos;&apos;
&apos;&apos;&apos;	For Forms started programmatically, the corresponding objects are built top-down
&apos;&apos;&apos;	Event management of forms and their controls requires to being able to rebuild Form
&apos;&apos;&apos;	and FormControl objects bottom-up
&apos;&apos;&apos;
&apos;&apos;&apos;	To avoid multiple rebuilds requested by multiple events,
&apos;&apos;&apos;		1. The active form objects are cached in a global array of _FormCache types
&apos;&apos;&apos;		2. FormControl objects are cached in Form objects
&apos;&apos;&apos;		3. The bottom-up rebuild is executed only once, at instance creation

Type _FormCache
	Terminated				As Boolean
	XUnoForm				As Object
	BasicForm				As Object
End Type

REM ============================================================== PUBLIC METHODS

REM -----------------------------------------------------------------------------
Public Sub RegisterScriptServices() As Variant
&apos;&apos;&apos;	Register into ScriptForge the list of the services implemented by the current library
&apos;&apos;&apos;	Each library pertaining to the framework must implement its own version of this method
&apos;&apos;&apos;
&apos;&apos;&apos;	It consists in successive calls to the RegisterService() and RegisterEventManager() methods
&apos;&apos;&apos;	with 2 arguments:
&apos;&apos;&apos;		ServiceName: the name of the service as a case-insensitive string
&apos;&apos;&apos;		ServiceReference: the reference as an object
&apos;&apos;&apos;			If the reference refers to a module, then return the module as an object:
&apos;&apos;&apos;				GlobalScope.Library.Module
&apos;&apos;&apos;			If the reference is a class instance, then return a string referring to the method
&apos;&apos;&apos;			containing the New statement creating the instance
&apos;&apos;&apos;				&quot;libraryname.modulename.function&quot;

	With GlobalScope.ScriptForge.SF_Services
		.RegisterService(&quot;Document&quot;,			&quot;SFDocuments.SF_Register._NewDocument&quot;)		&apos;	Reference to the function initializing the service
		.RegisterService(&quot;Calc&quot;,				&quot;SFDocuments.SF_Register._NewDocument&quot;)		&apos;	Same reference, distinction is made inside the function
		.RegisterService(&quot;Base&quot;,				&quot;SFDocuments.SF_Register._NewDocument&quot;)		&apos;	Same reference, distinction is made inside the function
		.RegisterEventManager(&quot;DocumentEvent&quot;,	&quot;SFDocuments.SF_Register._EventManager&quot;)	&apos;	Reference to the events manager
		.RegisterEventManager(&quot;FormEvent&quot;,		&quot;SFDocuments.SF_Register._FormEventManager&quot;)&apos;	Reference to the form and controls events manager
	End With

End Sub			&apos;	SFDocuments.SF_Register.RegisterScriptServices

REM =========================================================== PRIVATE FUNCTIONS

REM -----------------------------------------------------------------------------
Private Function _AddFormToCache(ByRef pvUnoForm As Object _
										, ByRef pvBasicForm As Object _
										) As Long
&apos;&apos;&apos;	Add a new entry in the cache array with the references of the actual Form
&apos;&apos;&apos;	If relevant, the last entry of the cache is reused.
&apos;&apos;&apos;	The cache is located in the global _SF_ variable
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		pvUnoForm: com.sun.star.form.XForm or com.sun.star.comp.forms.ODatabaseForm
&apos;&apos;&apos;		pvBasicForm: its corresponding Basic object
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The index of the new or modified entry

Dim vCache As New _FormCache		&apos;	Entry to be added
Dim lIndex As Long					&apos;	UBound of _SF_.SFForms
Dim vCacheArray As Variant			&apos;	Alias of _SF_.SFForms

Try:
	vCacheArray = _SF_.SFForms

	If IsEmpty(vCacheArray) Then vCacheArray = Array()
	lIndex = UBound(vCacheArray)
	If lIndex &lt; LBound(vCacheArray) Then
		ReDim vCacheArray(0 To 0)
		lIndex = 0
	ElseIf Not vCacheArray(lIndex).Terminated Then		&apos;	Often last entry can be reused
		lIndex = lIndex + 1
		ReDim Preserve vCacheArray(0 To lIndex)
	End If
	
	With vCache
		.Terminated = False
		Set .XUnoForm = pvUnoForm
		Set .BasicForm = pvBasicForm
	End With
	Set vCacheArray(lIndex) = vCache
	
	_SF_.SFForms = vCacheArray

Finally:
	_AddFormToCache = lIndex
	Exit Function
End Function	&apos;	SFDocuments.SF_Register._AddFormToCache

REM -----------------------------------------------------------------------------
Private Sub _CleanCacheEntry(ByVal plIndex As Long)
&apos;&apos;&apos;	Clean the plIndex-th entry in the Forms cache
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		plIndex: must fit within the actual boundaries of the cache, otherwise the request is ignored

Dim vCache As New _FormCache		&apos;	Cleaned entry

	With _SF_
		If Not IsArray(.SFForms) Then Exit Sub
		If plIndex &lt; LBound(.SFForms) Or plIndex &gt; UBound(.SFForms) Then Exit Sub

		With vCache
			.Terminated = True
			Set .XUnoForm = Nothing
			Set .BasicForm = Nothing
		End With
		.SFForms(plIndex) = vCache
	End With
	
Finally:
	Exit Sub
End Sub	&apos;	SFDocuments.SF_Register._CleanCacheEntry

REM -----------------------------------------------------------------------------
Public Function _EventManager(Optional ByRef pvArgs As Variant) As Object
&apos;&apos;&apos;	Returns a Document, Calc or Base object corresponding with the active component
&apos;&apos;&apos;	which triggered the event in argument
&apos;&apos;&apos;	This method should be triggered only thru the invocation of CreateScriptService
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		pvEvent: com.sun.star.document.DocumentEvent
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		the output of a Document, Calc, ... service or Nothing
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		Sub TriggeredByEvent(ByRef poEvent As Object)
&apos;&apos;&apos;			Dim oDoc As Object
&apos;&apos;&apos;			Set oDoc = CreateScriptService(&quot;SFDocuments.DocumentEvent&quot;, poEvent)
&apos;&apos;&apos;			If Not IsNull(oDoc) Then
&apos;&apos;&apos;				&apos; ... (a valid document has been identified)
&apos;&apos;&apos;		End Sub

Dim oSource As Object			&apos;	Return value
Dim vEvent As Variant			&apos;	Alias of pvArgs(0)

	&apos;	Never abort while an event is processed
	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Finally
	Set oSource = Nothing

Check:
	If IsMissing(pvArgs) Or IsEmpty(pvArgs) Then pvArgs = Array()
	If UBound(pvArgs) &gt;= 0 Then vEvent = pvArgs(0) Else Set vEvent = Empty
	If VarType(vEvent) &lt;&gt; ScriptForge.V_OBJECT Then GoTo Finally

Try:
	If ScriptForge.SF_Session.UnoObjectType(vEvent) = &quot;com.sun.star.document.DocumentEvent&quot; Then
		Set oSource = SF_Register._NewDocument(vEvent.Source)
	End If

Finally:
	Set _EventManager = oSource
	Exit Function
End Function	&apos;	SFDocuments.SF_Register._EventManager

REM -----------------------------------------------------------------------------
Private Function _FindFormInCache(ByRef poForm As Object) As Object
&apos;&apos;&apos;	Find the Form based on its XUnoForm
&apos;&apos;&apos;	The Form must not be terminated
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The corresponding Basic Form part or Nothing

Dim oBasicForm As Object		&apos;	Return value
Dim oCache As _FormCache		&apos;	Entry in the cache

	Set oBasicForm = Nothing

Try:
	With _SF_
		If Not IsEmpty(.SFForms) Then
			For Each oCache In .SFForms
				If EqualUnoObjects(poForm, oCache.XUnoForm) And Not oCache.Terminated Then
					Set oBasicForm = oCache.BasicForm
					Exit For
				End If
			Next oCache
		End If
	End With

Finally:
	Set _FindFormInCache = oBasicForm
	Exit Function
End Function	&apos;	SFDocuments.SF_Register._FindFormInCache

REM -----------------------------------------------------------------------------
Public Function _FormEventManager(Optional ByRef pvArgs As Variant) As Object
&apos;&apos;&apos;	Returns a Form or FormControl object corresponding with the form or control
&apos;&apos;&apos;	which triggered the event in argument
&apos;&apos;&apos;	This method should be triggered only thru the invocation of CreateScriptService
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		pvEvent: com.sun.star.lang.EventObject
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		the output of a Form, FormControl service or Nothing
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		Sub TriggeredByEvent(ByRef poEvent As Object)
&apos;&apos;&apos;			Dim oForm As Object
&apos;&apos;&apos;			Set oForm = CreateScriptService(&quot;SFDocuments.FormEvent&quot;, poEvent)
&apos;&apos;&apos;			If Not IsNull(oForm) Then
&apos;&apos;&apos;				&apos; ... (a valid form or subform has been identified)
&apos;&apos;&apos;		End Sub

Dim oSource As Object			&apos;	Return value
Dim vEvent As Variant			&apos;	Alias of pvArgs(0)
Dim oControlModel As Object		&apos;	com.sun.star.awt.XControlModel
Dim oParent As Object			&apos;	com.sun.star.form.OGridControlModel or com.sun.star.comp.forms.ODatabaseForm
Dim sParentType As String		&apos;	&quot;com.sun.star.form.OGridControlModel&quot; or &quot;com.sun.star.comp.forms.ODatabaseForm&quot;
Dim oSFParent As Object			&apos;	The parent as a ScriptForge instance: SF_Form or SF_FormControl
Dim oSFForm As Object			&apos;	The grand-parent SF_Form instance
Dim oSession As Object			:	Set oSession = ScriptForge.SF_Session

	&apos;	Never abort while an event is processed
	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Finally
	Set oSource = Nothing

Check:
	If IsMissing(pvArgs) Or IsEmpty(pvArgs) Then pvArgs = Array()
	If UBound(pvArgs) &gt;= 0 Then vEvent = pvArgs(0) Else Set vEvent = Empty
	If VarType(vEvent) &lt;&gt; ScriptForge.V_OBJECT Then GoTo Finally

Try:
	If oSession.HasUnoProperty(vEvent, &quot;Source&quot;) Then

		&apos;	FORM EVENT
		If oSession.UnoObjectType(vEvent.Source) = &quot;com.sun.star.comp.forms.ODatabaseForm&quot; Then
			Set oSource = SF_Register._NewForm(vEvent.Source, pbForceInit := True)
		
		&apos;	CONTROL EVENT
		Else
			&apos;	A SF_FormControl instance is always created from its parent, either a form, a subform or a table control
			Set oControlModel = vEvent.Source.Model		&apos;	The event source is a control view com.sun.star.awt.XControl
			Set oParent = oControlModel.Parent
			sParentType = oSession.UnoObjectType(oParent)
			Select Case sParentType
				Case &quot;com.sun.star.form.OGridControlModel&quot;
					Set oSFForm = SF_Register._NewForm(oParent.Parent, pbForceInit := True)
					Set oSFParent = oSFForm.Controls(oParent.Name)
				Case &quot;com.sun.star.comp.forms.ODatabaseForm&quot;
					Set oSFParent = SF_Register._NewForm(oParent, pbForceInit := True)
			End Select
			&apos;	The final instance is derived from its parent instance
			Set oSource = oSFParent.Controls(oControlModel.Name)

		End If

	End If

Finally:
	Set _FormEventManager = oSource
	Exit Function
End Function	&apos;	SFDocuments.SF_Register._FormEventManager

REM -----------------------------------------------------------------------------
Public Function _GetEventScriptCode(poObject As Object _
					, ByVal psEvent As String _
					, ByVal psName As String _
					) As String
&apos;&apos;&apos;	Extract from the parent of poObject the Basic script linked to psEvent.
&apos;&apos;&apos;	Helper function common to forms and form controls
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		poObject: a com.sun.star.form.XForm or XControl object
&apos;&apos;&apos;		psEvent: the &quot;On...&quot; name of the event
&apos;&apos;&apos;		psName: the name of the object to be identified from the parent object
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The script to trigger when psEvent occurs
&apos;&apos;&apos;		See Scripting Framework URI Specification : https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification

Dim vEvents As Variant			&apos;	List of available events in the parent object
								&apos;	Array of com.sun.star.script.ScriptEventDescriptor
Dim sEvent As String			&apos;	The targeted event name
Dim oParent As Object			&apos;	The parent object
Dim lIndex As Long				&apos;	The index of the targeted event in the events list of the parent object
Dim sName As String				&apos;	The corrected UNO event name
Dim i As Long

	_GetEventScriptCode = &quot;&quot;
	On Local Error GoTo Catch
	If Not ScriptForge.SF_Session.HasUnoMethod(poObject, &quot;getParent&quot;) Then GoTo Finally

Try:
	&apos;	Find form index i.e. find control via getByIndex()
	&apos;	The name is known (= psName) but getByIndex() is not in the same sequence as getElementNames()
	Set oParent = poObject.getParent()
	lIndex = -1
	For i = 0 To oParent.getCount() - 1
		sName = oParent.getByIndex(i).Name
		If (sName = psName) Then
			lIndex = i
			Exit For
		End If
	Next i
	If lIndex &lt; 0 Then GoTo Finally		&apos;	Not found, should not happen
	
	&apos;	Find script triggered by event
	vEvents = oParent.getScriptEvents(lIndex)				&apos;	Returns an array
	&apos;	Fix historical typo error
	sEvent = Replace(LCase(Mid(psEvent, 3, 1)) &amp; Mid(psEvent, 4), &quot;errorOccurred&quot;, &quot;errorOccured&quot;)
	For i = 0 To UBound(vEvents)
		If vEvents(i).EventMethod = sEvent Then
			_GetEventScriptCode = vEvents(i).ScriptCode
			Exit For
		End If
	Next i

Finally:
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	SFDocuments.SF_Register._GetEventScriptCode

REM -----------------------------------------------------------------------------
Public Function _NewDocument(Optional ByVal pvArgs As Variant) As Object
&apos;&apos;&apos;	Create a new instance of the (super) SF_Document class or of one of its subclasses (SF_Calc, ...)
&apos;	Args:
&apos;&apos;&apos;		WindowName: see the definition of WindowName in the description of the UI service
&apos;&apos;&apos;			If absent, the document is presumed to be in the active window
&apos;&apos;&apos;			If WindowName is an object, it must be a component
&apos;&apos;&apos;				(com.sun.star.lang.XComponent or com.sun.star.comp.dba.ODatabaseDocument)
&apos;&apos;&apos;	Returns: the instance or Nothing

Dim oDocument As Object				&apos;	Return value
Dim oSuperDocument As Object		&apos;	Companion superclass document
Dim vWindowName As Variant			&apos;	Alias of pvArgs(0)
Dim oEnum As Object					&apos;	com.sun.star.container.XEnumeration
Dim oComp As Object					&apos;	com.sun.star.lang.XComponent
Dim vWindow As Window				&apos;	A single component
Dim oUi As Object					&apos;	&quot;UI&quot; service
Dim bFound As Boolean				&apos;	True if the document is found on the desktop

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch

Check:
	If IsMissing(pvArgs) Or IsEmpty(pvArgs) Then pvArgs = Array()
	If Not IsArray(pvArgs) Then pvArgs = Array(pvArgs)		&apos;	Needed when _NewDocument called from _EventManager
	If UBound(pvArgs) &gt;= 0 Then vWindowName = pvArgs(0) Else vWindowName = &quot;&quot;
	If Not ScriptForge.SF_Utils._Validate(vWindowName, &quot;WindowName&quot;, Array(V_STRING, ScriptForge.V_OBJECT)) Then GoTo Finally
	Set oDocument = Nothing

Try:
	Set oUi = ScriptForge.SF_Register.CreateScriptService(&quot;UI&quot;)
	Select Case VarType(vWindowName)
		Case V_STRING
			If Len(vWindowName) &gt; 0 Then
				bFound = False
				Set oEnum = StarDesktop.Components().createEnumeration
				Do While oEnum.hasMoreElements
					Set oComp = oEnum.nextElement
					vWindow = oUi._IdentifyWindow(oComp)
					With vWindow
						&apos;	Does the current window match the argument ?
						If	(Len(.WindowFileName) &gt; 0 And .WindowFileName = ScriptForge.SF_FileSystem._ConvertToUrl(vWindowName)) _
							Or (Len(.WindowName) &gt; 0 And .WindowName = vWindowName) _
							Or (Len(.WindowTitle) &gt; 0 And .WindowTitle = vWindowName) Then
								bFound = True
								Exit Do
							End If
					End With
				Loop
			Else
				bFound = True
				vWindow = oUi._IdentifyWindow(StarDesktop.CurrentComponent)
			End If
		Case ScriptForge.V_OBJECT	&apos;	com.sun.star.lang.XComponent
			bFound = True
			vWindow = oUi._IdentifyWindow(vWindowName)
	End Select

	If bFound And Not IsNull(vWindow.Frame) And Len(vWindow.DocumentType) &gt; 0 Then
		&apos;	Create the right subclass and associate to it a new instance of the superclass
		Select Case vWindow.DocumentType
			Case &quot;Base&quot;
				Set oDocument = New SF_Base
				Set oSuperDocument = New SF_Document
				Set oDocument.[_Super] = oSuperDocument		&apos;	Now both super and subclass are twinned
				Set oSuperDocument.[_SubClass] = oDocument
			Case &quot;Calc&quot;
				Set oDocument = New SF_Calc
				Set oSuperDocument = New SF_Document
				Set oDocument.[_Super] = oSuperDocument		&apos;	Now both super and subclass are twinned
				Set oSuperDocument.[_SubClass] = oDocument
			Case Else		&apos;	Only superclass
				Set oDocument = New SF_Document
				Set oSuperDocument = oDocument
		End Select
		With oDocument		&apos;	Initialize attributes of subclass
			Set .[Me] = oDocument
			Set ._Component = vWindow.Component
			&apos;	Initialize specific attributes
			Select Case vWindow.DocumentType
				Case &quot;Base&quot;
					Set ._DataSource = ._Component.DataSource
				Case Else
			End Select
		End With
		With oSuperDocument	&apos;	Initialize attributes of superclass
			Set .[Me] = oSuperDocument
			Set ._Component = vWindow.Component
			Set ._Frame = vWindow.Frame
			._WindowName = vWindow.WindowName
			._WindowTitle = vWindow.WindowTitle
			._WindowFileName = vWindow.WindowFileName
			._DocumentType = vWindow.DocumentType
		End With
	End If

Finally:
	Set _NewDocument = oDocument
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	SFDocuments.SF_Register._NewDocument

REM -----------------------------------------------------------------------------
Public Function _NewForm(ByRef poForm As Object _
							, Optional pbForceInit As Boolean _
							) As Object
&apos;&apos;&apos;	Returns an existing or a new SF_Form instance based on the argument
&apos;&apos;&apos;	If the instance is new (not found in cache), the minimal members are initialized
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		poForm: com.sun.star.form.XForm or com.sun.star.comp.forms.ODatabaseForm
&apos;&apos;&apos;		pbForceInit: when True, initialize the form instance. Default = False
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		A SF_Form instance

Dim oForm As Object				&apos;	Return value

Try:
	Set oForm = SF_Register._FindFormInCache(poForm)
	If IsNull(oForm) Then		&apos;	Not found
		If IsMissing(pbForceInit) Or IsEmpty(pbForceInit) Then pbForceInit = False
		Set oForm = New SF_Form
		With oForm
			._Name = poForm.Name
			Set .[Me] = oForm
			Set ._Form = poForm
			If pbForceInit Then ._Initialize()
		End With
	End If

Finally:
	Set _NewForm = oForm
	Exit Function
End Function	&apos;	SFDocuments.SF_Register._NewForm

REM -----------------------------------------------------------------------------
Public Function _RegisterEventScript(poObject As Object _
								, ByVal psEvent As String _
								, ByVal psListener As String _
								, ByVal psScriptCode As String _
								, ByVal psName As String _
								) As Boolean
&apos;&apos;&apos;	Register a script event (psEvent) to poObject (Form, SubForm or Control)
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		poObject: a com.sun.star.form.XForm or XControl object
&apos;&apos;&apos;		psEvent: the &quot;On...&quot; name of the event
&apos;&apos;&apos;		psListener: the listener name corresponding with the event
&apos;&apos;&apos;		psScriptCode: The script to trigger when psEvent occurs
&apos;&apos;&apos;			See Scripting Framework URI Specification : https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification
&apos;&apos;&apos;		psName: the name of the object to associate with the event
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		True when successful

Dim oEvent As Object			&apos;	com.sun.star.script.ScriptEventDescriptor
Dim sEvent As String			&apos;	The targeted event name
Dim oParent As Object			&apos;	The parent object
Dim lIndex As Long				&apos;	The index of the targeted event in the events list of the parent object
Dim sName As String				&apos;	The corrected UNO event name
Dim i As Long

	_RegisterEventScript = False
	On Local Error GoTo Catch
	If Not ScriptForge.SF_Session.HasUnoMethod(poObject, &quot;getParent&quot;) Then GoTo Finally

Try:
	&apos;	Find object&apos;s internal index i.e. how to reach it via getByIndex() 
	Set oParent = poObject.getParent()
	lIndex = -1
	For i = 0 To oParent.getCount() - 1
		sName = oParent.getByIndex(i).Name
		If (sName = psName) Then
			lIndex = i
			Exit For
		End If
	Next i
	If lIndex &lt; 0 Then GoTo Finally		&apos;	Not found, should not happen

	&apos;	Fix historical typo error
	sEvent = Replace(LCase(Mid(psEvent, 3, 1)) &amp; Mid(psEvent, 4), &quot;errorOccurred&quot;, &quot;errorOccured&quot;)
	&apos;	Apply new script code. Erasing it is done with a specific UNO method
	If psScriptCode = &quot;&quot; Then
		oParent.revokeScriptEvent(lIndex, psListener, sEvent, &quot;&quot;)
	Else
		Set oEvent = CreateUnoStruct(&quot;com.sun.star.script.ScriptEventDescriptor&quot;)
		With oEvent
			.ListenerType = psListener
			.EventMethod = sEvent
			.ScriptType = &quot;Script&quot;			&apos;	Better than &quot;Basic&quot;
			.ScriptCode = psScriptCode
		End With
		oParent.registerScriptEvent(lIndex, oEvent)
	End If
	_RegisterEventScript = True

Finally:
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	SFDocuments.SF_Register._RegisterEventScript

REM ============================================== END OF SFDOCUMENTS.SF_REGISTER
</script:module>