ScriptForge (Dictionary) support case-sensitive keys

To enhance the compatibility between
 - sf dictionaries
 - python dicts
 - arrays of PropertyValues
it was necessary to propose the support
of case-sensitive keys, i.e. keys are
different if a case-sensitive comparison
finds them different.

So far only not case-sensitive keys
were supported.

This required a re-visit of the implementation
of the ScriptForge.SF_Dictionary service. So far
it was built upon a Basic Collection class which
differentiates keys not case-sensitively. The
new implementation uses sorted arrays.

The invocation of the service is now:
   dict = CreateScriptService("Dictionary", True/False)
True means case-sensitive keys.
Default = False, which preserves the compatibility
with the past.

ScriptForge uses dictionaries internally in
several places. For each of them it has been
assessed if the new attribute was justified
or not. For most of the contexts, it was.

The functionality makes sense only for Basic
user scripts.

The documentation of the Dictionary page
should be revised according to the new invocation
syntax.

Change-Id: If1f695bcbf1673a2b71c1e41487b1781caab71c2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173044
Tested-by: Jenkins
Reviewed-by: Jean-Pierre Ledure <jp@ledure.be>
This commit is contained in:
Jean-Pierre Ledure 2024-09-08 15:47:27 +02:00
parent 7639d70703
commit 70f3fea2f3
14 changed files with 100 additions and 90 deletions

View file

@ -336,7 +336,7 @@ End Function &apos; ScriptForge.SF_Array.Contains
REM -----------------------------------------------------------------------------
Public Function ConvertToDictionary(Optional ByRef Array_2D As Variant) As Variant
&apos;&apos;&apos; Store the content of a 2-columns array into a dictionary
&apos;&apos;&apos; Store the content of a 2-columns array into a dictionary with case-sensitive comparison of keys
&apos;&apos;&apos; Key found in 1st column, Item found in 2nd
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Array_2D: 1st column must contain exclusively non zero-length strings
@ -348,7 +348,7 @@ Public Function ConvertToDictionary(Optional ByRef Array_2D As Variant) As Varia
Dim oDict As Variant &apos; Return value
Dim i As Long
Const cstThisSub = &quot;Dictionary.ConvertToArray&quot;
Const cstThisSub = &quot;Array.ConvertToDictionary&quot;
Const cstSubArgs = &quot;Array_2D&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
@ -359,7 +359,7 @@ Check:
End If
Try:
Set oDict = SF_Services.CreateScriptService(&quot;Dictionary&quot;)
Set oDict = SF_Services.CreateScriptService(&quot;Dictionary&quot;, True)
For i = LBound(Array_2D, 1) To UBound(Array_2D, 1)
oDict.Add(Array_2D(i, 0), Array_2D(i, 1))
Next i

View file

