wizards/source/scriptforge/SF_FileSystem.xba     |    6 
 wizards/source/scriptforge/SF_PythonHelper.xba   |   33 +++
 wizards/source/scriptforge/SF_Root.xba           |   31 +++
 wizards/source/scriptforge/SF_TextStream.xba     |    4 
 wizards/source/scriptforge/python/scriptforge.py |  195 ++++++++++++++++++++---
 5 files changed, 236 insertions(+), 33 deletions(-)

New commits:
commit 055ba7014587b09e0a3166f0cc8d61db0b358a1c
Author:     Jean-Pierre Ledure <j...@ledure.be>
AuthorDate: Tue Mar 9 11:37:07 2021 +0100
Commit:     Jean-Pierre Ledure <j...@ledure.be>
CommitDate: Tue Mar 9 15:36:32 2021 +0100

    ScriptForge - (scriptforge.py) FileSystem and TextStream classes
    
    Addition of SF_FileSystem and SF_TextStream classes
    
    Machinery tuning:
    - freeze a predefined list of standard modules
    in the python persistent storage
    - error management reviewed to mimic Basic behaviour on wrong
    arguments
    
    Standard modules are predefined in scriptforge.py as well
    
    Both lists must be synchronized on a hardcoded entry number
    
    Basic has minor revisions:
    - complex boolean expressions return -1 and 0 to Python
    i.o. True and False => Add a CBool() function
    - [User]TemplatesFolder properties of FileSystem omitted the final "/"
    
    Change-Id: Ice138de956f5f87269557cdb3db023849081b99d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112199
    Tested-by: Jean-Pierre Ledure <j...@ledure.be>
    Tested-by: Jenkins
    Reviewed-by: Jean-Pierre Ledure <j...@ledure.be>

diff --git a/wizards/source/scriptforge/SF_FileSystem.xba 
b/wizards/source/scriptforge/SF_FileSystem.xba
index f626eba6fd92..11ec24c67a61 100644
--- a/wizards/source/scriptforge/SF_FileSystem.xba
+++ b/wizards/source/scriptforge/SF_FileSystem.xba
@@ -188,7 +188,7 @@ Const cstThisSub = &quot;FileSystem.getTemplatesFolder&quot;
 
        SF_Utils._EnterFunction(cstThisSub)
        sPath = SF_Utils._GetUNOService(&quot;PathSettings&quot;).Template
-       TemplatesFolder = SF_FileSystem._ConvertFromUrl(Split(sPath, 
&quot;;&quot;)(0))
+       TemplatesFolder = SF_FileSystem._ConvertFromUrl(Split(sPath, 
&quot;;&quot;)(0) &amp; &quot;/&quot;)
        SF_Utils._ExitFunction(cstThisSub)
 
 End Property   &apos;  ScriptForge.SF_FileSystem.TemplatesFolder
@@ -214,7 +214,7 @@ Const cstThisSub = 
&quot;FileSystem.getUserTemplatesFolder&quot;
 
        SF_Utils._EnterFunction(cstThisSub)
        sPath = 
SF_Utils._GetUNOService(&quot;PathSettings&quot;).Template_writable
-       UserTemplatesFolder = SF_FileSystem._ConvertFromUrl(sPath)
+       UserTemplatesFolder = SF_FileSystem._ConvertFromUrl(sPath &amp; 
&quot;/&quot;)
        SF_Utils._ExitFunction(cstThisSub)
 
 End Property   &apos;  ScriptForge.SF_FileSystem.UserTemplatesFolder
@@ -934,7 +934,7 @@ CatchNotExists:
 End Function    &apos;   ScriptForge.SF_FileSystem.GetFileLen
 
 REM 
-----------------------------------------------------------------------------
-Public Function GetFileModified(Optional ByVal FileName As Variant) As Date
+Public Function GetFileModified(Optional ByVal FileName As Variant) As Variant
 &apos;&apos;&apos;     Returns the last modified date for the given file
 &apos;&apos;&apos;     Args:
 &apos;&apos;&apos;             FileName: a string representing an existing file
