移除office-plugin, 使用新版jodconverter

This commit is contained in:
陈精华
2022-12-15 18:19:30 +08:00
parent 281a9cfbab
commit 7d3a4ebc4e
12562 changed files with 202 additions and 3641 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,952 @@
<?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;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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 Not SF_Utils._Validate(Value, &quot;Value&quot;) Then GoTo Catch
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>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,696 @@
<?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 3 mechanisms:
&apos;&apos;&apos; - AddText: for the programmer to build a set of words or sentences
&apos;&apos;&apos; meant for being translated later
&apos;&apos;&apos; - ExportToPOTFile: All the above texts are exported into a pristine POT-file
&apos;&apos;&apos; - 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; Service invocation examples:
&apos;&apos;&apos; Dim myPO As Variant
&apos;&apos;&apos; myPO = CreateScriptService(&quot;L10N&quot;) &apos; AddText 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;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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)
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 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 IsMissing(Header) Then Header = &quot;&quot;
If IsMissing(Encoding) Or IsMissing(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;_&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 _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,281 @@
<?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;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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 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 ServiceName As String
&apos;&apos;&apos; Internal use
ServiceName = &quot;ScriptForge.Platform&quot;
End Property &apos; ScriptForge.SF_Platform.ServiceName
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 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 ===================================================================== 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;Machine&quot; _
, &quot;OfficeVersion&quot; _
, &quot;OSName&quot; _
, &quot;OSPlatform&quot; _
, &quot;OSRelease&quot; _
, &quot;OSVersion&quot; _
, &quot;Processor&quot; _
)
End Function &apos; ScriptForge.SF_Platform.Properties
REM =========================================================== PRIVATE FUNCTIONS
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
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;
With ScriptForge.SF_Session
_PropertyGet = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper, psProperty)
End With
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 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,822 @@
<?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_Root" 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 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; SF_Root
&apos;&apos;&apos; =======
&apos;&apos;&apos; FOR INTERNAL USE ONLY
&apos;&apos;&apos; Singleton class holding all persistent variables shared
&apos;&apos;&apos; by all the modules of the ScriptForge library
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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 MEMBERS
&apos; Internals
Private [Me] As Object
Private [_Parent] As Object
Private ObjectType As String &apos; Must be &quot;ROOT&quot;
Private MainFunction As String &apos; Name of method or property called by user script
Private MainFunctionArgs As String &apos; Syntax of method called by user script
Private StackLevel As Integer &apos; Depth of calls between internal methods
&apos; Error management
Private ErrorHandler As Boolean &apos; True = error handling active, False = internal debugging
Private ConsoleLines() As Variant &apos; Array of messages displayable in console
Private ConsoleDialog As Object &apos; SFDialogs.Dialog object
Private ConsoleControl As Object &apos; SFDialogs.DialogControl object
Private DisplayEnabled As Boolean &apos; When True, display of console or error messages is allowed
Private StopWhenError As Boolean &apos; When True, process stops after error &gt; &quot;WARNING&quot;
Private DebugMode As Boolean &apos; When True, log enter/exit each official Sub
&apos; Services management
Private ServicesList As Variant &apos; Dictionary of provided services
&apos; Usual UNO services
Private FunctionAccess As Object &apos; com.sun.star.sheet.FunctionAccess
Private PathSettings As Object &apos; com.sun.star.util.PathSettings
Private PathSubstitution As Object &apos; com.sun.star.util.PathSubstitution
Private ScriptProvider As Object &apos; com.sun.star.script.provider.MasterScriptProviderFactory
Private SystemShellExecute As Object &apos; com.sun.star.system.SystemShellExecute
Private CoreReflection As Object &apos; com.sun.star.reflection.CoreReflection
Private DispatchHelper As Object &apos; com.sun.star.frame.DispatchHelper
Private TextSearch As Object &apos; com.sun.star.util.TextSearch
Private SearchOptions As Object &apos; com.sun.star.util.SearchOptions
Private Locale As Object &apos; com.sun.star.lang.Locale
Private CharacterClass As Object &apos; com.sun.star.i18n.CharacterClassification
Private FileAccess As Object &apos; com.sun.star.ucb.SimpleFileAccess
Private FilterFactory As Object &apos; com.sun.star.document.FilterFactory
Private FolderPicker As Object &apos; com.sun.star.ui.dialogs.FolderPicker
Private FilePicker As Object &apos; com.sun.star.ui.dialogs.FilePicker
Private URLTransformer As Object &apos; com.sun.star.util.URLTransformer
Private Introspection As Object &apos; com.sun.star.beans.Introspection
Private BrowseNodeFactory As Object &apos; com.sun.star.script.browse.BrowseNodeFactory
Private DatabaseContext As Object &apos; com.sun.star.sdb.DatabaseContext
Private ConfigurationProvider _
As Object &apos; com.sun.star.configuration.ConfigurationProvider
Private MailService As Object &apos; com.sun.star.system.SimpleCommandMail or com.sun.star.system.SimpleSystemMail
&apos; Specific persistent services objects or properties
Private FileSystemNaming As String &apos; If &quot;SYS&quot;, file and folder naming is based on operating system notation
Private PythonHelper As String &apos; File name of Python helper functions (stored in $(inst)/share/Scripts/python)
Private Interface As Object &apos; ScriptForge own L10N service
Private OSName As String &apos; WIN, LINUX, MACOS
Private SFDialogs As Variant &apos; Persistent storage for the SFDialogs library
REM ====================================================== CONSTRUCTOR/DESTRUCTOR
REM -----------------------------------------------------------------------------
Private Sub Class_Initialize()
Set [Me] = Nothing
Set [_Parent] = Nothing
ObjectType = &quot;ROOT&quot;
MainFunction = &quot;&quot;
MainFunctionArgs = &quot;&quot;
StackLevel = 0
ErrorHandler = True
ConsoleLines = Array()
Set ConsoleDialog = Nothing
Set ConsoleControl = Nothing
DisplayEnabled = True
StopWhenError = True
DebugMode = False
ServicesList = Empty
Set FunctionAccess = Nothing
Set PathSettings = Nothing
Set PathSubstitution = Nothing
Set ScriptProvider = Nothing
Set SystemShellExecute = Nothing
Set CoreReflection = Nothing
Set DispatchHelper = Nothing
Set TextSearch = Nothing
Set SearchOptions = Nothing
Set Locale = Nothing
Set CharacterClass = Nothing
Set FileAccess = Nothing
Set FilterFactory = Nothing
Set FolderPicker = Nothing
Set FilePicker = Nothing
Set URLTransformer = Nothing
Set Introspection = Nothing
FileSystemNaming = &quot;ANY&quot;
PythonHelper = &quot;ScriptForgeHelper.py&quot;
Set Interface = Nothing
Set BrowseNodeFactory = Nothing
Set DatabaseContext = Nothing
Set ConfigurationProvider = Nothing
Set MailService = Nothing
OSName = &quot;&quot;
SFDialogs = Empty
End Sub &apos; ScriptForge.SF_Root Constructor
REM -----------------------------------------------------------------------------
Private Sub Class_Terminate()
Call Class_Initialize()
End Sub &apos; ScriptForge.SF_Root Destructor
REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
Call Class_Terminate()
Set Dispose = Nothing
End Function &apos; ScriptForge.SF_Root Explicit destructor
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
Public Sub _AddToConsole(ByVal psLine As String)
&apos;&apos;&apos; Add a new line to the console
&apos;&apos;&apos; TAB characters are expanded before the insertion of the line
&apos;&apos;&apos; NB: Array redimensioning of a member of an object must be done in the class module
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psLine: the line to add
Dim lConsole As Long &apos; UBound of ConsoleLines
Dim sLine As String &apos; Alias of psLine
&apos; Resize ConsoleLines
lConsole = UBound(ConsoleLines)
If lConsole &lt; 0 Then
ReDim ConsoleLines(0)
Else
ReDim Preserve ConsoleLines(0 To lConsole + 1)
End If
&apos; Add a timestamp to the line and insert it (without date)
sLine = Mid(SF_Utils._Repr(Now()), 12) &amp; &quot; -&gt; &quot; &amp; psLine
ConsoleLines(lConsole + 1) = Mid(SF_Utils._Repr(Now()), 12) &amp; &quot; -&gt; &quot; &amp; psLine
&apos; Add the new line to the actual (probably non-modal) console, if active
If Not IsNull(ConsoleDialog) Then
If ConsoleDialog._IsStillAlive(False) Then &apos; False to not raise an error
If IsNull(ConsoleControl) Then Set ConsoleControl = ConsoleDialog.Controls(SF_Exception.CONSOLENAME) &apos; Should not happen ...
ConsoleControl.WriteLine(sLine)
End If
End If
End Sub &apos; ScriptForge.SF_Root._AddToConsole
REM -----------------------------------------------------------------------------
Public Sub _LoadLocalizedInterface(Optional ByVal psMode As String)
&apos;&apos;&apos; Build the user interface in a persistent L10N object
&apos;&apos;&apos; Executed - only once - at first ScriptForge invocation by a user script
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psMode: ADDTEXT =&gt; the (english) labels are loaded from code below
&apos;&apos;&apos; POFILE =&gt; the localized labels are loaded from a PO file
&apos;&apos;&apos; the name of the file is &quot;la.po&quot; where la = language part of locale
&apos;&apos;&apos; (fallback to ADDTEXT mode if file does not exist)
Dim sInstallFolder As String &apos; ScriptForge installation directory
Dim sPOFolder As String &apos; Folder containing the PO files
Dim sPOFile As String &apos; PO File to load
Dim sLocale As String &apos; Locale
If ErrorHandler Then On Local Error GoTo Catch
Try:
&apos;TODO: Modify default value
If IsMissing(psMode) Then psMode = &quot;POFILE&quot;
If psMode = &quot;POFILE&quot; Then &apos; Use this mode in production
&apos; Build the po file name
With SF_FileSystem
sInstallFolder = ._SFInstallFolder() &apos; ScriptForge installation folder
sLocale = SF_Utils._GetUNOService(&quot;Locale&quot;).Language
sPOFolder = .BuildPath(sInstallFolder, &quot;po&quot;)
sPOFile = .BuildPath(sPOFolder, sLocale &amp; &quot;.po&quot;)
If Not .FileExists(sPOFile) Then &apos; File not found =&gt; load texts from code below
psMode = &quot;ADDTEXT&quot;
Else
Set Interface = CreateScriptService(&quot;L10N&quot;, sPOFolder, sLocale)
End If
End With
End If
If psMode = &quot;ADDTEXT&quot; Then &apos; Use this mode in development to prepare a new POT file
Set Interface = CreateScriptService(&quot;L10N&quot;)
With Interface
&apos; SF_Exception.Raise
.AddText( Context := &quot;CLOSEBUTTON&quot; _
, MsgId := &quot;Close&quot; _
, Comment := &quot;Text in close buttons of progress and console dialog boxes&quot; _
)
.AddText( Context := &quot;ERRORNUMBER&quot; _
, MsgId := &quot;Error %1&quot; _
, Comment := &quot;Title in error message box\n&quot; _
&amp; &quot;%1: an error number&quot; _
)
.AddText( Context := &quot;ERRORLOCATION&quot; _
, MsgId := &quot;Location : %1&quot; _
, Comment := &quot;Error message box\n&quot; _
&amp; &quot;%1: a line number&quot; _
)
.AddText( Context := &quot;LONGERRORDESC&quot; _
, MsgId := &quot;Error %1 - Location = %2 - Description = %3&quot; _
, Comment := &quot;Logfile record&quot; _
)
.AddText( Context := &quot;STOPEXECUTION&quot; _
, MsgId := &quot;THE EXECUTION IS CANCELLED.&quot; _
, Comment := &quot;SF_Utils._Validate error message&quot; _
)
&apos; SF_Exception.RaiseAbort
.AddText( Context := &quot;INTERNALERROR&quot; _
, MsgId := &quot;The ScriptForge library has crashed. The reason is unknown.\n&quot; _
&amp; &quot;Maybe a bug that could be reported on\n&quot; _
&amp; &quot;\thttps://bugs.documentfoundation.org/\n\n&quot; _
&amp; &quot;More details : \n\n&quot; _
, Comment := &quot;SF_Exception.RaiseAbort error message&quot; _
)
&apos; SF_Utils._Validate
.AddText( Context := &quot;VALIDATESOURCE&quot; _
, MsgId := &quot;Library : \t%1\nService : \t%2\nMethod : \t%3&quot; _
, Comment := &quot;SF_Utils._Validate error message\n&quot; _
&amp; &quot;%1: probably ScriptForge\n&quot; _
&amp; &quot;%2: service or module name\n&quot; _
&amp; &quot;%3: property or method name where the error occurred&quot; _
)
.AddText( Context := &quot;VALIDATEARGS&quot; _
, MsgId := &quot;Arguments: %1&quot; _
, Comment := &quot;SF_Utils._Validate error message\n&quot; _
&amp; &quot;%1: list of arguments of the method&quot; _
)
.AddText( Context := &quot;VALIDATEERROR&quot; _
, MsgId := &quot;A serious error has been detected in your code on argument : « %1 ».&quot; _
, Comment := &quot;SF_Utils._Validate error message\n&quot; _
&amp; &quot;%1: Wrong argument name&quot; _
)
.AddText( Context := &quot;VALIDATIONRULES&quot; _
, MsgId := &quot;\tValidation rules :&quot;, Comment := &quot;SF_Utils.Validate error message&quot; _
)
.AddText( Context := &quot;VALIDATETYPES&quot; _
, MsgId := &quot;\t\t« %1 » must have next type (or one of next types) : %2&quot; _
, Comment := &quot;SF_Utils._Validate error message\n&quot; _
&amp; &quot;%1: Wrong argument name\n&quot; _
&amp; &quot;%2: Comma separated list of allowed types&quot; _
)
.AddText( Context := &quot;VALIDATEVALUES&quot; _
, MsgId := &quot;\t\t« %1 » must contain one of next values : %2&quot; _
, Comment := &quot;SF_Utils._Validate error message\n&quot; _
&amp; &quot;%1: Wrong argument name\n&quot; _
&amp; &quot;%2: Comma separated list of allowed values&quot; _
)
.AddText( Context := &quot;VALIDATEREGEX&quot; _
, MsgId := &quot;\t\t« %1 » must match next regular expression : %2&quot; _
, Comment := &quot;SF_Utils._Validate error message\n&quot; _
&amp; &quot;%1: Wrong argument name\n&quot; _
&amp; &quot;%2: A regular expression&quot; _
)
.AddText( Context := &quot;VALIDATECLASS&quot; _
, MsgId := &quot;\t\t« %1 » must be a Basic object of class : %2&quot; _
, Comment := &quot;SF_Utils._Validate error message\n&quot; _
&amp; &quot;%1: Wrong argument name\n&quot; _
&amp; &quot;%2: The name of a Basic class&quot; _
)
.AddText( Context := &quot;VALIDATEACTUAL&quot; _
, MsgId := &quot;The actual value of « %1 » is : &apos;%2&apos;&quot; _
, Comment := &quot;SF_Utils._Validate error message\n&quot; _
&amp; &quot;%1: Wrong argument name\n&quot; _
&amp; &quot;%2: The value of the argument as a string&quot; _
)
.AddText( Context := &quot;VALIDATEMISSING&quot; _
, MsgId := &quot;The « %1 » argument is mandatory, yet it is missing.&quot; _
, Comment := &quot;SF_Utils._Validate error message\n&quot; _
&amp; &quot;%1: Wrong argument name&quot; _
)
&apos; SF_Utils._ValidateArray
.AddText( Context := &quot;VALIDATEARRAY&quot; _
, MsgId := &quot;\t\t« %1 » must be an array.&quot; _
, Comment := &quot;SF_Utils._ValidateArray error message\n&quot; _
&amp; &quot;%1: Wrong argument name&quot; _
)
.AddText( Context := &quot;VALIDATEDIMS&quot; _
, MsgId := &quot;\t\t« %1 » must have exactly %2 dimension(s).&quot; _
, Comment := &quot;SF_Utils._ValidateArray error message\n&quot; _
&amp; &quot;%1: Wrong argument name\n&quot; _
&amp; &quot;%2: Number of dimensions of the array&quot; _
)
.AddText( Context := &quot;VALIDATEALLTYPES&quot; _
, MsgId := &quot;\t\t« %1 » must have all elements of the same type : %2&quot; _
, Comment := &quot;SF_Utils._ValidateArray error message\n&quot; _
&amp; &quot;%1: Wrong argument name\n&quot; _
&amp; &quot;%2: Either one single type or &apos;String, Date, Numeric&apos;&quot; _
)
.AddText( Context := &quot;VALIDATENOTNULL&quot; _
, MsgId := &quot;\t\t« %1 » must not contain any NULL or EMPTY elements.&quot; _
, Comment := &quot;SF_Utils._ValidateArray error message\n&quot; _
&amp; &quot;%1: Wrong argument name\n&quot; _
&amp; &quot;NULL and EMPTY should not be translated&quot; _
)
&apos; SF_Utils._ValidateFile
.AddText( Context := &quot;VALIDATEFILE&quot; _
, MsgId := &quot;\t\t« %1 » must be of type String.&quot; _
, Comment := &quot;SF_Utils._ValidateFile error message\n&quot; _
&amp; &quot;%1: Wrong argument name\n&quot; _
&amp; &quot;&apos;String&apos; should not be translated&quot; _
)
.AddText( Context := &quot;VALIDATEFILESYS&quot; _
, MsgId := &quot;\t\t« %1 » must be a valid file or folder name expressed in the operating system native notation.&quot; _
, Comment := &quot;SF_Utils._ValidateFile error message\n&quot; _
&amp; &quot;%1: Wrong argument name&quot; _
)
.AddText( Context := &quot;VALIDATEFILEURL&quot; _
, MsgId := &quot;\t\t« %1 » must be a valid file or folder name expressed in the portable URL notation.&quot; _
, Comment := &quot;SF_Utils._ValidateFile error message\n&quot; _
&amp; &quot;%1: Wrong argument name\n&quot; _
&amp; &quot;&apos;URL&apos; should not be translated&quot; _
)
.AddText( Context := &quot;VALIDATEFILEANY&quot; _
, MsgId := &quot;\t\t« %1 » must be a valid file or folder name.&quot; _
, Comment := &quot;SF_Utils._ValidateFile error message\n&quot; _
&amp; &quot;%1: Wrong argument name&quot; _
)
.AddText( Context := &quot;VALIDATEWILDCARD&quot; _
, MsgId := &quot;\t\t« %1 » may contain one or more wildcard characters (?, *) in its last path component only.&quot; _
, Comment := &quot;SF_Utils._ValidateFile error message\n&quot; _
&amp; &quot;%1: Wrong argument name\n&quot; _
&amp; &quot;&apos;(?, *)&apos; is to be left as is&quot; _
)
&apos; SF_Array.RangeInit
.AddText( Context := &quot;ARRAYSEQUENCE&quot; _
, MsgId := &quot;The respective values of &apos;From&apos;, &apos;UpTo&apos; and &apos;ByStep&apos; are incoherent.\n\n&quot; _
&amp; &quot;\t« From » = %1\n&quot; _
&amp; &quot;\t« UpTo » = %2\n&quot; _
&amp; &quot;\t« ByStep » = %3&quot; _
, Comment := &quot;SF_Array.RangeInit error message\n&quot; _
&amp; &quot;%1, %2, %3: Numeric values\n&quot; _
&amp; &quot;&apos;From&apos;, &apos;UpTo&apos;, &apos;ByStep&apos; should not be translated&quot; _
)
&apos; SF_Array.AppendColumn, AppendRow, PrependColumn, PrependRow
.AddText( Context := &quot;ARRAYINSERT&quot; _
, MsgId := &quot;The array and the vector to insert have incompatible sizes.\n\n&quot; _
&amp; &quot;\t« Array_2D » = %2\n&quot; _
&amp; &quot;\t« %1 » = %3&quot; _
, Comment := &quot;SF_Array.AppendColumn (...) error message\n&quot; _
&amp; &quot;%1: &apos;Column&apos; or &apos;Row&apos; of a matrix\n&quot; _
&amp; &quot;%2, %3: array contents\n&quot; _
&amp; &quot;&apos;Array_2D&apos; should not be translated&quot; _
)
&apos; SF_Array.ExtractColumn, ExtractRow
.AddText( Context := &quot;ARRAYINDEX1&quot; _
, MsgId := &quot;The given index does not fit within the bounds of the array.\n\n&quot; _
&amp; &quot;\t« Array_2D » = %2\n&quot; _
&amp; &quot;\t« %1 » = %3&quot; _
, Comment := &quot;SF_Array.ExtractColumn (...) error message\n&quot; _
&amp; &quot;%1: &apos;Column&apos; or &apos;Row&apos; of a matrix\n&quot; _
&amp; &quot;%2, %3: array contents\n&quot; _
&amp; &quot;&apos;Array_2D&apos; should not be translated&quot; _
)
&apos; SF_Array.ExtractColumn, ExtractRow
.AddText( Context := &quot;ARRAYINDEX2&quot; _
, MsgId := &quot;The given slice limits do not fit within the bounds of the array.\n\n&quot; _
&amp; &quot;\t« Array_2D » = %1\n&quot; _
&amp; &quot;\t« From » = %2\n&quot; _
&amp; &quot;\t« UpTo » = %3&quot; _
, Comment := &quot;SF_Array.ExtractColumn (...) error message\n&quot; _
&amp; &quot;%1: &apos;Column&apos; or &apos;Row&apos; of a matrix\n&quot; _
&amp; &quot;%2, %3: array contents\n&quot; _
&amp; &quot;&apos;Array_2D&apos;, &apos;From&apos; and &apos;UpTo&apos; should not be translated&quot; _
)
&apos; SF_Array.ImportFromCSVFile
.AddText( Context := &quot;CSVPARSING&quot; _
, MsgId := &quot;The given file could not be parsed as a valid CSV file.\n\n&quot; _
&amp; &quot;\t« File name » = %1\n&quot; _
&amp; &quot;\tLine number = %2\n&quot; _
&amp; &quot;\tContent = %3&quot; _
, Comment := &quot;SF_Array.ImportFromCSVFile error message\n&quot; _
&amp; &quot;%1: a file name\n&quot; _
&amp; &quot;%2: numeric\n&quot; _
&amp; &quot;%3: a long string&quot; _
)
&apos; SF_Dictionary.Add/ReplaceKey
.AddText( Context := &quot;DUPLICATEKEY&quot; _
, MsgId := &quot;The insertion of a new key &quot; _
&amp; &quot;into a dictionary failed because the key already exists.\n&quot; _
&amp; &quot;Note that the comparison between keys is NOT case-sensitive.\n\n&quot; _
&amp; &quot;« %1 » = %2&quot; _
, Comment := &quot;SF_Dictionary Add/ReplaceKey error message\n&quot; _
&amp; &quot;%1: An identifier&quot; _
&amp; &quot;%2: a (potentially long) string&quot; _
)
&apos; SF_Dictionary.Remove/ReplaceKey/ReplaceItem
.AddText( Context := &quot;UNKNOWNKEY&quot; _
, MsgId := &quot;The requested key does not exist in the dictionary.\n\n&quot; _
&amp; &quot;« %1 » = %2&quot; _
, Comment := &quot;SF_Dictionary Remove/ReplaceKey/ReplaceItem error message\n&quot; _
&amp; &quot;%1: An identifier&quot; _
&amp; &quot;%2: a (potentially long) string&quot; _
)
&apos; SF_Dictionary.Add/ReplaceKey
.AddText( Context := &quot;INVALIDKEY&quot; _
, MsgId := &quot;The insertion or the update of an entry &quot; _
&amp; &quot;into a dictionary failed because the given key contains only spaces.&quot; _
, Comment := &quot;SF_Dictionary Add/ReplaceKey error message\n&quot; _
)
&apos; SF_FileSystem.CopyFile/MoveFile/DeleteFile/CreateScriptService(&quot;L10N&quot;)
.AddText( Context := &quot;UNKNOWNFILE&quot; _
, MsgId := &quot;The given file could not be found on your system.\n\n&quot; _
&amp; &quot;« %1 » = %2&quot; _
, Comment := &quot;SF_FileSystem copy/move/delete error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A file name&quot; _
)
&apos; SF_FileSystem.CopyFolder/MoveFolder/DeleteFolder/Files/SubFolders
.AddText( Context := &quot;UNKNOWNFOLDER&quot; _
, MsgId := &quot;The given folder could not be found on your system.\n\n&quot; _
&amp; &quot;« %1 » = %2&quot; _
, Comment := &quot;SF_FileSystem copy/move/delete error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A folder name&quot; _
)
&apos; SF_FileSystem.CopyFile/MoveFolder/DeleteFile
.AddText( Context := &quot;NOTAFILE&quot; _
, MsgId := &quot;« %1 » contains the name of an existing folder, not that of a file.\n\n&quot; _
&amp; &quot;« %1 » = %2&quot; _
, Comment := &quot;SF_FileSystem copy/move/delete error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A file name&quot; _
)
&apos; SF_FileSystem.CopyFolder/MoveFolder/DeleteFolder/Files/SubFolders
.AddText( Context := &quot;NOTAFOLDER&quot; _
, MsgId := &quot;« %1 » contains the name of an existing file, not that of a folder.\n\n&quot; _
&amp; &quot;« %1 » = %2&quot; _
, Comment := &quot;SF_FileSystem copy/move/delete error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A folder name&quot; _
)
&apos; SF_FileSystem.Copy+Move/File+Folder/CreateTextFile/OpenTextFile
.AddText( Context := &quot;OVERWRITE&quot; _
, MsgId := &quot;You tried to create a new file which already exists. Overwriting it has been rejected.\n\n&quot; _
&amp; &quot;« %1 » = %2&quot; _
, Comment := &quot;SF_FileSystem copy/move/... error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A file name&quot; _
)
&apos; SF_FileSystem.Copy+Move+Delete/File+Folder
.AddText( Context := &quot;READONLY&quot; _
, MsgId := &quot;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&quot; _
&amp; &quot;« %1 » = %2&quot; _
, Comment := &quot;SF_FileSystem copy/move/delete error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A file name&quot; _
)
&apos; SF_FileSystem.Copy+Move+Delete/File+Folder
.AddText( Context := &quot;NOFILEMATCH&quot; _
, MsgId := &quot;When « %1 » contains wildcards. at least one file or folder must match the given filter. Otherwise the operation is rejected.\n\n&quot; _
&amp; &quot;« %1 » = %2&quot; _
, Comment := &quot;SF_FileSystem copy/move/delete error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A file or folder name with wildcards&quot; _
)
&apos; SF_FileSystem.CreateFolder
.AddText( Context := &quot;FOLDERCREATION&quot; _
, MsgId := &quot;« %1 » contains the name of an existing file or an existing folder. The operation is rejected.\n\n&quot; _
&amp; &quot;« %1 » = %2&quot; _
, Comment := &quot;SF_FileSystem CreateFolder error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A file or folder name&quot; _
)
&apos; SF_Services.CreateScriptService
.AddText( Context := &quot;UNKNOWNSERVICE&quot; _
, MsgId := &quot;No service named &apos;%4&apos; has been registered for the library &apos;%3&apos;.\n\n&quot; _
&amp; &quot;« %1 » = %2&quot; _
, Comment := &quot;SF_Services.CreateScriptService error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A string\n&quot; _
&amp; &quot;%3: A Basic library name\n&quot; _
&amp; &quot;%4: A service (1 word) name&quot; _
)
&apos; SF_Services.CreateScriptService
.AddText( Context := &quot;SERVICESNOTLOADED&quot; _
, MsgId := &quot;The library &apos;%3&apos; and its services could not been loaded.\n&quot; _
&amp; &quot;The reason is unknown.\n&quot; _
&amp; &quot;However, checking the &apos;%3.SF_Services.RegisterScriptServices()&apos; function and its return value can be a good starting point.\n\n&quot; _
&amp; &quot;« %1 » = %2&quot; _
, Comment := &quot;SF_Services.CreateScriptService error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A string\n&quot; _
&amp; &quot;%3: A Basic library name&quot; _
)
&apos; SF_Session.ExecuteCalcFunction
.AddText( Context := &quot;CALCFUNC&quot; _
, MsgId := &quot;The Calc &apos;%1&apos; function encountered an error. Either the given function does not exist or its arguments are invalid.&quot; _
, Comment := &quot;SF_Session.ExecuteCalcFunction error message\n&quot; _
&amp; &quot;&apos;Calc&apos; should not be translated&quot; _
)
&apos; SF_Session._GetScript
.AddText( Context := &quot;NOSCRIPT&quot; _
, MsgId := &quot;The requested %1 script could not be located in the given libraries and modules.\n&quot; _
&amp; &quot;« %2 » = %3\n&quot; _
&amp; &quot;« %4 » = %5&quot; _
, Comment := &quot;SF_Session._GetScript error message\n&quot; _
&amp; &quot;%1: &apos;Basic&apos; or &apos;Python&apos;\n&quot; _
&amp; &quot;%2: An identifier\n&quot; _
&amp; &quot;%3: A string\n&quot; _
&amp; &quot;%2: An identifier\n&quot; _
&amp; &quot;%3: A string&quot; _
)
&apos; SF_Session.ExecuteBasicScript
.AddText( Context := &quot;SCRIPTEXEC&quot; _
, MsgId := &quot;An exception occurred during the execution of the Basic script.\n&quot; _
&amp; &quot;Cause: %3\n&quot; _
&amp; &quot;« %1 » = %2&quot; _
, Comment := &quot;SF_Session.ExecuteBasicScript error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A string\n&quot; _
&amp; &quot;%3: A (long) string&quot; _
)
&apos; SF_Session.SendMail
.AddText( Context := &quot;WRONGEMAIL&quot; _
, MsgId := &quot;One of the email addresses has been found invalid.\n&quot; _
&amp; &quot;Invalid mail = « %1 »&quot; _
, Comment := &quot;SF_Session.SendMail error message\n&quot; _
&amp; &quot;%1 = a mail address&quot; _
)
&apos; SF_Session.SendMail
.AddText( Context := &quot;SENDMAIL&quot; _
, MsgId := &quot;The message could not be sent due to a system error.\n&quot; _
&amp; &quot;A possible cause is that LibreOffice could not find any mail client.&quot; _
, Comment := &quot;SF_Session.SendMail error message&quot; _
)
&apos; SF_TextStream._IsFileOpen
.AddText( Context := &quot;FILENOTOPEN&quot; _
, MsgId := &quot;The requested file operation could not be executed because the file was closed previously.\n\n&quot; _
&amp; &quot;File name = &apos;%1&apos;&quot; _
, Comment := &quot;SF_TextStream._IsFileOpen error message\n&quot; _
&amp; &quot;%1: A file name&quot; _
)
&apos; SF_TextStream._IsFileOpen
.AddText( Context := &quot;FILEOPENMODE&quot; _
, MsgId := &quot;The requested file operation could not be executed because it is incompatible with the mode in which the file was opened.\n\n&quot; _
&amp; &quot;File name = &apos;%1&apos;\n&quot; _
&amp; &quot;Open mode = %2&quot; _
, Comment := &quot;SF_TextStream._IsFileOpen error message\n&quot; _
&amp; &quot;%1: A file name\n&quot; _
&amp; &quot;%2: READ, WRITE or APPEND&quot; _
)
&apos; SF_UI.Document
.AddText( Context := &quot;DOCUMENT&quot; _
, MsgId := &quot;The requested document could not be found.\n\n&quot; _
&amp; &quot;%1 = &apos;%2&apos;&quot; _
, Comment := &quot;SF_UI.GetDocument error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A string&quot; _
)
&apos; SF_UI.Create
.AddText( Context := &quot;DOCUMENTCREATION&quot; _
, MsgId := &quot;The creation of a new document failed.\n&quot; _
&amp; &quot;Something must be wrong with some arguments.\n\n&quot; _
&amp; &quot;Either the document type is unknown, or no template file was given,\n&quot; _
&amp; &quot;or the given template file was not found on your system.\n\n&quot; _
&amp; &quot;%1 = &apos;%2&apos;\n&quot; _
&amp; &quot;%3 = &apos;%4&apos;&quot; _
, Comment := &quot;SF_UI.GetDocument error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A string\n&quot; _
&amp; &quot;%3: An identifier\n&quot; _
&amp; &quot;%4: A string&quot; _
)
&apos; SF_UI.OpenDocument
.AddText( Context := &quot;DOCUMENTOPEN&quot; _
, MsgId := &quot;The opening of the document failed.\n&quot; _
&amp; &quot;Something must be wrong with some arguments.\n\n&quot; _
&amp; &quot;Either the file does not exist, or the password is wrong, or the given filter is invalid.\n\n&quot; _
&amp; &quot;%1 = &apos;%2&apos;\n&quot; _
&amp; &quot;%3 = &apos;%4&apos;\n&quot; _
&amp; &quot;%5 = &apos;%6&apos;&quot; _
, Comment := &quot;SF_UI.OpenDocument error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A string\n&quot; _
&amp; &quot;%3: An identifier\n&quot; _
&amp; &quot;%4: A string\n&quot; _
&amp; &quot;%5: An identifier\n&quot; _
&amp; &quot;%6: A string&quot; _
)
&apos; SF_UI.OpenBaseDocument
.AddText( Context := &quot;BASEDOCUMENTOPEN&quot; _
, MsgId := &quot;The opening of the Base document failed.\n&quot; _
&amp; &quot;Something must be wrong with some arguments.\n\n&quot; _
&amp; &quot;Either the file does not exist, or the file is not registered under the given name.\n\n&quot; _
&amp; &quot;%1 = &apos;%2&apos;\n&quot; _
&amp; &quot;%3 = &apos;%4&apos;&quot; _
, Comment := &quot;SF_UI.OpenDocument error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A string\n&quot; _
&amp; &quot;%3: An identifier\n&quot; _
&amp; &quot;%4: A string&quot; _
)
&apos; SF_Document._IsStillAlive
.AddText( Context := &quot;DOCUMENTDEAD&quot; _
, MsgId := &quot;The requested action could not be executed because the document was closed inadvertently.\n\n&quot; _
&amp; &quot;The concerned document is &apos;%1&apos;&quot; _
, Comment := &quot;SF_Document._IsStillAlive error message\n&quot; _
&amp; &quot;%1: A file name&quot; _
)
&apos; SF_Document.Save
.AddText( Context := &quot;DOCUMENTSAVE&quot; _
, MsgId := &quot;The document could not be saved.\n&quot; _
&amp; &quot;Either the document has been opened read-only, or the destination file has a read-only attribute set, &quot; _
&amp; &quot;or the file where to save to is undefined.\n\n&quot; _
&amp; &quot;%1 = &apos;%2&apos;&quot; _
, Comment := &quot;SF_Document.SaveAs error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A file name\n&quot; _
)
&apos; SF_Document.SaveAs
.AddText( Context := &quot;DOCUMENTSAVEAS&quot; _
, MsgId := &quot;The document could not be saved.\n&quot; _
&amp; &quot;Either the document must not be overwritten, or the destination file has a read-only attribute set, &quot; _
&amp; &quot;or the given filter is invalid.\n\n&quot; _
&amp; &quot;%1 = &apos;%2&apos;\n&quot; _
&amp; &quot;%3 = %4\n&quot; _
&amp; &quot;%5 = &apos;%6&apos;&quot; _
, Comment := &quot;SF_Document.SaveAs error message\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A file name\n&quot; _
&amp; &quot;%3: An identifier\n&quot; _
&amp; &quot;%4: True or False\n&quot; _
&amp; &quot;%5: An identifier\n&quot; _
&amp; &quot;%6: A string&quot; _
)
&apos; SF_Document.any update
.AddText( Context := &quot;DOCUMENTREADONLY&quot; _
, MsgId := &quot;You tried to edit a document which is not modifiable. The document has not been changed.\n\n&quot; _
&amp; &quot;« %1 » = %2&quot; _
, Comment := &quot;SF_Document any update\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A file name&quot; _
)
&apos; SF_Base.GetDatabase
.AddText( Context := &quot;DBCONNECT&quot; _
, MsgId := &quot;The database related to the actual Base document could not be retrieved.\n&quot; _
&amp; &quot;Check the connection/login parameters.\n\n&quot; _
&amp; &quot;« %1 » = &apos;%2&apos;\n&quot; _
&amp; &quot;« %3 » = &apos;%4&apos;\n&quot; _
&amp; &quot;« Document » = %5&quot; _
, Comment := &quot;SF_Base GetDatabase\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A user name\n&quot; _
&amp; &quot;%3: An identifier\n&quot; _
&amp; &quot;%4: A password\n&quot; _
&amp; &quot;%5: A file name&quot; _
)
&apos; SF_Calc._ParseAddress (sheet)
.AddText( Context := &quot;CALCADDRESS1&quot; _
, MsgId := &quot;The given address does not correspond with a valid sheet name.\n\n&quot; _
&amp; &quot;« %1 » = %2\n&quot; _
&amp; &quot;« %3 » = %4&quot; _
, Comment := &quot;SF_Calc _ParseAddress (sheet)\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A string\n&quot; _
&amp; &quot;%3: An identifier\n&quot; _
&amp; &quot;%4: A file name&quot; _
)
&apos; SF_Calc._ParseAddress (range)
.AddText( Context := &quot;CALCADDRESS2&quot; _
, MsgId := &quot;The given address does not correspond with a valid range of cells.\n\n&quot; _
&amp; &quot;« %1 » = %2\n&quot; _
&amp; &quot;« %3 » = %4&quot; _
, Comment := &quot;SF_Calc _ParseAddress (range)\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A string\n&quot; _
&amp; &quot;%3: An identifier\n&quot; _
&amp; &quot;%4: A file name&quot; _
)
&apos; SF_Calc.InsertSheet
.AddText( Context := &quot;DUPLICATESHEET&quot; _
, MsgId := &quot;There exists already in the document a sheet with the same name.\n\n&quot; _
&amp; &quot;« %1 » = %2\n&quot; _
&amp; &quot;« %3 » = %4&quot; _
, Comment := &quot;SF_Calc InsertSheet\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A string\n&quot; _
&amp; &quot;%3: An identifier\n&quot; _
&amp; &quot;%4: A file name&quot; _
)
&apos; SF_Calc.Offset
.AddText( Context := &quot;OFFSETADDRESS&quot; _
, MsgId := &quot;The computed range falls beyond the sheet boundaries or is meaningless.\n\n&quot; _
&amp; &quot;« %1 » = %2\n&quot; _
&amp; &quot;« %3 » = %4\n&quot; _
&amp; &quot;« %5 » = %6\n&quot; _
&amp; &quot;« %7 » = %8\n&quot; _
&amp; &quot;« %9 » = %10\n&quot; _
&amp; &quot;« %11 » = %12&quot; _
, Comment := &quot;SF_Calc Offset\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A Calc reference\n&quot; _
&amp; &quot;%3: An identifier\n&quot; _
&amp; &quot;%4: A number\n&quot; _
&amp; &quot;%5: An identifier\n&quot; _
&amp; &quot;%6: A number\n&quot; _
&amp; &quot;%7: An identifier\n&quot; _
&amp; &quot;%8: A number\n&quot; _
&amp; &quot;%9: An identifier\n&quot; _
&amp; &quot;%10: A number\n&quot; _
&amp; &quot;%11: An identifier\n&quot; _
&amp; &quot;%12: A file name&quot; _
)
&apos; SF_Dialog._NewDialog
.AddText( Context := &quot;DIALOGNOTFOUND&quot; _
, MsgId := &quot;The requested dialog could not be located in the given container or library.\n&quot; _
&amp; &quot;« %1 » = %2\n&quot; _
&amp; &quot;« %3 » = %4\n&quot; _
&amp; &quot;« %5 » = %6\n&quot; _
&amp; &quot;« %7 » = %8&quot; _
, Comment := &quot;SF_Dialog creation\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: A string\n&quot; _
&amp; &quot;%3: An identifier\n&quot; _
&amp; &quot;%4: A file name\n&quot; _
&amp; &quot;%5: An identifier\n&quot; _
&amp; &quot;%6: A string\n&quot; _
&amp; &quot;%7: An identifier\n&quot; _
&amp; &quot;%8: A string&quot; _
)
&apos; SF_Dialog._IsStillAlive
.AddText( Context := &quot;DIALOGDEAD&quot; _
, MsgId := &quot;The requested action could not be executed because the dialog was closed inadvertently.\n\n&quot; _
&amp; &quot;The concerned dialog is &apos;%1&apos;.&quot; _
, Comment := &quot;SF_Dialog._IsStillAlive error message\n&quot; _
&amp; &quot;%1: An identifier&quot; _
)
&apos; SF_DialogControl._SetProperty
.AddText( Context := &quot;CONTROLTYPE&quot; _
, MsgId := &quot;The control &apos;%1&apos; in dialog &apos;%2&apos; is of type &apos;%3&apos;.\n&quot; _
&amp; &quot;The property &apos;%4&apos; is not applicable on that type of dialog controls.&quot; _
, Comment := &quot;SF_DialogControl property setting\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: An identifier\n&quot; _
&amp; &quot;%3: A string\n&quot; _
&amp; &quot;%4: An identifier&quot; _
)
&apos; SF_DialogControl.WriteLine
.AddText( Context := &quot;TEXTFIELD&quot; _
, MsgId := &quot;The control &apos;%1&apos; in dialog &apos;%2&apos; is not a multiline text field.\n&quot; _
&amp; &quot;The requested method could not be executed.&quot; _
, Comment := &quot;SF_DialogControl add line in textbox\n&quot; _
&amp; &quot;%1: An identifier\n&quot; _
&amp; &quot;%2: An identifier&quot; _
)
&apos; SF_Database.RunSql
.AddText( Context := &quot;DBREADONLY&quot; _
, MsgId := &quot;The database has been opened in read-only mode.\n&quot; _
&amp; &quot;The &apos;%1&apos; method must not be executed in this context.&quot; _
, Comment := &quot;SF_Database when running update SQL statement\n&quot; _
&amp; &quot;%1: The concerned method&quot; _
)
&apos; SF_Database._ExecuteSql
.AddText( Context := &quot;SQLSYNTAX&quot; _
, MsgId := &quot;An SQL statement could not be interpreted or executed by the database system.\n&quot; _
&amp; &quot;Check its syntax, table and/or field names, ...\n\n&quot; _
&amp; &quot;SQL Statement : « %1 »&quot; _
, Comment := &quot;SF_Database can&apos;t interpret SQL statement\n&quot; _
&amp; &quot;%1: The statement&quot; _
)
End With
End If
Finally:
Exit Sub
Catch:
GoTo Finally
End Sub &apos; ScriptForge.SF_Root._LoadLocalizedInterface
REM -----------------------------------------------------------------------------
Public Function _Repr() As String
&apos;&apos;&apos; Convert the unique SF_Root instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Return:
&apos;&apos;&apos; &quot;[Root] (MainFunction: xxx, Console: yyy lines, ServicesList)&quot;
Dim sRoot As String &apos; Return value
Const cstRoot = &quot;[Root] (&quot;
sRoot = cstRoot &amp; &quot;MainFunction: &quot; &amp; MainFunction &amp; &quot;, Console: &quot; &amp; UBound(ConsoleLines) + 1 &amp; &quot; lines&quot; _
&amp; &quot;, Libraries:&quot; &amp; SF_Utils._Repr(ServicesList.Keys) _
&amp; &quot;)&quot;
_Repr = sRoot
End Function &apos; ScriptForge.SF_Root._Repr
REM -----------------------------------------------------------------------------
Public Sub _StackReset()
&apos;&apos;&apos; Reset private members after a fatal/abort error to leave
&apos;&apos;&apos; a stable persistent storage after an unwanted interrupt
MainFunction = &quot;&quot;
MainFunctionArgs = &quot;&quot;
StackLevel = 0
End Sub &apos; ScriptForge.SF_Root._StackReset
REM ================================================== END OF SCRIPTFORGE.SF_ROOT
</script:module>

