wizards/Package_sfdocuments.mk                   |    1 
 wizards/source/scriptforge/SF_PythonHelper.xba   |    2 
 wizards/source/scriptforge/SF_Services.xba       |    2 
 wizards/source/scriptforge/SF_UI.xba             |    2 
 wizards/source/scriptforge/python/scriptforge.py |   67 +-
 wizards/source/sfdatabases/SF_Database.xba       |   91 +++
 wizards/source/sfdocuments/SF_Base.xba           |   36 -
 wizards/source/sfdocuments/SF_Calc.xba           |    6 
 wizards/source/sfdocuments/SF_Document.xba       |   16 
 wizards/source/sfdocuments/SF_Form.xba           |   73 +-
 wizards/source/sfdocuments/SF_FormControl.xba    |    5 
 wizards/source/sfdocuments/SF_FormDocument.xba   |  642 +++++++++++++++++++++++
 wizards/source/sfdocuments/SF_Register.xba       |    8 
 wizards/source/sfdocuments/SF_Writer.xba         |   10 
 wizards/source/sfdocuments/script.xlb            |    1 
 wizards/source/sfwidgets/SF_MenuListener.xba     |    7 
 16 files changed, 907 insertions(+), 62 deletions(-)

New commits:
commit 88a67c50af61fa9ee5fa677589ce5db2039d6f2e
Author:     Jean-Pierre Ledure <j...@ledure.be>
AuthorDate: Thu Jan 5 13:47:01 2023 +0100
Commit:     Jean-Pierre Ledure <j...@ledure.be>
CommitDate: Thu Jan 5 15:00:28 2023 +0000

    ScriptForge - (SFDocuments) new FormDocument service
    
    The SF_FormDocument service is focused on :
    - The orchestration of Base form documents
      (aka Base Forms, but this is confusing)
      and the identification of and the access to their controls.
    - Form documents are always contained in a Base document.
    
    A form document may be opened either:
    - via code or user interface from the Base file welcome page
    - via code only, without having its Base container opened first
    In any mode, a form document can be opened only in 1 single copy.
    
    The FormDocument service is triggered either by
        base.OpenFormDocument(...)
        database.OpenFormDocument(...)
            ' Base file may be closed
        ui.GetDocument(...)
    
    Specific methods:
        CloseDocument()
        Forms()
        GetDatabase()
        PrintOut()
    Next methods are inherited from the Document superclass:
        Activate()
        CreateMenu(), RemoveMenu()
        ExportAsPdf()
        RunCommand()
        SaveCopyAs()
        SetPrinter()
    
    As a consequence, next methods remain available
    but should be declared as deprecated in the help:
        base.CloseFormDocument()
        base.Forms()
        base.PrintOut()
        base.SetPrinter()
    
    Above changes have several more minor impacts :
    - beside IsCalc, IsWriter, ... , a new IsFormDocument property
    - the UI service identifies open form documents
    - a new service means a new entry to register
      in the Services catalog
    - management of form events has been reviewed
    - the connection between Base, FormDocument, Form
      and Database services is reinforced
    - menus were available on components, now also on sub-components
    
    The new service is available for both Basic and Python user scripts.
    It requires in the help
        - a new sf_formdocument page
        - a review of the sf_base, sf_database, sf_form, sf_ui pages
    
    Change-Id: Ib06d1c4565ca093af2f068fa5b8082082641752e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145080
    Tested-by: Jean-Pierre Ledure <j...@ledure.be>
    Reviewed-by: Jean-Pierre Ledure <j...@ledure.be>
    Tested-by: Jenkins