diff --git a/wizards/source/scriptforge/SF_PythonHelper.xba 
b/wizards/source/scriptforge/SF_PythonHelper.xba
index b90454dcd88d..c54d799ae282 100644
--- a/wizards/source/scriptforge/SF_PythonHelper.xba
+++ b/wizards/source/scriptforge/SF_PythonHelper.xba
@@ -557,6 +557,7 @@ Const cstNoArgs = &quot;+++NOARGS+++&quot;, cstSymEmpty = 
&quot;+++EMPTY+++&quot
 &apos; Determines the CallType
 Const vbGet = 2, vbLet = 4, vbMethod = 1, vbSet = 8
 &apos; Protocol flags
+Const cstDateRet = 128         &apos;  Return value can be a date
 Const cstArgArray = 512                &apos;  1st argument can be a 2D array
 Const cstRetArray = 1024       &apos;  Return value can be an array
 Const cstUno = 256                     &apos;  Return value can be a UNO object
@@ -580,7 +581,8 @@ Check:
                                If vArg = cstNoArgs Then Exit For
                        End If
                        If VarType(vArg) = V_STRING Then
-                               If vArg = cstSymEmpty Then
+                               If Len(vArg) = 0 Then
+                               ElseIf vArg = cstSymEmpty Then
                                        vArg = Empty
                                ElseIf vArg = cstSymNull Then
                                        vArg = Null
@@ -613,6 +615,11 @@ Try:
        &apos;          may be considered as properties when no argument
 &apos;                 Requires Python and Basic update in the concerned 
library but is transparent for this dispatcher
 
+       &apos;  Initialize Python persistent storage at 1st call
+       If IsEmpty(_SF_.PythonStorage) Then _SF_._InitPythonStorage()
+       &apos;  Reset any error
+       _SF_._Stackreset()
+
        Select case VarType(BasicObject)
                Case V_STRING
                        &apos;  Special entry for CreateScriptService()
@@ -644,9 +651,18 @@ Try:
                        bBasicClass = ( Left(sObjectType, 3) &lt;&gt; 
&quot;SF_&quot; )
                        sLibrary = Split(vBasicObject.ServiceName, 
&quot;.&quot;)(0)
                        
+                       &apos;  Methods in standard modules returning a date 
are hardcoded as exceptions
+                       If Not bBasicClass And ((CallType And vbMethod) = 
vbMethod) And ((CallType And cstDateRet) = cstDateRet) Then
+                               Select Case sLibrary
+                                       Case &quot;ScriptForge&quot;
+                                               If sObjectType = 
&quot;SF_FileSystem&quot; And Script = &quot;GetFileModified&quot; Then vReturn 
= SF_FileSystem.GetFileModified(vArgs(0))
+                               End Select
+
                        &apos;  Methods in usual modules are called by 
ExecuteBasicScript() except if they use a ParamArray
-                       If Not bBasicClass And (CallType And vbMethod) = 
vbMethod Then
+                       ElseIf Not bBasicClass And (CallType And vbMethod) = 
vbMethod Then
                                sScript = sLibrary &amp; &quot;.&quot; &amp; 
sObjectType &amp; &quot;.&quot; &amp; Script
+                               &apos;  Force validation in targeted function, 
not in ExecuteBasicScript()
+                               _SF_.StackLevel = -1
                                Select Case UBound(vArgs)
                                        Case -1 :       vReturn = 
sess.ExecuteBasicScript(, sScript)
                                        Case 0  :       vReturn = 
sess.ExecuteBasicScript(, sScript, vArgs(0))
@@ -658,6 +674,7 @@ Try:
                                        Case 6  :       vReturn = 
sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3), 
vArgs(4), vArgs(5), vArgs(6))
                                        Case 7  :       vReturn = 
sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3), 
vArgs(4), vArgs(5), vArgs(6), vArgs(7))
                                End Select
+                               _SF_.StackLevel = 0
                        
                        &apos;  Properties in any service are got and set with 
obj.GetProperty/SetProperty(...)
                        ElseIf (CallType And vbGet) = vbGet Then
@@ -677,8 +694,6 @@ Try:
                        ElseIf bBasicClass And ((CallType And vbMethod) = 
vbMethod) Then
                                Select Case UBound(vArgs)
                                        Case -1 :       vReturn = 
CallByName(vBasicObject, Script, vbMethod)
-                                               &apos;  Special case: Dispose() 
must update the cache for class objects created in Python scripts
-                                               If Script = &quot;Dispose&quot; 
Then Set _SF_.PythonStorage(BasicObject) = Nothing
                                        Case 0  :       vReturn = 
