This commit is contained in:
Jane
2024-07-16 15:55:31 +08:00
parent 8f4ec86367
commit 29bc31ade5
12411 changed files with 8139339 additions and 0 deletions

View File

@@ -0,0 +1,959 @@
<?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_Dictionary" 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 ClassModule
Option Explicit
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
&apos;&apos;&apos; SF_Dictionary
&apos;&apos;&apos; =============
&apos;&apos;&apos; Class for management of dictionaries
&apos;&apos;&apos; A dictionary is a collection of key-item pairs
&apos;&apos;&apos; The key is a not case-sensitive string
&apos;&apos;&apos; Items may be of any type
&apos;&apos;&apos; Keys, items can be retrieved, counted, etc.
&apos;&apos;&apos;
&apos;&apos;&apos; The implementation is based on
&apos;&apos;&apos; - one collection mapping keys and entries in the array
&apos;&apos;&apos; - one 1-column array: key + data
&apos;&apos;&apos;
&apos;&apos;&apos; Why a Dictionary class beside the builtin Collection class ?
&apos;&apos;&apos; A standard Basic collection does not support the retrieval of the keys
&apos;&apos;&apos; Additionally it may contain only simple data (strings, numbers, ...)
&apos;&apos;&apos;
&apos;&apos;&apos; Service instantiation example:
&apos;&apos;&apos; Dim myDict As Variant
&apos;&apos;&apos; myDict = CreateScriptService(&quot;Dictionary&quot;) &apos; Once per dictionary
&apos;&apos;&apos;
&apos;&apos;&apos; Detailed user documentation:
&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_dictionary.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 DUPLICATEKEYERROR = &quot;DUPLICATEKEYERROR&quot; &apos; Key exists already
Const UNKNOWNKEYERROR = &quot;UNKNOWNKEYERROR&quot; &apos; Key not found
Const INVALIDKEYERROR = &quot;INVALIDKEYERROR&quot; &apos; Key contains only spaces
REM ============================================================= PRIVATE MEMBERS
&apos; Defines an entry in the MapItems array
Type ItemMap
Key As String
Value As Variant
End Type
Private [Me] As Object
Private [_Parent] As Object
Private ObjectType As String &apos; Must be &quot;DICTIONARY&quot;
Private ServiceName As String
Private MapKeys As Variant &apos; To retain the original keys
Private MapItems As Variant &apos; Array of ItemMaps
Private _MapSize As Long &apos; Total number of entries in the dictionary
Private _MapRemoved As Long &apos; Number of inactive entries in the dictionary
REM ===================================================== CONSTRUCTOR/DESTRUCTOR
REM -----------------------------------------------------------------------------
Private Sub Class_Initialize()
Set [Me] = Nothing
Set [_Parent] = Nothing
ObjectType = &quot;DICTIONARY&quot;
ServiceName = &quot;ScriptForge.Dictionary&quot;
Set MapKeys = New Collection
Set MapItems = Array()
_MapSize = 0
_MapRemoved = 0
End Sub &apos; ScriptForge.SF_Dictionary Constructor
REM -----------------------------------------------------------------------------
Private Sub Class_Terminate()
Call Class_Initialize()
End Sub &apos; ScriptForge.SF_Dictionary Destructor
REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
RemoveAll()
Set Dispose = Nothing
End Function &apos; ScriptForge.SF_Dictionary Explicit destructor
REM ================================================================== PROPERTIES
REM -----------------------------------------------------------------------------
Property Get Count() As Long
&apos;&apos;&apos; Actual number of entries in the dictionary
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myDict.Count
Count = _PropertyGet(&quot;Count&quot;)
End Property &apos; ScriptForge.SF_Dictionary.Count
REM -----------------------------------------------------------------------------
Public Function Item(Optional ByVal Key As Variant) As Variant
&apos;&apos;&apos; Return the value of the item related to Key
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Key: the key value (string)
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; Empty if not found, otherwise the found value
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myDict.Item(&quot;ThisKey&quot;)
&apos;&apos;&apos; NB: defined as a function to not disrupt the Basic IDE debugger
Item = _PropertyGet(&quot;Item&quot;, Key)
End Function &apos; ScriptForge.SF_Dictionary.Item
REM -----------------------------------------------------------------------------
Property Get Items() as Variant
&apos;&apos;&apos; Return the list of Items as a 1D array
&apos;&apos;&apos; The Items and Keys properties return their respective contents in the same order
&apos;&apos;&apos; The order is however not necessarily identical to the creation sequence
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The array is empty if the dictionary is empty
&apos;&apos;&apos; Examples
&apos;&apos;&apos; a = myDict.Items
&apos;&apos;&apos; For Each b In a ...
Items = _PropertyGet(&quot;Items&quot;)
End Property &apos; ScriptForge.SF_Dictionary.Items
REM -----------------------------------------------------------------------------
Property Get Keys() as Variant
&apos;&apos;&apos; Return the list of keys as a 1D array
&apos;&apos;&apos; The Keys and Items properties return their respective contents in the same order
&apos;&apos;&apos; The order is however not necessarily identical to the creation sequence
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The array is empty if the dictionary is empty
&apos;&apos;&apos; Examples
&apos;&apos;&apos; a = myDict.Keys
&apos;&apos;&apos; For each b In a ...
Keys = _PropertyGet(&quot;Keys&quot;)
End Property &apos; ScriptForge.SF_Dictionary.Keys
REM ===================================================================== METHODS
REM -----------------------------------------------------------------------------
Public Function Add(Optional ByVal Key As Variant _
, Optional ByVal Item As Variant _
) As Boolean
&apos;&apos;&apos; Add a new key-item pair into the dictionary
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Key: must not yet exist in the dictionary
&apos;&apos;&apos; Item: any value, including an array, a Basic object, a UNO object, ...
&apos;&apos;&apos; Returns: True if successful
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; DUPLICATEKEYERROR: such a key exists already
&apos;&apos;&apos; INVALIDKEYERROR: zero-length string or only spaces
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myDict.Add(&quot;NewKey&quot;, NewValue)
Dim oItemMap As ItemMap &apos; New entry in the MapItems array
Const cstThisSub = &quot;Dictionary.Add&quot;
Const cstSubArgs = &quot;Key, Item&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Add = False
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
If IsArray(Item) Then
If Not SF_Utils._ValidateArray(Item, &quot;Item&quot;) Then GoTo Catch
Else
If Not SF_Utils._Validate(Item, &quot;Item&quot;) Then GoTo Catch
End If
End If
If Key = Space(Len(Key)) Then GoTo CatchInvalid
If Exists(Key) Then GoTo CatchDuplicate
Try:
_MapSize = _MapSize + 1
MapKeys.Add(_MapSize, Key)
oItemMap.Key = Key
oItemMap.Value = Item
ReDim Preserve MapItems(1 To _MapSize)
MapItems(_MapSize) = oItemMap
Add = True
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchDuplicate:
SF_Exception.RaiseFatal(DUPLICATEKEYERROR, &quot;Key&quot;, Key)
GoTo Finally
CatchInvalid:
SF_Exception.RaiseFatal(INVALIDKEYERROR, &quot;Key&quot;)
GoTo Finally
End Function &apos; ScriptForge.SF_Dictionary.Add
REM -----------------------------------------------------------------------------
Public Function ConvertToArray() As Variant
&apos;&apos;&apos; Store the content of the dictionary in a 2-columns array:
&apos;&apos;&apos; Key stored in 1st column, Item stored in 2nd
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; a zero-based 2D array(0:Count - 1, 0:1)
&apos;&apos;&apos; an empty array if the dictionary is empty
Dim vArray As Variant &apos; Return value
Dim sKey As String &apos; Tempry key
Dim vKeys As Variant &apos; Array of keys
Dim lCount As Long &apos; Counter
Const cstThisSub = &quot;Dictionary.ConvertToArray&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
vArray = Array()
If Count = 0 Then
Else
ReDim vArray(0 To Count - 1, 0 To 1)
lCount = -1
vKeys = Keys
For Each sKey in vKeys
lCount = lCount + 1
vArray(lCount, 0) = sKey
vArray(lCount, 1) = Item(sKey)
Next sKey
End If
Finally:
ConvertToArray = vArray()
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Dictionary.ConvertToArray
REM -----------------------------------------------------------------------------
Public Function ConvertToJson(ByVal Optional Indent As Variant) As Variant
&apos;&apos;&apos; Convert the content of the dictionary to a JSON string
&apos;&apos;&apos; JSON = JavaScript Object Notation: https://en.wikipedia.org/wiki/JSON
&apos;&apos;&apos; Limitations
&apos;&apos;&apos; Allowed item types: String, Boolean, numbers, Null and Empty
&apos;&apos;&apos; Arrays containing above types are allowed
&apos;&apos;&apos; Dates are converted into strings (not within arrays)
&apos;&apos;&apos; Other types are converted to their string representation (cfr. SF_String.Represent)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Indent:
&apos;&apos;&apos; If indent is a non-negative integer or string, then JSON array elements and object members will be pretty-printed with that indent level.
&apos;&apos;&apos; An indent level &lt;= 0 will only insert newlines.
&apos;&apos;&apos; &quot;&quot;, (the default) selects the most compact representation.
&apos;&apos;&apos; Using a positive integer indent indents that many spaces per level.
&apos;&apos;&apos; If indent is a string (such as Chr(9)), that string is used to indent each level.
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; the JSON string
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myDict.Add(&quot;p0&quot;, 12.5)
&apos;&apos;&apos; myDict.Add(&quot;p1&quot;, &quot;a string àé&quot;&quot;ê&quot;)
&apos;&apos;&apos; myDict.Add(&quot;p2&quot;, DateSerial(2020,9,28))
&apos;&apos;&apos; myDict.Add(&quot;p3&quot;, True)
&apos;&apos;&apos; myDict.Add(&quot;p4&quot;, Array(1,2,3))
&apos;&apos;&apos; MsgBox a.ConvertToJson() &apos; {&quot;p0&quot;: 12.5, &quot;p1&quot;: &quot;a string \u00e0\u00e9\&quot;\u00ea&quot;, &quot;p2&quot;: &quot;2020-09-28&quot;, &quot;p3&quot;: true, &quot;p4&quot;: [1, 2, 3]}
Dim sJson As String &apos; Return value
Dim vArray As Variant &apos; Array of property values
Dim oPropertyValue As Object &apos; com.sun.star.beans.PropertyValue
Dim sKey As String &apos; Tempry key
Dim vKeys As Variant &apos; Array of keys
Dim vItem As Variant &apos; Tempry item
Dim iVarType As Integer &apos; Extended VarType
Dim lCount As Long &apos; Counter
Dim vIndent As Variant &apos; Python alias of Indent
Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_Dictionary__ConvertToJson&quot;
Const cstThisSub = &quot;Dictionary.ConvertToJson&quot;
Const cstSubArgs = &quot;[Indent=Null]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
If IsMissing(Indent) Or IsEmpty(INDENT) Then Indent = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(Indent, &quot;Indent&quot;, Array(V_STRING, V_NUMERIC)) Then GoTo Finally
End If
sJson = &quot;&quot;
Try:
vArray = Array()
If Count = 0 Then
Else
ReDim vArray(0 To Count - 1)
lCount = -1
vKeys = Keys
For Each sKey in vKeys
&apos; Check item type
vItem = Item(sKey)
iVarType = SF_Utils._VarTypeExt(vItem)
Select Case iVarType
Case V_STRING, V_BOOLEAN, V_NUMERIC, V_NULL, V_EMPTY
Case V_DATE
vItem = SF_Utils._CDateToIso(vItem)
Case &gt;= V_ARRAY
Case Else
vItem = SF_Utils._Repr(vItem)
End Select
&apos; Build in each array entry a (Name, Value) pair
Set oPropertyValue = SF_Utils._MakePropertyValue(sKey, vItem)
lCount = lCount + 1
Set vArray(lCount) = oPropertyValue
Next sKey
End If
&apos;Pass array to Python script for the JSON conversion
With ScriptForge.SF_Session
vIndent = Indent
If VarType(Indent) = V_STRING Then
If Len(Indent) = 0 Then vIndent = Null
End If
sJson = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper, vArray, vIndent)
End With
Finally:
ConvertToJson = sJson
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Dictionary.ConvertToJson
REM -----------------------------------------------------------------------------
Public Function ConvertToPropertyValues() As Variant
&apos;&apos;&apos; Store the content of the dictionary in an array of PropertyValues
&apos;&apos;&apos; Key stored in Name, Item stored in Value
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; a zero-based 1D array(0:Count - 1). Each entry is a com.sun.star.beans.PropertyValue
&apos;&apos;&apos; Name: the key in the dictionary
&apos;&apos;&apos; Value:
&apos;&apos;&apos; Dates are converted to UNO dates
&apos;&apos;&apos; Empty arrays are replaced by Null
&apos;&apos;&apos; an empty array if the dictionary is empty
Dim vArray As Variant &apos; Return value
Dim oPropertyValue As Object &apos; com.sun.star.beans.PropertyValue
Dim sKey As String &apos; Tempry key
Dim vKeys As Variant &apos; Array of keys
Dim lCount As Long &apos; Counter
Const cstThisSub = &quot;Dictionary.ConvertToPropertyValues&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
vArray = Array()
If Count = 0 Then
Else
ReDim vArray(0 To Count - 1)
lCount = -1
vKeys = Keys
For Each sKey in vKeys
&apos; Build in each array entry a (Name, Value) pair
Set oPropertyValue = SF_Utils._MakePropertyValue(sKey, Item(sKey))
lCount = lCount + 1
Set vArray(lCount) = oPropertyValue
Next sKey
End If
Finally:
ConvertToPropertyValues = vArray()
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Dictionary.ConvertToPropertyValues
REM -----------------------------------------------------------------------------
Public Function Exists(Optional ByVal Key As Variant) As Boolean
&apos;&apos;&apos; Determine if a key exists in the dictionary
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Key: the key value (string)
&apos;&apos;&apos; Returns: True if key exists
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; If myDict.Exists(&quot;SomeKey&quot;) Then &apos; don&apos;t add again
Dim vItem As Variant &apos; Item part in MapKeys
Const cstThisSub = &quot;Dictionary.Exists&quot;
Const cstSubArgs = &quot;Key&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Exists = False
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
End If
Try:
&apos; Dirty but preferred to go through whole collection
On Local Error GoTo NotFound
vItem = MapKeys(Key)
NotFound:
Exists = ( Not ( Err = 5 ) And vItem &gt; 0 )
On Local Error GoTo 0
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Dictionary.Exists
REM -----------------------------------------------------------------------------
Public Function GetProperty(Optional ByVal PropertyName As Variant _
, Optional ByVal Key As Variant _
) As Variant
&apos;&apos;&apos; Return the actual value of the given property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyName: the name of the property as a string
&apos;&apos;&apos; Key: mandatory if PropertyName = &quot;Item&quot;, ignored otherwise
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The actual value of the property
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; ARGUMENTERROR The property does not exist
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myDict.GetProperty(&quot;Count&quot;)
Const cstThisSub = &quot;Dictionary.GetProperty&quot;
Const cstSubArgs = &quot;PropertyName, [Key]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
GetProperty = Null
Check:
If IsMissing(Key) Or IsEmpty(Key) Then Key = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
End If
Try:
GetProperty = _PropertyGet(PropertyName, Key)
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Dictionary.GetProperty
REM -----------------------------------------------------------------------------
Public Function ImportFromJson(Optional ByVal InputStr As Variant _
, Optional ByVal Overwrite As Variant _
) As Boolean
&apos;&apos;&apos; Adds the content of a Json string into the current dictionary
&apos;&apos;&apos; JSON = JavaScript Object Notation: https://en.wikipedia.org/wiki/JSON
&apos;&apos;&apos; Limitations
&apos;&apos;&apos; The JSON string may contain numbers, strings, booleans, null values and arrays containing those types
&apos;&apos;&apos; It must not contain JSON objects, i.e. sub-dictionaries
&apos;&apos;&apos; An attempt is made to convert strings to dates if they fit one of next patterns:
&apos;&apos;&apos; YYYY-MM-DD, HH:MM:SS or YYYY-MM-DD HH:MM:SS
&apos;&apos;&apos; Args:
&apos;&apos;&apos; InputStr: the json string to import
&apos;&apos;&apos; Overwrite: when True entries with same name may exist in the dictionary and their values are overwritten
&apos;&apos;&apos; Default = False
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if successful
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; DUPLICATEKEYERROR: such a key exists already
&apos;&apos;&apos; INVALIDKEYERROR: zero-length string or only spaces
&apos;&apos;&apos; Example:
&apos;&apos;&apos; Dim s As String
&apos;&apos;&apos; s = &quot;{&apos;firstName&apos;: &apos;John&apos;,&apos;lastName&apos;: &apos;Smith&apos;,&apos;isAlive&apos;: true,&apos;age&apos;: 66, &apos;birth&apos;: &apos;1954-09-28 20:15:00&apos;&quot; _
&apos;&apos;&apos; &amp; &quot;,&apos;address&apos;: {&apos;streetAddress&apos;: &apos;21 2nd Street&apos;,&apos;city&apos;: &apos;New York&apos;,&apos;state&apos;: &apos;NY&apos;,&apos;postalCode&apos;: &apos;10021-3100&apos;}&quot; _
&apos;&apos;&apos; &amp; &quot;,&apos;phoneNumbers&apos;: [{&apos;type&apos;: &apos;home&apos;,&apos;number&apos;: &apos;212 555-1234&apos;},{&apos;type&apos;: &apos;office&apos;,&apos;number&apos;: &apos;646 555-4567&apos;}]&quot; _
&apos;&apos;&apos; &amp; &quot;,&apos;children&apos;: [&apos;Q&apos;,&apos;M&apos;,&apos;G&apos;,&apos;T&apos;],&apos;spouse&apos;: null}&quot;
&apos;&apos;&apos; s = Replace(s, &quot;&apos;&quot;, &quot;&quot;&quot;&quot;)
&apos;&apos;&apos; myDict.ImportFromJson(s, OverWrite := True)
&apos;&apos;&apos; &apos; The (sub)-dictionaries &quot;address&quot; and &quot;phoneNumbers(0) and (1) are reduced to Empty
Dim bImport As Boolean &apos; Return value
Dim vArray As Variant &apos; JSON string converted to array
Dim vArrayEntry As Variant &apos; A single entry in vArray
Dim vKey As Variant &apos; Tempry key
Dim vItem As Variant &apos; Tempry item
Dim bExists As Boolean &apos; True when an entry exists
Dim dDate As Date &apos; String converted to Date
Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_Dictionary__ImportFromJson&quot;
Const cstThisSub = &quot;Dictionary.ImportFromJson&quot;
Const cstSubArgs = &quot;InputStr, [Overwrite=False]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bImport = False
Check:
If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = False
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoYo Finally
End If
Try:
With ScriptForge.SF_Session
vArray = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper, InputStr)
End With
If Not IsArray(vArray) Then GoTo Finally &apos; Conversion error or nothing to do
&apos; vArray = Array of subarrays = 2D DataArray (cfr. Calc)
For Each vArrayEntry In vArray
vKey = vArrayEntry(0)
If VarType(vKey) = V_STRING Then &apos; Else skip
vItem = vArrayEntry(1)
If Overwrite Then bExists = Exists(vKey) Else bExists = False
&apos; When the item matches a date pattern, convert it to a date
If VarType(vItem) = V_STRING Then
dDate = SF_Utils._CStrToDate(vItem)
If dDate &gt; -1 Then vItem = dDate
End If
If bExists Then
ReplaceItem(vKey, vItem)
Else
Add(vKey, vItem) &apos; Key controls are done in Add
End If
End If
Next vArrayEntry
bImport = True
Finally:
ImportFromJson = bImport
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Dictionary.ImportFromJson
REM -----------------------------------------------------------------------------
Public Function ImportFromPropertyValues(Optional ByVal PropertyValues As Variant _
, Optional ByVal Overwrite As Variant _
) As Boolean
&apos;&apos;&apos; Adds the content of an array of PropertyValues into the current dictionary
&apos;&apos;&apos; Names contain Keys, Values contain Items
&apos;&apos;&apos; UNO dates are replaced by Basic dates
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyValues: a zero-based 1D array. Each entry is a com.sun.star.beans.PropertyValue
&apos;&apos;&apos; Overwrite: when True entries with same name may exist in the dictionary and their values are overwritten
&apos;&apos;&apos; Default = False
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if successful
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; DUPLICATEKEYERROR: such a key exists already
&apos;&apos;&apos; INVALIDKEYERROR: zero-length string or only spaces
Dim bImport As Boolean &apos; Return value
Dim oPropertyValue As Object &apos; com.sun.star.beans.PropertyValue
Dim vItem As Variant &apos; Tempry item
Dim sObjectType As String &apos; UNO object type of dates
Dim bExists As Boolean &apos; True when an entry exists
Const cstThisSub = &quot;Dictionary.ImportFromPropertyValues&quot;
Const cstSubArgs = &quot;PropertyValues, [Overwrite=False]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bImport = False
Check:
If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = False
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If IsArray(PropertyValues) Then
If Not SF_Utils._ValidateArray(PropertyValues, &quot;PropertyValues&quot;, 1, V_OBJECT, True) Then GoTo Finally
Else
If Not SF_Utils._Validate(PropertyValues, &quot;PropertyValues&quot;, V_OBJECT) Then GoTo Finally
End If
If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoYo Finally
End If
Try:
If Not IsArray(PropertyValues) Then PropertyValues = Array(PropertyValues)
With oPropertyValue
For Each oPropertyValue In PropertyValues
If Overwrite Then bExists = Exists(.Name) Else bExists = False
If SF_Session.UnoObjectType(oPropertyValue) = &quot;com.sun.star.beans.PropertyValue&quot; Then
If IsUnoStruct(.Value) Then
sObjectType = SF_Session.UnoObjectType(.Value)
Select Case sObjectType
Case &quot;com.sun.star.util.DateTime&quot; : vItem = CDateFromUnoDateTime(.Value)
Case &quot;com.sun.star.util.Date&quot; : vItem = CDateFromUnoDate(.Value)
Case &quot;com.sun.star.util.Time&quot; : vItem = CDateFromUnoTime(.Value)
Case Else : vItem = .Value
End Select
Else
vItem = .Value
End If
If bExists Then
ReplaceItem(.Name, vItem)
Else
Add(.Name, vItem) &apos; Key controls are done in Add
End If
End If
Next oPropertyValue
End With
bImport = True
Finally:
ImportFromPropertyValues = bImport
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Dictionary.ImportFromPropertyValues
REM -----------------------------------------------------------------------------
Public Function Methods() As Variant
&apos;&apos;&apos; Return the list or methods of the Dictionary class as an array
Methods = Array( _
&quot;Add&quot; _
, &quot;ConvertToArray&quot; _
, &quot;ConvertToJson&quot; _
, &quot;ConvertToPropertyValues&quot; _
, &quot;Exists&quot; _
, &quot;ImportFromJson&quot; _
, &quot;ImportFromPropertyValues&quot; _
, &quot;Remove&quot; _
, &quot;RemoveAll&quot; _
, &quot;ReplaceItem&quot; _
, &quot;ReplaceKey&quot; _
)
End Function &apos; ScriptForge.SF_Dictionary.Methods
REM -----------------------------------------------------------------------------
Public Function Properties() As Variant
&apos;&apos;&apos; Return the list or properties of the Dictionary class as an array
Properties = Array( _
&quot;Count&quot; _
, &quot;Item&quot; _
, &quot;Items&quot; _
, &quot;Keys&quot; _
)
End Function &apos; ScriptForge.SF_Dictionary.Properties
REM -----------------------------------------------------------------------------
Public Function Remove(Optional ByVal Key As Variant) As Boolean
&apos;&apos;&apos; Remove an existing dictionary entry based on its key
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Key: must exist in the dictionary
&apos;&apos;&apos; Returns: True if successful
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; UNKNOWNKEYERROR: the key does not exist
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myDict.Remove(&quot;OldKey&quot;)
Dim lIndex As Long &apos; To remove entry in the MapItems array
Const cstThisSub = &quot;Dictionary.Remove&quot;
Const cstSubArgs = &quot;Key&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Remove = False
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
End If
If Not Exists(Key) Then GoTo CatchUnknown
Try:
lIndex = MapKeys.Item(Key)
MapKeys.Remove(Key)
Erase MapItems(lIndex) &apos; Is now Empty
_MapRemoved = _MapRemoved + 1
Remove = True
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchUnknown:
SF_Exception.RaiseFatal(UNKNOWNKEYERROR, &quot;Key&quot;, Key)
GoTo Finally
End Function &apos; ScriptForge.SF_Dictionary.Remove
REM -----------------------------------------------------------------------------
Public Function RemoveAll() As Boolean
&apos;&apos;&apos; Remove all the entries from the dictionary
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns: True if successful
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myDict.RemoveAll()
Dim vKeys As Variant &apos; Array of keys
Dim sColl As String &apos; A collection key in MapKeys
Const cstThisSub = &quot;Dictionary.RemoveAll&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
RemoveAll = False
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
vKeys = Keys
For Each sColl In vKeys
MapKeys.Remove(sColl)
Next sColl
Erase MapKeys
Erase MapItems
&apos; Make dictionary ready to receive new entries
Call Class_Initialize()
RemoveAll = True
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Dictionary.RemoveAll
REM -----------------------------------------------------------------------------
Public Function ReplaceItem(Optional ByVal Key As Variant _
, Optional ByVal Value As Variant _
) As Boolean
&apos;&apos;&apos; Replace the item value
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Key: must exist in the dictionary
&apos;&apos;&apos; Returns: True if successful
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; UNKNOWNKEYERROR: the old key does not exist
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myDict.ReplaceItem(&quot;Key&quot;, NewValue)
Dim oItemMap As ItemMap &apos; Content to update in the MapItems array
Dim lIndex As Long &apos; Entry in the MapItems array
Const cstThisSub = &quot;Dictionary.ReplaceItem&quot;
Const cstSubArgs = &quot;Key, Value&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
ReplaceItem = False
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
If IsArray(Value) Then
If Not SF_Utils._ValidateArray(Value, &quot;Value&quot;) Then GoTo Catch
Else
If Not SF_Utils._Validate(Value, &quot;Value&quot;) Then GoTo Catch
End If
End If
If Not Exists(Key) Then GoTo CatchUnknown
Try:
&apos; Find entry in MapItems and update it with the new value
lIndex = MapKeys.Item(Key)
oItemMap = MapItems(lIndex)
oItemMap.Value = Value
ReplaceItem = True
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchUnknown:
SF_Exception.RaiseFatal(UNKNOWNKEYERROR, &quot;Key&quot;, Key)
GoTo Finally
End Function &apos; ScriptForge.SF_Dictionary.ReplaceItem
REM -----------------------------------------------------------------------------
Public Function ReplaceKey(Optional ByVal Key As Variant _
, Optional ByVal Value As Variant _
) As Boolean
&apos;&apos;&apos; Replace existing key
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Key: must exist in the dictionary
&apos;&apos;&apos; Value: must not exist in the dictionary
&apos;&apos;&apos; Returns: True if successful
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; UNKNOWNKEYERROR: the old key does not exist
&apos;&apos;&apos; DUPLICATEKEYERROR: the new key exists
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myDict.ReplaceKey(&quot;OldKey&quot;, &quot;NewKey&quot;)
Dim oItemMap As ItemMap &apos; Content to update in the MapItems array
Dim lIndex As Long &apos; Entry in the MapItems array
Const cstThisSub = &quot;Dictionary.ReplaceKey&quot;
Const cstSubArgs = &quot;Key, Value&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
ReplaceKey = False
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
If Not SF_Utils._Validate(Value, &quot;Value&quot;, V_STRING) Then GoTo Catch
End If
If Not Exists(Key) Then GoTo CatchUnknown
If Value = Space(Len(Value)) Then GoTo CatchInvalid
If Exists(Value) Then GoTo CatchDuplicate
Try:
&apos; Remove the Key entry and create a new one in MapKeys
With MapKeys
lIndex = .Item(Key)
.Remove(Key)
.Add(lIndex, Value)
End With
oItemMap = MapItems(lIndex)
oItemMap.Key = Value
ReplaceKey = True
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchUnknown:
SF_Exception.RaiseFatal(UNKNOWNKEYERROR, &quot;Key&quot;, Key)
GoTo Finally
CatchDuplicate:
SF_Exception.RaiseFatal(DUPLICATEKEYERROR, &quot;Value&quot;, Value)
GoTo Finally
CatchInvalid:
SF_Exception.RaiseFatal(INVALIDKEYERROR, &quot;Key&quot;)
GoTo Finally
End Function &apos; ScriptForge.SF_Dictionary.ReplaceKey
REM -----------------------------------------------------------------------------
Public Function SetProperty(Optional ByVal PropertyName As Variant _
, Optional ByRef Value As Variant _
) As Boolean
&apos;&apos;&apos; Set a new value to the given property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyName: the name of the property as a string
&apos;&apos;&apos; Value: its new value
&apos;&apos;&apos; Exceptions
&apos;&apos;&apos; ARGUMENTERROR The property does not exist
Const cstThisSub = &quot;Dictionary.SetProperty&quot;
Const cstSubArgs = &quot;PropertyName, Value&quot;
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, &quot;PropertyName&quot;, 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 &apos; ScriptForge.SF_Dictionary.SetProperty
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
Private Function _PropertyGet(Optional ByVal psProperty As String _
, Optional pvKey As Variant _
)
&apos;&apos;&apos; Return the named property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psProperty: the name of the property
&apos;&apos;&apos; pvKey: the key to retrieve, numeric or string
Dim vItemMap As Variant &apos; Entry in the MapItems array
Dim vArray As Variant &apos; To get Keys or Values
Dim i As Long
Dim cstThisSub As String
Dim cstSubArgs As String
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
cstThisSub = &quot;SF_Dictionary.get&quot; &amp; psProperty
If IsMissing(pvKey) Then cstSubArgs = &quot;&quot; Else cstSubArgs = &quot;[Key]&quot;
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Select Case UCase(psProperty)
Case UCase(&quot;Count&quot;)
_PropertyGet = _MapSize - _MapRemoved
Case UCase(&quot;Item&quot;)
If Not SF_Utils._Validate(pvKey, &quot;Key&quot;, V_STRING) Then GoTo Catch
If Exists(pvKey) Then _PropertyGet = MapItems(MapKeys(pvKey)).Value Else _PropertyGet = Empty
Case UCase(&quot;Keys&quot;), UCase(&quot;Items&quot;)
vArray = Array()
If _MapSize - _MapRemoved - 1 &gt;= 0 Then
ReDim vArray(0 To (_MapSize - _MapRemoved - 1))
i = -1
For each vItemMap In MapItems()
If Not IsEmpty(vItemMap) Then
i = i + 1
If UCase(psProperty) = &quot;KEYS&quot; Then vArray(i) = vItemMap.Key Else vArray(i) = vItemMap.Value
End If
Next vItemMap
End If
_PropertyGet = vArray
End Select
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Dictionary._PropertyGet
REM -----------------------------------------------------------------------------
Private Function _Repr() As String
&apos;&apos;&apos; Convert the Dictionary instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Return:
&apos;&apos;&apos; &quot;[Dictionary] (key1:value1, key2:value2, ...)
Dim sDict As String &apos; Return value
Dim vKeys As Variant &apos; Array of keys
Dim sKey As String &apos; Tempry key
Dim vItem As Variant &apos; Tempry item
Const cstDictEmpty = &quot;[Dictionary] ()&quot;
Const cstDict = &quot;[Dictionary]&quot;
Const cstMaxLength = 50 &apos; Maximum length for items
Const cstSeparator = &quot;, &quot;
_Repr = &quot;&quot;
If Count = 0 Then
sDict = cstDictEmpty
Else
sDict = cstDict &amp; &quot; (&quot;
vKeys = Keys
For Each sKey in vKeys
vItem = Item(sKey)
sDict = sDict &amp; sKey &amp; &quot;:&quot; &amp; SF_Utils._Repr(vItem, cstMaxLength) &amp; cstSeparator
Next sKey
sDict = Left(sDict, Len(sDict) - Len(cstSeparator)) &amp; &quot;)&quot; &apos; Suppress last comma
End If
_Repr = sDict
End Function &apos; ScriptForge.SF_Dictionary._Repr
REM ============================================ END OF SCRIPTFORGE.SF_DICTIONARY
</script:module>

