wizards/source/scriptforge/SF_Services.xba       |    3 
 wizards/source/scriptforge/python/scriptforge.py |   26 +++++
 wizards/source/sfdialogs/SF_Dialog.xba           |   46 +++++++-
 wizards/source/sfdialogs/SF_Register.xba         |  118 +++++++++++++++++++++--
 4 files changed, 177 insertions(+), 16 deletions(-)

New commits:
commit 0a1022b04c90d36e16dee121923ca4111386585b
Author:     Jean-Pierre Ledure <j...@ledure.be>
AuthorDate: Sun May 21 17:06:05 2023 +0200
Commit:     Jean-Pierre Ledure <j...@ledure.be>
CommitDate: Mon May 22 14:08:20 2023 +0200

    ScriptForge (SFDialogs: create dialogs on-the-fly
    
    A dialog service is returned by next statement
    
      dialog = CreateScriptService("newdialog", dialogname, place)
    
    All properties and methods applicable to predefined
    dialogs are available for such new dialogs.
    In particular the series of CreateXXX() methods for the addition
    of ne dialog controls.
    
    The functionality is available from Basic and Python user
    scripts.
    
    An update of the SFDialogs.SF_Dialog help page is required.
    
    A display rendering unstability (flickerings, delays, ..) has
    been observed when (all conditions must be met)
    - the user script is run from Python
    - from inside the LibreOffice process
    - the dialog is non-modal
    
    Change-Id: Id3f311cd04497fd79712ce712bdb2724b5caa861
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152071
    Tested-by: Jean-Pierre Ledure <j...@ledure.be>
    Reviewed-by: Jean-Pierre Ledure <j...@ledure.be>

diff --git a/wizards/source/scriptforge/SF_Services.xba 
b/wizards/source/scriptforge/SF_Services.xba
index f5e0545546e6..f00ad9e94b21 100644
--- a/wizards/source/scriptforge/SF_Services.xba
+++ b/wizards/source/scriptforge/SF_Services.xba
@@ -128,7 +128,8 @@ Try:
                Select Case LCase(sService)
                        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;dialog&quot;, &quot;dialogevent&quot;, 
&quot;newdialog&quot;
+                                                                               
                                sLibrary = &quot;SFDialogs&quot;
                        Case &quot;database&quot;, &quot;datasheet&quot;        
                :       sLibrary = &quot;SFDatabases&quot;
                        Case &quot;unittest&quot;                               
                        :       sLibrary = &quot;SFUnitTests&quot;
                        Case &quot;menu&quot;, &quot;popupmenu&quot;, 
&quot;toolbar&quot;, &quot;toolbarbutton&quot;
diff --git a/wizards/source/scriptforge/python/scriptforge.py 
b/wizards/source/scriptforge/python/scriptforge.py
index 1b094c4711be..8b3a67fe2f60 100644
--- a/wizards/source/scriptforge/python/scriptforge.py
+++ b/wizards/source/scriptforge/python/scriptforge.py
@@ -1987,6 +1987,32 @@ class SFDialogs:
         def Terminate(self):
             return self.ExecMethod(self.vbMethod, 'Terminate')
 
+    # #########################################################################
+    # SF_NewDialog CLASS
+    # #########################################################################
+    class SF_NewDialog(SFServices):
+        """
+            Pseudo service never returned from the Basic world. A SF_Dialog 
instance is returned instead.
+            Main purpose: manage the arguments of CreateScritService() for the 
creation of a dialog from scratch
+            """
+        # Mandatory class properties for service registration
+        serviceimplementation = 'basic'
+        servicename = 'SFDialogs.NewDialog'
+        servicesynonyms = ('newdialog', 'sfdialogs.newdialog')
+        serviceproperties = dict()
+
+        @classmethod
+        def ReviewServiceArgs(cls, dialogname = '', place = (0, 0, 0, 0)):
+            """
+                Transform positional and keyword arguments into positional only
+                Add the XComponentContext as last argument
+                """
+            outsideprocess = len(ScriptForge.hostname) > 0 and 
ScriptForge.port > 0
+            if outsideprocess:
+                return dialogname, place, ScriptForge.componentcontext
+            else:
+                return dialogname, place
+
     # #########################################################################
     # SF_DialogControl CLASS
     # #########################################################################
diff --git a/wizards/source/sfdialogs/SF_Dialog.xba 
b/wizards/source/sfdialogs/SF_Dialog.xba
index 20f1e81dc650..4979fa82a681 100644
--- a/wizards/source/sfdialogs/SF_Dialog.xba
+++ b/wizards/source/sfdialogs/SF_Dialog.xba
@@ -14,18 +14,22 @@ 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_Dialog
 &apos;&apos;&apos;     =========
-&apos;&apos;&apos;             Management of dialogs defined with the Basic IDE
+&apos;&apos;&apos;             Management of dialogs. They may bedefined with 
the Basic IDE or built from scratch
 &apos;&apos;&apos;             Each instance of the current class represents a 
single dialog box displayed to the user
 &apos;&apos;&apos;
 &apos;&apos;&apos;             A dialog box can be displayed in modal or in 
non-modal modes
-&apos;&apos;&apos;             In modal mode, the box is displayed and the 
execution of the macro process is suspended
-&apos;&apos;&apos;             until one of the OK or Cancel buttons is 
pressed. In the meantime, other user actions
-&apos;&apos;&apos;             executed on the box can trigger specific 
actions.
-&apos;&apos;&apos;             In non-modal mode, the dialog box is 
&quot;floating&quot; on the user desktop and the execution
-&apos;&apos;&apos;             of the macro process continues normally
-&apos;&apos;&apos;             A dialog box disappears from memory after its 
explicit termination.
+&apos;&apos;&apos;
+&apos;&apos;&apos;                     In modal mode, the box is displayed and 
the execution of the macro process is suspended
+&apos;&apos;&apos;                     until one of the OK or Cancel buttons 
is pressed. In the meantime, other user actions
+&apos;&apos;&apos;                     executed on the box can trigger 
specific actions.
+&apos;&apos;&apos;
+&apos;&apos;&apos;                     In non-modal mode, the dialog box is 
&quot;floating&quot; on the user desktop and the execution
+&apos;&apos;&apos;                     of the macro process continues normally
+&apos;&apos;&apos;                     A dialog box disappears from memory 
after its explicit termination.
 &apos;&apos;&apos;
 &apos;&apos;&apos;             Service invocation and usage:
+&apos;&apos;&apos;
+&apos;&apos;&apos;             1) when the dialog exists in some dialog 
libraries (= pre-defined with the Basic IDE):
 &apos;&apos;&apos;                     Dim myDialog As Object, lButton As Long
 &apos;&apos;&apos;                             Set myDialog = 
