wizards/source/scriptforge/SF_Services.xba |    3 
 wizards/source/sfdocuments/SF_Base.xba     |   58 +++++++++-
 wizards/source/sfdocuments/SF_Calc.xba     |    8 -
 wizards/source/sfdocuments/SF_Document.xba |   11 -
 wizards/source/sfdocuments/SF_Form.xba     |  162 ++++++++++++++++++++++-------
 wizards/source/sfdocuments/SF_Register.xba |  109 +++++++++++++++++--
 6 files changed, 280 insertions(+), 71 deletions(-)

New commits:
commit f6ba6fc1adde356a88f5e3f91a013aaf3015a55a
Author:     Jean-Pierre Ledure <j...@ledure.be>
AuthorDate: Sat Dec 26 13:21:21 2020 +0100
Commit:     Jean-Pierre Ledure <j...@ledure.be>
CommitDate: Sat Dec 26 16:53:18 2020 +0100

    ScriptForge - (SF_Form) event management and bottom-up tree scan
    
    Strategy for management of Form and FormControl events:
    
    At the contrary of Dialogs and DialogControls, which are always started 
from some code,
    Forms and FormControls will be initiated most often by the user, even if 
the SFDocuments library
    allows to start forms programmatically
    
    For Forms started programmatically, the corresponding objects are built 
top-down
    Event management of forms and their controls requires to being able to 
rebuild Form
    and FormControl objects bottom-up
    
    To avoid multiple rebuilds requested by multiple events,
    1. The active form objects are cached in a global array of _FormCache types
    2. FormControl objects are cached in Form objects
    3. The bottom-up rebuild is executed only once, at instance creation
    
    Change-Id: I76ebb8064a900397427554ca47464c99266e0e5e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/108325
    Tested-by: Jenkins
    Reviewed-by: Jean-Pierre Ledure <j...@ledure.be>

diff --git a/wizards/source/scriptforge/SF_Services.xba 
b/wizards/source/scriptforge/SF_Services.xba
index 10b8c53978e2..39429d67384e 100644
--- a/wizards/source/scriptforge/SF_Services.xba
+++ b/wizards/source/scriptforge/SF_Services.xba
@@ -123,7 +123,8 @@ Try:
                sService = vSplit(0)
                &apos;  Accept other default values for associated libraries
                Select Case sService
-                       Case &quot;Document&quot;, &quot;Calc&quot;, 
&quot;Base&quot;                   :       sLibrary = &quot;SFDocuments&quot;
+                       Case &quot;Document&quot;, &quot;Calc&quot;, 
&quot;Base&quot;, &quot;DocumentEvent&quot;, &quot;FormEvent&quot;
+                                                                               
                                sLibrary = &quot;SFDocuments&quot;
                        Case &quot;Dialog&quot;, &quot;DialogEvent&quot;        
                :       sLibrary = &quot;SFDialogs&quot;
                        Case &quot;Database&quot;                               
                        :       sLibrary = &quot;SFDatabases&quot;
                        Case Else