View File

@@ -0,0 +1,607 @@
<?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;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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 sService
Case &quot;Document&quot;, &quot;Calc&quot;, &quot;Base&quot; : sLibrary = &quot;SFDocuments&quot;
Case &quot;Dialog&quot;, &quot;DialogEvent&quot; : sLibrary = &quot;SFDialogs&quot;
Case &quot;Database&quot; : sLibrary = &quot;SFDatabases&quot;
Case 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;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; 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 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
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
If IsMissing(pvArgs) Then pvArgs = Array()
If UBound(pvArgs) &lt; 0 Then
sPOFile = &quot;&quot;
sEncoding = &quot;&quot;
Else
If Not SF_Utils._ValidateFile(pvArgs(0), &quot;Folder (Arg0)&quot;) Then GoTo Catch
sFolderName = pvArgs(0)
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)
Else
Set oLocale = SF_Utils._GetUNOService(&quot;Locale&quot;)
sLocale = oLocale.Language &amp; &quot;-&quot; &amp; oLocale.Country
End If
If UBound(pvArgs) &gt;= 2 Then
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
sPOFile = SF_FileSystem.BuildPath(sFolderName, sLocale &amp; &quot;.po&quot;)
If Not SF_FileSystem.FileExists(sPOFile) Then GoTo CatchNotExists
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,918 @@
<?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_Session" 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_Session
&apos;&apos;&apos; ==========
&apos;&apos;&apos; Singleton class implementing the &quot;ScriptForge.Session&quot; service
&apos;&apos;&apos; Implemented as a usual Basic module
&apos;&apos;&apos;
&apos;&apos;&apos; Gathers diverse general-purpose properties and methods about :
&apos;&apos;&apos; - installation/execution environment
&apos;&apos;&apos; - UNO introspection utilities
&apos;&apos;&apos; - clipboard management
&apos;&apos;&apos; - invocation of external scripts or programs
&apos;&apos;&apos;
&apos;&apos;&apos; Service invocation example:
&apos;&apos;&apos; Dim session As Variant
&apos;&apos;&apos; session = CreateScriptService(&quot;Session&quot;)
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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 CALCFUNCERROR = &quot;CALCFUNCERROR&quot; &apos; Calc function execution failed
Const NOSCRIPTERROR = &quot;NOSCRIPTERROR&quot; &apos; Script could not be located
Const SCRIPTEXECERROR = &quot;SCRIPTEXECERROR&quot; &apos; Exception during script execution
Const WRONGEMAILERROR = &quot;WRONGEMAILERROR&quot; &apos; Wrong email address
Const SENDMAILERROR = &quot;SENDMAILERROR&quot; &apos; Mail could not be sent
Const UNKNOWNFILEERROR = &quot;UNKNOWNFILEERROR&quot; &apos; Source file does not exist
REM ============================================================ MODULE CONSTANTS
&apos;&apos;&apos; Script locations
&apos;&apos;&apos; ================
&apos;&apos;&apos; Use next constants as Scope argument when invoking next methods:
&apos;&apos;&apos; ExecuteBasicScript()
&apos;&apos;&apos; ExecutePythonScript()
&apos;&apos;&apos; Example:
&apos;&apos;&apos; session.ExecuteBasicScript(session.SCRIPTISEMBEDDED, &quot;Standard.myLib.myFunc&quot;, etc)
Const cstSCRIPTISEMBEDDED = &quot;document&quot; &apos; a library of the document (BASIC + PYTHON)
Const cstSCRIPTISAPPLICATION = &quot;application&quot; &apos; a shared library (BASIC)
Const cstSCRIPTISPERSONAL = &quot;user&quot; &apos; a library of My Macros (PYTHON)
Const cstSCRIPTISPERSOXT = &quot;user:uno_packages&quot; &apos; an extension for the current user (PYTHON)
Const cstSCRIPTISSHARED = &quot;share&quot; &apos; a library of LibreOffice Macros (PYTHON)
Const cstSCRIPTISSHAROXT = &quot;share:uno_packages&quot; &apos; an extension for all users (PYTHON)
Const cstSCRIPTISOXT = &quot;uno_packages&quot; &apos; an extension but install params are unknown (PYTHON)
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 ObjectType As String
&apos;&apos;&apos; Only to enable object representation
ObjectType = &quot;SF_Session&quot;
End Property &apos; ScriptForge.SF_Session.ObjectType
REM -----------------------------------------------------------------------------
Property Get ServiceName As String
&apos;&apos;&apos; Internal use
ServiceName = &quot;ScriptForge.Session&quot;
End Property &apos; ScriptForge.SF_Array.ServiceName
REM -----------------------------------------------------------------------------
Property Get SCRIPTISAPPLICATION As String
&apos;&apos;&apos; Convenient constants
SCRIPTISAPPLICATION = cstSCRIPTISAPPLICATION
End Property &apos; ScriptForge.SF_Session.SCRIPTISAPPLICATION
REM -----------------------------------------------------------------------------
Property Get SCRIPTISEMBEDDED As String
&apos;&apos;&apos; Convenient constants
SCRIPTISEMBEDDED = cstSCRIPTISEMBEDDED
End Property &apos; ScriptForge.SF_Session.SCRIPTISEMBEDDED
REM -----------------------------------------------------------------------------
Property Get SCRIPTISOXT As String
&apos;&apos;&apos; Convenient constants
SCRIPTISOXT = cstSCRIPTISOXT
End Property &apos; ScriptForge.SF_Session.SCRIPTISOXT
REM -----------------------------------------------------------------------------
Property Get SCRIPTISPERSONAL As String
&apos;&apos;&apos; Convenient constants
SCRIPTISPERSONAL = cstSCRIPTISPERSONAL
End Property &apos; ScriptForge.SF_Session.SCRIPTISPERSONAL
REM -----------------------------------------------------------------------------
Property Get SCRIPTISPERSOXT As String
&apos;&apos;&apos; Convenient constants
SCRIPTISPERSOXT = cstSCRIPTISPERSOXT
End Property &apos; ScriptForge.SF_Session.SCRIPTISPERSOXT
REM -----------------------------------------------------------------------------
Property Get SCRIPTISSHARED As String
&apos;&apos;&apos; Convenient constants
SCRIPTISSHARED = cstSCRIPTISSHARED
End Property &apos; ScriptForge.SF_Session.SCRIPTISSHARED
REM -----------------------------------------------------------------------------
Property Get SCRIPTISSHAROXT As String
&apos;&apos;&apos; Convenient constants
SCRIPTISSHAROXT = cstSCRIPTISSHAROXT
End Property &apos; ScriptForge.SF_Session.SCRIPTISSHAROXT
REM ============================================================== PUBLIC METHODS
REM -----------------------------------------------------------------------------
Public Function ExecuteBasicScript(Optional ByVal Scope As Variant _
, Optional ByVal Script As Variant _
, ParamArray pvArgs As Variant _
) As Variant
&apos;&apos;&apos; Execute the Basic script given as a string and return the value returned by the script
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Scope: &quot;Application&quot; (default) or &quot;Document&quot; (NOT case-sensitive)
&apos;&apos;&apos; (or use one of the SCRIPTIS... public constants above)
&apos;&apos;&apos; Script: library.module.method (Case sensitive)
&apos;&apos;&apos; library =&gt; The library may be not loaded yet
&apos;&apos;&apos; module =&gt; Must not be a class module
&apos;&apos;&apos; method =&gt; Sub or Function
&apos;&apos;&apos; Read https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification
&apos;&apos;&apos; pvArgs: the arguments of the called script
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The value returned by the call to the script
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; NOSCRIPTERROR The script could not be found
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; session.ExecuteBasicScript(, &quot;XrayTool._Main.Xray&quot;, someuno) &apos; Sub: no return expected
Dim oScript As Object &apos; Script to be invoked
Dim vReturn As Variant &apos; Returned value
Const cstThisSub = &quot;Session.ExecuteBasicScript&quot;
Const cstSubArgs = &quot;[Scope], Script, arg0[, arg1] ...&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
vReturn = Empty
Check:
If IsMissing(Scope) Or IsEmpty(Scope) Then Scope = SCRIPTISAPPLICATION
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(Scope, &quot;Scope&quot;, V_STRING _
, Array(SCRIPTISAPPLICATION, SCRIPTISEMBEDDED)) Then GoTo Finally
If Not SF_Utils._Validate(Script, &quot;Script&quot;, V_STRING) Then GoTo Finally
End If
Try:
&apos; Execute script
Set oScript = SF_Session._GetScript(&quot;Basic&quot;, Scope, Script)
On Local Error GoTo CatchExec
If Not IsNull(oScript) Then vReturn = oScript.Invoke(pvArgs(), Array(), Array())
Finally:
ExecuteBasicScript = vReturn
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchExec:
SF_Exception.RaiseFatal(SCRIPTEXECERROR, &quot;Script&quot;, Script, Error$)
GoTo Finally
End Function &apos; ScriptForge.SF_Session.ExecuteBasicScript
REM -----------------------------------------------------------------------------
Public Function ExecuteCalcFunction(Optional ByVal CalcFunction As Variant _
, ParamArray pvArgs As Variant _
) As Variant
&apos;&apos;&apos; Execute a Calc function by its (english) name and based on the given arguments
&apos;&apos;&apos; Args:
&apos;&apos;&apos; CalcFunction: the english name of the function to execute
&apos;&apos;&apos; pvArgs: the arguments of the called function
&apos;&apos;&apos; Each argument must be either a string, a numeric value
&apos;&apos;&apos; or an array of arrays combining those types
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The (string or numeric) value or the array of arrays returned by the call to the function
&apos;&apos;&apos; When the arguments contain arrays, the function is executed as an array function
&apos;&apos;&apos; Wrong arguments generate an error
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; CALCFUNCERROR &apos; Execution error in calc function
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; session.ExecuteCalcFunction(&quot;AVERAGE&quot;, 1, 5, 3, 7) returns 4
&apos;&apos;&apos; session.ExecuteCalcFunction(&quot;ABS&quot;, Array(Array(-1,2,3),Array(4,-5,6),Array(7,8,-9)))(2)(2) returns 9
&apos;&apos;&apos; session.ExecuteCalcFunction(&quot;LN&quot;, -3) generates an error
Dim oCalc As Object &apos; Give access to the com.sun.star.sheet.FunctionAccess service
Dim vReturn As Variant &apos; Returned value
Const cstThisSub = &quot;Session.ExecuteCalcFunction&quot;
Const cstSubArgs = &quot;CalcFunction, arg0[, arg1] ...&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
vReturn = Empty
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(CalcFunction, &quot;CalcFunction&quot;, V_STRING) Then GoTo Finally
End If
Try:
&apos; Execute function
Set oCalc = SF_Utils._GetUNOService(&quot;FunctionAccess&quot;)
On Local Error GoTo CatchCall
vReturn = oCalc.callFunction(UCase(CalcFunction), pvArgs())
Finally:
ExecuteCalcFunction = vReturn
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchCall:
SF_Exception.RaiseFatal(CALCFUNCERROR, CalcFunction)
GoTo Finally
End Function &apos; ScriptForge.SF_Session.ExecuteCalcFunction
REM -----------------------------------------------------------------------------
Public Function ExecutePythonScript(Optional ByVal Scope As Variant _
, Optional ByVal Script As Variant _
, ParamArray pvArgs As Variant _
) As Variant
&apos;&apos;&apos; Execute the Python script given as a string and return the value returned by the script
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Scope: one of the SCRIPTIS... public constants above (default = &quot;share&quot;)
&apos;&apos;&apos; Script: (Case sensitive)
&apos;&apos;&apos; &quot;library/module.py$method&quot;
&apos;&apos;&apos; or &quot;module.py$method&quot;
&apos;&apos;&apos; or &quot;myExtension.oxt|myScript|module.py$method&quot;
&apos;&apos;&apos; library =&gt; The library may be not loaded yet
&apos;&apos;&apos; myScript =&gt; The directory containing the python module
&apos;&apos;&apos; module.py =&gt; The python module
&apos;&apos;&apos; method =&gt; The python function
&apos;&apos;&apos; Read https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification
&apos;&apos;&apos; pvArgs: the arguments of the called script
&apos;&apos;&apos; Date arguments are converted to iso format. However dates in arrays are not converted
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The value(s) returned by the call to the script. If &gt;1 values, enclosed in an array
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; NOSCRIPTERROR The script could not be found
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; session.ExecutePythonScript(session.SCRIPTISSHARED, &quot;Capitalise.py$getNewString&quot;, &quot;Abc&quot;) returns &quot;abc&quot;
Dim oScript As Object &apos; Script to be invoked
Dim vArg As Variant &apos; Individual argument
Dim vReturn As Variant &apos; Returned value
Dim i As Long
Const cstThisSub = &quot;Session.ExecutePythonScript&quot;
Const cstSubArgs = &quot;[Scope], Script, arg0[, arg1] ...&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
vReturn = Empty
Check:
If IsError(Scope) Or IsMissing(Scope) Then Scope = SCRIPTISSHARED
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(Scope, &quot;Scope&quot;, V_STRING _
, Array(SCRIPTISSHARED, SCRIPTISEMBEDDED, SCRIPTISPERSONAL, SCRIPTISSHAROXT, SCRIPTISPERSOXT, SCRIPTISOXT) _
) Then GoTo Finally
If Not SF_Utils._Validate(Script, &quot;Script&quot;, V_STRING) Then GoTo Finally
End If
Try:
&apos; Filter date arguments - NB: dates in arrays are not filtered
For i = 0 To UBound(pvArgs) &apos; pvArgs always zero-based
vArg = pvArgs(i)
If VarType(vArg) = V_DATE Then pvArgs(i) = SF_Utils._CDateToIso(vArg)
Next i
&apos; Find script
Set oScript = SF_Session._GetScript(&quot;Python&quot;, Scope, Script)
&apos; Execute script
If Not IsNull(oScript) Then
vReturn = oScript.Invoke(pvArgs(), Array(), Array())
&apos; Remove surrounding array when single returned value
If IsArray(vReturn) Then
If UBound(vReturn) = 0 Then vReturn = vReturn(0)
End If
End If
Finally:
ExecutePythonScript = vReturn
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Session.ExecutePythonScript
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
Const cstThisSub = &quot;Session.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:
Select Case UCase(PropertyName)
Case Else
End Select
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Session.GetProperty
REM -----------------------------------------------------------------------------
Public Function HasUnoMethod(Optional ByRef UnoObject As Variant _
, Optional ByVal MethodName As Variant _
) As Boolean
&apos;&apos;&apos; Returns True if a UNO object contains the given method
&apos;&apos;&apos; Code-snippet derived from XRAY
&apos;&apos;&apos; Args:
&apos;&apos;&apos; UnoObject: the object to identify
&apos;&apos;&apos; MethodName: the name of the method as a string. The search is case-sensitive
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; False when the method is not found or when an argument is invalid
Dim oIntrospect As Object &apos; com.sun.star.beans.Introspection
Dim oInspect As Object &apos; com.sun.star.beans.XIntrospectionAccess
Dim bMethod As Boolean &apos; Return value
Const cstThisSub = &quot;Session.HasUnoMethod&quot;
Const cstSubArgs = &quot;UnoObject, MethodName&quot;
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Check:
bMethod = False
If VarType(UnoObject) &lt;&gt; V_OBJECT Then GoTo Finally
If IsNull(UnoObject) Then GoTo Finally
If VarType(MethodName) &lt;&gt; V_STRING Then GoTo Finally
If MethodName = Space(Len(MethodName)) Then GoTo Finally
Try:
On Local Error GoTo Catch
Set oIntrospect = SF_Utils._GetUNOService(&quot;Introspection&quot;)
Set oInspect = oIntrospect.inspect(UnoObject)
bMethod = oInspect.hasMethod(MethodName, com.sun.star.beans.MethodConcept.ALL)
Finally:
HasUnoMethod = bMethod
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
On Local Error GoTo 0
GoTo Finally
End Function &apos; ScriptForge.SF_Session.HasUnoMethod
REM -----------------------------------------------------------------------------
Public Function HasUnoProperty(Optional ByRef UnoObject As Variant _
, Optional ByVal PropertyName As Variant _
) As Boolean
&apos;&apos;&apos; Returns True if a UNO object contains the given property
&apos;&apos;&apos; Code-snippet derived from XRAY
&apos;&apos;&apos; Args:
&apos;&apos;&apos; UnoObject: the object to identify
&apos;&apos;&apos; PropertyName: the name of the property as a string. The search is case-sensitive
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; False when the property is not found or when an argument is invalid
Dim oIntrospect As Object &apos; com.sun.star.beans.Introspection
Dim oInspect As Object &apos; com.sun.star.beans.XIntrospectionAccess
Dim bProperty As Boolean &apos; Return value
Const cstThisSub = &quot;Session.HasUnoProperty&quot;
Const cstSubArgs = &quot;UnoObject, PropertyName&quot;
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Check:
bProperty = False
If VarType(UnoObject) &lt;&gt; V_OBJECT Then GoTo Finally
If IsNull(UnoObject) Then GoTo Finally
If VarType(PropertyName) &lt;&gt; V_STRING Then GoTo Finally
If PropertyName = Space(Len(PropertyName)) Then GoTo Finally
Try:
On Local Error GoTo Catch
Set oIntrospect = SF_Utils._GetUNOService(&quot;Introspection&quot;)
Set oInspect = oIntrospect.inspect(UnoObject)
bProperty = oInspect.hasProperty(PropertyName, com.sun.star.beans.PropertyConcept.ALL)
Finally:
HasUnoProperty = bProperty
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
On Local Error GoTo 0
GoTo Finally
End Function &apos; ScriptForge.SF_Session.HasUnoProperty
REM -----------------------------------------------------------------------------
Public Function Methods() As Variant
&apos;&apos;&apos; Return the list of public methods of the Session service as an array
Methods = Array( _
&quot;ExecuteBasicScript&quot; _
, &quot;ExecuteCalcFunction&quot; _
, &quot;ExecutePythonScript&quot; _
, &quot;HasUnoMethod&quot; _
, &quot;HasUnoProperty&quot; _
, &quot;OpenURLInBrowser&quot; _
, &quot;RunApplication&quot; _
, &quot;SendMail&quot; _
, &quot;UnoMethods&quot; _
, &quot;UnoObjectType&quot; _
, &quot;UnoProperties&quot; _
, &quot;WebService&quot; _
)
End Function &apos; ScriptForge.SF_Session.Methods
REM -----------------------------------------------------------------------------
Public Sub OpenURLInBrowser(Optional ByVal URL As Variant)
&apos;&apos;&apos; Opens a URL in the default browser
&apos;&apos;&apos; Args:
&apos;&apos;&apos; URL: The URL to open in the browser
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; session.OpenURLInBrowser(&quot;https://docs.python.org/3/library/webbrowser.html&quot;)
Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_Session__OpenURLInBrowser&quot;
Const cstThisSub = &quot;Session.OpenURLInBrowser&quot;
Const cstSubArgs = &quot;URL&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(URL, &quot;URL&quot;, V_STRING) Then GoTo Finally
End If
Try:
ExecutePythonScript(SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper, URL)
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Sub
Catch:
GoTo Finally
End Sub &apos; ScriptForge.SF_Session.OpenURLInBrowser
REM -----------------------------------------------------------------------------
Public Function Properties() As Variant
&apos;&apos;&apos; Return the list or properties as an array
Properties = Array( _
)
End Function &apos; ScriptForge.SF_Session.Properties
REM -----------------------------------------------------------------------------
Public Function RunApplication(Optional ByVal Command As Variant _
, Optional ByVal Parameters As Variant _
) As Boolean
&apos;&apos;&apos; Executes an arbitrary system command
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Command: The command to execute
&apos;&apos;&apos; This may be an executable file or a document which is registered with an application
&apos;&apos;&apos; so that the system knows what application to launch for that document
&apos;&apos;&apos; Parameters: a list of space separated parameters as a single string
&apos;&apos;&apos; The method does not validate the given parameters, but only passes them to the specified command
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if success
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; session.RunApplication(&quot;Notepad.exe&quot;)
&apos;&apos;&apos; session.RunApplication(&quot;C:\myFolder\myDocument.odt&quot;)
&apos;&apos;&apos; session.RunApplication(&quot;kate&quot;, &quot;/home/me/install.txt&quot;) &apos; (Linux)
Dim bReturn As Boolean &apos; Returned value
Dim oShell As Object &apos; com.sun.star.system.SystemShellExecute
Dim sCommand As String &apos; Command as an URL
Const cstThisSub = &quot;Session.RunApplication&quot;
Const cstSubArgs = &quot;Command, [Parameters]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bReturn = False
Check:
If IsMissing(Parameters) Then Parameters = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._ValidateFile(Command, &quot;Command&quot;) Then GoTo Finally
If Not SF_Utils._Validate(Parameters, &quot;Parameters&quot;, V_STRING) Then GoTo Finally
End If
Try:
Set oShell = SF_Utils._GetUNOService(&quot;SystemShellExecute&quot;)
sCommand = SF_FileSystem._ConvertToUrl(Command)
oShell.execute(sCommand, Parameters, com.sun.star.system.SystemShellExecuteFlags.DEFAULTS)
bReturn = True
Finally:
RunApplication = bReturn
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Session.RunApplication
REM -----------------------------------------------------------------------------
Public Sub SendMail(Optional ByVal Recipient As Variant _
, Optional ByRef Cc As Variant _
, Optional ByRef Bcc As Variant _
, Optional ByVal Subject As Variant _
, Optional ByRef Body As Variant _
, Optional ByVal FileNames As Variant _
, Optional ByVal EditMessage As Variant _
)
&apos;&apos;&apos; Send a message (with or without attachments) to recipients from the user&apos;s mail client
&apos;&apos;&apos; The message may be edited by the user before sending or, alternatively, be sent immediately
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Recipient: an email addresses (To recipient)
&apos;&apos;&apos; Cc: a comma-delimited list of email addresses (carbon copy)
&apos;&apos;&apos; Bcc: a comma-delimited list of email addresses (blind carbon copy)
&apos;&apos;&apos; Subject: the header of the message
&apos;&apos;&apos; FileNames: a comma-separated list of filenames to attach to the mail. SF_FileSystem naming conventions apply
&apos;&apos;&apos; Body: the unformatted text of the message
&apos;&apos;&apos; EditMessage: when True (default) the message is editable before being sent
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; UNKNOWNFILEERROR File does not exist
&apos;&apos;&apos; WRONGEMAILERROR String not recognized as an email address
&apos;&apos;&apos; SENDMAILERROR System error, probably no mail client
Dim sEmail As String &apos; An single email address
Dim sFile As String &apos; A single file name
Dim sArg As String &apos; Argument name
Dim vCc As Variant &apos; Array alias of Cc
Dim vBcc As Variant &apos; Array alias of Bcc
Dim vFileNames As Variant &apos; Array alias of FileNames
Dim oMailService As Object &apos; com.sun.star.system.SimpleCommandMail or com.sun.star.system.SimpleSystemMail
Dim oMail As Object &apos; com.sun.star.system.XSimpleMailClient
Dim oMessage As Object &apos; com.sun.star.system.XSimpleMailMessage
Dim lFlag As Long &apos; com.sun.star.system.SimpleMailClientFlags.XXX
Dim ARR As Object : ARR = ScriptForge.SF_Array
Dim i As Long
Const cstComma = &quot;,&quot;, cstSemiColon = &quot;;&quot;
Const cstThisSub = &quot;Session.SendMail&quot;
Const cstSubArgs = &quot;Recipient, [Cc=&quot;&quot;&quot;&quot;], [Bcc=&quot;&quot;&quot;&quot;], [Subject=&quot;&quot;&quot;&quot;], [FileNames=&quot;&quot;&quot;&quot;], [Body=&quot;&quot;&quot;&quot;], [EditMessage=True]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
If IsMissing(Cc) Or IsEmpty(Cc) Then Cc = &quot;&quot;
If IsMissing(Bcc) Or IsEmpty(Bcc) Then Bcc = &quot;&quot;
If IsMissing(Subject) Or IsEmpty(Subject) Then Subject = &quot;&quot;
If IsMissing(FileNames) Or IsEmpty(FileNames) Then FileNames = &quot;&quot;
If IsMissing(Body) Or IsEmpty(Body) Then Body = &quot;&quot;
If IsMissing(EditMessage) Or IsEmpty(EditMessage) Then EditMessage = True
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(Cc, &quot;Recipient&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Cc, &quot;Cc&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Bcc, &quot;Bcc&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Subject, &quot;Subject&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(FileNames, &quot;FileNames&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Body, &quot;Body&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(EditMessage, &quot;EditMessage&quot;, V_BOOLEAN) Then GoTo Finally
End If
&apos; Check email addresses
sArg = &quot;Recipient&quot; : sEmail = Recipient
If Not SF_String.IsEmail(sEmail) Then GoTo CatchEmail
sArg = &quot;Cc&quot; : vCc = ARR.TrimArray(Split(Cc, cstComma))
For Each sEmail In vCc
If Not SF_String.IsEmail(sEmail) Then GoTo CatchEmail
Next sEmail
sArg = &quot;Bcc&quot; : vBcc = ARR.TrimArray(Split(Bcc, cstComma))
For Each sEmail In vBcc
If Not SF_String.IsEmail(sEmail) Then GoTo CatchEmail
Next sEmail
&apos; Check file existence
If Len(FileNames) &gt; 0 Then
vFileNames = ARR.TrimArray(Split(FileNames, cstComma))
For i = 0 To UBound(vFileNames)
sFile = vFileNames(i)
If Not SF_Utils._ValidateFile(sFile, &quot;FileNames&quot;) Then GoTo Finally
If Not SF_FileSystem.FileExists(sFile) Then GoTo CatchNotExists
vFileNames(i) = ConvertToUrl(sFile)
Next i
End If
Try:
&apos; Initialize the mail service
Set oMailService = SF_Utils._GetUNOService(&quot;MailService&quot;)
If IsNull(oMailService) Then GoTo CatchMail
Set oMail = oMailService.querySimpleMailClient()
If IsNull(oMail) Then GoTo CatchMail
Set oMessage = oMail.createSimpleMailMessage()
If IsNull(oMessage) Then GoTo CatchMail
&apos; Feed the new mail message
With oMessage
.setRecipient(Recipient)
If Subject &lt;&gt; &quot;&quot; Then .setSubject(Subject)
If UBound(vCc) &gt;= 0 Then .setCcRecipient(vCc)
If UBound(vBcc) &gt;= 0 Then .setBccRecipient(vBcc)
.Body = Iif(Len(Body) = 0, &quot; &quot;, Body) &apos; Body must not be the empty string ??
.setAttachement(vFileNames)
End With
lFlag = Iif(EditMessage, com.sun.star.system.SimpleMailClientFlags.DEFAULTS, com.sun.star.system.SimpleMailClientFlags.NO_USER_INTERFACE)
&apos; Send using the mail service
oMail.sendSimpleMailMessage(oMessage, lFlag)
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Sub
Catch:
GoTo Finally
CatchEmail:
SF_Exception.RaiseFatal(WRONGEMAILERROR, sArg, sEmail)
GoTo Finally
CatchNotExists:
SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileNames&quot;, sFile)
GoTo Finally
CatchMail:
SF_Exception.RaiseFatal(SENDMAILERROR)
GoTo Finally
End Sub &apos; ScriptForge.SF_Session.SendMail
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;Session.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_Session.SetProperty
REM -----------------------------------------------------------------------------
Public Function UnoMethods(Optional ByRef UnoObject As Variant) As Variant
&apos;&apos;&apos; Returns a list of the methods callable from an UNO object
&apos;&apos;&apos; Code-snippet derived from XRAY
&apos;&apos;&apos; Args:
&apos;&apos;&apos; UnoObject: the object to identify
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A zero-based sorted array. May be empty
Dim oIntrospect As Object &apos; com.sun.star.beans.Introspection
Dim oInspect As Object &apos; com.sun.star.beans.XIntrospectionAccess
Dim vMethods As Variant &apos; Array of com.sun.star.reflection.XIdlMethod
Dim vMethod As Object &apos; com.sun.star.reflection.XIdlMethod
Dim lMax As Long &apos; UBounf of vMethods
Dim vMethodsList As Variant &apos; Return value
Dim i As Long
Const cstThisSub = &quot;Session.UnoMethods&quot;
Const cstSubArgs = &quot;UnoObject&quot;
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Check:
vMethodsList = Array()
If VarType(UnoObject) &lt;&gt; V_OBJECT Then GoTo Finally
If IsNull(UnoObject) Then GoTo Finally
Try:
On Local Error GoTo Catch
Set oIntrospect = SF_Utils._GetUNOService(&quot;Introspection&quot;)
Set oInspect = oIntrospect.inspect(UnoObject)
vMethods = oInspect.getMethods(com.sun.star.beans.MethodConcept.ALL)
&apos; The names must be extracted from com.sun.star.reflection.XIdlMethod structures
lMax = UBound(vMethods)
If lMax &gt;= 0 Then
ReDim vMethodsList(0 To lMax)
For i = 0 To lMax
vMethodsList(i) = vMethods(i).Name
Next i
vMethodsList = SF_Array.Sort(vMethodsList, CaseSensitive := True)
End If
Finally:
UnoMethods = vMethodsList
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
On Local Error GoTo 0
GoTo Finally
End Function &apos; ScriptForge.SF_Session.UnoMethods
REM -----------------------------------------------------------------------------
Public Function UnoObjectType(Optional ByRef UnoObject As Variant) As String
&apos;&apos;&apos; Identify the UNO type of an UNO object
&apos;&apos;&apos; Code-snippet derived from XRAY
&apos;&apos;&apos; Args:
&apos;&apos;&apos; UnoObject: the object to identify
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; com.sun.star. ... as a string
&apos;&apos;&apos; a zero-length string if identification was not successful
Dim oService As Object &apos; com.sun.star.reflection.CoreReflection
Dim vClass as Variant &apos; com.sun.star.reflection.XIdlClass
Dim sObjectType As String &apos; Return value
Const cstThisSub = &quot;Session.UnoObjectType&quot;
Const cstSubArgs = &quot;UnoObject&quot;
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Check:
sObjectType = &quot;&quot;
If VarType(UnoObject) &lt;&gt; V_OBJECT Then GoTo Finally
If IsNull(UnoObject) Then GoTo Finally
Try:
On Local Error Resume Next
&apos; Try usual ImplementationName method
sObjectType = UnoObject.getImplementationName()
If sObjectType = &quot;&quot; Then
&apos; Now try CoreReflection trick
Set oService = SF_Utils._GetUNOService(&quot;CoreReflection&quot;)
vClass = oService.getType(UnoObject)
If vClass.TypeClass &gt;= com.sun.star.uno.TypeClass.STRUCT Then sObjectType = vClass.Name
End If
Finally:
UnoObjectType = sObjectType
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Session.UnoObjectType
REM -----------------------------------------------------------------------------
Public Function UnoProperties(Optional ByRef UnoObject As Variant) As Variant
&apos;&apos;&apos; Returns a list of the properties of an UNO object
&apos;&apos;&apos; Code-snippet derived from XRAY
&apos;&apos;&apos; Args:
&apos;&apos;&apos; UnoObject: the object to identify
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A zero-based sorted array. May be empty
Dim oIntrospect As Object &apos; com.sun.star.beans.Introspection
Dim oInspect As Object &apos; com.sun.star.beans.XIntrospectionAccess
Dim vProperties As Variant &apos; Array of com.sun.star.beans.Property
Dim vProperty As Object &apos; com.sun.star.beans.Property
Dim lMax As Long &apos; UBounf of vProperties
Dim vPropertiesList As Variant &apos; Return value
Dim i As Long
Const cstThisSub = &quot;Session.UnoProperties&quot;
Const cstSubArgs = &quot;UnoObject&quot;
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Check:
vPropertiesList = Array()
If VarType(UnoObject) &lt;&gt; V_OBJECT Then GoTo Finally
If IsNull(UnoObject) Then GoTo Finally
Try:
On Local Error GoTo Catch
Set oIntrospect = SF_Utils._GetUNOService(&quot;Introspection&quot;)
Set oInspect = oIntrospect.inspect(UnoObject)
vProperties = oInspect.getProperties(com.sun.star.beans.PropertyConcept.ALL)
&apos; The names must be extracted from com.sun.star.beans.Property structures
lMax = UBound(vProperties)
If lMax &gt;= 0 Then
ReDim vPropertiesList(0 To lMax)
For i = 0 To lMax
vPropertiesList(i) = vProperties(i).Name
Next i
vPropertiesList = SF_Array.Sort(vPropertiesList, CaseSensitive := True)
End If
Finally:
UnoProperties = vPropertiesList
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
On Local Error GoTo 0
GoTo Finally
End Function &apos; ScriptForge.SF_Session.UnoProperties
REM -----------------------------------------------------------------------------
Public Function WebService(Optional ByVal URI As Variant) As String
&apos;&apos;&apos; Get some web content from a URI
&apos;&apos;&apos; Args:
&apos;&apos;&apos; URI: URI text of the web service
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The web page content of the URI
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; CALCFUNCERROR
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; session.WebService(&quot;wiki.documentfoundation.org/api.php?&quot; _
&apos;&apos;&apos; &amp; &quot;hidebots=1&amp;days=7&amp;limit=50&amp;action=feedrecentchanges&amp;feedformat=rss&quot;)
Dim sReturn As String &apos; Returned value
Const cstThisSub = &quot;Session.WebService&quot;
Const cstSubArgs = &quot;URI&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
sReturn = &quot;&quot;
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(URI, &quot;URI&quot;, V_STRING) Then GoTo Finally
End If
Try:
sReturn = SF_Session.ExecuteCalcFunction(&quot;WEBSERVICE&quot;, URI)
Finally:
WebService = sReturn
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Session.WebService
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
Private Function _GetScript(ByVal psLanguage As String _
, ByVal psScope As String _
, ByVal psScript As String _
) As Object
&apos;&apos;&apos; Get the adequate script provider and from there the requested script
&apos;&apos;&apos; Called by ExecuteBasicScript() and ExecutePythonScript()
&apos;&apos;&apos; The execution of the script is done by the caller
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psLanguage: Basic or Python
&apos;&apos;&apos; psScope: one of the SCRIPTISxxx constants
&apos;&apos;&apos; The SCRIPTISOXT constant is an alias for 2 cases, extension either
&apos;&apos;&apos; installed for one user only, or for all users
&apos;&apos;&apos; Managed here by trial and error
&apos;&apos;&apos; psScript: Read https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; A com.sun.star.script.provider.XScript object
Dim sScript As String &apos; The complete script string
Dim oScriptProvider As Object &apos; Script provider singleton
Dim oScript As Object &apos; Return value
Const cstScript1 = &quot;vnd.sun.star.script:&quot;
Const cstScript2 = &quot;?language=&quot;
Const cstScript3 = &quot;&amp;location=&quot;
Try:
&apos; Build script string
sScript = cstScript1 &amp; psScript &amp; cstScript2 &amp; psLanguage &amp; cstScript3 &amp; LCase(psScope)
&apos; Find script
Set oScript = Nothing
&apos; Python only: installation of extension is determined by user =&gt; unknown to script author
If psScope = SCRIPTISOXT Then &apos; =&gt; Trial and error
On Local Error GoTo ForAllUsers
sScript = cstScript1 &amp; psScript &amp; cstScript2 &amp; psLanguage &amp; cstScript3 &amp; SCRIPTISPERSOXT
Set oScriptProvider = SF_Utils._GetUNOService(&quot;ScriptProvider&quot;, SCRIPTISPERSOXT)
Set oScript = oScriptProvider.getScript(sScript)
End If
ForAllUsers:
On Local Error GoTo CatchNotFound
If IsNull(oScript) Then
If psScope = SCRIPTISOXT Then psScope = SCRIPTISSHAROXT
Set oScriptProvider = SF_Utils._GetUNOService(&quot;ScriptProvider&quot;, psScope)
Set oScript = oScriptProvider.getScript(sScript)
End If
Finally:
_GetScript = oScript
Exit Function
CatchNotFound:
SF_Exception.RaiseFatal(NOSCRIPTERROR, psLanguage, &quot;Scope&quot;, psScope, &quot;Script&quot;, psScript)
GoTo Finally
End Function &apos; ScriptForge.SF_Session._GetScript
REM =============================================== END OF SCRIPTFORGE.SF_SESSION
</script:module>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,701 @@
<?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;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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
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:
&apos;TODO: SF_Exception.RaiseFatal(FILEWRITEMODEERROR, cstThisSub)
MsgBox &quot;END OF FILE ERROR !!&quot;
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:
&apos;TODO: SF_Exception.RaiseFatal(FILEWRITEMODEERROR, cstThisSub)
MsgBox &quot;END OF FILE ERROR !!&quot;
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:
&apos;TODO: SF_Exception.RaiseFatal(FILEWRITEMODEERROR, cstThisSub)
MsfBox &quot;END OF FILE ERROR !!&quot;
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 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 = _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,463 @@
<?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;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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 = ( _TimerStatus = STATUSSTARTED Or _TimerStatus = STATUSSUSPENDED )
Case UCase(&quot;IsSuspended&quot;)
_PropertyGet = ( _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>

File diff suppressed because it is too large Load Diff

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_Utils" 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 Explicit
Option Private Module
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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_Utils
&apos;&apos;&apos; ========
&apos;&apos;&apos; FOR INTERNAL USE ONLY
&apos;&apos;&apos; Groups all private functions used by the official modules
&apos;&apos;&apos; Declares the Global variable _SF_
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&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 ===================================================================== GLOBALS
Global _SF_ As Variant &apos; SF_Root (Basic) object)
&apos;&apos;&apos; ScriptForge version
Const SF_Version = &quot;7.1&quot;
&apos;&apos;&apos; Standard symbolic names for VarTypes
&apos; V_EMPTY = 0
&apos; V_NULL = 1
&apos; V_INTEGER = 2
&apos; V_LONG = 3
&apos; V_SINGLE = 4
&apos; V_DOUBLE = 5
&apos; V_CURRENCY = 6
&apos; V_DATE = 7
&apos; V_STRING = 8
&apos;&apos;&apos; Additional symbolic names for VarTypes
Global Const V_OBJECT = 9
Global Const V_BOOLEAN = 11
Global Const V_VARIANT = 12
Global Const V_BYTE = 17
Global Const V_USHORT = 18
Global Const V_ULONG = 19
Global Const V_BIGINT = 35
Global Const V_DECIMAL = 37
Global Const V_ARRAY = 8192
Global Const V_NUMERIC = 99 &apos; Fictive VarType synonym of any numeric value
REM ================================================================== EXCEPTIONS
Const MISSINGARGERROR = &quot;MISSINGARGERROR&quot; &apos; A mandatory argument is missing
Const ARGUMENTERROR = &quot;ARGUMENTERROR&quot; &apos; An argument does not pass the _Validate() validation
Const ARRAYERROR = &quot;ARRAYERROR&quot; &apos; An argument does not pass the _ValidateArray() validation
Const FILEERROR = &quot;FILEERROR&quot; &apos; An argument does not pass the _ValidateFile() validation
REM =========================================pvA==================== PRIVATE METHODS
REM -----------------------------------------------------------------------------
Public Function _CDateToIso(pvDate As Variant) As Variant
&apos;&apos;&apos; Returns a string representation of the given Basic date
&apos;&apos;&apos; Dates as strings are essential in property values, where Basic dates are evil
Dim sIsoDate As Variant &apos; Return value
If VarType(pvDate) = V_DATE Then
If Year(pvDate) &lt; 1900 Then &apos; Time only
sIsoDate = Right(&quot;0&quot; &amp; Hour(pvDate), 2) &amp; &quot;:&quot; &amp; Right(&quot;0&quot; &amp; Minute(pvDate), 2) &amp; &quot;:&quot; &amp; Right(&quot;0&quot; &amp; Second(pvDate), 2)
ElseIf Hour(pvDate) + Minute(pvDate) + Second(pvDate) = 0 Then &apos; Date only
sIsoDate = Year(pvDate) &amp; &quot;-&quot; &amp; Right(&quot;0&quot; &amp; Month(pvDate), 2) &amp; &quot;-&quot; &amp; Right(&quot;0&quot; &amp; Day(pvDate), 2)
Else
sIsoDate = Year(pvDate) &amp; &quot;-&quot; &amp; Right(&quot;0&quot; &amp; Month(pvDate), 2) &amp; &quot;-&quot; &amp; Right(&quot;0&quot; &amp; Day(pvDate), 2) _
&amp; &quot; &quot; &amp; Right(&quot;0&quot; &amp; Hour(pvDate), 2) &amp; &quot;:&quot; &amp; Right(&quot;0&quot; &amp; Minute(pvDate), 2) _
&amp; &quot;:&quot; &amp; Right(&quot;0&quot; &amp; Second(pvDate), 2)
End If
Else
sIsoDate = pvDate
End If
_CDateToIso = sIsoDate
End Function &apos; ScriptForge.SF_Utils._CDateToIso
REM -----------------------------------------------------------------------------
Public Function _CDateToUnoDate(pvDate As Variant) As Variant
&apos;&apos;&apos; Returns a UNO com.sun.star.util.DateTime/Date/Time object depending on the given date
&apos;&apos;&apos; by using the appropriate CDateToUnoDateXxx builtin function
&apos;&apos;&apos; UNO dates are essential in property values, where Basic dates are evil
Dim vUnoDate As Variant &apos; Return value
If VarType(pvDate) = V_DATE Then
If Year(pvDate) &lt; 1900 Then
vUnoDate = CDateToUnoTime(pvDate)
ElseIf Hour(pvDate) + Minute(pvDate) + Second(pvDate) = 0 Then
vUnoDate = CDateToUnoDate(pvDate)
Else
vUnoDate = CDateToUnoDateTime(pvDate)
End If
Else
vUnoDate = pvDate
End If
_CDateToUnoDate = vUnoDate
End Function &apos; ScriptForge.SF_Utils._CDateToUnoDate
REM -----------------------------------------------------------------------------
Public Function _CPropertyValue(ByRef pvValue As Variant) As Variant
&apos;&apos;&apos; Set a value of a correct type in a com.sun.star.beans.PropertyValue
&apos;&apos;&apos; Date BASIC variables give error. Change them to UNO types
&apos;&apos;&apos; Empty arrays should be replaced by Null
Dim vValue As Variant &apos; Return value
If VarType(pvValue) = V_DATE Then
vValue = SF_Utils._CDateToUnoDate(pvValue)
ElseIf IsArray(pvValue) Then
If UBound(pvValue, 1) &lt; LBound(pvValue, 1) Then vValue = Null Else vValue = pvValue
Else
vValue = pvValue
End If
_CPropertyValue() = vValue
End Function &apos; ScriptForge.SF_Utils._CPropertyValue
REM -----------------------------------------------------------------------------
Public Function _CStrToDate(ByRef pvStr As String) As Date
&apos;&apos;&apos; Attempt to convert the input string to a Date variable with the CDate builtin function
&apos;&apos;&apos; If not successful, returns conventionally -1 (29/12/1899)
&apos;&apos;&apos; Date patterns: YYYY-MM-DD, HH:MM:DD and YYYY-MM-DD HH:MM:DD
Dim dDate As Date &apos; Return value
Const cstNoDate = -1
dDate = cstNoDate
Try:
On Local Error Resume Next
dDate = CDate(pvStr)
Finally:
_CStrToDate = dDate
Exit Function
End Function &apos; ScriptForge.SF_Utils._CStrToDate
REM -----------------------------------------------------------------------------
Public Function _EnterFunction(ByVal psSub As String, Optional ByVal psArgs As String)
&apos;&apos;&apos; Called on top of each public function
&apos;&apos;&apos; Used to trace routine in/outs (debug mode)
&apos;&apos;&apos; and to allow the explicit mention of the user call which caused an error
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psSub = the called Sub/Function/Property, usually something like &quot;service.sub&quot;
&apos;&apos;&apos; Return: True when psSub is called from a user script
&apos;&apos;&apos; Used to bypass the validation of the arguments when unnecessary
If IsEmpty(_SF_) Or IsNull(_SF_) Then SF_Utils._InitializeRoot() &apos; First use of ScriptForge during current LibO session
If IsMissing(psArgs) Then psArgs = &quot;&quot;
With _SF_
If .StackLevel = 0 Then
.MainFunction = psSub
.MainFunctionArgs = psArgs
_EnterFunction = True
Else
_EnterFunction = False
End If
.StackLevel = .StackLevel + 1
If .DebugMode Then ._AddToConsole(&quot;==&gt; &quot; &amp; psSub &amp; &quot;(&quot; &amp; .StackLevel &amp; &quot;)&quot;)
End With
End Function &apos; ScriptForge.SF_Utils._EnterFunction
REM -----------------------------------------------------------------------------
Public Function _ErrorHandling(Optional ByVal pbErrorHandler As Boolean) As Boolean
&apos;&apos;&apos; Error handling is normally ON and can be set OFF for debugging purposes
&apos;&apos;&apos; Each user visible routine starts with a call to this function to enable/disable
&apos;&apos;&apos; standard handling of internal errors
&apos;&apos;&apos; Args:
&apos;&apos;&apos; pbErrorHandler = if present, set its value
&apos;&apos;&apos; Return: the current value of the error handler
If IsEmpty(_SF_) Or IsNull(_SF_) Then SF_Utils._InitializeRoot() &apos; First use of ScriptForge during current LibO session
If Not IsMissing(pbErrorHandler) Then _SF_.ErrorHandler = pbErrorHandler
_ErrorHandling = _SF_.ErrorHandler
End Function &apos; ScriptForge.SF_Utils._ErrorHandling
REM -----------------------------------------------------------------------------
Public Sub _ExitFunction(ByVal psSub As String)
&apos;&apos;&apos; Called in the Finally block of each public function
&apos;&apos;&apos; Manage ScriptForge internal aborts
&apos;&apos;&apos; Resets MainFunction (root) when exiting the method called by a user script
&apos;&apos;&apos; Used to trace routine in/outs (debug mode)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psSub = the called Sub/Function/Property, usually something like &quot;service.sub&quot;
If IsEmpty(_SF_) Or IsNull(_SF_) Then SF_Utils._InitializeRoot() &apos; Useful only when current module has been recompiled
With _SF_
If Err &gt; 0 Then
SF_Exception.RaiseAbort(psSub)
End If
If .StackLevel = 1 Then
.MainFunction = &quot;&quot;
.MainFunctionArgs = &quot;&quot;
End If
If .DebugMode Then ._AddToConsole(&quot;&lt;== &quot; &amp; psSub &amp; &quot;(&quot; &amp; .StackLevel &amp; &quot;)&quot;)
If .StackLevel &gt; 0 Then .StackLevel = .StackLevel - 1
End With
End Sub &apos; ScriptForge.SF_Utils._ExitFunction
REM -----------------------------------------------------------------------------
Public Sub _ExportScriptForgePOTFile(ByVal FileName As String)
&apos;&apos;&apos; Export the ScriptForge POT file related to its own user interface
&apos;&apos;&apos; Should be called only before issuing new ScriptForge releases only
&apos;&apos;&apos; Args:
&apos;&apos;&apos; FileName: the resulting file. If it exists, is overwritten without warning
Dim sHeader As String &apos; The specific header to insert
sHeader = &quot;&quot; _
&amp; &quot;*********************************************************************\n&quot; _
&amp; &quot;*** The ScriptForge library and its associated libraries ***\n&quot; _
&amp; &quot;*** are part of the LibreOffice project. ***\n&quot; _
&amp; &quot;*********************************************************************\n&quot; _
&amp; &quot;\n&quot; _
&amp; &quot;ScriptForge Release &quot; &amp; SF_Version &amp; &quot;\n&quot; _
&amp; &quot;-----------------------&quot;
Try:
With _SF_
.Interface.ExportToPOTFile(FileName, Header := sHeader)
End With
Finally:
Exit Sub
End Sub &apos; ScriptForge.SF_Utils._ExportScriptForgePOTFile
REM -----------------------------------------------------------------------------
Public Function _GetPropertyValue(ByRef pvArgs As Variant, ByVal psName As String) As Variant
&apos;&apos;&apos; Returns the Value corresponding to the given name
&apos;&apos;&apos; Args
&apos;&apos;&apos; pvArgs: a zero_based array of PropertyValues
&apos;&apos;&apos; psName: the comparison is not case-sensitive
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; Zero-length string if not found
Dim vValue As Variant &apos; Return value
Dim i As Long
vValue = &quot;&quot;
If IsArray(pvArgs) Then
For i = LBound(pvArgs) To UBound(pvArgs)
If UCase(psName) = UCase(pvArgs(i).Name) Then
vValue = pvArgs(i).Value
Exit For
End If
Next i
End If
_GetPropertyValue = vValue
End Function &apos; ScriptForge.SF_Utils._GetPropertyValue
REM -----------------------------------------------------------------------------
Public Function _GetRegistryKeyContent(ByVal psKeyName as string _
, Optional pbForUpdate as Boolean _
) As Variant
&apos;&apos;&apos; Implement a ConfigurationProvider service
&apos;&apos;&apos; Derived from the Tools library
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psKeyName: the name of the node in the configuration tree
&apos;&apos;&apos; pbForUpdate: default = False
Dim oConfigProvider as Object &apos; com.sun.star.configuration.ConfigurationProvider
Dim vNodePath(0) as New com.sun.star.beans.PropertyValue
Dim sConfig As String &apos; One of next 2 constants
Const cstConfig = &quot;com.sun.star.configuration.ConfigurationAccess&quot;
Const cstConfigUpdate = &quot;com.sun.star.configuration.ConfigurationUpdateAccess&quot;
Set oConfigProvider = _GetUNOService(&quot;ConfigurationProvider&quot;)
vNodePath(0).Name = &quot;nodepath&quot;
vNodePath(0).Value = psKeyName
If IsMissing(pbForUpdate) Then pbForUpdate = False
If pbForUpdate Then sConfig = cstConfigUpdate Else sConfig = cstConfig
Set _GetRegistryKeyContent = oConfigProvider.createInstanceWithArguments(sConfig, vNodePath())
End Function &apos; ScriptForge.SF_Utils._GetRegistryKeyContent
REM -----------------------------------------------------------------------------
Public Function _GetUNOService(ByVal psService As String _
, Optional ByVal pvArg As Variant _
) As Object
&apos;&apos;&apos; Create a UNO service
&apos;&apos;&apos; Each service is called only once
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psService: shortcut to service
&apos;&apos;&apos; pvArg: some services might require an argument
Dim sLocale As String &apos; fr-BE f.i.
Dim oConfigProvider As Object
Dim oDefaultContext As Object
Dim vNodePath As Variant
Set _GetUNOService = Nothing
With _SF_
Select Case psService
Case &quot;BrowseNodeFactory&quot;
Set oDefaultContext = GetDefaultContext()
If Not IsNull(oDefaultContext) Then Set _GetUNOService = oDefaultContext.getValueByName(&quot;/singletons/com.sun.star.script.browse.theBrowseNodeFactory&quot;)
Case &quot;CharacterClass&quot;
If IsEmpty(.CharacterClass) Or IsNull(.CharacterClass) Then
Set .CharacterClass = CreateUnoService(&quot;com.sun.star.i18n.CharacterClassification&quot;)
End If
Set _GetUNOService = .CharacterClass
Case &quot;ConfigurationProvider&quot;
If IsEmpty(.ConfigurationProvider) Or IsNull(.ConfigurationProvider) Then
Set .ConfigurationProvider = CreateUnoService(&quot;com.sun.star.configuration.ConfigurationProvider&quot;)
End If
Set _GetUNOService = .ConfigurationProvider
Case &quot;CoreReflection&quot;
If IsEmpty(.CoreReflection) Or IsNull(.CoreReflection) Then
Set .CoreReflection = CreateUnoService(&quot;com.sun.star.reflection.CoreReflection&quot;)
End If
Set _GetUNOService = .CoreReflection
Case &quot;DatabaseContext&quot;
If IsEmpty(.DatabaseContext) Or IsNull(.DatabaseContext) Then
Set .DatabaseContext = CreateUnoService(&quot;com.sun.star.sdb.DatabaseContext&quot;)
End If
Set _GetUNOService = .DatabaseContext
Case &quot;DispatchHelper&quot;
If IsEmpty(.DispatchHelper) Or IsNull(.DispatchHelper) Then
Set .DispatchHelper = CreateUnoService(&quot;com.sun.star.frame.DispatchHelper&quot;)
End If
Set _GetUNOService = .DispatchHelper
Case &quot;FileAccess&quot;
If IsEmpty(.FileAccess) Or IsNull(.FileAccess) Then
Set .FileAccess = CreateUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
End If
Set _GetUNOService = .FileAccess
Case &quot;FilePicker&quot;
If IsEmpty(.FilePicker) Or IsNull(.FilePicker) Then
Set .FilePicker = CreateUnoService(&quot;com.sun.star.ui.dialogs.FilePicker&quot;)
End If
Set _GetUNOService = .FilePicker
Case &quot;FilterFactory&quot;
If IsEmpty(.FilterFactory) Or IsNull(.FilterFactory) Then
Set .FilterFactory = CreateUnoService(&quot;com.sun.star.document.FilterFactory&quot;)
End If
Set _GetUNOService = .FilterFactory
Case &quot;FolderPicker&quot;
If IsEmpty(.FolderPicker) Or IsNull(.FolderPicker) Then
Set .FolderPicker = CreateUnoService(&quot;com.sun.star.ui.dialogs.FolderPicker&quot;)
End If
Set _GetUNOService = .FolderPicker
Case &quot;FunctionAccess&quot;
If IsEmpty(.FunctionAccess) Or IsNull(.FunctionAccess) Then
Set .FunctionAccess = CreateUnoService(&quot;com.sun.star.sheet.FunctionAccess&quot;)
End If
Set _GetUNOService = .FunctionAccess
Case &quot;Introspection&quot;
If IsEmpty(.Introspection) Or IsNull(.Introspection) Then
Set .Introspection = CreateUnoService(&quot;com.sun.star.beans.Introspection&quot;)
End If
Set _GetUNOService = .Introspection
Case &quot;Locale&quot;
If IsEmpty(.Locale) Or IsNull(.Locale) Then
.Locale = CreateUnoStruct(&quot;com.sun.star.lang.Locale&quot;)
&apos; Derived from the Tools library
Set oConfigProvider = createUnoService(&quot;com.sun.star.configuration.ConfigurationProvider&quot;)
vNodePath = Array() : ReDim vNodePath(0)
vNodePath(0) = New com.sun.star.beans.PropertyValue
vNodePath(0).Name = &quot;nodepath&quot; : vNodePath(0).Value = &quot;org.openoffice.Setup/L10N&quot;
sLocale = oConfigProvider.createInstanceWithArguments(&quot;com.sun.star.configuration.ConfigurationAccess&quot;, vNodePath()).getByName(&quot;ooLocale&quot;)
.Locale.Language = Left(sLocale, 2)
.Locale.Country = Right(sLocale, 2)
End If
Set _GetUNOService = .Locale
Case &quot;MacroExpander&quot;
Set oDefaultContext = GetDefaultContext()
If Not IsNull(oDefaultContext) Then Set _GetUNOService = oDefaultContext.getValueByName(&quot;/singletons/com.sun.star.util.theMacroExpander&quot;)
Case &quot;MailService&quot;
If IsEmpty(.MailService) Or IsNull(.MailService) Then
If GetGuiType = 1 Then &apos; Windows
Set .MailService = CreateUnoService(&quot;com.sun.star.system.SimpleSystemMail&quot;)
Else
Set .MailService = CreateUnoService(&quot;com.sun.star.system.SimpleCommandMail&quot;)
End If
End If
Set _GetUNOService = .MailService
Case &quot;PathSettings&quot;
If IsEmpty(.PathSettings) Or IsNull(.PathSettings) Then
Set .PathSettings = CreateUnoService(&quot;com.sun.star.util.PathSettings&quot;)
End If
Set _GetUNOService = .PathSettings
Case &quot;PathSubstitution&quot;
If IsEmpty(.PathSubstitution) Or IsNull(.PathSubstitution) Then
Set .PathSubstitution = CreateUnoService(&quot;com.sun.star.util.PathSubstitution&quot;)
End If
Set _GetUNOService = .PathSubstitution
Case &quot;ScriptProvider&quot;
If IsMissing(pvArg) Then pvArg = SF_Session.SCRIPTISAPPLICATION
Select Case LCase(pvArg)
Case SF_Session.SCRIPTISEMBEDDED &apos; Document
If Not IsNull(ThisComponent) Then Set _GetUNOService = ThisComponent.getScriptProvider()
Case Else
If IsEmpty(.ScriptProvider) Or IsNull(.ScriptProvider) Then
Set .ScriptProvider = _
CreateUnoService(&quot;com.sun.star.script.provider.MasterScriptProviderFactory&quot;).createScriptProvider(&quot;&quot;)
End If
Set _GetUNOService = .ScriptProvider
End Select
Case &quot;SearchOptions&quot;
If IsEmpty(.SearchOptions) Or IsNull(.SearchOptions) Then
Set .SearchOptions = New com.sun.star.util.SearchOptions
With .SearchOptions
.algorithmType = com.sun.star.util.SearchAlgorithms.REGEXP
.searchFlag = 0
End With
End If
Set _GetUNOService = .SearchOptions
Case &quot;SystemShellExecute&quot;
If IsEmpty(.SystemShellExecute) Or IsNull(.SystemShellExecute) Then
Set .SystemShellExecute = CreateUnoService(&quot;com.sun.star.system.SystemShellExecute&quot;)
End If
Set _GetUNOService = .SystemShellExecute
Case &quot;TextSearch&quot;
If IsEmpty(.TextSearch) Or IsNull(.TextSearch) Then
Set .TextSearch = CreateUnoService(&quot;com.sun.star.util.TextSearch&quot;)
End If
Set _GetUNOService = .TextSearch
Case &quot;URLTransformer&quot;
If IsEmpty(.URLTransformer) Or IsNull(.URLTransformer) Then
Set .URLTransformer = CreateUnoService(&quot;com.sun.star.util.URLTransformer&quot;)
End If
Set _GetUNOService = .URLTransformer
Case Else
End Select
End With
End Function &apos; ScriptForge.SF_Utils._GetUNOService
REM -----------------------------------------------------------------------------
Public Sub _InitializeRoot(Optional ByVal pbForce As Boolean)
&apos;&apos;&apos; Initialize _SF_ as SF_Root basic object
&apos;&apos;&apos; Args:
&apos;&apos;&apos; pbForce = True forces the reinit (default = False)
If IsMissing(pbForce) Then pbForce = False
If pbForce Then Set _SF_ = Nothing
If IsEmpty(_SF_) Or IsNull(_SF_) Then
Set _SF_ = New SF_Root
Set _SF_.[Me] = _SF_
&apos; Localization
_SF_._LoadLocalizedInterface()
End If
End Sub &apos; ScriptForge.SF_Utils._InitializeRoot
REM -----------------------------------------------------------------------------
Public Function _MakePropertyValue(ByVal psName As String _
, ByRef pvValue As Variant _
) As com.sun.star.beans.PropertyValue
&apos;&apos;&apos; Create and return a new com.sun.star.beans.PropertyValue
Dim oPropertyValue As New com.sun.star.beans.PropertyValue
With oPropertyValue
.Name = psName
.Value = SF_Utils._CPropertyValue(pvValue)
End With
_MakePropertyValue() = oPropertyValue
End Function &apos; ScriptForge.SF_Utils._MakePropertyValue
REM -----------------------------------------------------------------------------
Public Function _Repr(ByVal pvArg As Variant, Optional ByVal plMax As Long) As String
&apos;&apos;&apos; Convert pvArg into a readable string (truncated if length &gt; plMax)
&apos;&apos;&apos; Args
&apos;&apos;&apos; pvArg: may be of any type
&apos;&apos;&apos; plMax: maximum length of the resulting string (default = 32K)
Dim sArg As String &apos; Return value
Dim oObject As Object &apos; Alias of argument to avoid &quot;Object variable not set&quot;
Dim sObject As String &apos; Object representation
Dim sObjectType As String &apos; ObjectType attribute of Basic objects
Dim sLength As String &apos; String length as a string
Dim i As Long
Const cstBasicObject = &quot;com.sun.star.script.NativeObjectWrapper&quot;
Const cstMaxLength = 2^15 - 1 &apos; 32767
Const cstByteLength = 25
Const cstEtc = &quot; &quot;
If IsMissing(plMax) Or plMax = 0 Then plMax = cstMaxLength
If IsArray(pvArg) Then
sArg = SF_Array._Repr(pvArg)
Else
Select Case VarType(pvArg)
Case V_EMPTY : sArg = &quot;[EMPTY]&quot;
Case V_NULL : sArg = &quot;[NULL]&quot;
Case V_OBJECT
If IsNull(pvArg) Then
sArg = &quot;[NULL]&quot;
Else
sObject = SF_Session.UnoObjectType(pvArg)
If sObject = &quot;&quot; Or sObject = cstBasicObject Then &apos; Not a UNO object
&apos; Test if argument is a ScriptForge object
sObjectType = &quot;&quot;
On Local Error Resume Next
Set oObject = pvArg
sObjectType = oObject.ObjectType
On Error GoTo 0
If sObjectType = &quot;&quot; Then
sArg = &quot;[OBJECT]&quot;
ElseIf Left(sObjectType, 3) = &quot;SF_&quot; Then
sArg = &quot;[&quot; &amp; sObjectType &amp; &quot;]&quot;
Else
sArg = oObject._Repr()
End If
Else
sArg = &quot;[&quot; &amp; sObject &amp; &quot;]&quot;
End If
End If
Case V_VARIANT : sArg = &quot;[VARIANT]&quot;
Case V_STRING
sArg = SF_String._Repr(pvArg)
Case V_BOOLEAN : sArg = Iif(pvArg, &quot;[TRUE]&quot;, &quot;[FALSE]&quot;)
Case V_BYTE : sArg = Right(&quot;00&quot; &amp; Hex(pvArg), 2)
Case V_SINGLE, V_DOUBLE, V_CURRENCY
sArg = Format(pvArg)
If InStr(1, sArg, &quot;E&quot;, 1) = 0 Then sArg = Format(pvArg, &quot;##0.0##&quot;)
sArg = Replace(sArg, &quot;,&quot;, &quot;.&quot;) &apos;Force decimal point
Case V_BIGINT : sArg = CStr(CLng(pvArg))
Case V_DATE : sArg = _CDateToIso(pvArg)
Case Else : sArg = CStr(pvArg)
End Select
End If
If Len(sArg) &gt; plMax Then
sLength = &quot;(&quot; &amp; Len(sArg) &amp; &quot;)&quot;
sArg = Left(sArg, plMax - Len(cstEtc) - Len(slength)) &amp; cstEtc &amp; sLength
End If
_Repr = sArg
End Function &apos; ScriptForge.SF_Utils._Repr
REM -----------------------------------------------------------------------------
Private Function _ReprValues(Optional ByVal pvArgs As Variant _
, Optional ByVal plMax As Long _
) As String
&apos;&apos;&apos; Convert an array of values to a comma-separated list of readable strings
Dim sValues As String &apos; Return value
Dim sValue As String &apos; A single value
Dim vValue As Variant &apos; A single item in the argument
Dim i As Long &apos; Items counter
Const cstMax = 20 &apos; Maximum length of single string
Const cstContinue = &quot;&quot; &apos; Unicode continuation char U+2026
_ReprValues = &quot;&quot;
If IsMissing(pvArgs) Then Exit Function
If Not IsArray(pvArgs) Then pvArgs = Array(pvArgs)
sValues = &quot;&quot;
For i = 0 To UBound(pvArgs)
vValue = pvArgs(i)
If i &lt; plMax Then
If VarType(vValue) = V_STRING Then sValue = &quot;&quot;&quot;&quot; &amp; vValue &amp; &quot;&quot;&quot;&quot; Else sValue = SF_Utils._Repr(vValue, cstMax)
If Len(sValues) = 0 Then sValues = sValue Else sValues = sValues &amp; &quot;, &quot; &amp; sValue
ElseIf i &lt; UBound(pvArgs) Then
sValues = sValues &amp; &quot;, &quot; &amp; cstContinue
Exit For
End If
Next i
_ReprValues = sValues
End Function &apos; ScriptForge.SF_Utils._ReprValues
REM -----------------------------------------------------------------------------
Public Sub _SetPropertyValue(ByRef pvPropertyValue As Variant _
, ByVal psName As String _
, ByRef pvValue As Variant _
)
&apos;&apos;&apos; Update the 1st argument (passed by reference), which is an array of property values
&apos;&apos;&apos; If the property psName exists, update it with pvValue, otherwise create it on top of the array
Dim oPropertyValue As New com.sun.star.beans.PropertyValue
Dim lIndex As Long &apos; Found entry
Dim vValue As Variant &apos; Alias of pvValue
Dim i As Long
lIndex = -1
For i = 0 To UBound(pvPropertyValue)
If pvPropertyValue(i).Name = psName Then
lIndex = i
Exit For
End If
Next i
If lIndex &lt; 0 Then &apos; Not found
lIndex = UBound(pvPropertyValue) + 1
ReDim Preserve pvPropertyValue(0 To lIndex)
Set oPropertyValue = SF_Utils._MakePropertyValue(psName, pvValue)
pvPropertyValue(lIndex) = oPropertyValue
Else &apos; psName exists already in array of property values
pvPropertyValue(lIndex).Value = SF_Utils._CPropertyValue(pvValue)
End If
End Sub &apos; ScriptForge.SF_Utils._SetPropertyValue
REM -----------------------------------------------------------------------------
Private Function _TypeNames(Optional ByVal pvArgs As Variant) As String
&apos;&apos;&apos; Converts the array of VarTypes to a comma-separated list of TypeNames
Dim sTypes As String &apos; Return value
Dim sType As String &apos; A single type
Dim iType As Integer &apos; A single item of the argument
_TypeNames = &quot;&quot;
If IsMissing(pvArgs) Then Exit Function
If Not IsArray(pvArgs) Then pvArgs = Array(pvArgs)
sTypes = &quot;&quot;
For Each iType In pvArgs
Select Case iType
Case V_EMPTY : sType = &quot;Empty&quot;
Case V_NULL : sType = &quot;Null&quot;
Case V_INTEGER : sType = &quot;Integer&quot;
Case V_LONG : sType = &quot;Long&quot;
Case V_SINGLE : sType = &quot;Single&quot;
Case V_DOUBLE : sType = &quot;Double&quot;
Case V_CURRENCY : sType = &quot;Currency&quot;
Case V_DATE : sType = &quot;Date&quot;
Case V_STRING : sType = &quot;String&quot;
Case V_OBJECT : sType = &quot;Object&quot;
Case V_BOOLEAN : sType = &quot;Boolean&quot;
Case V_VARIANT : sType = &quot;Variant&quot;
Case V_DECIMAL : sType = &quot;Decimal&quot;
Case &gt;= V_ARRAY : sType = &quot;Array&quot;
Case V_NUMERIC : sType = &quot;Numeric&quot;
End Select
If Len(sTypes) = 0 Then sTypes = sType Else sTypes = sTypes &amp; &quot;, &quot; &amp; sType
Next iType
_TypeNames = sTypes
End Function &apos; ScriptForge.SF_Utils._TypeNames
REM -----------------------------------------------------------------------------
Public Function _Validate(Optional ByRef pvArgument As Variant _
, ByVal psName As String _
, Optional ByVal pvTypes As Variant _
, Optional ByVal pvValues As Variant _
, Optional ByVal pvRegex As Variant _
, Optional ByVal pvObjectType As Variant _
) As Boolean
&apos;&apos;&apos; Validate the arguments set by user scripts
&apos;&apos;&apos; The arguments of the function define the validation rules
&apos;&apos;&apos; This function ignores arrays. Use _ValidateArray instead
&apos;&apos;&apos; Args:
&apos;&apos;&apos; pvArgument: the argument to (in)validate
&apos;&apos;&apos; psName: the documented name of the argument (can be inserted in an error message)
&apos;&apos;&apos; pvTypes: array of allowed VarTypes
&apos;&apos;&apos; pvValues: array of allowed values
&apos;&apos;&apos; pvRegex: regular expression to comply with
&apos;&apos;&apos; pvObjectType: mandatory Basic class
&apos;&apos;&apos; Return: True if validation OK
&apos;&apos;&apos; Otherwise an error is raised
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; ARGUMENTERROR
Dim iVarType As Integer &apos; Extended VarType of argument
Dim bValid As Boolean &apos; Returned value
Dim oArgument As Variant &apos; Workaround &quot;Object variable not set&quot; error on 1st executable statement
Const cstMaxLength = 256 &apos; Maximum length of readable value
Const cstMaxValues = 10 &apos; Maximum number of allowed items to list in an error message
&apos; To avoid useless recursions, keep main function, only increase stack depth
_SF_.StackLevel = _SF_.StackLevel + 1
On Local Error GoTo Finally &apos; Do never interrupt
Try:
bValid = True
If IsMissing(pvArgument) Then GoTo CatchMissing
If IsMissing(pvRegex) Or IsEmpty(pvRegex) Then pvRegex = &quot;&quot;
If IsMissing(pvObjectType) Or IsEmpty(pvObjectType) Then pvObjectType = &quot;&quot;
iVarType = SF_Utils._VarTypeExt(pvArgument)
&apos; Arrays NEVER pass validation
If iVarType &gt;= V_ARRAY Then
bValid = False
Else
&apos; Check existence of argument
bValid = iVarType &lt;&gt; V_NULL And iVarType &lt;&gt; V_EMPTY
&apos; Check if argument&apos;s VarType is valid
If bValid And Not IsMissing(pvTypes) Then
If Not IsArray(pvTypes) Then bValid = ( pvTypes = iVarType ) Else bValid = SF_Array.Contains(pvTypes, iVarType)
End If
&apos; Check if argument&apos;s value is valid
If bValid And Not IsMissing(pvValues) Then
If Not IsArray(pvValues) Then pvValues = Array(pvValues)
bValid = SF_Array.Contains(pvValues, pvArgument, CaseSensitive := False)
End If
&apos; Check regular expression
If bValid And Len(pvRegex) &gt; 0 And iVarType = V_STRING Then
If Len(pvArgument) &gt; 0 Then bValid = SF_String.IsRegex(pvArgument, pvRegex, CaseSensitive := False)
End If
&apos; Check instance types
If bValid And Len(pvObjectType) &gt; 0 And iVarType = V_OBJECT Then
Set oArgument = pvArgument
bValid = ( pvObjectType = oArgument.ObjectType )
End If
End If
If Not bValid Then
&apos;&apos;&apos; Library: ScriptForge
&apos;&apos;&apos; Service: Array
&apos;&apos;&apos; Method: Contains
&apos;&apos;&apos; Arguments: Array_1D, ToFind, [CaseSensitive=False], [SortOrder=&quot;&quot;]
&apos;&apos;&apos; A serious error has been detected on argument SortOrder
&apos;&apos;&apos; Rules: SortOrder is of type String
&apos;&apos;&apos; SortOrder must contain one of next values: &quot;ASC&quot;, &quot;DESC&quot;, &quot;&quot;
&apos;&apos;&apos; Actual value: &quot;Ascending&quot;
SF_Exception.RaiseFatal(ARGUMENTERROR _
, SF_Utils._Repr(pvArgument, cstMaxLength), psName, SF_Utils._TypeNames(pvTypes) _
, SF_Utils._ReprValues(pvValues, cstMaxValues), pvRegex, pvObjectType _
)
End If
Finally:
_Validate = bValid
_SF_.StackLevel = _SF_.StackLevel - 1
Exit Function
CatchMissing:
bValid = False
SF_Exception.RaiseFatal(MISSINGARGERROR, psName)
GoTo Finally
End Function &apos; ScriptForge.SF_Utils._Validate
REM -----------------------------------------------------------------------------
Public Function _ValidateArray(Optional ByRef pvArray As Variant _
, ByVal psName As String _
, Optional ByVal piDimensions As Integer _
, Optional ByVal piType As Integer _
, Optional ByVal pbNotNull As Boolean _
) As Boolean
&apos;&apos;&apos; Validate the (array) arguments set by user scripts
&apos;&apos;&apos; The arguments of the function define the validation rules
&apos;&apos;&apos; This function ignores non-arrays. Use _Validate instead
&apos;&apos;&apos; Args:
&apos;&apos;&apos; pvArray: the argument to (in)validate
&apos;&apos;&apos; psName: the documented name of the array (can be inserted in an error message)
&apos;&apos;&apos; piDimensions: the # of dimensions the array must have. 0 = Any (default)
&apos;&apos;&apos; piType: (default = -1, i.e. not applicable)
&apos;&apos;&apos; For 2D arrays, the 1st column is checked
&apos;&apos;&apos; 0 =&gt; all items must be any out of next types: string, date or numeric,
&apos;&apos;&apos; but homogeneously: all strings or all dates or all numeric
&apos;&apos;&apos; V_STRING or V_DATE or V_NUMERIC =&gt; that specific type is required
&apos;&apos;&apos; pbNotNull: piType must be &gt;=0, otherwise ignored
&apos;&apos;&apos; If True: Empty, Null items are rejected
&apos;&apos;&apos; Return: True if validation OK
&apos;&apos;&apos; Otherwise an error is raised
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; ARRAYERROR
Dim iVarType As Integer &apos; VarType of argument
Dim vItem As Variant &apos; Array item
Dim iItemType As Integer &apos; VarType of individual items of argument
Dim iDims As Integer &apos; Number of dimensions of the argument
Dim bValid As Boolean &apos; Returned value
Dim iArrayType As Integer &apos; Static array type
Dim iFirstItemType As Integer &apos; Type of 1st non-null/empty item
Dim sType As String &apos; Allowed item types as a string
Dim i As Long
Const cstMaxLength = 256 &apos; Maximum length of readable value
&apos; To avoid useless recursions, keep main function, only increase stack depth
_SF_.StackLevel = _SF_.StackLevel + 1
On Local Error GoTo Finally &apos; Do never interrupt
Try:
bValid = True
If IsMissing(pvArray) Then GoTo CatchMissing
If IsMissing(piDimensions) Then piDimensions = 0
If IsMissing(piType) Then piType = -1
If IsMissing(pbNotNull) Then pbNotNull = False
iVarType = VarType(pvArray)
&apos; Scalars NEVER pass validation
If iVarType &lt; V_ARRAY Then
bValid = False
Else
&apos; Check dimensions
iDims = SF_Array.CountDims(pvArray)
If iDims &gt; 2 Then bValid = False &apos; Only 1D and 2D arrays
If bValid And piDimensions &gt; 0 Then
bValid = ( iDims = piDimensions Or (iDims = 0 And piDimensions = 1) ) &apos; Allow empty vectors
End If
&apos; Check VarType and Empty/Null status of the array items
If bValid And iDims = 1 And piType &gt;= 0 Then
iArrayType = SF_Array._StaticType(pvArray)
If (piType = 0 And iArrayType &gt; 0) Or (piType &gt; 0 And iArrayType = piType) Then
&apos; If static array of the right VarType ..., OK
Else
&apos; Go through array and check individual items
iFirstItemType = -1
For i = LBound(pvArray, 1) To UBound(pvArray, 1)
If iDims = 1 Then vItem = pvArray(i) Else vItem = pvArray(i, LBound(pvArray, 2))
iItemType = SF_Utils._VarTypeExt(vItem)
If iItemType &gt; V_NULL Then &apos; Exclude Empty and Null
&apos; Initialization at first non-null item
If iFirstItemType &lt; 0 Then
iFirstItemType = iItemType
If piType &gt; 0 Then bValid = ( iFirstItemType = piType ) Else bValid = SF_Array.Contains(Array(V_STRING, V_DATE, V_NUMERIC), iFirstItemType)
Else
bValid = (iItemType = iFirstItemType)
End If
Else
bValid = Not pbNotNull
End If
If Not bValid Then Exit For
Next i
End If
End If
End If
If Not bValid Then
&apos;&apos;&apos; Library: ScriptForge
&apos;&apos;&apos; Service: Array
&apos;&apos;&apos; Method: Contains
&apos;&apos;&apos; Arguments: Array_1D, ToFind, [CaseSensitive=False], [SortOrder=&quot;&quot;|&quot;ASC&quot;|&quot;DESC&quot;]
&apos;&apos;&apos; An error was detected on argument Array_1D
&apos;&apos;&apos; Rules: Array_1D is of type Array
&apos;&apos;&apos; Array_1D must have maximum 1 dimension
&apos;&apos;&apos; Array_1D must have all elements of the same type: either String, Date or Numeric
&apos;&apos;&apos; Actual value: (0:2, 0:3)
sType = &quot;&quot;
If piType = 0 Then
sType = &quot;String, Date, Numeric&quot;
ElseIf piType &gt; 0 Then
sType = SF_Utils._TypeNames(piType)
End If
SF_Exception.RaiseFatal(ARRAYERROR _
, SF_Utils._Repr(pvArray, cstMaxLength), psName, piDimensions, sType, pbNotNull)
End If
Finally:
_ValidateArray = bValid
_SF_.StackLevel = _SF_.StackLevel - 1
Exit Function
CatchMissing:
bValid = False
SF_Exception.RaiseFatal(MISSINGARGERROR, psName)
GoTo Finally
End Function &apos; ScriptForge.SF_Utils._ValidateArray
REM -----------------------------------------------------------------------------
Public Function _ValidateFile(Optional ByRef pvArgument As Variant _
, ByVal psName As String _
, Optional ByVal pbWildCards As Boolean _
, Optional ByVal pbSpace As Boolean _
)
&apos;&apos;&apos; Validate the argument as a valid FileName
&apos;&apos;&apos; Args:
&apos;&apos;&apos; pvArgument: the argument to (in)validate
&apos;&apos;&apos; pbWildCards: if True, wildcard characters are accepted in the last component of the 1st argument
&apos;&apos;&apos; pbSpace: if True, the argument may be an empty string. Default = False
&apos;&apos;&apos; Return: True if validation OK
&apos;&apos;&apos; Otherwise an error is raised
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; ARGUMENTERROR
Dim iVarType As Integer &apos; VarType of argument
Dim sFile As String &apos; Alias for argument
Dim bValid As Boolean &apos; Returned value
Dim sFileNaming As String &apos; Alias of SF_FileSystem.FileNaming
Dim oArgument As Variant &apos; Workaround &quot;Object variable not set&quot; error on 1st executable statement
Const cstMaxLength = 256 &apos; Maximum length of readable value
&apos; To avoid useless recursions, keep main function, only increase stack depth
_SF_.StackLevel = _SF_.StackLevel + 1
On Local Error GoTo Finally &apos; Do never interrupt
Try:
bValid = True
If IsMissing(pvArgument) Then GoTo CatchMissing
If IsMissing(pbWildCards) Then pbWildCards = False
If IsMissing(pbSpace) Then pbSpace = False
iVarType = VarType(pvArgument)
&apos; Arrays NEVER pass validation
If iVarType &gt;= V_ARRAY Then
bValid = False
Else
&apos; Argument must be a string containing a valid file name
bValid = ( iVarType = V_STRING )
If bValid Then
bValid = ( Len(pvArgument) &gt; 0 Or pbSpace )
If bValid And Len(pvArgument) &gt; 0 Then
&apos; Wildcards are replaced by arbitrary alpha characters
If pbWildCards Then
sFile = Replace(Replace(pvArgument, &quot;?&quot;, &quot;Z&quot;), &quot;*&quot;, &quot;A&quot;)
Else
sFile = pvArgument
bValid = ( InStr(sFile, &quot;?&quot;) + InStr(sFile, &quot;*&quot;) = 0 )
End If
&apos; Check file format without wildcards
If bValid Then
With SF_FileSystem
sFileNaming = .FileNaming
Select Case sFileNaming
Case &quot;ANY&quot; : bValid = SF_String.IsUrl(ConvertToUrl(sFile))
Case &quot;URL&quot; : bValid = SF_String.IsUrl(sFile)
Case &quot;SYS&quot; : bValid = SF_String.IsFileName(sFile)
End Select
End With
End If
&apos; Check that wildcards are only present in last component
If bValid And pbWildCards Then
sFile = SF_FileSystem.GetParentFolderName(pvArgument)
bValid = ( InStr(sFile, &quot;*&quot;) + InStr(sFile, &quot;?&quot;) + InStr(sFile,&quot;%3F&quot;) = 0 ) &apos; ConvertToUrl replaces ? by %3F
End If
End If
End If
End If
If Not bValid Then
&apos;&apos;&apos; Library: ScriptForge
&apos;&apos;&apos; Service: FileSystem
&apos;&apos;&apos; Method: CopyFile
&apos;&apos;&apos; Arguments: Source, Destination
&apos;&apos;&apos; A serious error has been detected on argument Source
&apos;&apos;&apos; Rules: Source is of type String
&apos;&apos;&apos; Source must be a valid file name expressed in operating system notation
&apos;&apos;&apos; Source may contain one or more wildcard characters in its last component
&apos;&apos;&apos; Actual value: /home/jean-*/SomeFile.odt
SF_Exception.RaiseFatal(FILEERROR _
, SF_Utils._Repr(pvArgument, cstMaxLength), psName, pbWildCards)
End If
Finally:
_ValidateFile = bValid
_SF_.StackLevel = _SF_.StackLevel - 1
Exit Function
CatchMissing:
bValid = False
SF_Exception.RaiseFatal(MISSINGARGERROR, psName)
GoTo Finally
End Function &apos; ScriptForge.SF_Utils._ValidateFile
REM -----------------------------------------------------------------------------
Public Function _VarTypeExt(ByRef pvValue As Variant) As Integer
&apos;&apos;&apos; Return the VarType of the argument but all numeric types are aggregated into V_NUMERIC
&apos;&apos;&apos; Args:
&apos;&apos;&apos; pvValue: value to examine
&apos;&apos;&apos; Return:
&apos;&apos;&apos; The extended VarType
Dim iType As Integer &apos; VarType of argument
iType = VarType(pvValue)
Select Case iType
Case V_INTEGER, V_LONG, V_SINGLE, V_DOUBLE, V_CURRENCY, V_BIGINT, V_DECIMAL
_VarTypeExt = V_NUMERIC
Case Else : _VarTypeExt = iType
End Select
End Function &apos; ScriptForge.SF_Utils._VarTypeExt
REM ================================================= END OF SCRIPTFORGE.SF_UTILS
</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-2020 Jean-Pierre LEDURE, Jean-François NIFENECKER, 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:value="Close">
<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:value="Close" dlg:button-type="ok"/>
</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:value="Close">
<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,801 @@
#
# 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.1
# -----------------------
#
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: 2020-10-10 16:05:30\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"
#. Text in close buttons of progress and console dialog boxes
msgctxt "CLOSEBUTTON"
msgid "Close"
msgstr ""
#. 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 ""
#. SF_Utils._Validate error message
msgctxt "STOPEXECUTION"
msgid "THE EXECUTION IS CANCELLED."
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_2D', '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_2D » = %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
#. %2: An identifier
#. %3: 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 number
#, 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_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_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 '%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_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 ""

View File

@@ -0,0 +1,801 @@
#
# 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.1
# -----------------------
#
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: 2020-10-10 16:05:30\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"
#. Text in close buttons of progress and console dialog boxes
msgctxt "CLOSEBUTTON"
msgid "Close"
msgstr ""
#. 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 ""
#. SF_Utils._Validate error message
msgctxt "STOPEXECUTION"
msgid "THE EXECUTION IS CANCELLED."
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_2D', '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_2D » = %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
#. %2: An identifier
#. %3: 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 number
#, 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_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_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 '%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_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 ""

View File

@@ -0,0 +1,21 @@
<?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:library>