CreateScriptService(&quot;SFDialogs.Dialog&quot;, Container, Library, 
DialogName)
 &apos;&apos;&apos;                                     &apos;  Args:
@@ -42,6 +46,24 @@ Option Explicit
 &apos;&apos;&apos;                             End If
 &apos;&apos;&apos;                             myDialog.Terminate()
 &apos;&apos;&apos;
+&apos;&apos;&apos;             2) when the dialog is fully defined by code:
+&apos;&apos;&apos;                     Dim myDialog As Object, oButton As 
Object lExec As Long
+&apos;&apos;&apos;                             Set myDialog = 
CreateScriptService(&quot;SFDialogs.NewDialog&quot;, DialogName, Place)
+&apos;&apos;&apos;                                     &apos;  Args:
+&apos;&apos;&apos;                                     &apos;          
DialogName:     a case-sensitive string designating the dialog
+&apos;&apos;&apos;                                                     Place: 
either
+&apos;&apos;&apos;                                                     - an 
array with 4 elements: (X, Y, Width, Height)
+&apos;&apos;&apos;                                                     - a 
com.sun.star.awt.Rectangle [X, Y, Width, Height]
+&apos;&apos;&apos;                                                             
(All elements are expressed in &quot;Map AppFont&quot; units).
+&apos;&apos;&apos;                             &apos;  ... Create controls 
with the CreateXXX(...) methods ..., e.g.
+&apos;&apos;&apos;                             Set oButton = 
myDialog.CreateButton(&quot;OKButton&quot;, Place := Array(100, 100, 20, 10), 
Push := &quot;OK&quot;)
+&apos;&apos;&apos;                             lExec = myDialog.Execute()      
&apos;  Default mode = Modal
+&apos;&apos;&apos;                             If lExec = myDialog.OKBUTTON 
Then
+&apos;&apos;&apos;                                     &apos;  ... Process 
controls and do what is needed
+&apos;&apos;&apos;                             End If
+&apos;&apos;&apos;                             myDialog.Terminate()
+&apos;&apos;&apos;
+&apos;&apos;&apos;
 &apos;&apos;&apos;             Detailed user documentation:
 &apos;&apos;&apos;                     
