summaryrefslogtreecommitdiff
path: root/wizards
diff options
context:
space:
mode:
authorJean-Pierre Ledure <jp@ledure.be>2020-12-26 13:21:21 +0100
committerJean-Pierre Ledure <jp@ledure.be>2020-12-26 16:53:18 +0100
commitf6ba6fc1adde356a88f5e3f91a013aaf3015a55a (patch)
tree916e5bc5861171d428c310803191110445396f0d /wizards
parent61749b473d777f8252cdd74fbb09c47a704ae5dd (diff)
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 <jp@ledure.be>
Diffstat (limited to 'wizards')
-rw-r--r--wizards/source/scriptforge/SF_Services.xba3
-rw-r--r--wizards/source/sfdocuments/SF_Base.xba58
-rw-r--r--wizards/source/sfdocuments/SF_Calc.xba8
-rw-r--r--wizards/source/sfdocuments/SF_Document.xba11
-rw-r--r--wizards/source/sfdocuments/SF_Form.xba162
-rw-r--r--wizards/source/sfdocuments/SF_Register.xba109
6 files changed, 280 insertions, 71 deletions
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
@@ -706,6 +705,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 _
) 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)
@@ -584,10 +584,91 @@ 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,12 +196,16 @@ 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
@@ -200,6 +213,49 @@ Finally:
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, ...)
&apos; Args:
@@ -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