CallByName(vBasicObject, Script, vbMethod, vArgs(0))
                                        Case 1  :       vReturn = 
CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1))
                                        Case 2  :       vReturn = 
CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2))
@@ -689,6 +704,12 @@ Try:
                                        Case 7  :       vReturn = 
CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), 
vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7))
                                End Select
                        End If
+
+                       &apos;  Post processing
+                       If Script = &quot;Dispose&quot; Then
+                               &apos;  Special case: Dispose() must update the 
cache for class objects created in Python scripts
+                               Set _SF_.PythonStorage(BasicObject) = Nothing
+                       End If
                Case Else
        End Select
        
@@ -725,7 +746,7 @@ Try:
                End If
        Else    &apos;  Scalar or Nothing
                ReDim vReturnArray(0 To 1)
-               vReturnArray(0) = vReturn
+               If VarType(vReturn) = V_DATE Then vReturnArray(0) = 
SF_Utils._CDateToIso(vReturn) Else vReturnArray(0) = vReturn
                vReturnArray(1) = VarType(vReturn)
        End If
 
@@ -749,4 +770,4 @@ Private Function _Repr() As String
 End Function   &apos;  ScriptForge.SF_PythonHelper._Repr
 
 REM ================================================= END OF 
SCRIPTFORGE.SF_PythonHelper
-</script:module>
+</script:module>
\ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_Root.xba 
b/wizards/source/scriptforge/SF_Root.xba
index 379cb3586a2b..fcbba9039596 100644
--- a/wizards/source/scriptforge/SF_Root.xba
+++ b/wizards/source/scriptforge/SF_Root.xba
@@ -74,6 +74,7 @@ Private OSName                                As String       
&apos; WIN, LINUX, MACOS
 Private SFDialogs                      As Variant      &apos; Persistent 
storage for the SFDialogs library
 Private SFForms                                As Variant      &apos; 
Persistent storage for the SF_Form class in the SFDocuments library
 Private PythonStorage          As Variant      &apos; Persistent storage for 
the objects created and processed in Python
+Private PythonPermanent                As Long         &apos; Number of 
permanent entries in PythonStorage containing standard module objects
 
 REM ====================================================== 
CONSTRUCTOR/DESTRUCTOR
 
@@ -122,6 +123,7 @@ Private Sub Class_Initialize()
        SFDialogs = Empty
        SFForms = Empty
        PythonStorage = Empty
+       PythonPermanent = -1
 End Sub                &apos;  ScriptForge.SF_Root Constructor
 
 REM 
-----------------------------------------------------------------------------
@@ -186,12 +188,11 @@ Check:
        lIndex = -1
        If IsNull(poObject) Then Exit Function
        On Local Error GoTo Finally
-       If IsEmpty(PythonStorage) Then PythonStorage = Array()
        lSize = UBound(PythonStorage)
 
 Try:
        &apos;  Can an empty entry be reused ?
-       For i = 0 To lSize
+       For i = PythonPermanent + 1 To lSize
                If IsNull(PythonStorage(i)) Then
                        lIndex = i
                        Exit For
@@ -213,6 +214,32 @@ Finally:
        Exit Function
 End Function   &apos;  ScriptForge.SF_Root._AddToPythonStorage
 
+REM 
-----------------------------------------------------------------------------
+Public Sub _InitPythonStorage()
+&apos;&apos;&apos;     Make PythonStorage an array
+&apos;&apos;&apos;     In prevision to an abundant use of those objects in 
Python, hardcode to optimize the performance and memory :
+&apos;&apos;&apos;     Initialize the first entries with the standard module 
objects located in the ScriptForge library
+
+Try:
+       If Not IsArray(PythonStorage) Then
+               PythonPermanent = 7
+               PythonStorage = Array()
+               ReDim PythonStorage(0 To PythonPermanent)
+               &apos;  Initialize each entry
+               PythonStorage(0) = ScriptForge.SF_Array
+               PythonStorage(1) = ScriptForge.SF_Exception
+               PythonStorage(2) = ScriptForge.SF_FileSystem
+               PythonStorage(3) = ScriptForge.SF_Platform
+               PythonStorage(4) = ScriptForge.SF_Services
+               PythonStorage(5) = ScriptForge.SF_Session
+               PythonStorage(6) = ScriptForge.SF_String
+               PythonStorage(7) = ScriptForge.SF_UI
+       End If
+
+Finally:
+       Exit Sub
+End Sub                &apos;  ScriptForge.SF_Root._InitPythonStorage
+
 REM 