https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_dialog.html?DbPAR=BASIC
 &apos;&apos;&apos;
@@ -63,6 +85,8 @@ Private ServiceName                   As String
 &apos; Dialog location
 Private _Container                     As String
 Private _Library                       As String
+Private _BuiltFromScratch      As Boolean              &apos; When True, 
dialog is not stored in a library
+Private _BuiltInPython         As Boolean              &apos; Used only when 
_BuiltFromScratch = True
 Private _Name                          As String
 Private _CacheIndex                    As Long                 &apos; Index in 
cache storage
 
@@ -145,6 +169,8 @@ Private Sub Class_Initialize()
        ServiceName = &quot;SFDialogs.Dialog&quot;
        _Container = &quot;&quot;
        _Library = &quot;&quot;
+       _BuiltFromScratch = False
+       _BuiltInPython = False
        _Name = &quot;&quot;
        _CacheIndex = -1
        Set _DialogProvider = Nothing
@@ -1895,7 +1921,8 @@ Try:
        Else
                _Modal = False
                _Displayed = True
-               _DialogModel.DesktopAsParent = True
+               &apos;  To make visible an on-the-fly designed dialog when 
macro triggered from Python
+               _DialogModel.DesktopAsParent = Not ( _BuiltFromScratch And 
_BuiltInPython )
                _DialogControl.setVisible(True)
                lExecute = 0
        End If
@@ -2600,7 +2627,8 @@ Check:
        If IsMissing(pbError) Then pbError = True
 
 Try:
-       bAlive = ( Not IsNull(_DialogProvider) And Not IsNull(_DialogControl) )
+       bAlive = ( Not IsNull(_DialogProvider) Or _BuiltFromScratch )
+       If bAlive Then bAlive = Not IsNull(_DialogControl)
        If Not bAlive Then GoTo Catch
 
 Finally:
diff --git a/wizards/source/sfdialogs/SF_Register.xba 
b/wizards/source/sfdialogs/SF_Register.xba
index e81dbb069fa8..d2986468ef95 100644
--- a/wizards/source/sfdialogs/SF_Register.xba
+++ b/wizards/source/sfdialogs/SF_Register.xba
@@ -56,9 +56,9 @@ Public Sub RegisterScriptServices() As Variant
 &apos;&apos;&apos;                             
&quot;libraryname.modulename.function&quot;
 
        With GlobalScope.ScriptForge.SF_Services
-               .RegisterService(&quot;Dialog&quot;,                            
&quot;SFDialogs.SF_Register._NewDialog&quot;)                   &apos;  
Reference to the function initializing the service
-               .RegisterEventManager(&quot;DialogEvent&quot;,  
&quot;SFDialogs.SF_Register._EventManager&quot;)                &apos;  
Reference to the events manager
-               &apos;TODO
+               .RegisterService(&quot;Dialog&quot;,                            
&quot;SFDialogs.SF_Register._NewDialog&quot;)                           &apos;  
Reference to the function initializing the service
+               .RegisterEventManager(&quot;DialogEvent&quot;,  
&quot;SFDialogs.SF_Register._EventManager&quot;)                        &apos;  
Reference to the events manager
+               .RegisterEventManager(&quot;NewDialog&quot;,            
&quot;SFDialogs.SF_Register._NewDialogFromScratch&quot;)        &apos;  
Reference to the function initializing the service
        End With
 
 End Sub                        &apos;  