diff --git a/wizards/Package_sfdocuments.mk b/wizards/Package_sfdocuments.mk
index a2a03178736a..4dcebfc84140 100644
--- a/wizards/Package_sfdocuments.mk
+++ b/wizards/Package_sfdocuments.mk
@@ -27,6 +27,7 @@ $(eval $(call 
gb_Package_add_files,wizards_basicsrvsfdocuments,$(LIBO_SHARE_FOLD
        SF_DocumentListener.xba \
        SF_Form.xba \
        SF_FormControl.xba \
+       SF_FormDocument.xba \
        SF_Register.xba \
        SF_Writer.xba \
        __License.xba \
diff --git a/wizards/source/scriptforge/SF_PythonHelper.xba 
b/wizards/source/scriptforge/SF_PythonHelper.xba
index 99d9f86c610c..ffec0af7586c 100644
--- a/wizards/source/scriptforge/SF_PythonHelper.xba
+++ b/wizards/source/scriptforge/SF_PythonHelper.xba
@@ -814,6 +814,8 @@ Try:
                                                        End Select
                                                Case 
&quot;SFDocuments.FormControl&quot;
                                                        If Script = 
&quot;Controls&quot; Then           vReturn = vBasicObject.Controls(vArgs(0))
+                                               Case 
&quot;SFDocuments.FormDocument&quot;
+                                                       If Script = 
&quot;Forms&quot; Then              vReturn = vBasicObject.Forms(vArgs(0))
                                        End Select
                                End If
                        
diff --git a/wizards/source/scriptforge/SF_Services.xba 
b/wizards/source/scriptforge/SF_Services.xba
index b72298ea3046..8de43d389581 100644
--- a/wizards/source/scriptforge/SF_Services.xba
+++ b/wizards/source/scriptforge/SF_Services.xba
@@ -126,7 +126,7 @@ Try:
                sService = vSplit(0)
                &apos;  Accept other default values for associated libraries
                Select Case LCase(sService)
-                       Case &quot;document&quot;, &quot;calc&quot;, 
&quot;writer&quot;, &quot;base&quot;, &quot;documentevent&quot;, 
&quot;formevent&quot;
+                       Case &quot;document&quot;, &quot;calc&quot;, 
&quot;writer&quot;, &quot;base&quot;, &quot;formdocument&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;, &quot;datasheet&quot;        
                :       sLibrary = &quot;SFDatabases&quot;
diff --git a/wizards/source/scriptforge/SF_UI.xba 
b/wizards/source/scriptforge/SF_UI.xba
index 186d88244d75..4b96ac3274fc 100644
--- a/wizards/source/scriptforge/SF_UI.xba
+++ b/wizards/source/scriptforge/SF_UI.xba
@@ -69,6 +69,7 @@ Const WELCOMESCREEN                           = 
&quot;WELCOMESCREEN&quot;
 Const BASEDOCUMENT                             = &quot;Base&quot;
 Const CALCDOCUMENT                             = &quot;Calc&quot;
 Const DRAWDOCUMENT                             = &quot;Draw&quot;
+Const FORMDOCUMENT                             = &quot;FormDocument&quot;
 Const IMPRESSDOCUMENT                  = &quot;Impress&quot;
 Const MATHDOCUMENT                             = &quot;Math&quot;
 Const WRITERDOCUMENT                   = &quot;Writer&quot;
@@ -1303,6 +1304,7 @@ Dim FSO As Object                                 &apos;  
Alias for SF_FileSystem
                                        If 
SF_Session.HasUnoProperty(poComponent, &quot;Title&quot;) Then .WindowTitle = 
poComponent.Title
                                        Select Case sIdentifier
                                                Case 
&quot;com.sun.star.sdb.FormDesign&quot;                                         
           &apos;  Form
+                                                       .DocumentType = 
FORMDOCUMENT
                                                Case 
&quot;com.sun.star.sdb.TextReportDesign&quot;                                   
   &apos;  Report
                                                Case 
&quot;com.sun.star.text.TextDocument&quot;                                      
   &apos;  Writer
                                                        .DocumentType = 
WRITERDOCUMENT
diff --git a/wizards/source/scriptforge/python/scriptforge.py 
b/wizards/source/scriptforge/python/scriptforge.py
index b3b79132d4b2..a15261caed58 100644
--- a/wizards/source/scriptforge/python/scriptforge.py
+++ b/wizards/source/scriptforge/python/scriptforge.py
@@ -1751,6 +1751,9 @@ class SFDatabases:
         def GetRows(self, sqlcommand, directsql = False, header = False, 
maxrows = 0):
             return self.ExecMethod(self.vbMethod + self.flgArrayRet, 
'GetRows', sqlcommand, directsql, header, maxrows)
 
+        def OpenFormDocument(self, formdocument):
+            return self.ExecMethod(self.vbMethod, 'OpenFormDocument', 
formdocument)
+
         def OpenQuery(self, queryname):
             return self.ExecMethod(self.vbMethod, 'OpenQuery', queryname)
 
@@ -1968,9 +1971,9 @@ class SFDocuments:
         servicename = 'SFDocuments.Document'
         servicesynonyms = ('document', 'sfdocuments.document')
         serviceproperties = dict(Description = True, DocumentType = False, 
ExportFilters = False, ImportFilters = False,
-                                 IsBase = False, IsCalc = False, IsDraw = 
False, IsImpress = False, IsMath = False,
-                                 IsWriter = False, Keywords = True, Readonly = 
False, Subject = True, Title = True,
-                                 XComponent = False)
+                                 IsBase = False, IsCalc = False, IsDraw = 
False, IsFormDocument = False,
+                                 IsImpress = False, IsMath = False, IsWriter = 
False, Keywords = True, Readonly = False,
+                                 Subject = True, Title = True, XComponent = 
False)
         # Force for each property to get its value from Basic - due to intense 
interactivity with user
         forceGetProperty = True
 
@@ -2029,8 +2032,8 @@ class SFDocuments:
         serviceimplementation = 'basic'
         servicename = 'SFDocuments.Base'
         servicesynonyms = ('base', 'scriptforge.base')
-        serviceproperties = dict(DocumentType = False, IsBase = False, IsCalc 
= False,
-                                 IsDraw = False, IsImpress = False, IsMath = 
False, IsWriter = False,
+        serviceproperties = dict(DocumentType = False, IsBase = False, IsCalc 
= False, IsDraw = False,
+                                 IsFormDocument = False, IsImpress = False, 
IsMath = False, IsWriter = False,
                                  XComponent = False)
 
         @classmethod
@@ -2088,9 +2091,9 @@ class SFDocuments:
         servicesynonyms = ('calc', 'sfdocuments.calc')
         serviceproperties = dict(CurrentSelection = True, Sheets = False,
                                  Description = True, DocumentType = False, 
ExportFilters = False, ImportFilters = False,
-                                 IsBase = False, IsCalc = False, IsDraw = 
False, IsImpress = False, IsMath = False,
-                                 IsWriter = False, Keywords = True, Readonly = 
False, Subject = True, Title = True,
-                                 XComponent = False)
+                                 IsBase = False, IsCalc = False, IsDraw = 
False, IsFormDocument = False,
+                                 IsImpress = False, IsMath = False, IsWriter = 
False, Keywords = True, Readonly = False,
+                                 Subject = True, Title = True, XComponent = 
False)
         # Force for each property to get its value from Basic - due to intense 
interactivity with user
         forceGetProperty = True
 
@@ -2343,7 +2346,7 @@ class SFDocuments:
             It includes the management of subforms
             Each instance of the current class represents a single form or a 
single subform
             A form may optionally be (understand "is often") linked to a data 
source manageable with
-            the SFDatabases.Database service. The current service offers a 
rapid access to that service.
+            the SFDatabases.Database service. The current service offers rapid 
access to that service.
             """
         # Mandatory class properties for service registration
         serviceimplementation = 'basic'
@@ -2426,6 +2429,46 @@ class SFDocuments:
         def SetFocus(self):
             return self.ExecMethod(self.vbMethod, 'SetFocus')
 
+    # #########################################################################
+    # SF_FormDocument CLASS
+    # #########################################################################
+    class SF_FormDocument(SF_Document, SFServices):
+        """
+            The orchestration of Base form documents (aka Base Forms, but this 
is confusing)
+            and the identification of and the access to their controls.
+            Form documents are always contained in a Base document.
+            They should not be confused with Writer documents containing forms,
+            even if it is easy to convert the former to the latter.
+            """
+        # Mandatory class properties for service registration
+        serviceimplementation = 'basic'
+        servicename = 'SFDocuments.FormDocument'
+        servicesynonyms = ('formdocument', 'sfdocuments.formdocument')
+        serviceproperties = dict(DocumentType = False, IsBase = False, IsCalc 
= False, IsDraw = False,
+                                 IsFormDocument = False, IsImpress = False, 
IsMath = False, IsWriter = False,
+                                 Readonly = False, XComponent = False)
+
+        @classmethod
+        def ReviewServiceArgs(cls, windowname = ''):
+            """
+                Transform positional and keyword arguments into positional only
+                """
+            return windowname,
+
+        def CloseDocument(self):
+            return self.ExecMethod(self.vbMethod, 'CloseDocument')
+
+        def Forms(self, form = ''):
+            return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'Forms', 
form)
+
+        def GetDatabase(self, user = '', password = ''):
+            return self.ExecMethod(self.vbMethod, 'GetDatabase', user, 
password)
+
+        def PrintOut(self, pages = '', copies = 1, printbackground = True, 
printblankpages = False,
+                     printevenpages = True, printoddpages = True, printimages 
= True):
+            return self.ExecMethod(self.vbMethod, 'PrintOut', pages, copies, 
printbackground, printblankpages,
+                                   printevenpages, printoddpages, printimages)
+
     # #########################################################################
     # SF_Writer CLASS
     # #########################################################################
@@ -2439,9 +2482,9 @@ class SFDocuments:
         servicename = 'SFDocuments.Writer'
         servicesynonyms = ('writer', 'sfdocuments.writer')
         serviceproperties = dict(Description = True, DocumentType = False, 
ExportFilters = False, ImportFilters = False,
-                                 IsBase = False, IsCalc = False, IsDraw = 
False, IsImpress = False, IsMath = False,
-                                 IsWriter = False, Keywords = True, Readonly = 
False, Subject = True, Title = True,
-                                 XComponent = False)
+                                 IsBase = False, IsCalc = False, IsDraw = 
False, IsFormDocument = False,
+                                 IsImpress = False, IsMath = False, IsWriter = 
False, Keywords = True, Readonly = False,
+                                 Subject = True, Title = True, XComponent = 
False)
         # Force for each property to get its value from Basic - due to intense 
interactivity with user
         forceGetProperty = True
 
diff --git a/wizards/source/sfdatabases/SF_Database.xba 
b/wizards/source/sfdatabases/SF_Database.xba
index f0dec87c294e..de891935be69 100644
--- a/wizards/source/sfdatabases/SF_Database.xba
+++ b/wizards/source/sfdatabases/SF_Database.xba
@@ -69,6 +69,8 @@ Private       _MetaData                               As 
Object               &apos; com.sun.star.sdbc.XDatabaseMetaData
 
 REM ============================================================ MODULE 
CONSTANTS
 
+Const cstToken = &quot;//&quot;                                                
        &apos; Form names accept special characters but not slashes
+
 REM ===================================================== 
CONSTRUCTOR/DESTRUCTOR
 
 REM 
-----------------------------------------------------------------------------
@@ -401,6 +403,7 @@ Public Function Methods() As Variant
                                        , &quot;DMin&quot; _
                                        , &quot;DSum&quot; _
                                        , &quot;GetRows&quot; _
+                                       , &quot;OpenFormDocument&quot; _
                                        , &quot;OpenQuery&quot; _
                                        , &quot;OpenSql&quot; _
                                        , &quot;OpenTable&quot; _
@@ -409,6 +412,56 @@ Public Function Methods() As Variant
 
 End Function   &apos;  SFDatabases.SF_Database.Methods
 
+REM 
-----------------------------------------------------------------------------
+Public Function OpenFormDocument(Optional ByVal FormDocument As Variant) As 
Object
+&apos;&apos;&apos;     Open the FormDocument given by its hierarchical name in 
normal mode
+&apos;&apos;&apos;     If the form document is already open, the form document 
is made active
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             FormDocument: a valid form document name as a 
case-sensitive string
+&apos;&apos;&apos;                     When hierarchical, the hierarchy must 
be rendered with forward slashes (&quot;/&quot;)
+&apos;&apos;&apos;     Returns:
+&apos;&apos;&apos;             A FormDocument instance or Nothing
+&apos;&apos;&apos;     Exceptions:
+&apos;&apos;&apos;             Form name is invalid
+&apos;&apos;&apos;     Example:
+&apos;&apos;&apos;             Set oForm = 
oDb.OpenFormDocument(&quot;Folder1/myFormDocument&quot;)
+
+Dim oOpen As Object                                    &apos;  Return value
+Dim oFormDocuments As Variant          &apos;  
com.sun.star.comp.dba.ODocumentContainer
+Dim vFormNames As Variant                      &apos;  Array of all document 
form names present in the document
+Dim vOpenArgs As Variant                       &apos;  Array of property values
+Dim oNewForm As Object                         &apos;  Output of 
loadComponent()
+Const cstThisSub = &quot;SFDatabases.Database.OpenFormDocument&quot;
+Const cstSubArgs = &quot;FormDocument&quot;
+
+       If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+       Set oOpen = Nothing
+
+Check:
+       &apos;  Build list of available FormDocuments recursively with 
_CollectFormDocuments
+       Set oFormDocuments = _Connection.Parent.DataBaseDocument.FormDocuments
+
+       If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+               vFormNames = Split(_CollectFormDocuments(oFormDocuments), 
cstToken)
+               If Not ScriptForge.SF_Utils._Validate(FormDocument, 
&quot;FormDocument&quot;, V_STRING, vFormNames) Then GoTo Finally
+       End If
+
+Try:
+       vOpenArgs = 
Array(SF_Utils._MakePropertyValue(&quot;ActiveConnection&quot;, _Connection) _
+                                               , 
SF_Utils._MakePropertyValue(&quot;OpenMode&quot;, &quot;open&quot;) _
+                               )
+       Set oNewForm = oFormDocuments.loadComponentFromURL(FormDocument, 
&quot;&quot;, 0, vOpenArgs)
+
+       Set oOpen = 
ScriptForge.SF_Services.CreateScriptService(&quot;SFDocuments.FormDocument&quot;,
 oNewForm)
+
+Finally:
+       Set OpenFormDocument = oOpen
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       GoTo Finally
+End Function   &apos;  SF_Databases.SF_Database.OpenFormDocument
+
 REM 
-----------------------------------------------------------------------------
 Public Function OpenQuery(Optional ByVal QueryName As Variant) As Object
 &apos;&apos;&apos;     Open the query given by its name
@@ -632,6 +685,44 @@ End Function       &apos;  
SFDatabases.SF_Database.SetProperty
 
 REM =========================================================== PRIVATE 
FUNCTIONS
 
+REM 
-----------------------------------------------------------------------------
+Private Function _CollectFormDocuments(ByRef poContainer As Object) As String
+&apos;&apos;&apos;     Returns a token-separated string of all hierarchical 
formdocument names
+&apos;&apos;&apos;     depending on the formdocuments container in argument
+&apos;&apos;&apos;     The function traverses recursively the whole tree below 
the container
+&apos;&apos;&apos;     The initial call starts from the container 
_Component.getFormDocuments
+&apos;&apos;&apos;     The list contains closed and open forms
+
+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 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:
+       sCollectNames = &quot;&quot;
+       With poContainer
+               For i = 0 To .Count - 1
+                       Set oSubItem = .getByIndex(i)
+                       If oSubItem.ContentType = cstFormType Then              
&apos;  Add the form to the list
+                               sCollectNames = sCollectNames &amp; cstToken 
&amp; oSubItem.HierarchicalName
+                       Else
+                               sCollectNames = sCollectNames &amp; cstToken 
&amp; _CollectFormDocuments(oSubItem)
+                       End If
+               Next i
+       End With
+
+Finally:
+       If Len(sCollectNames) &gt; 0 Then
+               _CollectFormDocuments = Mid(sCollectNames, Len(cstToken) + 1)   
&apos;  Skip the initial token
+       Else
+               _CollectFormDocuments = &quot;&quot;
+       End If
+       Exit Function
+End Function   &apos;  SFDocuments.SF_Base._CollectFormDocuments
+
 REM 
-----------------------------------------------------------------------------------------------------------------------
 Private Function _DFunction(ByVal psFunction As String _
                                                                , Optional 
ByVal pvExpression As Variant _
diff --git a/wizards/source/sfdocuments/SF_Base.xba 
b/wizards/source/sfdocuments/SF_Base.xba
index 8970b7c05b96..24d1e1b0997b 100644
--- a/wizards/source/sfdocuments/SF_Base.xba
+++ b/wizards/source/sfdocuments/SF_Base.xba
@@ -145,6 +145,7 @@ Public Function CloseFormDocument(Optional ByVal 
FormDocument As Variant) As Boo
 &apos;&apos;&apos;             True if closure is successful
 &apos;&apos;&apos;     Example:
 &apos;&apos;&apos;                     
oDoc.CloseFormDocument(&quot;Folder1/myFormDocument&quot;)
+&apos;&apos;&apos;     DEPRECATED - Use preferably the CloseDocument() method 
of the FormDocument service
 
 Dim bClose As Boolean                          &apos;  Return value
 Dim oMainForm As Object                                &apos;  
com.sun.star.comp.sdb.Content
@@ -235,6 +236,7 @@ Public Function Forms(Optional ByVal FormDocument As 
Variant _
 &apos;&apos;&apos;                     Dim myForm As Object, myList As Variant
 &apos;&apos;&apos;                             myList = 
oDoc.Forms(&quot;Folder1/myFormDocument&quot;)
 &apos;&apos;&apos;                             Set myForm = 
oDoc.Forms(&quot;Folder1/myFormDocument&quot;, 0)
+&apos;&apos;&apos;     DEPRECATED - Use preferably the Forms() method of the 
FormDocument service
 
 Dim oForm As Object                                    &apos;  The new Form 
class instance
 Dim oFormDocument As Object                    &apos;  
com.sun.star.comp.sdb.Content
@@ -283,7 +285,8 @@ Try:
                        ._Name = oXForm.Name
                        Set .[Me] = oForm
                        Set .[_Parent] = [Me]
-                       Set ._Component = _Component
+                       Set ._Component = oFormDocument.Component
+                       Set ._BaseComponent = _Component
                        ._FormDocumentName = FormDocument
                        Set ._FormDocument = oFormDocument
                        ._FormType = ISBASEFORM
@@ -455,28 +458,28 @@ End Function      &apos;  SFDocuments.SF_Base.Methods
 REM 
-----------------------------------------------------------------------------
 Public Function OpenFormDocument(Optional ByVal FormDocument As Variant _
                                                                        , 
Optional ByVal DesignMode As Variant _
-                                                                       ) As 
Boolean
+                                                                       ) As 
Object
 &apos;&apos;&apos;     Open the FormDocument given by its hierarchical name 
either in normal or in design mode
 &apos;&apos;&apos;     If the form document is already open, the form document 
is made active without changing its mode
 &apos;&apos;&apos;     Args:
 &apos;&apos;&apos;             FormDocument: a valid form document name as a 
case-sensitive string
+&apos;&apos;&apos;                     When hierarchical, the hierarchy must 
be rendered with forward slashes (&quot;/&quot;)
 &apos;&apos;&apos;             DesignMode: when True the form document is 
opened in design mode (Default = False)
 &apos;&apos;&apos;     Returns:
-&apos;&apos;&apos;             True if the form document could be opened, 
otherwise False
+&apos;&apos;&apos;             A FormDocument instance or Nothing
 &apos;&apos;&apos;     Exceptions:
 &apos;&apos;&apos;             Form name is invalid
 &apos;&apos;&apos;     Example:
-&apos;&apos;&apos;             
oDoc.OpenFormDocument(&quot;Folder1/myFormDocument&quot;)
+&apos;&apos;&apos;             Set oForm = 
oDoc.OpenFormDocument(&quot;Folbder1/myFormDocument&quot;)
 
-Dim bOpen As Boolean                           &apos;  Return value
+Dim oOpen As Object                                    &apos;  Return value
 Dim vFormNames As Variant                      &apos;  Array of all document 
form names present in the document
-Dim oContainer As Object                       &apos;  com.sun.star.awt.XWindow
 Dim oNewForm As Object                         &apos;  Output of 
loadComponent()
 Const cstThisSub = &quot;SFDocuments.Base.OpenFormDocument&quot;
 Const cstSubArgs = &quot;FormDocument, [DesignMode=False]&quot;
 
        If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
-       bOpen = False
+       Set oOpen = Nothing
 
 Check:
        If IsMissing(DesignMode) Or IsEmpty(DesignMode) Then DesignMode = False
@@ -499,10 +502,11 @@ Try:
                        If .isFormDesignMode() &lt;&gt; DesignMode Then 
.setFormDesignMode(DesignMode)
                End With
        End With
-       bOpen = True
+
+       Set oOpen = 
ScriptForge.SF_Services.CreateScriptService(&quot;SFDocuments.FormDocument&quot;,
 oNewForm)
 
 Finally:
-       OpenFormDocument = bOpen
+       Set OpenFormDocument = oOpen
        ScriptForge.SF_Utils._ExitFunction(cstThisSub)
        Exit Function
 Catch:
@@ -632,6 +636,7 @@ Public Function PrintOut(Optional ByVal FormDocument As 
Variant _
 &apos;&apos;&apos;             True when successful
 &apos;&apos;&apos;     Examples:
 &apos;&apos;&apos;             oDoc.PrintOut(&quot;myForm&quot;, 
&quot;1-4;10;15-18&quot;, Copies := 2)
+&apos;&apos;&apos;     DEPRECATED - Use preferably the PrintOut() method of 
the FormDocument service
 
 Dim bPrint As Boolean                          &apos;  Return value
 Dim vFormNames As Variant                      &apos;  Array of all document 
form names present in the document
@@ -681,6 +686,7 @@ Public Function Properties() As Variant
                                        , &quot;IsBase&quot; _
                                        , &quot;IsCalc&quot; _
                                        , &quot;IsDraw &quot; _
+                                       , &quot;IsFormDocument&quot; _
                                        , &quot;IsImpress&quot; _
                                        , &quot;IsMath&quot; _
                                        , &quot;IsWriter&quot; _
@@ -708,6 +714,7 @@ Public Function SetPrinter(Optional ByVal FormDocument As 
Variant _
 &apos;&apos;&apos;             True when successful
 &apos;&apos;&apos;     Examples:
 &apos;&apos;&apos;             oDoc.SetPrinter(&quot;myForm&quot;, Orientation 
:= &quot;PORTRAIT&quot;)
+&apos;&apos;&apos;     DEPRECATED - Use preferably the SetPrinter() method of 
the FormDocument service
 
 Dim bPrinter As Boolean                                &apos;  Return value
 Dim vFormDocuments As Variant          &apos;  Array of form documents
@@ -829,6 +836,11 @@ Property Get IsDraw() As Boolean
        IsDraw = [_Super].GetProperty(&quot;IsDraw&quot;)
 End Property   &apos;  SFDocuments.SF_Base.IsDraw
 
+REM 
-----------------------------------------------------------------------------
+Property Get IsFormDocument() As Boolean
+       IsFormDocument = [_Super].GetProperty(&quot;IsFormDocument&quot;)
+End Property   &apos;  SFDocuments.SF_Writer.IsFormDocument
+
 REM 
-----------------------------------------------------------------------------
 Property Get IsImpress() As Boolean
        IsImpress = [_Super].GetProperty(&quot;IsImpress&quot;)
@@ -968,7 +980,11 @@ Try:
        End With
 
 Finally:
-       _CollectFormDocuments = Mid(sCollectNames, Len(cstToken) + 1)   &apos;  
Skip the initial token
+       If Len(sCollectNames) &gt; 0 Then
+               _CollectFormDocuments = Mid(sCollectNames, Len(cstToken) + 1)   
&apos;  Skip the initial token
+       Else
+               _CollectFormDocuments = &quot;&quot;
+       End If
        Exit Function
 End Function   &apos;  SFDocuments.SF_Base._CollectFormDocuments
 
diff --git a/wizards/source/sfdocuments/SF_Calc.xba 
b/wizards/source/sfdocuments/SF_Calc.xba
index 0733be07eb6a..806f30bd7cad 100644
--- a/wizards/source/sfdocuments/SF_Calc.xba
+++ b/wizards/source/sfdocuments/SF_Calc.xba
@@ -2556,6 +2556,7 @@ Public Function Properties() As Variant
                                        , &quot;IsBase&quot; _
                                        , &quot;IsCalc&quot; _
                                        , &quot;IsDraw&quot; _
+                                       , &quot;IsFormDocument&quot; _
                                        , &quot;IsImpress&quot; _
                                        , &quot;IsMath&quot; _
                                        , &quot;IsWriter&quot; _
@@ -3482,6 +3483,11 @@ Property Get IsDraw() As Boolean
        IsDraw = [_Super].GetProperty(&quot;IsDraw&quot;)
 End Property   &apos;  SFDocuments.SF_Calc.IsDraw
 
+REM 
-----------------------------------------------------------------------------
+Property Get IsFormDocument() As Boolean
+       IsFormDocument = [_Super].GetProperty(&quot;IsFormDocument&quot;)
+End Property   &apos;  SFDocuments.SF_Writer.IsFormDocument
+
 REM 
-----------------------------------------------------------------------------
 Property Get IsImpress() As Boolean
        IsImpress = [_Super].GetProperty(&quot;IsImpress&quot;)
diff --git a/wizards/source/sfdocuments/SF_Document.xba 
b/wizards/source/sfdocuments/SF_Document.xba
index bba8b3c21bd5..03fb215369ea 100644
--- a/wizards/source/sfdocuments/SF_Document.xba
+++ b/wizards/source/sfdocuments/SF_Document.xba
@@ -268,6 +268,11 @@ Property Get IsDraw() As Boolean
        IsDraw = _PropertyGet(&quot;IsDraw&quot;)
 End Property   &apos;  SFDocuments.SF_Document.IsDraw
 
+REM 
-----------------------------------------------------------------------------
+Property Get IsFormDocument() As Boolean
+       IsFormDocument = _PropertyGet(&quot;IsFormDocument&quot;)
+End Property   &apos;  SFDocuments.SF_Document.IsFormDocument
+
 REM 
-----------------------------------------------------------------------------
 Property Get IsImpress() As Boolean
        IsImpress = _PropertyGet(&quot;IsImpress&quot;)
@@ -459,7 +464,7 @@ Try:
        If SaveAsk And _Component.IsModified Then       &apos;  Execute closure 
with the File/Close menu command
                Activate()
                RunCommand(&quot;CloseDoc&quot;)
-               bClosed = _IsStillAlive(, False)                        &apos;  
Do not raise error
+               bClosed = Not _IsStillAlive(, False)                    &apos;  
Do not raise error
        Else
                _Frame.close(True)
                _Frame.dispose()
@@ -472,6 +477,7 @@ Finally:
        ScriptForge.SF_Utils._ExitFunction(cstThisSub)
        Exit Function
 Catch:
+       On Local Error GoTo 0
        GoTo Finally
 End Function   &apos;   SFDocuments.SF_Document.CloseDocument
 
@@ -592,7 +598,10 @@ Check:
 
 Try:
        &apos;  Setup arguments
-       sFilter = LCase(_DocumentType) &amp; &quot;_pdf_Export&quot;
+       Select Case _DocumentType                       &apos;  Disguise form 
documents as a Writer document
+               Case &quot;FormDocument&quot;                   :       sFilter 
= &quot;Writer_pdf_Export&quot;
+               Case Else                                       :       sFilter 
= LCase(_DocumentType) &amp; &quot;_pdf_Export&quot;
+       End Select
        &apos;  FilterData parameters are added only if they are meaningful
        vFilterData = Array()
        If Len(Pages) &gt; 0 Then
@@ -751,6 +760,7 @@ Public Function Properties() As Variant
                                        , &quot;IsBase&quot; _
                                        , &quot;IsCalc&quot; _
                                        , &quot;IsDraw&quot; _
+                                       , &quot;IsFormDocument&quot; _
                                        , &quot;IsImpress&quot; _
                                        , &quot;IsMath&quot; _
                                        , &quot;IsWriter&quot; _
@@ -1471,7 +1481,7 @@ Const cstSubArgs = &quot;&quot;
                        _PropertyGet = _GetFilterNames(True)
                Case &quot;ImportFilters&quot;
                        _PropertyGet = _GetFilterNames(False)
-               Case &quot;IsBase&quot;, &quot;IsCalc&quot;, 
&quot;IsDraw&quot;, &quot;IsImpress&quot;, &quot;IsMath&quot;, 
&quot;IsWriter&quot;
+               Case &quot;IsBase&quot;, &quot;IsCalc&quot;, 
&quot;IsDraw&quot;, &quot;IsFormDocument&quot;, &quot;IsImpress&quot;, 
&quot;IsMath&quot;, &quot;IsWriter&quot;
                        _PropertyGet = ( Mid(psProperty, 3) = _DocumentType )
                Case &quot;Keywords&quot;
                        _PropertyGet = 
Join(_Component.DocumentProperties.Keywords, &quot;, &quot;)
diff --git a/wizards/source/sfdocuments/SF_Form.xba 
b/wizards/source/sfdocuments/SF_Form.xba
index 2879536efb6f..10b84622d5e5 100644
--- a/wizards/source/sfdocuments/SF_Form.xba
+++ b/wizards/source/sfdocuments/SF_Form.xba
@@ -23,8 +23,8 @@ Option Explicit
 &apos;&apos;&apos;             
 &apos;&apos;&apos;             Definitions:
 &apos;&apos;&apos;
-&apos;&apos;&apos;                     FormDocument:
-&apos;&apos;&apos;                             For usual documents, there is 
only 1 form document. It is in fact the document itself.
+&apos;&apos;&apos;                     FormDocument: BASE DOCUMENTS ONLY
+&apos;&apos;&apos;                             For usual documents, there is 
only 1 forms cpntainer. It is either the document itself or one of its sheets 
(Calc)
 &apos;&apos;&apos;                             A Base document may contain an 
unlimited number of form documents.
 &apos;&apos;&apos;                                     In the Base terminology 
they are called &quot;forms&quot; or &quot;Base forms&quot;. This could create 
some confusion.
 &apos;&apos;&apos;                                     They can be organized 
in folders. Their name is then always the full path of folders + form
@@ -34,29 +34,36 @@ Option Explicit
 &apos;&apos;&apos;                                     the user experience 
significantly
 &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;                             Is an abstract set of Controls 
in an OPEN Document or FormDocument
 &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
-&apos;&apos;&apos;                             A form is defined by its owning 
FormDocument and its FormName or FormIndex
+&apos;&apos;&apos;                             A form is defined by its owning 
Document or FormDocument and its FormName or FormIndex
 &apos;&apos;&apos;
 &apos;&apos;&apos;             Service invocations:
 &apos;&apos;&apos;
-&apos;&apos;&apos;                     REM the form is stored in a not-Base 
document (Calc, Writer)    
+&apos;&apos;&apos;                     REM the form is stored in a Writer 
document
 &apos;&apos;&apos;                     Dim oDoc As Object, myForm As Object
 &apos;&apos;&apos;                             Set oDoc = 
CreateScriptService(&quot;SFDocuments.Document&quot;, ThisComponent)
 &apos;&apos;&apos;                             Set myForm = 
oDoc.Forms(&quot;Form1&quot;)
 &apos;&apos;&apos;                             &apos;  or, alternatively, when 
there is only 1 form
 &apos;&apos;&apos;                             Set myForm = oDoc.Forms(0)      
 &apos;&apos;&apos;
+&apos;&apos;&apos;                     REM the form is stored in a Calc 
document
+&apos;&apos;&apos;                     Dim oCalc As Object, myForm As Object
+&apos;&apos;&apos;                             Set oCalc = 
CreateScriptService(&quot;SFDocuments.Document&quot;, ThisComponent)
+&apos;&apos;&apos;                             Set myForm = 
oCalc.Forms(&quot;Sheet1&quot;, &quot;Form1&quot;)
+&apos;&apos;&apos;                             &apos;  or, alternatively, when 
there is only 1 form
+&apos;&apos;&apos;                             Set myForm = 
oCalc.Forms(&quot;Sheet1&quot;, 0) 
+&apos;&apos;&apos;
 &apos;&apos;&apos;                     REM the form is stored in one of the 
FormDocuments of a Base document
-&apos;&apos;&apos;                     Dim oDoc As Object, myForm As Object, 
mySubForm As Object
-&apos;&apos;&apos;                             Set oDoc = 
CreateScriptService(&quot;SFDocuments.Document&quot;, ThisDatabaseDocument)
-&apos;&apos;&apos;                             
oDoc.OpenFormDocument(&quot;thisFormDocument&quot;)
-&apos;&apos;&apos;                             Set myForm = 
oDoc.Forms(&quot;thisFormDocument&quot;, &quot;MainForm&quot;)
+&apos;&apos;&apos;                     Dim oBase As Object, myFormDoc As 
Object, myForm As Object, mySubForm As Object
+&apos;&apos;&apos;                             Set oBase = 
CreateScriptService(&quot;SFDocuments.Document&quot;, ThisDatabaseDocument)
+&apos;&apos;&apos;                             Set oFormDoc = 
oBase.OpenFormDocument(&quot;thisFormDocument&quot;)
+&apos;&apos;&apos;                             Set myForm = 
oFormDoc.Forms(&quot;MainForm&quot;)
 &apos;&apos;&apos;                             &apos;  or, alternatively, when 
there is only 1 form
-&apos;&apos;&apos;                             Set myForm = 
oDoc.Forms(&quot;thisFormDocument&quot;, 0)
+&apos;&apos;&apos;                             Set myForm = oFormDoc.Forms(0)
 &apos;&apos;&apos;                             &apos;  To access a subform: 
myForm and mySubForm become distinct instances of the current class
 &apos;&apos;&apos;                             Set mySubForm = 
myForm.SubForms(&quot;mySubForm&quot;)
 &apos;&apos;&apos;
@@ -87,9 +94,10 @@ Private _Name                                As String       
        &apos; Internal name of the form
 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 _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
+Private _FormDocument          As Object               &apos; 
com.sun.star.comp.sdb.Content - the form document container
+&apos; The form topmost containers
+Private _Component                     As Object               &apos; 
com.sun.star.lang.XComponent
+Private _BaseComponent         As Object               &apos; 
com.sun.star.comp.dba.ODatabaseDocument
 
 &apos; Events management
 Private _CacheIndex                    As Long                 &apos; Index in 
central cache storage
@@ -98,9 +106,9 @@ Private _CacheIndex                  As Long                 
&apos; Index in central cache storage
 &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
-Private _Database                      As Object               &apos; Database 
class instance
 
 &apos; Form attributes
+Private _Database                      As Object               &apos; Database 
class instance
 
 &apos; Cache storage for controls
 Private _ControlNames          As Variant              &apos; Array of control 
names
@@ -110,7 +118,7 @@ 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 ISBASEFORM                       =       3                       &apos; 
Form is stored in a Base form document
 Const ISSUBFORM                                =       4                       
&apos; Form is a subform of a form or of another subform
 Const ISUNDEFINED                      =       -1                      &apos; 
Undefined form type
 
@@ -126,6 +134,8 @@ Private Sub Class_Initialize()
        _SheetName = &quot;&quot;
        _FormDocumentName = &quot;&quot;
        Set _FormDocument = Nothing
+       Set _Component = Nothing
+       Set _BaseComponent = Nothing
        _FormType = ISUNDEFINED
        _CacheIndex = -1
        Set _Form = Nothing
@@ -535,11 +545,14 @@ Check:
        End If
 Try:
        Select Case _FormType
-               Case ISDOCFORM, ISCALCFORM, ISSUBFORM
-               Case ISBASEFORM
-                       _FormDocument.close()
-                       Dispose()
-                       bClose = True
+               Case ISDOCFORM, ISCALCFORM
+               Case ISBASEFORM, ISSUBFORM
+                       If Not IsNull(_FormDocument) Then
+                               _FormDocument.close()
+                               Dispose()
+                               bClose = True
+                       End If
+               Case Else
        End Select
 
 Finally:
@@ -673,7 +686,7 @@ Check:
        If IsMissing(User) Or IsEmpty(User) Then User = &quot;&quot;
        If IsMissing(Password) Or IsEmpty(Password) Then Password = &quot;&quot;
        If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
-               If Not [_Parent]._IsStillAlive(True) Then GoTo Finally
+               If Not [_Parent]._IsStillAlive(False) Then GoTo Finally
                If Not ScriptForge.SF_Utils._Validate(User, &quot;User&quot;, 
V_STRING) Then GoTo Finally
                If Not ScriptForge.SF_Utils._Validate(Password, 
&quot;Password&quot;, V_STRING) Then GoTo Finally
        End If
@@ -691,7 +704,7 @@ Try:
 
        &apos;  Connect to database, avoiding multiple requests
        If IsNull(_Database) Then               &apos;  1st connection request 
from the current form instance
-               If _FormType = ISBASEFORM Then
+               If _FormType = ISBASEFORM And Not IsNull(_BaseComponent) Then
                        &apos;  Fetch the shared connection
                        Set _Database = [_Parent].GetDatabase(User, Password)
                ElseIf _FormType = ISSUBFORM Then
@@ -1123,6 +1136,7 @@ Try:
                        Set .[_Parent] = [Me]
                        ._FormType = ISSUBFORM
                        Set ._Component = _Component
+                       Set ._BaseComponent = _BaseComponent
                        Set ._FormDocument = _FormDocument
                        ._SheetName = _SheetName
                        ._FormDocumentName = _FormDocumentName
@@ -1208,8 +1222,8 @@ Private Sub _GetParents()
 
 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 oBase As Object                                    &apos;  Empty Base 
instance
 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
@@ -1243,12 +1257,15 @@ Try:
                        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;)
+                                       _FormType = ISBASEFORM
+                                       &apos;  Make a new SF_FormDocument 
instance
+                                       Set [_Parent] = 
ScriptForge.SF_Services.CreateScriptService(&quot;SFDocuments.FormDocument&quot;,
 oParent)
+                                       Set _FormDocument = 
[_Parent]._FormDocument
                                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
+                               Set _Component = oParent
                        Case &quot;ScModelObj&quot;                             
                                &apos;  The parent document: a Calc document
                                _FormType = ISCALCFORM
                                Set [_Parent] = 
ScriptForge.SF_Services.CreateScriptService(&quot;SFDocuments.Document&quot;, 
oParent)
@@ -1256,12 +1273,6 @@ Try:
                                &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)
-                               _FormDocumentName = 
_FormDocument.HierarchicalName
                        Case Else
                End Select
                If oSession.HasUnoProperty(oParent, &quot;Parent&quot;) Then 
Set oParent = oParent.Parent Else Set oParent = Nothing
diff --git a/wizards/source/sfdocuments/SF_FormControl.xba 
b/wizards/source/sfdocuments/SF_FormControl.xba
index a48c22b6c1c5..180cb682b381 100644
--- a/wizards/source/sfdocuments/SF_FormControl.xba
+++ b/wizards/source/sfdocuments/SF_FormControl.xba
@@ -13,7 +13,8 @@ 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_FormControl
-&apos;&apos;&apos;     ================
+&apos;&apos;&apos;     ==============
+&apos;&apos;&apos;
 &apos;&apos;&apos;             Manage the controls belonging to a form or 
subform stored in a document
 &apos;&apos;&apos;             Each instance of the current class represents a 
single control within a form, a subform or a tablecontrol
 &apos;&apos;&apos;             A prerequisite is that all controls within the 
same form, subform or tablecontrol must have
@@ -1131,7 +1132,7 @@ Try:
        End With
 
        &apos;  Store  the SF_FormControl object in the parent cache
-       Set _Parent._ControlCache(_IndexOfNames) = [Me]
+       Set [_Parent]._ControlCache(_IndexOfNames) = [Me]
 
 Finally:
        Exit Sub
diff --git a/wizards/source/sfdocuments/SF_FormDocument.xba 
b/wizards/source/sfdocuments/SF_FormDocument.xba
new file mode 100644
index 000000000000..8d13d86e96e4
--- /dev/null
+++ b/wizards/source/sfdocuments/SF_FormDocument.xba
@@ -0,0 +1,642 @@
+<?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_FormDocument" 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 ClassModule
+
+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_FormDocument
+&apos;&apos;&apos;     ===============
+&apos;&apos;&apos;
+&apos;&apos;&apos;             The SFDocuments library gathers a number of 
methods and properties making easy
+&apos;&apos;&apos;             managing and manipulating LibreOffice documents
+&apos;&apos;&apos;
+&apos;&apos;&apos;             Some methods are generic for all types of 
documents: they are combined in the SF_Document module.
+&apos;&apos;&apos;             Specific properties and methods are implemented 
in the concerned subclass(es) SF_Calc, SF_Writer, SF_Base, ...
+&apos;&apos;&apos;
+&apos;&apos;&apos;             To workaround the absence of class inheritance 
in LibreOffice Basic, some redundancy is necessary
+&apos;&apos;&apos;             Each subclass MUST implement also the generic 
methods and properties, even if they only call
+&apos;&apos;&apos;             the parent methods and properties.
+&apos;&apos;&apos;             They should also duplicate some generic private 
members as a subset of their own set of members
+&apos;&apos;&apos;
+&apos;&apos;&apos;             The SF_FormDocument module is focused on :
+&apos;&apos;&apos;                     The orchestration of Base form 
documents (aka Base Forms, but this is confusing)
+&apos;&apos;&apos;                     and the identification of and the 
access to their controls.
+&apos;&apos;&apos;                     Form documents are always contained in 
a Base document.
+&apos;&apos;&apos;                     They should not be confused with Writer 
documents containing forms,
+&apos;&apos;&apos;                     even if it is easy to convert the 
former to the latter.
+&apos;&apos;&apos;
+&apos;&apos;&apos;             The current module is closely related to
+&apos;&apos;&apos;                     the &quot;Base&quot; service of the 
current library
+&apos;&apos;&apos;                     the &quot;Database&quot; service of the 
SFDatabases library
+&apos;&apos;&apos;
+&apos;&apos;&apos;             A form document may be opened either:
+&apos;&apos;&apos;                     via code or user interface from the 
Base file welcome page
+&apos;&apos;&apos;                     via code only, without having its Base 
container opened first
+&apos;&apos;&apos;                             The Base document remains 
hidden but the user might be prompted about the macro execution mode
+&apos;&apos;&apos;             In any mode, a form document can be opened only 
in 1 single copy
+&apos;&apos;&apos;
+&apos;&apos;&apos;             Service invocation examples:
+&apos;&apos;&apos;                     1) From the Base service
+&apos;&apos;&apos;                             Dim oBase As Object, oFormDoc 
As Object
+&apos;&apos;&apos;                             &apos;  oBase is presumed to 
represent an open Base document
+&apos;&apos;&apos;                             Set oFormDoc = 
oBade.OpenFormDocument(&quot;Folder1/Form1&quot;)
+&apos;&apos;&apos;                     2) Directly without making the Base 
document visible
+&apos;&apos;&apos;                             Dim oDatabase As Object, 
oFormDoc As Object
+&apos;&apos;&apos;                             Set oDatabase = 
CreateScriptService(&quot;SFDatabases.Database&quot;, 
&quot;.../myFile.odb&quot;, ReadOnly := False)
+&apos;&apos;&apos;                             &apos; The substring 
&quot;SFDatabases.&quot; in the service name is optional
+&apos;&apos;&apos;                             Set oFormDoc = 
oDatabase.OpenFormDocument(&quot;Folder1/Form1&quot;)
+&apos;&apos;&apos;
+&apos;&apos;&apos;             Definitions: 
+&apos;&apos;&apos;                     None
+&apos;&apos;&apos;
+&apos;&apos;&apos;             Detailed user documentation:
+&apos;&apos;&apos;                     
https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_formdocument.html?DbPAR=BASIC
+&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;
+
+REM ================================================================== 
EXCEPTIONS
+
+Private Const BASEFORMNOTFOUNDERROR    =       
&quot;BASEFORMNOTFOUNDERROR&quot;
+
+REM ============================================================= PRIVATE 
MEMBERS
+
+Private [Me]                                   As Object
+Private [_Parent]                              As Object               &apos;  
Unused
+Private [_Super]                               As Object               &apos;  
Document superclass, which the current instance is a subclass of
+Private ObjectType                             As String               &apos;  
Must be FormDocument
+Private ServiceName                            As String
+
+&apos; Components
+Private _Component                             As Object               &apos;  
com.sun.star.lang.XComponent
+Private _BaseComponent                 As Object               &apos;  
com.sun.star.comp.dba.ODatabaseDocument
+Private _FormDocument                  As Object               &apos;  
com.sun.star.comp.sdb.Content
+
+&apos; Form document description
+Private _PersistentName                        As String               &apos;  
Typically Objxx
+Private _HierarchicalName              As String
+Private _DataSource                            As Object               &apos;  
com.sun.star.sdbc.XDataSource
+Private _User                                  As String               &apos;  
Credentials
+Private _Password                              As String
+
+REM ============================================================ MODULE 
CONSTANTS
+
+Const ISBASEFORM = 3                           &apos;  Form is stored in a 
Form document
+
+REM ====================================================== 
CONSTRUCTOR/DESTRUCTOR
+
+REM 
-----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+       Set [Me] = Nothing
+       Set [_Parent] = Nothing
+       Set [_Super] = Nothing
+       ObjectType = &quot;FormDocument&quot;
+       ServiceName = &quot;SFDocuments.FormDocument&quot;
+       Set _Component = Nothing
+       Set _BaseComponent = Nothing
+       Set _FormDocument = Nothing
+       Set _DataSource = Nothing
+       Set _Database = Nothing
+       _PersistentName = &quot;&quot;
+       _HierarchicalName = &quot;&quot;
+End Sub                &apos;  SFDocuments.SF_FormDocument Constructor
+
+REM 
-----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+       Call Class_Initialize()
+End Sub                &apos;  SFDocuments.SF_FormDocument Destructor
+
+REM 
-----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+       If Not IsNull([_Super]) Then Set [_Super] = [_Super].Dispose()
+       Call Class_Terminate()
+       Set Dispose = Nothing
+End Function   &apos;  SFDocuments.SF_FormDocument Explicit Destructor
+
+REM ================================================================== 
PROPERTIES
+
+REM ===================================================================== 
METHODS
+
+REM 
-----------------------------------------------------------------------------
+Public Function CloseDocument() As Boolean
+&apos;&apos;&apos;     Close the form document and dispose the actual instance
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;     Returns:
+&apos;&apos;&apos;             True if closure is successful
+&apos;&apos;&apos;     Example:
+&apos;&apos;&apos;                     myFormDoc.CloseDocument()
+
+Dim bClose As Boolean                  &apos;  Return value
+Dim oContainer As Object               &apos;  com.sun.star.awt.XWindow
+Const cstThisSub = &quot;SFDocuments.FormDocument.CloseDocument&quot;
+Const cstSubArgs = &quot;&quot;
+
+       If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+       bClose = False
+
+Check:
+       If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+               If Not _IsStillAlive() Then GoTo Finally
+       End If
+Try:
+       _FormDocument.close()
+       Dispose()
+       bClose = True
+
+Finally:
+       CloseDocument = bClose
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       GoTo Finally
+End Function   &apos;  SFDocuments.SF_FormDocument.CloseDocument
+
+REM 
-----------------------------------------------------------------------------
+Public Function Forms(Optional ByVal Form As Variant) As Variant
+&apos;&apos;&apos;     Return either
+&apos;&apos;&apos;             - the list of the Forms contained in the form 
document
+&apos;&apos;&apos;             - a SFDocuments.Form object based on its name 
or its index
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             Form: a form stored in the document given by 
its name or its index
+&apos;&apos;&apos;                     When absent, the list of available 
forms is returned
+&apos;&apos;&apos;                     To get the first (unique ?) form stored 
in the form document, set Form = 0
+&apos;&apos;&apos;     Exceptions:
+&apos;&apos;&apos;             BASEFORMNOTFOUNDERROR           Form not found
+&apos;&apos;&apos;     Returns:
+&apos;&apos;&apos;             A zero-based array of strings if Form is absent
+&apos;&apos;&apos;             An instance of the SF_Form class if Form exists
+&apos;&apos;&apos;     Example:
+&apos;&apos;&apos;                     Dim myForm As Object, myList As Variant
+&apos;&apos;&apos;                             myList = oDoc.Forms()
+&apos;&apos;&apos;                             Set myForm = 
oDoc.Forms(&quot;myForm&quot;)
+
+Dim oForm As Object                                    &apos;  The new Form 
class instance
+Dim oMainForm As Object                                &apos;  
com.sun.star.comp.sdb.Content
+Dim oXForm As Object                           &apos;  com.sun.star.form.XForm
+Dim vFormNames As Variant                      &apos;  Array of form names
+Dim oForms As Object                           &apos;  Forms collection
+Const cstDrawPage = 0                          &apos;  Only 1 drawpage in a 
FormDocument document
+
+Const cstThisSub = &quot;SFDocuments.FormDocument.Forms&quot;
+Const cstSubArgs = &quot;[Form=&quot;&quot;&quot;&quot;]&quot;
+
+       If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+       If IsMissing(Form) Or IsEmpty(Form) Then Form = &quot;&quot;
+       If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+               If Not _IsStillAlive() Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(Form, &quot;Form&quot;, 
Array(V_STRING, ScriptForge.V_NUMERIC)) Then GoTo Finally
+       End If
+
+Try:
+       &apos;  Start from the document component and go down to forms
+       Set oForms = _Component.DrawPages(cstDrawPage).Forms
+       vFormNames = oForms.getElementNames()
+
+       If Len(Form) = 0 Then   &apos;  Return the list of valid form names
+               Forms = vFormNames
+       Else
+               If VarType(Form) = V_STRING Then        &apos;  Find the form 
by name
+                       If Not ScriptForge.SF_Array.Contains(vFormNames, Form, 
CaseSensitive := True) Then GoTo CatchNotFound
+                       Set oXForm = oForms.getByName(Form)
+               Else                                                            
&apos;  Find the form by index
+                       If Form &lt; 0 Or Form &gt;= oForms.Count Then GoTo 
CatchNotFound
+                       Set oXForm = oForms.getByIndex(Form)
+               End If
+               &apos;  Create the new Form class instance
+               Set oForm = SF_Register._NewForm(oXForm)
+               With oForm
+                       Set .[_Parent] = [Me]
+                       ._FormType = ISBASEFORM
+                       Set ._Component = _Component
+                       Set ._BaseComponent = _BaseComponent
+                       ._FormDocumentName = _HierarchicalName
+                       ._FormDocument = _FormDocument
+                       ._Initialize()
+               End With
+               Set Forms = oForm
+       End If
+
+Finally:
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       GoTo Finally
+CatchNotFound:
+       ScriptForge.SF_Exception.RaiseFatal(BASEFORMNOTFOUNDERROR, Form, 
_FileIdent())
+End Function   &apos;  SFDocuments.SF_FormDocument.Forms
+
+REM 
-----------------------------------------------------------------------------
+Public Function GetDatabase(Optional ByVal User As Variant _
+                                                               , Optional 
ByVal Password As Variant _
+                                                               ) As Object
+&apos;&apos;&apos;     Returns a Database instance (service = 
SFDatabases.Database) giving access
+&apos;&apos;&apos;     to the execution of SQL commands on the database 
defined and/or stored in
+&apos;&apos;&apos;     the actual form document
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             User, Password: the login parameters as 
strings. Defaults = &quot;&quot;
+&apos;&apos;&apos;     Returns:
+&apos;&apos;&apos;             A SFDatabases.Database instance or Nothing
+&apos;&apos;&apos;     Example:
+&apos;&apos;&apos;             Dim myDb As Object
+&apos;&apos;&apos;                     Set myDb = oFormDoc.GetDatabase()
+
+Dim oDatabase As Object                                &apos;  Return value
+Const cstThisSub = &quot;SFDocuments.FormDocument.GetDatabase&quot;
+Const cstSubArgs = &quot;[User=&quot;&quot;&quot;&quot;], 
[Password=&quot;&quot;&quot;&quot;]&quot;
+
+       If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+       Set oDatabase = Nothing
+
+Check:
+       If IsMissing(User) Or IsEmpty(User) Then User = &quot;&quot;
+       If IsMissing(Password) Or IsEmpty(Password) Then Password = &quot;&quot;
+       If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+               If Not _IsStillAlive(False) Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(User, &quot;User&quot;, 
V_STRING) Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(Password, 
&quot;Password&quot;, V_STRING) Then GoTo Finally
+       End If
+
+Try:
+       If IsNull(_DataSource) Then GoTo CatchConnect
+       Set oDatabase = 
ScriptForge.SF_Services.CreateScriptService(&quot;SFDatabases.DatabaseFromDocument&quot;
 _
+                                               , _DataSource, Iif(User = 
&quot;&quot;, _User, User), Iif(Password = &quot;&quot;, _Password, 
&quot;&quot;))
+       If IsNull(oDatabase) Then GoTo CatchConnect
+       oDatabase._Location = _DataSource.Name
+
+Finally:
+       Set GetDatabase = oDatabase
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       GoTo Finally
+CatchConnect:
+       ScriptForge.SF_Exception.RaiseFatal(DBCONNECTERROR, &quot;User&quot;, 
User, &quot;Password&quot;, Password, [_Super]._FileIdent())
+       GoTo Finally
+End Function   &apos;  SFDocuments.SF_FormDocument.GetDatabase
+
+REM 
-----------------------------------------------------------------------------
+Public Function GetProperty(Optional ByVal PropertyName As Variant _
+                                                               , Optional 
ObjectName As Variant _
+                                                               ) As Variant
+&apos;&apos;&apos;     Return the actual value of the given property
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             PropertyName: the name of the property as a 
string
+&apos;&apos;&apos;             ObjectName: a sheet or range name
+&apos;&apos;&apos;     Returns:
+&apos;&apos;&apos;             The actual value of the property
+&apos;&apos;&apos;     Exceptions:
+&apos;&apos;&apos;             ARGUMENTERROR           The property does not 
exist
+
+Const cstThisSub = &quot;SFDocuments.FormDocument.GetProperty&quot;
+Const cstSubArgs = &quot;&quot;
+
+       If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+       GetProperty = Null
+
+Check:
+       If IsMissing(ObjectName) Or IsEmpty(ObjectName) Then ObjectName = 
&quot;&quot;
+       If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+               If Not ScriptForge.SF_Utils._Validate(PropertyName, 
&quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
+               If Not ScriptForge.SF_Utils._Validate(ObjectName, 
&quot;ObjectName&quot;, V_STRING) Then GoTo Catch
+       End If
+
+Try:
+       &apos;  Superclass or subclass property ?
+       If ScriptForge.SF_Array.Contains([_Super].Properties(), PropertyName) 
Then
+               GetProperty = [_Super].GetProperty(PropertyName)
+       ElseIf Len(ObjectName) = 0 Then
+               GetProperty = _PropertyGet(PropertyName)
+       Else
+               GetProperty = _PropertyGet(PropertyName, ObjectName)
+       End If
+
+Finally:
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       GoTo Finally
+End Function   &apos;  SFDocuments.SF_FormDocument.GetProperty
+
+REM 
-----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos;     Return the list of public methods of the FormDocument 
service as an array
+
+       Methods = Array( _
+                                       &quot;CloseDocument&quot; _
+                                       , &quot;Forms&quot; _
+                                       , &quot;PrintOut&quot; _
+                                       )
+
+End Function   &apos;  SFDocuments.SF_FormDocument.Methods
+
+REM 
-----------------------------------------------------------------------------
+Public Function PrintOut(Optional ByVal Pages As Variant _
+                                                       , Optional ByVal Copies 
As Variant _
+                                                       , Optional ByVal 
PrintBackground As Variant _
+                                                       , Optional ByVal 
PrintBlankPages As Variant _
+                                                       , Optional ByVal 
PrintEvenPages As Variant _
+                                                       , Optional ByVal 
PrintOddPages As Variant _
+                                                       , Optional ByVal 
PrintImages As Variant _
+                                                       ) As Boolean
+&apos;&apos;&apos; Send the content of the document to the printer.
+&apos;&apos;&apos;     The printer might be defined previously by default, by 
the user or by the SetPrinter() method
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             Pages: the pages to print as a string, like in 
the user interface. Example: &quot;1-4;10;15-18&quot;. Default = all pages
+&apos;&apos;&apos;             Copies: the number of copies
+&apos;&apos;&apos;             PrintBackground: print the background image 
when True (default)
+&apos;&apos;&apos;             PrintBlankPages: when False (default), omit 
empty pages
+&apos;&apos;&apos;             PrintEvenPages: print the left pages when True 
(default)
+&apos;&apos;&apos;             PrintOddPages: print the right pages when True 
(default)
+&apos;&apos;&apos;             PrintImages: print the graphic objects when 
True (default)
+&apos;&apos;&apos;     Returns:
+&apos;&apos;&apos;             True when successful
+&apos;&apos;&apos;     Examples:
+&apos;&apos;&apos;             oDoc.PrintOut(&quot;1-4;10;15-18&quot;, Copies 
:= 2, PrintImages := False)
+
+Dim bPrint As Boolean                          &apos;  Return value
+Dim vPrintOptions As Variant           &apos;  
com.sun.star.text.DocumentSettings
+
+Const cstThisSub = &quot;SFDocuments.FormDocument.PrintOut&quot;
+Const cstSubArgs = &quot;[Pages=&quot;&quot;&quot;&quot;], [Copies=1], 
[PrintBackground=True], [PrintBlankPages=False], [PrintEvenPages=True]&quot; _
+                                               &amp; &quot;, 
[PrintOddPages=True], [PrintImages=True]&quot;
+
+       If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+       bPrint = False
+
+Check:
+       If IsMissing(Pages) Or IsEmpty(Pages) Then Pages = &quot;&quot;
+       If IsMissing(Copies) Or IsEmpty(Copies) Then Copies = 1
+       If IsMissing(PrintBackground) Or IsEmpty(PrintBackground) Then 
PrintBackground = True
+       If IsMissing(PrintBlankPages) Or IsEmpty(PrintBlankPages) Then 
PrintBlankPages = False
+       If IsMissing(PrintEvenPages) Or IsEmpty(PrintEvenPages) Then 
PrintEvenPages = True
+       If IsMissing(PrintOddPages) Or IsEmpty(PrintOddPages) Then 
PrintOddPages = True
+       If IsMissing(PrintImages) Or IsEmpty(PrintImages) Then PrintImages = 
True
+       
+       If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+               If Not _IsStillAlive() Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(Pages, &quot;Pages&quot;, 
V_STRING) Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(Copies, 
&quot;Copies&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(PrintBackground, 
&quot;PrintBackground&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(PrintBlankPages, 
&quot;PrintBlankPages&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(PrintEvenPages, 
&quot;PrintEvenPages&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(PrintOddPages, 
&quot;PrintOddPages&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+               If Not ScriptForge.SF_Utils._Validate(PrintImages, 
&quot;PrintImages&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+       End If
+
+Try:
+       vPrintOptions = 
_Component.createInstance(&quot;com.sun.star.text.DocumentSettings&quot;)
+       With vPrintOptions
+               .PrintPageBackground = PrintBackground
+               .PrintEmptyPages = PrintBlankPages
+               .PrintLeftPages = PrintEvenPages
+               .PrintRightPages = PrintOddPages
+               .PrintGraphics = PrintImages
+               .PrintDrawings = PrintImages
+       End With
+
+       bPrint = [_Super].PrintOut(Pages, Copies, _Component)
+
+Finally:
+       PrintOut = bPrint
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+Catch:
+       GoTo Finally
+End Function   &apos;   SFDocuments.SF_FormDocument.PrintOut
+
+REM 
-----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos;     Return the list or properties of the FormDocument class 
as an array
+
+       Properties = Array( _
+                                       &quot;DocumentType&quot; _
+                                       , &quot;IsBase&quot; _
+                                       , &quot;IsCalc&quot; _
+                                       , &quot;IsDraw&quot; _
+                                       , &quot;IsFormDocument&quot; _
+                                       , &quot;IsImpress&quot; _
+                                       , &quot;IsMath&quot; _
+                                       , &quot;Readonly&quot; _
+                                       , &quot;XComponent&quot; _
+                                       )
+
+End Function   &apos;  SFDocuments.SF_FormDocument.Properties
+
+REM ======================================================= SUPERCLASS 
PROPERTIES
+
+REM 
-----------------------------------------------------------------------------
+Property Get IsBase() As Boolean
+       IsBase = [_Super].GetProperty(&quot;IsBase&quot;)
+End Property   &apos;  SFDocuments.SF_FormDocument.IsBase
+
+REM 
-----------------------------------------------------------------------------
+Property Get IsCalc() As Boolean
+       IsCalc = [_Super].GetProperty(&quot;IsCalc&quot;)
+End Property   &apos;  SFDocuments.SF_FormDocument.IsCalc
+
+REM 
-----------------------------------------------------------------------------
+Property Get IsDraw() As Boolean
+       IsDraw = [_Super].GetProperty(&quot;IsDraw&quot;)
+End Property   &apos;  SFDocuments.SF_FormDocument.IsDraw
+
+REM 
-----------------------------------------------------------------------------
+Property Get IsFormDocument() As Boolean
+       IsFormDocument = [_Super].GetProperty(&quot;IsFormDocument&quot;)
+End Property   &apos;  SFDocuments.SF_Writer.IsFormDocument
+
+REM 
-----------------------------------------------------------------------------
+Property Get IsImpress() As Boolean
+       IsImpress = [_Super].GetProperty(&quot;IsImpress&quot;)
+End Property   &apos;  SFDocuments.SF_FormDocument.IsImpress
+
+REM 
-----------------------------------------------------------------------------
+Property Get IsMath() As Boolean
+       IsMath = [_Super].GetProperty(&quot;IsMath&quot;)
+End Property   &apos;  SFDocuments.SF_FormDocument.IsMath
+
+REM 
-----------------------------------------------------------------------------
+Property Get Readonly() As Variant
+       Readonly = [_Super].GetProperty(&quot;Readonly&quot;)
+End Property   &apos;  SFDocuments.SF_FormDocument.Readonly
+
+REM 
-----------------------------------------------------------------------------
+Property Get XComponent() As Variant
+       XComponent = [_Super].GetProperty(&quot;XComponent&quot;)
+End Property   &apos;  SFDocuments.SF_FormDocument.XComponent
+
+REM ========================================================== SUPERCLASS 
METHODS
+
+REM 
-----------------------------------------------------------------------------
+Public Function Activate() As Boolean
+       Activate = [_Super].Activate()
+End Function    &apos;   SFDocuments.SF_FormDocument.Activate
+
+REM 
-----------------------------------------------------------------------------
+Public Function CreateMenu(Optional ByVal MenuHeader As Variant _
+                                                               , Optional 
ByVal Before As Variant _
+                                                               , Optional 
ByVal SubmenuChar As Variant _
+                                                               ) As Object
+       Set CreateMenu = [_Super].CreateMenu(MenuHeader, Before, SubmenuChar)
+End Function   &apos;  SFDocuments.SF_FormDocument.CreateMenu
+
+REM 
-----------------------------------------------------------------------------
+Public Function ExportAsPDF(Optional ByVal FileName As Variant _
+                                                       , Optional ByVal 
Overwrite As Variant _
+                                                       , Optional ByVal Pages 
As Variant _
+                                                       , Optional ByVal 
Password As Variant _
+                                                       , Optional ByVal 
Watermark As Variant _
+                                                       ) As Boolean
+       ExportAsPDF = [_Super].ExportAsPDF(FileName, Overwrite, Pages, 
Password, Watermark)
+End Function   &apos;   SFDocuments.SF_FormDocument.ExportAsPDF
+
+REM 
-----------------------------------------------------------------------------
+Public Function RemoveMenu(Optional ByVal MenuHeader As Variant) As Boolean
+       RemoveMenu = [_Super].RemoveMenu(MenuHeader)
+End Function   &apos;  SFDocuments.SF_FormDocument.RemoveMenu
+
+REM 
-----------------------------------------------------------------------------
+Public Sub RunCommand(Optional ByVal Command As Variant _
+                                                                       , 
ParamArray Args As Variant _
+                                                                       )
+       [_Super].RunCommand(Command, Args)
+End Sub                  &apos;   SFDocuments.SF_FormDocument.RunCommand
+
+REM 
-----------------------------------------------------------------------------
+Public Function SaveCopyAs(Optional ByVal FileName As Variant _
+                                                       , Optional ByVal 
Overwrite As Variant _
+                                                       , Optional ByVal 
Password As Variant _
+                                                       , Optional ByVal 
FilterName As Variant _
+                                                       , Optional ByVal 
FilterOptions As Variant _
+                                                       ) As Boolean
+       SaveCopyAs = [_Super].SaveCopyAs(FileName, Overwrite, Password, 
FilterName, FilterOptions)
+End Function   &apos;   SFDocuments.SF_FormDocument.SaveCopyAs
+
+REM 
-----------------------------------------------------------------------------
+Public Function SetPrinter(Optional ByVal Printer As Variant _
+                                                       , Optional ByVal 
Orientation As Variant _
+                                                       , Optional ByVal 
PaperFormat As Variant _
+                                                       ) As Boolean
+       SetPrinter = [_Super].SetPrinter(Printer, Orientation, PaperFormat)
+End Function   &apos;   SFDocuments.SF_FormDocument.SetPrinter
+
+REM =========================================================== PRIVATE 
FUNCTIONS
+
+REM 
-----------------------------------------------------------------------------
+Private Function _FileIdent() As String
+&apos;&apos;&apos;     Returns a file identification from the information that 
is currently available
+&apos;&apos;&apos;     Useful e.g. for display in error messages
+
+       _FileIdent = [_Super]._FileIdent()
+
+End Function   &apos;  SFDocuments.SF_FormDocument._FileIdent
+
+REM 
-----------------------------------------------------------------------------
+Public Sub _Initialize()
+&apos;&apos;&apos;     Achieve the creation of a SF_Form instance
+&apos;&apos;&apos;             - the database file
+&apos;&apos;&apos;             - the database connection
+&apos;&apos;&apos;     the internal and external names
+
+Dim oBase As Object                                    &apos;  A temporary 
Base instance
+
+       On Local Error GoTo Catch
+
+Try:
+       &apos;  Base file where form document is stored
+       Set _BaseComponent = _Component.Parent
+
+       &apos;  Connection arguments
+       Set _DataSource = _BaseComponent.DataSource
+       With _DataSource
+               _User = .User
+               _Password = .Password
+       End With
+
+       &apos;  External and internal names
+       _PersistentName = 
ScriptForge.SF_Utils._GetPropertyValue(_Component.Args, 
&quot;HierarchicalDocumentName&quot;)
+       Set oBase = New SF_Base         &apos;  Only to be able to call the 
_FindByPersistentName() method
+       With oBase
+               Set _FormDocument = 
._FindByPersistentName(_BaseComponent.getFormDocuments(), _PersistentName)
+               _HierarchicalName = _FormDocument.HierarchicalName
+               Set oBase = .Dispose()
+       End With
+
+Finally:
+       Exit Sub
+Catch:
+       On Local Error GoTo 0
+       GoTo Finally
+End Sub                        &apos;  SFDocuments.SF_FormDocument._Initialize
+
+REM 
-----------------------------------------------------------------------------
+Private Function _IsStillAlive(Optional ByVal pbForUpdate As Boolean _
+                                                                       , 
Optional ByVal pbError As Boolean _
+                                                                       ) As 
Boolean
+&apos;&apos;&apos;     Returns True if the document has not been closed 
manually or incidentally since the last use
+&apos;&apos;&apos;     If dead the actual instance is disposed. The execution 
is cancelled when pbError = True (default)
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             pbForUpdate: if True (default = False), check 
additionally if document is open for editing
+&apos;&apos;&apos;             pbError: if True (default), raise a fatal error
+
+Dim bAlive As Boolean                  &apos;  Return value
+
+       If IsMissing(pbForUpdate) Then pbForUpdate = False
+       If IsMissing(pbError) Then pbError = True
+
+Try:
+       bAlive = [_Super]._IsStillAlive(pbForUpdate, pbError)
+
+Finally:
+       _IsStillAlive = bAlive
+       Exit Function
+End Function   &apos;  SFDocuments.SF_FormDocument._IsStillAlive
+
+REM 
-----------------------------------------------------------------------------
+Private Function _PropertyGet(Optional ByVal psProperty As String _
+                                                               , Optional 
ByVal pvArg As Variant _
+                                                               ) As Variant
+&apos;&apos;&apos;     Return the value of the named property
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             psProperty: the name of the property
+
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+       _PropertyGet = False
+
+       cstThisSub = &quot;SFDocuments.FormDocument.get&quot; &amp; psProperty
+       ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+       If Not _IsStillAlive() Then GoTo Finally
+
+       Select Case psProperty
+               Case Else
+                       _PropertyGet = Null
+       End Select
+
+Finally:
+       ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+       Exit Function
+End Function   &apos;  SFDocuments.SF_FormDocument._PropertyGet
+
+REM 
-----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos;     Convert the SF_FormDocument instance to a readable 
string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;     Return:
+&apos;&apos;&apos;             &quot;[DOCUMENT]: Type/File&quot;
+
+       _Repr = &quot;[FormDocument]: &quot; &amp; [_Super]._FileIdent()
+
+End Function   &apos;  SFDocuments.SF_FormDocument._Repr
+
+REM ============================================ END OF 
SFDOCUMENTS.SF_FORMDOCUMENT
+</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 5baf37afb484..c2a58bc61a8d 100644
--- a/wizards/source/sfdocuments/SF_Register.xba
+++ b/wizards/source/sfdocuments/SF_Register.xba
@@ -69,6 +69,7 @@ Public Sub RegisterScriptServices() As Variant
                .RegisterService(&quot;Base&quot;,                              
&quot;SFDocuments.SF_Register._NewDocument&quot;)               &apos;  Same 
reference, distinction is made inside the function
                .RegisterService(&quot;Calc&quot;,                              
&quot;SFDocuments.SF_Register._NewDocument&quot;)               &apos;  Same 
reference, distinction is made inside the function
                .RegisterService(&quot;Writer&quot;,                            
&quot;SFDocuments.SF_Register._NewDocument&quot;)               &apos;  Same 
reference, distinction is made inside the function
+               .RegisterService(&quot;FormDocument&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
@@ -408,6 +409,11 @@ Try:
                                Set oSuperDocument = New SF_Document
                                Set oDocument.[_Super] = oSuperDocument         
&apos;  Now both super and subclass are twinned
                                Set oSuperDocument.[_SubClass] = oDocument
+                       Case &quot;FormDocument&quot;
+                               Set oDocument = New SF_FormDocument
+                               Set oSuperDocument = New SF_Document
+                               Set oDocument.[_Super] = oSuperDocument         
&apos;  Now both super and subclass are twinned
+                               Set oSuperDocument.[_SubClass] = oDocument
                        Case &quot;Writer&quot;
                                Set oDocument = New SF_Writer
                                Set oSuperDocument = New SF_Document
@@ -424,6 +430,8 @@ Try:
                        Select Case vWindow.DocumentType
                                Case &quot;Base&quot;
                                        Set ._DataSource = 
._Component.DataSource
+                               Case &quot;FormDocument&quot;
+                                       ._Initialize()
                                Case Else
                        End Select
                End With
diff --git a/wizards/source/sfdocuments/SF_Writer.xba 
b/wizards/source/sfdocuments/SF_Writer.xba
index eded35de9a96..6f3f258dcb75 100644
--- a/wizards/source/sfdocuments/SF_Writer.xba
+++ b/wizards/source/sfdocuments/SF_Writer.xba
@@ -47,7 +47,7 @@ Option Explicit
 &apos;&apos;&apos;                     TBD
 &apos;&apos;&apos;
 &apos;&apos;&apos;             Detailed user documentation:
-&apos;&apos;&apos;                     
https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/SF_Writer.html?DbPAR=BASIC
+&apos;&apos;&apos;                     
https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_writer.html?DbPAR=BASIC
 &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;
 
@@ -68,6 +68,8 @@ Private _Component                            As Object       
        &apos;  com.sun.star.lang.XComponent
 
 REM ============================================================ MODULE 
CONSTANTS
 
+Const ISDOCFORM = 1                            &apos;  Form is stored in a 
Writer document
+
 REM ====================================================== 
CONSTRUCTOR/DESTRUCTOR
 
 REM 
-----------------------------------------------------------------------------
@@ -312,6 +314,7 @@ Public Function Properties() As Variant
                                        , &quot;IsBase&quot; _
                                        , &quot;IsCalc&quot; _
                                        , &quot;IsDraw&quot; _
+                                       , &quot;IsFormDocument&quot; _
                                        , &quot;IsImpress&quot; _
                                        , &quot;IsMath&quot; _
                                        , &quot;IsWriter&quot; _
@@ -429,6 +432,11 @@ Property Get IsDraw() As Boolean
        IsDraw = [_Super].GetProperty(&quot;IsDraw&quot;)
 End Property   &apos;  SFDocuments.SF_Writer.IsDraw
 
+REM 
-----------------------------------------------------------------------------
+Property Get IsFormDocument() As Boolean
+       IsFormDocument = [_Super].GetProperty(&quot;IsFormDocument&quot;)
+End Property   &apos;  SFDocuments.SF_Writer.IsFormDocument
+
 REM 
-----------------------------------------------------------------------------
 Property Get IsImpress() As Boolean
        IsImpress = [_Super].GetProperty(&quot;IsImpress&quot;)
diff --git a/wizards/source/sfdocuments/script.xlb 
b/wizards/source/sfdocuments/script.xlb
index ff4495124f98..6945460dda77 100644
--- a/wizards/source/sfdocuments/script.xlb
+++ b/wizards/source/sfdocuments/script.xlb
@@ -11,4 +11,5 @@
  <library:element library:name="SF_Writer"/>
  <library:element library:name="SF_Chart"/>
  <library:element library:name="SF_DocumentListener"/>
+ <library:element library:name="SF_FormDocument"/>
 </library:library>
\ No newline at end of file
diff --git a/wizards/source/sfwidgets/SF_MenuListener.xba 
b/wizards/source/sfwidgets/SF_MenuListener.xba
index 9ab018f77b8b..cb7839de5804 100644
--- a/wizards/source/sfwidgets/SF_MenuListener.xba
+++ b/wizards/source/sfwidgets/SF_MenuListener.xba
@@ -88,7 +88,10 @@ Try:
        End With
        
        If Len(sCommand) &gt; 0 Then
-               Set oFrame = StarDesktop.ActiveFrame    &apos;  A menu has been 
clicked necessarily in the current window
+               &apos;  A menu has been clicked necessarily in the current 
window (Document) or one of its subcomponents (FormDocument)
+               Set oFrame = StarDesktop.ActiveFrame
+               If oFrame.Frames.Count &gt; 0 Then Set oFrame = 
oFrame.getActiveFrame()
+               &apos;  Command or script ?
                If Left(sCommand, Len(cstUnoPrefix)) = cstUnoPrefix Then
                        &apos;  Execute uno command
                        Set oDispatcher = 
ScriptForge.SF_Utils._GetUNOService(&quot;DispatchHelper&quot;)
@@ -124,5 +127,5 @@ Sub _SFMENU_disposing(Optional poEvent As Object)           
        &apos;  com.sun.star.awt.Menu
        Exit Sub
 End Sub                        &apos;  
SFWidgets.SF_MenuListener._SFMENU_disposing
 
-REM ============================================ END OF 
SFDIALOGS.SF_DIALOGLISTENER
+REM ============================================ END OF 
SFWIDGETS.SF_MENULISTENER
 </script:module>
\ No newline at end of file

Reply via email to