-----------------------------------------------------------------------------
 Public Sub _LoadLocalizedInterface(Optional ByVal psMode As String)
 &apos;&apos;&apos;     Build the user interface in a persistent L10N object
diff --git a/wizards/source/scriptforge/SF_TextStream.xba 
b/wizards/source/scriptforge/SF_TextStream.xba
index bb8ea78486f6..27ff3d9bb4c9 100644
--- a/wizards/source/scriptforge/SF_TextStream.xba
+++ b/wizards/source/scriptforge/SF_TextStream.xba
@@ -499,7 +499,7 @@ Public Sub WriteBlankLines(Optional ByVal Lines As Variant)
 &apos;&apos;&apos;     Returns:
 &apos;&apos;&apos;     Exceptions:
 &apos;&apos;&apos;             FILENOTOPENERROR                File not open 
or already closed
-&apos;&apos;&apos;             FILEOPENMODEERROR               File opened in 
in read mode
+&apos;&apos;&apos;             FILEOPENMODEERROR               File opened in 
read mode
 &apos;&apos;&apos;     Examples:
 &apos;&apos;&apos;                     myFile.WriteBlankLines(10)
 Dim i As Long
@@ -657,7 +657,7 @@ Dim cstSubArgs As String
                Case UCase(&quot;AtEndOfStream&quot;)
                        Select Case _IOMode
                                Case SF_FileSystem.ForReading
-                                       If IsNull(_InputStream) Then 
_PropertyGet = True Else _PropertyGet = _InputStream.isEOF() And Not 
_ForceBlankLine
+                                       If IsNull(_InputStream) Then 
_PropertyGet = True Else _PropertyGet = CBool(_InputStream.isEOF() And Not 
_ForceBlankLine)
                                Case Else       :       _PropertyGet = True
                        End Select
                Case UCase(&quot;Encoding&quot;)
diff --git a/wizards/source/scriptforge/python/scriptforge.py 
b/wizards/source/scriptforge/python/scriptforge.py
index fd1b3e0df957..a131329308bb 100644
--- a/wizards/source/scriptforge/python/scriptforge.py
+++ b/wizards/source/scriptforge/python/scriptforge.py
@@ -56,7 +56,6 @@
 
 import uno
 
-from platform import system as _opsys
 import datetime
 import os
 
@@ -106,6 +105,8 @@ class ScriptForge(object, metaclass = _Singleton):
     #
     # Basic dispatcher for Python scripts
     basicdispatcher = 'ScriptForge.SF_PythonHelper._PythonDispatcher'
+    # Python helper functions module
+    pythonhelpermodule = 'ScriptForgeHelper.py'
     #
     # VarType() constants
     V_EMPTY, V_NULL, V_INTEGER, V_LONG, V_SINGLE, V_DOUBLE = 0, 1, 2, 3, 4, 5
@@ -115,6 +116,15 @@ class ScriptForge(object, metaclass = _Singleton):
     objMODULE, objCLASS, objUNO = 1, 2, 3
     # Special argument symbols
     cstSymEmpty, cstSymNull, cstSymMissing = '+++EMPTY+++', '+++NULL+++', 
'+++MISSING+++'
+    # Predefined references for services implemented as standard Basic modules
+    servicesmodules = dict([('ScriptForge.Array', 0),
+                            ('ScriptForge.Exception', 1),
+                            ('ScriptForge.FileSystem', 2),
+                            ('ScriptForge.Platform', 3),
+                            ('ScriptForge.Services', 4),
+                            ('ScriptForge.Session', 5),
+                            ('ScriptForge.String', 6),
+                            ('ScriptForge.UI', 7)])
 
     def __init__(self, hostname = '', port = 0):
         """
@@ -266,17 +276,19 @@ class ScriptForge(object, metaclass = _Singleton):
             if returntuple[cstClass] == ScriptForge.objUNO:
                 pass
             else:
-                # Create the new class instance of the right subclass of 
Service()
+                # Create the new class instance of the right subclass of 
SFServices()
                 servname = returntuple[cstService]
-                for subcls in SFServices.__subclasses__():
-                    if servname == subcls.servicename:
-                       return subcls(returntuple[cstValue], 
returntuple[cstType], returntuple[cstClass],
-                                      returntuple[cstName])
+                subcls = cls.serviceslist[servname]
+                if subcls is not None:
+                    return subcls(returntuple[cstValue], returntuple[cstType], 
returntuple[cstClass],
+                                  returntuple[cstName])
                 # When service not found
                 raise RuntimeError("The service '" + servname + "' is not 
available in Python. Execution stops.")
         elif returntuple[cstVarType] >= ScriptForge.V_ARRAY:
             pass
-        else:         # All scalar values
+        elif returntuple[cstVarType] == ScriptForge.V_DATE:
+            return datetime.datetime.fromisoformat(returntuple[cstValue])
+        else:         # All other scalar values
             pass
         return returntuple[cstValue]
 
@@ -340,6 +352,7 @@ class SFServices(object):
         """
     # Python-Basic protocol constants and flags
     vbGet, vbLet, vbMethod, vbSet = 2, 4, 1, 8  # CallByName constants