SFDialogs.SF_Register.RegisterScriptServices
@@ -251,16 +251,18 @@ Const cstGlobal = &quot;GlobalScope&quot;
 
 Check:
        If IsMissing(pvArgs) Or IsEmpty(pvArgs) Then pvArgs = Array()
-       If Not IsArray(pvArgs) Then pvArgs = Array(pvArgs)              &apos;  
Needed when _NewDialog called from _EventManager
+       If Not IsArray(pvArgs) Then pvArgs = Array(pvArgs)
        If UBound(pvArgs) &gt;= 0 Then vContainer = pvArgs(0) Else vContainer = 
&quot;&quot;
        If UBound(pvArgs) &gt;= 1 Then vLibrary = pvArgs(1)
        If IsEmpty(vLibrary) Then vLibrary = &quot;Standard&quot;
        If UBound(pvArgs) &gt;= 2 Then vDialogName = pvArgs(2) Else vDialogName 
= Empty &apos;  Use Empty to force mandatory status
+
        If Not ScriptForge.SF_Utils._Validate(vContainer, 
&quot;Container&quot;, Array(V_STRING, ScriptForge.V_OBJECT)) Then GoTo Finally
        If Not ScriptForge.SF_Utils._Validate(vLibrary, &quot;Library&quot;, 
V_STRING) Then GoTo Finally
        If Not ScriptForge.SF_Utils._Validate(vDialogName, 
&quot;DialogName&quot;, V_STRING) Then GoTo Finally
-       If UBound(pvArgs) &gt;= 3 Then vContext = pvArgs(3) Else vContext = 
Nothing
-       If Not ScriptForge.SF_Utils._Validate(vContext, &quot;DialogName&quot;, 
V_OBJECT) Then GoTo Finally
+       If UBound(pvArgs) &gt;= 3 Then vContext = pvArgs(3) Else Set vContext = 
Nothing
+       If Not ScriptForge.SF_Utils._Validate(vContext, &quot;Context&quot;, 
ScriptForge.V_OBJECT) Then GoTo Finally
+
        Set oDialog = Nothing
 
 Try:
@@ -344,5 +346,109 @@ CatchNotFound:
        GoTo Finally
 End Function   &apos;  SFDialogs.SF_Register._NewDialog
 
