SF_Dictionary.xba 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
  3. <script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_Dictionary" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
  4. REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
  5. REM === Full documentation is available on https://help.libreoffice.org/ ===
  6. REM =======================================================================================================================
  7. Option Compatible
  8. Option ClassModule
  9. Option Explicit
  10. &apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
  11. &apos;&apos;&apos; SF_Dictionary
  12. &apos;&apos;&apos; =============
  13. &apos;&apos;&apos; Class for management of dictionaries
  14. &apos;&apos;&apos; A dictionary is a collection of key-item pairs
  15. &apos;&apos;&apos; The key is a not case-sensitive string
  16. &apos;&apos;&apos; Items may be of any type
  17. &apos;&apos;&apos; Keys, items can be retrieved, counted, etc.
  18. &apos;&apos;&apos;
  19. &apos;&apos;&apos; The implementation is based on
  20. &apos;&apos;&apos; - one collection mapping keys and entries in the array
  21. &apos;&apos;&apos; - one 1-column array: key + data
  22. &apos;&apos;&apos;
  23. &apos;&apos;&apos; Why a Dictionary class beside the builtin Collection class ?
  24. &apos;&apos;&apos; A standard Basic collection does not support the retrieval of the keys
  25. &apos;&apos;&apos; Additionally it may contain only simple data (strings, numbers, ...)
  26. &apos;&apos;&apos;
  27. &apos;&apos;&apos; Service instantiation example:
  28. &apos;&apos;&apos; Dim myDict As Variant
  29. &apos;&apos;&apos; myDict = CreateScriptService(&quot;Dictionary&quot;) &apos; Once per dictionary
  30. &apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
  31. REM ================================================================== EXCEPTIONS
  32. Const DUPLICATEKEYERROR = &quot;DUPLICATEKEYERROR&quot; &apos; Key exists already
  33. Const UNKNOWNKEYERROR = &quot;UNKNOWNKEYERROR&quot; &apos; Key not found
  34. Const INVALIDKEYERROR = &quot;INVALIDKEYERROR&quot; &apos; Key contains only spaces
  35. REM ============================================================= PRIVATE MEMBERS
  36. &apos; Defines an entry in the MapItems array
  37. Type ItemMap
  38. Key As String
  39. Value As Variant
  40. End Type
  41. Private [Me] As Object
  42. Private [_Parent] As Object
  43. Private ObjectType As String &apos; Must be &quot;DICTIONARY&quot;
  44. Private ServiceName As String
  45. Private MapKeys As Variant &apos; To retain the original keys
  46. Private MapItems As Variant &apos; Array of ItemMaps
  47. Private _MapSize As Long &apos; Total number of entries in the dictionary
  48. Private _MapRemoved As Long &apos; Number of inactive entries in the dictionary
  49. REM ===================================================== CONSTRUCTOR/DESTRUCTOR
  50. REM -----------------------------------------------------------------------------
  51. Private Sub Class_Initialize()
  52. Set [Me] = Nothing
  53. Set [_Parent] = Nothing
  54. ObjectType = &quot;DICTIONARY&quot;
  55. ServiceName = &quot;ScriptForge.Dictionary&quot;
  56. Set MapKeys = New Collection
  57. Set MapItems = Array()
  58. _MapSize = 0
  59. _MapRemoved = 0
  60. End Sub &apos; ScriptForge.SF_Dictionary Constructor
  61. REM -----------------------------------------------------------------------------
  62. Private Sub Class_Terminate()
  63. Call Class_Initialize()
  64. End Sub &apos; ScriptForge.SF_Dictionary Destructor
  65. REM -----------------------------------------------------------------------------
  66. Public Function Dispose() As Variant
  67. RemoveAll()
  68. Set Dispose = Nothing
  69. End Function &apos; ScriptForge.SF_Dictionary Explicit destructor
  70. REM ================================================================== PROPERTIES
  71. REM -----------------------------------------------------------------------------
  72. Property Get Count() As Long
  73. &apos;&apos;&apos; Actual number of entries in the dictionary
  74. &apos;&apos;&apos; Example:
  75. &apos;&apos;&apos; myDict.Count
  76. Count = _PropertyGet(&quot;Count&quot;)
  77. End Property &apos; ScriptForge.SF_Dictionary.Count
  78. REM -----------------------------------------------------------------------------
  79. Public Function Item(Optional ByVal Key As Variant) As Variant
  80. &apos;&apos;&apos; Return the value of the item related to Key
  81. &apos;&apos;&apos; Args:
  82. &apos;&apos;&apos; Key: the key value (string)
  83. &apos;&apos;&apos; Returns:
  84. &apos;&apos;&apos; Empty if not found, otherwise the found value
  85. &apos;&apos;&apos; Example:
  86. &apos;&apos;&apos; myDict.Item(&quot;ThisKey&quot;)
  87. &apos;&apos;&apos; NB: defined as a function to not disrupt the Basic IDE debugger
  88. Item = _PropertyGet(&quot;Item&quot;, Key)
  89. End Function &apos; ScriptForge.SF_Dictionary.Item
  90. REM -----------------------------------------------------------------------------
  91. Property Get Items() as Variant
  92. &apos;&apos;&apos; Return the list of Items as a 1D array
  93. &apos;&apos;&apos; The Items and Keys properties return their respective contents in the same order
  94. &apos;&apos;&apos; The order is however not necessarily identical to the creation sequence
  95. &apos;&apos;&apos; Returns:
  96. &apos;&apos;&apos; The array is empty if the dictionary is empty
  97. &apos;&apos;&apos; Examples
  98. &apos;&apos;&apos; a = myDict.Items
  99. &apos;&apos;&apos; For Each b In a ...
  100. Items = _PropertyGet(&quot;Items&quot;)
  101. End Property &apos; ScriptForge.SF_Dictionary.Items
  102. REM -----------------------------------------------------------------------------
  103. Property Get Keys() as Variant
  104. &apos;&apos;&apos; Return the list of keys as a 1D array
  105. &apos;&apos;&apos; The Keys and Items properties return their respective contents in the same order
  106. &apos;&apos;&apos; The order is however not necessarily identical to the creation sequence
  107. &apos;&apos;&apos; Returns:
  108. &apos;&apos;&apos; The array is empty if the dictionary is empty
  109. &apos;&apos;&apos; Examples
  110. &apos;&apos;&apos; a = myDict.Keys
  111. &apos;&apos;&apos; For each b In a ...
  112. Keys = _PropertyGet(&quot;Keys&quot;)
  113. End Property &apos; ScriptForge.SF_Dictionary.Keys
  114. REM ===================================================================== METHODS
  115. REM -----------------------------------------------------------------------------
  116. Public Function Add(Optional ByVal Key As Variant _
  117. , Optional ByVal Item As Variant _
  118. ) As Boolean
  119. &apos;&apos;&apos; Add a new key-item pair into the dictionary
  120. &apos;&apos;&apos; Args:
  121. &apos;&apos;&apos; Key: must not yet exist in the dictionary
  122. &apos;&apos;&apos; Item: any value, including an array, a Basic object, a UNO object, ...
  123. &apos;&apos;&apos; Returns: True if successful
  124. &apos;&apos;&apos; Exceptions:
  125. &apos;&apos;&apos; DUPLICATEKEYERROR: such a key exists already
  126. &apos;&apos;&apos; INVALIDKEYERROR: zero-length string or only spaces
  127. &apos;&apos;&apos; Examples:
  128. &apos;&apos;&apos; myDict.Add(&quot;NewKey&quot;, NewValue)
  129. Dim oItemMap As ItemMap &apos; New entry in the MapItems array
  130. Const cstThisSub = &quot;Dictionary.Add&quot;
  131. Const cstSubArgs = &quot;Key, Item&quot;
  132. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  133. Add = False
  134. Check:
  135. If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  136. If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
  137. If IsArray(Item) Then
  138. If Not SF_Utils._ValidateArray(Item, &quot;Item&quot;) Then GoTo Catch
  139. Else
  140. If Not SF_Utils._Validate(Item, &quot;Item&quot;) Then GoTo Catch
  141. End If
  142. End If
  143. If Key = Space(Len(Key)) Then GoTo CatchInvalid
  144. If Exists(Key) Then GoTo CatchDuplicate
  145. Try:
  146. _MapSize = _MapSize + 1
  147. MapKeys.Add(_MapSize, Key)
  148. oItemMap.Key = Key
  149. oItemMap.Value = Item
  150. ReDim Preserve MapItems(1 To _MapSize)
  151. MapItems(_MapSize) = oItemMap
  152. Add = True
  153. Finally:
  154. SF_Utils._ExitFunction(cstThisSub)
  155. Exit Function
  156. Catch:
  157. GoTo Finally
  158. CatchDuplicate:
  159. SF_Exception.RaiseFatal(DUPLICATEKEYERROR, &quot;Key&quot;, Key)
  160. GoTo Finally
  161. CatchInvalid:
  162. SF_Exception.RaiseFatal(INVALIDKEYERROR, &quot;Key&quot;)
  163. GoTo Finally
  164. End Function &apos; ScriptForge.SF_Dictionary.Add
  165. REM -----------------------------------------------------------------------------
  166. Public Function ConvertToArray() As Variant
  167. &apos;&apos;&apos; Store the content of the dictionary in a 2-columns array:
  168. &apos;&apos;&apos; Key stored in 1st column, Item stored in 2nd
  169. &apos;&apos;&apos; Args:
  170. &apos;&apos;&apos; Returns:
  171. &apos;&apos;&apos; a zero-based 2D array(0:Count - 1, 0:1)
  172. &apos;&apos;&apos; an empty array if the dictionary is empty
  173. Dim vArray As Variant &apos; Return value
  174. Dim sKey As String &apos; Tempry key
  175. Dim vKeys As Variant &apos; Array of keys
  176. Dim lCount As Long &apos; Counter
  177. Const cstThisSub = &quot;Dictionary.ConvertToArray&quot;
  178. Const cstSubArgs = &quot;&quot;
  179. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  180. Check:
  181. SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
  182. Try:
  183. vArray = Array()
  184. If Count = 0 Then
  185. Else
  186. ReDim vArray(0 To Count - 1, 0 To 1)
  187. lCount = -1
  188. vKeys = Keys
  189. For Each sKey in vKeys
  190. lCount = lCount + 1
  191. vArray(lCount, 0) = sKey
  192. vArray(lCount, 1) = Item(sKey)
  193. Next sKey
  194. End If
  195. Finally:
  196. ConvertToArray = vArray()
  197. SF_Utils._ExitFunction(cstThisSub)
  198. Exit Function
  199. Catch:
  200. GoTo Finally
  201. End Function &apos; ScriptForge.SF_Dictionary.ConvertToArray
  202. REM -----------------------------------------------------------------------------
  203. Public Function ConvertToJson(ByVal Optional Indent As Variant) As Variant
  204. &apos;&apos;&apos; Convert the content of the dictionary to a JSON string
  205. &apos;&apos;&apos; JSON = JavaScript Object Notation: https://en.wikipedia.org/wiki/JSON
  206. &apos;&apos;&apos; Limitations
  207. &apos;&apos;&apos; Allowed item types: String, Boolean, numbers, Null and Empty
  208. &apos;&apos;&apos; Arrays containing above types are allowed
  209. &apos;&apos;&apos; Dates are converted into strings (not within arrays)
  210. &apos;&apos;&apos; Other types are converted to their string representation (cfr. SF_String.Represent)
  211. &apos;&apos;&apos; Args:
  212. &apos;&apos;&apos; Indent:
  213. &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.
  214. &apos;&apos;&apos; An indent level &lt;= 0 will only insert newlines.
  215. &apos;&apos;&apos; &quot;&quot;, (the default) selects the most compact representation.
  216. &apos;&apos;&apos; Using a positive integer indent indents that many spaces per level.
  217. &apos;&apos;&apos; If indent is a string (such as Chr(9)), that string is used to indent each level.
  218. &apos;&apos;&apos; Returns:
  219. &apos;&apos;&apos; the JSON string
  220. &apos;&apos;&apos; Example:
  221. &apos;&apos;&apos; myDict.Add(&quot;p0&quot;, 12.5)
  222. &apos;&apos;&apos; myDict.Add(&quot;p1&quot;, &quot;a string àé&quot;&quot;ê&quot;)
  223. &apos;&apos;&apos; myDict.Add(&quot;p2&quot;, DateSerial(2020,9,28))
  224. &apos;&apos;&apos; myDict.Add(&quot;p3&quot;, True)
  225. &apos;&apos;&apos; myDict.Add(&quot;p4&quot;, Array(1,2,3))
  226. &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]}
  227. Dim sJson As String &apos; Return value
  228. Dim vArray As Variant &apos; Array of property values
  229. Dim oPropertyValue As Object &apos; com.sun.star.beans.PropertyValue
  230. Dim sKey As String &apos; Tempry key
  231. Dim vKeys As Variant &apos; Array of keys
  232. Dim vItem As Variant &apos; Tempry item
  233. Dim iVarType As Integer &apos; Extended VarType
  234. Dim lCount As Long &apos; Counter
  235. Dim vIndent As Variant &apos; Python alias of Indent
  236. Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_Dictionary__ConvertToJson&quot;
  237. Const cstThisSub = &quot;Dictionary.ConvertToJson&quot;
  238. Const cstSubArgs = &quot;[Indent=Null]&quot;
  239. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  240. Check:
  241. If IsMissing(Indent) Or IsEmpty(INDENT) Then Indent = &quot;&quot;
  242. If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  243. If Not SF_Utils._Validate(Indent, &quot;Indent&quot;, Array(V_STRING, V_NUMERIC)) Then GoTo Finally
  244. End If
  245. sJson = &quot;&quot;
  246. Try:
  247. vArray = Array()
  248. If Count = 0 Then
  249. Else
  250. ReDim vArray(0 To Count - 1)
  251. lCount = -1
  252. vKeys = Keys
  253. For Each sKey in vKeys
  254. &apos; Check item type
  255. vItem = Item(sKey)
  256. iVarType = SF_Utils._VarTypeExt(vItem)
  257. Select Case iVarType
  258. Case V_STRING, V_BOOLEAN, V_NUMERIC, V_NULL, V_EMPTY
  259. Case V_DATE
  260. vItem = SF_Utils._CDateToIso(vItem)
  261. Case &gt;= V_ARRAY
  262. Case Else
  263. vItem = SF_Utils._Repr(vItem)
  264. End Select
  265. &apos; Build in each array entry a (Name, Value) pair
  266. Set oPropertyValue = SF_Utils._MakePropertyValue(sKey, vItem)
  267. lCount = lCount + 1
  268. Set vArray(lCount) = oPropertyValue
  269. Next sKey
  270. End If
  271. &apos;Pass array to Python script for the JSON conversion
  272. With ScriptForge.SF_Session
  273. vIndent = Indent
  274. If VarType(Indent) = V_STRING Then
  275. If Len(Indent) = 0 Then vIndent = Null
  276. End If
  277. sJson = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper, vArray, vIndent)
  278. End With
  279. Finally:
  280. ConvertToJson = sJson
  281. SF_Utils._ExitFunction(cstThisSub)
  282. Exit Function
  283. Catch:
  284. GoTo Finally
  285. End Function &apos; ScriptForge.SF_Dictionary.ConvertToJson
  286. REM -----------------------------------------------------------------------------
  287. Public Function ConvertToPropertyValues() As Variant
  288. &apos;&apos;&apos; Store the content of the dictionary in an array of PropertyValues
  289. &apos;&apos;&apos; Key stored in Name, Item stored in Value
  290. &apos;&apos;&apos; Args:
  291. &apos;&apos;&apos; Returns:
  292. &apos;&apos;&apos; a zero-based 1D array(0:Count - 1). Each entry is a com.sun.star.beans.PropertyValue
  293. &apos;&apos;&apos; Name: the key in the dictionary
  294. &apos;&apos;&apos; Value:
  295. &apos;&apos;&apos; Dates are converted to UNO dates
  296. &apos;&apos;&apos; Empty arrays are replaced by Null
  297. &apos;&apos;&apos; an empty array if the dictionary is empty
  298. Dim vArray As Variant &apos; Return value
  299. Dim oPropertyValue As Object &apos; com.sun.star.beans.PropertyValue
  300. Dim sKey As String &apos; Tempry key
  301. Dim vKeys As Variant &apos; Array of keys
  302. Dim lCount As Long &apos; Counter
  303. Const cstThisSub = &quot;Dictionary.ConvertToPropertyValues&quot;
  304. Const cstSubArgs = &quot;&quot;
  305. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  306. Check:
  307. SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
  308. Try:
  309. vArray = Array()
  310. If Count = 0 Then
  311. Else
  312. ReDim vArray(0 To Count - 1)
  313. lCount = -1
  314. vKeys = Keys
  315. For Each sKey in vKeys
  316. &apos; Build in each array entry a (Name, Value) pair
  317. Set oPropertyValue = SF_Utils._MakePropertyValue(sKey, Item(sKey))
  318. lCount = lCount + 1
  319. Set vArray(lCount) = oPropertyValue
  320. Next sKey
  321. End If
  322. Finally:
  323. ConvertToPropertyValues = vArray()
  324. SF_Utils._ExitFunction(cstThisSub)
  325. Exit Function
  326. Catch:
  327. GoTo Finally
  328. End Function &apos; ScriptForge.SF_Dictionary.ConvertToPropertyValues
  329. REM -----------------------------------------------------------------------------
  330. Public Function Exists(Optional ByVal Key As Variant) As Boolean
  331. &apos;&apos;&apos; Determine if a key exists in the dictionary
  332. &apos;&apos;&apos; Args:
  333. &apos;&apos;&apos; Key: the key value (string)
  334. &apos;&apos;&apos; Returns: True if key exists
  335. &apos;&apos;&apos; Examples:
  336. &apos;&apos;&apos; If myDict.Exists(&quot;SomeKey&quot;) Then &apos; don&apos;t add again
  337. Dim vItem As Variant &apos; Item part in MapKeys
  338. Const cstThisSub = &quot;Dictionary.Exists&quot;
  339. Const cstSubArgs = &quot;Key&quot;
  340. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  341. Exists = False
  342. Check:
  343. If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  344. If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
  345. End If
  346. Try:
  347. &apos; Dirty but preferred to go through whole collection
  348. On Local Error GoTo NotFound
  349. vItem = MapKeys(Key)
  350. NotFound:
  351. Exists = ( Not ( Err = 5 ) And vItem &gt; 0 )
  352. On Local Error GoTo 0
  353. Finally:
  354. SF_Utils._ExitFunction(cstThisSub)
  355. Exit Function
  356. Catch:
  357. GoTo Finally
  358. End Function &apos; ScriptForge.SF_Dictionary.Exists
  359. REM -----------------------------------------------------------------------------
  360. Public Function GetProperty(Optional ByVal PropertyName As Variant _
  361. , Optional ByVal Key As Variant _
  362. ) As Variant
  363. &apos;&apos;&apos; Return the actual value of the given property
  364. &apos;&apos;&apos; Args:
  365. &apos;&apos;&apos; PropertyName: the name of the property as a string
  366. &apos;&apos;&apos; Key: mandatory if PropertyName = &quot;Item&quot;, ignored otherwise
  367. &apos;&apos;&apos; Returns:
  368. &apos;&apos;&apos; The actual value of the property
  369. &apos;&apos;&apos; Exceptions:
  370. &apos;&apos;&apos; ARGUMENTERROR The property does not exist
  371. &apos;&apos;&apos; Examples:
  372. &apos;&apos;&apos; myDict.GetProperty(&quot;Count&quot;)
  373. Const cstThisSub = &quot;Dictionary.GetProperty&quot;
  374. Const cstSubArgs = &quot;PropertyName, [Key]&quot;
  375. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  376. GetProperty = Null
  377. Check:
  378. If IsMissing(Key) Or IsEmpty(Key) Then Key = &quot;&quot;
  379. If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  380. If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
  381. End If
  382. Try:
  383. GetProperty = _PropertyGet(PropertyName, Key)
  384. Finally:
  385. SF_Utils._ExitFunction(cstThisSub)
  386. Exit Function
  387. Catch:
  388. GoTo Finally
  389. End Function &apos; ScriptForge.SF_Dictionary.GetProperty
  390. REM -----------------------------------------------------------------------------
  391. Public Function ImportFromJson(Optional ByVal InputStr As Variant _
  392. , Optional Byval Overwrite As Variant _
  393. ) As Boolean
  394. &apos;&apos;&apos; Adds the content of a Json string into the current dictionary
  395. &apos;&apos;&apos; JSON = JavaScript Object Notation: https://en.wikipedia.org/wiki/JSON
  396. &apos;&apos;&apos; Limitations
  397. &apos;&apos;&apos; The JSON string may contain numbers, strings, booleans, null values and arrays containing those types
  398. &apos;&apos;&apos; It must not contain JSON objects, i.e. sub-dictionaries
  399. &apos;&apos;&apos; An attempt is made to convert strings to dates if they fit one of next patterns:
  400. &apos;&apos;&apos; YYYY-MM-DD, HH:MM:SS or YYYY-MM-DD HH:MM:SS
  401. &apos;&apos;&apos; Args:
  402. &apos;&apos;&apos; InputStr: the json string to import
  403. &apos;&apos;&apos; Overwrite: when True entries with same name may exist in the dictionary and their values are overwritten
  404. &apos;&apos;&apos; Default = False
  405. &apos;&apos;&apos; Returns:
  406. &apos;&apos;&apos; True if successful
  407. &apos;&apos;&apos; Exceptions:
  408. &apos;&apos;&apos; DUPLICATEKEYERROR: such a key exists already
  409. &apos;&apos;&apos; INVALIDKEYERROR: zero-length string or only spaces
  410. &apos;&apos;&apos; Example:
  411. &apos;&apos;&apos; Dim s As String
  412. &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; _
  413. &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; _
  414. &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; _
  415. &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;
  416. &apos;&apos;&apos; s = Replace(s, &quot;&apos;&quot;, &quot;&quot;&quot;&quot;)
  417. &apos;&apos;&apos; myDict.ImportFromJson(s, OverWrite := True)
  418. &apos;&apos;&apos; &apos; The (sub)-dictionaries &quot;address&quot; and &quot;phoneNumbers(0) and (1) are reduced to Empty
  419. Dim bImport As Boolean &apos; Return value
  420. Dim vArray As Variant &apos; JSON string converted to array
  421. Dim vArrayEntry As Variant &apos; A single entry in vArray
  422. Dim vKey As Variant &apos; Tempry key
  423. Dim vItem As Variant &apos; Tempry item
  424. Dim bExists As Boolean &apos; True when an entry exists
  425. Dim dDate As Date &apos; String converted to Date
  426. Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_Dictionary__ImportFromJson&quot;
  427. Const cstThisSub = &quot;Dictionary.ImportFromJson&quot;
  428. Const cstSubArgs = &quot;InputStr, [Overwrite=False]&quot;
  429. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  430. bImport = False
  431. Check:
  432. If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = False
  433. If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  434. If Not SF_Utils._Validate(InputStr, &quot;InputStr&quot;, V_STRING) Then GoTo Finally
  435. If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoYo Finally
  436. End If
  437. Try:
  438. With ScriptForge.SF_Session
  439. vArray = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper, InputStr)
  440. End With
  441. If Not IsArray(vArray) Then GoTo Finally &apos; Conversion error or nothing to do
  442. &apos; vArray = Array of subarrays = 2D DataArray (cfr. Calc)
  443. For Each vArrayEntry In vArray
  444. vKey = vArrayEntry(0)
  445. If VarType(vKey) = V_STRING Then &apos; Else skip
  446. vItem = vArrayEntry(1)
  447. If Overwrite Then bExists = Exists(vKey) Else bExists = False
  448. &apos; When the item matches a date pattern, convert it to a date
  449. If VarType(vItem) = V_STRING Then
  450. dDate = SF_Utils._CStrToDate(vItem)
  451. If dDate &gt; -1 Then vItem = dDate
  452. End If
  453. If bExists Then
  454. ReplaceItem(vKey, vItem)
  455. Else
  456. Add(vKey, vItem) &apos; Key controls are done in Add
  457. End If
  458. End If
  459. Next vArrayEntry
  460. bImport = True
  461. Finally:
  462. ImportFromJson = bImport
  463. SF_Utils._ExitFunction(cstThisSub)
  464. Exit Function
  465. Catch:
  466. GoTo Finally
  467. End Function &apos; ScriptForge.SF_Dictionary.ImportFromJson
  468. REM -----------------------------------------------------------------------------
  469. Public Function ImportFromPropertyValues(Optional ByVal PropertyValues As Variant _
  470. , Optional Byval Overwrite As Variant _
  471. ) As Boolean
  472. &apos;&apos;&apos; Adds the content of an array of PropertyValues into the current dictionary
  473. &apos;&apos;&apos; Names contain Keys, Values contain Items
  474. &apos;&apos;&apos; UNO dates are replaced by Basic dates
  475. &apos;&apos;&apos; Args:
  476. &apos;&apos;&apos; PropertyValues: a zero-based 1D array. Each entry is a com.sun.star.beans.PropertyValue
  477. &apos;&apos;&apos; Overwrite: when True entries with same name may exist in the dictionary and their values are overwritten
  478. &apos;&apos;&apos; Default = False
  479. &apos;&apos;&apos; Returns:
  480. &apos;&apos;&apos; True if successful
  481. &apos;&apos;&apos; Exceptions:
  482. &apos;&apos;&apos; DUPLICATEKEYERROR: such a key exists already
  483. &apos;&apos;&apos; INVALIDKEYERROR: zero-length string or only spaces
  484. Dim bImport As Boolean &apos; Return value
  485. Dim oPropertyValue As Object &apos; com.sun.star.beans.PropertyValue
  486. Dim vItem As Variant &apos; Tempry item
  487. Dim sObjectType As String &apos; UNO object type of dates
  488. Dim bExists As Boolean &apos; True when an entry exists
  489. Const cstThisSub = &quot;Dictionary.ImportFromPropertyValues&quot;
  490. Const cstSubArgs = &quot;PropertyValues, [Overwrite=False]&quot;
  491. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  492. bImport = False
  493. Check:
  494. If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = False
  495. If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  496. If IsArray(PropertyValues) Then
  497. If Not SF_Utils._ValidateArray(PropertyValues, &quot;PropertyValues&quot;, 1, V_OBJECT, True) Then GoTo Finally
  498. Else
  499. If Not SF_Utils._Validate(PropertyValues, &quot;PropertyValues&quot;, V_OBJECT) Then GoTo Finally
  500. End If
  501. If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoYo Finally
  502. End If
  503. Try:
  504. If Not IsArray(PropertyValues) Then PropertyValues = Array(PropertyValues)
  505. With oPropertyValue
  506. For Each oPropertyValue In PropertyValues
  507. If Overwrite Then bExists = Exists(.Name) Else bExists = False
  508. If SF_Session.UnoObjectType(oPropertyValue) = &quot;com.sun.star.beans.PropertyValue&quot; Then
  509. If IsUnoStruct(.Value) Then
  510. sObjectType = SF_Session.UnoObjectType(.Value)
  511. Select Case sObjectType
  512. Case &quot;com.sun.star.util.DateTime&quot; : vItem = CDateFromUnoDateTime(.Value)
  513. Case &quot;com.sun.star.util.Date&quot; : vItem = CDateFromUnoDate(.Value)
  514. Case &quot;com.sun.star.util.Time&quot; : vItem = CDateFromUnoTime(.Value)
  515. Case Else : vItem = .Value
  516. End Select
  517. Else
  518. vItem = .Value
  519. End If
  520. If bExists Then
  521. ReplaceItem(.Name, vItem)
  522. Else
  523. Add(.Name, vItem) &apos; Key controls are done in Add
  524. End If
  525. End If
  526. Next oPropertyValue
  527. End With
  528. bImport = True
  529. Finally:
  530. ImportFromPropertyValues = bImport
  531. SF_Utils._ExitFunction(cstThisSub)
  532. Exit Function
  533. Catch:
  534. GoTo Finally
  535. End Function &apos; ScriptForge.SF_Dictionary.ImportFromPropertyValues
  536. REM -----------------------------------------------------------------------------
  537. Public Function Methods() As Variant
  538. &apos;&apos;&apos; Return the list or methods of the Dictionary class as an array
  539. Methods = Array( _
  540. &quot;Add&quot; _
  541. , &quot;ConvertToArray&quot; _
  542. , &quot;ConvertToJson&quot; _
  543. , &quot;ConvertToPropertyValues&quot; _
  544. , &quot;Exists&quot; _
  545. , &quot;ImportFromJson&quot; _
  546. , &quot;ImportFromPropertyValues&quot; _
  547. , &quot;Remove&quot; _
  548. , &quot;RemoveAll&quot; _
  549. , &quot;ReplaceItem&quot; _
  550. , &quot;ReplaceKey&quot; _
  551. )
  552. End Function &apos; ScriptForge.SF_Dictionary.Methods
  553. REM -----------------------------------------------------------------------------
  554. Public Function Properties() As Variant
  555. &apos;&apos;&apos; Return the list or properties of the Dictionary class as an array
  556. Properties = Array( _
  557. &quot;Count&quot; _
  558. , &quot;Item&quot; _
  559. , &quot;Items&quot; _
  560. , &quot;Keys&quot; _
  561. )
  562. End Function &apos; ScriptForge.SF_Dictionary.Properties
  563. REM -----------------------------------------------------------------------------
  564. Public Function Remove(Optional ByVal Key As Variant) As Boolean
  565. &apos;&apos;&apos; Remove an existing dictionary entry based on its key
  566. &apos;&apos;&apos; Args:
  567. &apos;&apos;&apos; Key: must exist in the dictionary
  568. &apos;&apos;&apos; Returns: True if successful
  569. &apos;&apos;&apos; Exceptions:
  570. &apos;&apos;&apos; UNKNOWNKEYERROR: the key does not exist
  571. &apos;&apos;&apos; Examples:
  572. &apos;&apos;&apos; myDict.Remove(&quot;OldKey&quot;)
  573. Dim lIndex As Long &apos; To remove entry in the MapItems array
  574. Const cstThisSub = &quot;Dictionary.Remove&quot;
  575. Const cstSubArgs = &quot;Key&quot;
  576. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  577. Remove = False
  578. Check:
  579. If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  580. If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
  581. End If
  582. If Not Exists(Key) Then GoTo CatchUnknown
  583. Try:
  584. lIndex = MapKeys.Item(Key)
  585. MapKeys.Remove(Key)
  586. Erase MapItems(lIndex) &apos; Is now Empty
  587. _MapRemoved = _MapRemoved + 1
  588. Remove = True
  589. Finally:
  590. SF_Utils._ExitFunction(cstThisSub)
  591. Exit Function
  592. Catch:
  593. GoTo Finally
  594. CatchUnknown:
  595. SF_Exception.RaiseFatal(UNKNOWNKEYERROR, &quot;Key&quot;, Key)
  596. GoTo Finally
  597. End Function &apos; ScriptForge.SF_Dictionary.Remove
  598. REM -----------------------------------------------------------------------------
  599. Public Function RemoveAll() As Boolean
  600. &apos;&apos;&apos; Remove all the entries from the dictionary
  601. &apos;&apos;&apos; Args:
  602. &apos;&apos;&apos; Returns: True if successful
  603. &apos;&apos;&apos; Examples:
  604. &apos;&apos;&apos; myDict.RemoveAll()
  605. Dim vKeys As Variant &apos; Array of keys
  606. Dim sColl As String &apos; A collection key in MapKeys
  607. Const cstThisSub = &quot;Dictionary.RemoveAll&quot;
  608. Const cstSubArgs = &quot;&quot;
  609. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  610. RemoveAll = False
  611. Check:
  612. SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
  613. Try:
  614. vKeys = Keys
  615. For Each sColl In vKeys
  616. MapKeys.Remove(sColl)
  617. Next sColl
  618. Erase MapKeys
  619. Erase MapItems
  620. &apos; Make dictionary ready to receive new entries
  621. Call Class_Initialize()
  622. RemoveAll = True
  623. Finally:
  624. SF_Utils._ExitFunction(cstThisSub)
  625. Exit Function
  626. Catch:
  627. GoTo Finally
  628. End Function &apos; ScriptForge.SF_Dictionary.RemoveAll
  629. REM -----------------------------------------------------------------------------
  630. Public Function ReplaceItem(Optional ByVal Key As Variant _
  631. , Optional ByVal Value As Variant _
  632. ) As Boolean
  633. &apos;&apos;&apos; Replace the item value
  634. &apos;&apos;&apos; Args:
  635. &apos;&apos;&apos; Key: must exist in the dictionary
  636. &apos;&apos;&apos; Returns: True if successful
  637. &apos;&apos;&apos; Exceptions:
  638. &apos;&apos;&apos; UNKNOWNKEYERROR: the old key does not exist
  639. &apos;&apos;&apos; Examples:
  640. &apos;&apos;&apos; myDict.ReplaceItem(&quot;Key&quot;, NewValue)
  641. Dim oItemMap As ItemMap &apos; Content to update in the MapItems array
  642. Dim lIndex As Long &apos; Entry in the MapItems array
  643. Const cstThisSub = &quot;Dictionary.ReplaceItem&quot;
  644. Const cstSubArgs = &quot;Key, Value&quot;
  645. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  646. ReplaceItem = False
  647. Check:
  648. If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  649. If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
  650. If Not SF_Utils._Validate(Value, &quot;Value&quot;) Then GoTo Catch
  651. End If
  652. If Not Exists(Key) Then GoTo CatchUnknown
  653. Try:
  654. &apos; Find entry in MapItems and update it with the new value
  655. lIndex = MapKeys.Item(Key)
  656. oItemMap = MapItems(lIndex)
  657. oItemMap.Value = Value
  658. ReplaceItem = True
  659. Finally:
  660. SF_Utils._ExitFunction(cstThisSub)
  661. Exit Function
  662. Catch:
  663. GoTo Finally
  664. CatchUnknown:
  665. SF_Exception.RaiseFatal(UNKNOWNKEYERROR, &quot;Key&quot;, Key)
  666. GoTo Finally
  667. End Function &apos; ScriptForge.SF_Dictionary.ReplaceItem
  668. REM -----------------------------------------------------------------------------
  669. Public Function ReplaceKey(Optional ByVal Key As Variant _
  670. , Optional ByVal Value As Variant _
  671. ) As Boolean
  672. &apos;&apos;&apos; Replace existing key
  673. &apos;&apos;&apos; Args:
  674. &apos;&apos;&apos; Key: must exist in the dictionary
  675. &apos;&apos;&apos; Value: must not exist in the dictionary
  676. &apos;&apos;&apos; Returns: True if successful
  677. &apos;&apos;&apos; Exceptions:
  678. &apos;&apos;&apos; UNKNOWNKEYERROR: the old key does not exist
  679. &apos;&apos;&apos; DUPLICATEKEYERROR: the new key exists
  680. &apos;&apos;&apos; Examples:
  681. &apos;&apos;&apos; myDict.ReplaceKey(&quot;OldKey&quot;, &quot;NewKey&quot;)
  682. Dim oItemMap As ItemMap &apos; Content to update in the MapItems array
  683. Dim lIndex As Long &apos; Entry in the MapItems array
  684. Const cstThisSub = &quot;Dictionary.ReplaceKey&quot;
  685. Const cstSubArgs = &quot;Key, Value&quot;
  686. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  687. ReplaceKey = False
  688. Check:
  689. If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  690. If Not SF_Utils._Validate(Key, &quot;Key&quot;, V_STRING) Then GoTo Catch
  691. If Not SF_Utils._Validate(Value, &quot;Value&quot;, V_STRING) Then GoTo Catch
  692. End If
  693. If Not Exists(Key) Then GoTo CatchUnknown
  694. If Value = Space(Len(Value)) Then GoTo CatchInvalid
  695. If Exists(Value) Then GoTo CatchDuplicate
  696. Try:
  697. &apos; Remove the Key entry and create a new one in MapKeys
  698. With MapKeys
  699. lIndex = .Item(Key)
  700. .Remove(Key)
  701. .Add(lIndex, Value)
  702. End With
  703. oItemMap = MapItems(lIndex)
  704. oItemMap.Key = Value
  705. ReplaceKey = True
  706. Finally:
  707. SF_Utils._ExitFunction(cstThisSub)
  708. Exit Function
  709. Catch:
  710. GoTo Finally
  711. CatchUnknown:
  712. SF_Exception.RaiseFatal(UNKNOWNKEYERROR, &quot;Key&quot;, Key)
  713. GoTo Finally
  714. CatchDuplicate:
  715. SF_Exception.RaiseFatal(DUPLICATEKEYERROR, &quot;Value&quot;, Value)
  716. GoTo Finally
  717. CatchInvalid:
  718. SF_Exception.RaiseFatal(INVALIDKEYERROR, &quot;Key&quot;)
  719. GoTo Finally
  720. End Function &apos; ScriptForge.SF_Dictionary.ReplaceKey
  721. REM -----------------------------------------------------------------------------
  722. Public Function SetProperty(Optional ByVal PropertyName As Variant _
  723. , Optional ByRef Value As Variant _
  724. ) As Boolean
  725. &apos;&apos;&apos; Set a new value to the given property
  726. &apos;&apos;&apos; Args:
  727. &apos;&apos;&apos; PropertyName: the name of the property as a string
  728. &apos;&apos;&apos; Value: its new value
  729. &apos;&apos;&apos; Exceptions
  730. &apos;&apos;&apos; ARGUMENTERROR The property does not exist
  731. Const cstThisSub = &quot;Dictionary.SetProperty&quot;
  732. Const cstSubArgs = &quot;PropertyName, Value&quot;
  733. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  734. SetProperty = False
  735. Check:
  736. If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
  737. If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
  738. End If
  739. Try:
  740. Select Case UCase(PropertyName)
  741. Case Else
  742. End Select
  743. Finally:
  744. SF_Utils._ExitFunction(cstThisSub)
  745. Exit Function
  746. Catch:
  747. GoTo Finally
  748. End Function &apos; ScriptForge.SF_Dictionary.SetProperty
  749. REM =========================================================== PRIVATE FUNCTIONS
  750. REM -----------------------------------------------------------------------------
  751. Private Function _PropertyGet(Optional ByVal psProperty As String _
  752. , Optional pvKey As Variant _
  753. )
  754. &apos;&apos;&apos; Return the named property
  755. &apos;&apos;&apos; Args:
  756. &apos;&apos;&apos; psProperty: the name of the property
  757. &apos;&apos;&apos; pvKey: the key to retrieve, numeric or string
  758. Dim vItemMap As Variant &apos; Entry in the MapItems array
  759. Dim vArray As Variant &apos; To get Keys or Values
  760. Dim i As Long
  761. Dim cstThisSub As String
  762. Dim cstSubArgs As String
  763. If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
  764. cstThisSub = &quot;SF_Dictionary.get&quot; &amp; psProperty
  765. If IsMissing(pvKey) Then cstSubArgs = &quot;&quot; Else cstSubArgs = &quot;[Key]&quot;
  766. SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
  767. Select Case UCase(psProperty)
  768. Case UCase(&quot;Count&quot;)
  769. _PropertyGet = _MapSize - _MapRemoved
  770. Case UCase(&quot;Item&quot;)
  771. If Not SF_Utils._Validate(pvKey, &quot;Key&quot;, V_STRING) Then GoTo Catch
  772. If Exists(pvKey) Then _PropertyGet = MapItems(MapKeys(pvKey)).Value Else _PropertyGet = Empty
  773. Case UCase(&quot;Keys&quot;), UCase(&quot;Items&quot;)
  774. vArray = Array()
  775. If _MapSize - _MapRemoved - 1 &gt;= 0 Then
  776. ReDim vArray(0 To (_MapSize - _MapRemoved - 1))
  777. i = -1
  778. For each vItemMap In MapItems()
  779. If Not IsEmpty(vItemMap) Then
  780. i = i + 1
  781. If UCase(psProperty) = &quot;KEYS&quot; Then vArray(i) = vItemMap.Key Else vArray(i) = vItemMap.Value
  782. End If
  783. Next vItemMap
  784. End If
  785. _PropertyGet = vArray
  786. End Select
  787. Finally:
  788. SF_Utils._ExitFunction(cstThisSub)
  789. Exit Function
  790. Catch:
  791. GoTo Finally
  792. End Function &apos; ScriptForge.SF_Dictionary._PropertyGet
  793. REM -----------------------------------------------------------------------------
  794. Private Function _Repr() As String
  795. &apos;&apos;&apos; Convert the Dictionary instance to a readable string, typically for debugging purposes (DebugPrint ...)
  796. &apos;&apos;&apos; Args:
  797. &apos;&apos;&apos; Return:
  798. &apos;&apos;&apos; &quot;[Dictionary] (key1:value1, key2:value2, ...)
  799. Dim sDict As String &apos; Return value
  800. Dim vKeys As Variant &apos; Array of keys
  801. Dim sKey As String &apos; Tempry key
  802. Dim vItem As Variant &apos; Tempry item
  803. Const cstDictEmpty = &quot;[Dictionary] ()&quot;
  804. Const cstDict = &quot;[Dictionary]&quot;
  805. Const cstMaxLength = 50 &apos; Maximum length for items
  806. Const cstSeparator = &quot;, &quot;
  807. _Repr = &quot;&quot;
  808. If Count = 0 Then
  809. sDict = cstDictEmpty
  810. Else
  811. sDict = cstDict &amp; &quot; (&quot;
  812. vKeys = Keys
  813. For Each sKey in vKeys
  814. vItem = Item(sKey)
  815. sDict = sDict &amp; sKey &amp; &quot;:&quot; &amp; SF_Utils._Repr(vItem, cstMaxLength) &amp; cstSeparator
  816. Next sKey
  817. sDict = Left(sDict, Len(sDict) - Len(cstSeparator)) &amp; &quot;)&quot; &apos; Suppress last comma
  818. End If
  819. _Repr = sDict
  820. End Function &apos; ScriptForge.SF_Dictionary._Repr
  821. REM ============================================ END OF SCRIPTFORGE.SF_DICTIONARY
  822. </script:module>