+    flgDateRet = 128  # Invoked service method can return a date
     flgArrayArg = 512  # 1st argument can be a 2D array
     flgArrayRet = 1024  # Invoked service method can return an array
     flgUno = 256  # Invoked service method/property can return a UNO object
@@ -409,7 +422,7 @@ class SFServices(object):
 
     def Dispose(self):
         if self.serviceimplementation == 'basic':
-            if self.classmodule == self.moduleClass and self.objectreference 
>= 0:
+            if self.objectreference >= 0:
                 self.Execute(self.vbMethod, 'Dispose')
                 self.objectreference = -1
 
@@ -425,6 +438,9 @@ class SFServices(object):
             """
         return self.EXEC(self.objectreference, self.vbGet, propertyname)
 
+    def Properties(self):
+        return list(self.serviceProperties)
+
     def SetProperty(self, propertyname, value):
         """
             Set the given property to a new value in the Basic world
@@ -442,7 +458,7 @@ class SFScriptForge:
     class SF_Basic(SFServices, metaclass = _Singleton):
         """
             This service proposes a collection of Basic methods to be executed 
in a Python context
-            to simulate the exact syntax and behaviour of the identical Basic 
builtin method.
+            simulating the exact syntax and behaviour of the identical Basic 
builtin method.
             Typical example:
                 SF_Basic.MsgBox('This has to be displayed in a message box')
             """
@@ -495,16 +511,16 @@ class SFScriptForge:
                 value = value.isoformat()
             return self.SIMPLEEXEC(self.module + '.PyFormat', value, pattern)
 
+        @staticmethod
+        def GetDefaultContext():
+            return ScriptForge.componentcontext
+
         def GetGuiType(self):
             return self.SIMPLEEXEC(self.module + '.PyGetGuiType')
 
         def GetSystemTicks(self):
             return self.SIMPLEEXEC(self.module + '.PyGetSystemTicks')
 
-        @staticmethod
-        def GetDefaultContext():
-            return ScriptForge.componentcontext
-
         @staticmethod
         def GetPathSeparator():
             return os.sep
@@ -512,11 +528,11 @@ class SFScriptForge:
         class GlobalScope(object, metaclass = _Singleton):
             @classmethod  # Mandatory because the GlobalScope class is 
normally not instantiated
             def BasicLibraries(cls):
-                return 
SFScriptForge.SF_Basic().SIMPLEEXEC(SFScriptForge.SF_Basic.module + 
'.PyGlobalScope', 'Basic')
+                return 
ScriptForge.InvokeSimpleScript(SFScriptForge.SF_Basic.module + 
'.PyGlobalScope', 'Basic')
 
             @classmethod
             def DialogLibraries(cls):
-                return 
SFScriptForge.SF_Basic().SIMPLEEXEC(SFScriptForge.SF_Basic.module + 
'.PyGlobalScope', 'Dialog')
+                return 
ScriptForge.InvokeSimpleScript(SFScriptForge.SF_Basic.module + 
'.PyGlobalScope', 'Dialog')
 
         def InputBox(self, msg, title = '', default = '', xpos = -1, ypos = 
-1):
             if xpos < 0 or ypos < 0:
@@ -563,6 +579,8 @@ class SFScriptForge:
         serviceProperties = dict(FileNaming = True, ConfigFolder = False, 
ExtensionsFolder = False, HomeFolder = False,
                                  InstallFolder = False, TemplatesFolder = 
False, TemporaryFolder = False,
                                  UserTemplatesFolder = False)