+REM 
-----------------------------------------------------------------------------
+Private Function _NewDialogFromScratch(Optional ByVal pvArgs As Variant) As 
Object
+&apos;&apos;&apos;     Create a new instance of the SF_Dialog class describing 
a dynamically defined dialog box
+&apos;&apos;&apos;     Args:
+&apos;&apos;&apos;             DialogName: a symbolic name of the dialog to 
create, for information only. Not checked for unicity.
+&apos;&apos;&apos;             Place: either
+&apos;&apos;&apos;                     - an array with 4 elements: (X, Y, 
Width, Height)
+&apos;&apos;&apos;                     - a com.sun.star.awt.Rectangle [X, Y, 
Width, Height]
+&apos;&apos;&apos;                             All elements are expressed in 
&quot;Map AppFont&quot; units.
+&apos;&apos;&apos;             Context: When called from Python, the context 
must be provided : XSCRIPTCONTEXT
+&apos;&apos;&apos;     Returns: the instance or Nothing
+
+Dim oDialog As Object                          &apos;  Return value
+Dim vDialogName As Variant                     &apos;  The name is for 
information only
+Dim vPlace As variant                          &apos;  
com.sun.star.awt.rectangle or array(X, Y, Width, Height)
+Dim oPlace As Object                           &apos;  
com.sun.star.awt.rectangle
+Dim oProcessManager As Object          &apos;  
com.sun.star.lang.XMultiServiceFactory
+Dim bBuiltInPython As Boolean          &apos;  True when context is present
+Dim oModel As Object                           &apos;  
com.sun.star.awt.UnoControlDialogModel
+Dim oView As Object                                    &apos;  
com.sun.star.awt.UnoControlDialog
+Dim vContext As Variant                                &apos;  
com.sun.star.uno.XComponentContext
+
+Const cstDialogModel = &quot;com.sun.star.awt.UnoControlDialogModel&quot;
+Const cstDialogView = &quot;com.sun.star.awt.UnoControlDialog&quot;
+
+       If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+       If IsMissing(pvArgs) Or IsEmpty(pvArgs) Then pvArgs = Array()
+       If Not IsArray(pvArgs) Then pvArgs = Array(pvArgs)
+       If UBound(pvArgs) &gt;= 0 Then vDialogName = pvArgs(0) Else vDialogName 
= Empty
+       If UBound(pvArgs) &gt;= 1 Then vPlace = pvArgs(1) Else vPlace = Empty   
&apos;  Use Empty to force the mandatory status
+       If IsMissing(vDialogName) Or IsEmpty(vDialogName) Then vDialogName = 
&quot;DYNDIALOG&quot;
+       If UBound(pvArgs) &gt;= 2 Then vContext = pvArgs(2) Else Set vContext = 
Nothing
+
+       If Not ScriptForge.SF_Utils._Validate(vDialogName, 
&quot;DialogName&quot;, V_STRING) Then GoTo Finally
+       If IsArray(vPlace) Then
+               If Not ScriptForge.SF_Utils._ValidateArray(vPlace, 
&quot;Place&quot;, 1, ScriptForge.V_NUMERIC, True) Then GoTo Finally
+       Else
+               If Not ScriptForge.SF_Utils._Validate(vPlace, 
&quot;Place&quot;, ScriptForge.V_OBJECT) Then GoTo Finally
+       End If
+       If Not ScriptForge.SF_Utils._Validate(vContext, &quot;Context&quot;, 
ScriptForge.V_OBJECT) Then GoTo Finally
+
+       Set oDialog = Nothing
+
+Try:
+       &apos;  Determine the process service manager and create the dialog 
model
+       If IsNull(vContext)     Then                                            
&apos;  Basic
+               Set oprocessManager = GetProcessServiceManager()
+               Set oModel = oProcessManager.createInstance(cstDialogModel)
+               bBuiltInPython = False
+       Else                                                                    
                &apos;  Python
+               Set oprocessManager = vContext.getServiceManager()
+               Set oModel = 
oProcessManager.createInstanceWithContext(cstDialogModel, vContext)
+               bBuiltInPython = True
+       End If
+
+       oModel.Name = vDialogName
+
+       &apos;  Set dimension and position
+       With oModel
+               If IsArray(vPlace) Then
+                       If UBound(vPlace) = 3 Then
+                               .PositionX = vPlace(0)
+                               .PositionY = vPlace(1)
+                               .Width = vPlace(2)
+                               .Height = vPlace(3)
+                       End If
+               ElseIf ScriptForge.SF_Session.UnoObjectType(vPlace) = 
&quot;com.sun.star.awt.Rectangle&quot; Then
+                       Set oPlace = vPlace
+                       .PositionX = oPlace.X
+                       .PositionY = oPlace.Y
+                       .Width = oPlace.Width
+                       .Height = oPlace.Height
+               Else
+                       &apos;Leave everything to zero
+               End If
+       End With
+
+       &apos;  Create the view and associate model and view
+       Set oView = oprocessManager.createInstance(cstDialogView)
+       oView.setModel(oModel)
+
+       &apos;  Initialize the basic SF_Dialog instance to return to the user 
script
+       Set oDialog = New SF_Dialog
+       With oDialog
+               Set .[Me] = oDialog
+               ._Container = &quot;&quot;
+               ._Library = &quot;&quot;
+               ._BuiltFromScratch = True
+               ._BuiltInPython = bBuiltInPython
+               ._Name = vDialogName
+               Set ._DialogProvider = Nothing
+               Set ._DialogControl = oView
+               ._Initialize()
+       End With
+
+Finally:
+       Set _NewDialogFromScratch = oDialog
+       Exit Function
+Catch:
+       GoTo Finally
+End Function   &apos;  SFDialogs.SF_Register._NewDialogFromScratch
+
 REM ============================================== END OF SFDIALOGS.SF_REGISTER
 </script:module>
\ No newline at end of file

Reply via email to