diff --git a/wizards/source/sfdocuments/SF_Base.xba 
b/wizards/source/sfdocuments/SF_Base.xba
index 31c12b016a50..dec3b2eccad9 100644
--- a/wizards/source/sfdocuments/SF_Base.xba
+++ b/wizards/source/sfdocuments/SF_Base.xba
@@ -191,7 +191,7 @@ Public Function Forms(Optional ByVal FormDocument As 
Variant _
 &apos;&apos;&apos;                             Set myForm = 
oDoc.Forms(&quot;Folder1/myFormDocument&quot;, 0)
 
 Dim oForm As Object                                    &apos;  The new Form 
class instance
-Dim oMainForm As Object                                &apos;  
com.sun.star.comp.sdb.Content
+Dim oFormDocument As Object                            &apos;  
com.sun.star.comp.sdb.Content
 Dim oXForm As Object                           &apos;  com.sun.star.form.XForm
 Dim vFormDocuments As Variant          &apos;  Array of form documents
 Dim vFormNames As Variant                      &apos;  Array of form names
@@ -217,8 +217,8 @@ Check:
 
 Try:
        &apos;  Start from the form document and go down to forms
-       Set oMainForm = _FormDocuments.getByHierarchicalName(FormDocument)
-       Set oForms = oMainForm.Component.DrawPages(cstDrawPage).Forms
+       Set oFormDocument = _FormDocuments.getByHierarchicalName(FormDocument)
+       Set oForms = oFormDocument.Component.DrawPages(cstDrawPage).Forms
        vFormNames = oForms.getElementNames()
 
        If Len(Form) = 0 Then   &apos;  Return the list of valid form names
@@ -237,9 +237,9 @@ Try:
                        ._Name = oXForm.Name
                        Set .[Me] = oForm
                        Set .[_Parent] = [Me]
-                       ._DrawPage = cstDrawPage
+                       Set ._Component = _Component
                        ._FormDocumentName = FormDocument
-                       Set ._MainForm = oMainForm
+                       Set ._FormDocument = oFormDocument
                        ._FormType = ISBASEFORM
                        Set ._Form = oXForm
                        ._Initialize()
@@ -671,7 +671,6 @@ Private Function _CollectFormDocuments(ByRef poContainer As 
Object) As String
 
 Dim sCollectNames As String                    &apos;  Return value
 Dim oSubItem As Object                         &apos;  
com.sun.star.container.XNameAccess (folder) or com.sun.star.ucb.XContent (form)
-Dim sFormName As String                                &apos;  Single form name
 Dim i As Long
 Const cstFormType = &quot;application/vnd.oasis.opendocument.text&quot;
                                                                        &apos;  
Identifies forms. Folders have a zero-length content type
@@ -705,6 +704,53 @@ Private Function _FileIdent() As String
 
 End Function   &apos;  SFDocuments.SF_Base._FileIdent
 
+REM 
-----------------------------------------------------------------------------
+Private Function _FindByPersistentName(ByRef poContainer As Object _
+                                                                               
, psPersistent As String _
+                                                                               
) As Object
+&apos;&apos;&apos;     The FormDocuments property of a Base component has 
strangely
+&apos;&apos;&apos;     a getByHierarchical() method but no access to the same 
com.sun.star.comp.sdb.Content
+&apos;&apos;&apos;     object via its persistent/ODF name
+&apos;&apos;&apos;     This method returns the object having the given 
persistent name
+&apos;&apos;&apos;     The function traverses recursively the whole tree below 
the container until found
+&apos;&apos;&apos;     The initial call starts from the container 
_Component.getFormDocuments
+&apos;&apos;&apos;     The list contains closed and open forms
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             poContainer: the actual top of the free, 
initially _FormDocuments
+&apos;&apos;&apos;             psPersistent: a name like &quot;Obj...&quot;
+&apos;&apos;&apos;     Returns:
+&apos;&apos;&apos;             A com.sun.star.comp.sdb.Content object (object 
found, the process stops)
+&apos;&apos;&apos;             or Nothing (object not found, the process 
continues)
+
+Dim oMainForm As Object                                &apos;  Return value
+Dim oSubItem As Object                         &apos;  
com.sun.star.container.XNameAccess (folder) or com.sun.star.ucb.XContent (form)
+Dim i As Long
+Const cstFormType = &quot;application/vnd.oasis.opendocument.text&quot;
+                                                                       &apos;  
Identifies forms. Folders have a zero-length content type
+
+       On Local Error GoTo Finally
+
+Try:
+       Set oMainForm = Nothing
+       With poContainer
+               For i = 0 To .Count - 1
+                       Set oSubItem = .getByIndex(i)
+                       If oSubItem.ContentType = cstFormType Then              
&apos;  Examine its persistent name
+                               If oSubItem.PersistentName = psPersistent Then
+                                       Set oMainForm = oSubItem
+                                       Exit For
+                               End If
+                       Else
+                               Set oMainForm = _FindByPersistentName(oSubItem, 
psPersistent)
+                       End If
+               Next i
+       End With
+
+Finally:
+       Set _FindByPersistentName = oMainForm
+       Exit Function
+End Function   &apos;  SFDocuments.SF_Base.FindByPersistentName
+
 REM 
-----------------------------------------------------------------------------
 Private Function _IsStillAlive(Optional ByVal pbForUpdate As Boolean _
                                                                        , 
Optional ByVal pbError As Boolean _
diff --git a/wizards/source/sfdocuments/SF_Calc.xba 
b/wizards/source/sfdocuments/SF_Calc.xba
index 8bbcf29019ac..8f542af3aa58 100644
--- a/wizards/source/sfdocuments/SF_Calc.xba
+++ b/wizards/source/sfdocuments/SF_Calc.xba
@@ -908,16 +908,12 @@ Try:
                        Set oXForm = oForms.getByIndex(Form)
                End If
                &apos;  Create the new Form class instance
-               Set oForm = New SF_Form
+               Set oForm = SF_Register._NewForm(oXForm)
                With oForm
-                       ._Name = oXForm.Name
-                       Set .[Me] = oForm
                        Set .[_Parent] = [Me]
-                       ._DrawPage = cstDrawPage
                        ._SheetName = SheetName
-                       Set ._MainForm = Nothing
                        ._FormType = ISCALCFORM
-                       Set ._Form = oXForm
+                       Set ._Component = _Component
                        ._Initialize()
                End With
                Set Forms = oForm
diff --git a/wizards/source/sfdocuments/SF_Document.xba 
b/wizards/source/sfdocuments/SF_Document.xba
index b028d140c74f..a77e0ad9223b 100644
--- a/wizards/source/sfdocuments/SF_Document.xba
+++ b/wizards/source/sfdocuments/SF_Document.xba
@@ -79,7 +79,7 @@ Private _CustomProperties             As Object               
&apos;  Dictionary of custom properties
 
 REM ============================================================ MODULE 
CONSTANTS
 
-Const ISDOCFORM = 1                            &apos;  Form is stored in a 
Calc, Writer, ... document
+Const ISDOCFORM = 1                            &apos;  Form is stored in a 
Writer document
 
 REM ====================================================== 
CONSTRUCTOR/DESTRUCTOR
 
@@ -511,16 +511,11 @@ Try:
                        Set oXForm = oForms.getByIndex(Form)
                End If
                &apos;  Create the new Form class instance
-               Set oForm = New SF_Form
+               Set oForm = SF_Register._NewForm(oXForm)
                With oForm
-                       ._Name = oXForm.Name
-                       Set .[Me] = oForm
                        Set .[_Parent] = [Me]
-                       ._DrawPage = cstDrawPage
-                       ._UsualName = ._Name
-                       Set ._MainForm = Nothing
                        ._FormType = ISDOCFORM
-                       Set ._Form = oXForm
+                       Set ._Component = _Component
                        ._Initialize()
                End With
                Set Forms = oForm
diff --git a/wizards/source/sfdocuments/SF_Form.xba 
b/wizards/source/sfdocuments/SF_Form.xba
index 1962c54831fe..1ed94d51faf3 100644
--- a/wizards/source/sfdocuments/SF_Form.xba
+++ b/wizards/source/sfdocuments/SF_Form.xba
@@ -35,7 +35,7 @@ Option Explicit
 &apos;&apos;&apos;
 &apos;&apos;&apos;                     Form: WHERE IT IS ABOUT IN THE CURRENT 
&quot;Form&quot; SERVICE
 &apos;&apos;&apos;                             Is an abstract set of Controls 
in an OPEN FormDocument
-&apos;&apos;&apos;                             Each form is (often) linked to 
a dataset (table, query or Select statement),
+&apos;&apos;&apos;                             Each form is usually linked to 
one single dataset (table, query or Select statement),
 &apos;&apos;&apos;                             located in any database 
(provided the user may access it)
 &apos;&apos;&apos;                                     A usual document may 
contain several forms. Each of which may have its own data source (database + 
dataset)
 &apos;&apos;&apos;                                     A Base form document 
may contain several forms. Each of which may address its own dataset. The 
database however is unique
@@ -75,16 +75,18 @@ Private ServiceName                 As String
 
 &apos; Form location
 Private _Name                          As String               &apos; Internal 
name of the form
-Private _DrawPage                      As Long                 &apos; Index in 
DrawPages collection
+Private _FormType                      As Integer              &apos; One of 
the ISxxxFORM constants
 Private _SheetName                     As String               &apos; Name as 
the sheet containing the form (Calc only)
 Private _FormDocumentName      As String               &apos; The hierarchical 
name of the containing form document (Base only)
-Private _FormType                      As Integer              &apos; One of 
the ISxxxFORM constants
+Private _FormDocument          As Object               &apos; 
com.sun.star.comp.sdb.Content - the containing form document
+       &apos;  The form topmost container
+Private _Component                     As Object               &apos; 
com.sun.star.lang.XComponent or com.sun.star.comp.dba.ODatabaseDocument
+
+&apos; EVents management
 Private _CacheIndex                    As Long                 &apos; Index in 
central cache storage
+Private _IssuedFromEvent       As Boolean              &apos; When True 
instance is always presumed alive
 
 &apos; Form UNO references
-&apos;         The forms container found in a Base document
-&apos;         Vital for Base forms and subforms
-Private _MainForm                      As Object               &apos; 
com.sun.star.comp.sdb.Content
 &apos;         The entry to the interactions with the form. Validity checked 
by the _IsStillAlive() method
 &apos;         Each method or property requiring that the form is opened 
should first invoke that method
 Private _Form                          As Object               &apos; 
com.sun.star.form.XForm or com.sun.star.comp.forms.ODatabaseForm
@@ -100,7 +102,8 @@ REM 
============================================================ MODULE CONSTANT
 Const ISDOCFORM                                =       1                       
&apos; Form is stored in a Writer document
 Const ISCALCFORM                       =       2                       &apos; 
Form is stored in a Calc document
 Const ISBASEFORM                       =       3                       &apos; 
Form is stored in a Base document
-Const ISSUBFORM                                =       4                       
&apos; Form is a subform of a form stored in a Base document or of another 
subform
+Const ISSUBFORM                                =       4                       
&apos; Form is a subform of a form or of another subform
+Const ISUNDEFINED                      =       -1                      &apos; 
Undefined form type
 
 REM ====================================================== 
CONSTRUCTOR/DESTRUCTOR
 
@@ -111,12 +114,12 @@ Private Sub Class_Initialize()
        ObjectType = &quot;Form&quot;
        ServiceName = &quot;SFDocuments.Form&quot;
        _Name = &quot;&quot;
-       _DrawPage = -1
        _SheetName = &quot;&quot;
        _FormDocumentName = &quot;&quot;
-       _FormType = 0
+       Set _FormDocument = Nothing
+       _FormType = ISUNDEFINED
        _CacheIndex = -1
-       Set _MainForm = Nothing
+       _IssuedFromEvent = False
        Set _Form = Nothing
        Set _Database = Nothing
        _ControlCache = Array()
@@ -194,16 +197,10 @@ Property Let Width(Optional ByVal pvWidth As Variant)
 End Property   &apos;  SFDocuments.SF_Form.Width (let)
 
 REM 
-----------------------------------------------------------------------------
-Property Get XFormModel() As Object
-&apos;&apos;&apos;     The XFormModel property returns the model UNO object of 
the Form
-       XFormModel = _PropertyGet(&quot;XFormModel&quot;)
-End Property   &apos;  SFDocuments.SF_Form.XFormModel (get)
-
-REM 
-----------------------------------------------------------------------------
-Property Get XFormView() As Object
-&apos;&apos;&apos;     The XFormView property returns the view UNO object of 
the Form
-       XFormView = _PropertyGet(&quot;XFormView&quot;)
-End Property   &apos;  SFDocuments.SF_Form.XFormView (get)
+Property Get XForm() As Object
+&apos;&apos;&apos;     The XForm property returns the XForm UNO object of the 
Form
+       XForm = _PropertyGet(&quot;XForm&quot;)
+End Property   &apos;  SFDocuments.SF_Form.XForm (get)
 
 REM ===================================================================== 
METHODS
 
@@ -238,7 +235,7 @@ Try:
                Case ISDOCFORM          :       bActivate = [_Parent].Activate()
                Case ISCALCFORM         :       bActivate = 
[_Parent].Activate(_SheetName)
                Case ISBASEFORM
-                       Set oContainer = 
_MainForm.Component.CurrentController.Frame.ContainerWindow
+                       Set oContainer = 
_FormDocument.Component.CurrentController.Frame.ContainerWindow
                        With oContainer
                                If .isVisible() = False Then .setVisible(True)
                                .IsMinimized = False
@@ -284,7 +281,7 @@ Try:
        Select Case _FormType
                Case ISDOCFORM, ISCALCFORM, ISSUBFORM
                Case ISBASEFORM
-                       _MainForm.close()
+                       _FormDocument.close()
                        Dispose()
                        bClose = True
        End Select
@@ -514,9 +511,11 @@ Public Function Properties() As Variant
                                        , &quot;OnUnloading&quot; _
                                        , &quot;OrderBy&quot; _
                                        , &quot;OrderByOn&quot; _
+                                       , &quot;Parent&quot; _
                                        , &quot;RecordSource&quot; _
                                        , &quot;Visible&quot; _
                                        , &quot;Width&quot; _
+                                       , &quot;XForm&quot; _
                                        )
 
 End Function   &apos;  SFDocuments.SF_Form.Properties
@@ -545,6 +544,7 @@ Check:
 
 Try:
        SetProperty = _PropertySet(PropertyName, Value)
+                               Set UI = 
ScriptForge.SF_Services.CreateScriptService(&quot;ScriptForge.UI&quot;)
 
 Finally:
        SF_Utils._ExitFunction(cstThisSub)
@@ -583,11 +583,92 @@ Private Function _GetListener(ByVal psEventName As 
String) As String
        
 End Function   &apos;  SFDocuments.SF_Form._GetListener
 
+REM 
-----------------------------------------------------------------------------
+Private Sub _GetParents()
+&apos;&apos;&apos;     When the current instance is created top-down, the 
parents are completely defined
+&apos;&apos;&apos;     and nothing should be done in this method
+&apos;&apos;&apos;     When the a class instance is created in a 
(form/control) event, it is the opposite
+&apos;&apos;&apos;     The current method rebuilds the missing members in the 
instance from the bottom
+&apos;&apos;&apos;     Members potentially to collect are:
+&apos;&apos;&apos;             - _FormType
+&apos;&apos;&apos;             - [_Parent], the immediate parent: a form or a 
document instance
+&apos;&apos;&apos;             + Only when the _FormType is a main form
+&apos;&apos;&apos;                     - _SheetName (Calc only)
+&apos;&apos;&apos;                     - _FormDocumentName (Base only)
+&apos;&apos;&apos;                     - _FormDocument, the topmost form 
collection
+&apos;&apos;&apos;                     - _Component, the containing document
+&apos;&apos;&apos;     They must be identified only starting from the _Form 
UNO object
+&apos;&apos;&apos;
+&apos;&apos;&apos;     The method is called from the _Initialize() method at 
instance creation
+
+Dim oParent As Object                          &apos;  Successive bottom-up 
parents
+Dim sType As String                                    &apos;  UNO object type
+Dim sPersistentName As String          &apos;  The Obj... name of a Base form
+Dim iLevel As Integer                          &apos;  When = 1 =&gt; first 
parent
+Dim oSession As Object                         :       Set oSession = 
ScriptForge.SF_Session
+
+       On Local Error GoTo Finally             &apos;  Being probably called 
from events, this method should avoid failures
+       &apos;  When the form type is known, the upper part of the branch is 
not scanned
+       If _FormType &lt;&gt; ISUNDEFINED Then GoTo Finally
+
+Try:
+       &apos;  The whole branch is scanned bottom-up
+       If oSession.HasUnoProperty(_Form, &quot;Parent&quot;) Then Set oParent 
= _Form.Parent Else Set oParent = Nothing
+       _FormType = ISUNDEFINED
+       iLevel = 1
+
+       Do While Not IsNull(oParent)
+               sType = SF_Session.UnoObjectType(oParent)
+               Select Case sType
+                       &apos;  Collect at each level the needed info
+                       Case &quot;com.sun.star.comp.forms.ODatabaseForm&quot;  
&apos;  The parent _Form of a subform
+                               If iLevel = 1 Then
+                                       _FormType = ISSUBFORM
+                                       Set [_Parent] = 
SF_Register._NewForm(oParent)
+                                       &apos;  The parent form could be a main 
form
+                                       [_Parent]._Initialize()
+                                       &apos;  Everything is in the parent, 
stop scan
+                                       Exit Sub
+                               End If
+                       Case &quot;com.sun.star.form.OFormsCollection&quot;     
        &apos;  The collection of forms inside a drawpage
+                       Case &quot;SwXTextDocument&quot;                        
                                &apos;  The parent document: a Writer document 
or a Base form document
+                               If oParent.Identifier = 
&quot;com.sun.star.sdb.FormDesign&quot; Then
+                                       sPersistentName = 
ScriptForge._GetPropertyValue(oParent.Args, 
&quot;HierarchicalDocumentName&quot;)
+                               ElseIf oParent.Identifier = 
&quot;com.sun.star.text.TextDocument&quot; Then
+                                       _FormType = ISDOCFORM
+                                       Set [_Parent] = 
ScriptForge.SF_Services.CreateScriptService(&quot;SFDocuments.Document&quot;, 
oParent)
+                                       Set _Component = [_Parent]._Component
+                               End If
+                       Case &quot;ScModelObj&quot;                             
                                &apos;  The parent document: a Calc document
+                               _FormType = ISCALCFORM
+                               Set [_Parent] = 
ScriptForge.SF_Services.CreateScriptService(&quot;SFDocuments.Document&quot;, 
oParent)
+                               Set _Component = oParent
+                               &apos;  The triggered form event is presumed to 
be located in the (drawpage of the) active sheet
+                               _SheetName = 
[_Parent].XSpreadsheet(&quot;~&quot;)
+                       Case 
&quot;com.sun.star.comp.dba.ODatabaseDocument&quot;        &apos;  The Base 
document
+                               _FormType = ISBASEFORM
+                               Set [_Parent] = 
ScriptForge.SF_Services.CreateScriptService(&quot;SFDocuments.Document&quot;, 
oParent)
+                               Set _Component = oParent
+                               If IsNull([_Parent]._FormDocuments) Then Set 
[_Parent]._FormDocuments = _Component.getFormDocuments()
+                               Set _FormDocument = 
[_Parent]._FindByPersistentName([_Parent]._FormDocuments, sPersistentName)
+                       Case Else
+               End Select
+               If oSession.HasUnoProperty(oParent, &quot;Parent&quot;) Then 
Set oParent = oParent.Parent Else Set oParent = Nothing
+               iLevel = iLevel + 1
+       Loop
+
+Finally:
+       Exit Sub
+End Sub        &apos;  SFDocuments.SF_Form._GetParents
+
 REM 
-----------------------------------------------------------------------------
 Public Sub _Initialize()
 &apos;&apos;&apos;     Achieve the creation of a SF_Form instance
+&apos;&apos;&apos;             - complete the missing private members
 &apos;&apos;&apos;             - store the new instance in the cache
 
+       
+       _GetParents()
        _CacheIndex = SF_Register._AddFormToCache(_Form, [Me])
 
 End Sub                        &apos;  SFDocuments.SF_Form._Initialize
@@ -609,18 +690,22 @@ Check:
        If IsMissing(pbError) Then pbError = True
 
 Try:
-       &apos;  For usual documents, check that the parent document is still 
open
-       &apos;  For Base forms and subforms, check the openness of the main form
-       Select Case _FormType
-               Case ISDOCFORM, ISCALCFORM
-                       bAlive = [_Parent]._IsStillAlive(pbError)
-               Case ISBASEFORM, ISSUBFORM
-                       &apos;  A form that has never been opened has no 
component
-                       &apos;  If ever opened and closed afterwards, it keeps 
the Component but loses its Controller
-                       bAlive = Not IsNull(_MainForm.Component)
-                       If bAlive Then bAlive = Not 
IsNull(_MainForm.Component.CurrentController)
-       End Select
-       If Not bAlive Then GoTo Catch
+       If _IssuedFromEvent Then                &apos;  Instance is presumed 
alive when issued from an event
+               bAlive = True
+       Else
+               &apos;  For usual documents, check that the parent document is 
still open
+               &apos;  For Base forms and subforms, check the openness of the 
main form
+               Select Case _FormType
+                       Case ISDOCFORM, ISCALCFORM
+                               bAlive = [_Parent]._IsStillAlive(pbError)
+                       Case ISBASEFORM, ISSUBFORM
+                               &apos;  A form that has never been opened has 
no component
+                               &apos;  If ever opened and closed afterwards, 
it keeps the Component but loses its Controller
+                               bAlive = Not IsNull(_FormDocument.Component)
+                               If bAlive Then bAlive = Not 
IsNull(_FormDocument.Component.CurrentController)
+               End Select
+               If Not bAlive Then GoTo Catch
+       End If
 
 Finally:
        _IsStillAlive = bAlive
@@ -645,7 +730,7 @@ Private Function _PropertyGet(Optional ByVal psProperty As 
String) As Variant
 &apos;&apos;&apos;     Args:
 &apos;&apos;&apos;             psProperty: the name of the property
 
-Static oSession As Object                                      &apos;  Alias 
of SF_Session
+Static oSession As Object              &apos;  Alias of SF_Session
 Dim cstThisSub As String
 Const cstSubArgs = &quot;&quot;
 
@@ -653,7 +738,6 @@ Const cstSubArgs = &quot;&quot;
        If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
 
        ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
-       &apos;  All the properties except one require an open form
        If Not _IsStillAlive() Then GoTo Finally
 
        If IsNull(oSession) Then Set oSession = 
ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
@@ -661,8 +745,12 @@ Const cstSubArgs = &quot;&quot;
                Case UCase(&quot;Caption&quot;)
                Case UCase(&quot;Height&quot;)
                Case UCase(&quot;Name&quot;)
+               Case UCase(&quot;Parent&quot;)
+                       _PropertyGet = [_Parent]
                Case UCase(&quot;Visible&quot;)
                Case UCase(&quot;Width&quot;)
+               Case UCase(&quot;XForm&quot;)
+                       Set _PropertyGet = _Form
                Case Else
                        _PropertyGet = Null
        End Select
@@ -731,4 +819,4 @@ Dim sParent As String               &apos;  To recognize 
the parent
 End Function   &apos;  SFDocuments.SF_Form._Repr
 
 REM ============================================ END OF SFDOCUMENTS.SF_FORM
-</script:module>
+</script:module>
\ No newline at end of file
diff --git a/wizards/source/sfdocuments/SF_Register.xba 
b/wizards/source/sfdocuments/SF_Register.xba
index 2dccc12c972d..55224b0d53d4 100644
--- a/wizards/source/sfdocuments/SF_Register.xba
+++ b/wizards/source/sfdocuments/SF_Register.xba
@@ -26,9 +26,20 @@ REM 
================================================================== EXCEPTION
 
 REM ================================================================= 
DEFINITIONS
 
-&apos;&apos;&apos;     Event management of forms requires to being able to 
rebuild a Form object
-&apos;&apos;&apos;     from its com.sun.star.form.XForm or 
com.sun.star.comp.forms.ODatabaseForm UNO instance
-&apos;&apos;&apos;     For that purpose, the active forms are buffered in a 
global array of _FormCache types
+&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
@@ -58,7 +69,7 @@ Public Sub RegisterScriptServices() As Variant
                .RegisterService(&quot;Calc&quot;,                              
&quot;SFDocuments.SF_Register._NewDocument&quot;)               &apos;  Same 
references, distinction is made inside the function
                .RegisterService(&quot;Base&quot;,                              
&quot;SFDocuments.SF_Register._NewDocument&quot;)               &apos;  Same 
references, distinction is made inside the function
                .RegisterEventManager(&quot;DocumentEvent&quot;,        
&quot;SFDocuments.SF_Register._EventManager&quot;)      &apos;  Reference to 
the events manager
-               &apos;TODO
+               .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
@@ -135,7 +146,7 @@ End Sub     &apos;  SFDocuments.SF_Register._CleanCacheEntry
 
 REM 
-----------------------------------------------------------------------------
 Public Function _EventManager(Optional ByRef pvArgs As Variant) As Object
-&apos;&apos;&apos;     Returns a Document or Calc object corresponding with 
the active component
+&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:
@@ -164,9 +175,7 @@ Check:
 
 Try:
        If ScriptForge.SF_Session.UnoObjectType(vEvent) = 
&quot;com.sun.star.document.DocumentEvent&quot; Then
-               If ScriptForge.SF_Session.UnoObjectType(vEvent.Source) = 
&quot;SwXTextDocument&quot; Then
-                       Set oSource = SF_Register._NewDocument(vEvent.Source)
-               End If
+               Set oSource = SF_Register._NewDocument(vEvent.Source)
        End If
 
 Finally:
@@ -187,18 +196,65 @@ Dim oCache As _FormCache          &apos;  Entry in the 
cache
        Set oBasicForm = Nothing
 
 Try:
-       For Each oCache In _SF_.SFForms
-               If EqualUnoObjects(poForm, oCache.XUnoForm) And Not 
oCache.Terminated Then
-                       Set oBasicForm = oCache.BasicForm
-                       Exit For
+       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
-       Next oCache
+       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 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.UnoObjectType(vEvent) = 
&quot;com.sun.star.lang.EventObject&quot; Then
+               If oSession.UnoObjectType(vEvent.Source) = 
&quot;com.sun.star.comp.forms.ODatabaseForm&quot; Then
+                       Set oSource = SF_Register._NewForm(vEvent.Source)
+               Else            &apos;  Add for controls
+               End If
+       End If
+
+Finally:
+       Set _FormEventManager = oSource
+       Exit Function
+End Function   &apos;  SFDocuments.SF_Register._FormEventManager
+
 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, ...)
@@ -301,5 +357,32 @@ Catch:
        GoTo Finally
 End Function   &apos;  SFDocuments.SF_Register._NewDocument
 
+REM 
-----------------------------------------------------------------------------
+Public Function _NewForm(Optional ByRef poForm As Object) 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;     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
+               Set oForm = New SF_Form
+               With oForm
+                       ._Name = poForm.Name
+                       Set .[Me] = oForm
+                       Set ._Form = poForm
+               End With
+       End If
+
+Finally:
+       Set _NewForm = oForm
+       Exit Function
+End Function   &apos;  SFDocuments.SF_Register._NewForm
+
 REM ============================================== END OF 
SFDOCUMENTS.SF_REGISTER
 </script:module>
\ No newline at end of file
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to