+        # Open TextStream constants
+        ForReading, ForWriting, ForAppending = 1, 2, 8
 
         @property
         def ConfigFolder(self):
@@ -571,9 +589,139 @@ class SFScriptForge:
         def BuildPath(self, foldername, name):
             return self.Execute(self.vbMethod, 'BuildPath', foldername, name)
 
+        def CompareFiles(self, filename1, filename2, comparecontents = False):
+            py = ScriptForge.pythonhelpermodule + '$' + 
'_SF_FileSystem__CompareFiles'
+            if self.FileExists(filename1) and self.FileExists(filename2):
+                file1 = self._ConvertFromUrl(filename1)
+                file2 = self._ConvertFromUrl(filename2)
+                return self.SIMPLEEXEC(py, file1, file2, comparecontents)
+            else:
+                return False
+
+        def CopyFile(self, source, destination, overwrite = True):
+            return self.Execute(self.vbMethod, 'CopyFile', source, 
destination, overwrite)
+
+        def CopyFolder(self, source, destination, overwrite = True):
+            return self.Execute(self.vbMethod, 'CopyFolder', source, 
destination, overwrite)
+
+        def CreateFolder(self, foldername):
+            return self.Execute(self.vbMethod, 'CreateFolder', foldername)
+
+        def CreateTextFile(self, filename, overwrite = True, encoding = 
'UTF-8'):
+            return self.Execute(self.vbMethod, 'CreateTextFile', filename, 
overwrite, encoding)
+
+        def DeleteFile(self, filename):
+            return self.Execute(self.vbMethod, 'DeleteFile', filename)
+
+        def DeleteFolder(self, foldername):
+            return self.Execute(self.vbMethod, 'DeleteFolder', foldername)
+
+        def FileExists(self, filename):
+            return self.Execute(self.vbMethod, 'FileExists', filename)
+
+        def Files(self, foldername, filter = ''):
+            return self.Execute(self.vbMethod + self.flgArrayRet, 'Files', 
foldername, filter)
+
         def FolderExists(self, foldername):
             return self.Execute(self.vbMethod, 'FolderExists', foldername)
 