@ -15,21 +15,23 @@ Option Explicit
&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; The key is either a case-sensitive or 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; The implementation is based on 3 one-column arrays:
&apos;&apos;&apos; 1) The keys - sorted
&apos;&apos;&apos; 2) The positions in 3) - same sequence as 1)
&apos;&apos;&apos; 3) The item contents - stacked up when defined - erased items are set to Empty
&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; A standard Basic collection does not support the update/removal of entries
&apos;&apos;&apos; No easy conversion to/from json or PropertyValues
&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; myDict = CreateScriptService(&quot;Dictionary&quot;, True) &apos; Case-sensitive, default = False
&apos;&apos;&apos;
&apos;&apos;&apos; Detailed user documentation:
&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_dictionary.html?DbPAR=BASIC
@ -43,17 +45,13 @@ Const INVALIDKEYERROR = &quot;INVALIDKEYERROR&quot; &apos; Key contains only
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 CaseSensitive As Boolean &apos; Determined at dictionary creation, default = False
Private MapKeys As Variant &apos; Array of keys
Private MapPositions As Variant &apos; Array of indexes in MapItems, sorted as MapKeys
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
@ -66,8 +64,10 @@ Private Sub Class_Initialize()
Set [_Parent] = Nothing
ObjectType = &quot;DICTIONARY&quot;
ServiceName = &quot;ScriptForge.Dictionary&quot;
Set MapKeys = New Collection
Set MapItems = Array()
CaseSensitive = False
MapKeys = Array()
MapPositions = Array()
MapItems = Array()
_MapSize = 0
_MapRemoved = 0
End Sub &apos; ScriptForge.SF_Dictionary Constructor
@ -157,7 +157,8 @@ Public Function Add(Optional ByVal Key As Variant _
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myDict.Add(&quot;NewKey&quot;, NewValue)
Dim oItemMap As ItemMap &apos; New entry in the MapItems array
Dim vItemMap As Variant &apos; Output of SF_Array._FindItem
Dim lIndex As Long &apos; Index in MapKeys and MapPositions
Const cstThisSub = &quot;Dictionary.Add&quot;
Const cstSubArgs = &quot;Key, Item&quot;
@ -174,15 +175,16 @@ Check:
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
vItemMap = SF_Array._FindItem(MapKeys, Key, CaseSensitive, &quot;ASC&quot;)
If vItemMap(0) Then GoTo CatchDuplicate &apos; Key exists already
lIndex = vItemMap(1)
MapKeys = SF_Array.Insert(MapKeys, lIndex, Key)
MapPositions = SF_Array.Insert(MapPositions, lIndex, _MapSize)
ReDim Preserve MapItems(1 To _MapSize)
MapItems(_MapSize) = oItemMap
MapItems(_MapSize) = Item
Add = True
Finally:
@ -404,12 +406,7 @@ Check:
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
Exists = SF_Array.Contains(MapKeys, Key, CaseSensitive, SortOrder := &quot;ASC&quot;)
Finally:
SF_Utils._ExitFunction(cstThisSub)
@ -660,7 +657,8 @@ Public Function Remove(Optional ByVal Key As Variant) As Boolean
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myDict.Remove(&quot;OldKey&quot;)
Dim lIndex As Long &apos; To remove entry in the MapItems array
Dim vItemMap As Variant &apos; Output of SF_Array._FindItem
Dim lIndex As Long &apos; Index in MapKeys and MapPositions
Const cstThisSub = &quot;Dictionary.Remove&quot;
Const cstSubArgs = &quot;Key&quot;
@ -671,12 +669,15 @@ 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
vItemMap = SF_Array._FindItem(MapKeys, Key, CaseSensitive, &quot;ASC&quot;)
If Not vItemMap(0) Then GoTo CatchUnknown
lIndex = vItemMap(1)
MapKeys(lIndex) = &quot;&quot;
MapKeys = SF_Array.TrimArray(MapKeys)
Erase MapItems(MapPositions(lIndex))
MapPositions(lIndex) = Null
MapPositions = SF_Array.TrimArray(MapPositions)
_MapRemoved = _MapRemoved + 1
Remove = True
@ -712,7 +713,7 @@ Check:
Try:
vKeys = Keys
For Each sColl In vKeys
MapKeys.Remove(sColl)
Remove(sColl)
Next sColl
Erase MapKeys
Erase MapItems
@ -740,7 +741,7 @@ Public Function ReplaceItem(Optional ByVal Key As Variant _
&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 vItemMap As Variant &apos; Output of SF_Array._FindItem
Dim lIndex As Long &apos; Entry in the MapItems array
Const cstThisSub = &quot;Dictionary.ReplaceItem&quot;
Const cstSubArgs = &quot;Key, Value&quot;
@ -757,13 +758,13 @@ Check:
If Not SF_Utils._Validate(Value, &quot;Value&quot;) Then GoTo Catch
End If
End If
If Not Exists(Key) Then GoTo CatchUnknown
Try:
&apos; Find entry in MapItems and update it with the new value
lIndex = MapKeys.Item(Key)
oItemMap = MapItems(lIndex)
oItemMap.Value = Value
vItemMap = SF_Array._FindItem(MapKeys, Key, CaseSensitive, &quot;ASC&quot;)
If Not vItemMap(0) Then GoTo CatchUnknown
lIndex = vItemMap(1)
MapItems(MapPositions(lIndex)) = Value
ReplaceItem = True
Finally:
@ -791,8 +792,6 @@ Public Function ReplaceKey(Optional ByVal Key As Variant _
&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;
@ -809,14 +808,9 @@ Check:
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
&apos; Remove the Key entry and create a new one
Add(Value, Item(Key))
Remove(Key)
ReplaceKey = True
Finally:
@ -880,8 +874,9 @@ Private Function _PropertyGet(Optional ByVal psProperty As String _
&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 vItemMap As Variant &apos; Output of SF_Array._FindItem
Dim lIndex As Long &apos; Entry in the MapItems array
Dim vArray As Variant &apos; To get Keys or Items
Dim i As Long
Dim cstThisSub As String
Dim cstSubArgs As String
@ -898,18 +893,19 @@ Dim cstSubArgs As String
_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
vItemMap = SF_Array._FindItem(MapKeys, pvKey, CaseSensitive, &quot;ASC&quot;)
lIndex = vItemMap(1)
If vItemMap(0) Then _PropertyGet = MapItems(MapPositions(lIndex)) 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
If UBound(MapKeys) &gt;= 0 Then
ReDim vArray(0 To UBound(MapKeys))
For i = 0 To UBound(MapKeys)
Select Case UCase(psProperty)
Case &quot;KEYS&quot; : vArray(i) = MapKeys(i)
Case &quot;ITEMS&quot; : vArray(i) = MapItems(MapPositions(i))
End Select
Next i
End If
_PropertyGet = vArray
End Select

View file

@ -670,8 +670,8 @@ 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;)
&apos; Initialize dictionary anyway with case-sensitive comparison of keys
Set _Dictionary = SF_Services.CreateScriptService(&quot;Dictionary&quot;, True)
Set _Dictionary.[_Parent] = [Me]
&apos; Load PO file

View file

@ -221,7 +221,7 @@ REM ----------------------------------------------------------------------------
Property Get UserData() As Variant
&apos;&apos;&apos; Returns a dictionary of all Options + User Data values
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox platform.UserData
&apos;&apos;&apos; dict = platform.UserData
UserData = _PropertyGet(&quot;UserData&quot;)
End Property &apos; ScriptForge.SF_Platform.UserData (get)
@ -464,8 +464,8 @@ Const cstSubArgs = &quot;&quot;
)
&apos; Get the UserData page from the Options database
vUserDataOptions = SF_Utils._GetRegistryKeyContent(&quot;org.openoffice.UserProfile/Data&quot;)
&apos; Create and feed the output dictionary
vUserData = CreateScriptService(&quot;ScriptForge.Dictionary&quot;)
&apos; Create and feed an output dictionary with case-sensitive comparison of keys
vUserData = CreateScriptService(&quot;ScriptForge.Dictionary&quot;, True)
For i = 0 To UBound(vUserDataExternal)
vUserData.Add(vUserDataExternal(i), vUserDataOptions.getByName(vUserDataInternal(i)))
Next i

View file

@ -635,7 +635,7 @@ Check:
&apos; Reinterpret arguments one by one into vArgs
&apos; - convert UNO dates/times
&apos; - identify conventional NoArgs/Empty/Null/Missing constants
&apos; - convert arrays of property values into DictionarY
&apos; - convert arrays of property values into Dictionary
iNbArgs = -1
vArgs = Array()
@ -667,7 +667,8 @@ Check:
If IsArray(vArg) Then
If UBound(vArg) &gt;= 0 Then
If sess.UnoObjectType(vArg(0)) = &quot;com.sun.star.beans.PropertyValue&quot; Then
Set oDict = CreateScriptService(&quot;ScriptForge.Dictionary&quot;)
&apos; Create a dictionary - keys in Python dicts are case-sensitive
Set oDict = CreateScriptService(&quot;ScriptForge.Dictionary&quot;, True)
oDict.ImportFromPropertyValues(vArg, Overwrite := True)
vArg = oDict
End If

View file

@ -41,7 +41,7 @@ Const UNKNOWNFILEERROR = &quot;UNKNOWNFILEERROR&quot; &apos; Source file doe
REM ============================================================== PUBLIC MEMBERS
&apos; Defines an entry in in the services dictionary
&apos; Defines an entry in the services dictionary
Type _Service
ServiceName As String
ServiceType As Integer
@ -494,19 +494,31 @@ Finally:
End Function &apos; ScriptForge.SF_Services._LoadLibraryServices
REM -----------------------------------------------------------------------------
Public Function _NewDictionary() As Variant
Public Function _NewDictionary(Optional ByVal pvArgs As Variant) As Variant
&apos;&apos;&apos; Create a new instance of the SF_Dictionary class
&apos;&apos;&apos; Args:
&apos;&apos;&apos; [0] : If True, the keys are compared case-sensitively. Default = False
&apos;&apos;&apos; Returns: the instance or Nothing
Dim oDict As Variant
Dim oDict As Variant &apos; Reurn value
Dim bCaseSensitive As Boolean &apos; Keys comparison
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
If IsMissing(pvArgs) Then pvArgs = Array()
If Not IsArray(pvArgs) Then pvArgs = Array(pvArgs)
If UBound(pvArgs) &lt; 0 Then
bCaseSensitive = False
Else
If Not SF_Utils._Validate(pvArgs(0), &quot;CaseSensitive (Arg0)&quot;, V_BOOLEAN) Then GoTo Catch
bCaseSensitive = pvArgs(0)
End If
Try:
Set oDict = New SF_Dictionary
Set oDict.[Me] = oDict
oDict.CaseSensitive = bCaseSensitive
Finally:
Set _NewDictionary = oDict

View file

@ -355,8 +355,8 @@ Try:
Set oNodePath = SF_Utils._MakePropertyValue(&quot;nodepath&quot;, &quot;/org.openoffice.Office.Common/Filter/PDF/Export/&quot;)
Set oOptions = oConfig.createInstanceWithArguments(&quot;com.sun.star.configuration.ConfigurationAccess&quot;, Array(oNodePath))
&apos; Copy the options into a ScriptForge dictionary
Set vDict = CreateScriptService(&quot;dictionary&quot;)
&apos; Copy the options into a ScriptForge dictionary with case-sensitive comparison of keys
Set vDict = CreateScriptService(&quot;Dictionary&quot;, True)
vOptionNames = oOptions.getElementNames()
vOptionValues = oOptions.getPropertyValues(vOptionNames)
&apos;

View file

@ -1427,7 +1427,7 @@ Check:
If IsNull(poComponent) Then GoTo Catch
Try:
Set oToolbarsDict = CreateScriptService(&quot;Dictionary&quot;)
Set oToolbarsDict = CreateScriptService(&quot;Dictionary&quot;, True) &apos; with case-sensitive comparison of keys
&apos; 1. Collect all builtin and custom toolbars stored in the LibreOffice configuration files

View file

@ -1381,7 +1381,7 @@ Private Function _PropertyGet(Optional ByVal psProperty As String) As Variant
Dim vBookmark As Variant &apos; Bookmark on the current record
Dim vValue As Variant &apos; A single record field value
Dim vValuesDict As Object &apos; A dictionary (field name, field value)
Dim vValuesDict As Object &apos; A dictionary (field name, field value)
Dim i As Long
Dim cstThisSub As String
@ -1397,8 +1397,8 @@ Const cstSubArgs = &quot;&quot;
Case &quot;BOF&quot;
_PropertyGet = .isBeforeFirst()
Case &quot;DefaultValues&quot;
&apos; Load the pairs field name / field default value in the dictionary
vValuesDict = ScriptForge.SF_Services.CreateScriptService(&quot;ScriptForge.Dictionary&quot;)
&apos; Load the pairs field name / field default value in the dictionary (with case-sensitive comparison of keys)
vValuesDict = ScriptForge.SF_Services.CreateScriptService(&quot;ScriptForge.Dictionary&quot;, True)
For i = 0 To UBound(_DefaultValues)
vValuesDict.Add(_Fields(i), _DefaultValues(i))
Next i
@ -1434,8 +1434,8 @@ Const cstSubArgs = &quot;&quot;
If .isBeforeFirst() Or .isAfterLast() Or .rowDeleted() Then
Set _PropertyGet = Nothing
Else
&apos; Load the pairs field name / field value in the dictionary
vValuesDict = ScriptForge.SF_Services.CreateScriptService(&quot;ScriptForge.Dictionary&quot;)
&apos; Load the pairs field name / field value in the dictionary (with case-sensitive comparison of keys)
vValuesDict = ScriptForge.SF_Services.CreateScriptService(&quot;ScriptForge.Dictionary&quot;, True)
For i = 0 To UBound(_Fields)
vValue = _ParentDatabase._GetColumnValue(_RowSet, i + 1, False)
vValuesDict.Add(_Fields(i), vValue)

View file

@ -2101,7 +2101,7 @@ End Function &apos; SFDocuments.SF_Document._ListContextMenus
REM -----------------------------------------------------------------------------
Private Sub _LoadDocumentProperties()
&apos;&apos;&apos; Create dictionary with document properties as entries/ Custom properties are excluded
&apos;&apos;&apos; Create dictionary with document properties as entries / Custom properties are excluded
&apos;&apos;&apos; Document is presumed still alive
&apos;&apos;&apos; Special values:
&apos;&apos;&apos; Only valid dates are taken
@ -2169,7 +2169,8 @@ Const cstSubArgs = &quot;&quot;
Select Case psProperty
Case &quot;CustomProperties&quot;
_CustomProperties = CreateScriptService(&quot;Dictionary&quot;) &apos; Always reload as updates could have been done manually by user
_CustomProperties = CreateScriptService(&quot;Dictionary&quot;, True) &apos; Always reload as updates could have been done manually by user
&apos; (with case-sensitive comparison of keys)
_CustomProperties.ImportFromPropertyValues(_Component.getDocumentProperties().UserDefinedProperties.getPropertyValues)
_PropertyGet = _CustomProperties
Case &quot;Description&quot;

View file

@ -1515,7 +1515,7 @@ Try:
bEval = ( Len(A) &gt; 0 )
If bEval Then
Set oAliasB = B
bEval = ScriptForge.SF_Array.Contains(oAliasB.Keys(), A, CaseSensitive := True)
bEval = ScriptForge.SF_Array.Contains(oAliasB.Keys(), A, CaseSensitive := oAliasB.CaseSensitive)
End If
Case Else
bEval = False

View file

@ -482,7 +482,7 @@ Dim MainConfigManager As Object &apos; com.sun.star.ui.XUIConfigurationManager
Try:
&apos; Initialize the dictionary
Set MenuTree = ScriptForge.SF_Services.CreateScriptService(&quot;Dictionary&quot;)
Set MenuTree = ScriptForge.SF_Services.CreateScriptService(&quot;Dictionary&quot;, True) &apos; with case-sensitive comparison of keys
&apos; Identify the container of the menu tree
&apos; The container is taken either from the system configuration manager of from the local (= in document) one

View file

@ -710,10 +710,10 @@ Public Sub _Initialize(ByRef poPeer As Object _
&apos;&apos;&apos; plXPos, plYPos: the coordinates
Try:
&apos; Initialize the dictionaries
&apos; Initialize the dictionaries (with case-sensitive comparison of keys)
With ScriptForge.SF_Services
Set MenuTree = .CreateScriptService(&quot;Dictionary&quot;)
Set MenuIdentification = .CreateScriptService(&quot;Dictionary&quot;)
Set MenuTree = .CreateScriptService(&quot;Dictionary&quot;, True)
Set MenuIdentification = .CreateScriptService(&quot;Dictionary&quot;, True)
End With
&apos; Initialize the root of the menu tree

View file

@ -372,7 +372,7 @@ Try:
&apos; Force the visibility of the toolbar
Visible = True
Set _ToolbarButtons = ScriptForge.SF_Services.CreateScriptService(&quot;ScriptForge.Dictionary&quot;)
Set _ToolbarButtons = ScriptForge.SF_Services.CreateScriptService(&quot;ScriptForge.Dictionary&quot;, True) &apos; with case-sensitive comparison of keys
Set oElement = _LayoutManager.getElement(_ResourceURL)
Set oSettings = oElement.getSettings(True)