summaryrefslogtreecommitdiffstats
path: root/wizards/source/scriptforge/SF_Services.xba
diff options
context:
space:
mode:
Diffstat (limited to 'wizards/source/scriptforge/SF_Services.xba')
-rw-r--r--wizards/source/scriptforge/SF_Services.xba639
1 files changed, 639 insertions, 0 deletions
diff --git a/wizards/source/scriptforge/SF_Services.xba b/wizards/source/scriptforge/SF_Services.xba
new file mode 100644
index 000000000..627dc4d2e
--- /dev/null
+++ b/wizards/source/scriptforge/SF_Services.xba
@@ -0,0 +1,639 @@
+<?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_Services" 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
+
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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_Services
+&apos;&apos;&apos; ===========
+&apos;&apos;&apos; Singleton class implementing the &quot;ScriptForge.Services&quot; service
+&apos;&apos;&apos; Implemented as a usual Basic module
+&apos;&apos;&apos; The ScriptForge framework includes
+&apos;&apos;&apos; the current ScriptForge library
+&apos;&apos;&apos; a number of &quot;associated&quot; libraries
+&apos;&apos;&apos; any user/contributor extension wanting to fit into the framework
+&apos;&apos;&apos; The methods in this module constitute the kernel of the ScriptForge framework
+&apos;&apos;&apos; - RegisterScriptServices
+&apos;&apos;&apos; Register for a library the list of services it implements
+&apos;&apos;&apos; Each library in the framework must implement its own RegisterScriptServices method
+&apos;&apos;&apos; This method consists in a series of invocations of next 2 methods
+&apos;&apos;&apos; - RegisterService
+&apos;&apos;&apos; Register a single service
+&apos;&apos;&apos; - RegisterEventManager
+&apos;&apos;&apos; Register a single event manager
+&apos;&apos;&apos; - CreateScriptService
+&apos;&apos;&apos; Called by user scripts to get an object giving access to a service or to the event manager
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_services.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;
+
+REM ================================================================== EXCEPTIONS
+
+Const UNKNOWNSERVICEERROR = &quot;UNKNOWNSERVICEERROR&quot; &apos; Service not found within the registered services of the given library
+Const SERVICESNOTLOADEDERROR = &quot;SERVICESNOTLOADEDERROR&quot; &apos; Failure during the registering of the services of the given library
+Const UNKNOWNFILEERROR = &quot;UNKNOWNFILEERROR&quot; &apos; Source file does not exist
+
+REM ============================================================== PUBLIC MEMBERS
+
+&apos; Defines an entry in in the services dictionary
+Type _Service
+ ServiceName As String
+ ServiceType As Integer
+ &apos; 0 Undefined
+ &apos; 1 Basic module
+ &apos; 2 Method reference as a string
+ ServiceReference As Object
+ ServiceMethod As String
+ EventManager As Boolean &apos; True if registered item is an event manager
+End Type
+
+Private vServicesArray As Variant &apos; List of services registered by a library
+
+REM ============================================================== PUBLIC METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function CreateScriptService(Optional ByRef Service As Variant _
+ , ParamArray pvArgs As Variant _
+ ) As Variant
+&apos;&apos;&apos; Create access to the services of a library for the benefit of a user script
+&apos;&apos;&apos; A service is to understand either:
+&apos;&apos;&apos; as a set of methods gathered in a Basic standard module
+&apos;&apos;&apos; or a set of methods and properties gathered in a Basic class module
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Service: the name of the service in 2 parts &quot;library.service&quot;
+&apos;&apos;&apos; The library is a Basic library that must exist in the GlobalScope
+&apos;&apos;&apos; (default = &quot;ScriptForge&quot;)
+&apos;&apos;&apos; The service is one of the services registered by the library
+&apos;&apos;&apos; thru the RegisterScriptServices() routine
+&apos;&apos;&apos; pvArgs: a set of arguments passed to the constructor of the service
+&apos;&apos;&apos; This is only possible if the service refers to a Basic class module
+&apos;&apos;&apos; Returns
+&apos;&apos;&apos; The object containing either the reference of the Basic module
+&apos;&apos;&apos; or of the Basic class instance
+&apos;&apos;&apos; Both are Basic objects
+&apos;&apos;&apos; Returns Nothing if an error occurred.
+&apos;&apos;&apos; ==&gt;&gt; NOTE: The error can be within the user script creating the new class instance
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; SERVICESNOTLOADEDERROR RegisterScriptService probable failure
+&apos;&apos;&apos; UNKNOWNSERVICEERROR Service not found
+&apos;&apos;&apos; Examples
+&apos;&apos;&apos; CreateScriptService(&quot;Array&quot;)
+&apos;&apos;&apos; =&gt; Refers to ScriptForge.Array or SF_Array
+&apos;&apos;&apos; CreateScriptService(&quot;ScriptForge.Dictionary&quot;)
+&apos;&apos;&apos; =&gt; Returns a new empty dictionary; &quot;ScriptForge.&quot; is optional
+&apos;&apos;&apos; CreateScriptService(&quot;SFDocuments.Calc&quot;)
+&apos;&apos;&apos; =&gt; Refers to the Calc service, implemented in the SFDocuments library
+&apos;&apos;&apos; CreateScriptService(&quot;Dialog&quot;, dlgName)
+&apos;&apos;&apos; =&gt; Returns a Dialog instance referring to the dlgName dialog
+&apos;&apos;&apos; CreateScriptService(&quot;SFDocuments.Event&quot;, oEvent)
+&apos;&apos;&apos; =&gt; Refers to the Document service instance, implemented in the SFDocuments library, having triggered the event
+
+Dim vScriptService As Variant &apos; Return value
+Dim vServiceItem As Variant &apos; A single service (see _Service type definition)
+Dim vServicesList As Variant &apos; Output of RegisterScriptServices
+Dim vSplit As Variant &apos; Array to split argument in
+Dim sLibrary As String &apos; Library part of the argument
+Dim sService As String &apos; Service part of the argument
+Dim vLibrary As Variant &apos; Dictionary of libraries
+Dim vService As Variant &apos; An individual service object
+Const cstThisSub = &quot;SF_Services.CreateScriptService&quot;
+Const cstSubArgs = &quot;Service, arg0[, arg1] ...&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set vScriptService = Nothing
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Service, &quot;Service&quot;, V_STRING) Then GoTo Catch
+ If Len(Service) = 0 Then GoTo CatchNotFound
+ End If
+
+Try:
+ &apos; Initialize the list of services when CreateScriptService called for the very 1st time
+ If IsEmpty(_SF_.ServicesList) Then _SF_.ServicesList = SF_Services._NewDictionary()
+
+ &apos; Simple parsing of argument
+ vSplit = Split(Service, &quot;.&quot;)
+ If UBound(vSplit) &gt; 1 Then GoTo CatchNotFound
+ If UBound(vSplit) = 0 Then
+ sLibrary = &quot;ScriptForge&quot; &apos; Yes, the default value !
+ 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;
+ sLibrary = &quot;SFDocuments&quot;
+ Case &quot;dialog&quot;, &quot;dialogevent&quot; : sLibrary = &quot;SFDialogs&quot;
+ Case &quot;database&quot; : sLibrary = &quot;SFDatabases&quot;
+ Case &quot;unittest&quot; : sLibrary = &quot;SFUnitTests&quot;
+ Case &quot;menu&quot;, &quot;popupmenu&quot; : sLibrary = &quot;SFWidgets&quot;
+ Case Else
+ End Select
+ Else
+ sLibrary = vSplit(0)
+ sService = vSplit(1)
+ End If
+
+ With _SF_.ServicesList
+
+ &apos; Load the set of services from the library, if not yet done
+ If Not .Exists(sLibrary) Then
+ If Not SF_Services._LoadLibraryServices(sLibrary) Then GoTo CatchNotLoaded
+ End If
+
+ &apos; Find and return the requested service
+ vServicesList = .Item(sLibrary)
+ If Not vServicesList.Exists(sService) Then GoTo CatchNotFound
+ vServiceItem = vServicesList.Item(sService)
+ Select Case vServiceItem.ServiceType
+ Case 1 &apos; Basic module
+ vScriptService = vServiceItem.ServiceReference
+ Case 2 &apos; Method to call
+ If sLibrary = &quot;ScriptForge&quot; Then &apos; Direct call
+ Select Case UCase(sService)
+ Case &quot;DICTIONARY&quot; : vScriptService = SF_Services._NewDictionary()
+ Case &quot;L10N&quot; : vScriptService = SF_Services._NewL10N(pvArgs)
+ Case &quot;TIMER&quot; : vScriptService = SF_Services._NewTimer(pvArgs)
+ Case Else
+ End Select
+ Else &apos; Call via script provider
+ Set vService = SF_Session._GetScript(&quot;Basic&quot;, SF_Session.SCRIPTISAPPLICATION, vServiceItem.ServiceMethod)
+ vScriptService = vService.Invoke(Array(pvArgs()), Array(), Array())
+ End If
+ Case Else
+ End Select
+
+ End With
+
+Finally:
+ CreateScriptService = vScriptService
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotFound:
+ SF_Exception.RaiseFatal(UNKNOWNSERVICEERROR, &quot;Service&quot;, Service, sLibrary, sService)
+ GoTo Finally
+CatchNotLoaded:
+ SF_Exception.RaiseFatal(SERVICESNOTLOADEDERROR, &quot;Service&quot;, Service, sLibrary)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Services.CreateScriptService
+
+REM -----------------------------------------------------------------------------
+Public Function RegisterEventManager(Optional ByVal ServiceName As Variant _
+ , Optional ByRef ServiceReference As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Register into ScriptForge a new event entry for the library
+&apos;&apos;&apos; from which this method is called
+&apos;&apos;&apos; MUST BE CALLED ONLY from a specific RegisterScriptServices() method
+&apos;&apos;&apos; Usually the method should be called only once by library
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ServiceName: the name of the service as a string. It the service exists
+&apos;&apos;&apos; already for the library the method overwrites the existing entry
+&apos;&apos;&apos; ServiceReference: the function which will identify the source of the triggered event
+&apos;&apos;&apos; something like: &quot;libraryname.modulename.function&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; &apos; Code snippet stored in a module contained in the SFDocuments library
+&apos;&apos;&apos; Sub RegisterScriptServices()
+&apos;&apos;&apos; &apos; Register the events manager of the library
+&apos;&apos;&apos; RegisterEventManager(&quot;DocumentEvent&quot;, &quot;SFDocuments.SF_Register._EventManager&quot;)
+&apos;&apos;&apos; End Sub
+&apos;&apos;&apos; &apos; Code snippet stored in a user script
+&apos;&apos;&apos; Sub Trigger(poEvent As Object) &apos; Triggered by a DOCUMENTEVENT event
+&apos;&apos;&apos; Dim myDoc As Object
+&apos;&apos;&apos; &apos; To get the document concerned by the event:
+&apos;&apos;&apos; Set myDoc = CreateScriptService(&quot;SFDocuments.DocumentEvent&quot;, poEvent)
+&apos;&apos;&apos; End Sub
+
+Dim bRegister As Boolean &apos; Return value
+Const cstThisSub = &quot;SF_Services.RegisterEventManager&quot;
+Const cstSubArgs = &quot;ServiceName, ServiceReference&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bRegister = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(ServiceName, &quot;ServiceName&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(ServiceReference, &quot;ServiceReference&quot;,V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ bRegister = _AddToServicesArray(ServiceName, ServiceReference, True)
+
+Finally:
+ RegisterEventManager = bRegister
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Services.RegisterEventManager
+
+REM -----------------------------------------------------------------------------
+Public Function RegisterService(Optional ByVal ServiceName As Variant _
+ , Optional ByRef ServiceReference As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Register into ScriptForge a new service entry for the library
+&apos;&apos;&apos; from which this method is called
+&apos;&apos;&apos; MUST BE CALLED ONLY from a specific RegisterScriptServices() method
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ServiceName: the name of the service as a string. It the service exists
+&apos;&apos;&apos; already for the library the method overwrites the existing entry
+&apos;&apos;&apos; ServiceReference: either
+&apos;&apos;&apos; - the Basic module that implements the methods of the service
+&apos;&apos;&apos; something like: GlobalScope.Library.Module
+&apos;&apos;&apos; - an instance of the class implementing the methods and properties of the service
+&apos;&apos;&apos; something like: &quot;libraryname.modulename.function&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful
+
+Dim bRegister As Boolean &apos; Return value
+Const cstThisSub = &quot;SF_Services.RegisterService&quot;
+Const cstSubArgs = &quot;ServiceName, ServiceReference&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bRegister = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(ServiceName, &quot;ServiceName&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(ServiceReference, &quot;ServiceReference&quot;, Array(V_STRING, V_OBJECT)) Then GoTo Finally
+ End If
+
+Try:
+ bRegister = _AddToServicesArray(ServiceName, ServiceReference, False)
+
+Finally:
+ RegisterService = bRegister
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Services.RegisterService
+
+REM -----------------------------------------------------------------------------
+Public Sub RegisterScriptServices() As Variant
+&apos;&apos;&apos; Register into ScriptForge the list of the services implemented by the current library
+&apos;&apos;&apos; Each library pertaining to the framework must implement its own version of this method
+&apos;&apos;&apos; This method may be stored in any standard (i.e. not class-) module
+&apos;&apos;&apos;
+&apos;&apos;&apos; Each individual service is registered by calling the RegisterService() method
+&apos;&apos;&apos;
+&apos;&apos;&apos; The current version is given as an example
+&apos;&apos;&apos;
+ With GlobalScope.ScriptForge.SF_Services
+ .RegisterService(&quot;Array&quot;, GlobalScope.ScriptForge.SF_Array) &apos; Reference to the Basic module
+ .RegisterService(&quot;Dictionary&quot;, &quot;ScriptForge.SF_Services._NewDictionary&quot;) &apos; Reference to the function initializing the service
+ .RegisterService(&quot;Exception&quot;, GlobalScope.ScriptForge.SF_Exception)
+ .RegisterService(&quot;FileSystem&quot;, GlobalScope.ScriptForge.SF_FileSystem)
+ .RegisterService(&quot;L10N&quot;, &quot;ScriptForge.SF_Services._NewL10N&quot;)
+ .RegisterService(&quot;Platform&quot;, GlobalScope.ScriptForge.SF_Platform)
+ .RegisterService(&quot;Region&quot;, GlobalScope.ScriptForge.SF_Region)
+ .RegisterService(&quot;Session&quot;, GlobalScope.ScriptForge.SF_Session)
+ .RegisterService(&quot;String&quot;, GlobalScope.ScriptForge.SF_String)
+ .RegisterService(&quot;Timer&quot;, &quot;ScriptForge.SF_Services._NewTimer&quot;)
+ .RegisterService(&quot;UI&quot;, GlobalScope.ScriptForge.SF_UI)
+ &apos;TODO
+ End With
+
+End Sub &apos; ScriptForge.SF_Services.RegisterScriptServices
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _AddToServicesArray(ByVal psServiceName As String _
+ , ByRef pvServiceReference As Variant _
+ , ByVal pbEvent As Boolean _
+ ) As Boolean
+&apos;&apos;&apos; Add the arguments as an additional row in vServicesArray (Public variable)
+&apos;&apos;&apos; Called from RegisterService and RegisterEvent methods
+
+Dim bRegister As Boolean &apos; Return value
+Dim lMax As Long &apos; Number of rows in vServicesArray
+
+ bRegister = False
+
+Check:
+ &apos; Ignore when method is not called from RegisterScriptServices()
+ If IsEmpty(vServicesArray) Or IsNull(vServicesArray) Or Not IsArray(vServicesArray) Then GoTo Finally
+
+Try:
+ lMax = UBound(vServicesArray, 1) + 1
+ If lMax &lt;= 0 Then
+ ReDim vServicesArray(0 To 0, 0 To 2)
+ Else
+ ReDim Preserve vServicesArray(0 To lMax, 0 To 2)
+ End If
+ vServicesArray(lMax, 0) = psServiceName
+ vServicesArray(lMax, 1) = pvServiceReference
+ vServicesArray(lMax, 2) = pbEvent
+ bRegister = True
+
+Finally:
+ _AddToServicesArray = bRegister
+ Exit Function
+End Function &apos; ScriptForge.SF_Services._AddToServicesArray
+
+REM -----------------------------------------------------------------------------
+Private Function _FindModuleFromMethod(ByVal psLibrary As String _
+ , ByVal psMethod As String _
+ ) As String
+&apos;&apos;&apos; Find in the given library the name of the module containing
+&apos;&apos;&apos; the method given as 2nd argument (usually RegisterScriptServices)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psLibrary: the name of the Basic library
+&apos;&apos;&apos; psMethod: the method to locate
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The name of the module or a zero-length string if not found
+
+Dim vCategories As Variant &apos; &quot;user&quot; or &quot;share&quot; library categories
+Dim sCategory As String
+Dim vLanguages As Variant &apos; &quot;Basic&quot;, &quot;Python&quot;, ... programming languages
+Dim sLanguage As String
+Dim vLibraries As Variant &apos; Library names
+Dim sLibrary As String
+Dim vModules As Variant &apos; Module names
+Dim sModule As String &apos; Return value
+Dim vMethods As Variant &apos; Method/properties/subs/functions
+Dim sMethod As String
+Dim oRoot As Object &apos; com.sun.star.script.browse.BrowseNodeFactory
+Dim i As Integer, j As Integer, k As Integer, l As Integer, m As Integer
+
+ _FindModuleFromMethod = &quot;&quot;
+ Set oRoot = SF_Utils._GetUNOService(&quot;BrowseNodeFactory&quot;).createView(com.sun.star.script.browse.BrowseNodeFactoryViewTypes.MACROORGANIZER)
+
+ &apos; Exploration is done via tree nodes
+ If Not IsNull(oRoot) Then
+ If oRoot.hasChildNodes() Then
+ vCategories = oRoot.getChildNodes()
+ For i = 0 To UBound(vCategories)
+ sCategory = vCategories(i).getName()
+ &apos; Consider &quot;My macros &amp; Dialogs&quot; and &quot;LibreOffice Macros &amp; Dialogs&quot; only
+ If sCategory = &quot;user&quot; Or sCategory = &quot;share&quot; Then
+ If vCategories(i).hasChildNodes() Then
+ vLanguages = vCategories(i).getChildNodes()
+ For j = 0 To UBound(vLanguages)
+ sLanguage = vLanguages(j).getName()
+ &apos; Consider Basic libraries only
+ If sLanguage = &quot;Basic&quot; Then
+ If vLanguages(j).hasChildNodes() Then
+ vLibraries = vLanguages(j).getChildNodes()
+ For k = 0 To UBound(vLibraries)
+ sLibrary = vLibraries(k).getName()
+ &apos; Consider the given library only
+ If sLibrary = psLibrary Then
+ If vLibraries(k).hasChildNodes() Then
+ vModules = vLibraries(k).getChildNodes()
+ For l = 0 To UBound(vModules)
+ sModule = vModules(l).getName()
+ &apos; Check if the module contains the targeted method
+ If vModules(l).hasChildNodes() Then
+ vMethods = vModules(l).getChildNodes()
+ For m = 0 To UBound(vMethods)
+ sMethod = vMethods(m).getName()
+ If sMethod = psMethod Then
+ _FindModuleFromMethod = sModule
+ Exit Function
+ End If
+ Next m
+ End If
+ Next l
+ End If
+ End If
+ Next k
+ End If
+ End If
+ Next j
+ End If
+ End If
+ Next i
+ End If
+ End If
+
+End Function &apos; ScriptForge.SF_Services._FindModuleFromMethod
+
+REM -----------------------------------------------------------------------------
+Private Function _LoadLibraryServices(ByVal psLibrary As String) As Boolean
+&apos;&apos;&apos; Execute psLibrary.RegisterScriptServices() and load its services into the persistent storage
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psLibrary: the name of the Basic library
+&apos;&apos;&apos; Library will be loaded if not yet done
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if success
+&apos;&apos;&apos; The list of services is loaded directly into the persistent storage
+
+
+Dim vServicesList As Variant &apos; Dictionary of services
+Dim vService As Variant &apos; Single service entry in dictionary
+Dim vServiceItem As Variant &apos; Single service in vServicesArray
+Dim sModule As String &apos; Name of module containing the RegisterScriptServices method
+Dim i As Long
+Const cstRegister = &quot;RegisterScriptServices&quot;
+
+Try:
+ _LoadLibraryServices = False
+
+ vServicesArray = Array()
+
+ If psLibrary = &quot;ScriptForge&quot; Then
+ &apos; Direct call
+ ScriptForge.SF_Services.RegisterScriptServices()
+ Else
+ &apos; Register services via script provider
+ If GlobalScope.BasicLibraries.hasByName(psLibrary) Then
+ If Not GlobalScope.BasicLibraries.isLibraryLoaded(psLibrary) Then
+ GlobalScope.BasicLibraries.LoadLibrary(psLibrary)
+ End If
+ Else
+ GoTo Finally
+ End If
+ sModule = SF_Services._FindModuleFromMethod(psLibrary, cstRegister)
+ If Len(sModule) = 0 Then GoTo Finally
+ SF_Session.ExecuteBasicScript(, psLibrary &amp; &quot;.&quot; &amp; sModule &amp; &quot;.&quot; &amp; cstRegister)
+ End If
+
+ &apos; Store in persistent storage
+ &apos; - Create list of services for the current library
+ Set vServicesList = SF_Services._NewDictionary()
+ For i = 0 To UBound(vServicesArray, 1)
+ Set vService = New _Service
+ With vService
+ .ServiceName = vServicesArray(i, 0)
+ vServiceItem = vServicesArray(i, 1)
+ If VarType(vServiceItem) = V_STRING Then
+ .ServiceType = 2
+ .ServiceMethod = vServiceItem
+ Set .ServiceReference = Nothing
+ Else &apos; OBJECT
+ .ServiceType = 1
+ .ServiceMethod = &quot;&quot;
+ Set .ServiceReference = vServiceItem
+ End If
+ .EventManager = vServicesArray(i, 2)
+ End With
+ vServicesList.Add(vServicesArray(i, 0), vService)
+ Next i
+ &apos; - Add the new dictionary to the persistent dictionary
+ _SF_.ServicesList.Add(psLibrary, vServicesList)
+ _LoadLibraryServices = True
+ vServicesArray = Empty
+
+Finally:
+ Exit Function
+End Function &apos; ScriptForge.SF_Services._LoadLibraryServices
+
+REM -----------------------------------------------------------------------------
+Public Function _NewDictionary() As Variant
+&apos;&apos;&apos; Create a new instance of the SF_Dictionary class
+&apos;&apos;&apos; Returns: the instance or Nothing
+
+Dim oDict As Variant
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+
+Try:
+ Set oDict = New SF_Dictionary
+ Set oDict.[Me] = oDict
+
+Finally:
+ Set _NewDictionary = oDict
+ Exit Function
+Catch:
+ Set oDict = Nothing
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Services._NewDictionary
+
+REM -----------------------------------------------------------------------------
+Public Function _NewL10N(Optional ByVal pvArgs As Variant) As Variant
+&apos;&apos;&apos; Create a new instance of the SF_L10N class
+&apos; Args:
+&apos;&apos;&apos; FolderName: the folder containing the PO files in SF_FileSystem.FileNaming notation
+&apos;&apos;&apos; Locale: locale of user session (default) or any other valid la{nguage]-CO[UNTRY] combination
+&apos;&apos;&apos; The country part is optional. Valid are f.i. &quot;fr&quot;, &quot;fr-CH&quot;, &quot;en-US&quot;
+&apos;&apos;&apos; Encoding: The character set that should be used
+&apos;&apos;&apos; Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
+&apos;&apos;&apos; Note that LibreOffice probably does not implement all existing sets
+&apos;&apos;&apos; Default = UTF-8
+&apos;&apos;&apos; Locale2: fallback Locale to select if Locale po file does not exist (typically &quot;en-US&quot;)
+&apos;&apos;&apos; Encoding2: Encoding of the 2nd Locale file
+&apos;&apos;&apos; Returns: the instance or Nothing
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR The PO file does not exist
+
+Dim oL10N As Variant &apos; Return value
+Dim sFolderName As String &apos; Folder containing the PO files
+Dim sLocale As String &apos; Passed argument or that of the user session
+Dim sLocale2 As String &apos; Alias for Locale2
+Dim oLocale As Variant &apos; com.sun.star.lang.Locale
+Dim sPOFile As String &apos; PO file must exist
+Dim sEncoding As String &apos; Alias for Encoding
+Dim sEncoding2 As String &apos; Alias for Encoding2
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(pvArgs) Then pvArgs = Array()
+ sPOFile = &quot;&quot;
+ sEncoding = &quot;&quot;
+ If UBound(pvArgs) &gt;= 0 Then
+ If Not SF_Utils._ValidateFile(pvArgs(0), &quot;Folder (Arg0)&quot;, , True) Then GoTo Catch
+ sFolderName = pvArgs(0)
+ sLocale = &quot;&quot;
+ If UBound(pvArgs) &gt;= 1 Then
+ If Not SF_Utils._Validate(pvArgs(1), &quot;Locale (Arg1)&quot;, V_STRING) Then GoTo Catch
+ sLocale = pvArgs(1)
+ End If
+ If Len(sLocale) = 0 Then &apos; Called from Python, the Locale argument may be the zero-length string
+ Set oLocale = SF_Utils._GetUNOService(&quot;OfficeLocale&quot;)
+ sLocale = oLocale.Language &amp; &quot;-&quot; &amp; oLocale.Country
+ End If
+ If UBound(pvArgs) &gt;= 2 Then
+ If IsMissing(pvArgs(2)) Or IsEmpty(pvArgs(2)) Then pvArgs(2) = &quot;UTF-8&quot;
+ If Not SF_Utils._Validate(pvArgs(2), &quot;Encoding (Arg2)&quot;, V_STRING) Then GoTo Catch
+ sEncoding = pvArgs(2)
+ Else
+ sEncoding = &quot;UTF-8&quot;
+ End If
+ sLocale2 = &quot;&quot;
+ If UBound(pvArgs) &gt;= 3 Then
+ If Not SF_Utils._Validate(pvArgs(3), &quot;Locale2 (Arg3)&quot;, V_STRING) Then GoTo Catch
+ sLocale2 = pvArgs(3)
+ End If
+ If UBound(pvArgs) &gt;= 4 Then
+ If Not SF_Utils._Validate(pvArgs(4), &quot;Encoding2 (Arg4)&quot;, V_STRING) Then GoTo Catch
+ sEncoding2 = pvArgs(4)
+ Else
+ sEncoding2 = &quot;UTF-8&quot;
+ End If
+ If Len(sFolderName) &gt; 0 Then
+ sPOFile = SF_FileSystem.BuildPath(sFolderName, sLocale &amp; &quot;.po&quot;)
+ If Not SF_FileSystem.FileExists(sPOFile) Then
+ If Len(sLocale2) = 0 Then GoTo CatchNotExists &apos; No fallback =&gt; error
+ &apos; Try the fallback
+ sPOFile = SF_FileSystem.BuildPath(sFolderName, sLocale2 &amp; &quot;.po&quot;)
+ If Not SF_FileSystem.FileExists(sPOFile) Then GoTo CatchNotExists
+ sEncoding = sEncoding2
+ End If
+ End If
+ End If
+
+Try:
+ Set oL10N = New SF_L10N
+ Set oL10N.[Me] = oL10N
+ oL10N._Initialize(sPOFile, sEncoding)
+
+Finally:
+ Set _NewL10N = oL10N
+ Exit Function
+Catch:
+ Set oL10N = Nothing
+ GoTo Finally
+CatchNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, sPOFile)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Services._NewL10N
+
+REM -----------------------------------------------------------------------------
+Public Function _NewTimer(Optional ByVal pvArgs As Variant) As Variant
+&apos;&apos;&apos; Create a new instance of the SF_Timer class
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; [0] : If True, start the timer immediately
+&apos;&apos;&apos; Returns: the instance or Nothing
+
+Dim oTimer As Variant &apos; Return value
+Dim bStart As Boolean &apos; Automatic start ?
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(pvArgs) Then pvArgs = Array()
+ If UBound(pvArgs) &lt; 0 Then
+ bStart = False
+ Else
+ If Not SF_Utils._Validate(pvArgs(0), &quot;Start (Arg0)&quot;, V_BOOLEAN) Then GoTo Catch
+ bStart = pvArgs(0)
+ End If
+Try:
+ Set oTimer = New SF_Timer
+ Set oTimer.[Me] = oTimer
+ If bStart Then oTimer.Start()
+
+Finally:
+ Set _NewTimer = oTimer
+ Exit Function
+Catch:
+ Set oTimer = Nothing
+ GoTo Finally
+End Function &apos; ScriptForge.SF_Services._NewTimer
+
+REM ============================================== END OF SCRIPTFORGE.SF_SERVICES
+</script:module> \ No newline at end of file