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