View File

@@ -0,0 +1,825 @@
<?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_L10N" 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 ClassModule
&apos;Option Private Module
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; L10N (aka SF_L10N)
&apos;&apos;&apos; ====
&apos;&apos;&apos; Implementation of a Basic class for providing a number of services
&apos;&apos;&apos; related to the translation of user interfaces into a huge number of languages
&apos;&apos;&apos; with a minimal impact on the program code itself
&apos;&apos;&apos;
&apos;&apos;&apos; The design choices of this module are based on so-called PO-files
&apos;&apos;&apos; PO-files (portable object files) have long been promoted in the free software industry
&apos;&apos;&apos; as a mean of providing multilingual UIs. This is accomplished through the use of human-readable
&apos;&apos;&apos; text files with a well defined structure that specifies, for any given language,
&apos;&apos;&apos; the source language string and the localized string
&apos;&apos;&apos;
&apos;&apos;&apos; To read more about the PO format and its ecosystem of associated toolsets:
&apos;&apos;&apos; https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html#PO-Files
&apos;&apos;&apos; and, IMHO, a very good tutorial:
&apos;&apos;&apos; http://pology.nedohodnik.net/doc/user/en_US/ch-about.html
&apos;&apos;&apos;
&apos;&apos;&apos; The main advantage of the PO format is the complete dissociation between the two
&apos;&apos;&apos; very different profiles, i.e. the programmer and the translator(s).
&apos;&apos;&apos; Being independent text files, one per language to support, the programmer may give away
&apos;&apos;&apos; pristine PO template files (known as POT-files) for a translator to process.
&apos;&apos;&apos;
&apos;&apos;&apos; This class implements mainly 4 mechanisms:
&apos;&apos;&apos; 1. AddText: for the programmer to build a set of words or sentences
&apos;&apos;&apos; meant for being translated later
&apos;&apos;&apos; 2. AddTextsFromDialog: to automatically execute AddText() on each fixed text of a dialog
&apos;&apos;&apos; 3. ExportToPOTFile: All the above texts are exported into a pristine POT-file
&apos;&apos;&apos; 4. GetText: At runtime get the text in the user language
&apos;&apos;&apos; Note that the first two are optional: POT and PO-files may be built with a simple text editor
&apos;&apos;&apos;
&apos;&apos;&apos; Several instances of the L10N class may coexist
&apos; The constraint however is that each instance should find its PO-files
&apos;&apos;&apos; in a separate directory
&apos;&apos;&apos; PO-files must be named with the targeted locale: f.i. &quot;en-US.po&quot; or &quot;fr-BE.po&quot;
&apos;&apos;&apos;
&apos;&apos;&apos; Service invocation syntax
&apos;&apos;&apos; CreateScriptService(&quot;L10N&quot;[, FolderName[, Locale]])
&apos;&apos;&apos; FolderName: the folder containing the PO-files (in SF_FileSystem.FileNaming notation)
&apos;&apos;&apos; Locale: in the form la-CO (language-COUNTRY)
&apos;&apos;&apos; Encoding: The character set that should be used (default = UTF-8)
&apos;&apos;&apos; Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
&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; Service invocation examples:
&apos;&apos;&apos; Dim myPO As Variant
&apos;&apos;&apos; myPO = CreateScriptService(&quot;L10N&quot;) &apos; AddText, AddTextsFromDialog and ExportToPOTFile are allowed
&apos;&apos;&apos; myPO = CreateScriptService(&quot;L10N&quot;, &quot;C:\myPOFiles\&quot;, &quot;fr-BE&quot;)
&apos;&apos;&apos; &apos;All functionalities are available
&apos;&apos;&apos;
&apos;&apos;&apos; Detailed user documentation:
&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_l10n.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 =============================================================== PRIVATE TYPES
&apos;&apos;&apos; The recognized elements of an entry in a PO file are (other elements are ignored) :
&apos;&apos;&apos; #. Extracted comments (given by the programmer to the translator)
&apos;&apos;&apos; #, flag (the kde-format flag when the string contains tokens)
&apos;&apos;&apos; msgctxt Context (to store an acronym associated with the message, this is a distortion of the norm)
&apos;&apos;&apos; msgid untranslated-string
&apos;&apos;&apos; msgstr translated-string
&apos;&apos;&apos; NB: plural forms are not supported
Type POEntry
Comment As String
Flag As String
Context As String
MsgId As String
MsgStr As String
End Type
REM ================================================================== EXCEPTIONS
Const DUPLICATEKEYERROR = &quot;DUPLICATEKEYERROR&quot;
REM ============================================================= PRIVATE MEMBERS
Private [Me] As Object
Private [_Parent] As Object
Private ObjectType As String &apos; Must be &quot;L10N&quot;
Private ServiceName As String
Private _POFolder As String &apos; PO files container
Private _Locale As String &apos; la-CO
Private _POFile As String &apos; PO file in URL format
Private _Encoding As String &apos; Used to open the PO file, default = UTF-8
Private _Dictionary As Object &apos; SF_Dictionary
REM ===================================================== CONSTRUCTOR/DESTRUCTOR
REM -----------------------------------------------------------------------------
Private Sub Class_Initialize()
Set [Me] = Nothing
Set [_Parent] = Nothing
ObjectType = &quot;L10N&quot;
ServiceName = &quot;ScriptForge.L10N&quot;
_POFolder = &quot;&quot;
_Locale = &quot;&quot;
_POFile = &quot;&quot;
Set _Dictionary = Nothing
End Sub &apos; ScriptForge.SF_L10N Constructor
REM -----------------------------------------------------------------------------
Private Sub Class_Terminate()
If Not IsNull(_Dictionary) Then Set _Dictionary = _Dictionary.Dispose()
Call Class_Initialize()
End Sub &apos; ScriptForge.SF_L10N Destructor
REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
Call Class_Terminate()
Set Dispose = Nothing
End Function &apos; ScriptForge.SF_L10N Explicit Destructor
REM ================================================================== PROPERTIES
REM -----------------------------------------------------------------------------
Property Get Folder() As String
&apos;&apos;&apos; Returns the FolderName containing the PO-files expressed as given by the current FileNaming
&apos;&apos;&apos; property of the SF_FileSystem service. Default = URL format
&apos;&apos;&apos; May be empty
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myPO.Folder
Folder = _PropertyGet(&quot;Folder&quot;)
End Property &apos; ScriptForge.SF_L10N.Folder
REM -----------------------------------------------------------------------------
Property Get Languages() As Variant
&apos;&apos;&apos; Returns a zero-based array listing all the BaseNames of the PO-files found in Folder,
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myPO.Languages
Languages = _PropertyGet(&quot;Languages&quot;)
End Property &apos; ScriptForge.SF_L10N.Languages
REM -----------------------------------------------------------------------------
Property Get Locale() As String
&apos;&apos;&apos; Returns the currently active language-COUNTRY combination. May be empty
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myPO.Locale
Locale = _PropertyGet(&quot;Locale&quot;)
End Property &apos; ScriptForge.SF_L10N.Locale
REM ===================================================================== METHODS
REM -----------------------------------------------------------------------------
Public Function AddText(Optional ByVal Context As Variant _
, Optional ByVal MsgId As Variant _
, Optional ByVal Comment As Variant _
, Optional ByVal MsgStr As Variant _
) As Boolean
&apos;&apos;&apos; Add a new entry in the list of localizable text strings
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Context: when not empty, the key to retrieve the translated string via GetText. Default = &quot;&quot;
&apos;&apos;&apos; MsgId: the untranslated string, i.e. the text appearing in the program code. Must not be empty
&apos;&apos;&apos; The key to retrieve the translated string via GetText when Context is empty
&apos;&apos;&apos; May contain placeholders (%1 ... %9) for dynamic arguments to be inserted in the text at run-time
&apos;&apos;&apos; If the string spans multiple lines, insert escape sequences (\n) where relevant
&apos;&apos;&apos; Comment: the so-called &quot;extracted-comments&quot; intended to inform/help translators
&apos;&apos;&apos; If the string spans multiple lines, insert escape sequences (\n) where relevant
&apos;&apos;&apos; MsgStr: (internal use only) the translated string
&apos;&apos;&apos; If the string spans multiple lines, insert escape sequences (\n) where relevant
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if successful
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; DUPLICATEKEYERROR: such a key exists already
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myPO.AddText(, &quot;This is a text to be included in a POT file&quot;)
Dim bAdd As Boolean &apos; Output buffer
Dim sKey As String &apos; The key part of the new entry in the dictionary
Dim vItem As POEntry &apos; The item part of the new entry in the dictionary
Const cstPipe = &quot;|&quot; &apos; Pipe forbidden in MsgId&apos;s
Const cstThisSub = &quot;L10N.AddText&quot;
Const cstSubArgs = &quot;[Context=&quot;&quot;&quot;&quot;], MsgId, [Comment=&quot;&quot;&quot;&quot;]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bAdd = False
Check:
If IsMissing(Context) Or IsMissing(Context) Then Context = &quot;&quot;
If IsMissing(Comment) Or IsMissing(Comment) Then Comment = &quot;&quot;
If IsMissing(MsgStr) Or IsMissing(MsgStr) Then MsgStr = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(Context, &quot;Context&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(MsgId, &quot;MsgId&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Comment, &quot;Comment&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(MsgStr, &quot;MsgStr&quot;, V_STRING) Then GoTo Finally
End If
If Len(MsgId) = 0 Then GoTo Finally
Try:
If Len(Context) &gt; 0 Then sKey = Context Else sKey = MsgId
If _Dictionary.Exists(sKey) Then GoTo CatchDuplicate
With vItem
.Comment = Comment
If InStr(MsgId, &quot;%&quot;) &gt; 0 Then .Flag = &quot;kde-format&quot; Else .Flag = &quot;&quot;
.Context = Replace(Context, cstPipe, &quot; &quot;)
.MsgId = Replace(MsgId, cstPipe, &quot; &quot;)
.MsgStr = MsgStr
End With
_Dictionary.Add(sKey, vItem)
bAdd = True
Finally:
AddText = bAdd
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchDuplicate:
SF_Exception.RaiseFatal(DUPLICATEKEYERROR, Iif(Len(Context) &gt; 0, &quot;Context&quot;, &quot;MsgId&quot;), sKey)
GoTo Finally
End Function &apos; ScriptForge.SF_L10N.AddText
REM -----------------------------------------------------------------------------
Public Function AddTextsFromDialog(Optional ByRef Dialog As Variant) As Boolean
&apos;&apos;&apos; Add all fixed text strings of a dialog to the list of localizable text strings
&apos;&apos;&apos; Added texts are:
&apos;&apos;&apos; - the title of the dialog
&apos;&apos;&apos; - the caption associated with next control types: Button, CheckBox, FixedLine, FixedText, GroupBox and RadioButton
&apos;&apos;&apos; - the content of list- and comboboxes
&apos;&apos;&apos; - the tip- or helptext displayed when the mouse is hovering the control
&apos;&apos;&apos; The current method has method SFDialogs.SF_Dialog.GetTextsFromL10N as counterpart
&apos;&apos;&apos; The targeted dialog must not be open when the current method is run
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Dialog: a SFDialogs.Dialog service instance
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True when successful
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; Dim myDialog As Object
&apos;&apos;&apos; Set myDialog = CreateScriptService(&quot;SFDialogs.Dialog&quot;, &quot;GlobalScope&quot;, &quot;XrayTool&quot;, &quot;DlgXray&quot;)
&apos;&apos;&apos; myPO.AddTextsFromDialog(myDialog)
Dim bAdd As Boolean &apos; Return value
Dim vControls As Variant &apos; Array of control names
Dim sControl As String &apos; A single control name
Dim oControl As Object &apos; SFDialogs.DialogControl
Dim sText As String &apos; The text to insert in the dictionary
Dim sDialogComment As String &apos; The prefix in the comment to insert in the dictionary for the dialog
Dim sControlComment As String &apos; The prefix in the comment to insert in the dictionary for a control
Dim vSource As Variant &apos; RowSource property of dialog control as an array
Dim i As Long
Const cstThisSub = &quot;L10N.AddTextsFromDialog&quot;
Const cstSubArgs = &quot;Dialog&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bAdd = False
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(Dialog, &quot;Dialog&quot;, V_OBJECT, , , &quot;DIALOG&quot;) Then GoTo Finally
End If
Try:
With Dialog
&apos; Store the title of the dialog
sDialogComment = &quot;Dialog =&gt; &quot; &amp; ._Container &amp; &quot; : &quot; &amp; ._Library &amp; &quot; : &quot; &amp; ._Name &amp; &quot; : &quot;
stext = .Caption
If Len(sText) &gt; 0 Then
If Not _ReplaceText(&quot;&quot;, sText, sDialogComment &amp; &quot;Caption&quot;) Then GoTo Catch
End If
&apos; Scan all controls
vControls = .Controls()
For Each sControl In vControls
Set oControl = .Controls(sControl)
sControlComment = sDialogComment &amp; sControl &amp; &quot;.&quot;
With oControl
&apos; Extract fixed texts
sText = .Caption
If Len(sText) &gt; 0 Then
If Not _ReplaceText(&quot;&quot;, sText, sControlComment &amp; &quot;Caption&quot;) Then GoTo Catch
End If
vSource = .RowSource &apos; List and comboboxes only
If IsArray(vSource) Then
For i = 0 To UBound(vSource)
If Len(vSource(i)) &gt; 0 Then
If Not _ReplaceText(&quot;&quot;, vSource(i), sControlComment &amp; &quot;RowSource[&quot; &amp; i &amp; &quot;]&quot;) Then GoTo Catch
End If
Next i
End If
sText = .TipText
If Len(sText) &gt; 0 Then
If Not _ReplaceText(&quot;&quot;, sText, sControlComment &amp; &quot;TipText&quot;) Then GoTo Catch
End If
End With
Next sControl
End With
bAdd = True
Finally:
AddTextsFromDialog = bAdd
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_L10N.AddTextsFromDialog
REM -----------------------------------------------------------------------------
Public Function ExportToPOTFile(Optional ByVal FileName As Variant _
, Optional ByVal Header As Variant _
, Optional ByVal Encoding As Variant _
) As Boolean
&apos;&apos;&apos; Export a set of untranslated strings as a POT file
&apos;&apos;&apos; The set of strings has been built either by a succession of AddText() methods
&apos;&apos;&apos; or by a successful invocation of the L10N service with the FolderName argument
&apos;&apos;&apos; The generated file should pass successfully the &quot;msgfmt --check &apos;the pofile&apos;&quot; GNU command
&apos;&apos;&apos; Args:
&apos;&apos;&apos; FileName: the complete file name to export to. If it exists, is overwritten without warning
&apos;&apos;&apos; Header: Comments that will appear on top of the generated file. Do not include any leading &quot;#&quot;
&apos;&apos;&apos; If the string spans multiple lines, insert escape sequences (\n) where relevant
&apos;&apos;&apos; A standard header will be added anyway
&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; Returns:
&apos;&apos;&apos; True if successful
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myPO.ExportToPOTFile(&quot;myFile.pot&quot;, Header := &quot;Top comment\nSecond line of top comment&quot;)
Dim bExport As Boolean &apos; Return value
Dim oFile As Object &apos; Generated file handler
Dim vLines As Variant &apos; Wrapped lines
Dim sLine As String &apos; A single line
Dim vItems As Variant &apos; Array of dictionary items
Dim vItem As Variant &apos; POEntry type
Const cstSharp = &quot;# &quot;, cstSharpDot = &quot;#. &quot;, cstFlag = &quot;#, kde-format&quot;
Const cstTabSize = 4
Const cstWrap = 70
Const cstThisSub = &quot;L10N.ExportToPOTFile&quot;
Const cstSubArgs = &quot;FileName, [Header=&quot;&quot;&quot;&quot;], [Encoding=&quot;&quot;UTF-8&quot;&quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bExport = False
Check:
If IsMissing(Header) Or IsEmpty(Header) Then Header = &quot;&quot;
If IsMissing(Encoding) Or IsEmpty(Encoding) Then Encoding = &quot;UTF-8&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
If Not SF_Utils._Validate(Header, &quot;Header&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Encoding, &quot;Encoding&quot;, V_STRING) Then GoTo Finally
End If
Try:
Set oFile = SF_FileSystem.CreateTextFile(FileName, Overwrite := True, Encoding := Encoding)
If Not IsNull(oFile) Then
With oFile
&apos; Standard header
.WriteLine(cstSharp)
.WriteLine(cstSharp &amp; &quot;This pristine POT file has been generated by LibreOffice/ScriptForge&quot;)
.WriteLine(cstSharp &amp; &quot;Full documentation is available on https://help.libreoffice.org/&quot;)
&apos; User header
If Len(Header) &gt; 0 Then
.WriteLine(cstSharp)
vLines = SF_String.Wrap(Header, cstWrap, cstTabSize)
For Each sLine In vLines
.WriteLine(cstSharp &amp; Replace(sLine, SF_String.sfLF, &quot;&quot;))
Next sLine
End If
&apos; Standard header
.WriteLine(cstSharp)
.WriteLine(&quot;msgid &quot;&quot;&quot;&quot;&quot;)
.WriteLine(&quot;msgstr &quot;&quot;&quot;&quot;&quot;)
.WriteLine(SF_String.Quote(&quot;Project-Id-Version: PACKAGE VERSION\n&quot;))
.WriteLine(SF_String.Quote(&quot;Report-Msgid-Bugs-To: &quot; _
&amp; &quot;https://bugs.libreoffice.org/enter_bug.cgi?product=LibreOffice&amp;bug_status=UNCONFIRMED&amp;component=UI\n&quot;))
.WriteLine(SF_String.Quote(&quot;POT-Creation-Date: &quot; &amp; SF_STring.Represent(Now()) &amp; &quot;\n&quot;))
.WriteLine(SF_String.Quote(&quot;PO-Revision-Date: YYYY-MM-DD HH:MM:SS\n&quot;))
.WriteLine(SF_String.Quote(&quot;Last-Translator: FULL NAME &lt;EMAIL@ADDRESS&gt;\n&quot;))
.WriteLine(SF_String.Quote(&quot;Language-Team: LANGUAGE &lt;EMAIL@ADDRESS&gt;\n&quot;))
.WriteLine(SF_String.Quote(&quot;Language: en_US\n&quot;))
.WriteLine(SF_String.Quote(&quot;MIME-Version: 1.0\n&quot;))
.WriteLine(SF_String.Quote(&quot;Content-Type: text/plain; charset=&quot; &amp; Encoding &amp; &quot;\n&quot;))
.WriteLine(SF_String.Quote(&quot;Content-Transfer-Encoding: 8bit\n&quot;))
.WriteLine(SF_String.Quote(&quot;Plural-Forms: nplurals=2; plural=n &gt; 1;\n&quot;))
.WriteLine(SF_String.Quote(&quot;X-Generator: LibreOffice - ScriptForge\n&quot;))
.WriteLine(SF_String.Quote(&quot;X-Accelerator-Marker: ~\n&quot;))
&apos; Individual translatable strings
vItems = _Dictionary.Items()
For Each vItem in vItems
.WriteBlankLines(1)
&apos; Comments
vLines = Split(vItem.Comment, &quot;\n&quot;)
For Each sLine In vLines
.WriteLine(cstSharpDot &amp; SF_String.ExpandTabs(SF_String.Unescape(sLine), cstTabSize))
Next sLine
&apos; Flag
If InStr(vItem.MsgId, &quot;%&quot;) &gt; 0 Then .WriteLine(cstFlag)
&apos; Context
If Len(vItem.Context) &gt; 0 Then
.WriteLine(&quot;msgctxt &quot; &amp; SF_String.Quote(vItem.Context))
End If
&apos; MsgId
vLines = SF_String.Wrap(vItem.MsgId, cstWrap, cstTabSize)
If UBound(vLines) = 0 Then
.WriteLine(&quot;msgid &quot; &amp; SF_String.Quote(SF_String.Escape(vLines(0))))
Else
.WriteLine(&quot;msgid &quot;&quot;&quot;&quot;&quot;)
For Each sLine in vLines
.WriteLine(SF_String.Quote(SF_String.Escape(sLine)))
Next sLine
End If
&apos; MsgStr
.WriteLine(&quot;msgstr &quot;&quot;&quot;&quot;&quot;)
Next vItem
.CloseFile()
End With
End If
bExport = True
Finally:
If Not IsNull(oFile) Then Set oFile = oFile.Dispose()
ExportToPOTFile = bExport
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_L10N.ExportToPOTFile
REM -----------------------------------------------------------------------------
Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
&apos;&apos;&apos; Return the actual value of the given property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyName: the name of the property as a string
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The actual value of the property
&apos;&apos;&apos; If the property does not exist, returns Null
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; ARGUMENTERROR The property does not exist
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myL10N.GetProperty(&quot;MyProperty&quot;)
Const cstThisSub = &quot;L10N.GetProperty&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
GetProperty = Null
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
End If
Try:
GetProperty = _PropertyGet(PropertyName)
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_L10N.GetProperty
REM -----------------------------------------------------------------------------
Public Function GetText(Optional ByVal MsgId As Variant _
, ParamArray pvArgs As Variant _
) As String
&apos;&apos;&apos; Get the translated string corresponding with the given argument
&apos;&apos;&apos; Args:
&apos;&apos;&apos; MsgId: the identifier of the string or the untranslated string
&apos;&apos;&apos; Either - the untranslated text (MsgId)
&apos;&apos;&apos; - the reference to the untranslated text (Context)
&apos;&apos;&apos; - both (Context|MsgId) : the pipe character is essential
&apos;&apos;&apos; pvArgs(): a list of arguments present as %1, %2, ... in the (un)translated string)
&apos;&apos;&apos; to be substituted in the returned string
&apos;&apos;&apos; Any type is admitted but only strings, numbers or dates are relevant
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The translated string
&apos;&apos;&apos; If not found the MsgId string or the Context string
&apos;&apos;&apos; Anyway the substitution is done
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myPO.GetText(&quot;This is a text to be included in a POT file&quot;)
&apos;&apos;&apos; &apos; Ceci est un text à inclure dans un fichier POT
Dim sText As String &apos; Output buffer
Dim sContext As String &apos; Context part of argument
Dim sMsgId As String &apos; MsgId part of argument
Dim vItem As POEntry &apos; Entry in the dictionary
Dim vMsgId As Variant &apos; MsgId split on pipe
Dim sKey As String &apos; Key of dictionary
Dim sPercent As String &apos; %1, %2, ... placeholders
Dim i As Long
Const cstPipe = &quot;|&quot;
Const cstThisSub = &quot;L10N.GetText&quot;
Const cstSubArgs = &quot;MsgId, [Arg0, Arg1, ...]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
sText = &quot;&quot;
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(MsgId, &quot;MsgId&quot;, V_STRING) Then GoTo Finally
End If
If Len(Trim(MsgId)) = 0 Then GoTo Finally
sText = MsgId
Try:
&apos; Find and load entry from dictionary
If Left(MsgId, 1) = cstPipe then MsgId = Mid(MsgId, 2)
vMsgId = Split(MsgId, cstPipe)
sKey = vMsgId(0)
If Not _Dictionary.Exists(sKey) Then &apos; Not found
If UBound(vMsgId) = 0 Then sText = vMsgId(0) Else sText = Mid(MsgId, InStr(MsgId, cstPipe) + 1)
Else
vItem = _Dictionary.Item(sKey)
If Len(vItem.MsgStr) &gt; 0 Then sText = vItem.MsgStr Else sText = vItem.MsgId
End If
&apos; Substitute %i placeholders
For i = UBound(pvArgs) To 0 Step -1 &apos; Go downwards to not have a limit in number of args
sPercent = &quot;%&quot; &amp; (i + 1)
sText = Replace(sText, sPercent, SF_String.Represent(pvArgs(i)))
Next i
Finally:
GetText = sText
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_L10N.GetText
REM - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Public Function _(Optional ByVal MsgId As Variant _
, ParamArray pvArgs As Variant _
) As String
&apos;&apos;&apos; Get the translated string corresponding with the given argument
&apos;&apos;&apos; Alias of GetText() - See above
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myPO._(&quot;This is a text to be included in a POT file&quot;)
&apos;&apos;&apos; &apos; Ceci est un text à inclure dans un fichier POT
Dim sText As String &apos; Output buffer
Dim sPercent As String &apos; %1, %2, ... placeholders
Dim i As Long
Const cstPipe = &quot;|&quot;
Const cstThisSub = &quot;L10N._&quot;
Const cstSubArgs = &quot;MsgId, [Arg0, Arg1, ...]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
sText = &quot;&quot;
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(MsgId, &quot;MsgId&quot;, V_STRING) Then GoTo Finally
End If
If Len(Trim(MsgId)) = 0 Then GoTo Finally
Try:
&apos; Find and load entry from dictionary
sText = GetText(MsgId)
&apos; Substitute %i placeholders - done here, not in GetText(), because # of arguments is undefined
For i = 0 To UBound(pvArgs)
sPercent = &quot;%&quot; &amp; (i + 1)
sText = Replace(sText, sPercent, SF_String.Represent(pvArgs(i)))
Next i
Finally:
_ = sText
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_L10N._
REM -----------------------------------------------------------------------------
Public Function Methods() As Variant
&apos;&apos;&apos; Return the list of public methods of the L10N service as an array
Methods = Array( _
&quot;AddText&quot; _
, &quot;ExportToPOTFile&quot; _
, &quot;GetText&quot; _
, &quot;AddTextsFromDialog&quot; _
, &quot;_&quot; _
)
End Function &apos; ScriptForge.SF_L10N.Methods
REM -----------------------------------------------------------------------------
Public Function Properties() As Variant
&apos;&apos;&apos; Return the list or properties of the Timer class as an array
Properties = Array( _
&quot;Folder&quot; _
, &quot;Languages&quot; _
, &quot;Locale&quot; _
)
End Function &apos; ScriptForge.SF_L10N.Properties
REM -----------------------------------------------------------------------------
Public Function SetProperty(Optional ByVal PropertyName As Variant _
, Optional ByRef Value As Variant _
) As Boolean
&apos;&apos;&apos; Set a new value to the given property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyName: the name of the property as a string
&apos;&apos;&apos; Value: its new value
&apos;&apos;&apos; Exceptions
&apos;&apos;&apos; ARGUMENTERROR The property does not exist
Const cstThisSub = &quot;L10N.SetProperty&quot;
Const cstSubArgs = &quot;PropertyName, Value&quot;
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, &quot;PropertyName&quot;, 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 &apos; ScriptForge.SF_L10N.SetProperty
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
Public Sub _Initialize(ByVal psPOFile As String _
, ByVal Encoding As String _
)
&apos;&apos;&apos; Completes initialization of the current instance requested from CreateScriptService()
&apos;&apos;&apos; Load the POFile in the dictionary, otherwise leave the dictionary empty
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psPOFile: the file to load the translated strings from
&apos;&apos;&apos; Encoding: The character set that should be used. Default = UTF-8
Dim oFile As Object &apos; PO file handler
Dim sContext As String &apos; Collected context string
Dim sMsgId As String &apos; Collected untranslated string
Dim sComment As String &apos; Collected comment string
Dim sMsgStr As String &apos; Collected translated string
Dim sLine As String &apos; Last line read
Dim iContinue As Integer &apos; 0 = None, 1 = MsgId, 2 = MsgStr
Const cstMsgId = 1, cstMsgStr = 2
Try:
&apos; Initialize dictionary anyway
Set _Dictionary = SF_Services.CreateScriptService(&quot;Dictionary&quot;)
Set _Dictionary.[_Parent] = [Me]
&apos; Load PO file
If Len(psPOFile) &gt; 0 Then
With SF_FileSystem
_POFolder = ._ConvertToUrl(.GetParentFolderName(psPOFile))
_Locale = .GetBaseName(psPOFile)
_POFile = ._ConvertToUrl(psPOFile)
End With
&apos; Load PO file
Set oFile = SF_FileSystem.OpenTextFile(psPOFile, IOMode := SF_FileSystem.ForReading, Encoding := Encoding)
If Not IsNull(oFile) Then
With oFile
&apos; The PO file is presumed valid =&gt; syntax check is not very strict
sContext = &quot;&quot; : sMsgId = &quot;&quot; : sComment = &quot;&quot; : sMsgStr = &quot;&quot;
Do While Not .AtEndOfStream
sLine = Trim(.ReadLine())
&apos; Trivial examination of line header
Select Case True
Case sLine = &quot;&quot;
If Len(sMsgId) &gt; 0 Then AddText(sContext, sMsgId, sComment, sMsgStr)
sContext = &quot;&quot; : sMsgId = &quot;&quot; : sComment = &quot;&quot; : sMsgStr = &quot;&quot;
iContinue = 0
Case Left(sLine, 3) = &quot;#. &quot;
sComment = sComment &amp; Iif(Len(sComment) &gt; 0, &quot;\n&quot;, &quot;&quot;) &amp; Trim(Mid(sLine, 4))
iContinue = 0
Case Left(sLine, 8) = &quot;msgctxt &quot;
sContext = SF_String.Unquote(Trim(Mid(sLine, 9)))
iContinue = 0
Case Left(sLine, 6) = &quot;msgid &quot;
sMsgId = SF_String.Unquote(Trim(Mid(sLine, 7)))
iContinue = cstMsgId
Case Left(sLine, 7) = &quot;msgstr &quot;
sMsgStr = sMsgStr &amp; SF_String.Unquote(Trim(Mid(sLine, 8)))
iContinue = cstMsgStr
Case Left(sLine, 1) = &quot;&quot;&quot;&quot;
If iContinue = cstMsgId Then
sMsgId = sMsgId &amp; SF_String.Unquote(sLine)
ElseIf iContinue = cstMsgStr Then
sMsgStr = sMsgStr &amp; SF_String.Unquote(sLine)
Else
iContinue = 0
End If
Case Else &apos; Skip line
iContinue = 0
End Select
Loop
&apos; Be sure to store the last entry
If Len(sMsgId) &gt; 0 Then AddText(sContext, sMsgId, sComment, sMsgStr)
.CloseFile()
Set oFile = .Dispose()
End With
End If
Else
_POFolder = &quot;&quot;
_Locale = &quot;&quot;
_POFile = &quot;&quot;
End If
Finally:
Exit Sub
End Sub &apos; ScriptForge.SF_L10N._Initialize
REM -----------------------------------------------------------------------------
Private Function _PropertyGet(Optional ByVal psProperty As String)
&apos;&apos;&apos; Return the value of the named property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psProperty: the name of the property
Dim vFiles As Variant &apos; Array of PO-files
Dim i As Long
Dim cstThisSub As String
Dim cstSubArgs As String
cstThisSub = &quot;SF_L10N.get&quot; &amp; psProperty
cstSubArgs = &quot;&quot;
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
With SF_FileSystem
Select Case psProperty
Case &quot;Folder&quot;
If Len(_POFolder) &gt; 0 Then _PropertyGet = ._ConvertFromUrl(_POFolder) Else _PropertyGet = &quot;&quot;
Case &quot;Languages&quot;
If Len(_POFolder) &gt; 0 Then
vFiles = .Files(._ConvertFromUrl(_POFolder), &quot;*.po&quot;)
For i = 0 To UBound(vFiles)
vFiles(i) = SF_FileSystem.GetBaseName(vFiles(i))
Next i
Else
vFiles = Array()
End If
_PropertyGet = vFiles
Case &quot;Locale&quot;
_PropertyGet = _Locale
Case Else
_PropertyGet = Null
End Select
End With
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_L10N._PropertyGet
REM -----------------------------------------------------------------------------
Private Function _ReplaceText(ByVal psContext As String _
, ByVal psMsgId As String _
, ByVal psComment As String _
) As Boolean
&apos;&apos;&apos; When the entry in the dictionary does not yet exist, equivalent to AddText
&apos;&apos;&apos; When it exists already, extend the existing comment with the psComment argument
&apos;&apos;&apos; Used from AddTextsFromDialog to manage identical strings without raising errors,
&apos;&apos;&apos; e.g. when multiple dialogs have the same &quot;Close&quot; button
Dim bAdd As Boolean &apos; Return value
Dim sKey As String &apos; The key part of an entry in the dictionary
Dim vItem As POEntry &apos; The item part of the new entry in the dictionary
Try:
bAdd = False
If Len(psContext) &gt; 0 Then sKey = psContext Else sKey = psMsgId
If _Dictionary.Exists(sKey) Then
&apos; Load the entry, adapt comment and rewrite
vItem = _Dictionary.Item(sKey)
If Len(vItem.Comment) = 0 Then vItem.Comment = psComment Else vItem.Comment = vItem.Comment &amp; &quot;\n&quot; &amp; psComment
bAdd = _Dictionary.ReplaceItem(sKey, vItem)
Else
&apos; Add a new entry as usual
bAdd = AddText(psContext, psMsgId, psComment)
End If
Finally:
_ReplaceText = bAdd
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_L10N._ReplaceText
REM -----------------------------------------------------------------------------
Private Function _Repr() As String
&apos;&apos;&apos; Convert the L10N instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Return:
&apos;&apos;&apos; &quot;[L10N]: PO file&quot;
_Repr = &quot;[L10N]: &quot; &amp; _POFile
End Function &apos; ScriptForge.SF_L10N._Repr
REM ============================================ END OF SCRIPTFORGE.SF_L10N
</script:module>

View File

@@ -0,0 +1,451 @@
<?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_Platform" 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_Platform
&apos;&apos;&apos; ===========
&apos;&apos;&apos; Singleton class implementing the &quot;ScriptForge.Platform&quot; service
&apos;&apos;&apos; Implemented as a usual Basic module
&apos;&apos;&apos;
&apos;&apos;&apos; A collection of properties about the execution environment:
&apos;&apos;&apos; - HW platform
&apos;&apos;&apos; - Operating System
&apos;&apos;&apos; - current user
&apos;&apos;&apos; - LibreOffice version
&apos;&apos;&apos;
&apos;&apos;&apos; Service invocation example:
&apos;&apos;&apos; Dim platform As Variant
&apos;&apos;&apos; platform = CreateScriptService(&quot;Platform&quot;)
&apos;&apos;&apos;
&apos;&apos;&apos; Detailed user documentation:
&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_platform.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
REM ============================================================ MODULE CONSTANTS
REM ===================================================== CONSTRUCTOR/DESTRUCTOR
REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
Set Dispose = Nothing
End Function &apos; ScriptForge.SF_Array Explicit destructor
REM ================================================================== PROPERTIES
REM -----------------------------------------------------------------------------
Property Get Architecture() As String
&apos;&apos;&apos; Returns the actual bit architecture
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.Architecture &apos; 64bit
Architecture = _PropertyGet(&quot;Architecture&quot;)
End Property &apos; ScriptForge.SF_Platform.Architecture (get)
REM -----------------------------------------------------------------------------
Property Get ComputerName() As String
&apos;&apos;&apos; Returns the computer&apos;s network name
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.ComputerName
ComputerName = _PropertyGet(&quot;ComputerName&quot;)
End Property &apos; ScriptForge.SF_Platform.ComputerName (get)
REM -----------------------------------------------------------------------------
Property Get CPUCount() As Integer
&apos;&apos;&apos; Returns the number of Central Processor Units
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.CPUCount &apos; 4
CPUCount = _PropertyGet(&quot;CPUCount&quot;)
End Property &apos; ScriptForge.SF_Platform.CPUCount (get)
REM -----------------------------------------------------------------------------
Property Get CurrentUser() As String
&apos;&apos;&apos; Returns the name of logged in user
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.CurrentUser
CurrentUser = _PropertyGet(&quot;CurrentUser&quot;)
End Property &apos; ScriptForge.SF_Platform.CurrentUser (get)
REM -----------------------------------------------------------------------------
Property Get Extensions() As Variant
&apos;&apos;&apos; Returns the list of availableeExtensions as an unsorted array of unique strings
&apos;&apos;&apos; To get the list sorted, use SF_Array.Sort()
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myExtensionsList = platform.Extensions
Extensions = _PropertyGet(&quot;Extensions&quot;)
End Property &apos; ScriptForge.SF_Platform.Extensions (get)
REM -----------------------------------------------------------------------------
Property Get FilterNames() As Variant
&apos;&apos;&apos; Returns the list of available document import and export filter names as an unsorted array of unique strings
&apos;&apos;&apos; To get the list sorted, use SF_Array.Sort()
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myFilterNamesList = platform.FilterNames
FilterNames = _PropertyGet(&quot;FilterNames&quot;)
End Property &apos; ScriptForge.SF_Platform.FilterNames (get)
REM -----------------------------------------------------------------------------
Property Get Fonts() As Variant
&apos;&apos;&apos; Returns the list of available fonts as an unsorted array of unique strings
&apos;&apos;&apos; To get the list sorted, use SF_Array.Sort()
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myFontsList = platform.Fonts
Fonts = _PropertyGet(&quot;Fonts&quot;)
End Property &apos; ScriptForge.SF_Platform.Fonts (get)
REM -----------------------------------------------------------------------------
Property Get FormatLocale() As String
&apos;&apos;&apos; Returns the locale used for number and date formats, combining language-COUNTRY (la-CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.FormatLocale
FormatLocale = _PropertyGet(&quot;FormatLocale&quot;)
End Property &apos; ScriptForge.SF_Platform.FormatLocale (get)
REM -----------------------------------------------------------------------------
Property Get Locale() As String
&apos;&apos;&apos; Returns the locale of the operating system, combining language-COUNTRY (la-CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.Locale
Locale = _PropertyGet(&quot;Locale&quot;)
End Property &apos; ScriptForge.SF_Platform.Locale (get)
REM -----------------------------------------------------------------------------
Property Get Machine() As String
&apos;&apos;&apos; Returns the machine type like &apos;i386&apos; or &apos;x86_64&apos;
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.Machine
Machine = _PropertyGet(&quot;Machine&quot;)
End Property &apos; ScriptForge.SF_Platform.Machine (get)
REM -----------------------------------------------------------------------------
Property Get ObjectType As String
&apos;&apos;&apos; Only to enable object representation
ObjectType = &quot;SF_Platform&quot;
End Property &apos; ScriptForge.SF_Platform.ObjectType
REM -----------------------------------------------------------------------------
Property Get OfficeLocale() As String
&apos;&apos;&apos; Returns the locale of the user interface, combining language-COUNTRY (la-CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.OfficeLocale
OfficeLocale = _PropertyGet(&quot;OfficeLocale&quot;)
End Property &apos; ScriptForge.SF_Platform.OfficeLocale (get)
REM -----------------------------------------------------------------------------
Property Get OfficeVersion() As String
&apos;&apos;&apos; Returns the office software version in the form &apos;LibreOffice w.x.y.z (The Document Foundation)&apos;
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.OfficeVersion
OfficeVersion = _PropertyGet(&quot;OfficeVersion&quot;)
End Property &apos; ScriptForge.SF_Platform.OfficeVersion (get)
REM -----------------------------------------------------------------------------
Property Get OSName() As String
&apos;&apos;&apos; Returns the name of the operating system like &apos;Linux&apos; or &apos;Windows&apos;
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.OSName
OSName = _PropertyGet(&quot;OSName&quot;)
End Property &apos; ScriptForge.SF_Platform.OSName (get)
REM -----------------------------------------------------------------------------
Property Get OSPlatform() As String
&apos;&apos;&apos; Returns a single string identifying the underlying platform with as much useful and human-readable information as possible
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.OSPlatform &apos; Linux-4.15.0-117-generic-x86_64-with-Ubuntu-18.04-bionic
OSPlatform = _PropertyGet(&quot;OSPlatform&quot;)
End Property &apos; ScriptForge.SF_Platform.OSPlatform (get)
REM -----------------------------------------------------------------------------
Property Get OSRelease() As String
&apos;&apos;&apos; Returns the operating system&apos;s release
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.OSRelease &apos; 4.15.0-117-generic
OSRelease = _PropertyGet(&quot;OSRelease&quot;)
End Property &apos; ScriptForge.SF_Platform.OSRelease (get)
REM -----------------------------------------------------------------------------
Property Get OSVersion() As String
&apos;&apos;&apos; Returns the name of the operating system build or version
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.OSVersion &apos; #118-Ubuntu SMP Fri Sep 4 20:02:41 UTC 2020
OSVersion = _PropertyGet(&quot;OSVersion&quot;)
End Property &apos; ScriptForge.SF_Platform.OSVersion (get)
REM -----------------------------------------------------------------------------
Property Get Printers() As Variant
&apos;&apos;&apos; Returns the list of available printers type as a zero-based array
&apos;&apos;&apos; The default printer is put in the 1st position in the list (index = 0)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox join(platform.Printers, &quot;,&quot;)
Printers = _PropertyGet(&quot;Printers&quot;)
End Property &apos; ScriptForge.SF_Platform.Printers (get)
REM -----------------------------------------------------------------------------
Property Get Processor() As String
&apos;&apos;&apos; Returns the (real) processor name, e.g. &apos;amdk6&apos;. Might return the same value as Machine
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.Processor
Processor = _PropertyGet(&quot;Processor&quot;)
End Property &apos; ScriptForge.SF_Platform.Processor (get)
REM -----------------------------------------------------------------------------
Property Get PythonVersion() As String
&apos;&apos;&apos; Returns the Python version as string &apos;Python major.minor.patchlevel&apos;
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.PythonVersion &apos; Python 3.7.7
PythonVersion = _PropertyGet(&quot;PythonVersion&quot;)
End Property &apos; ScriptForge.SF_Platform.PythonVersion (get)
REM -----------------------------------------------------------------------------
Property Get ServiceName As String
&apos;&apos;&apos; Internal use
ServiceName = &quot;ScriptForge.Platform&quot;
End Property &apos; ScriptForge.SF_Platform.ServiceName
REM -----------------------------------------------------------------------------
Property Get SystemLocale() As String
&apos;&apos;&apos; Returns the locale of the operating system, combining language-COUNTRY (la-CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.SystemLocale
SystemLocale = _PropertyGet(&quot;SystemLocale&quot;)
End Property &apos; ScriptForge.SF_Platform.SystemLocale (get)
REM ===================================================================== METHODS
REM -----------------------------------------------------------------------------
Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
&apos;&apos;&apos; Return the actual value of the given property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyName: the name of the property as a string
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The actual value of the property
&apos;&apos;&apos; If the property does not exist, returns Null
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; ARGUMENTERROR The property does not exist
Const cstThisSub = &quot;Platform.GetProperty&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
GetProperty = Null
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
End If
Try:
GetProperty = _PropertyGet(PropertyName)
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Platform.GetProperty
REM -----------------------------------------------------------------------------
Public Function Methods() As Variant
&apos;&apos;&apos; Return the list of public methods of the Model service as an array
Methods = Array( _
)
End Function &apos; ScriptForge.SF_Platform.Methods
REM -----------------------------------------------------------------------------
Public Function Properties() As Variant
&apos;&apos;&apos; Return the list or properties of the Platform class as an array
Properties = Array( _
&quot;Architecture&quot; _
, &quot;ComputerName&quot; _
, &quot;CPUCount&quot; _
, &quot;CurrentUser&quot; _
, &quot;Extensions&quot; _
, &quot;FilterNames&quot; _
, &quot;Fonts&quot; _
, &quot;FormatLocale&quot; _
, &quot;Locale&quot; _
, &quot;Machine&quot; _
, &quot;OfficeLocale&quot; _
, &quot;OfficeVersion&quot; _
, &quot;OSName&quot; _
, &quot;OSPlatform&quot; _
, &quot;OSRelease&quot; _
, &quot;OSVersion&quot; _
, &quot;Printers&quot; _
, &quot;Processor&quot; _
, &quot;PythonVersion&quot; _
, &quot;SystemLocale&quot; _
)
End Function &apos; ScriptForge.SF_Platform.Properties
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
Public Function _GetPrinters() as Variant
&apos;&apos;&apos; Returns the list of available printers.
&apos;&apos;&apos; The default printer is put in the 1st position (index = 0)
Dim oPrinterServer As Object &apos; com.sun.star.awt.PrinterServer
Dim vPrinters As Variant &apos; Array of printer names
Dim sDefaultPrinter As String &apos; The default printer
Dim lDefault As Long &apos; Initial position of the default printer in the list
On Local Error GoTo Catch &apos; Prevent any error
vPrinters = Array()
Try:
&apos; Find printers
Set oPrinterServer = SF_Utils._GetUNOService(&quot;PrinterServer&quot;)
With oPrinterServer
vPrinters = .getPrinterNames()
sDefaultPrinter = .getDefaultPrinterName()
End With
&apos; Put the default printer on top of the list
If Len(sDefaultPrinter) &gt; 0 Then
lDefault = SF_Array.IndexOf(vPrinters, sDefaultPrinter, CaseSensitive := True)
If lDefault &gt; 0 Then &apos; Invert 2 printers
vPrinters(lDefault) = vPrinters(0)
vPrinters(0) = sDefaultPrinter
End If
End If
Finally:
_GetPrinters() = vPrinters()
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Platform._GetPrinters
REM -----------------------------------------------------------------------------
Public Function _GetProductName() as String
&apos;&apos;&apos; Returns Office product and version numbers found in configuration registry
&apos;&apos;&apos; Derived from the Tools library
Dim oProdNameAccess as Object &apos; configmgr.RootAccess
Dim sProdName as String
Dim sVersion as String
Dim sVendor As String
On Local Error GoTo Catch &apos; Prevent any error
_GetProductName = &quot;&quot;
Try:
Set oProdNameAccess = SF_Utils._GetRegistryKeyContent(&quot;org.openoffice.Setup/Product&quot;)
sProdName = oProdNameAccess.ooName
sVersion = oProdNameAccess.ooSetupVersionAboutBox
sVendor = oProdNameAccess.ooVendor
_GetProductName = sProdName &amp; &quot; &quot; &amp; sVersion &amp; &quot; (&quot; &amp; sVendor &amp; &quot;)&quot;
Finally:
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Platform._GetProductName
REM -----------------------------------------------------------------------------
Private Function _PropertyGet(Optional ByVal psProperty As String) As Variant
&apos;&apos;&apos; Return the value of the named property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psProperty: the name of the property
Dim sOSName As String &apos; Operating system
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim oPrinterServer As Object &apos; com.sun.star.awt.PrinterServer
Dim oToolkit As Object &apos; com.sun.star.awt.Toolkit
Dim oDevice As Object &apos; com.sun.star.awt.XDevice
Dim oFilterFactory As Object &apos; com.sun.star.document.FilterFactory
Dim oFontDescriptors As Variant &apos; Array of com.sun.star.awt.FontDescriptor
Dim sFonts As String &apos; Comma-separated list of fonts
Dim sFont As String &apos; A single font name
Dim vExtensionsList As Variant &apos; Array of extension descriptors
Dim sExtensions As String &apos; Comma separated list of extensions
Dim sExtension As String &apos; A single extension name
Dim i As Long
Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_Platform&quot;
Dim cstThisSub As String
Const cstSubArgs = &quot;&quot;
cstThisSub = &quot;Platform.get&quot; &amp; psProperty
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Select Case psProperty
Case &quot;Architecture&quot;, &quot;ComputerName&quot;, &quot;CPUCount&quot;, &quot;CurrentUser&quot;, &quot;Machine&quot; _
, &quot;OSPlatform&quot;, &quot;OSRelease&quot;, &quot;OSVersion&quot;, &quot;Processor&quot;, &quot;PythonVersion&quot;
With ScriptForge.SF_Session
_PropertyGet = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper, psProperty)
End With
Case &quot;Extensions&quot;
Set vExtensionsList = SF_Utils._GetUnoService(&quot;PackageInformationProvider&quot;).ExtensionList
sExtensions = &quot;&quot;
For i = 0 To UBound(vExtensionsList)
sExtensions = sExtensions &amp; &quot;,&quot; &amp; vExtensionsList(i)(0)
Next i
If Len(sExtensions) &gt; 0 Then _PropertyGet = Split(Mid(sExtensions, 2), &quot;,&quot;) Else _PropertyGet = Array()
Case &quot;FilterNames&quot;
Set oFilterFactory = SF_Utils._GetUNOService(&quot;FilterFactory&quot;)
_PropertyGet = oFilterFactory.getElementNames()
Case &quot;Fonts&quot;
Set oToolkit = SF_Utils._GetUnoService(&quot;Toolkit&quot;)
Set oDevice = oToolkit.createScreenCompatibleDevice(0, 0)
oFontDescriptors = oDevice.FontDescriptors()
sFonts = &quot;,&quot;
&apos; Select only not yet registered fonts
For i = 0 To UBound(oFontDescriptors)
sFont = oFontDescriptors(i).Name
If InStr(1, sFonts, &quot;,&quot; &amp; sFont &amp; &quot;,&quot;, 0) = 0 Then sFonts = sFonts &amp; sFont &amp; &quot;,&quot; &apos; Case-sensitive comparison
Next i
&apos; Remove leading and trailing commas
If Len(sFonts) &gt; 1 Then _PropertyGet = Split(Mid(sFonts, 2, Len(sFonts) - 2), &quot;,&quot;) Else _PropertyGet = Array()
Case &quot;FormatLocale&quot;
Set oLocale = SF_Utils._GetUNOService(&quot;FormatLocale&quot;)
_PropertyGet = oLocale.Language &amp; &quot;-&quot; &amp; oLocale.Country
Case &quot;OfficeLocale&quot;
Set oLocale = SF_Utils._GetUNOService(&quot;OfficeLocale&quot;)
_PropertyGet = oLocale.Language &amp; &quot;-&quot; &amp; oLocale.Country
Case &quot;OfficeVersion&quot;
_PropertyGet = _GetProductName()
Case &quot;OSName&quot;
&apos; Calc INFO function preferred to Python script to avoid ScriptForge initialization risks when Python is not installed
sOSName = _SF_.OSName
If sOSName = &quot;&quot; Then
sOSName = SF_Session.ExecuteCalcFunction(&quot;INFO&quot;, &quot;system&quot;)
Select Case sOSName
Case &quot;WNT&quot; : sOSName = &quot;Windows&quot;
Case &quot;MACOSX&quot; : sOSName = &quot;macOS&quot;
Case &quot;LINUX&quot; : sOSName = &quot;Linux&quot;
Case &quot;SOLARIS&quot; : sOSName = &quot;Solaris&quot;
Case Else : sOSName = SF_String.Capitalize(sOSName)
End Select
EndIf
_PropertyGet = sOSName
Case &quot;Printers&quot;
_PropertyGet = _GetPrinters()
Case &quot;SystemLocale&quot;, &quot;Locale&quot;
Set oLocale = SF_Utils._GetUNOService(&quot;SystemLocale&quot;)
_PropertyGet = oLocale.Language &amp; &quot;-&quot; &amp; oLocale.Country
Case Else
_PropertyGet = Null
End Select
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Platform._PropertyGet
REM ============================================ END OF SCRIPTFORGE.SF_PLATFORM
</script:module>

View File

@@ -0,0 +1,967 @@
<?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_PythonHelper" 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_PythonHelper (aka Basic)
&apos;&apos;&apos; ===============
&apos;&apos;&apos; Singleton class implementing the &quot;ScriptForge.Basic&quot; service
&apos;&apos;&apos; Implemented as a usual Basic module
&apos;&apos;&apos;
&apos;&apos;&apos; The &quot;Basic&quot; service must be called ONLY from a PYTHON script
&apos;&apos;&apos; Service invocations: Next Python code lines are equivalent:
&apos;&apos;&apos; bas = CreateScriptService(&apos;ScriptForge.Basic&apos;)
&apos;&apos;&apos; bas = CreateScriptService(&apos;Basic&apos;)
&apos;&apos;&apos;
&apos;&apos;&apos; This service proposes a collection of methods to be executed in a Python context
&apos;&apos;&apos; to simulate the exact behaviour of the identical Basic builtin method.
&apos;&apos;&apos; Typical example:
&apos;&apos;&apos; bas.MsgBox(&apos;This has to be displayed in a message box&apos;)
&apos;&apos;&apos;
&apos;&apos;&apos; The service includes also an agnostic &quot;Python Dispatcher&quot; function.
&apos;&apos;&apos; It dispatches Python script requests to execute Basic services to the
&apos;&apos;&apos; appropriate properties and methods via dynamic call techniques
&apos;&apos;&apos;
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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
REM ============================================================ MODULE CONSTANTS
REM ===================================================== CONSTRUCTOR/DESTRUCTOR
REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
Set Dispose = Nothing
End Function &apos; ScriptForge.SF_PythonHelper Explicit destructor
REM ================================================================== PROPERTIES
REM -----------------------------------------------------------------------------
Property Get ObjectType As String
&apos;&apos;&apos; Only to enable object representation
ObjectType = &quot;SF_PythonHelper&quot;
End Property &apos; ScriptForge.SF_PythonHelper.ObjectType
REM -----------------------------------------------------------------------------
Property Get ServiceName As String
&apos;&apos;&apos; Internal use
ServiceName = &quot;ScriptForge.Basic&quot;
End Property &apos; ScriptForge.SF_PythonHelper.ServiceName
REM ============================================================== PUBLIC METHODS
REM -----------------------------------------------------------------------------
Public Function PyCDate(ByVal DateArg As Variant) As Variant
&apos;&apos;&apos; Convenient function to replicate CDate() in Python scripts
&apos;&apos;&apos; Args:
&apos;&apos;&apos; DateArg: a date as a string or as a double
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The converted date as a UNO DateTime structure
&apos;&apos;&apos; If the input argument could not be recognized as a date, return the argument unchanged
&apos;&apos;&apos; Example: (Python code)
&apos;&apos;&apos; a = bas.CDate(&apos;2021-02-18&apos;)
Dim vDate As Variant &apos; Return value
Const cstThisSub = &quot;Basic.CDate&quot;
Const cstSubArgs = &quot;datearg&quot;
On Local Error GoTo Catch
vDate = Null
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
vDate = CDate(DateArg)
Finally:
If VarType(vDate) = V_DATE Then PyCDate = CDateToUnoDateTime(vDate) Else PyCDate = DateArg
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
On Local Error GoTo 0
GoTo Finally
End Function &apos; ScriptForge.SF_PythonHelper.PyCDate
REM -----------------------------------------------------------------------------
Public Function PyConvertFromUrl(ByVal FileName As Variant) As String
&apos;&apos;&apos; Convenient function to replicate ConvertFromUrl() in Python scripts
&apos;&apos;&apos; Args:
&apos;&apos;&apos; FileName: a string representing a file in URL format
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The same file name in native operating system notation
&apos;&apos;&apos; Example: (Python code)
&apos;&apos;&apos; a = bas.ConvertFromUrl(&apos;file:////boot.sys&apos;)
Dim sFileName As String &apos; Return value
Const cstThisSub = &quot;Basic.ConvertFromUrl&quot;
Const cstSubArgs = &quot;filename&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
sFileName = &quot;&quot;
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
sFileName = ConvertFromUrl(FileName)
Finally:
PyConvertFromUrl = sFileName
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_PythonHelper.PyConvertFromUrl
REM -----------------------------------------------------------------------------
Public Function PyConvertToUrl(ByVal FileName As Variant) As String
&apos;&apos;&apos; Convenient function to replicate ConvertToUrl() in Python scripts
&apos;&apos;&apos; Args:
&apos;&apos;&apos; FileName: a string representing a file in native operating system notation
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The same file name in URL format
&apos;&apos;&apos; Example: (Python code)
&apos;&apos;&apos; a = bas.ConvertToUrl(&apos;C:\boot.sys&apos;)
Dim sFileName As String &apos; Return value
Const cstThisSub = &quot;Basic.ConvertToUrl&quot;
Const cstSubArgs = &quot;filename&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
sFileName = &quot;&quot;
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
sFileName = ConvertToUrl(FileName)
Finally:
PyConvertToUrl = sFileName
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_PythonHelper.PyConvertToUrl
REM -----------------------------------------------------------------------------
Public Function PyCreateUnoService(ByVal UnoService As Variant) As Variant
&apos;&apos;&apos; Convenient function to replicate CreateUnoService() in Python scripts
&apos;&apos;&apos; Args:
&apos;&apos;&apos; UnoService: a string representing the service to create
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A UNO object
&apos;&apos;&apos; Example: (Python code)
&apos;&apos;&apos; a = bas.CreateUnoService(&apos;com.sun.star.i18n.CharacterClassification&apos;)
Dim vUno As Variant &apos; Return value
Const cstThisSub = &quot;Basic.CreateUnoService&quot;
Const cstSubArgs = &quot;unoservice&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Set vUno = Nothing
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
Set vUno = CreateUnoService(UnoService)
Finally:
Set PyCreateUnoService = vUno
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_PythonHelper.PyCreateUnoService
REM -----------------------------------------------------------------------------
Public Function PyDateAdd(ByVal Add As Variant _
, ByVal Count As Variant _
, ByVal DateArg As Variant _
) As Variant
&apos;&apos;&apos; Convenient function to replicate DateAdd() in Python scripts
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Add: The unit to add
&apos;&apos;&apos; Count: how many times to add (might be negative)
&apos;&apos;&apos; DateArg: a date as a com.sun.star.util.DateTime UNO structure
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The new date as a string in iso format
&apos;&apos;&apos; Example: (Python code)
&apos;&apos;&apos; a = bas.DateAdd(&apos;d&apos;, 1, bas.Now()) &apos; Tomorrow
Dim vNewDate As Variant &apos; Return value
Dim vDate As Date &apos; Alias of DateArg
Const cstThisSub = &quot;Basic.DateAdd&quot;
Const cstSubArgs = &quot;add, count, datearg&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
vNewDate = &quot;&quot;
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If VarType(DateArg) = V_OBJECT Then
vDate = CDateFromUnoDateTime(DateArg)
Else
vDate = SF_Utils._CStrToDate(DateArg)
End If
vNewDate = DateAdd(Add, Count, vDate)
Finally:
If VarType(vNewDate) = V_DATE Then PyDateAdd = CDateToUnoDateTime(vNewDate) Else PyDateAdd = vNewDate
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_PythonHelper.PyDateAdd
REM -----------------------------------------------------------------------------
Public Function PyDateDiff(ByVal Add As Variant _
, ByVal Date1 As Variant _
, ByVal Date2 As Variant _
, ByVal WeekStart As Variant _
, ByVal YearStart As Variant _
) As Long
&apos;&apos;&apos; Convenient function to replicate DateDiff() in Python scripts
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Add: The unit of the date interval
&apos;&apos;&apos; Date1, Date2: the two dates to be compared
&apos;&apos;&apos; WeekStart: the starting day of a week
&apos;&apos;&apos; YearStart: the starting week of a year
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The number of intervals expressed in Adds
&apos;&apos;&apos; Example: (Python code)
&apos;&apos;&apos; a = bas.DateDiff(&apos;d&apos;, bas.DateAdd(&apos;d&apos;, 1, bas.Now()), bas.Now()) &apos; -1 day
Dim lDiff As Long &apos; Return value
Dim vDate1 As Date &apos; Alias of Date1
Dim vDate2 As Date &apos; Alias of Date2
Const cstThisSub = &quot;Basic.DateDiff&quot;
Const cstSubArgs = &quot;add, date1, date2, [weekstart=1], [yearstart=1]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
lDiff = 0
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If VarType(Date1) = V_OBJECT Then
vDate1 = CDateFromUnoDateTime(Date1)
Else
vDate1 = SF_Utils._CStrToDate(Date1)
End If
If VarType(Date2) = V_OBJECT Then
vDate2 = CDateFromUnoDateTime(Date2)
Else
vDate2 = SF_Utils._CStrToDate(Date2)
End If
lDiff = DateDiff(Add, vDate1, vDate2, WeekStart, YearStart)
Finally:
PyDateDiff = lDiff
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_PythonHelper.PyDateDiff
REM -----------------------------------------------------------------------------
Public Function PyDatePart(ByVal Add As Variant _
, ByVal DateArg As Variant _
, ByVal WeekStart As Variant _
, ByVal YearStart As Variant _
) As Long
&apos;&apos;&apos; Convenient function to replicate DatePart() in Python scripts
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Add: The unit of the date interval
&apos;&apos;&apos; DateArg: The date from which to extract a part
&apos;&apos;&apos; WeekStart: the starting day of a week
&apos;&apos;&apos; YearStart: the starting week of a year
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The specified part of the date
&apos;&apos;&apos; Example: (Python code)
&apos;&apos;&apos; a = bas.DatePart(&apos;y&apos;, bas.Now()) &apos; day of year
Dim lPart As Long &apos; Return value
Dim vDate As Date &apos; Alias of DateArg
Const cstThisSub = &quot;Basic.DatePart&quot;
Const cstSubArgs = &quot;add, datearg, [weekstart=1], [yearstart=1]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
lPart = 0
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If VarType(DateArg) = V_OBJECT Then
vDate = CDateFromUnoDateTime(DateArg)
Else
vDate = SF_Utils._CStrToDate(DateArg)
End If
lPart = DatePart(Add, vDate, WeekStart, YearStart)
Finally:
PyDatePart = lPart
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_PythonHelper.PyDatePart
REM -----------------------------------------------------------------------------
Public Function PyDateValue(ByVal DateArg As Variant) As Variant
&apos;&apos;&apos; Convenient function to replicate DateValue() in Python scripts
&apos;&apos;&apos; Args:
&apos;&apos;&apos; DateArg: a date as a string
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The converted date as a UNO DateTime structure
&apos;&apos;&apos; Example: (Python code)
&apos;&apos;&apos; a = bas.DateValue(&apos;2021-02-18&apos;)
Dim vDate As Variant &apos; Return value
Const cstThisSub = &quot;Basic.DateValue&quot;
Const cstSubArgs = &quot;datearg&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
vDate = &quot;&quot;
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
vDate = DateValue(DateArg)
Finally:
If VarType(vDate) = V_DATE Then PyDateValue = CDateToUnoDateTime(vDate) Else PyDateValue = vDate
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_PythonHelper.PyDateValue
REM -----------------------------------------------------------------------------
Public Function PyFormat(ByVal Value As Variant _
, ByVal Pattern As Variant _
) As String
&apos;&apos;&apos; Convenient function to replicate Format() in Python scripts
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Value: a date or a number
&apos;&apos;&apos; Pattern: the format to apply
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The formatted value
&apos;&apos;&apos; Example: (Python code)
&apos;&apos;&apos; MsgBox bas.Format(6328.2, &apos;##,##0.00&apos;)
Dim sFormat As String &apos; Return value
Dim vValue As Variant &apos; Alias of Value
Const cstThisSub = &quot;Basic.Format&quot;
Const cstSubArgs = &quot;value, pattern&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
sFormat = &quot;&quot;
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If VarType(Value) = V_OBJECT Then vValue = CDateFromUnoDateTime(Value) ELse vValue = Value
If IsEmpty(Pattern) Or Len(Pattern) = 0 Then sFormat = Str(vValue) Else sFormat = Format(vValue, Pattern)
Finally:
PyFormat = sFormat
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_PythonHelper.PyFormat
REM -----------------------------------------------------------------------------
Public Function PyGetGuiType() As Integer
&apos;&apos;&apos; Convenient function to replicate GetGuiType() in Python scripts
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The GetGuiType value
&apos;&apos;&apos; Example: (Python code)
&apos;&apos;&apos; MsgBox bas.GetGuiType()
Const cstThisSub = &quot;Basic.GetGuiType&quot;
Const cstSubArgs = &quot;&quot;
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
PyGetGuiType = GetGuiType()
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_PythonHelper.PyGetGuiType
REM -----------------------------------------------------------------------------
Public Function PyGetSystemTicks() As Long
&apos;&apos;&apos; Convenient function to replicate GetSystemTicks() in Python scripts
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The GetSystemTicks value
&apos;&apos;&apos; Example: (Python code)
&apos;&apos;&apos; MsgBox bas.GetSystemTicks()
Const cstThisSub = &quot;Basic.GetSystemTicks&quot;
Const cstSubArgs = &quot;&quot;
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
PyGetSystemTicks = GetSystemTicks()
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_PythonHelper.PyGetSystemTicks
REM -----------------------------------------------------------------------------
Public Function PyGlobalScope(ByVal Library As Variant) As Object
&apos;&apos;&apos; Convenient function to replicate GlobalScope() in Python scripts
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Library: &quot;Basic&quot; or &quot;Dialog&quot;
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The GlobalScope value
&apos;&apos;&apos; Example: (Python code)
&apos;&apos;&apos; MsgBox bas.GlobalScope.BasicLibraries()
Const cstThisSub = &quot;Basic.GlobalScope.BasicLibraries&quot; &apos; or DialogLibraries
Const cstSubArgs = &quot;&quot;
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
Select Case Library
Case &quot;Basic&quot;
PyGlobalScope = GlobalScope.BasicLibraries()
Case &quot;Dialog&quot;
PyGlobalScope = GlobalScope.DialogLibraries()
Case Else
End Select
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_PythonHelper.PyGlobalScope
REM -----------------------------------------------------------------------------
Public Function PyInputBox(ByVal Msg As Variant _
, ByVal Title As Variant _
, ByVal Default As Variant _
, Optional ByVal XPosTwips As Variant _
, Optional ByVal YPosTwips As Variant _
) As String
&apos;&apos;&apos; Convenient function to replicate InputBox() in Python scripts
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Msg: String expression displayed as the message in the dialog box
&apos;&apos;&apos; Title: String expression displayed in the title bar of the dialog box
&apos;&apos;&apos; Default: String expression displayed in the text box as default if no other input is given
&apos;&apos;&apos; XPosTwips: Integer expression that specifies the horizontal position of the dialog
&apos;&apos;&apos; YPosTwips: Integer expression that specifies the vertical position of the dialog
&apos;&apos;&apos; If XPosTwips and YPosTwips are omitted, the dialog is centered on the screen
&apos;&apos;&apos; The position is specified in twips.
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The entered value or &quot;&quot; if the user pressed the Cancel button
&apos;&apos;&apos; Example: (Python code)
&apos;&apos;&apos; a = bas.InputBox (&apos;Please enter a phrase:&apos;, &apos;Dear User&apos;)
Dim sInput As String &apos; Return value
Const cstThisSub = &quot;Basic.InputBox&quot;
Const cstSubArgs = &quot;msg, [title=&apos;&apos;], [default=&apos;&apos;], [xpostwips], [ypostwips]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
sInput = &quot;&quot;
Check:
If IsMissing(YPosTwips) Then YPosTwips = 1
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If IsMissing(XPosTwips) Then
sInput = InputBox(Msg, Title, Default)
Else
sInput = InputBox(Msg, Title, Default, XPosTwips, YPosTwips)
End If
Finally:
PyInputBox = sInput
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_PythonHelper.PyInputBox
REM -----------------------------------------------------------------------------
Public Function PyMsgBox(ByVal Text As Variant _
, ByVal DialogType As Variant _
, ByVal DialogTitle As Variant _
) As Integer
&apos;&apos;&apos; Convenient function to replicate MsgBox() in Python scripts
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Text: String expression displayed as a message in the dialog box
&apos;&apos;&apos; DialogType: Any integer expression that defines the number and type of buttons or icons displayed
&apos;&apos;&apos; DialogTitle: String expression displayed in the title bar of the dialog
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The pressed button
&apos;&apos;&apos; Example: (Python code)
&apos;&apos;&apos; a = bas.MsgBox (&apos;Please press a button:&apos;, bas.MB_EXCLAMATION, &apos;Dear User&apos;)
Dim iMsg As Integer &apos; Return value
Const cstThisSub = &quot;Basic.MsgBox&quot;
Const cstSubArgs = &quot;text, [dialogtype=0], [dialogtitle]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
iMsg = -1
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
iMsg = MsgBox(Text, DialogType, DialogTitle)
Finally:
PyMsgBox = iMsg
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_PythonHelper.PyMsgBox
REM ============================================================= PRIVATE METHODS
REM -----------------------------------------------------------------------------
Public Function _PythonDispatcher(ByRef BasicObject As Variant _
, ByVal CallType As Variant _
, ByVal Script As Variant _
, ParamArray Args() As Variant _
) As Variant
&apos;&apos;&apos; Called from Python only
&apos;&apos;&apos; The method calls the method Script associated with the BasicObject class or module
&apos;&apos;&apos; with the given arguments
&apos;&apos;&apos; The invocation of the method can be a Property Get, Property Let or a usual call
&apos;&apos;&apos; NB: arguments and return values must not be 2D arrays
&apos;&apos;&apos; The implementation intends to be as AGNOSTIC as possible in terms of objects nature and methods called
&apos;&apos;&apos; Args:
&apos;&apos;&apos; BasicObject: a module or a class instance - May also be the reserved string: &quot;SF_Services&quot;
&apos;&apos;&apos; CallType: one of the constants applicable to a CallByName statement + optional protocol flags
&apos;&apos;&apos; Script: the name of the method or property
&apos;&apos;&apos; Args: the arguments to pass to the method. Input arguments can contain symbolic constants for Null, Missing, etc.
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A 1D array:
&apos;&apos;&apos; [0] The returned value - scalar, object or 1D array
&apos;&apos;&apos; [1] The VarType() of the returned value
&apos;&apos;&apos; Null, Empty and Nothing have different vartypes but return all None to Python
&apos;&apos;&apos; Additionally, when array:
&apos;&apos;&apos; [2] Number of dimensions in Basic
&apos;&apos;&apos; Additionally, when Basic object:
&apos;&apos;&apos; [2] Module (1), Class instance (2) or UNO (3)
&apos;&apos;&apos; [3] The object&apos;s ObjectType
&apos;&apos;&apos; [4] The object&apos;s service name
&apos;&apos;&apos; [5] The object&apos;s name
&apos;&apos;&apos; When an error occurs Python receives None as a scalar. This determines the occurrence of a failure
Dim vReturn As Variant &apos; The value returned by the invoked property or method
Dim vReturnArray As Variant &apos; Return value
Dim vBasicObject As Variant &apos; Alias of BasicObject to avoid &quot;Object reference not set&quot; error
Dim iNbArgs As Integer &apos; Number of valid input arguments
Dim vArg As Variant &apos; Alias for a single argument
Dim vArgs() As Variant &apos; Alias for Args()
Dim sScript As String &apos; Argument of ExecuteBasicScript()
Dim vParams As Variant &apos; Array of arguments to pass to a ParamArray
Dim sObjectType As String &apos; Alias of object.ObjectType
Dim sServiceName As String &apos; Alias of BasicObject.ServiceName
Dim bBasicClass As Boolean &apos; True when BasicObject is a class
Dim sLibrary As String &apos; Library where the object belongs to
Dim bUno As Boolean &apos; Return value is a UNO object
Dim oObjDesc As Object &apos; _ObjectDescriptor type
Dim iDims As Integer &apos; # of dims of vReturn
Dim sess As Object : Set sess = ScriptForge.SF_Session
Dim i As Long, j As Long
&apos; Conventional special input or output values
Const cstNoArgs = &quot;+++NOARGS+++&quot;, cstSymEmpty = &quot;+++EMPTY+++&quot;, cstSymNull = &quot;+++NULL+++&quot;, cstSymMissing = &quot;+++MISSING+++&quot;
&apos; https://support.office.com/en-us/article/CallByName-fonction-49ce9475-c315-4f13-8d35-e98cfe98729a
&apos; Determines the CallType
Const vbGet = 2, vbLet = 4, vbMethod = 1, vbSet = 8
&apos; Protocol flags
Const cstDateArg = 64 &apos; May contain a date argument
Const cstDateRet = 128 &apos; Return value can be a date
Const cstUno = 256 &apos; Return value can be a UNO object
Const cstArgArray = 512 &apos; Any argument can be a 2D array
Const cstRetArray = 1024 &apos; Return value can be an array
Const cstObject = 2048 &apos; 1st argument is a Basic object when numeric
Const cstHardCode = 4096 &apos; Method must not be executed with CallByName()
&apos; Object nature in returned array
Const objMODULE = 1, objCLASS = 2, objUNO = 3
Check:
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
_PythonDispatcher = Null
&apos; Ignore Null basic objects (Null = Null or Nothing)
If IsNull(BasicObject) Or IsEmpty(BasicObject) Then GoTo Catch
&apos; Reinterpret arguments one by one into vArgs, convert UNO date/times and conventional NoArgs/Empty/Null/Missing values
iNbArgs = -1
vArgs = Array()
If UBound(Args) &gt;= 0 Then
For i = 0 To UBound(Args)
vArg = Args(i)
&apos; Are there arguments ?
If i = 0 And VarType(vArg) = V_STRING Then
If vArg = cstNoArgs Then Exit For
End If
&apos; Is 1st argument a reference to a Basic object ?
If i = 0 And (( CallType And cstObject ) = cstObject) And SF_Utils._VarTypeExt(vArg) = V_NUMERIC Then
If vArg &lt; 0 Or Not IsArray(_SF_.PythonStorage) Then GoTo Catch
If vArg &gt; UBound(_SF_.PythonStorage) Then GoTo Catch
vArg = _SF_.PythonStorage(vArg)
&apos; Is argument a symbolic constant for Null, Empty, ... , or a date?
ElseIf VarType(vArg) = V_STRING Then
If Len(vArg) = 0 Then
ElseIf vArg = cstSymEmpty Then
vArg = Empty
ElseIf vArg = cstSymNull Then
vArg = Null
ElseIf vArg = cstSymMissing Then
Exit For &apos; Next arguments must be missing also
End If
ElseIf VarType(vArg) = V_OBJECT Then
If ( CallType And cstDateArg ) = cstDateArg Then vArg = CDateFromUnoDateTime(vArg)
End If
iNbArgs = iNbArgs + 1
ReDim Preserve vArgs(iNbArgs)
vArgs(iNbArgs) = vArg
Next i
End If
Try:
&apos; Dispatching strategy: based on next constraints
&apos; (1) Bug https://bugs.documentfoundation.org/show_bug.cgi?id=138155
&apos; The CallByName function fails when returning an array
&apos; (2) Python has tuples and tuple of tuples, not 2D arrays
&apos; (3) Passing 2D arrays through a script provider always transform it into a sequence of sequences
&apos; (4) The CallByName function takes exclusive control on the targeted object up to its exit
&apos; 1. Methods in usual modules are called by ExecuteBasicScript() except if they use a ParamArray
&apos; 2. Properties in any service are got and set with obj.GetProperty/SetProperty(...)
&apos; 3. Methods in class modules are invoked with CallByName
&apos; 4. Methods in class modules using a 2D array or returning arrays, or methods using ParamArray,
&apos;&apos;&apos; are hardcoded as exceptions or are not implemented
&apos; 5. Due to constraint (4), a predefined list of method calls must be hardcoded to avoid blocking use of CallByName
&apos; The concerned methods are flagged with cstHardCode
With _SF_
&apos; Initialize Python persistent storage at 1st call
If IsEmpty(.PythonStorage) Then ._InitPythonStorage()
&apos; Reset any error
._Stackreset()
&apos; Set Python trigger to manage signatures in error messages
.TriggeredByPython = True
End With
Select case VarType(BasicObject)
Case V_STRING
&apos; Special entry for CreateScriptService()
vBasicObject = BasicObject
If vBasicObject = &quot;SF_Services&quot; Then
If UBound(vArgs) = 0 Then vParams = Array() Else vParams = SF_Array.Slice(vArgs, 1)
Select Case UBound(vParams)
Case -1 : vReturn = SF_Services.CreateScriptService(vArgs(0))
Case 0 : vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0))
Case 1 : vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0), vParams(1))
Case 2 : vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0), vParams(1), vParams(2))
Case 3 : vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0), vParams(1), vParams(2), vParams(3))
Case 4 : vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0), vParams(1), vParams(2), vParams(3), vParams(4))
End Select
End If
If VarType(vReturn) = V_OBJECT And Not IsNull(vReturn) Then
vBasicObject = vReturn
sObjectType = vBasicObject.ObjectType
bBasicClass = ( Left(sObjectType, 3) &lt;&gt; &quot;SF_&quot; )
End If
&apos; Implement dispatching strategy
Case V_INTEGER
If BasicObject &lt; 0 Or Not IsArray(_SF_.PythonStorage) Then GoTo Catch
If BasicObject &gt; UBound(_SF_.PythonStorage) Then GoTo Catch
vBasicObject = _SF_.PythonStorage(BasicObject)
sObjectType = vBasicObject.ObjectType
sServiceName = vBasicObject.ServiceName
&apos; Basic modules have type = &quot;SF_*&quot;
bBasicClass = ( Left(sObjectType, 3) &lt;&gt; &quot;SF_&quot; )
sLibrary = Split(sServiceName, &quot;.&quot;)(0)
&apos; Methods in standard modules returning/passing a date are hardcoded as exceptions
If Not bBasicClass And ((CallType And vbMethod) = vbMethod) _
And (((CallType And cstDateRet) = cstDateRet) Or ((CallType And cstDateArg) = cstDateArg)) Then
Select Case sServiceName
Case &quot;ScriptForge.FileSystem&quot;
If Script = &quot;GetFileModified&quot; Then vReturn = SF_FileSystem.GetFileModified(vArgs(0))
Case &quot;ScriptForge.Region&quot;
Select Case Script
Case &quot;DSTOffset&quot; : vReturn = SF_Region.DSTOffset(vArgs(0), vArgs(1), vArgs(2))
Case &quot;LocalDateTime&quot; : vReturn = SF_Region.LocalDateTime(vArgs(0), vArgs(1), vArgs(2))
Case &quot;UTCDateTime&quot; : vReturn = SF_Region.UTCDateTime(vArgs(0), vArgs(1), vArgs(2))
Case &quot;UTCNow&quot; : vReturn = SF_Region.UTCNow(vArgs(0), vArgs(1))
Case Else
End Select
End Select
&apos; Methods in usual modules using a 2D array or returning arrays are hardcoded as exceptions
ElseIf Not bBasicClass And _
(((CallType And vbMethod) + (CallType And cstArgArray)) = vbMethod + cstArgArray Or _
((CallType And vbMethod) + (CallType And cstRetArray)) = vbMethod + cstRetArray) Then
&apos; Not service related
If Script = &quot;Methods&quot; Then
vReturn = vBasicObject.Methods()
ElseIf Script = &quot;Properties&quot; Then
vReturn = vBasicObject.Properties()
Else
Select Case sServiceName
Case &quot;ScriptForge.Array&quot;
If Script = &quot;ImportFromCSVFile&quot; Then vReturn = SF_Array.ImportFromCSVFile(vArgs(0), vArgs(1), vArgs(2), True)
End Select
End If
&apos; Methods in usual modules are called by ExecuteBasicScript() except if they use a ParamArray
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))
Case 1 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1))
Case 2 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2))
Case 3 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3))
Case 4 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4))
Case 5 : vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5))
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 &apos; In some cases (Calc ...) GetProperty may have an argument
If UBound(vArgs) &lt; 0 Then vReturn = vBasicObject.GetProperty(Script) Else vReturn = vBasicObject.GetProperty(Script, vArgs(0))
ElseIf (CallType And vbLet) = vbLet Then
vReturn = vBasicObject.SetProperty(Script, vArgs(0))
&apos; Methods in class modules using a 2D array or returning arrays are hardcoded as exceptions. Bug #138155
ElseIf ((CallType And vbMethod) + (CallType And cstArgArray)) = vbMethod + cstArgArray Or _
((CallType And vbMethod) + (CallType And cstRetArray)) = vbMethod + cstRetArray Then
If Script = &quot;Methods&quot; Then
vReturn = vBasicObject.Methods()
ElseIf Script = &quot;Properties&quot; Then
vReturn = vBasicObject.Properties()
Else
Select Case sServiceName
Case &quot;SFDatabases.Database&quot;
If Script = &quot;GetRows&quot; Then vReturn = vBasicObject.GetRows(vArgs(0), vArgs(1), vArgs(2), vArgs(3))
Case &quot;SFDialogs.Dialog&quot;
If Script = &quot;Controls&quot; Then vReturn = vBasicObject.Controls(vArgs(0))
Case &quot;SFDialogs.DialogControl&quot;
If Script = &quot;SetTableData&quot; Then vReturn = vBasicObject.SetTableData(vArgs(0), vArgs(1), vArgs(2))
Case &quot;SFDocuments.Document&quot;
If Script = &quot;Forms&quot; Then vReturn = vBasicObject.Forms(vArgs(0))
Case &quot;SFDocuments.Base&quot;
Select Case Script
Case &quot;FormDocuments&quot; : vReturn = vBasicObject.FormDocuments()
Case &quot;Forms&quot; : vReturn = vBasicObject.Forms(vArgs(0), vArgs(1))
End Select
Case &quot;SFDocuments.Calc&quot;
Select Case Script
Case &quot;Charts&quot; : vReturn = vBasicObject.Charts(vArgs(0), vArgs(1))
Case &quot;Forms&quot; : vReturn = vBasicObject.Forms(vArgs(0), vArgs(1))
Case &quot;GetFormula&quot; : vReturn = vBasicObject.GetFormula(vArgs(0))
Case &quot;GetValue&quot; : vReturn = vBasicObject.GetValue(vArgs(0))
Case &quot;SetArray&quot; : vReturn = vBasicObject.SetArray(vArgs(0), vArgs(1))
Case &quot;SetFormula&quot; : vReturn = vBasicObject.SetFormula(vArgs(0), vArgs(1))
Case &quot;SetValue&quot; : vReturn = vBasicObject.SetValue(vArgs(0), vArgs(1))
End Select
Case &quot;SFDocuments.Form&quot;
Select Case Script
Case &quot;Controls&quot; : vReturn = vBasicObject.Controls(vArgs(0))
Case &quot;Subforms&quot; : vReturn = vBasicObject.Subforms(vArgs(0))
End Select
Case &quot;SFDocuments.FormControl&quot;
If Script = &quot;Controls&quot; Then vReturn = vBasicObject.Controls(vArgs(0))
End Select
End If
&apos; Methods in class modules may better not be executed with CallByName()
ElseIf bBasicClass And ((CallType And vbMethod) + (CallType And cstHardCode)) = vbMethod + cstHardCode Then
Select Case sServiceName
Case &quot;SFDialogs.Dialog&quot;
Select Case Script
Case &quot;Activate&quot; : vReturn = vBasicObject.Activate()
Case &quot;Center&quot;
If UBound(vArgs) &lt; 0 Then vReturn = vBasicObject.Center() Else vReturn = vBasicObject.Center(vArgs(0))
Case &quot;EndExecute&quot; : vReturn = vBasicObject.EndExecute(vArgs(0))
Case &quot;Execute&quot; : vReturn = vBasicObject.Execute(vArgs(0))
Case &quot;Resize&quot; : vReturn = vBasicObject.Resize(vArgs(0), vArgs(1), vArgs(2), vArgs(3))
End Select
End Select
&apos; Methods in class modules are invoked with CallByName
ElseIf bBasicClass And ((CallType And vbMethod) = vbMethod) Then
Select Case UBound(vArgs)
&apos; Dirty alternatives to process usual and ParamArray cases
&apos; But, up to ... how many ?
&apos; - The OFFSETADDRESSERROR has 12 arguments
&apos; - The &quot;.uno:DataSort&quot; command may have 14 property name-value pairs
Case -1 : vReturn = CallByName(vBasicObject, Script, vbMethod)
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))
Case 3 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3))
Case 4 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4))
Case 5 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5))
Case 6 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6))
Case 7 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7))
Case 8 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
, vArgs(8))
Case 9 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
, vArgs(8), vArgs(9))
Case 10 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
, vArgs(8), vArgs(9), vArgs(10))
Case 11 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
, vArgs(8), vArgs(9), vArgs(10), vArgs(11))
Case 12, 13 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12))
Case 14, 15 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14))
Case 16, 17 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16))
Case 18, 19 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18))
Case 20, 21 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
, vArgs(19), vArgs(20))
Case 22, 23 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
, vArgs(19), vArgs(20), vArgs(21), vArgs(22))
Case 24, 25 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
, vArgs(19), vArgs(20), vArgs(21), vArgs(22), vArgs(23), vArgs(24))
Case 26, 27 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
, vArgs(19), vArgs(20), vArgs(21), vArgs(22), vArgs(23), vArgs(24), vArgs(25), vArgs(26))
Case &gt;= 28 : vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
, vArgs(19), vArgs(20), vArgs(21), vArgs(22), vArgs(23), vArgs(24), vArgs(25), vArgs(26), vArgs(27), vArgs(28))
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
&apos; Format the returned array
vReturnArray = Array()
&apos; Distinguish: Basic object
&apos; UNO object
&apos; Array
&apos; Scalar
If IsArray(vReturn) Then
ReDim vReturnArray(0 To 2)
iDims = SF_Array.CountDims(vReturn)
&apos; Replace dates by UNO format
If iDims = 1 Then
For i = LBound(vReturn) To UBound(vReturn)
If VarType(vReturn(i)) = V_DATE Then vReturn(i) = CDateToUnoDateTime(vReturn(i))
Next i
ElseIf iDims = 2 Then
For i = LBound(vReturn, 1) To UBound(vReturn, 1)
For j = LBound(vReturn, 2) To UBound(vReturn, 2)
If VarType(vReturn(i, j)) = V_DATE Then vReturn(i, j) = CDateToUnoDateTime(vReturn(i, j))
Next j
Next i
End If
vReturnArray(0) = vReturn &apos; 2D arrays are flattened by the script provider when returning to Python
vReturnArray(1) = VarType(vReturn)
vReturnArray(2) = iDims
ElseIf VarType(vReturn) = V_OBJECT And Not IsNull(vReturn) Then
&apos; Uno or not Uno ?
bUno = False
If (CallType And cstUno) = cstUno Then &apos; UNO considered only when pre-announced in CallType
Set oObjDesc = SF_Utils._VarTypeObj(vReturn)
bUno = ( oObjDesc.iVarType = V_UNOOBJECT )
End If
If bUno Then
ReDim vReturnArray(0 To 2)
Set vReturnArray(0) = vReturn
Else
ReDim vReturnArray(0 To 5)
vReturnArray(0) = _SF_._AddToPythonSTorage(vReturn)
End If
vReturnArray(1) = V_OBJECT
vReturnArray(2) = Iif(bUno, objUNO, Iif(bBasicClass, objCLASS, objMODULE))
If Not bUno Then
vReturnArray(3) = vReturn.ObjectType
vReturnArray(4) = vReturn.ServiceName
vReturnArray(5) = &quot;&quot;
If vReturn.ObjectType &lt;&gt; &quot;SF_CalcReference&quot; Then &apos; Calc references are implemented as a Type ... End Type data structure
If SF_Array.Contains(vReturn.Properties(), &quot;Name&quot;, SortOrder := &quot;ASC&quot;) Then vReturnArray(5) = vReturn.Name
End If
End If
Else &apos; Scalar or Nothing
ReDim vReturnArray(0 To 1)
If VarType(vReturn) = V_DATE Then vReturnArray(0) = CDateToUnoDateTime(vReturn) Else vReturnArray(0) = vReturn
vReturnArray(1) = VarType(vReturn)
End If
_PythonDispatcher = vReturnArray
Finally:
_SF_.TriggeredByPython = False &apos; Reset normal state
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_PythonHelper._PythonDispatcher
REM -----------------------------------------------------------------------------
Private Function _Repr() As String
&apos;&apos;&apos; Convert the Basic instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Return:
&apos;&apos;&apos; &quot;[PythonHelper]&quot;
_Repr = &quot;[PythonHelper]&quot;
End Function &apos; ScriptForge.SF_PythonHelper._Repr
REM ================================================= END OF SCRIPTFORGE.SF_PythonHelper
</script:module>