+        def GetBaseName(self, filename):
+            return self.Execute(self.vbMethod, 'GetBaseName', filename)
+
+        def GetExtension(self, filename):
+            return self.Execute(self.vbMethod, 'GetExtension', filename)
+
+        def GetFileLen(self, filename):
+            py = ScriptForge.pythonhelpermodule + '$' + 
'_SF_FileSystem__GetFilelen'
+            if self.FileExists(filename):
+                file = self._ConvertFromUrl(filename)
+                return int(self.SIMPLEEXEC(py, file))
+            else:
+                return 0
+
+        def GetFileModified(self, filename):
+            return self.Execute(self.vbMethod + self.flgDateRet, 
'GetFileModified', filename)
+
+        def GetName(self, filename):
+            return self.Execute(self.vbMethod, 'GetName', filename)
+
+        def GetParentFolderName(self, filename):
+            return self.Execute(self.vbMethod, 'GetParentFolderName', filename)
+
+        def GetTempName(self):
+            return self.Execute(self.vbMethod, 'GetTempName')
+
+        def HashFile(self, filename, algorithm):
+            py = ScriptForge.pythonhelpermodule + '$' + 
'_SF_FileSystem__HashFile'
+            if self.FileExists(filename):
+                file = self._ConvertFromUrl(filename)
+                return self.SIMPLEEXEC(py, file, algorithm.lower())
+            else:
+                return ''
+
+        def MoveFile(self, source, destination):
+            return self.Execute(self.vbMethod, 'MoveFile', source, destination)
+
+        def MoveFolder(self, source, destination):
+            return self.Execute(self.vbMethod, 'MoveFolder', source, 
destination)
+
+        def OpenTextFile(self, filename, iomode = 1, create = False, encoding 
= 'UTF-8'):
+            return self.Execute(self.vbMethod, 'OpenTextFile', filename, 
iomode, create, encoding)
+
+        def PickFile(self, defaultfile = ScriptForge.cstSymEmpty, mode = 
'OPEN', filter = ''):
+            return self.Execute(self.vbMethod, 'PickFile', defaultfile, mode, 
filter)
+
+        def PickFolder(self, defaultfolder = ScriptForge.cstSymEmpty, freetext 
= ''):
+            return self.Execute(self.vbMethod, 'PickFolder', defaultfolder, 
freetext)
+
+        def SubFolders(self, foldername, filter = ''):
+            return self.Execute(self.vbMethod + self.flgArrayRet, 
'SubFolders', foldername, filter)
+
+        def _ConvertFromUrl(self, filename):
+            # Alias for same function in FileSystem Basic module
+            return 
self.SIMPLEEXEC('ScriptForge.SF_FileSystem._ConvertFromUrl', filename)
+
+    # #########################################################################
+    # SF_TextStream CLASS
+    # #########################################################################
+    class SF_TextStream(SFServices):
+        """
+            The TextStream service is used to sequentially read from and write 
to files opened or created
+            using the ScriptForge.FileSystem service..
+            """
+        # Mandatory class properties for service registration
+        serviceimplementation = 'basic'
+        servicename = 'ScriptForge.TextStream'
+        serviceProperties = dict(AtEndOfStream = False, Encoding = False, 
FileName = False,
+                                 IOMode = False, Line = False, NewLine = True)
+
+        @property
+        def AtEndOfStream(self):
+            return self.GetProperty('AtEndOfStream')
+
+        @property
+        def Line(self):
+            return self.GetProperty('Line')
+
+        def CloseFile(self):
+            return self.Execute(self.vbMethod, 'CloseFile')
+
+        def ReadAll(self):
+            return self.Execute(self.vbMethod, 'ReadAll')
+
+        def ReadLine(self):
+            return self.Execute(self.vbMethod, 'ReadLine')
+
+        def SkipLine(self):
+            return self.Execute(self.vbMethod, 'SkipLine')
+
+        def WriteBlankLines(self, lines):
+            return self.Execute(self.vbMethod, 'WriteBlankLines', lines)
+
+        def WriteLine(self, line):
+            return self.Execute(self.vbMethod, 'WriteLine', line)
+
+
     # #########################################################################
     # SF_Timer CLASS
     # #########################################################################
@@ -640,21 +788,27 @@ def CreateScriptService(service, *args):
 
     def ResolveSynonyms(servicename):
         """
-            Synonyms within service names implemented in Python are resolved 
here
+            Synonyms within service names implemented in Python or predefined 
are resolved here
             :param servicename: The short name of the service
             :return: The official service name
             """
         if servicename.lower() in ('basic', 'scriptforge.basic'):
             return 'ScriptForge.Basic'
+        if servicename.lower() in ('filesystem', 'scriptforge.filesystem'):
+            return 'ScriptForge.FileSystem'
         return servicename
 
     #
-    # Check the list of available services to examine if the requested service 
is within the Python world
+    # Check the list of available services
     scriptservice = ResolveSynonyms(service)
     if scriptservice in ScriptForge.serviceslist:
         serv = ScriptForge.serviceslist[scriptservice]
+        # Check if the requested service is within the Python world
         if serv.serviceimplementation == 'python':
             return serv()
+        # Check if the service is a predefined standard Basic service
+        elif scriptservice in ScriptForge.servicesmodules:
+            return serv(ScriptForge.servicesmodules[scriptservice], 
classmodule = SFServices.moduleStandard)
     # The requested service is to be found in the Basic world
     if len(args) == 0:
         serv = ScriptForge.InvokeBasicService('SF_Services', 
SFServices.vbMethod, 'CreateScriptService', service)
@@ -662,15 +816,16 @@ def CreateScriptService(service, *args):
         serv = ScriptForge.InvokeBasicService('SF_Services', 
SFServices.vbMethod, 'CreateScriptService', service, *args)
     return serv
 
+
 # 
#####################################################################################################################
 #                           Services shortcuts                                 
                                     ###
 # 
#####################################################################################################################
-# SF_Basic = CreateScriptService('SFPython.Basic')
-# SF_String = _ScriptForge.SF_String
+SF_Basic = SFScriptForge.SF_Basic()
+# SF_String = None
 
 
 # ######################################################################
-# lists the scripts, that shall be visible inside the Basic/Python IDE
+# Lists the scripts, that shall be visible inside the Basic/Python IDE
 # ######################################################################
 
 g_exportedScripts = ()
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to