wizards/Package_scriptforge.mk | 1 wizards/source/scriptforge/SF_PythonHelper.xba | 11 wizards/source/scriptforge/SF_Root.xba | 17 wizards/source/scriptforge/SF_Services.xba | 47 +- wizards/source/scriptforge/SF_Session.xba | 6 wizards/source/scriptforge/SF_SharedMemory.xba | 468 ++++++++++++++++++++++ wizards/source/scriptforge/python/scriptforge.py | 43 +- wizards/source/scriptforge/python/scriptforge.pyi | 84 +++ wizards/source/scriptforge/script.xlb | 21 9 files changed, 648 insertions(+), 50 deletions(-)
New commits: commit e79a47409f2cae3485ed9e0399ed15a60b66a3ac Author: Jean-Pierre Ledure <j...@ledure.be> AuthorDate: Mon Aug 25 15:01:44 2025 +0200 Commit: Jean-Pierre Ledure <j...@ledure.be> CommitDate: Mon Aug 25 16:24:31 2025 +0200 ScriptForge - new SharedMemory service Singleton class implementing the "ScriptForge.SharedMemory" service. Implemented as a usual Basic module. Contains the mechanisms to manage persistent memory storage across Basic and/or Python scripts. When a script stops running, all the variables it uses vanish, except Basic Global variables, which stay in memory until the end of the LibreOffice session. However event-driven scripting can often benefit from having variables still being available when the next script is triggered, probably due to a user action. The SharedMemory service implements interfaces allowing to store both BASIC and PYTHON variables in persistent storage, and to retrieve them later from either BASIC or PYTHON scripts interchangeably. The use of the Basic Global statement is more efficient than the actual service and should be preferred when the variables are created and retrieved in basic scripts only. The supported variable types are: * Scalar or tuple combining: - int, within the bounds of the Basic Long type - float, within the bounds of the Basic Double type - str - bool - None * datetime.datetime * UNO object * ScriptForge class instance Example: Sub CreateDoc() ui = CreateScriptService("UI") doc = ui.CreateDocument("Calc") store = CreateScriptService("SharedMemory") store.StoreValue(doc, "actualdocument") ... def UpdateDoc(): store = CreateScriptService("SharedMemory") doc = store.ReadValue("actualdocument") ... The service is available both for Basic and Python scripts. The actual commit requires the creation of an additional Help page. Change-Id: Id53994be5105206c16659f769338261b3dde2d3a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190174 Reviewed-by: Jean-Pierre Ledure <j...@ledure.be> Tested-by: Jenkins diff --git a/wizards/Package_scriptforge.mk b/wizards/Package_scriptforge.mk index cb1e4d8fb3d2..6581c77bc586 100644 --- a/wizards/Package_scriptforge.mk +++ b/wizards/Package_scriptforge.mk @@ -31,6 +31,7 @@ $(eval $(call gb_Package_add_files,wizards_basicsrvscriptforge,$(LIBO_SHARE_FOLD SF_Root.xba \ SF_Services.xba \ SF_Session.xba \ + SF_SharedMemory.xba \ SF_String.xba \ SF_TextStream.xba \ SF_Timer.xba \ diff --git a/wizards/source/scriptforge/SF_PythonHelper.xba b/wizards/source/scriptforge/SF_PythonHelper.xba index 4de5bf74d44e..085d5ff639af 100644 --- a/wizards/source/scriptforge/SF_PythonHelper.xba +++ b/wizards/source/scriptforge/SF_PythonHelper.xba @@ -1021,16 +1021,5 @@ Catch: GoTo Finally End Function ' ScriptForge.SF_PythonHelper._PythonDispatcher -REM ----------------------------------------------------------------------------- -Private Function _Repr() As String -''' Convert the Basic instance to a readable string, typically for debugging purposes (DebugPrint ...) -''' Args: -''' Return: -''' "[PythonHelper]" - - _Repr = "[PythonHelper]" - -End Function ' ScriptForge.SF_PythonHelper._Repr - REM ================================================= END OF SCRIPTFORGE.SF_PythonHelper </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 ddc84b41c7a5..f0db856873c8 100644 --- a/wizards/source/scriptforge/SF_Root.xba +++ b/wizards/source/scriptforge/SF_Root.xba @@ -74,14 +74,14 @@ Private URLTransformer As Object ' com.sun.star.util.URLTransformer Private Introspection As Object ' com.sun.star.beans.Introspection Private BrowseNodeFactory As Object ' com.sun.star.script.browse.BrowseNodeFactory Private DatabaseContext As Object ' com.sun.star.sdb.DatabaseContext -Private ConfigurationProvider As Object - ' com.sun.star.configuration.ConfigurationProvider +Private ConfigurationProvider _ + As Object ' com.sun.star.configuration.ConfigurationProvider Private PackageProvider As Object ' com.sun.star.comp.deployment.PackageInformationProvider Private MailService As Object ' com.sun.star.system.SimpleCommandMail or com.sun.star.system.SimpleSystemMail Private GraphicExportFilter As Object ' com.sun.star.drawing.GraphicExportFilter Private Toolkit As Object ' com.sun.star.awt.Toolkit -Private ModuleUIConfigurationManagerSupplier As Object - ' com.sun.star.ui.ModuleUIConfigurationManagerSupplier +Private ModuleUIConfigurationManagerSupplier _ + As Object ' com.sun.star.ui.ModuleUIConfigurationManagerSupplier Private TransientDocument As Object ' com.sun.star.frame.TransientDocumentsDocumentContentFactory ' Specific persistent services objects or properties @@ -94,6 +94,7 @@ Private SFDialogs As Variant ' Persistent storage for the SFDialogs libra Private SFForms As Variant ' Persistent storage for the SF_Form class in the SFDocuments library Private PythonStorage As Variant ' Persistent storage for the objects created and processed in Python Private PythonPermanent As Long ' Number of permanent entries in PythonStorage containing standard module objects +Private GlobalStorage As Object ' Dictionary of storage shared between Basic and Python REM ====================================================== CONSTRUCTOR/DESTRUCTOR @@ -159,6 +160,7 @@ Private Sub Class_Initialize() SFForms = Empty PythonStorage = Empty PythonPermanent = -1 + Set GlobalStorage = Nothing End Sub ' ScriptForge.SF_Root Constructor REM ----------------------------------------------------------------------------- @@ -271,7 +273,7 @@ Public Sub _InitPythonStorage() Try: If Not IsArray(PythonStorage) Then - PythonPermanent = 8 + PythonPermanent = 9 PythonStorage = Array() ReDim PythonStorage(0 To PythonPermanent) ' Initialize each entry @@ -282,8 +284,9 @@ Try: PythonStorage(4) = ScriptForge.SF_Region PythonStorage(5) = ScriptForge.SF_Services PythonStorage(6) = ScriptForge.SF_Session - PythonStorage(7) = ScriptForge.SF_String - PythonStorage(8) = ScriptForge.SF_UI + PythonStorage(7) = ScriptForge.SF_SharedMemory + PythonStorage(8) = ScriptForge.SF_String + PythonStorage(9) = ScriptForge.SF_UI End If Finally: diff --git a/wizards/source/scriptforge/SF_Services.xba b/wizards/source/scriptforge/SF_Services.xba index ebf8ef215318..42c62784193c 100644 --- a/wizards/source/scriptforge/SF_Services.xba +++ b/wizards/source/scriptforge/SF_Services.xba @@ -13,20 +13,34 @@ Option Explicit ''' =========== ''' Singleton class implementing the "ScriptForge.Services" service ''' Implemented as a usual Basic module -''' The ScriptForge framework includes -''' the current ScriptForge library -''' a number of "associated" libraries -''' any user/contributor extension wanting to fit into the framework +''' +''' The modules and classes implemented in ScriptForge will be invoked +''' from user scripts as "Services". +''' +''' A generic constructor of those services has been designed for that purpose: +''' CreateScriptService("servicename"[, arg0, arg1, ...]) +''' All top-level services are created through this mechanism. +''' +''' To become a candidate for incorporation into ScriptForge, a library of services +''' must register its services by implementing a +''' RegisterScriptServices(...) +''' method. This method must be present in any external library wanting to extend +''' the set of available services. +''' +''' Above mechanisms make ScriptForge an easily extensible ecosystem combining a core library, +''' additional standard libraries and libraries published as extensions or distributed +''' as company extensions. +''' ''' The methods in this module constitute the kernel of the ScriptForge framework -''' - RegisterScriptServices -''' Register for a library the list of services it implements -''' Each library in the framework must implement its own RegisterScriptServices method +''' RegisterScriptServices() +''' Register for a library the list of services it implements. +''' Each library in the framework must implement its own RegisterScriptServices() method. ''' This method consists in a series of invocations of next 2 methods -''' - RegisterService -''' Register a single service -''' - RegisterEventManager -''' Register a single event manager -''' - CreateScriptService +''' RegisterService() +''' Register a single service +''' RegisterEventManager() +''' Register a single event manager +''' CreateScriptService() ''' Called by user scripts to get an object giving access to a service or to the event manager ''' ''' Detailed user documentation: @@ -84,12 +98,12 @@ Public Function CreateScriptService(Optional ByRef Service As Variant _ ''' UNKNOWNSERVICEERROR Service not found ''' Examples ''' CreateScriptService("Array") -''' => Refers to ScriptForge.Array or SF_Array -''' CreateScriptService("ScriptForge.Dictionary") +''' => Refers to "ScriptForge.Array", i.e. the ScriptForge.SF_Array module +''' CreateScriptService("ScriptForge.Dictionary", ...) ''' => Returns a new empty dictionary; "ScriptForge." is optional -''' CreateScriptService("SFDocuments.Calc") +''' CreateScriptService("SFDocuments.Calc", ...) ''' => Refers to the Calc service, implemented in the SFDocuments library -''' CreateScriptService("Dialog", dlgName) +''' CreateScriptService("Dialog", dlgName, ...) ''' => Returns a Dialog instance referring to the dlgName dialog ''' CreateScriptService("SFDocuments.Event", oEvent) ''' => Refers to the Document service instance, implemented in the SFDocuments library, having triggered the event @@ -301,6 +315,7 @@ Public Sub RegisterScriptServices() As Variant .RegisterService("Platform", GlobalScope.ScriptForge.SF_Platform) .RegisterService("Region", GlobalScope.ScriptForge.SF_Region) .RegisterService("Session", GlobalScope.ScriptForge.SF_Session) + .RegisterService("SharedMemory", GlobalScope.ScriptForge.SF_SharedMemory) .RegisterService("String", GlobalScope.ScriptForge.SF_String) .RegisterService("Timer", "ScriptForge.SF_Services._NewTimer") .RegisterService("UI", GlobalScope.ScriptForge.SF_UI) diff --git a/wizards/source/scriptforge/SF_Session.xba b/wizards/source/scriptforge/SF_Session.xba index ce89fb8f3bbc..a4f7088e8536 100644 --- a/wizards/source/scriptforge/SF_Session.xba +++ b/wizards/source/scriptforge/SF_Session.xba @@ -67,7 +67,7 @@ REM ===================================================== CONSTRUCTOR/DESTRUCTOR REM ----------------------------------------------------------------------------- Public Function Dispose() As Variant Set Dispose = Nothing -End Function ' ScriptForge.SF_Array Explicit destructor +End Function ' ScriptForge.SF_Session Explicit destructor REM ================================================================== PROPERTIES @@ -81,7 +81,7 @@ REM ---------------------------------------------------------------------------- Property Get ServiceName As String ''' Internal use ServiceName = "ScriptForge.Session" -End Property ' ScriptForge.SF_Array.ServiceName +End Property ' ScriptForge.SF_Session.ServiceName REM ----------------------------------------------------------------------------- Property Get SCRIPTISAPPLICATION As String @@ -1188,4 +1188,4 @@ CatchNotFound: End Function ' ScriptForge.SF_Session._GetScript REM =============================================== END OF SCRIPTFORGE.SF_SESSION -</script:module> +</script:module> \ No newline at end of file diff --git a/wizards/source/scriptforge/SF_SharedMemory.xba b/wizards/source/scriptforge/SF_SharedMemory.xba new file mode 100644 index 000000000000..f16a323f0d60 --- /dev/null +++ b/wizards/source/scriptforge/SF_SharedMemory.xba @@ -0,0 +1,468 @@ +<?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_SharedMemory" script:language="StarBasic" script:moduleType="normal">REM ======================================================================================================================= +REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. === +REM === Full documentation is available on https://help.libreoffice.org/ === +REM ======================================================================================================================= + +Option Compatible +Option Explicit + +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +''' SF_SharedMemory +''' =============== +''' Singleton class implementing the "ScriptForge.SharedMemory" service +''' Implemented as a usual Basic module +''' +''' Contains the mechanisms to manage persistent memory storage +''' across Basic and/or Python scripts. +''' +''' When a script stops running, all the variables it uses vanish, +''' except Basic Global variables, which stay in memory until the end +''' of the LibreOffice session. +''' +''' However event-driven scripting can often benefit from having variables +''' still being available when the next script is triggered, probably due +''' to a user action. +''' +''' The SharedMemory service implements interfaces allowing to store both BASIC +''' and PYTHON variables in persistent storage, and to retrieve them later +''' from either BASIC or PYTHON scripts interchangeably. +''' +''' The use of the Basic Global statement is more efficient than the actual service +''' and should be preferred when the variables are created and retrieved in basic +''' scripts only. +''' +''' Service invocation example: +''' Dim memory As Variant +''' memory = CreateScriptService("SharedMemory") +''' +''' Example: +''' Sub CreateDoc() +''' ui = CreateScriptService("UI") +''' doc = ui.CreateDocument("Calc") +''' store = CreateScriptService("SharedMemory") +''' store.StoreValue(doc, "actualdocument") +''' ... +''' +''' def UpdateDoc(): +''' store = CreateScriptService("SharedMemory") +''' doc = store.ReadValue("actualdocument") +''' ... +''' +''' Detailed user documentation: +''' https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_SharedMemory.html?DbPAR=BASIC +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +REM ================================================================== EXCEPTIONS + +REM ============================================================ MODULE CONSTANTS + +REM ===================================================== CONSTRUCTOR/DESTRUCTOR + +REM ----------------------------------------------------------------------------- +Public Function Dispose() As Variant + RemoveAll() + Set Dispose = Nothing +End Function ' ScriptForge.SF_SharedMemory Explicit destructor + +REM ================================================================== PROPERTIES + +REM ----------------------------------------------------------------------------- +Property Get ObjectType As String +''' Only to enable object representation + ObjectType = "SF_SharedMemory" +End Property ' ScriptForge.SF_SharedMemory.ObjectType + +REM ----------------------------------------------------------------------------- +Property Get ServiceName As String +''' Internal use + ServiceName = "ScriptForge.SharedMemory" +End Property ' ScriptForge.SF_SharedMemory.ServiceName + +REM ============================================================== PUBLIC METHODS + +REM ----------------------------------------------------------------------------- +Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant +''' Return the actual value of the given property +''' Args: +''' PropertyName: the name of the property as a string +''' Returns: +''' The actual value of the property +''' Exceptions +''' ARGUMENTERROR The property does not exist + +Const cstThisSub = "SharedMemory.GetProperty" +Const cstSubArgs = "PropertyName" + + If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch + GetProperty = Null + +Check:SharedMemory + If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then + If Not SF_Utils._Validate(PropertyName, "PropertyName", V_STRING, Properties()) Then GoTo Catch + End If + +Try: + Select Case UCase(PropertyName) + Case Else + End Select + +Finally: + SF_Utils._ExitFunction(cstThisSub) + Exit Function +Catch: + GoTo Finally +End Function ' ScriptForge.SF_SharedMemory.GetProperty + +REM ----------------------------------------------------------------------------- +Public Function Methods() As Variant +''' Return the list of public methods of the SharedMemory service as an array + + Methods = Array( _ + "Exists" _ + , "ReadValue" _ + , "Rename" _ + , "Remove" _ + , "RemoveAll" _ + , "StoreValue" _ + ) + +End Function ' ScriptForge.SF_SharedMemory.Methods + +REM ----------------------------------------------------------------------------- +Public Function Properties() As Variant +''' Return the list or properties as an array + + Properties = Array( _ + ) + +End Function ' ScriptForge.SF_SharedMemory.Properties + +REM ----------------------------------------------------------------------------- +Public Function Exists(Optional ByVal VariableName As Variant) As Boolean +''' Returns True if the given name exists in the shared and persistent storage. +''' Args: +''' VariableName: a case-sensitive name. +''' Returns: +''' True if VariableName exists. +''' Example: +''' memory = CreateScriptService("SharedMemory") +''' If memory.Exists("ActualDoc") Then +''' ... + +Dim bExists As Boolean ' Return value + +Const cstThisSub = "SharedMemory.Exists" +Const cstSubArgs = "VariableName" + + If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch + bExists = False + +Check: + If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then + If Not SF_Utils._Validate(VariableName, "VariableName", V_STRING) Then GoTo Catch + End If + +Try: + If Not IsNull(_SF_.GlobalStorage) Then bExists = _SF_.GlobalStorage.Exists(VariableName) + +Finally: + Exists = bExists + SF_Utils._ExitFunction(cstThisSub) + Exit Function +Catch: + GoTo Finally +End Function ' ScriptForge.SF_SharedMemory.Exists + +REM ----------------------------------------------------------------------------- +Public Function ReadValue(Optional ByVal VariableName As Variant) As Variant +''' Read in the shared and persistent storage area the requested value or array of values. +''' If the returned value is a ScriptForge class instance, the user script can verify if the +''' corresponding interface (dialog, document, ...) is still valid with its IsAlive property. +''' Args: +''' VariableName: the case-sensitive name of the value to retrieve. +''' Returns: +''' A scalar or an array of scalars. +''' If VariableName does not exist, an error is generated. +''' Example: +''' memory = CreateScriptService("SharedMemory") +''' doc = CreateScriptService("Document", ThisComponent) +''' memory.StoreValue(doc, "ActualDoc") +''' ... ' The script might be stopped +''' doc2 = memory.ReadValue("ActualDoc") +''' If doc2.IsAlive Then ' Check that the document has not be closed by the user +''' ... + +Dim vRead As Variant ' Return value +Dim vKeys As Variant ' Array of dictionary keys + +Const cstThisSub = "SharedMemory.ReadValue" +Const cstSubArgs = "VariableName" + + If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch + vRead = Empty + ' Initialize the dictionary if necessary + If IsNull(_SF_.GlobalStorage) Then _SF_.GlobalStorage = CreateScriptService("Dictionary", True) + +Check: + vKeys = _SF_.GlobalStorage.Keys + If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then + If Not SF_Utils._Validate(VariableName, "VariableName", V_STRING, vKeys, True) Then GoTo Catch + End If + +Try: + ' Read the value in the persistent dictionary + vRead = _SF_.GlobalStorage.Item(VariableName) + +Finally: + ReadValue = vRead + SF_Utils._ExitFunction(cstThisSub) + Exit Function +Catch: + GoTo Finally +End Function ' ScriptForge.SF_SharedMemory.ReadValue + +REM ----------------------------------------------------------------------------- +Public Function Remove(Optional ByVal VariableName As Variant) As Boolean +''' Remove the entry in the shared and persistent storage area corresponding with the given name. +''' Args: +''' VariableName: the case-sensitive name to remove. +''' Returns: +''' A scalar or an array of scalars. +''' If VariableName does not exist, an error is generated. +''' Example: +''' memory = CreateScriptService("SharedMemory") +''' If memory.Exists("ActualDoc") Then memory.Remove("ActualDoc") +''' ... + +Dim bRemove As Boolean ' Return value +Dim vKeys As Variant ' Array of dictionary keys + +Const cstThisSub = "SharedMemory.Remove" +Const cstSubArgs = "VariableName" + + If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch + bRemove = False + ' Initialize the dictionary if necessary + If IsNull(_SF_.GlobalStorage) Then _SF_.GlobalStorage = CreateScriptService("Dictionary", True) + +Check: + vKeys = _SF_.GlobalStorage.Keys + If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then + If Not SF_Utils._Validate(VariableName, "VariableName", V_STRING, vKeys, True) Then GoTo Catch + End If + +Try: + ' Remove key and item from the persistent dictionary + bRemove = _SF_.GlobalStorage.Remove(VariableName) + +Finally: + Remove = bRemove + SF_Utils._ExitFunction(cstThisSub) + Exit Function +Catch: + GoTo Finally +End Function ' ScriptForge.SF_SharedMemory.Remove + +REM ----------------------------------------------------------------------------- +Public Function RemoveAll() As Boolean +''' Remove the whole content of the shared and persistent storage area. +''' Returns: +''' True when successful. +''' Example: +''' memory = CreateScriptService("SharedMemory") +''' memory.RemoveAll() +''' MsgBox memory.Exists("ActualDoc") ' False +''' ... + +Dim bRemoveAll As Boolean ' Return value + +Const cstThisSub = "SharedMemory.RemoveAll" +Const cstSubArgs = "" + + If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch + bRemoveAll = False + +Check: + SF_Utils._EnterFunction(cstThisSub, cstSubArgs) + +Try: + If Not IsNull(_SF_.GlobalStorage) Then bRemoveAll = _SF_.GlobalStorage.RemoveAll() + +Finally: + RemoveAll = bRemoveAll + SF_Utils._ExitFunction(cstThisSub) + Exit Function +Catch: + GoTo Finally +End Function ' ScriptForge.SF_SharedMemory.RemoveAll + +REM ----------------------------------------------------------------------------- +Public Function SetProperty(Optional ByVal PropertyName As Variant _ + , Optional ByRef Value As Variant _ + ) As Boolean +''' Set a new value to the given property +''' Args: +''' PropertyName: the name of the property as a string +''' Value: its new value +''' Exceptions +''' ARGUMENTERROR The property does not exist + +Const cstThisSub = "SharedMemory.SetProperty" +Const cstSubArgs = "PropertyName, Value" + + If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch + SetProperty = False + +Check: + If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then + If Not SF_Utils._Validate(PropertyName, "PropertyName", V_STRING, Properties()) Then GoTo Catch + End If + +Try: + Select Case UCase(PropertyName) + Case Else + End Select + SetProperty = True + +Finally: + SF_Utils._ExitFunction(cstThisSub) + Exit Function +Catch: + GoTo Finally +End Function ' ScriptForge.SF_SharedMemory.SetProperty + +REM ----------------------------------------------------------------------------- +Public Function StoreValue(Optional ByVal Value As Variant _ + , Optional ByVal VariableName As Variant _ + ) As Boolean +''' Store in the shared and persistent storage area the given value. +''' Later retrieval will be done thanks to the given variable name. +''' If the given name already exists, its value is replaced without warning. +''' Args: +''' Value: the value to be stored. +''' The supported variable types are: +''' * Scalar or 1D-array/tuple combining : +''' - Integer/Long or int, within the bounds of the Basic Long type +''' - Single/Double or float, within the bounds of the Basic Double type +''' - String or str +''' - Boolean or bool +''' - Null or None (Empty and Nothing are reset to Null) +''' - Variant embedding one of above types +''' * Date or datetime.datetime +''' * UNO object +''' * ScriptForge class instance +''' VariableName: the case-sensitive name to retrieve the Value when needed. +''' Returns: +''' True when successful +''' Example: +''' memory = CreateScriptService("SharedMemory") +''' doc = CreateScriptService("Document", ThisComponent) +''' memory.StoreValue(doc, "ActualDoc") + +Dim bStore As Boolean ' Return value +Dim vGlobal As Variant ' A stored value +Dim i As Long + +Const cstThisSub = "SharedMemory.StoreValue" +Const cstSubArgs = "Value, VariableName" + + If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch + bStore = False + +Check: + If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then + If IsArray(Value) Then + If Not SF_Utils._ValidateArray(Value, "Value", 1) Then GoTo Catch + End If + If Not SF_Utils._Validate(VariableName, "VariableName", V_STRING) Then GoTo Catch + End If + +Try: + ' Initialize the dictionary if necessary + If IsNull(_SF_.GlobalStorage) Then _SF_.GlobalStorage = CreateScriptService("Dictionary", True) + + ' Size the returned array when the input is an array + If IsArray(Value) Then + vGlobal = Array() + ReDim vGlobal(LBound(Value) To UBound(Value)) + For i = LBound(vGlobal) To UBound(vGlobal) + vGlobal(i) = _ConvertValue(Value(i), pbArray := True) + If IsEmpty(vGlobal(i)) Then + vGlobal = Empty + Exit For + End If + Next i + Else + vGlobal = _ConvertValue(Value, pbArray := False) + End If + + ' Store the value in the persistent dictionary + If Not IsEmpty(vGlobal) Then + With _SF_.GlobalStorage + If .Exists(VariableName) Then bStore = .ReplaceItem(VariableName, vGlobal) Else bStore = .Add(VariableName, vGlobal) + End With + End If + +Finally: + StoreValue = bStore + SF_Utils._ExitFunction(cstThisSub) + Exit Function +Catch: + GoTo Finally +End Function ' ScriptForge.SF_SharedMemory.StoreValue + +REM =========================================================== PRIVATE FUNCTIONS + +REM ----------------------------------------------------------------------------- +Private Function _ConvertValue(pvValue As Variant _ + , pbArray As Boolean _ + ) As Variant +''' Convert the input value to one of the types applicable +''' to shared memory constraints. +''' Args: +''' pvValue: the input value, must not be an array +''' pbArray: when True, pvValue is an item inside an array +''' Returns: +''' The converted value. +''' Empty when the conversion was not successful. + +Dim vGlobal As Variant ' Return value +Dim iObjectType As Integer ' The object type returned by _VarTypeObj() + +Try: + vGlobal = Empty + Select Case VarType(pvValue) + Case V_INTEGER, V_LONG, V_BIGINT + vGlobal = CLng(pvValue) + Case V_SINGLE, V_DOUBLE, V_CURRENCY, V_DECIMAL + vGlobal = CDbl(pvValue) + Case V_EMPTY, V_NULL + vGlobal = Null + Case V_STRING, ScriptForge.V_BOOLEAN + vGlobal = pvValue + Case V_DATE ' No dates in arrays + If Not pbArray Then vGlobal = pvValue + Case ScriptForge.V_OBJECT + If Not pbArray Then ' No objects in arrays + iObjectType = SF_Utils._VarTypeObj(pvValue).iVarType + Select Case iObjectType + Case ScriptForge.V_Nothing + vGlobal = Null + Case ScriptForge.V_UNOOBJECT, ScriptForge.V_SFOBJECT + vGlobal = pvValue + Case Else ' V_BASICOBJECT + End Select + End If + Case >= ScriptForge.V_ARRAY ' No subarrays + Case Else + End Select + +Finally: + _ConvertValue = vGlobal + Exit Function +End Function ' ScriptForge.SF_SharedMemory._ConvertValue + +REM =============================================== END OF SCRIPTFORGE.SF_SHAREDMEMORY +</script:module> \ No newline at end of file diff --git a/wizards/source/scriptforge/python/scriptforge.py b/wizards/source/scriptforge/python/scriptforge.py index eb1a39ad6809..3e21db3f114b 100644 --- a/wizards/source/scriptforge/python/scriptforge.py +++ b/wizards/source/scriptforge/python/scriptforge.py @@ -145,8 +145,9 @@ class ScriptForge(object, metaclass = _Singleton): ('ScriptForge.Region', 4), ('ScriptForge.Services', 5), ('ScriptForge.Session', 6), - ('ScriptForge.String', 7), - ('ScriptForge.UI', 8)]) + ('ScriptForge.SharedMemory', 7), + ('ScriptForge.String', 8), + ('ScriptForge.UI', 9)]) def __init__(self, hostname = '', port = 0, pipe = ''): """ @@ -1609,6 +1610,43 @@ class SFScriptForge: def WebService(self, uri): return self.ExecMethod(self.vbMethod, 'WebService', uri) + # ######################################################################### + # SF_SharedMemory CLASS + # ######################################################################### + class SF_SharedMemory(SFServices, metaclass = _Singleton): + """ + Contains the mechanisms to manage persistent memory storage across Basic and/or Python scripts. + + The SharedMemory service implements interfaces allowing to store both Basic and Python variables + in persistent storage, and to retrieve them later from either Basic or Python scripts interchangeably. + """ + # Mandatory class properties for service registration + serviceimplementation = 'basic' + servicename = 'ScriptForge.SharedMemory' + servicesynonyms = ('sharedmemory', 'scriptforge.sharedmemory') + serviceproperties = dict() + + def Exists(self, variablename): + return self.ExecMethod(self.vbMethod, 'Exists', variablename) + + def ReadValue(self, variablename): + return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'ReadValue', variablename) + + def Remove(self, variablename): + return self.ExecMethod(self.vbMethod, 'Remove', variablename) + + def RemoveAll(self): + return self.ExecMethod(self.vbMethod, 'RemoveAll') + + def StoreValue(self, value, variablename): + if isinstance(value, SFServices): + return self.ExecMethod(self.vbMethod + self.flgObject, 'StoreValue', + value.objectreference, variablename) + if isinstance(value, datetime.datetime): + value = SFScriptForge.SF_Basic.CDateToUnoDateTime(value) + return self.ExecMethod(self.vbMethod + self.flgDateArg, 'StoreValue', value, variablename) + return self.ExecMethod(self.vbMethod, 'StoreValue', value, variablename) + # ######################################################################### # SF_String CLASS # ######################################################################### @@ -3170,6 +3208,7 @@ L10N = SFScriptForge.SF_L10N PLATFORM = SFScriptForge.SF_Platform REGION = SFScriptForge.SF_Region SESSION = SFScriptForge.SF_Session +SHAREDMEMORY = SFScriptForge.SF_SharedMemory STRING = SFScriptForge.SF_String TEXTSTREAM = SFScriptForge.SF_TextStream TIMER = SFScriptForge.SF_Timer diff --git a/wizards/source/scriptforge/python/scriptforge.pyi b/wizards/source/scriptforge/python/scriptforge.pyi index 1b7067bba499..1a4ed520047d 100644 --- a/wizards/source/scriptforge/python/scriptforge.pyi +++ b/wizards/source/scriptforge/python/scriptforge.pyi @@ -63,6 +63,7 @@ L10N = SFScriptForge.SF_L10N PLATFORM = SFScriptForge.SF_Platform REGION = SFScriptForge.SF_Region SESSION = SFScriptForge.SF_Session +SHAREDMEMORY = SFScriptForge.SF_SharedMemory STRING = SFScriptForge.SF_String TEXTSTREAM = SFScriptForge.SF_TextStream TIMER = SFScriptForge.SF_Timer @@ -1795,7 +1796,7 @@ class SFScriptForge: @classmethod def ExecuteBasicScript( - cls, scope: str = ..., script: str = ..., *args: Optional[Any] + cls, scope: Optional[str] = ..., script: str = ..., *args: Optional[Any] ) -> Any: """ Execute the Basic script given its name and location and fetch its result if any. @@ -2035,6 +2036,85 @@ class SFScriptForge: The web page content of the URI. """ ... + + # ######################################################################### + # SF_SharedMemory CLASS + # ######################################################################### + class SF_SharedMemory(SFServices, metaclass = ...): + """ + Contains the mechanisms to manage persistent memory storage across Basic and/or Python scripts. + + The SharedMemory service implements interfaces allowing to store both Basic and Python variables + in persistent storage, and to retrieve them later from either Basic or Python scripts interchangeably. + """ + + def Exists(self, variablename: str) -> bool: + """ + Returns whether the given name exists in the shared and persistent storage. + Args + ``variablename``: a case-sensitive name. + Returns + ``True`` when the name has been found. + """ + ... + + def ReadValue(self, variablename: str) -> Any: + """ + Read in the shared and persistent storage area the requested value or array of values. + Args + ``variablename``: the case-sensitive name of the value to retrieve. + Returns + A scalar or a tuple of scalars. If ``variablename`` does not exist, an error is raised. + Note + If the returned value is a ``ScriptForge`` class instance, the user script can verify if the + corresponding interface (dialog, document, ...) is still valid with its ``IsAlive`` property. + """ + ... + + def Remove(self, variablename: str) -> bool: + """ + Remove the entry in the shared and persistent storage area corresponding with the given name. + Args + ``variablename``: the case-sensitive name of the variable to remove. + Returns + ``True`` when the name has been removed successfully. + """ + ... + + def RemoveAll(self) -> bool: + """ + Remove the whole content of the shared and persistent storage area. + Returns + ``True`` when successful. + """ + ... + + def StoreValue(self, + value: Union[Any | datetime.datetime | UNO, Tuple[Union[int, float, str, bool]]], + variablename: str + ) -> bool: + """ + Store in the shared and persistent storage area the given value. Later retrieval will be done thanks + to the given variable name. If the given name already exists, its value is replaced without warning. + Args + ``value``: the value to be stored. + The supported variable types are: + * Scalar or tuple combining: + - int, within the bounds of the Basic Long type + - float, within the bounds of the Basic Double type + - str + - bool + - None + * datetime.datetime + * UNO object + * ScriptForge class instance + + ``variablename``: the case-sensitive name to retrieve ``value`` when needed. + Returns + ``True`` when successful + """ + ... + # ######################################################################### # SF_String CLASS # ######################################################################### @@ -7713,6 +7793,8 @@ def CreateScriptService(service: Literal['region', 'Region', 'ScriptForge.Region @overload def CreateScriptService(service: Literal['session', 'Session', 'ScriptForge.Session']) -> SESSION: ... @overload +def CreateScriptService(service: Literal['sharedmemory', 'SharedMemory', 'ScriptForge.SharedMemory']) -> SHAREDMEMORY: ... +@overload def CreateScriptService(service: Literal['string', 'String', 'ScriptForge.String']) -> STRING: ... @overload def CreateScriptService(service: Literal['timer', 'Timer', 'ScriptForge.Timer'], start: bool = False diff --git a/wizards/source/scriptforge/script.xlb b/wizards/source/scriptforge/script.xlb index 98570642b8e2..7c5f29231c27 100644 --- a/wizards/source/scriptforge/script.xlb +++ b/wizards/source/scriptforge/script.xlb @@ -1,23 +1,24 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd"> <library:library xmlns:library="http://openoffice.org/2000/library" library:name="ScriptForge" library:readonly="false" library:passwordprotected="false"> - <library:element library:name="SF_Root"/> - <library:element library:name="__License"/> - <library:element library:name="SF_Region"/> - <library:element library:name="SF_L10N"/> - <library:element library:name="SF_String"/> - <library:element library:name="_ModuleModel"/> - <library:element library:name="SF_UI"/> - <library:element library:name="SF_Services"/> <library:element library:name="SF_PythonHelper"/> <library:element library:name="SF_Platform"/> <library:element library:name="SF_Array"/> <library:element library:name="SF_TextStream"/> <library:element library:name="SF_Utils"/> - <library:element library:name="SF_FileSystem"/> + <library:element library:name="SF_String"/> + <library:element library:name="_ModuleModel"/> + <library:element library:name="SF_SharedMemory"/> + <library:element library:name="SF_L10N"/> + <library:element library:name="SF_Region"/> + <library:element library:name="__License"/> + <library:element library:name="SF_Root"/> <library:element library:name="SF_Timer"/> - <library:element library:name="SF_Session"/> + <library:element library:name="SF_FileSystem"/> + <library:element library:name="SF_Services"/> + <library:element library:name="SF_UI"/> <library:element library:name="SF_Exception"/> <library:element library:name="SF_Dictionary"/> + <library:element library:name="SF_Session"/> <library:element library:name="_CodingConventions"/> </library:library> \ No newline at end of file