View File

@@ -0,0 +1,861 @@
<?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_Region" 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_Region
&apos;&apos;&apos; =========
&apos;&apos;&apos; Singleton class implementing the &quot;ScriptForge.Region&quot; service
&apos;&apos;&apos; Implemented as a usual Basic module
&apos;&apos;&apos;
&apos;&apos;&apos; A collection of functions about languages, countries and timezones
&apos;&apos;&apos; - Locales
&apos;&apos;&apos; - Currencies
&apos;&apos;&apos; - Numbers and dates formatting
&apos;&apos;&apos; - Calendars
&apos;&apos;&apos; - Timezones conversions
&apos;&apos;&apos; - Numbers transformed to text
&apos;&apos;&apos;
&apos;&apos;&apos; Definitions:
&apos;&apos;&apos; Locale or Region
&apos;&apos;&apos; A combination of a language (2 or 3 lower case characters) and a country (2 upper case characters)
&apos;&apos;&apos; Most properties and methods require a locale as argument.
&apos;&apos;&apos; Some of them accept either the complete locale or only the language or country parts.
&apos;&apos;&apos; When absent, the considered locale is the locale used in the LibreOffice user interface.
&apos;&apos;&apos; (see the SF_Platform.OfficeLocale property)
&apos;&apos;&apos; Timezone
&apos;&apos;&apos; Specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;.
&apos;&apos;&apos; The time offset between the timezone and the Greenwich Meridian Time (GMT) is expressed in minutes.
&apos;&apos;&apos; The Daylight Saving Time (DST) is an additional offset.
&apos;&apos;&apos; Both offsets can be positive or negative.
&apos;&apos;&apos; More info on
&apos;&apos;&apos; https://timezonedb.com/time-zones
&apos;&apos;&apos; https://en.wikipedia.org/wiki/Time_zone
&apos;&apos;&apos;
&apos;&apos;&apos; Service invocation example:
&apos;&apos;&apos; Dim regio As Object
&apos;&apos;&apos; Set regio = CreateScriptService(&quot;Region&quot;)
&apos;&apos;&apos;
&apos;&apos;&apos; Detailed user documentation:
&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_region.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
REM ============================================================= PRIVATE MEMBERS
Private UserLocale As String &apos; platform.OfficeLocale
&apos; Reference tables
Private LocaleData As Variant &apos; com.sun.star.i18n.LocaleData
Private LocaleNames As Variant &apos; Array of all available &quot;la-CO&quot; strings
Private UserIndex As Integer &apos; Index of UserLocale in reference tables
REM ============================================================ MODULE CONSTANTS
REM ===================================================== CONSTRUCTOR/DESTRUCTOR
REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
Set Dispose = Nothing
End Function &apos; ScriptForge.SF_Region Explicit destructor
REM ================================================================== PROPERTIES
REM -----------------------------------------------------------------------------
Property Get Country(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the english country name applicable in the given region.
&apos;&apos;&apos; The region expressed either as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - country only (CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.Country(&quot;IT&quot;) &apos; Italy
Country = _PropertyGet(&quot;Country&quot;, Region)
End Property &apos; ScriptForge.SF_Region.Country (get)
REM -----------------------------------------------------------------------------
Property Get Currency(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the currency applicable in the given region.
&apos;&apos;&apos; The region is expressed either as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - country only (CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.Currency(&quot;IT&quot;) &apos; EUR
Currency = _PropertyGet(&quot;Currency&quot;, Region)
End Property &apos; ScriptForge.SF_Region.Currency (get)
REM -----------------------------------------------------------------------------
Public Function DatePatterns(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
&apos;&apos;&apos; Returns list of date acceptance patterns for the given region.
&apos;&apos;&apos; Patterns with input combinations that are accepted as incomplete date input, such as M/D or D.M
&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; The list is zero-based.
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Join(Regio.DatePatterns(&quot;it-IT&quot;), &quot;,&quot;) &apos; D/M/Y,D/M
DatePatterns = _PropertyGet(&quot;DatePatterns&quot;, Region)
End Function &apos; ScriptForge.SF_Region.DatePatterns (get)
REM -----------------------------------------------------------------------------
Property Get DateSeparator(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the separator used in dates applicable in the given region.
&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.DateSeparator(&quot;it-IT&quot;) &apos; /
DateSeparator = _PropertyGet(&quot;DateSeparator&quot;, Region)
End Property &apos; ScriptForge.SF_Region.DateSeparator (get)
REM -----------------------------------------------------------------------------
Public Function DayAbbrevNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
&apos;&apos;&apos; Returns list of abbreviated names of weekdays applicable in the given region.
&apos;&apos;&apos; The region expressed as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - language only (la)
&apos;&apos;&apos; The list is zero-based. The 1st in the list [0] is the Monday.
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Join(Regio.DayAbbrevNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; lun,mar,mer,gio,ven,sab,dom
DayAbbrevNames = _PropertyGet(&quot;DayAbbrevNames&quot;, Region)
End Function &apos; ScriptForge.SF_Region.DayAbbrevNames (get)
REM -----------------------------------------------------------------------------
Public Function DayNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
&apos;&apos;&apos; Returns list of names of weekdays applicable in the given region.
&apos;&apos;&apos; The region expressed as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - language only (la)
&apos;&apos;&apos; The list is zero-based. The 1st in the list [0] is the Monday.
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Join(Regio.DayNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; lunedì,martedì,mercoledì,giovedì,venerdì,sabato,domenica
DayNames = _PropertyGet(&quot;DayNames&quot;, Region)
End Function &apos; ScriptForge.SF_Region.DayNames (get)
REM -----------------------------------------------------------------------------
Public Function DayNarrowNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
&apos;&apos;&apos; Returns list of initials of weekdays applicable in the given region.
&apos;&apos;&apos; The region expressed as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - language only (la)
&apos;&apos;&apos; The list is zero-based. The 1st in the list [0] is the Monday.
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Join(Regio.DayNarrowNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; l,m,m,g,v,s,d
DayNarrowNames = _PropertyGet(&quot;DayNarrowNames&quot;, Region)
End Function &apos; ScriptForge.SF_Region.DayNarrowNames (get)
REM -----------------------------------------------------------------------------
Property Get DecimalPoint(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the decimal separator used in numbers applicable in the given region.
&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.DecimalPoint(&quot;it-IT&quot;) &apos; .
DecimalPoint = _PropertyGet(&quot;DecimalPoint&quot;, Region)
End Property &apos; ScriptForge.SF_Region.DecimalPoint (get)
REM -----------------------------------------------------------------------------
Property Get Language(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the english Language name applicable in the given region.
&apos;&apos;&apos; The region expressed as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - language only (la)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.Language(&quot;it-IT&quot;) &apos; Italian
Language = _PropertyGet(&quot;Language&quot;, Region)
End Property &apos; ScriptForge.SF_Region.Language (get)
REM -----------------------------------------------------------------------------
Property Get ListSeparator(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the separator used in lists applicable in the given region.
&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.ListSeparator(&quot;it-IT&quot;) &apos; ;
ListSeparator = _PropertyGet(&quot;ListSeparator&quot;, Region)
End Property &apos; ScriptForge.SF_Region.ListSeparator (get)
REM -----------------------------------------------------------------------------
Public Function MonthAbbrevNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
&apos;&apos;&apos; Returns list of abbreviated names of months applicable in the given region.
&apos;&apos;&apos; The region expressed as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - language only (la)
&apos;&apos;&apos; The list is zero-based.
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Join(Regio.MonthAbbrevNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic
MonthAbbrevNames = _PropertyGet(&quot;MonthAbbrevNames&quot;, Region)
End Function &apos; ScriptForge.SF_Region.MonthAbbrevNames (get)
REM -----------------------------------------------------------------------------
Public Function MonthNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
&apos;&apos;&apos; Returns list of names of months applicable in the given region.
&apos;&apos;&apos; The region expressed as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - language only (la)
&apos;&apos;&apos; The list is zero-based.
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Join(Regio.MonthNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; gennaio,febbraio,marzo,aprile,maggio,giugno,luglio,agosto,settembre,ottobre,novembre,dicembre
MonthNames = _PropertyGet(&quot;MonthNames&quot;, Region)
End Function &apos; ScriptForge.SF_Region.MonthNames (get)
REM -----------------------------------------------------------------------------
Public Function MonthNarrowNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
&apos;&apos;&apos; Returns list of initials of months applicable in the given region.
&apos;&apos;&apos; The region expressed as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - language only (la)
&apos;&apos;&apos; The list is zero-based.
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Join(Regio.MonthNarrowNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; g,f,m,a,m,g,l,a,s,o,n,d
MonthNarrowNames = _PropertyGet(&quot;MonthNarrowNames&quot;, Region)
End Function &apos; ScriptForge.SF_Region.MonthNarrowNames (get)
REM -----------------------------------------------------------------------------
Property Get ObjectType As String
&apos;&apos;&apos; Only to enable object representation
ObjectType = &quot;SF_Region&quot;
End Property &apos; ScriptForge.SF_Region.ObjectType
REM -----------------------------------------------------------------------------
Property Get ServiceName As String
&apos;&apos;&apos; Internal use
ServiceName = &quot;ScriptForge.Region&quot;
End Property &apos; ScriptForge.SF_Region.ServiceName
REM -----------------------------------------------------------------------------
Property Get ThousandSeparator(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the thousands separator used in numbers applicable in the given region.
&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.ThousandSeparator(&quot;it-IT&quot;) &apos; .
ThousandSeparator = _PropertyGet(&quot;ThousandSeparator&quot;, Region)
End Property &apos; ScriptForge.SF_Region.ThousandSeparator (get)
REM -----------------------------------------------------------------------------
Property Get TimeSeparator(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the separator used to format times applicable in the given region.
&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.TimeSeparator(&quot;it-IT&quot;) &apos; :
TimeSeparator = _PropertyGet(&quot;TimeSeparator&quot;, Region)
End Property &apos; ScriptForge.SF_Region.TimeSeparator (get)
REM ===================================================================== METHODS
REM -----------------------------------------------------------------------------
Public Function DSTOffset(Optional ByVal LocalDateTime As Variant _
, Optional ByVal TimeZone As Variant _
, Optional ByVal Locale As Variant _
) As Integer
&apos;&apos;&apos; Computes the additional offset due to daylight saving (&quot;summer time&quot;)
&apos;&apos;&apos; Args
&apos;&apos;&apos; LocalDateTime: local date and time as a Date. DST offset varies during the year.
&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
&apos;&apos;&apos; Return:
&apos;&apos;&apos; The offset in minutes
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; regio.DSTOffset(DateSerial(2022, 8, 20) + TimeSerial(16, 58, 17), &quot;Europe/Brussels&quot;, &quot;fr-BE&quot;) &apos; 60
Dim iDSTOffset As Integer &apos; Return value
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
Const cstThisSub = &quot;Region.DSTOffset&quot;
Const cstSubArgs = &quot;LocalDateTime, TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
iDSTOffset = 0
Check:
If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(LocalDateTime, &quot;LocalDateTime&quot;, V_DATE) Then GoTo Finally
If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
End If
Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
If IsNull(oLocale) Then GoTo Finally
Try:
Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
With oCalendarImpl
.loadDefaultCalendarTZ(oLocale, TimeZone)
.setLocalDateTime(LocaldateTime)
iDSTOffset = .getValue(com.sun.star.i18n.CalendarFieldIndex.DST_OFFSET)
End With
Finally:
DSTOffset = iDSTOffset
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Region.DSTOffset
REM -----------------------------------------------------------------------------
Public Function GetProperty(Optional ByVal PropertyName As Variant _
, Optional Region As Variant _
) As Variant
&apos;&apos;&apos; Return the actual value of the given property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyName: the name of the property as a string
&apos;&apos;&apos; Region: the language-COUNTRY combination (la-CO) or the country (CO- or the language (la)
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The actual value of the property
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; ARGUMENTERROR The property does not exist
Const cstThisSub = &quot;Region.GetProperty&quot;
Const cstSubArgs = &quot;&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
GetProperty = Null
Check:
If IsMissing(Region) Or IsEmpty(Region) Then Region = &quot;&quot;
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not ScriptForge.SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
If Not ScriptForge.SF_Utils._Validate(Region, &quot;Region&quot;, V_STRING) Then GoTo Catch
End If
Try:
If Len(Region) = 0 Then
GetProperty = _PropertyGet(PropertyName)
Else
GetProperty = _PropertyGet(PropertyName, Region)
End If
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Region.GetProperty
REM -----------------------------------------------------------------------------
Public Function LocalDateTime(Optional ByVal UTCDateTime As Variant _
, Optional ByVal TimeZone As Variant _
, Optional ByVal Locale As Variant _
) As Date
&apos;&apos;&apos; Computes the local date and time from a UTC date and time
&apos;&apos;&apos; Args
&apos;&apos;&apos; UTCDateTime: the universal date and time to be converted to local time
&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
&apos;&apos;&apos; Return:
&apos;&apos;&apos; The local time converted from the corresponding UTC date and time as a Date
&apos;&apos;&apos; If the returned value is before 1900, it is likely that the Locale is not recognized
&apos;&apos;&apos; If the returned value matches the local time, it is likely that the timezone is not recognized
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; regio.LocalDateTime(DateSerial(2022, 3, 20) + TimeSerial(16, 58, 17), &quot;Europe/Brussels&quot;, &quot;fr-BE&quot;)
&apos;&apos;&apos; &apos; 2022-03-20 17:58:17
Dim dLocalDateTime As Double &apos; Return value
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
Const cstThisSub = &quot;Region.LocalDateTime&quot;
Const cstSubArgs = &quot;UTCDateTime, TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
dLocalDateTime = -1
Check:
If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(LocalDateTime, &quot;LocalDateTime&quot;, V_DATE) Then GoTo Finally
If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
End If
Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
If IsNull(oLocale) Then GoTo Finally
Try:
Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
With oCalendarImpl
.loadDefaultCalendarTZ(oLocale, TimeZone)
.setDateTime(UTCDateTime)
dLocalDateTime = .getLocalDateTime()
End With
Finally:
LocalDateTime = CDate(dLocalDateTime)
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Region.LocalDateTime
REM -----------------------------------------------------------------------------
Public Function Methods() As Variant
&apos;&apos;&apos; Return the list of public methods of the Region class as an array
Methods = Array( _
&quot;DSTOffset&quot; _
, &quot;LocalDateTime&quot; _
, &quot;Number2Text&quot; _
, &quot;TimeZoneOffset&quot; _
, &quot;UTCDateTime&quot; _
, &quot;UTCNow&quot; _
)
End Function &apos; ScriptForge.SF_Region.Methods
REM -----------------------------------------------------------------------------
Public Function Number2Text(Optional ByVal Number As Variant _
, Optional ByVal Locale As Variant _
) As String
&apos;&apos;&apos; Convert numbers and money amounts in many languages into words
&apos;&apos;&apos; Args
&apos;&apos;&apos; Number: the number to spell out
&apos;&apos;&apos; Accepted types: strings or numeric values (integer or real numbers)
&apos;&apos;&apos; When a string, a variety of prefixes is supported
&apos;&apos;&apos; The string &quot;help&quot; provides helpful tips about allowed prefixes by language
&apos;&apos;&apos; Example for french
&apos;&apos;&apos; un, deux, trois
&apos;&apos;&apos; feminine: une, deux, trois
&apos;&apos;&apos; masculine: un, deux, trois
&apos;&apos;&apos; ordinal: premier, deuxième, troisième
&apos;&apos;&apos; ordinal-feminine: première, deuxième, troisième
&apos;&apos;&apos; ordinal-masculine: premier, deuxième, troisième
&apos;&apos;&apos; informal: onze-cents, douze-cents, treize-cents
&apos;&apos;&apos; Numbers may be prefixed by ISO currency codes (EUR, USD, ...)
&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or language alone (la)
&apos;&apos;&apos; The list of supported languages can be found on
&apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1linguistic2_1_1XNumberText.html
&apos;&apos;&apos; Return:
&apos;&apos;&apos; The number or amount transformed in words
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; regio.Number2Text(&quot;help&quot;, &quot;fr&quot;) &apos; See above
&apos;&apos;&apos; regio.Number2Text(&quot;79,93&quot;, &quot;fr-BE&quot;) &apos; septante-neuf virgule nonante-trois
&apos;&apos;&apos; regio.Number2Text(Pi(), &quot;pt-BR&quot;) &apos; três vírgula um quatro um cinco nove dois seis cinco três cinco oito nove sete nove
&apos;&apos;&apos; regio.Number2Text(&quot;EUR 1234.56&quot;, &quot;it&quot;) &apos; milleduecentotrentaquattro euro cinquantasei centesimi
Dim sNumber2Text As String &apos; Return value
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim oNumber2Text As Object &apos; com.sun.star.linguistic2.NumberText
Const cstThisSub = &quot;Region.Number2Text&quot;
Const cstSubArgs = &quot;Number, [Locale=&quot;&quot;&quot;&quot;]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
sNumber2Text = &quot;&quot;
Check:
If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(Number, &quot;Number&quot;, Array(V_STRING, V_NUMERIC)) Then GoTo Finally
If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
End If
Set oLocale = SF_Region._GetLocale(Locale, pbLanguage := True)
If IsNull(oLocale) Then GoTo Finally
Try:
Set oNumber2Text = SF_Utils._GetUNOService(&quot;Number2Text&quot;)
sNumber2Text = oNumber2Text.getNumberText(Number, oLocale)
Finally:
Number2Text = sNumber2Text
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Region.Number2Text
REM -----------------------------------------------------------------------------
Public Function Properties() As Variant
&apos;&apos;&apos; Return the list or properties of the Region class as an array
Properties = Array( _
&quot;Country&quot; _
, &quot;Currency&quot; _
, &quot;DatePatterns&quot; _
, &quot;DateSeparator&quot; _
, &quot;DayAbbrevNames&quot; _
, &quot;DayNames&quot; _
, &quot;DayNarrowNames&quot; _
, &quot;DecimalPoint&quot; _
, &quot;Language&quot; _
, &quot;ListSeparator&quot; _
, &quot;MonthAbbrevNames&quot; _
, &quot;MonthNames&quot; _
, &quot;MonthNarrowNames&quot; _
, &quot;ThousandSeparator&quot; _
, &quot;TimeSeparator&quot; _
)
End Function &apos; ScriptForge.SF_Region.Properties
REM -----------------------------------------------------------------------------
Public Function TimeZoneOffset(Optional ByVal TimeZone As Variant _
, Optional ByVal Locale As Variant _
) As Integer
&apos;&apos;&apos; Computes the offset between GMT and the given timezone and locale
&apos;&apos;&apos; Args
&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
&apos;&apos;&apos; Return:
&apos;&apos;&apos; The offset in minutes
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; regio.TimeZoneOffset(&quot;Europe/Brussels&quot;, &quot;fr-BE&quot;) &apos; 60
Dim iTimeZoneOffset As Integer &apos; Return value
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
Const cstThisSub = &quot;Region.TimeZoneOffset&quot;
Const cstSubArgs = &quot;TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
iTimeZoneOffset = 0
Check:
If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
End If
Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
If IsNull(oLocale) Then GoTo Finally
Try:
Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
With oCalendarImpl
.loadDefaultCalendarTZ(oLocale, TimeZone)
iTimeZoneOffset = .getValue(com.sun.star.i18n.CalendarFieldIndex.ZONE_OFFSET)
End With
Finally:
TimeZoneOffset = iTimeZoneOffset
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Region.TimeZoneOffset
REM -----------------------------------------------------------------------------
Public Function UTCDateTime(Optional ByVal LocalDateTime As Variant _
, Optional ByVal TimeZone As Variant _
, Optional ByVal Locale As Variant _
) As Date
&apos;&apos;&apos; Computes the UTC date and time of a given local date and time
&apos;&apos;&apos; Args
&apos;&apos;&apos; LocalDateTime: the date and time measured in a given timezone
&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
&apos;&apos;&apos; Return:
&apos;&apos;&apos; The local time converted to the corresponding UTC date and time as a Date
&apos;&apos;&apos; If the returned value is before 1900, it is likely that the Locale is not recognized
&apos;&apos;&apos; If the returned value matches the local time, it is likely that the the timezone is not recognized
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; regio.UTCDateTime(DateSerial(2022, 3, 20) + TimeSerial(17, 58, 17), &quot;Europe/Brussels&quot;, &quot;fr-BE&quot;)
&apos;&apos;&apos; &apos; 2022-03-20 16:58:17
Dim dUTCDateTime As Double &apos; Return value
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
Const cstThisSub = &quot;Region.UTCDateTime&quot;
Const cstSubArgs = &quot;LocalDateTime, TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
dUTCDateTime = -1
Check:
If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(LocalDateTime, &quot;LocalDateTime&quot;, V_DATE) Then GoTo Finally
If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
End If
Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
If IsNull(oLocale) Then GoTo Finally
Try:
Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
With oCalendarImpl
.loadDefaultCalendarTZ(oLocale, TimeZone)
.setLocalDateTime(LocalDateTime)
dUTCDateTime = .getDateTime()
End With
Finally:
UTCDateTime = CDate(dUTCDateTime)
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Region.UTCDateTime
REM -----------------------------------------------------------------------------
Public Function UTCNow(Optional ByVal TimeZone As Variant _
, Optional ByVal Locale As Variant _
) As Date
&apos;&apos;&apos; Computes the actual UTC date and time
&apos;&apos;&apos; Args
&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
&apos;&apos;&apos; Return:
&apos;&apos;&apos; The actual UTC date and time as a Date
&apos;&apos;&apos; If the returned value is before 1900, it is likely that the Locale is not recognized
&apos;&apos;&apos; If the returned value matches the local time, it is likely that the the timezone is not recognized
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; regio.UTCNow(&quot;Europe/Brussels&quot;, &quot;fr-BE&quot;) &apos; 2022-03-20 16:58:17
Dim dUTCNow As Double &apos; Return value
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
Const cstThisSub = &quot;Region.UTCNow&quot;
Const cstSubArgs = &quot;TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
dUTCNow = -1
Check:
If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
End If
Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
If IsNull(oLocale) Then GoTo Finally
Try:
Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
With oCalendarImpl
.loadDefaultCalendarTZ(oLocale, TimeZone)
.setLocalDateTime(Now())
dUTCNow = .getDateTime()
End With
Finally:
UTCNow = CDate(dUTCNow)
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Region.UTCNow
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
Private Function _GetLocale(ByVal psLocale As String _
, Optional ByVal pbCountry As Variant _
, Optional ByVal pbLanguage As Variant _
) As Object
&apos;&apos;&apos; Convert a locale given as a string to a com.sun.star.lang.Locale object
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psLocale: the input string, as &quot;la-CO&quot;, &quot;la&quot; or &quot;CO&quot;
&apos;&apos;&apos; pbCountry: True when &quot;CO&quot; only is admitted
&apos;&apos;&apos; pbLanguage: True when &quot;la&quot; only is admitted
&apos;&apos;&apos; At most one out of pbLanguage or pbCountry may be True
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; com.sun.star.lang.Locale
Dim sLocale As String &apos; &quot;la-CO&quot;
Dim iLocale As Integer &apos; Index in reference tables
Dim oLocale As Object &apos; Return value com.sun.star.lang.Locale
Dim i As Integer
If IsMissing(pbCountry) Or IsEmpty(pbCountry) Then pbCountry = False
If IsMissing(pbLanguage) Or IsEmpty(pbLanguage) Then pbLanguage = False
_LoadAllLocales() &apos; Initialize locale reference tables
Check:
&apos; The argument may be a language &quot;la&quot;, a country &quot;CO&quot; or a Locale &quot;la-CO&quot;
&apos; Scan the reference tables to find a valid locale as a com.sun.star.lang.Locale
Set oLocale = Nothing : sLocale = &quot;&quot; : iLocale = -1
If Len(psLocale) = 0 Then &apos; Default value is the office com.sun.star.i18n.Locale
sLocale = UserLocale
iLocale = UserIndex
ElseIf InStr(psLocale, &quot;-&quot;) = 0 Then &apos; Language only or country only
Select Case True
Case pbLanguage
&apos; Find any locale having the argument as language
For i = 0 To UBound(LocaleNames)
&apos; A language is presumed 2 or 3 characters long
If Split(LocaleNames(i), &quot;-&quot;)(0) = LCase(psLocale) Then
sLocale = LocaleNames(i)
iLocale = i
Exit For
End If
Next i
Case pbCountry
&apos; Find any locale having the argument as country
For i = 0 To UBound(LocaleNames)
&apos; A country is presumed exactly 2 characters long
If Right(LocaleNames(i), 2) = UCase(psLocale) Then
sLocale = LocaleNames(i)
iLocale = i
Exit For
End If
Next i
Case Else
End Select
Else &apos; A full locale is given
iLocale = SF_Array.IndexOf(LocaleNames, psLocale, CaseSensitive := False)
If iLocale &gt;= 0 Then sLocale = LocaleNames(iLocale)
End If
Try:
&apos; Build error message when relevant
If iLocale &lt; 0 Then
If Not SF_Utils._Validate(psLocale, &quot;Locale&quot;, V_STRING, LocaleNames) Then GoTo Finally
Else
Set oLocale = CreateUnoStruct(&quot;com.sun.star.lang.Locale&quot;)
oLocale.Language = Split(sLocale, &quot;-&quot;)(0) &apos; A language is 2 or 3 characters long
oLocale.Country = Right(sLocale, 2)
End If
Finally:
Set _GetLocale = oLocale
Exit Function
End Function &apos; ScriptForge.SF_Region._GetLocale
REM -----------------------------------------------------------------------------
Private Sub _LoadAllLocales()
&apos;&apos;&apos; Initialize the LocaleNames array = the list of all available locales in the LibreOffice installation
Dim oOffice As Object &apos; com.sun.star.lang.Locale
Dim vLocales As Variant &apos; Array of com.sun.star.lang.Locale
Dim iTop As Integer &apos; Upper bound of LocaleNames
Dim i As Integer
Try:
&apos; Office locale
If Len(UserLocale) = 0 Then
Set oOffice = SF_Utils._GetUNOService(&quot;OfficeLocale&quot;)
UserLocale = oOffice.Language &amp; &quot;-&quot; &amp; oOffice.Country
End If
&apos; LocaleData, localeNames and UserIndex
If IsEmpty(LocaleData) Or IsNull(LocaleData) Or Not IsArray(LocaleNames) Then
LocaleData = SF_Utils._GetUNOService(&quot;LocaleData&quot;)
vLocales = LocaleData.getAllInstalledLocaleNames()
LocaleNames = Array()
iTop = UBound(vLocales)
ReDim LocaleNames(0 To iTop)
For i = 0 To iTop
LocaleNames(i) = vLocales(i).Language &amp; &quot;-&quot; &amp; vLocales(i).Country
If LocaleNames(i) = UserLocale Then UserIndex = i
Next i
End If
End Sub &apos; ScriptForge.SF_Region._LoadAllLocales
REM -----------------------------------------------------------------------------
Private Function _PropertyGet(Optional ByVal psProperty As String _
, Optional ByVal pvLocale As Variant) As Variant
&apos;&apos;&apos; Return the value of the named property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psProperty: the name of the property
&apos;&apos;&apos; pvLocale: a locale in the form language-COUNTRY (la-CO) or language only, or country only
&apos;&apos;&apos; When language or country only, any locale matching either the language or the country is selected
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim vCurrencies As Variant &apos; Array of com.sun.star.i18n.Currency
Dim oCurrency As Object &apos; com.sun.star.i18n.Currency
Dim oLanguageCountryInfo As Object &apos; com.sun.star.i18n.LanguageCountryInfo
Dim oLocaleDataItem2 As Object &apos; com.sun.star.i18n.LocaleDataItem2
Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
Dim oCalItem As Object &apos; com.sun.star.i18n.CalendarItem2
Dim vCalItems() As Variant &apos; Array of days/months
Dim i As Integer, j As Integer
Dim cstThisSub As String
Const cstSubArgs = &quot;&quot;
cstThisSub = &quot;Region.Get&quot; &amp; psProperty
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Check:
If IsMissing(pvLocale) Or IsEmpty(pvLocale) Then pvLocale = &quot;&quot;
If Not SF_Utils._Validate(pvLocale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
Select Case psProperty
Case &quot;Currency&quot;, &quot;Country&quot;
Set oLocale = SF_Region._GetLocale(pvLocale, pbCountry := True) &apos; Country only is admitted
Case &quot;Language&quot;, &quot;DayNames&quot;, &quot;DayAbbrevNames&quot;, &quot;DayNarrowNames&quot; _
, &quot;MonthNames&quot;, &quot;MonthAbbrevNames&quot;, &quot;MonthNarrowNames&quot;
Set oLocale = SF_Region._GetLocale(pvLocale, pbLanguage := True) &apos; Language only is admitted
Case Else
Set oLocale = SF_Region._GetLocale(pvLocale)
End Select
If IsNull(oLocale) Then GoTo Finally
Try:
Select Case psProperty
Case &quot;Country&quot;, &quot;Language&quot;
Set oLanguageCountryInfo = LocaleData.getLanguageCountryInfo(oLocale)
With oLanguageCountryInfo
If psProperty = &quot;Country&quot; Then _PropertyGet = .CountryDefaultName Else _PropertyGet = .LanguageDefaultName
End With
Case &quot;Currency&quot;
vCurrencies = LocaleData.getAllCurrencies(oLocale)
_PropertyGet = &quot;&quot;
For Each oCurrency In vCurrencies
If oCurrency.Default Then
_PropertyGet = oCurrency.BankSymbol
Exit For
End If
Next oCurrency
Case &quot;DatePatterns&quot;
_PropertyGet = LocaleData.getDateAcceptancePatterns(oLocale)
Case &quot;DateSeparator&quot;, &quot;DecimalPoint&quot;, &quot;ListSeparator&quot;, &quot;ThousandSeparator&quot;, &quot;TimeSeparator&quot;
Set oLocaleDataItem2 = LocaleData.getLocaleItem2(oLocale)
With oLocaleDataItem2
Select Case psProperty
Case &quot;DateSeparator&quot; : _PropertyGet = .dateSeparator
Case &quot;DecimalPoint&quot; : _PropertyGet = .decimalSeparator
Case &quot;ListSeparator&quot; : _PropertyGet = .listSeparator
Case &quot;ThousandSeparator&quot; : _PropertyGet = .thousandSeparator
Case &quot;TimeSeparator&quot; : _PropertyGet = .timeSeparator
End Select
End With
Case &quot;DayAbbrevNames&quot;, &quot;DayNames&quot;, &quot;DayNarrowNames&quot;
Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
With oCalendarImpl
.loadDefaultCalendar(oLocale)
vCalItems = Array() : ReDim vCalItems(0 To 6)
For i = 0 To UBound(.Days2)
Set oCalItem = .Days2(i)
j = Iif(i = 0, 6, i - 1)
Select Case psProperty
Case &quot;DayNames&quot; : vCalItems(j) = oCalItem.FullName
Case &quot;DayAbbrevNames&quot; : vCalItems(j) = oCalItem.AbbrevName
Case &quot;DayNarrowNames&quot; : vCalItems(j) = oCalItem.NarrowName
End Select
Next i
_PropertyGet = vCalItems
End With
Case &quot;MonthAbbrevNames&quot;, &quot;MonthNames&quot;, &quot;MonthNarrowNames&quot;
Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
With oCalendarImpl
.loadDefaultCalendar(oLocale)
vCalItems = Array() : ReDim vCalItems(0 To 11)
For i = 0 To UBound(.Months2)
Set oCalItem = .Months2(i)
Select Case psProperty
Case &quot;MonthNames&quot; : vCalItems(i) = oCalItem.FullName
Case &quot;MonthAbbrevNames&quot; : vCalItems(i) = oCalItem.AbbrevName
Case &quot;MonthNarrowNames&quot; : vCalItems(i) = oCalItem.NarrowName
End Select
Next i
_PropertyGet = vCalItems
End With
Case Else
_PropertyGet = &quot;&quot;
End Select
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Region._PropertyGet
REM ================================================ END OF SCRIPTFORGE.SF_REGION
</script:module>

View File

@@ -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;, &quot;datasheet&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>

View File

@@ -0,0 +1,702 @@
<?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_TextStream" 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 ClassModule
Option Explicit
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
&apos;&apos;&apos; SF_TextStream
&apos;&apos;&apos; =============
&apos;&apos;&apos; Class instantiated by the
&apos;&apos;&apos; SF_FileSystem.CreateTextFile
&apos;&apos;&apos; SF_FileSystem.OpenTextFile
&apos;&apos;&apos; methods to facilitate the sequential processing of text files
&apos;&apos;&apos; All open/read/write/close operations are presumed to happen during the same macro run
&apos;&apos;&apos; The encoding to be used may be chosen by the user
&apos;&apos;&apos; The list is in the Name column of https://www.iana.org/assignments/character-sets/character-sets.xhtml
&apos;&apos;&apos; Note that probably not all values are available
&apos;&apos;&apos; Line delimiters may be chosen by the user
&apos;&apos;&apos; In input, CR, LF or CR+LF are supported
&apos;&apos;&apos; In output, the default value is the usual newline on the actual operating system (see SF_FileSystem.sfNEWLINE)
&apos;&apos;&apos;
&apos;&apos;&apos; The design choices are largely inspired by
&apos;&apos;&apos; https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/textstream-object
&apos;&apos;&apos; The implementation is mainly based on the XTextInputStream and XTextOutputStream UNO interfaces
&apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1io_1_1XTextInputStream.html
&apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1io_1_1XTextOutputStream.html
&apos;&apos;&apos;
&apos;&apos;&apos; Instantiation example:
&apos;&apos;&apos; Dim FSO As Object, myFile As Object
&apos;&apos;&apos; Set FSO = CreateScriptService(&quot;FileSystem&quot;)
&apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\ThisFile.txt&quot;, FSO.ForReading) &apos; Once per file
&apos;&apos;&apos;
&apos;&apos;&apos; Detailed user documentation:
&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_textstream.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 FILENOTOPENERROR = &quot;FILENOTOPENERROR&quot; &apos; The file is already closed
Const FILEOPENMODEERROR = &quot;FILEOPENMODEERROR&quot; &apos; The file is open in incompatible mode
Const ENDOFFILEERROR = &quot;ENDOFFILEERROR&quot; &apos; When file was read, an end-of-file was encountered
REM ============================================================= PRIVATE MEMBERS
Private [Me] As Object
Private [_Parent] As Object
Private ObjectType As String &apos; Must be TEXTSTREAM
Private ServiceName As String
Private _FileName As String &apos; File where it is about
Private _IOMode As Integer &apos; ForReading, ForWriting or ForAppending
Private _Encoding As String &apos; https://www.iana.org/assignments/character-sets/character-sets.xhtml
Private _NewLine As String &apos; Line break in write mode
Private _FileExists As Boolean &apos; True if file exists before open
Private _LineNumber As Long &apos; Number of lines read or written
Private _FileHandler As Object &apos; com.sun.star.io.XInputStream or
&apos; com.sun.star.io.XOutputStream or
&apos; com.sun.star.io.XStream
Private _InputStream As Object &apos; com.sun.star.io.TextInputStream
Private _OutputStream As Object &apos; com.sun.star.io.TextOutputStream
Private _ForceBlankLine As Boolean &apos; Workaround: XTextInputStream misses last line if file ends with newline
REM ============================================================ MODULE CONSTANTS
REM ===================================================== CONSTRUCTOR/DESTRUCTOR
REM -----------------------------------------------------------------------------
Private Sub Class_Initialize()
Set [Me] = Nothing
Set [_Parent] = Nothing
ObjectType = &quot;TEXTSTREAM&quot;
ServiceName = &quot;ScriptForge.TextStream&quot;
_FileName = &quot;&quot;
_IOMode = -1
_Encoding = &quot;&quot;
_NewLine = &quot;&quot;
_FileExists = False
_LineNumber = 0
Set _FileHandler = Nothing
Set _InputStream = Nothing
Set _OutputStream = Nothing
_ForceBlankLine = False
End Sub &apos; ScriptForge.SF_TextStream Constructor
REM -----------------------------------------------------------------------------
Private Sub Class_Terminate()
Call Class_Initialize()
End Sub &apos; ScriptForge.SF_TextStream Destructor
REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
Call Class_Terminate()
Set Dispose = Nothing
End Function &apos; ScriptForge.SF_TextStream Explicit Destructor
REM ================================================================== PROPERTIES
REM -----------------------------------------------------------------------------
Property Get AtEndOfStream() As Boolean
&apos;&apos;&apos; In reading mode, True indicates that the end of the file has been reached
&apos;&apos;&apos; In write and append modes, or if the file is not ready =&gt; always True
&apos;&apos;&apos; The property should be invoked BEFORE each ReadLine() method:
&apos;&apos;&apos; A ReadLine() executed while AtEndOfStream is True will raise an error
&apos;&apos;&apos; Example:
&apos;&apos;&apos; Dim sLine As String
&apos;&apos;&apos; Do While Not myFile.AtEndOfStream
&apos;&apos;&apos; sLine = myFile.ReadLine()
&apos;&apos;&apos; &apos; ...
&apos;&apos;&apos; Loop
AtEndOfStream = _PropertyGet(&quot;AtEndOfStream&quot;)
End Property &apos; ScriptForge.SF_TextStream.AtEndOfStream
REM -----------------------------------------------------------------------------
Property Get Encoding() As String
&apos;&apos;&apos; Returns the name of the text file either in url or in native operating system format
&apos;&apos;&apos; Example:
&apos;&apos;&apos; Dim myFile As Object
&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
&apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\myFile.txt&quot;)
&apos;&apos;&apos; MsgBox myFile.Encoding &apos; UTF-8
Encoding = _PropertyGet(&quot;Encoding&quot;)
End Property &apos; ScriptForge.SF_TextStream.Encoding
REM -----------------------------------------------------------------------------
Property Get FileName() As String
&apos;&apos;&apos; Returns the name of the text file either in url or in native operating system format
&apos;&apos;&apos; Example:
&apos;&apos;&apos; Dim myFile As Object
&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
&apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\myFile.txt&quot;)
&apos;&apos;&apos; MsgBox myFile.FileName &apos; C:\Temp\myFile.txt
FileName = _PropertyGet(&quot;FileName&quot;)
End Property &apos; ScriptForge.SF_TextStream.FileName
REM -----------------------------------------------------------------------------
Property Get IOMode() As String
&apos;&apos;&apos; Returns either &quot;READ&quot;, &quot;WRITE&quot; or &quot;APPEND&quot;
&apos;&apos;&apos; Example:
&apos;&apos;&apos; Dim myFile As Object
&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
&apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\myFile.txt&quot;)
&apos;&apos;&apos; MsgBox myFile.IOMode &apos; READ
IOMode = _PropertyGet(&quot;IOMode&quot;)
End Property &apos; ScriptForge.SF_TextStream.IOMode
REM -----------------------------------------------------------------------------
Property Get Line() As Long
&apos;&apos;&apos; Returns the number of lines read or written so far
&apos;&apos;&apos; Example:
&apos;&apos;&apos; Dim myFile As Object
&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
&apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\myFile.txt&quot;, FSO.ForAppending)
&apos;&apos;&apos; MsgBox myFile.Line &apos; The number of lines already present in myFile
Line = _PropertyGet(&quot;Line&quot;)
End Property &apos; ScriptForge.SF_TextStream.Line
REM -----------------------------------------------------------------------------
Property Get NewLine() As Variant
&apos;&apos;&apos; Returns the current character string to be inserted between 2 successive written lines
&apos;&apos;&apos; The default value is the native line separator in the current operating system
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox myFile.NewLine
NewLine = _PropertyGet(&quot;NewLine&quot;)
End Property &apos; ScriptForge.SF_TextStream.NewLine (get)
REM -----------------------------------------------------------------------------
Property Let NewLine(ByVal pvLineBreak As Variant)
&apos;&apos;&apos; Sets the current character string to be inserted between 2 successive written lines
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myFile.NewLine = Chr(13) &amp; Chr(10)
Const cstThisSub = &quot;TextStream.setNewLine&quot;
SF_Utils._EnterFunction(cstThisSub)
If VarType(pvLineBreak) = V_STRING Then _NewLine = pvLineBreak
SF_Utils._ExitFunction(cstThisSub)
End Property &apos; ScriptForge.SF_TextStream.NewLine (let)
REM ===================================================================== METHODS
REM -----------------------------------------------------------------------------
Public Function CloseFile() As Boolean
&apos;&apos;&apos; Empties the output buffer if relevant. Closes the actual input or output stream
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if the closure was successful
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; FILENOTOPENERROR Nothing found to close
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myFile.CloseFile()
Dim bClose As Boolean &apos; Return value
Const cstThisSub = &quot;TextStream.CloseFile&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bClose = False
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
If Not _IsFileOpen() Then GoTo Finally
Try:
If Not IsNull(_InputStream) Then _InputStream.closeInput()
If Not IsNull(_OutputStream) Then
_OutputStream.flush()
_OutputStream.closeOutput()
End If
Set _InputStream = Nothing
Set _OutputStream = Nothing
Set _FileHandler = Nothing
bClose = True
Finally:
CloseFile = bClose
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_TextStream.CloseFile
REM -----------------------------------------------------------------------------
Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
&apos;&apos;&apos; Return the actual value of the given property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyName: the name of the property as a string
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The actual value of the property
&apos;&apos;&apos; If the property does not exist, returns Null
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; see the exceptions of the individual properties
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myModel.GetProperty(&quot;MyProperty&quot;)
Const cstThisSub = &quot;TextStream.GetProperty&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
GetProperty = Null
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
End If
Try:
GetProperty = _PropertyGet(PropertyName)
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_TextStream.GetProperty
REM -----------------------------------------------------------------------------
Public Function Methods() As Variant
&apos;&apos;&apos; Return the list of public methods of the Model service as an array
Methods = Array( _
&quot;CloseFile&quot; _
, &quot;ReadAll&quot; _
, &quot;readLine&quot; _
, &quot;SkipLine&quot; _
, &quot;WriteBlankLines&quot; _
, &quot;WriteLine&quot; _
)
End Function &apos; ScriptForge.SF_TextStream.Methods
REM -----------------------------------------------------------------------------
Public Function Properties() As Variant
&apos;&apos;&apos; Return the list or properties of the Timer class as an array
Properties = Array( _
&quot;AtEndOfStream&quot; _
, &quot;Encoding&quot; _
, &quot;FileName&quot; _
, &quot;IOMode&quot; _
, &quot;Line&quot; _
, &quot;NewLine&quot; _
)
End Function &apos; ScriptForge.SF_TextStream.Properties
REM -----------------------------------------------------------------------------
Public Function ReadAll() As String
&apos;&apos;&apos; Returns all the remaining lines in the text stream as one string. Line breaks are NOT removed
&apos;&apos;&apos; The resulting string can be split in lines
&apos;&apos;&apos; either by using the usual Split Basic builtin function if the line delimiter is known
&apos;&apos;&apos; or with the SF_String.SplitLines method
&apos;&apos;&apos; For large files, using the ReadAll method wastes memory resources.
&apos;&apos;&apos; Other techniques should be used to input a file, such as reading a file line-by-line
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The read lines. The string may be empty.
&apos;&apos;&apos; Note that the Line property in incremented only by 1
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
&apos;&apos;&apos; FILEOPENMODEERROR File opened in write or append modes
&apos;&apos;&apos; ENDOFFILEERROR Previous reads already reached the end of the file
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; Dim a As String
&apos;&apos;&apos; a = myFile.ReadAll()
Dim sRead As String &apos; Return value
Const cstThisSub = &quot;TextStream.ReadAll&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
sRead = &quot;&quot;
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsFileOpen(&quot;READ&quot;) Then GoTo Finally
If _InputStream.isEOF() Then GoTo CatchEOF
End If
Try:
sRead = _InputStream.readString(Array(), False)
_LineNumber = _LineNumber + 1
Finally:
ReadAll = sRead
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchEOF:
SF_Exception.RaiseFatal(ENDOFFILEERROR, FileName)
GoTo Finally
End Function &apos; ScriptForge.SF_TextStream.ReadAll
REM -----------------------------------------------------------------------------
Public Function ReadLine() As String
&apos;&apos;&apos; Returns the next line in the text stream as a string. Line breaks are removed.
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The read line. The string may be empty.
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
&apos;&apos;&apos; FILEOPENMODEERROR File opened in write or append modes
&apos;&apos;&apos; ENDOFFILEERROR Previous reads already reached the end of the file
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; Dim a As String
&apos;&apos;&apos; a = myFile.ReadLine()
Dim sRead As String &apos; Return value
Dim iRead As Integer &apos; Length of line break
Const cstThisSub = &quot;TextStream.ReadLine&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
sRead = &quot;&quot;
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsFileOpen(&quot;READ&quot;) Then GoTo Finally
If AtEndOfStream Then GoTo CatchEOF
End If
Try:
&apos; When the text file ends with a line break,
&apos; XTextInputStream.readLine() returns the line break together with the last line
&apos; Hence the workaround to force a blank line at the end
If _ForceBlankLine Then
sRead = &quot;&quot;
_ForceBlankLine = False
Else
sRead = _InputStream.readLine()
&apos; The isEOF() is set immediately after having read the last line
If _InputStream.isEOF() And Len(sRead) &gt; 0 Then
iRead = 0
If SF_String.EndsWith(sRead, SF_String.sfCRLF) Then
iRead = 2
ElseIf SF_String.EndsWith(sRead, SF_String.sfLF) Or SF_String.EndsWith(sRead, SF_String.sfCR) Then
iRead = 1
End If
If iRead &gt; 0 Then
sRead = Left(sRead, Len(sRead) - iRead)
_ForceBlankLine = True &apos; Provision for a last empty line at the next read loop
End If
End If
End If
_LineNumber = _LineNumber + 1
Finally:
ReadLine = sRead
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchEOF:
SF_Exception.RaiseFatal(ENDOFFILEERROR, FileName)
GoTo Finally
End Function &apos; ScriptForge.SF_TextStream.ReadLine
REM -----------------------------------------------------------------------------
Public Function SetProperty(Optional ByVal PropertyName As Variant _
, Optional ByRef Value As Variant _
) As Boolean
&apos;&apos;&apos; Set a new value to the given property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyName: the name of the property as a string
&apos;&apos;&apos; Value: its new value
&apos;&apos;&apos; Exceptions
&apos;&apos;&apos; ARGUMENTERROR The property does not exist
Dim bSet As Boolean &apos; Return value
Const cstThisSub = &quot;TextStream.SetProperty&quot;
Const cstSubArgs = &quot;PropertyName, Value&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bSet = False
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
End If
Try:
bSet = True
Select Case UCase(PropertyName)
Case &quot;NEWLINE&quot;
If Not SF_Utils._Validate(Value, &quot;Value&quot;, V_STRING) Then GoTo Catch
NewLine = Value
Case Else
bSet = False
End Select
Finally:
SetProperty = bSet
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_TextStream.SetProperty
REM -----------------------------------------------------------------------------
Public Sub SkipLine()
&apos;&apos;&apos; Skips the next line when reading a TextStream file.
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
&apos;&apos;&apos; FILEOPENMODEERROR File opened in write or append modes
&apos;&apos;&apos; ENDOFFILEERROR Previous reads already reached the end of the file
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myFile.SkipLine()
Dim sRead As String &apos; Read buffer
Const cstThisSub = &quot;TextStream.SkipLine&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsFileOpen(&quot;READ&quot;) Then GoTo Finally
If Not _ForceBlankLine Then &apos; The file ends with a newline =&gt; return one empty line more
If _InputStream.isEOF() Then GoTo CatchEOF
End If
End If
Try:
sRead = ReadLine()
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Sub
Catch:
GoTo Finally
CatchEOF:
SF_Exception.RaiseFatal(ENDOFFILEERROR, FileName)
GoTo Finally
End Sub &apos; ScriptForge.SF_TextStream.SkipLine
REM -----------------------------------------------------------------------------
Public Sub WriteBlankLines(Optional ByVal Lines As Variant)
&apos;&apos;&apos; Writes a number of empty lines in the output stream
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Lines: the number of lines to write
&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 read mode
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myFile.WriteBlankLines(10)
Dim i As Long
Const cstThisSub = &quot;TextStream.WriteBlankLines&quot;
Const cstSubArgs = &quot;Lines&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsFileOpen(&quot;WRITE&quot;) Then GoTo Finally
If Not SF_Utils._Validate(Lines, &quot;Lines&quot;, V_NUMERIC) Then GoTo Finally
End If
Try:
For i = 1 To Lines
_OutputStream.writeString(_NewLine)
Next i
_LineNumber = _LineNumber + Lines
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Sub
Catch:
GoTo Finally
End Sub &apos; ScriptForge.SF_TextStream.WriteBlankLines
REM -----------------------------------------------------------------------------
Public Sub WriteLine(Optional ByVal Line As Variant)
&apos;&apos;&apos; Writes the given line to the output stream. A newline is inserted if relevant
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Line: the line to write, may be empty
&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; Examples:
&apos;&apos;&apos; myFile.WriteLine(&quot;Next line&quot;)
Dim i As Long
Const cstThisSub = &quot;TextStream.WriteLine&quot;
Const cstSubArgs = &quot;Line&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsFileOpen(&quot;WRITE&quot;) Then GoTo Finally
If Not SF_Utils._Validate(Line, &quot;Line&quot;, V_STRING) Then GoTo Finally
End If
Try:
_OutputStream.writeString(Iif(_LineNumber &gt; 0, _NewLine, &quot;&quot;) &amp; Line)
_LineNumber = _LineNumber + 1
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Sub
Catch:
GoTo Finally
End Sub &apos; ScriptForge.SF_TextStream.WriteLine
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
Public Sub _Initialize()
&apos;&apos;&apos; Opens file and setup input and/or output streams (ForAppending requires both)
Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
&apos; Default newline related to current operating system
_NewLine = SF_String.sfNEWLINE
Set oSfa = SF_Utils._GetUNOService(&quot;FileAccess&quot;)
&apos; Setup input and/or output streams based on READ/WRITE/APPEND IO modes
Select Case _IOMode
Case SF_FileSystem.ForReading
Set _FileHandler = oSfa.openFileRead(_FileName)
Set _InputStream = CreateUnoService(&quot;com.sun.star.io.TextInputStream&quot;)
_InputStream.setInputStream(_FileHandler)
Case SF_FileSystem.ForWriting
&apos; Output file is deleted beforehand
If _FileExists Then oSfa.kill(_FileName)
Set _FileHandler = oSfa.openFileWrite(_FileName)
Set _OutputStream = CreateUnoService(&quot;com.sun.star.io.TextOutputStream&quot;)
_OutputStream.setOutputStream(_FileHandler)
Case SF_FileSystem.ForAppending
Set _FileHandler = oSfa.openFileReadWrite(_FileName)
Set _InputStream = CreateUnoService(&quot;com.sun.star.io.TextInputStream&quot;)
Set _OutputStream = CreateUnoService(&quot;com.sun.star.io.TextOutputStream&quot;)
_InputStream.setInputStream(_FileHandler)
&apos; Position at end of file: Skip and count existing lines
_LineNumber = 0
Do While Not _InputStream.isEOF()
_InputStream.readLine()
_LineNumber = _LineNumber + 1
Loop
_OutputStream.setOutputStream(_FileHandler)
End Select
If _Encoding = &quot;&quot; Then _Encoding = &quot;UTF-8&quot;
If Not IsNull(_InputStream) Then _InputStream.setEncoding(_Encoding)
If Not IsNull(_OutputStream) Then _OutputStream.setEncoding(_Encoding)
End Sub &apos; ScriptForge.SF_TextStream._Initialize
REM -----------------------------------------------------------------------------
Private Function _IsFileOpen(Optional ByVal psMode As String) As Boolean
&apos;&apos;&apos; Checks if file is open with the right mode (READ or WRITE)
&apos;&apos;&apos; Raises an exception if the file is not open at all or not in the right mode
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psMode: READ or WRITE or zero-length string
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
&apos;&apos;&apos; FILEOPENMODEERROR File opened in incompatible mode
_IsFileOpen = False
If IsMissing(psMode) Then psMode = &quot;&quot;
If IsNull(_InputStream) And IsNull(_OutputStream) Then GoTo CatchNotOpen
Select Case psMode
Case &quot;READ&quot;
If IsNull(_InputStream) Then GoTo CatchOpenMode
If _IOMode &lt;&gt; SF_FileSystem.ForReading Then GoTo CatchOpenMode
Case &quot;WRITE&quot;
If IsNull(_OutputStream) Then GoTo CatchOpenMode
If _IOMode = SF_FileSystem.ForReading Then GoTo CatchOpenMode
Case Else
End Select
_IsFileOpen = True
Finally:
Exit Function
CatchNotOpen:
SF_Exception.RaiseFatal(FILENOTOPENERROR, FileName)
GoTo Finally
CatchOpenMode:
SF_Exception.RaiseFatal(FILEOPENMODEERROR, FileName, IOMode)
GoTo Finally
End Function &apos; ScriptForge.SF_TextStream._IsFileOpen
REM -----------------------------------------------------------------------------
Private Function _PropertyGet(Optional ByVal psProperty As String)
&apos;&apos;&apos; Return the value of the named property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psProperty: the name of the property
Dim cstThisSub As String
Dim cstSubArgs As String
cstThisSub = &quot;TextStream.get&quot; &amp; psProperty
cstSubArgs = &quot;&quot;
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Select Case UCase(psProperty)
Case UCase(&quot;AtEndOfStream&quot;)
Select Case _IOMode
Case SF_FileSystem.ForReading
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;)
_PropertyGet = _Encoding
Case UCase(&quot;FileName&quot;)
_PropertyGet = SF_FileSystem._ConvertFromUrl(_FileName) &apos; Depends on FileNaming
Case UCase(&quot;IOMode&quot;)
With SF_FileSystem
Select Case _IOMode
Case .ForReading : _PropertyGet = &quot;READ&quot;
Case .ForWriting : _PropertyGet = &quot;WRITE&quot;
Case .ForAppending : _PropertyGet = &quot;APPEND&quot;
Case Else : _PropertyGet = &quot;&quot;
End Select
End With
Case UCase(&quot;Line&quot;)
_PropertyGet = _LineNumber
Case UCase(&quot;NewLine&quot;)
_PropertyGet = _NewLine
Case Else
_PropertyGet = Null
End Select
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_TextStream._PropertyGet
REM -----------------------------------------------------------------------------
Private Function _Repr() As String
&apos;&apos;&apos; Convert the TextStream instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Return:
&apos;&apos;&apos; &quot;[TextStream]: File name, IOMode, LineNumber&quot;
_Repr = &quot;[TextStream]: &quot; &amp; FileName &amp; &quot;,&quot; &amp; IOMode &amp; &quot;,&quot; &amp; CStr(Line)
End Function &apos; ScriptForge.SF_TextStream._Repr
REM ============================================ END OF SCRIPTFORGE.SF_TextStream
</script:module>

View File

@@ -0,0 +1,466 @@
<?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_Timer" 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 ClassModule
Option Explicit
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
&apos;&apos;&apos; SF_Timer
&apos;&apos;&apos; ========
&apos;&apos;&apos; Class for management of scripts execution performance
&apos;&apos;&apos; A Timer measures durations. It can be suspended, resumed, restarted
&apos;&apos;&apos; Duration properties are expressed in seconds with a precision of 3 decimal digits
&apos;&apos;&apos;
&apos;&apos;&apos; Service invocation example:
&apos;&apos;&apos; Dim myTimer As Variant
&apos;&apos;&apos; myTimer = CreateScriptService(&quot;Timer&quot;)
&apos;&apos;&apos; myTimer = CreateScriptService(&quot;Timer&quot;, True) &apos; =&gt; To start timer immediately
&apos;&apos;&apos;
&apos;&apos;&apos; Detailed user documentation:
&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_timer.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
REM ============================================================= PRIVATE MEMBERS
Private [Me] As Object
Private [_Parent] As Object
Private ObjectType As String &apos; Must be &quot;TIMER&quot;
Private ServiceName As String
Private _TimerStatus As Integer &apos; inactive, started, suspended or stopped
Private _StartTime As Double &apos; Moment when timer started, restarted
Private _EndTime As Double &apos; Moment when timer stopped
Private _SuspendTime As Double &apos; Moment when timer suspended
Private _SuspendDuration As Double &apos; Duration of suspended status as a difference of times
REM ============================================================ MODULE CONSTANTS
Private Const STATUSINACTIVE = 0
Private Const STATUSSTARTED = 1
Private Const STATUSSUSPENDED = 2
Private Const STATUSSTOPPED = 3
Private Const DSECOND As Double = 1 / (24 * 60 * 60) &apos; Duration of 1 second as compared to 1.0 = 1 day
REM ===================================================== CONSTRUCTOR/DESTRUCTOR
REM -----------------------------------------------------------------------------
Private Sub Class_Initialize()
Set [Me] = Nothing
Set [_Parent] = Nothing
ObjectType = &quot;TIMER&quot;
ServiceName = &quot;ScriptForge.Timer&quot;
_TimerStatus = STATUSINACTIVE
_StartTime = 0
_EndTime = 0
_SuspendTime = 0
_SuspendDuration = 0
End Sub &apos; ScriptForge.SF_Timer Constructor
REM -----------------------------------------------------------------------------
Private Sub Class_Terminate()
Call Class_Initialize()
End Sub &apos; ScriptForge.SF_Timer Destructor
REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
Call Class_Terminate()
Set Dispose = Nothing
End Function &apos; ScriptForge.SF_Timer Explicit destructor
REM ================================================================== PROPERTIES
REM -----------------------------------------------------------------------------
Public Function Duration() As Double
&apos;&apos;&apos; Returns the actual (out of suspensions) time elapsed since start or between start and stop
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A Double expressing the duration in seconds
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myTimer.Duration returns 1.234 (1 sec, 234 ms)
Duration = _PropertyGet(&quot;Duration&quot;)
End Function &apos; ScriptForge.SF_Timer.Duration
REM -----------------------------------------------------------------------------
Property Get IsStarted() As Boolean
&apos;&apos;&apos; Returns True if timer is started or suspended
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myTimer.IsStarted
IsStarted = _PropertyGet(&quot;IsStarted&quot;)
End Property &apos; ScriptForge.SF_Timer.IsStarted
REM -----------------------------------------------------------------------------
Property Get IsSuspended() As Boolean
&apos;&apos;&apos; Returns True if timer is started and suspended
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myTimer.IsSuspended
IsSuspended = _PropertyGet(&quot;IsSuspended&quot;)
End Property &apos; ScriptForge.SF_Timer.IsSuspended
REM -----------------------------------------------------------------------------
Public Function SuspendDuration() As Double
&apos;&apos;&apos; Returns the actual time elapsed while suspended since start or between start and stop
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A Double expressing the duration in seconds
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myTimer.SuspendDuration returns 1.234 (1 sec, 234 ms)
SuspendDuration = _PropertyGet(&quot;SuspendDuration&quot;)
End Function &apos; ScriptForge.SF_Timer.SuspendDuration
REM -----------------------------------------------------------------------------
Public Function TotalDuration() As Double
&apos;&apos;&apos; Returns the actual time elapsed (including suspensions) since start or between start and stop
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A Double expressing the duration in seconds
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myTimer.TotalDuration returns 1.234 (1 sec, 234 ms)
TotalDuration = _PropertyGet(&quot;TotalDuration&quot;)
End Function &apos; ScriptForge.SF_Timer.TotalDuration
REM ===================================================================== METHODS
REM -----------------------------------------------------------------------------
Public Function Continue() As Boolean
&apos;&apos;&apos; Halt suspension of a running timer
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if successful, False if the timer is not suspended
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myTimer.Continue()
Const cstThisSub = &quot;Timer.Continue&quot;
Const cstSubArgs = &quot;&quot;
Check:
Continue = False
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If _TimerStatus = STATUSSUSPENDED Then
_TimerStatus = STATUSSTARTED
_SuspendDuration = _SuspendDuration + _Now() - _SuspendTime
_SuspendTime = 0
Continue = True
End If
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Timer.Continue
REM -----------------------------------------------------------------------------
Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
&apos;&apos;&apos; Return the actual value of the given property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyName: the name of the property as a string
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The actual value of the property
&apos;&apos;&apos; Exceptions
&apos;&apos;&apos; ARGUMENTERROR The property does not exist
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myTimer.GetProperty(&quot;Duration&quot;)
Const cstThisSub = &quot;Timer.GetProperty&quot;
Const cstSubArgs = &quot;PropertyName&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
GetProperty = Null
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
End If
Try:
GetProperty = _PropertyGet(PropertyName)
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Timer.Properties
REM -----------------------------------------------------------------------------
Public Function Methods() As Variant
&apos;&apos;&apos; Return the list or methods of the Timer class as an array
Methods = Array( _
&quot;Continue&quot; _
, &quot;Restart&quot; _
, &quot;Start&quot; _
, &quot;Suspend&quot; _
, &quot;Terminate&quot; _
)
End Function &apos; ScriptForge.SF_Timer.Methods
REM -----------------------------------------------------------------------------
Public Function Properties() As Variant
&apos;&apos;&apos; Return the list or properties of the Timer class as an array
Properties = Array( _
&quot;Duration&quot; _
, &quot;IsStarted&quot; _
, &quot;IsSuspended&quot; _
, &quot;SuspendDuration&quot; _
, &quot;TotalDuration&quot; _
)
End Function &apos; ScriptForge.SF_Timer.Properties
REM -----------------------------------------------------------------------------
Public Function Restart() As Boolean
&apos;&apos;&apos; Terminate the timer and restart a new clean timer
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if successful, False if the timer is inactive
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myTimer.Restart()
Const cstThisSub = &quot;Timer.Restart&quot;
Const cstSubArgs = &quot;&quot;
Check:
Restart = False
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If _TimerStatus &lt;&gt; STATUSINACTIVE Then
If _TimerStatus &lt;&gt; STATUSSTOPPED Then Terminate()
Start()
Restart = True
End If
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Timer.Restart
REM -----------------------------------------------------------------------------
Public Function SetProperty(Optional ByVal PropertyName As Variant _
, Optional ByRef Value As Variant _
) As Boolean
&apos;&apos;&apos; Set a new value to the given property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyName: the name of the property as a string
&apos;&apos;&apos; Value: its new value
&apos;&apos;&apos; Exceptions
&apos;&apos;&apos; ARGUMENTERROR The property does not exist
Const cstThisSub = &quot;Timer.SetProperty&quot;
Const cstSubArgs = &quot;PropertyName, Value&quot;
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, &quot;PropertyName&quot;, 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 &apos; ScriptForge.SF_Timer.SetProperty
REM -----------------------------------------------------------------------------
Public Function Start() As Boolean
&apos;&apos;&apos; Start a new clean timer
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if successful, False if the timer is already started
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myTimer.Start()
Const cstThisSub = &quot;Timer.Start&quot;
Const cstSubArgs = &quot;&quot;
Check:
Start = False
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If _TimerStatus = STATUSINACTIVE Or _TimerStatus = STATUSSTOPPED Then
_TimerStatus = STATUSSTARTED
_StartTime = _Now()
_EndTime = 0
_SuspendTime = 0
_SuspendDuration = 0
Start = True
End If
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Timer.Start
REM -----------------------------------------------------------------------------
Public Function Suspend() As Boolean
&apos;&apos;&apos; Suspend a running timer
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if successful, False if the timer is not started or already suspended
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myTimer.Suspend()
Const cstThisSub = &quot;Timer.Suspend&quot;
Const cstSubArgs = &quot;&quot;
Check:
Suspend = False
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If _TimerStatus = STATUSSTARTED Then
_TimerStatus = STATUSSUSPENDED
_SuspendTime = _Now()
Suspend = True
End If
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Timer.Suspend
REM -----------------------------------------------------------------------------
Public Function Terminate() As Boolean
&apos;&apos;&apos; Terminate a running timer
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if successful, False if the timer is neither started nor suspended
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myTimer.Terminate()
Const cstThisSub = &quot;Timer.Terminate&quot;
Const cstSubArgs = &quot;&quot;
Check:
Terminate = False
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
If _TimerStatus = STATUSSTARTED Or _TimerStatus = STATUSSUSPENDED Then
If _TimerSTatus = STATUSSUSPENDED Then Continue()
_TimerStatus = STATUSSTOPPED
_EndTime = _Now()
Terminate = True
End If
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Timer.Terminate
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
Private Function _Now() As Double
&apos;&apos;&apos; Returns the current date and time
&apos;&apos;&apos; Uses the Calc NOW() function to get a higher precision than the usual Basic Now() function
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The actual time as a number
&apos;&apos;&apos; The integer part represents the date, the decimal part represents the time
_Now = SF_Session.ExecuteCalcFunction(&quot;NOW&quot;)
End Function &apos; ScriptForge.SF_Timer._Now
REM -----------------------------------------------------------------------------
Private Function _PropertyGet(Optional ByVal psProperty As String)
&apos;&apos;&apos; Return the named property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psProperty: the name of the property
Dim dDuration As Double &apos; Computed duration
Dim cstThisSub As String
Dim cstSubArgs As String
cstThisSub = &quot;Timer.get&quot; &amp; psProperty
cstSubArgs = &quot;&quot;
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Select Case UCase(psProperty)
Case UCase(&quot;Duration&quot;)
Select Case _TimerStatus
Case STATUSINACTIVE : dDuration = 0.0
Case STATUSSTARTED
dDuration = _Now() - _StartTime - _SuspendDuration
Case STATUSSUSPENDED
dDuration = _SuspendTime - _StartTime - _SuspendDuration
Case STATUSSTOPPED
dDuration = _EndTime - _StartTime - _SuspendDuration
End Select
_PropertyGet = Fix(dDuration * 1000 / DSECOND) / 1000
Case UCase(&quot;IsStarted&quot;)
_PropertyGet = CBool( _TimerStatus = STATUSSTARTED Or _TimerStatus = STATUSSUSPENDED )
Case UCase(&quot;IsSuspended&quot;)
_PropertyGet = CBool( _TimerStatus = STATUSSUSPENDED )
Case UCase(&quot;SuspendDuration&quot;)
Select Case _TimerStatus
Case STATUSINACTIVE : dDuration = 0.0
Case STATUSSTARTED, STATUSSTOPPED
dDuration = _SuspendDuration
Case STATUSSUSPENDED
dDuration = _Now() - _SuspendTime + _SuspendDuration
End Select
_PropertyGet = Fix(dDuration * 1000 / DSECOND) / 1000
Case UCase(&quot;TotalDuration&quot;)
Select Case _TimerStatus
Case STATUSINACTIVE : dDuration = 0.0
Case STATUSSTARTED, STATUSSUSPENDED
dDuration = _Now() - _StartTime
Case STATUSSTOPPED
dDuration = _EndTime - _StartTime
End Select
_PropertyGet = Fix(dDuration * 1000 / DSECOND) / 1000
End Select
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Timer._PropertyGet
REM -----------------------------------------------------------------------------
Private Function _Repr() As String
&apos;&apos;&apos; Convert the Timer instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Return:
&apos;&apos;&apos; &quot;[Timer] Duration:xxx.yyy
Const cstTimer = &quot;[Timer] Duration: &quot;
Const cstMaxLength = 50 &apos; Maximum length for items
_Repr = cstTimer &amp; Replace(SF_Utils._Repr(Duration), &quot;.&quot;, &quot;&quot;&quot;&quot;)
End Function &apos; ScriptForge.SF_Timer._Repr
REM ============================================ END OF SCRIPTFORGE.SF_TIMER
</script:module>

View File

@@ -0,0 +1,100 @@
<?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="_CodingConventions" 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 =======================================================================================================================
&apos;&apos;&apos;
&apos; Conventions used in the coding of the *ScriptForge* library
&apos; -----------------------------------------------------------
&apos;&apos;&apos;
&apos; Library and Modules
&apos; ===================
&apos; * Module names are all prefixed with &quot;SF_&quot;.
&apos; * The *Option Explicit* statement is mandatory in every module.
&apos; * The *Option Private Module* statement is recommended in internal modules.
&apos; * A standard header presenting the module/class is mandatory
&apos; * An end of file (eof) comment line is mandatory
&apos; * Every module lists the constants that are related to it and documented as return values, arguments, etc.
&apos; They are defined as *Global Const*.
&apos; The scope of global constants being limited to one single library, their invocation from user scripts shall be qualified.
&apos; * The Basic reserved words are *Proper-Cased*.
&apos;&apos;&apos;
&apos; Functions and Subroutines
&apos; =========================
&apos; * LibreOffice ignores the Private/Public attribute in Functions or Subs declarations.
&apos; Nevertheless the attribute must be present.
&apos; Rules to recognize their scope are:
&apos; * Public + name starts with a letter
&apos; The Sub/Function belongs to the official ScriptForge API.
&apos; As such it may be called from any user script.
&apos; * Public + name starts with an underscore &quot;_&quot;
&apos; The Sub/Function may be called only from within the ScriptForge library.
&apos; As such it MUST NOT be called from another library or from a user script,
&apos; as there is no guarantee about the arguments, the semantic or even the existence of that piece of code in a later release.
&apos; * Private - The Sub/Function name must start with an underscore &quot;_&quot;.
&apos; The Sub/Function may be called only from the module in which it is located.
&apos; * Functions and Subroutines belonging to the API (= &quot;standard&quot; functions/Subs) are defined in their module in alphabetical order.
&apos; For class modules, all the properties precede the methods which precede the events.
&apos; * Functions and Subroutines not belonging to the API are defined in their module in alphabetical order below the standard ones.
&apos; * The return value of a function is always declared explicitly.
&apos; * The parameters are always declared explicitly even if they&apos;re variants.
&apos; * The Function and Sub declarations start at the 1st column of the line.
&apos; * The End Function/Sub statement is followed by a comment reminding the name of the containing library.module and of the function or sub.
&apos; If the Function/Sub is declared for the first time or modified in a release &gt; initial public release, the actual release number is mentioned as well.
&apos;&apos;&apos;
&apos; Variable declarations
&apos; =====================
&apos; * Variable names use only alpha characters, the underscore and digits (no accented characters).
&apos; Exceptionally, names of private variables may be embraced with `[` and `]` if `Option Compatible` is present.
&apos; * The Global, Dim and Const statements always start in the first column of the line.
&apos; * The type (*Dim ... As ...*, *Function ... As ...*) is always declared explicitly, even if the type is Variant.
&apos; * Variables are *Proper-Cased*. They are always preceded by a lower-case letter indicating their type.
&apos; With next exception: variables i, j, k, l, m and n must be declared as integers or longs.
&apos; &gt; b Boolean
&apos; &gt; d Date
&apos; &gt; v Variant
&apos; &gt; o Object
&apos; &gt; i Integer
&apos; &gt; l Long
&apos; &gt; s String
&apos; Example:
&apos; Dim sValue As String
&apos; * Parameters are preceded by the letter *p* which itself precedes the single *typing letter*.
&apos; In official methods, to match their published documentation, the *p* and the *typing letter* may be omitted. Like in:
&apos; Private Function MyFunction(psValue As String) As Variant
&apos; Public Function MyOfficialFunction(Value As String) As Variant
&apos; * Global variables in the ScriptForge library are ALL preceded by an underscore &quot;_&quot; as NONE of them should be invoked from outside the library.
&apos; * Constant values with a local scope are *Proper-Cased* and preceded by the letters *cst*.
&apos; * Constants with a global scope are *UPPER-CASED*.
&apos; Example:
&apos; Global Const ACONSTANT = &quot;This is a global constant&quot;
&apos; Function MyFunction(pocControl As Object, piValue) As Variant
&apos; Dim iValue As Integer
&apos; Const cstMyConstant = 3
&apos;&apos;&apos;
&apos; Indentation
&apos; ===========
&apos; Code shall be indented with TAB characters.
&apos;&apos;&apos;
&apos; Goto/Gosub
&apos; ==========
&apos; The *GoSub* … *Return* statement is forbidden.
&apos; The *GoTo* statement is forbidden.
&apos; However *GoTo* is highly recommended for *error* and *exception* handling.
&apos;&apos;&apos;
&apos; Comments (english only)
&apos; ========
&apos; * Every public routine should be documented with a python-like &quot;docstring&quot;:
&apos; 1. Role of Sub/Function
&apos; 2. List of arguments, mandatory/optional, role
&apos; 3. Returned value(s) type and meaning
&apos; 4. Examples when useful
&apos; 5. Eventual specific exception codes
&apos; * The &quot;docstring&quot; comments shall be marked by a triple (single) quote character at the beginning of the line
&apos; * Meaningful variables shall be declared one per line. Comment on same line.
&apos; * Comments about a code block should be left indented.
&apos; If it concerns only the next line, no indent required (may also be put at the end of the line).
&apos;&apos;&apos;
</script:module>

View File

@@ -0,0 +1,221 @@
<?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="_ModuleModel" 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 ClassModule
&apos;Option Private Module
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; ModuleModel (aka SF_Model)
&apos;&apos;&apos; ===========
&apos;&apos;&apos; Illustration of how the ScriptForge modules are structured
&apos;&apos;&apos; Copy and paste this code in an empty Basic module to start a new service
&apos;&apos;&apos; Comment in, comment out, erase what you want, but at the end respect the overall structure
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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
&apos;&apos;&apos; FAKENEWSERROR
REM ============================================================= PRIVATE MEMBERS
Private [Me] As Object &apos; Should be initialized immediately after the New statement
&apos; Dim obj As Object : Set obj = New SF_Model
&apos; Set obj.[Me] = obj
Private [_Parent] As Object &apos; To keep trace of the instance having created a sub-instance
&apos; Set obj._Parent = [Me]
Private ObjectType As String &apos; Must be UNIQUE
REM ============================================================ MODULE CONSTANTS
Private Const SOMECONSTANT = 1
REM ====================================================== CONSTRUCTOR/DESTRUCTOR
REM -----------------------------------------------------------------------------
Private Sub Class_Initialize()
Set [Me] = Nothing
Set [_Parent] = Nothing
ObjectType = &quot;MODEL&quot;
End Sub &apos; ScriptForge.SF_Model Constructor
REM -----------------------------------------------------------------------------
Private Sub Class_Terminate()
Call Class_Initialize()
End Sub &apos; ScriptForge.SF_Model Destructor
REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
Call Class_Terminate()
Set Dispose = Nothing
End Function &apos; ScriptForge.SF_Model Explicit Destructor
REM ================================================================== PROPERTIES
REM -----------------------------------------------------------------------------
Property Get MyProperty() As Boolean
&apos;&apos;&apos; Returns True or False
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myModel.MyProperty
MyProperty = _PropertyGet(&quot;MyProperty&quot;)
End Property &apos; ScriptForge.SF_Model.MyProperty
REM ===================================================================== METHODS
REM -----------------------------------------------------------------------------
Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
&apos;&apos;&apos; Return the actual value of the given property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyName: the name of the property as a string
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The actual value of the property
&apos;&apos;&apos; If the property does not exist, returns Null
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; see the exceptions of the individual properties
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myModel.GetProperty(&quot;MyProperty&quot;)
Const cstThisSub = &quot;Model.GetProperty&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
GetProperty = Null
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
End If
Try:
GetProperty = _PropertyGet(PropertyName)
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Model.GetProperty
REM -----------------------------------------------------------------------------
Public Function Methods() As Variant
&apos;&apos;&apos; Return the list of public methods of the Model service as an array
Methods = Array( _
&quot;MyFunction&quot; _
, &quot;etc&quot; _
)
End Function &apos; ScriptForge.SF_Model.Methods
REM -----------------------------------------------------------------------------
Public Function MyFunction(Optional ByVal Arg1 As Variant _
, Optional ByVal Arg2 As Variant _
) As Variant
&apos;&apos;&apos; Fictive function that concatenates Arg1 Arg2 times
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Arg1 String Text
&apos;&apos;&apos; Arg2 Numeric Number of times (default = 2)
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The new string
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; FAKENEWSERROR
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; MyFunction(&quot;value1&quot;) returns &quot;value1value1&quot;
Dim sOutput As String &apos; Output buffer
Dim i As Integer
Const cstThisSub = &quot;Model.myFunction&quot;
Const cstSubArgs = &quot;Arg1, [Arg2=2]&quot;
&apos; _ErrorHandling returns False when, for debugging, the standard error handling is preferred
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
myFunction = &quot;&quot;
Check:
If IsMissing(Arg2) Then Arg2 = 2
&apos; _EnterFunction returns True when current method is invoked from a user script
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
&apos; Check Arg1 is a string and Arg2 is a number.
&apos; Validation rules for scalars and arrays are described in SF_Utils
If Not SF_Utils._Validate(Arg1, &quot;Arg1&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Arg2, &quot;Arg2&quot;, V_NUMERIC) Then GoTo Finally
&apos; Fatal error ?
If Arg2 &lt; 0 Then GoTo CatchFake
End If
Try:
sOutput = &quot;&quot;
For i = 0 To Arg2
sOutput = sOutput &amp; Arg1
Next i
myFunction = sOutput
Finally:
&apos; _ExitFunction manages internal (On Local) errors
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchFake:
SF_Exception.RaiseFatal(&quot;FAKENEWSERROR&quot;, cstThisSub)
GoTo Finally
End Function &apos; ScriptForge.SF_Model.myFunction
REM -----------------------------------------------------------------------------
Public Function Properties() As Variant
&apos;&apos;&apos; Return the list or properties of the Model class as an array
Properties = Array( _
&quot;MyProperty&quot; _
, &quot;etc&quot; _
)
End Function &apos; ScriptForge.SF_Model.Properties
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
Private Function _PropertyGet(Optional ByVal psProperty As String) As Variant
&apos;&apos;&apos; Return the value of the named property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psProperty: the name of the property
Dim cstThisSub As String
Const cstSubArgs = &quot;&quot;
cstThisSub = &quot;SF_Model.get&quot; &amp; psProperty
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Select Case psProperty
Case &quot;MyProperty&quot;
_PropertyGet = TBD
Case Else
_PropertyGet = Null
End Select
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Model._PropertyGet
REM -----------------------------------------------------------------------------
Private Function _Repr() As String
&apos;&apos;&apos; Convert the Model instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Return:
&apos;&apos;&apos; &quot;[MODEL]: A readable string&quot;
_Repr = &quot;[MODEL]: A readable string&quot;
End Function &apos; ScriptForge.SF_Model._Repr
REM ============================================ END OF SCRIPTFORGE.SF_MODEL
</script:module>

View File

@@ -0,0 +1,25 @@
<?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="__License" script:language="StarBasic" script:moduleType="normal">
&apos;&apos;&apos; Copyright 2019-2022 Jean-Pierre LEDURE, Rafael LIMA, Alain ROMEDENNE
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 =======================================================================================================================
&apos;&apos;&apos; ScriptForge is distributed in the hope that it will be useful,
&apos;&apos;&apos; but WITHOUT ANY WARRANTY; without even the implied warranty of
&apos;&apos;&apos; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
&apos;&apos;&apos; ScriptForge is free software; you can redistribute it and/or modify it under the terms of either (at your option):
&apos;&apos;&apos; 1) The Mozilla Public License, v. 2.0. If a copy of the MPL was not
&apos;&apos;&apos; distributed with this file, you can obtain one at http://mozilla.org/MPL/2.0/ .
&apos;&apos;&apos; 2) The GNU Lesser General Public License as published by
&apos;&apos;&apos; the Free Software Foundation, either version 3 of the License, or
&apos;&apos;&apos; (at your option) any later version. If a copy of the LGPL was not
&apos;&apos;&apos; distributed with this file, see http://www.gnu.org/licenses/ .
</script:module>

View File

@@ -0,0 +1,6 @@
<?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="dlgConsole"/>
<library:element library:name="dlgProgress"/>
</library:library>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="dlgConsole" dlg:left="114" dlg:top="32" dlg:width="321" dlg:height="239" dlg:closeable="true" dlg:moveable="true" dlg:title="ScriptForge">
<dlg:styles>
<dlg:style dlg:style-id="0" dlg:font-name="Courier New" dlg:font-stylename="Regular" dlg:font-family="modern"/>
</dlg:styles>
<dlg:bulletinboard>
<dlg:textfield dlg:style-id="0" dlg:id="ConsoleLines" dlg:tab-index="0" dlg:left="4" dlg:top="2" dlg:width="312" dlg:height="225" dlg:hscroll="true" dlg:vscroll="true" dlg:multiline="true" dlg:readonly="true"/>
<dlg:button dlg:id="CloseNonModalButton" dlg:tab-index="2" dlg:left="265" dlg:top="228" dlg:width="50" dlg:height="10" dlg:default="true" dlg:image-src="private:graphicrepository/cmd/sc_cancel.png">
<script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:ScriptForge.SF_Exception._CloseConsole?language=Basic&amp;location=application" script:language="Script"/>
</dlg:button>
<dlg:button dlg:id="CloseModalButton" dlg:tab-index="1" dlg:left="265" dlg:top="228" dlg:width="50" dlg:height="10" dlg:default="true" dlg:button-type="ok" dlg:image-src="private:graphicrepository/cmd/sc_cancel.png"/>
</dlg:bulletinboard>
</dlg:window>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="dlgProgress" dlg:left="180" dlg:top="90" dlg:width="275" dlg:height="37" dlg:closeable="true" dlg:moveable="true">
<dlg:bulletinboard>
<dlg:text dlg:id="ProgressText" dlg:tab-index="1" dlg:left="16" dlg:top="7" dlg:width="245" dlg:height="8" dlg:value="ProgressText" dlg:tabstop="true"/>
<dlg:progressmeter dlg:id="ProgressBar" dlg:tab-index="0" dlg:left="16" dlg:top="18" dlg:width="190" dlg:height="10" dlg:value="50"/>
<dlg:button dlg:id="CloseButton" dlg:tab-index="2" dlg:left="210" dlg:top="18" dlg:width="50" dlg:height="10" dlg:image-src="private:graphicrepository/cmd/sc_cancel.png">
<script:event script:event-name="on-performaction" script:macro-name="vnd.sun.star.script:ScriptForge.SF_UI._CloseProgressBar?language=Basic&amp;location=application" script:language="Script"/>
</dlg:button>
</dlg:bulletinboard>
</dlg:window>

View File

@@ -0,0 +1,992 @@
#
# This pristine POT file has been generated by LibreOffice/ScriptForge
# Full documentation is available on https://help.libreoffice.org/
#
# *********************************************************************
# *** The ScriptForge library and its associated libraries ***
# *** are part of the LibreOffice project. ***
# *********************************************************************
#
# ScriptForge Release 7.4
# -----------------------
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: https://bugs.libreoffice.org/enter_bug.cgi?product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n"
"POT-Creation-Date: 2022-10-12 15:07:35\n"
"PO-Revision-Date: YYYY-MM-DD HH:MM:SS\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
"Language: en_US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: LibreOffice - ScriptForge\n"
"X-Accelerator-Marker: ~\n"
#. Title in error message box
#. %1: an error number
#, kde-format
msgctxt "ERRORNUMBER"
msgid "Error %1"
msgstr ""
#. Error message box
#. %1: a line number
#, kde-format
msgctxt "ERRORLOCATION"
msgid "Location : %1"
msgstr ""
#. Logfile record
#, kde-format
msgctxt "LONGERRORDESC"
msgid "Error %1 - Location = %2 - Description = %3"
msgstr ""
#. Any blocking error message
msgctxt "STOPEXECUTION"
msgid "THE EXECUTION IS CANCELLED."
msgstr ""
#. Any blocking error message
#. %1: a method name
#, kde-format
msgctxt "NEEDMOREHELP"
msgid "Do you want to receive more information about the '%1' method ?"
msgstr ""
#. SF_Exception.RaiseAbort error message
msgctxt "INTERNALERROR"
msgid ""
"The ScriptForge library has crashed. The reason is unknown.\n"
"Maybe a bug that could be reported on\n"
" https://bugs.documentfoundation.org/\n"
"\n"
"More details : \n"
"\n"
""
msgstr ""
#. SF_Utils._Validate error message
#. %1: probably ScriptForge
#. %2: service or module name
#. %3: property or method name where the error occurred
#, kde-format
msgctxt "VALIDATESOURCE"
msgid ""
"Library : %1\n"
"Service : %2\n"
"Method : %3"
msgstr ""
#. SF_Utils._Validate error message
#. %1: list of arguments of the method
#, kde-format
msgctxt "VALIDATEARGS"
msgid "Arguments: %1"
msgstr ""
#. SF_Utils._Validate error message
#. %1: Wrong argument name
#, kde-format
msgctxt "VALIDATEERROR"
msgid "A serious error has been detected in your code on argument : « %1 »."
msgstr ""
#. SF_Utils.Validate error message
msgctxt "VALIDATIONRULES"
msgid " Validation rules :"
msgstr ""
#. SF_Utils._Validate error message
#. %1: Wrong argument name
#. %2: Comma separated list of allowed types
#, kde-format
msgctxt "VALIDATETYPES"
msgid " « %1 » must have next type (or one of next types) : %2"
msgstr ""
#. SF_Utils._Validate error message
#. %1: Wrong argument name
#. %2: Comma separated list of allowed values
#, kde-format
msgctxt "VALIDATEVALUES"
msgid " « %1 » must contain one of next values : %2"
msgstr ""
#. SF_Utils._Validate error message
#. %1: Wrong argument name
#. %2: A regular expression
#, kde-format
msgctxt "VALIDATEREGEX"
msgid " « %1 » must match next regular expression : %2"
msgstr ""
#. SF_Utils._Validate error message
#. %1: Wrong argument name
#. %2: The name of a Basic class
#, kde-format
msgctxt "VALIDATECLASS"
msgid " « %1 » must be a Basic object of class : %2"
msgstr ""
#. SF_Utils._Validate error message
#. %1: Wrong argument name
#. %2: The value of the argument as a string
#, kde-format
msgctxt "VALIDATEACTUAL"
msgid "The actual value of « %1 » is : '%2'"
msgstr ""
#. SF_Utils._Validate error message
#. %1: Wrong argument name
#, kde-format
msgctxt "VALIDATEMISSING"
msgid "The « %1 » argument is mandatory, yet it is missing."
msgstr ""
#. SF_Utils._ValidateArray error message
#. %1: Wrong argument name
#, kde-format
msgctxt "VALIDATEARRAY"
msgid " « %1 » must be an array."
msgstr ""
#. SF_Utils._ValidateArray error message
#. %1: Wrong argument name
#. %2: Number of dimensions of the array
#, kde-format
msgctxt "VALIDATEDIMS"
msgid " « %1 » must have exactly %2 dimension(s)."
msgstr ""
#. SF_Utils._ValidateArray error message
#. %1: Wrong argument name
#. %2: Either one single type or 'String, Date, Numeric'
#, kde-format
msgctxt "VALIDATEALLTYPES"
msgid " « %1 » must have all elements of the same type : %2"
msgstr ""
#. SF_Utils._ValidateArray error message
#. %1: Wrong argument name
#. NULL and EMPTY should not be translated
#, kde-format
msgctxt "VALIDATENOTNULL"
msgid " « %1 » must not contain any NULL or EMPTY elements."
msgstr ""
#. SF_Utils._ValidateFile error message
#. %1: Wrong argument name
#. 'String' should not be translated
#, kde-format
msgctxt "VALIDATEFILE"
msgid " « %1 » must be of type String."
msgstr ""
#. SF_Utils._ValidateFile error message
#. %1: Wrong argument name
#, kde-format
msgctxt "VALIDATEFILESYS"
msgid ""
" « %1 » must be a valid file or folder name expressed in the "
"operating system native notation."
msgstr ""
#. SF_Utils._ValidateFile error message
#. %1: Wrong argument name
#. 'URL' should not be translated
#, kde-format
msgctxt "VALIDATEFILEURL"
msgid ""
" « %1 » must be a valid file or folder name expressed in the "
"portable URL notation."
msgstr ""
#. SF_Utils._ValidateFile error message
#. %1: Wrong argument name
#, kde-format
msgctxt "VALIDATEFILEANY"
msgid " « %1 » must be a valid file or folder name."
msgstr ""
#. SF_Utils._ValidateFile error message
#. %1: Wrong argument name
#. '(?, *)' is to be left as is
#, kde-format
msgctxt "VALIDATEWILDCARD"
msgid ""
" « %1 » may contain one or more wildcard characters (?, *) in "
"its last path component only."
msgstr ""
#. SF_Array.RangeInit error message
#. %1, %2, %3: Numeric values
#. 'From', 'UpTo', 'ByStep' should not be translated
#, kde-format
msgctxt "ARRAYSEQUENCE"
msgid ""
"The respective values of 'From', 'UpTo' and 'ByStep' are incoherent.\n"
"\n"
" « From » = %1\n"
" « UpTo » = %2\n"
" « ByStep » = %3"
msgstr ""
#. SF_Array.AppendColumn (...) error message
#. %1: 'Column' or 'Row' of a matrix
#. %2, %3: array contents
#. 'Array_2D' should not be translated
#, kde-format
msgctxt "ARRAYINSERT"
msgid ""
"The array and the vector to insert have incompatible sizes.\n"
"\n"
" « Array_2D » = %2\n"
" « %1 » = %3"
msgstr ""
#. SF_Array.ExtractColumn (...) error message
#. %1: 'Column' or 'Row' of a matrix
#. %2, %3: array contents
#. 'Array_2D' should not be translated
#, kde-format
msgctxt "ARRAYINDEX1"
msgid ""
"The given index does not fit within the bounds of the array.\n"
"\n"
" « Array_2D » = %2\n"
" « %1 » = %3"
msgstr ""
#. SF_Array.ExtractColumn (...) error message
#. %1: 'Column' or 'Row' of a matrix
#. %2, %3: array contents
#. 'Array_1D', 'From' and 'UpTo' should not be translated
#, kde-format
msgctxt "ARRAYINDEX2"
msgid ""
"The given slice limits do not fit within the bounds of the array.\n"
"\n"
" « Array_1D » = %1\n"
" « From » = %2\n"
" « UpTo » = %3"
msgstr ""
#. SF_Array.ImportFromCSVFile error message
#. %1: a file name
#. %2: numeric
#. %3: a long string
#, kde-format
msgctxt "CSVPARSING"
msgid ""
"The given file could not be parsed as a valid CSV file.\n"
"\n"
" « File name » = %1\n"
" Line number = %2\n"
" Content = %3"
msgstr ""
#. SF_Dictionary Add/ReplaceKey error message
#. %1: An identifier%2: a (potentially long) string
#, kde-format
msgctxt "DUPLICATEKEY"
msgid ""
"The insertion of a new key into a dictionary failed because the key "
"already exists.\n"
"Note that the comparison between keys is NOT case-sensitive.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_Dictionary Remove/ReplaceKey/ReplaceItem error message
#. %1: An identifier%2: a (potentially long) string
#, kde-format
msgctxt "UNKNOWNKEY"
msgid ""
"The requested key does not exist in the dictionary.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_Dictionary Add/ReplaceKey error message
#.
msgctxt "INVALIDKEY"
msgid ""
"The insertion or the update of an entry into a dictionary failed "
"because the given key contains only spaces."
msgstr ""
#. SF_FileSystem copy/move/delete error message
#. %1: An identifier
#. %2: A file name
#, kde-format
msgctxt "UNKNOWNFILE"
msgid ""
"The given file could not be found on your system.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_FileSystem copy/move/delete error message
#. %1: An identifier
#. %2: A folder name
#, kde-format
msgctxt "UNKNOWNFOLDER"
msgid ""
"The given folder could not be found on your system.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_FileSystem copy/move/delete error message
#. %1: An identifier
#. %2: A file name
#, kde-format
msgctxt "NOTAFILE"
msgid ""
"« %1 » contains the name of an existing folder, not that of a file.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_FileSystem copy/move/delete error message
#. %1: An identifier
#. %2: A folder name
#, kde-format
msgctxt "NOTAFOLDER"
msgid ""
"« %1 » contains the name of an existing file, not that of a folder.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_FileSystem copy/move/... error message
#. %1: An identifier
#. %2: A file name
#, kde-format
msgctxt "OVERWRITE"
msgid ""
"You tried to create a new file which already exists. Overwriting it "
"has been rejected.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_FileSystem copy/move/delete error message
#. %1: An identifier
#. %2: A file name
#, kde-format
msgctxt "READONLY"
msgid ""
"Copying or moving a file to a destination which has its read-only "
"attribute set, or deleting such a file or folder is forbidden.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_FileSystem copy/move/delete error message
#. %1: An identifier
#. %2: A file or folder name with wildcards
#, kde-format
msgctxt "NOFILEMATCH"
msgid ""
"When « %1 » contains wildcards. at least one file or folder must "
"match the given filter. Otherwise the operation is rejected.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_FileSystem CreateFolder error message
#. %1: An identifier
#. %2: A file or folder name
#, kde-format
msgctxt "FOLDERCREATION"
msgid ""
"« %1 » contains the name of an existing file or an existing folder. "
"The operation is rejected.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_Services.CreateScriptService error message
#. %1: An identifier
#. %2: A string
#. %3: A Basic library name
#. %4: A service (1 word) name
#, kde-format
msgctxt "UNKNOWNSERVICE"
msgid ""
"No service named '%4' has been registered for the library '%3'.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_Services.CreateScriptService error message
#. %1: An identifier
#. %2: A string
#. %3: A Basic library name
#, kde-format
msgctxt "SERVICESNOTLOADED"
msgid ""
"The library '%3' and its services could not been loaded.\n"
"The reason is unknown.\n"
"However, checking the '%3.SF_Services.RegisterScriptServices()' "
"function and its return value can be a good starting point.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_Session.ExecuteCalcFunction error message
#. 'Calc' should not be translated
#, kde-format
msgctxt "CALCFUNC"
msgid ""
"The Calc '%1' function encountered an error. Either the given "
"function does not exist or its arguments are invalid."
msgstr ""
#. SF_Session._GetScript error message
#. %1: 'Basic' or 'Python'
#. %2: An identifier
#. %3: A string
#. %4: An identifier
#. %5: A string
#, kde-format
msgctxt "NOSCRIPT"
msgid ""
"The requested %1 script could not be located in the given libraries "
"and modules.\n"
"« %2 » = %3\n"
"« %4 » = %5"
msgstr ""
#. SF_Session.ExecuteBasicScript error message
#. %1: An identifier
#. %2: A string
#. %3: A (long) string
#, kde-format
msgctxt "SCRIPTEXEC"
msgid ""
"An exception occurred during the execution of the Basic script.\n"
"Cause: %3\n"
"« %1 » = %2"
msgstr ""
#. SF_Session.SendMail error message
#. %1 = a mail address
#, kde-format
msgctxt "WRONGEMAIL"
msgid ""
"One of the email addresses has been found invalid.\n"
"Invalid mail = « %1 »"
msgstr ""
#. SF_Session.SendMail error message
msgctxt "SENDMAIL"
msgid ""
"The message could not be sent due to a system error.\n"
"A possible cause is that LibreOffice could not find any mail client."
msgstr ""
#. SF_TextStream._IsFileOpen error message
#. %1: A file name
#, kde-format
msgctxt "FILENOTOPEN"
msgid ""
"The requested file operation could not be executed because the file "
"was closed previously.\n"
"\n"
"File name = '%1'"
msgstr ""
#. SF_TextStream._IsFileOpen error message
#. %1: A file name
#. %2: READ, WRITE or APPEND
#, kde-format
msgctxt "FILEOPENMODE"
msgid ""
"The requested file operation could not be executed because it is "
"incompatible with the mode in which the file was opened.\n"
"\n"
"File name = '%1'\n"
"Open mode = %2"
msgstr ""
#. SF_TextStream.ReadLine/ReadAll/SkipLine error message
#. %1: A file name
#, kde-format
msgctxt "ENDOFFILE"
msgid ""
"The requested file read operation could not be completed because an "
"unexpected end-of-file was encountered.\n"
"\n"
"File name = '%1'"
msgstr ""
#. SF_UI.GetDocument error message
#. %1: An identifier
#. %2: A string
#, kde-format
msgctxt "DOCUMENT"
msgid ""
"The requested document could not be found.\n"
"\n"
"%1 = '%2'"
msgstr ""
#. SF_UI.GetDocument error message
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A string
#, kde-format
msgctxt "DOCUMENTCREATION"
msgid ""
"The creation of a new document failed.\n"
"Something must be wrong with some arguments.\n"
"\n"
"Either the document type is unknown, or no template file was given,\n"
"or the given template file was not found on your system.\n"
"\n"
"%1 = '%2'\n"
"%3 = '%4'"
msgstr ""
#. SF_UI.OpenDocument error message
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A string
#. %5: An identifier
#. %6: A string
#, kde-format
msgctxt "DOCUMENTOPEN"
msgid ""
"The opening of the document failed.\n"
"Something must be wrong with some arguments.\n"
"\n"
"Either the file does not exist, or the password is wrong, or the "
"given filter is invalid.\n"
"\n"
"%1 = '%2'\n"
"%3 = '%4'\n"
"%5 = '%6'"
msgstr ""
#. SF_UI.OpenDocument error message
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A string
#, kde-format
msgctxt "BASEDOCUMENTOPEN"
msgid ""
"The opening of the Base document failed.\n"
"Something must be wrong with some arguments.\n"
"\n"
"Either the file does not exist, or the file is not registered under "
"the given name.\n"
"\n"
"%1 = '%2'\n"
"%3 = '%4'"
msgstr ""
#. SF_Document._IsStillAlive error message
#. %1: A file name
#, kde-format
msgctxt "DOCUMENTDEAD"
msgid ""
"The requested action could not be executed because the document was "
"closed inadvertently.\n"
"\n"
"The concerned document is '%1'"
msgstr ""
#. SF_Document.SaveAs error message
#. %1: An identifier
#. %2: A file name
#.
#, kde-format
msgctxt "DOCUMENTSAVE"
msgid ""
"The document could not be saved.\n"
"Either the document has been opened read-only, or the destination "
"file has a read-only attribute set, or the file where to save to is "
"undefined.\n"
"\n"
"%1 = '%2'"
msgstr ""
#. SF_Document.SaveAs error message
#. %1: An identifier
#. %2: A file name
#. %3: An identifier
#. %4: True or False
#. %5: An identifier
#. %6: A string
#, kde-format
msgctxt "DOCUMENTSAVEAS"
msgid ""
"The document could not be saved.\n"
"Either the document must not be overwritten, or the destination file "
"has a read-only attribute set, or the given filter is invalid.\n"
"\n"
"%1 = '%2'\n"
"%3 = %4\n"
"%5 = '%6'"
msgstr ""
#. SF_Document any update
#. %1: An identifier
#. %2: A file name
#, kde-format
msgctxt "DOCUMENTREADONLY"
msgid ""
"You tried to edit a document which is not modifiable. The document "
"has not been changed.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_Base GetDatabase
#. %1: An identifier
#. %2: A user name
#. %3: An identifier
#. %4: A password
#. %5: A file name
#, kde-format
msgctxt "DBCONNECT"
msgid ""
"The database related to the actual Base document could not be "
"retrieved.\n"
"Check the connection/login parameters.\n"
"\n"
"« %1 » = '%2'\n"
"« %3 » = '%4'\n"
"« Document » = %5"
msgstr ""
#. SF_Calc _ParseAddress (sheet)
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A file name
#, kde-format
msgctxt "CALCADDRESS1"
msgid ""
"The given address does not correspond with a valid sheet name.\n"
"\n"
"« %1 » = %2\n"
"« %3 » = %4"
msgstr ""
#. SF_Calc _ParseAddress (range)
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A file name
#, kde-format
msgctxt "CALCADDRESS2"
msgid ""
"The given address does not correspond with a valid range of cells.\n"
"\n"
"« %1 » = %2\n"
"« %3 » = %4"
msgstr ""
#. SF_Calc InsertSheet
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A file name
#, kde-format
msgctxt "DUPLICATESHEET"
msgid ""
"There exists already in the document a sheet with the same name.\n"
"\n"
"« %1 » = %2\n"
"« %3 » = %4"
msgstr ""
#. SF_Calc Offset
#. %1: An identifier
#. %2: A Calc reference
#. %3: An identifier
#. %4: A number
#. %5: An identifier
#. %6: A number
#. %7: An identifier
#. %8: A number
#. %9: An identifier
#. %10: A number
#. %11: An identifier
#. %12: A file name
#, kde-format
msgctxt "OFFSETADDRESS"
msgid ""
"The computed range falls beyond the sheet boundaries or is "
"meaningless.\n"
"\n"
"« %1 » = %2\n"
"« %3 » = %4\n"
"« %5 » = %6\n"
"« %7 » = %8\n"
"« %9 » = %10\n"
"« %11 » = %12"
msgstr ""
#. SF_Calc CreateChart
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A string
#. %5: An identifier
#. %6: A file name
#, kde-format
msgctxt "DUPLICATECHART"
msgid ""
"A chart with the same name exists already in the sheet.\n"
"\n"
"« %1 » = %2\n"
"« %3 » = %4\n"
"« %5 » = %6\n"
""
msgstr ""
#. SF_Calc.ExportRangeToFile error message
#. %1: An identifier
#. %2: A file name
#. %3: An identifier
#. %4: True or False
#.
#, kde-format
msgctxt "RANGEEXPORT"
msgid ""
"The given range could not be exported.\n"
"Either the destination file must not be overwritten, or it has a "
"read-only attribute set.\n"
"\n"
"%1 = '%2'\n"
"%3 = %4"
msgstr ""
#. SF_Chart.ExportToFile error message
#. %1: An identifier
#. %2: A file name
#. %3: An identifier
#. %4: True or False
#.
#, kde-format
msgctxt "CHARTEXPORT"
msgid ""
"The chart could not be exported.\n"
"Either the destination file must not be overwritten, or it has a "
"read-only attribute set.\n"
"\n"
"%1 = '%2'\n"
"%3 = %4"
msgstr ""
#. SF_Dialog._IsStillAlive error message
#. %1: An identifier%2: A file name
#, kde-format
msgctxt "FORMDEAD"
msgid ""
"The requested action could not be executed because the form is not "
"open or the document was closed inadvertently.\n"
"\n"
"The concerned form is '%1' in document '%2'."
msgstr ""
#. SF_Form determination
#. %1: A number
#. %2: A sheet name
#. %3: A file name
#, kde-format
msgctxt "CALCFORMNOTFOUND"
msgid ""
"The requested form could not be found in the Calc sheet. The given "
"index is off-limits.\n"
"\n"
"The concerned Calc document is '%3'.\n"
"\n"
"The name of the sheet = '%2'\n"
"The index = %1."
msgstr ""
#. SF_Form determination
#. %1: A number
#. %2: A file name
#, kde-format
msgctxt "WRITERFORMNOTFOUND"
msgid ""
"The requested form could not be found in the Writer document. The "
"given index is off-limits.\n"
"\n"
"The concerned Writer document is '%2'.\n"
"\n"
"The index = %1."
msgstr ""
#. SF_Form determination
#. %1: A number
#. %2: A string
#. %3: A file name
#, kde-format
msgctxt "BASEFORMNOTFOUND"
msgid ""
"The requested form could not be found in the form document '%2'. The "
"given index is off-limits.\n"
"\n"
"The concerned Base document is '%3'.\n"
"\n"
"The index = %1."
msgstr ""
#. SF_Form determination
#. %1: A form name
#. %2: A form name
#, kde-format
msgctxt "SUBFORMNOTFOUND"
msgid ""
"The requested subform could not be found below the given main form.\n"
"\n"
"The main form = '%2'.\n"
"The subform = '%1'."
msgstr ""
#. SF_FormControl property setting
#. %1: An identifier
#. %2: An identifier
#. %3: A string
#. %4: An identifier
#, kde-format
msgctxt "FORMCONTROLTYPE"
msgid ""
"The control '%1' in form '%2' is of type '%3'.\n"
"The property or method '%4' is not applicable on that type of form "
"controls."
msgstr ""
#. SF_Dialog creation
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A file name
#. %5: An identifier
#. %6: A string
#. %7: An identifier
#. %8: A string
#, kde-format
msgctxt "DIALOGNOTFOUND"
msgid ""
"The requested dialog could not be located in the given container or "
"library.\n"
"« %1 » = %2\n"
"« %3 » = %4\n"
"« %5 » = %6\n"
"« %7 » = %8"
msgstr ""
#. SF_Dialog._IsStillAlive error message
#. %1: An identifier
#, kde-format
msgctxt "DIALOGDEAD"
msgid ""
"The requested action could not be executed because the dialog was "
"closed inadvertently.\n"
"\n"
"The concerned dialog is '%1'."
msgstr ""
#. SF_DialogControl property setting
#. %1: An identifier
#. %2: An identifier
#. %3: A string
#. %4: An identifier
#, kde-format
msgctxt "CONTROLTYPE"
msgid ""
"The control '%1' in dialog '%2' is of type '%3'.\n"
"The property or method '%4' is not applicable on that type of dialog "
"controls."
msgstr ""
#. SF_DialogControl add line in textbox
#. %1: An identifier
#. %2: An identifier
#, kde-format
msgctxt "TEXTFIELD"
msgid ""
"The control '%1' in dialog '%2' is not a multiline text field.\n"
"The requested method could not be executed."
msgstr ""
#. SF_Dialog Page Manager setting
#. %1: An identifier
#. %2: A list of names separated by commas
#. %3: An identifier
#. %4: A list of names separated by commas
#. %5: An identifier
#. %6: A list of names separated by commas
#, kde-format
msgctxt "PAGEMANAGER"
msgid ""
"The Page Manager could not be setup due to inconsistent arguments.\n"
"\n"
" %1 : « %2 »\n"
" %3 : « %4 »\n"
" %5 : « %6 »"
msgstr ""
#. SF_Database when running update SQL statement
#. %1: The concerned method
#, kde-format
msgctxt "DBREADONLY"
msgid ""
"The database has been opened in read-only mode.\n"
"The '%1' method must not be executed in this context."
msgstr ""
#. SF_Database can't interpret SQL statement
#. %1: The statement
#, kde-format
msgctxt "SQLSYNTAX"
msgid ""
"An SQL statement could not be interpreted or executed by the "
"database system.\n"
"Check its syntax, table and/or field names, ...\n"
"\n"
"SQL Statement : « %1 »"
msgstr ""
#. SF_Exception.PythonShell error messageAPSO: to leave unchanged
msgctxt "PYTHONSHELL"
msgid ""
"The APSO extension could not be located in your LibreOffice "
"installation."
msgstr ""
#. SFUnitTest could not locate the library gven as argument
#. %1: The name of the library
#, kde-format
msgctxt "UNITTESTLIBRARY"
msgid ""
"The requested library could not be located.\n"
"The UnitTest service has not been initialized.\n"
"\n"
"Library name : « %1 »"
msgstr ""
#. SFUnitTest finds a RunTest() call in a inappropriate location
#. %1: The name of a method
#, kde-format
msgctxt "UNITTESTMETHOD"
msgid ""
"The method '%1' is unexpected in the current context.\n"
"The UnitTest service cannot proceed further with the on-going test."
msgstr ""

View File

@@ -0,0 +1,992 @@
#
# This pristine POT file has been generated by LibreOffice/ScriptForge
# Full documentation is available on https://help.libreoffice.org/
#
# *********************************************************************
# *** The ScriptForge library and its associated libraries ***
# *** are part of the LibreOffice project. ***
# *********************************************************************
#
# ScriptForge Release 7.4
# -----------------------
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: https://bugs.libreoffice.org/enter_bug.cgi?product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n"
"POT-Creation-Date: 2022-10-12 15:07:35\n"
"PO-Revision-Date: YYYY-MM-DD HH:MM:SS\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
"Language: en_US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: LibreOffice - ScriptForge\n"
"X-Accelerator-Marker: ~\n"
#. Title in error message box
#. %1: an error number
#, kde-format
msgctxt "ERRORNUMBER"
msgid "Error %1"
msgstr ""
#. Error message box
#. %1: a line number
#, kde-format
msgctxt "ERRORLOCATION"
msgid "Location : %1"
msgstr ""
#. Logfile record
#, kde-format
msgctxt "LONGERRORDESC"
msgid "Error %1 - Location = %2 - Description = %3"
msgstr ""
#. Any blocking error message
msgctxt "STOPEXECUTION"
msgid "THE EXECUTION IS CANCELLED."
msgstr ""
#. Any blocking error message
#. %1: a method name
#, kde-format
msgctxt "NEEDMOREHELP"
msgid "Do you want to receive more information about the '%1' method ?"
msgstr ""
#. SF_Exception.RaiseAbort error message
msgctxt "INTERNALERROR"
msgid ""
"The ScriptForge library has crashed. The reason is unknown.\n"
"Maybe a bug that could be reported on\n"
" https://bugs.documentfoundation.org/\n"
"\n"
"More details : \n"
"\n"
""
msgstr ""
#. SF_Utils._Validate error message
#. %1: probably ScriptForge
#. %2: service or module name
#. %3: property or method name where the error occurred
#, kde-format
msgctxt "VALIDATESOURCE"
msgid ""
"Library : %1\n"
"Service : %2\n"
"Method : %3"
msgstr ""
#. SF_Utils._Validate error message
#. %1: list of arguments of the method
#, kde-format
msgctxt "VALIDATEARGS"
msgid "Arguments: %1"
msgstr ""
#. SF_Utils._Validate error message
#. %1: Wrong argument name
#, kde-format
msgctxt "VALIDATEERROR"
msgid "A serious error has been detected in your code on argument : « %1 »."
msgstr ""
#. SF_Utils.Validate error message
msgctxt "VALIDATIONRULES"
msgid " Validation rules :"
msgstr ""
#. SF_Utils._Validate error message
#. %1: Wrong argument name
#. %2: Comma separated list of allowed types
#, kde-format
msgctxt "VALIDATETYPES"
msgid " « %1 » must have next type (or one of next types) : %2"
msgstr ""
#. SF_Utils._Validate error message
#. %1: Wrong argument name
#. %2: Comma separated list of allowed values
#, kde-format
msgctxt "VALIDATEVALUES"
msgid " « %1 » must contain one of next values : %2"
msgstr ""
#. SF_Utils._Validate error message
#. %1: Wrong argument name
#. %2: A regular expression
#, kde-format
msgctxt "VALIDATEREGEX"
msgid " « %1 » must match next regular expression : %2"
msgstr ""
#. SF_Utils._Validate error message
#. %1: Wrong argument name
#. %2: The name of a Basic class
#, kde-format
msgctxt "VALIDATECLASS"
msgid " « %1 » must be a Basic object of class : %2"
msgstr ""
#. SF_Utils._Validate error message
#. %1: Wrong argument name
#. %2: The value of the argument as a string
#, kde-format
msgctxt "VALIDATEACTUAL"
msgid "The actual value of « %1 » is : '%2'"
msgstr ""
#. SF_Utils._Validate error message
#. %1: Wrong argument name
#, kde-format
msgctxt "VALIDATEMISSING"
msgid "The « %1 » argument is mandatory, yet it is missing."
msgstr ""
#. SF_Utils._ValidateArray error message
#. %1: Wrong argument name
#, kde-format
msgctxt "VALIDATEARRAY"
msgid " « %1 » must be an array."
msgstr ""
#. SF_Utils._ValidateArray error message
#. %1: Wrong argument name
#. %2: Number of dimensions of the array
#, kde-format
msgctxt "VALIDATEDIMS"
msgid " « %1 » must have exactly %2 dimension(s)."
msgstr ""
#. SF_Utils._ValidateArray error message
#. %1: Wrong argument name
#. %2: Either one single type or 'String, Date, Numeric'
#, kde-format
msgctxt "VALIDATEALLTYPES"
msgid " « %1 » must have all elements of the same type : %2"
msgstr ""
#. SF_Utils._ValidateArray error message
#. %1: Wrong argument name
#. NULL and EMPTY should not be translated
#, kde-format
msgctxt "VALIDATENOTNULL"
msgid " « %1 » must not contain any NULL or EMPTY elements."
msgstr ""
#. SF_Utils._ValidateFile error message
#. %1: Wrong argument name
#. 'String' should not be translated
#, kde-format
msgctxt "VALIDATEFILE"
msgid " « %1 » must be of type String."
msgstr ""
#. SF_Utils._ValidateFile error message
#. %1: Wrong argument name
#, kde-format
msgctxt "VALIDATEFILESYS"
msgid ""
" « %1 » must be a valid file or folder name expressed in the "
"operating system native notation."
msgstr ""
#. SF_Utils._ValidateFile error message
#. %1: Wrong argument name
#. 'URL' should not be translated
#, kde-format
msgctxt "VALIDATEFILEURL"
msgid ""
" « %1 » must be a valid file or folder name expressed in the "
"portable URL notation."
msgstr ""
#. SF_Utils._ValidateFile error message
#. %1: Wrong argument name
#, kde-format
msgctxt "VALIDATEFILEANY"
msgid " « %1 » must be a valid file or folder name."
msgstr ""
#. SF_Utils._ValidateFile error message
#. %1: Wrong argument name
#. '(?, *)' is to be left as is
#, kde-format
msgctxt "VALIDATEWILDCARD"
msgid ""
" « %1 » may contain one or more wildcard characters (?, *) in "
"its last path component only."
msgstr ""
#. SF_Array.RangeInit error message
#. %1, %2, %3: Numeric values
#. 'From', 'UpTo', 'ByStep' should not be translated
#, kde-format
msgctxt "ARRAYSEQUENCE"
msgid ""
"The respective values of 'From', 'UpTo' and 'ByStep' are incoherent.\n"
"\n"
" « From » = %1\n"
" « UpTo » = %2\n"
" « ByStep » = %3"
msgstr ""
#. SF_Array.AppendColumn (...) error message
#. %1: 'Column' or 'Row' of a matrix
#. %2, %3: array contents
#. 'Array_2D' should not be translated
#, kde-format
msgctxt "ARRAYINSERT"
msgid ""
"The array and the vector to insert have incompatible sizes.\n"
"\n"
" « Array_2D » = %2\n"
" « %1 » = %3"
msgstr ""
#. SF_Array.ExtractColumn (...) error message
#. %1: 'Column' or 'Row' of a matrix
#. %2, %3: array contents
#. 'Array_2D' should not be translated
#, kde-format
msgctxt "ARRAYINDEX1"
msgid ""
"The given index does not fit within the bounds of the array.\n"
"\n"
" « Array_2D » = %2\n"
" « %1 » = %3"
msgstr ""
#. SF_Array.ExtractColumn (...) error message
#. %1: 'Column' or 'Row' of a matrix
#. %2, %3: array contents
#. 'Array_1D', 'From' and 'UpTo' should not be translated
#, kde-format
msgctxt "ARRAYINDEX2"
msgid ""
"The given slice limits do not fit within the bounds of the array.\n"
"\n"
" « Array_1D » = %1\n"
" « From » = %2\n"
" « UpTo » = %3"
msgstr ""
#. SF_Array.ImportFromCSVFile error message
#. %1: a file name
#. %2: numeric
#. %3: a long string
#, kde-format
msgctxt "CSVPARSING"
msgid ""
"The given file could not be parsed as a valid CSV file.\n"
"\n"
" « File name » = %1\n"
" Line number = %2\n"
" Content = %3"
msgstr ""
#. SF_Dictionary Add/ReplaceKey error message
#. %1: An identifier%2: a (potentially long) string
#, kde-format
msgctxt "DUPLICATEKEY"
msgid ""
"The insertion of a new key into a dictionary failed because the key "
"already exists.\n"
"Note that the comparison between keys is NOT case-sensitive.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_Dictionary Remove/ReplaceKey/ReplaceItem error message
#. %1: An identifier%2: a (potentially long) string
#, kde-format
msgctxt "UNKNOWNKEY"
msgid ""
"The requested key does not exist in the dictionary.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_Dictionary Add/ReplaceKey error message
#.
msgctxt "INVALIDKEY"
msgid ""
"The insertion or the update of an entry into a dictionary failed "
"because the given key contains only spaces."
msgstr ""
#. SF_FileSystem copy/move/delete error message
#. %1: An identifier
#. %2: A file name
#, kde-format
msgctxt "UNKNOWNFILE"
msgid ""
"The given file could not be found on your system.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_FileSystem copy/move/delete error message
#. %1: An identifier
#. %2: A folder name
#, kde-format
msgctxt "UNKNOWNFOLDER"
msgid ""
"The given folder could not be found on your system.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_FileSystem copy/move/delete error message
#. %1: An identifier
#. %2: A file name
#, kde-format
msgctxt "NOTAFILE"
msgid ""
"« %1 » contains the name of an existing folder, not that of a file.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_FileSystem copy/move/delete error message
#. %1: An identifier
#. %2: A folder name
#, kde-format
msgctxt "NOTAFOLDER"
msgid ""
"« %1 » contains the name of an existing file, not that of a folder.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_FileSystem copy/move/... error message
#. %1: An identifier
#. %2: A file name
#, kde-format
msgctxt "OVERWRITE"
msgid ""
"You tried to create a new file which already exists. Overwriting it "
"has been rejected.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_FileSystem copy/move/delete error message
#. %1: An identifier
#. %2: A file name
#, kde-format
msgctxt "READONLY"
msgid ""
"Copying or moving a file to a destination which has its read-only "
"attribute set, or deleting such a file or folder is forbidden.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_FileSystem copy/move/delete error message
#. %1: An identifier
#. %2: A file or folder name with wildcards
#, kde-format
msgctxt "NOFILEMATCH"
msgid ""
"When « %1 » contains wildcards. at least one file or folder must "
"match the given filter. Otherwise the operation is rejected.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_FileSystem CreateFolder error message
#. %1: An identifier
#. %2: A file or folder name
#, kde-format
msgctxt "FOLDERCREATION"
msgid ""
"« %1 » contains the name of an existing file or an existing folder. "
"The operation is rejected.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_Services.CreateScriptService error message
#. %1: An identifier
#. %2: A string
#. %3: A Basic library name
#. %4: A service (1 word) name
#, kde-format
msgctxt "UNKNOWNSERVICE"
msgid ""
"No service named '%4' has been registered for the library '%3'.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_Services.CreateScriptService error message
#. %1: An identifier
#. %2: A string
#. %3: A Basic library name
#, kde-format
msgctxt "SERVICESNOTLOADED"
msgid ""
"The library '%3' and its services could not been loaded.\n"
"The reason is unknown.\n"
"However, checking the '%3.SF_Services.RegisterScriptServices()' "
"function and its return value can be a good starting point.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_Session.ExecuteCalcFunction error message
#. 'Calc' should not be translated
#, kde-format
msgctxt "CALCFUNC"
msgid ""
"The Calc '%1' function encountered an error. Either the given "
"function does not exist or its arguments are invalid."
msgstr ""
#. SF_Session._GetScript error message
#. %1: 'Basic' or 'Python'
#. %2: An identifier
#. %3: A string
#. %4: An identifier
#. %5: A string
#, kde-format
msgctxt "NOSCRIPT"
msgid ""
"The requested %1 script could not be located in the given libraries "
"and modules.\n"
"« %2 » = %3\n"
"« %4 » = %5"
msgstr ""
#. SF_Session.ExecuteBasicScript error message
#. %1: An identifier
#. %2: A string
#. %3: A (long) string
#, kde-format
msgctxt "SCRIPTEXEC"
msgid ""
"An exception occurred during the execution of the Basic script.\n"
"Cause: %3\n"
"« %1 » = %2"
msgstr ""
#. SF_Session.SendMail error message
#. %1 = a mail address
#, kde-format
msgctxt "WRONGEMAIL"
msgid ""
"One of the email addresses has been found invalid.\n"
"Invalid mail = « %1 »"
msgstr ""
#. SF_Session.SendMail error message
msgctxt "SENDMAIL"
msgid ""
"The message could not be sent due to a system error.\n"
"A possible cause is that LibreOffice could not find any mail client."
msgstr ""
#. SF_TextStream._IsFileOpen error message
#. %1: A file name
#, kde-format
msgctxt "FILENOTOPEN"
msgid ""
"The requested file operation could not be executed because the file "
"was closed previously.\n"
"\n"
"File name = '%1'"
msgstr ""
#. SF_TextStream._IsFileOpen error message
#. %1: A file name
#. %2: READ, WRITE or APPEND
#, kde-format
msgctxt "FILEOPENMODE"
msgid ""
"The requested file operation could not be executed because it is "
"incompatible with the mode in which the file was opened.\n"
"\n"
"File name = '%1'\n"
"Open mode = %2"
msgstr ""
#. SF_TextStream.ReadLine/ReadAll/SkipLine error message
#. %1: A file name
#, kde-format
msgctxt "ENDOFFILE"
msgid ""
"The requested file read operation could not be completed because an "
"unexpected end-of-file was encountered.\n"
"\n"
"File name = '%1'"
msgstr ""
#. SF_UI.GetDocument error message
#. %1: An identifier
#. %2: A string
#, kde-format
msgctxt "DOCUMENT"
msgid ""
"The requested document could not be found.\n"
"\n"
"%1 = '%2'"
msgstr ""
#. SF_UI.GetDocument error message
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A string
#, kde-format
msgctxt "DOCUMENTCREATION"
msgid ""
"The creation of a new document failed.\n"
"Something must be wrong with some arguments.\n"
"\n"
"Either the document type is unknown, or no template file was given,\n"
"or the given template file was not found on your system.\n"
"\n"
"%1 = '%2'\n"
"%3 = '%4'"
msgstr ""
#. SF_UI.OpenDocument error message
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A string
#. %5: An identifier
#. %6: A string
#, kde-format
msgctxt "DOCUMENTOPEN"
msgid ""
"The opening of the document failed.\n"
"Something must be wrong with some arguments.\n"
"\n"
"Either the file does not exist, or the password is wrong, or the "
"given filter is invalid.\n"
"\n"
"%1 = '%2'\n"
"%3 = '%4'\n"
"%5 = '%6'"
msgstr ""
#. SF_UI.OpenDocument error message
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A string
#, kde-format
msgctxt "BASEDOCUMENTOPEN"
msgid ""
"The opening of the Base document failed.\n"
"Something must be wrong with some arguments.\n"
"\n"
"Either the file does not exist, or the file is not registered under "
"the given name.\n"
"\n"
"%1 = '%2'\n"
"%3 = '%4'"
msgstr ""
#. SF_Document._IsStillAlive error message
#. %1: A file name
#, kde-format
msgctxt "DOCUMENTDEAD"
msgid ""
"The requested action could not be executed because the document was "
"closed inadvertently.\n"
"\n"
"The concerned document is '%1'"
msgstr ""
#. SF_Document.SaveAs error message
#. %1: An identifier
#. %2: A file name
#.
#, kde-format
msgctxt "DOCUMENTSAVE"
msgid ""
"The document could not be saved.\n"
"Either the document has been opened read-only, or the destination "
"file has a read-only attribute set, or the file where to save to is "
"undefined.\n"
"\n"
"%1 = '%2'"
msgstr ""
#. SF_Document.SaveAs error message
#. %1: An identifier
#. %2: A file name
#. %3: An identifier
#. %4: True or False
#. %5: An identifier
#. %6: A string
#, kde-format
msgctxt "DOCUMENTSAVEAS"
msgid ""
"The document could not be saved.\n"
"Either the document must not be overwritten, or the destination file "
"has a read-only attribute set, or the given filter is invalid.\n"
"\n"
"%1 = '%2'\n"
"%3 = %4\n"
"%5 = '%6'"
msgstr ""
#. SF_Document any update
#. %1: An identifier
#. %2: A file name
#, kde-format
msgctxt "DOCUMENTREADONLY"
msgid ""
"You tried to edit a document which is not modifiable. The document "
"has not been changed.\n"
"\n"
"« %1 » = %2"
msgstr ""
#. SF_Base GetDatabase
#. %1: An identifier
#. %2: A user name
#. %3: An identifier
#. %4: A password
#. %5: A file name
#, kde-format
msgctxt "DBCONNECT"
msgid ""
"The database related to the actual Base document could not be "
"retrieved.\n"
"Check the connection/login parameters.\n"
"\n"
"« %1 » = '%2'\n"
"« %3 » = '%4'\n"
"« Document » = %5"
msgstr ""
#. SF_Calc _ParseAddress (sheet)
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A file name
#, kde-format
msgctxt "CALCADDRESS1"
msgid ""
"The given address does not correspond with a valid sheet name.\n"
"\n"
"« %1 » = %2\n"
"« %3 » = %4"
msgstr ""
#. SF_Calc _ParseAddress (range)
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A file name
#, kde-format
msgctxt "CALCADDRESS2"
msgid ""
"The given address does not correspond with a valid range of cells.\n"
"\n"
"« %1 » = %2\n"
"« %3 » = %4"
msgstr ""
#. SF_Calc InsertSheet
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A file name
#, kde-format
msgctxt "DUPLICATESHEET"
msgid ""
"There exists already in the document a sheet with the same name.\n"
"\n"
"« %1 » = %2\n"
"« %3 » = %4"
msgstr ""
#. SF_Calc Offset
#. %1: An identifier
#. %2: A Calc reference
#. %3: An identifier
#. %4: A number
#. %5: An identifier
#. %6: A number
#. %7: An identifier
#. %8: A number
#. %9: An identifier
#. %10: A number
#. %11: An identifier
#. %12: A file name
#, kde-format
msgctxt "OFFSETADDRESS"
msgid ""
"The computed range falls beyond the sheet boundaries or is "
"meaningless.\n"
"\n"
"« %1 » = %2\n"
"« %3 » = %4\n"
"« %5 » = %6\n"
"« %7 » = %8\n"
"« %9 » = %10\n"
"« %11 » = %12"
msgstr ""
#. SF_Calc CreateChart
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A string
#. %5: An identifier
#. %6: A file name
#, kde-format
msgctxt "DUPLICATECHART"
msgid ""
"A chart with the same name exists already in the sheet.\n"
"\n"
"« %1 » = %2\n"
"« %3 » = %4\n"
"« %5 » = %6\n"
""
msgstr ""
#. SF_Calc.ExportRangeToFile error message
#. %1: An identifier
#. %2: A file name
#. %3: An identifier
#. %4: True or False
#.
#, kde-format
msgctxt "RANGEEXPORT"
msgid ""
"The given range could not be exported.\n"
"Either the destination file must not be overwritten, or it has a "
"read-only attribute set.\n"
"\n"
"%1 = '%2'\n"
"%3 = %4"
msgstr ""
#. SF_Chart.ExportToFile error message
#. %1: An identifier
#. %2: A file name
#. %3: An identifier
#. %4: True or False
#.
#, kde-format
msgctxt "CHARTEXPORT"
msgid ""
"The chart could not be exported.\n"
"Either the destination file must not be overwritten, or it has a "
"read-only attribute set.\n"
"\n"
"%1 = '%2'\n"
"%3 = %4"
msgstr ""
#. SF_Dialog._IsStillAlive error message
#. %1: An identifier%2: A file name
#, kde-format
msgctxt "FORMDEAD"
msgid ""
"The requested action could not be executed because the form is not "
"open or the document was closed inadvertently.\n"
"\n"
"The concerned form is '%1' in document '%2'."
msgstr ""
#. SF_Form determination
#. %1: A number
#. %2: A sheet name
#. %3: A file name
#, kde-format
msgctxt "CALCFORMNOTFOUND"
msgid ""
"The requested form could not be found in the Calc sheet. The given "
"index is off-limits.\n"
"\n"
"The concerned Calc document is '%3'.\n"
"\n"
"The name of the sheet = '%2'\n"
"The index = %1."
msgstr ""
#. SF_Form determination
#. %1: A number
#. %2: A file name
#, kde-format
msgctxt "WRITERFORMNOTFOUND"
msgid ""
"The requested form could not be found in the Writer document. The "
"given index is off-limits.\n"
"\n"
"The concerned Writer document is '%2'.\n"
"\n"
"The index = %1."
msgstr ""
#. SF_Form determination
#. %1: A number
#. %2: A string
#. %3: A file name
#, kde-format
msgctxt "BASEFORMNOTFOUND"
msgid ""
"The requested form could not be found in the form document '%2'. The "
"given index is off-limits.\n"
"\n"
"The concerned Base document is '%3'.\n"
"\n"
"The index = %1."
msgstr ""
#. SF_Form determination
#. %1: A form name
#. %2: A form name
#, kde-format
msgctxt "SUBFORMNOTFOUND"
msgid ""
"The requested subform could not be found below the given main form.\n"
"\n"
"The main form = '%2'.\n"
"The subform = '%1'."
msgstr ""
#. SF_FormControl property setting
#. %1: An identifier
#. %2: An identifier
#. %3: A string
#. %4: An identifier
#, kde-format
msgctxt "FORMCONTROLTYPE"
msgid ""
"The control '%1' in form '%2' is of type '%3'.\n"
"The property or method '%4' is not applicable on that type of form "
"controls."
msgstr ""
#. SF_Dialog creation
#. %1: An identifier
#. %2: A string
#. %3: An identifier
#. %4: A file name
#. %5: An identifier
#. %6: A string
#. %7: An identifier
#. %8: A string
#, kde-format
msgctxt "DIALOGNOTFOUND"
msgid ""
"The requested dialog could not be located in the given container or "
"library.\n"
"« %1 » = %2\n"
"« %3 » = %4\n"
"« %5 » = %6\n"
"« %7 » = %8"
msgstr ""
#. SF_Dialog._IsStillAlive error message
#. %1: An identifier
#, kde-format
msgctxt "DIALOGDEAD"
msgid ""
"The requested action could not be executed because the dialog was "
"closed inadvertently.\n"
"\n"
"The concerned dialog is '%1'."
msgstr ""
#. SF_DialogControl property setting
#. %1: An identifier
#. %2: An identifier
#. %3: A string
#. %4: An identifier
#, kde-format
msgctxt "CONTROLTYPE"
msgid ""
"The control '%1' in dialog '%2' is of type '%3'.\n"
"The property or method '%4' is not applicable on that type of dialog "
"controls."
msgstr ""
#. SF_DialogControl add line in textbox
#. %1: An identifier
#. %2: An identifier
#, kde-format
msgctxt "TEXTFIELD"
msgid ""
"The control '%1' in dialog '%2' is not a multiline text field.\n"
"The requested method could not be executed."
msgstr ""
#. SF_Dialog Page Manager setting
#. %1: An identifier
#. %2: A list of names separated by commas
#. %3: An identifier
#. %4: A list of names separated by commas
#. %5: An identifier
#. %6: A list of names separated by commas
#, kde-format
msgctxt "PAGEMANAGER"
msgid ""
"The Page Manager could not be setup due to inconsistent arguments.\n"
"\n"
" %1 : « %2 »\n"
" %3 : « %4 »\n"
" %5 : « %6 »"
msgstr ""
#. SF_Database when running update SQL statement
#. %1: The concerned method
#, kde-format
msgctxt "DBREADONLY"
msgid ""
"The database has been opened in read-only mode.\n"
"The '%1' method must not be executed in this context."
msgstr ""
#. SF_Database can't interpret SQL statement
#. %1: The statement
#, kde-format
msgctxt "SQLSYNTAX"
msgid ""
"An SQL statement could not be interpreted or executed by the "
"database system.\n"
"Check its syntax, table and/or field names, ...\n"
"\n"
"SQL Statement : « %1 »"
msgstr ""
#. SF_Exception.PythonShell error messageAPSO: to leave unchanged
msgctxt "PYTHONSHELL"
msgid ""
"The APSO extension could not be located in your LibreOffice "
"installation."
msgstr ""
#. SFUnitTest could not locate the library gven as argument
#. %1: The name of the library
#, kde-format
msgctxt "UNITTESTLIBRARY"
msgid ""
"The requested library could not be located.\n"
"The UnitTest service has not been initialized.\n"
"\n"
"Library name : « %1 »"
msgstr ""
#. SFUnitTest finds a RunTest() call in a inappropriate location
#. %1: The name of a method
#, kde-format
msgctxt "UNITTESTMETHOD"
msgid ""
"The method '%1' is unexpected in the current context.\n"
"The UnitTest service cannot proceed further with the on-going test."
msgstr ""

View File

@@ -0,0 +1,23 @@
<?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="__License"/>
<library:element library:name="SF_String"/>
<library:element library:name="_CodingConventions"/>
<library:element library:name="SF_Timer"/>
<library:element library:name="_ModuleModel"/>
<library:element library:name="SF_Utils"/>
<library:element library:name="SF_Root"/>
<library:element library:name="SF_Array"/>
<library:element library:name="SF_Services"/>
<library:element library:name="SF_Dictionary"/>
<library:element library:name="SF_Session"/>
<library:element library:name="SF_FileSystem"/>
<library:element library:name="SF_TextStream"/>
<library:element library:name="SF_L10N"/>
<library:element library:name="SF_Exception"/>
<library:element library:name="SF_UI"/>
<library:element library:name="SF_Platform"/>
<library:element library:name="SF_PythonHelper"/>
<library:element library:name="SF_Region"/>
</library:library>