summaryrefslogtreecommitdiff
path: root/wizards
diff options
context:
space:
mode:
authorJean-Pierre Ledure <jp@ledure.be>2021-12-03 12:18:17 +0100
committerJean-Pierre Ledure <jp@ledure.be>2021-12-03 15:24:57 +0100
commit88c82f10280a3de773091ddc41983c6d2f8ee157 (patch)
treec4f445c29b967e63cb92f4fdb125c00b3cb7fe57 /wizards
parent4321fb516f4a65b047b182c4cb6f9c9a232efd85 (diff)
ScriptForge - (SFWidgets) new SF_Menu service
Display a menu in the menubar of a document (form document to be done) After use, the menu will not be saved neither in the application settings, nor in the document. The menu setting does not affect the modified status of the document. The menu will be displayed, as usual, when its header in the menubar is clicked. When one of its items is selected, there are 3 alternative options: - a UNO command (like ".uno:About") is triggered - a user script is run receiving a standard argument defined in this service - one of above combined with a toggle of the status of the item The menu is described from top to bottom. Each menu item receives a numeric and a string identifier. Each menu item may be decorated with a tooltip and/or an icon. The AddItem(), AddCheckBox() and AddRadioButton() methods, when coompared with their equivalents in the SF_PopupMenu service, receive 2 additional arguments: Command and Script. The various document services receive 2 additional methods: CreateMenu(), returning a Menu service instance RemoveMenu() Very short example: menu = doc.CreateMenu("My menu", Before := "Help") menu.AddItem("First Item", Command := "About") menu.AddItem('2nd Item", Script := "... URI notation ...") menu.Dispose() ' Once set the menu object may ve erased, listeners stay tuned Later in the lifecycle of the document, one may run: doc.RemoveMenu("My menu") ' doc.RemoveMenu("File") works as well !!! All the functionalities are available both in Basic and Python user scripts. Change-Id: Iabd157573693e9648fcb06d36c90af9a22b17a6c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126309 Tested-by: Jean-Pierre Ledure <jp@ledure.be> Tested-by: Jenkins Reviewed-by: Jean-Pierre Ledure <jp@ledure.be>
Diffstat (limited to 'wizards')
-rw-r--r--wizards/Package_sfwidgets.mk2
-rw-r--r--wizards/source/scriptforge/SF_Services.xba2
-rw-r--r--wizards/source/scriptforge/SF_Session.xba9
-rw-r--r--wizards/source/scriptforge/python/scriptforge.py39
-rw-r--r--wizards/source/sfdocuments/SF_Base.xba18
-rw-r--r--wizards/source/sfdocuments/SF_Calc.xba21
-rw-r--r--wizards/source/sfdocuments/SF_Document.xba134
-rw-r--r--wizards/source/sfdocuments/SF_Writer.xba15
-rw-r--r--wizards/source/sfwidgets/SF_Menu.xba590
-rw-r--r--wizards/source/sfwidgets/SF_MenuListener.xba128
-rw-r--r--wizards/source/sfwidgets/SF_PopupMenu.xba82
-rw-r--r--wizards/source/sfwidgets/SF_Register.xba64
-rw-r--r--wizards/source/sfwidgets/script.xlb2
13 files changed, 1071 insertions, 35 deletions
diff --git a/wizards/Package_sfwidgets.mk b/wizards/Package_sfwidgets.mk
index f89b83e58d5b..3e2041a5f810 100644
--- a/wizards/Package_sfwidgets.mk
+++ b/wizards/Package_sfwidgets.mk
@@ -20,6 +20,8 @@
$(eval $(call gb_Package_Package,wizards_basicsrvsfwidgets,$(SRCDIR)/wizards/source/sfwidgets))
$(eval $(call gb_Package_add_files,wizards_basicsrvsfwidgets,$(LIBO_SHARE_FOLDER)/basic/SFWidgets,\
+ SF_Menu.xba \
+ SF_MenuListener.xba \
SF_PopupMenu.xba \
SF_Register.xba \
__License.xba \
diff --git a/wizards/source/scriptforge/SF_Services.xba b/wizards/source/scriptforge/SF_Services.xba
index 74bc110c9371..a2a96cb088c6 100644
--- a/wizards/source/scriptforge/SF_Services.xba
+++ b/wizards/source/scriptforge/SF_Services.xba
@@ -130,7 +130,7 @@ Try:
sLibrary = &quot;SFDocuments&quot;
Case &quot;dialog&quot;, &quot;dialogevent&quot; : sLibrary = &quot;SFDialogs&quot;
Case &quot;database&quot; : sLibrary = &quot;SFDatabases&quot;
- Case &quot;popupmenu&quot; : sLibrary = &quot;SFWidgets&quot;
+ Case &quot;menu&quot;, &quot;popupmenu&quot; : sLibrary = &quot;SFWidgets&quot;
Case Else
End Select
Else
diff --git a/wizards/source/scriptforge/SF_Session.xba b/wizards/source/scriptforge/SF_Session.xba
index db3cb9449889..f02a958768ce 100644
--- a/wizards/source/scriptforge/SF_Session.xba
+++ b/wizards/source/scriptforge/SF_Session.xba
@@ -994,12 +994,13 @@ REM =========================================================== PRIVATE FUNCTION
REM -----------------------------------------------------------------------------
Private Function _ExecuteScript(ByVal psScript As String _
- , ByRef poEvent As Object _
+ , Optional ByRef pvArg As Variant _
) As Variant
&apos;&apos;&apos; Execute the script expressed in the scripting framework_URI notation
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psScript: read https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification
-&apos;&apos;&apos; poEvent: the event object which triggered the execution. It is given as argument to the called script
+&apos;&apos;&apos; pvArg: the unique argument to pass to the called script.
+&apos;&apos;&apos; It is often an event object that triggered the execution of the script.
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The return value after the script execution. May be ignored for events
@@ -1020,9 +1021,9 @@ Try:
sScript = vStrings(0) : sLanguage = vStrings(1) : sScope = vStrings(2)
&apos; Execute script
If UCase(sLanguage) = &quot;BASIC&quot; Then
- _ExecuteScript = ExecuteBasicScript(sScope, sScript, poEvent)
+ _ExecuteScript = ExecuteBasicScript(sScope, sScript, pvArg)
Else &apos; Python
- _ExecuteScript = ExecutePythonScript(sScope, sScript, poEvent)
+ _ExecuteScript = ExecutePythonScript(sScope, sScript, pvArg)
End If
End If
diff --git a/wizards/source/scriptforge/python/scriptforge.py b/wizards/source/scriptforge/python/scriptforge.py
index 9dc95d21f715..18334f3684c8 100644
--- a/wizards/source/scriptforge/python/scriptforge.py
+++ b/wizards/source/scriptforge/python/scriptforge.py
@@ -1774,12 +1774,18 @@ class SFDocuments:
def CloseDocument(self, saveask = True):
return self.ExecMethod(self.vbMethod, 'CloseDocument', saveask)
+ def CreateMenu(self, menuheader, before = '', submenuchar = '>'):
+ return self.ExecMethod(self.vbMethod, 'CreateMenu', menuheader, before, submenuchar)
+
def ExportAsPDF(self, filename, overwrite = False, pages = '', password = '', watermark = ''):
return self.ExecMethod(self.vbMethod, 'ExportAsPDF', filename, overwrite, pages, password, watermark)
def PrintOut(self, pages = '', copies = 1):
return self.ExecMethod(self.vbMethod, 'PrintOut', pages, copies)
+ def RemoveMenu(self, menuheader):
+ return self.ExecMethod(self.vbMethod, 'RemoveMenu', menuheader)
+
def RunCommand(self, command):
return self.ExecMethod(self.vbMethod, 'RunCommand', command)
@@ -2230,6 +2236,39 @@ class SFWidgets:
pass
# #########################################################################
+ # SF_Menu CLASS
+ # #########################################################################
+ class SF_Menu(SFServices):
+ """
+ Display a menu in the menubar of a document or a form document.
+ After use, the menu will not be saved neither in the application settings, nor in the document.
+ The menu will be displayed, as usual, when its header in the menubar is clicked.
+ When one of its items is selected, there are 3 alternative options:
+ - a UNO command (like ".uno:About") is triggered
+ - a user script is run receiving a standard argument defined in this service
+ - one of above combined with a toggle of the status of the item
+ The menu is described from top to bottom. Each menu item receives a numeric and a string identifier.
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFWidgets.Menu'
+ servicesynonyms = ('menu', 'sfwidgets.menu')
+ serviceproperties = dict(ShortcutCharacter = False, SubmenuCharacter = False)
+
+ def AddCheckBox(self, menuitem, name = '', status = False, icon = '', tooltip = '',
+ command = '', script = ''):
+ return self.ExecMethod(self.vbMethod, 'AddCheckBox', menuitem, name, status, icon, tooltip,
+ command, script)
+
+ def AddItem(self, menuitem, name = '', icon = '', tooltip = '', command = '', script = ''):
+ return self.ExecMethod(self.vbMethod, 'AddItem', menuitem, name, icon, tooltip, command, script)
+
+ def AddRadioButton(self, menuitem, name = '', status = False, icon = '', tooltip = '',
+ command = '', script = ''):
+ return self.ExecMethod(self.vbMethod, 'AddRadioButton', menuitem, name, status, icon, tooltip,
+ command, script)
+
+ # #########################################################################
# SF_PopupMenu CLASS
# #########################################################################
class SF_PopupMenu(SFServices):
diff --git a/wizards/source/sfdocuments/SF_Base.xba b/wizards/source/sfdocuments/SF_Base.xba
index efdc57be9b4d..0199341bb5da 100644
--- a/wizards/source/sfdocuments/SF_Base.xba
+++ b/wizards/source/sfdocuments/SF_Base.xba
@@ -120,7 +120,7 @@ Check:
If IsMissing(SaveAsk) Or IsEmpty(SaveAsk) Then SaveAsk = True
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive(True) Then GoTo Finally
- If Not ScriptForge.SF_Utils._Validate(SaveAsk, &quot;SaveAsk&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SaveAsk, &quot;SaveAsk&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
End If
Try:
@@ -442,12 +442,15 @@ Public Function Methods() As Variant
Methods = Array( _
&quot;Activate&quot; _
, &quot;CloseDocument&quot; _
+ , &quot;CloseFormDocument&quot; _
+ , &quot;CreateMenu&quot; _
, &quot;FormDocuments&quot; _
, &quot;Forms&quot; _
, &quot;GetDatabase&quot; _
, &quot;IsLoaded&quot; _
, &quot;OpenFormDocument&quot; _
, &quot;PrintOut&quot; _
+ , &quot;RemoveMenu&quot; _
, &quot;RunCommand&quot; _
, &quot;Save&quot; _
, &quot;SaveAs&quot; _
@@ -792,6 +795,19 @@ Public Function Activate() As Boolean
End Function &apos; SFDocuments.SF_Base.Activate
REM -----------------------------------------------------------------------------
+Public Function CreateMenu(Optional ByVal MenuHeader As Variant _
+ , Optional ByVal Before As Variant _
+ , Optional ByVal SubmenuChar As Variant _
+ ) As Object
+ Set CreateMenu = [_Super].CreateMenu(MenuHeader, Before, SubmenuChar)
+End Function &apos; SFDocuments.SF_Base.CreateMenu
+
+REM -----------------------------------------------------------------------------
+Public Function RemoveMenu(Optional ByVal MenuHeader As Variant) As Boolean
+ RemoveMenu = [_Super].RemoveMenu(MenuHeader)
+End Function &apos; SFDocuments.SF_Base.RemoveMenu
+
+REM -----------------------------------------------------------------------------
Public Sub RunCommand(Optional ByVal Command As Variant)
[_Super].RunCommand(Command)
End Sub &apos; SFDocuments.SF_Base.RunCommand
diff --git a/wizards/source/sfdocuments/SF_Calc.xba b/wizards/source/sfdocuments/SF_Calc.xba
index e5b35e4afa12..f22a64642e36 100644
--- a/wizards/source/sfdocuments/SF_Calc.xba
+++ b/wizards/source/sfdocuments/SF_Calc.xba
@@ -1647,6 +1647,7 @@ Public Function Methods() As Variant
, &quot;CopyToCell&quot; _
, &quot;CopyToRange&quot; _
, &quot;CreateChart&quot; _
+ , &quot;CreateMenu&quot; _
, &quot;DAvg&quot; _
, &quot;DCount&quot; _
, &quot;DMax&quot; _
@@ -1665,6 +1666,7 @@ Public Function Methods() As Variant
, &quot;OpenRangeSelector&quot; _
, &quot;Printf&quot; _
, &quot;PrintOut&quot; _
+ , &quot;RemoveMenu&quot; _
, &quot;RemoveSheet&quot; _
, &quot;RenameSheet&quot; _
, &quot;RunCommand&quot; _
@@ -2889,9 +2891,9 @@ Check:
If Not ScriptForge.SF_Utils._ValidateArray(SortKeys, &quot;SortKeys&quot;, 1, V_NUMERIC, True) Then GoTo Finally
If Not ScriptForge.SF_Utils._Validate(DestinationCell, &quot;DestinationCell&quot;, V_STRING) Then GoTo Finally
If Not ScriptForge.SF_Utils._ValidateArray(SortOrder, &quot;SortOrder&quot;, 1, V_STRING, True) Then GoTo Finally
- If Not ScriptForge.SF_Utils._Validate(ContainsHeader, &quot;ContainsHeader&quot;, V_BOOLEAN) Then GoTo Finally
- If Not ScriptForge.SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
- If Not ScriptForge.SF_Utils._Validate(SortColumns, &quot;SortColumns&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(ContainsHeader, &quot;ContainsHeader&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SortColumns, &quot;SortColumns&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
End If
Set oRangeAddress = _ParseAddress(Range)
If Len(DestinationCell) &gt; 0 Then Set oDestRange = _ParseAddress(DestinationCell)
@@ -3068,6 +3070,14 @@ Public Function CloseDocument(Optional ByVal SaveAsk As Variant) As Boolean
End Function &apos; SFDocuments.SF_Calc.CloseDocument
REM -----------------------------------------------------------------------------
+Public Function CreateMenu(Optional ByVal MenuHeader As Variant _
+ , Optional ByVal Before As Variant _
+ , Optional ByVal SubmenuChar As Variant _
+ ) As Object
+ Set CreateMenu = [_Super].CreateMenu(MenuHeader, Before, SubmenuChar)
+End Function &apos; SFDocuments.SF_Calc.CreateMenu
+
+REM -----------------------------------------------------------------------------
Public Function ExportAsPDF(Optional ByVal FileName As Variant _
, Optional ByVal Overwrite As Variant _
, Optional ByVal Pages As Variant _
@@ -3078,6 +3088,11 @@ Public Function ExportAsPDF(Optional ByVal FileName As Variant _
End Function &apos; SFDocuments.SF_Calc.ExportAsPDF
REM -----------------------------------------------------------------------------
+Public Function RemoveMenu(Optional ByVal MenuHeader As Variant) As Boolean
+ RemoveMenu = [_Super].RemoveMenu(MenuHeader)
+End Function &apos; SFDocuments.SF_Calc.RemoveMenu
+
+REM -----------------------------------------------------------------------------
Public Sub RunCommand(Optional ByVal Command As Variant)
[_Super].RunCommand(Command)
End Sub &apos; SFDocuments.SF_Calc.RunCommand
diff --git a/wizards/source/sfdocuments/SF_Document.xba b/wizards/source/sfdocuments/SF_Document.xba
index 00aa22fc08b4..37c4e4e6bbe7 100644
--- a/wizards/source/sfdocuments/SF_Document.xba
+++ b/wizards/source/sfdocuments/SF_Document.xba
@@ -436,7 +436,7 @@ Check:
If IsMissing(SaveAsk) Or IsEmpty(SaveAsk) Then SaveAsk = True
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive() Then GoTo Finally
- If Not ScriptForge.SF_Utils._Validate(SaveAsk, &quot;SaveAsk&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SaveAsk, &quot;SaveAsk&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
End If
Try:
@@ -460,6 +460,63 @@ Catch:
End Function &apos; SFDocuments.SF_Document.CloseDocument
REM -----------------------------------------------------------------------------
+Public Function CreateMenu(Optional ByVal MenuHeader As Variant _
+ , Optional ByVal Before As Variant _
+ , Optional ByVal SubmenuChar As Variant _
+ , Optional ByRef _Document As Variant _
+ ) As Object
+&apos;&apos;&apos; Create a new menu entry in the document&apos;s menubar
+&apos;&apos;&apos; The menu is not intended to be saved neither in the LibreOffice global environment, nor in the document
+&apos;&apos;&apos; The method returns a SFWidgets.Menu instance. Its methods let define the menu further.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MenuHeader: the name/header of the menu
+&apos;&apos;&apos; Before: the place where to put the new menu on the menubar (string or number &gt;= 1)
+&apos;&apos;&apos; When not found =&gt; last position
+&apos;&apos;&apos; SubmenuChar: the delimiter used in menu trees. Default = &quot;&gt;&quot;
+&apos;&apos;&apos; _Document: undocumented argument to designate the document where the menu will be located
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A SFWidgets.Menu instance or Nothing
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim oMenu As Object
+&apos;&apos;&apos; Set oMenu = oDoc.CreateMenu(&quot;My menu&quot;, Before := &quot;Styles&quot;)
+&apos;&apos;&apos; With oMenu
+&apos;&apos;&apos; .AddItem(&quot;Item 1&quot;, Command := &quot;About&quot;)
+&apos;&apos;&apos; &apos;...
+&apos;&apos;&apos; .Dispose() &apos; When definition is complete, the menu instance may be disposed
+&apos;&apos;&apos; End With
+&apos;&apos;&apos; &apos; ...
+
+Dim oMenu As Object &apos; return value
+Const cstThisSub = &quot;SFDocuments.Document.CreateMenu&quot;
+Const cstSubArgs = &quot;MenuHeader, [Before=&quot;&quot;&quot;&quot;], [SubmenuChar=&quot;&quot;&gt;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oMenu = Nothing
+
+Check:
+ If IsMissing(Before) Or IsEmpty(Before) Then Before = &quot;&quot;
+ If IsMissing(SubmenuChar) Or IsEmpty(SubmenuChar) Then SubmenuChar = &quot;&quot;
+ If IsMissing(_Document) Or IsEmpty(_Document) Or IsNull(_Document) Then Set _Document = _Component
+
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(MenuHeader, &quot;MenuHeader&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Before, &quot;Before&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SubmenuChar, &quot;SubmenuChar&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set oMenu = ScriptForge.SF_Services.CreateScriptService(&quot;SFWidgets.Menu&quot;, _Document, MenuHeader, Before, SubmenuChar)
+
+Finally:
+ Set CreateMenu = oMenu
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Document.CreateMenu
+
+REM -----------------------------------------------------------------------------
Public Function ExportAsPDF(Optional ByVal FileName As Variant _
, Optional ByVal Overwrite As Variant _
, Optional ByVal Pages As Variant _
@@ -502,7 +559,7 @@ Check:
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive() Then GoTo Finally
If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
- If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
If Not SF_Utils._Validate(Pages, &quot;Pages&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Password, &quot;Password&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Watermark, &quot;Watermark&quot;, V_STRING) Then GoTo Finally
@@ -596,8 +653,10 @@ Public Function Methods() As Variant
Methods = Array( _
&quot;Activate&quot; _
, &quot;CloseDocument&quot; _
+ , &quot;CreateMenu&quot; _
, &quot;ExportAsPDF&quot; _
, &quot;PrintOut&quot; _
+ , &quot;RemoveMenu&quot; _
, &quot;RunCommand&quot; _
, &quot;Save&quot; _
, &quot;SaveAs&quot; _
@@ -687,6 +746,73 @@ Public Function Properties() As Variant
End Function &apos; SFDocuments.SF_Document.Properties
REM -----------------------------------------------------------------------------
+Public Function RemoveMenu(Optional ByVal MenuHeader As Variant _
+ , Optional ByRef _Document As Variant _
+) As Boolean
+&apos;&apos;&apos; Remove a menu entry in the document&apos;s menubar
+&apos;&apos;&apos; The removal is not intended to be saved neither in the LibreOffice global environment, nor in the document
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MenuHeader: the name/header of the menu, without tilde &quot;~&quot;, as a case-sensitive string
+&apos;&apos;&apos; _Document: undocumented argument to designate the document where the menu is located
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.RemoveMenu(&quot;File&quot;)
+&apos;&apos;&apos; &apos; ...
+
+Dim bRemove As Boolean &apos; Return value
+Dim oLayout As Object &apos; com.sun.star.comp.framework.LayoutManager
+Dim oMenuBar As Object &apos; com.sun.star.awt.XMenuBar or stardiv.Toolkit.VCLXMenuBar
+Dim sName As String &apos; Menu name
+Dim iMenuId As Integer &apos; Menu identifier
+Dim iMenuPosition As Integer &apos; Menu position &gt;= 0
+Dim i As Integer
+Const cstTilde = &quot;~&quot;
+
+Const cstThisSub = &quot;SFDocuments.Document.RemoveMenu&quot;
+Const cstSubArgs = &quot;MenuHeader&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bRemove = False
+
+Check:
+ If IsMissing(_Document) Or IsEmpty(_Document) Or IsNull(_Document) Then Set _Document = _Component
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(MenuHeader, &quot;MenuHeader&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set oLayout = _Document.CurrentController.Frame.LayoutManager
+ Set oMenuBar = oLayout.getElement(&quot;private:resource/menubar/menubar&quot;).XMenuBar
+
+ &apos; Search the menu identifier to remove by its name, Mark its position
+ With oMenuBar
+ iMenuPosition = -1
+ For i = 0 To .ItemCount - 1
+ iMenuId = .getItemId(i)
+ sName = Replace(.getItemText(iMenuId), cstTilde, &quot;&quot;)
+ If MenuHeader= sName Then
+ iMenuPosition = i
+ Exit For
+ End If
+ Next i
+ &apos; Remove the found menu item
+ If iMenuPosition &gt;= 0 Then
+ .removeItem(iMenuPosition, 1)
+ bRemove = True
+ End If
+ End With
+
+Finally:
+ RemoveMenu = bRemove
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Document.RemoveMenu
+
+REM -----------------------------------------------------------------------------
Public Sub RunCommand(Optional ByVal Command As Variant)
&apos;&apos;&apos; Run on the document the given menu command. The command is executed without arguments
&apos;&apos;&apos; A few typical commands:
@@ -811,7 +937,7 @@ Check:
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive() Then GoTo Finally
If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
- If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
If Not SF_Utils._Validate(Password, &quot;Password&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(FilterName, &quot;FilterName&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(FilterOptions, &quot;FilterOptions&quot;, V_STRING) Then GoTo Finally
@@ -910,7 +1036,7 @@ Check:
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsStillAlive() Then GoTo Finally
If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
- If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
If Not SF_Utils._Validate(Password, &quot;Password&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(FilterName, &quot;FilterName&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(FilterOptions, &quot;FilterOptions&quot;, V_STRING) Then GoTo Finally
diff --git a/wizards/source/sfdocuments/SF_Writer.xba b/wizards/source/sfdocuments/SF_Writer.xba
index 4acdd5c750f0..96ed289f92ff 100644
--- a/wizards/source/sfdocuments/SF_Writer.xba
+++ b/wizards/source/sfdocuments/SF_Writer.xba
@@ -219,9 +219,11 @@ Public Function Methods() As Variant
Methods = Array( _
&quot;Activate&quot; _
, &quot;CloseDocument&quot; _
+ , &quot;CreateMenu&quot; _
, &quot;ExportAsPDF&quot; _
, &quot;Forms&quot; _
, &quot;PrintOut&quot; _
+ , &quot;RemoveMenu&quot; _
, &quot;RunCommand&quot; _
, &quot;Save&quot; _
, &quot;SaveAs&quot; _
@@ -493,6 +495,14 @@ Public Function CloseDocument(Optional ByVal SaveAsk As Variant) As Boolean
End Function &apos; SFDocuments.SF_Writer.CloseDocument
REM -----------------------------------------------------------------------------
+Public Function CreateMenu(Optional ByVal MenuHeader As Variant _
+ , Optional ByVal Before As Variant _
+ , Optional ByVal SubmenuChar As Variant _
+ ) As Object
+ Set CreateMenu = [_Super].CreateMenu(MenuHeader, Before, SubmenuChar)
+End Function &apos; SFDocuments.SF_Writer.CreateMenu
+
+REM -----------------------------------------------------------------------------
Public Function ExportAsPDF(Optional ByVal FileName As Variant _
, Optional ByVal Overwrite As Variant _
, Optional ByVal Pages As Variant _
@@ -503,6 +513,11 @@ Public Function ExportAsPDF(Optional ByVal FileName As Variant _
End Function &apos; SFDocuments.SF_Writer.ExportAsPDF
REM -----------------------------------------------------------------------------
+Public Function RemoveMenu(Optional ByVal MenuHeader As Variant) As Boolean
+ RemoveMenu = [_Super].RemoveMenu(MenuHeader)
+End Function &apos; SFDocuments.SF_Writer.RemoveMenu
+
+REM -----------------------------------------------------------------------------
Public Sub RunCommand(Optional ByVal Command As Variant)
[_Super].RunCommand(Command)
End Sub &apos; SFDocuments.SF_Writer.RunCommand
diff --git a/wizards/source/sfwidgets/SF_Menu.xba b/wizards/source/sfwidgets/SF_Menu.xba
new file mode 100644
index 000000000000..308e959d1cee
--- /dev/null
+++ b/wizards/source/sfwidgets/SF_Menu.xba
@@ -0,0 +1,590 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_Menu" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFWidgets library is one of the associated libraries. ===
+REM === Full documentation is available on https://help.libreoffice.org/ ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+&apos;&apos;&apos; SF_Menu
+&apos;&apos;&apos; ============
+&apos;&apos;&apos; Display a menu in the menubar of a document or a form document.
+&apos;&apos;&apos; After use, the menu will not be saved neither in the application settings, nor in the document.
+&apos;&apos;&apos;
+&apos;&apos;&apos; The menu will be displayed, as usual, when its header in the menubar is clicked.
+&apos;&apos;&apos; When one of its items is selected, there are 3 alternative options:
+&apos;&apos;&apos; - a UNO command (like &quot;.uno:About&quot;) is triggered
+&apos;&apos;&apos; - a user script is run receiving a standard argument defined in this service
+&apos;&apos;&apos; - one of above combined with a toggle of the status of the item
+&apos;&apos;&apos;
+&apos;&apos;&apos; The menu is described from top to bottom. Each menu item receives a numeric and a string identifier.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Menu items are either:
+&apos;&apos;&apos; - usual items
+&apos;&apos;&apos; - checkboxes
+&apos;&apos;&apos; - radio buttons
+&apos;&apos;&apos; - a menu separator
+&apos;&apos;&apos; Menu items can be decorated with icons and tooltips.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Definitions:
+&apos;&apos;&apos; SubmenuCharacter: the character or the character string that identifies how menus are cascading
+&apos;&apos;&apos; Default = &quot;&gt;&quot;
+&apos;&apos;&apos; Can be set when invoking the Menu service
+&apos;&apos;&apos; ShortcutCharacter: the underline access key character
+&apos;&apos;&apos; Default = &quot;~&quot;
+&apos;&apos;&apos;
+&apos;&apos;&apos; Menus and submenus
+&apos;&apos;&apos; To create a menu with submenus, use the character defined in the
+&apos;&apos;&apos; SubmenuCharacter property while creating the menu entry to define where it will be
+&apos;&apos;&apos; placed. For instance, consider the following menu/submenu hierarchy.
+&apos;&apos;&apos; Item A
+&apos;&apos;&apos; Item B &gt; Item B.1
+&apos;&apos;&apos; Item B.2
+&apos;&apos;&apos; ------ (line separator)
+&apos;&apos;&apos; Item C &gt; Item C.1 &gt; Item C.1.1
+&apos;&apos;&apos; Item C.1.2
+&apos;&apos;&apos; Item C &gt; Item C.2 &gt; Item C.2.1
+&apos;&apos;&apos; Item C.2.2
+&apos;&apos;&apos; Next code will create the menu/submenu hierarchy
+&apos;&apos;&apos; With myMenu
+&apos;&apos;&apos; .AddItem(&quot;Item A&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item B&gt;Item B.1&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item B&gt;Item B.2&quot;)
+&apos;&apos;&apos; .AddItem(&quot;---&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.1&gt;Item C.1.1&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.1&gt;Item C.1.2&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.2&gt;Item C.2.1&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.2&gt;Item C.2.2&quot;)
+&apos;&apos;&apos; End With
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation:
+&apos;&apos;&apos; Dim ui As ObjectoDoc As Object, myMenu As Object
+&apos;&apos;&apos; Set ui = CreateScriptService(&quot;UI&quot;)
+&apos;&apos;&apos; Set oDoc = ui.GetDocument(ThisComponent)
+&apos;&apos;&apos; Set myMenu = oDoc.CreateMenu(&quot;My own menu&quot;)
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/SF_Menu.html?DbPAR=BASIC
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private ObjectType As String &apos; Must be MENU
+Private ServiceName As String
+
+
+&apos; Menu descriptors
+Private Component As Object &apos; the com.sun.star.lang.XComponent hosting the menu in its menubar
+Private MenuBar As Object &apos; com.sun.star.awt.XMenuBar or stardiv.Toolkit.VCLXMenuBar
+Private SubmenuChar As String &apos; Delimiter in menu trees
+Private MenuHeader As String &apos; Header of the menu
+Private MenuId As Integer &apos; Menu numeric identifier in the menubar
+Private MenuPosition As Integer &apos; Position of the menu on the menubar &gt;= 1
+Private PopupMenu As Object &apos; The underlying popup menu as a SF_PopupMenu object
+
+REM ============================================================ MODULE CONSTANTS
+
+Private Const _UnderlineAccessKeyChar = &quot;~&quot;
+Private Const _DefaultSubmenuChar = &quot;&gt;&quot;
+Private Const cstUnoPrefix = &quot;.uno:&quot;
+Private Const cstScriptArg = &quot;:::&quot;
+Private Const cstNormal = &quot;N&quot;
+Private Const cstCheck = &quot;C&quot;
+Private Const cstRadio = &quot;R&quot;
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ ObjectType = &quot;MENU&quot;
+ ServiceName = &quot;SFWidgets.Menu&quot;
+ Set Component = Nothing
+ Set MenuBar = Nothing
+ SubmenuChar = _DefaultSubmenuChar
+ MenuHeader = &quot;&quot;
+ MenuId = -1
+ MenuPosition = 0
+ Set PopupMenu = Nothing
+End Sub &apos; SFWidgets.SF_Menu Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; SFWidgets.SF_Menu Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ PopupMenu.Dispose()
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; SFWidgets.SF_Menu Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get ShortcutCharacter() As Variant
+&apos;&apos;&apos; The ShortcutCharacter property specifies character preceding the underline access key
+ ShortcutCharacter = _PropertyGet(&quot;ShortcutCharacter&quot;)
+End Property &apos; SFWidgets.SF_Menu.ShortcutCharacter (get)
+
+REM -----------------------------------------------------------------------------
+Property Get SubmenuCharacter() As Variant
+&apos;&apos;&apos; The SubmenuCharacter property specifies the character string indicating
+&apos;&apos;&apos; a sub-menu in a popup menu item
+ SubmenuCharacter = _PropertyGet(&quot;SubmenuCharacter&quot;)
+End Property &apos; SFWidgets.SF_Menu.SubmenuCharacter (get)
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function AddCheckBox(Optional ByVal MenuItem As Variant _
+ , Optional ByVal Name As Variant _
+ , Optional ByVal Status As Variant _
+ , Optional ByVal Icon As Variant _
+ , Optional ByVal Tooltip As Variant _
+ , Optional ByVal Command As Variant _
+ , Optional ByVal Script As Variant _
+ ) As Integer
+&apos;&apos;&apos; Insert in the popup menu a new entry as a checkbox
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MenuItem: The text to be displayed in the menu entry.
+&apos;&apos;&apos; It determines also the hierarchy of the popup menu
+&apos;&apos;&apos; It is made up of all the components (separated by the &quot;SubmenuCharacter&quot;) of the menu branch
+&apos;&apos;&apos; Example: A&gt;B&gt;C means &quot;C&quot; is a new entry in submenu &quot;A =&gt; B =&gt;&quot;
+&apos;&apos;&apos; If the last component is equal to the &quot;SeparatorCharacter&quot;, a line separator is inserted
+&apos;&apos;&apos; Name: The name identifying the item. Default = the last component of MenuItem.
+&apos;&apos;&apos; Status: when True the item is selected. Default = False
+&apos;&apos;&apos; Icon: The path name of the icon to be displayed, without leading path separator
+&apos;&apos;&apos; The icons are stored in one of the &lt;install folder&gt;/share/config/images_*.zip files
+&apos;&apos;&apos; The exact file depends on the user options about the current icon set
+&apos;&apos;&apos; Use the (normal) slash &quot;/&quot; as path separator
+&apos;&apos;&apos; Example: &quot;cmd/sc_cut.png&quot;
+&apos;&apos;&apos; Tooltip: The help text to be displayed as a tooltip
+&apos;&apos;&apos; Command: A menu command like &quot;.uno:About&quot;. The validity of the command is not checked.
+&apos;&apos;&apos; Script: a Basic or Python script (determined by its URI notation) to be run when the item is clicked
+&apos;&apos;&apos; Read https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification
+&apos;&apos;&apos; Next string argument will be passed to the called script : a comma-separated string of 4 components:
+&apos;&apos;&apos; - the menu header
+&apos;&apos;&apos; - the name of the clicked menu item
+&apos;&apos;&apos; - the numeric identifier of the clicked menu item
+&apos;&apos;&apos; - &quot;1&quot; when the status is &quot;checked&quot;, otherwide &quot;0&quot;
+&apos;&apos;&apos; Arguments Command and Script are mutually exclusive.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The numeric identification of the newly inserted item
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim iId As Integer
+&apos;&apos;&apos; iId = myMenu.AddCheckBox(&quot;Menu top&gt;Checkbox item&quot;, Status := True, Command := &quot;Bold&quot;)
+
+Dim iId As Integer &apos; Return value
+Dim sCommand As String &apos; Alias of either Command or Script
+
+
+Const cstThisSub = &quot;SFWidgets.Menu.AddCheckBox&quot;
+Const cstSubArgs = &quot;MenuItem, [Name=&quot;&quot;&quot;&quot;], [Status=False], [Icon=&quot;&quot;&quot;&quot;], [Tooltip=&quot;&quot;&quot;&quot;], [Command=&quot;&quot;&quot;&quot;], [Script=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ iId = 0
+
+Check:
+ If IsMissing(Name) Or IsEmpty(Name) Then Name = &quot;&quot;
+ If IsMissing(Status) Or IsEmpty(Status) Then Status = False
+ If IsMissing(Icon) Or IsEmpty(Icon) Then Icon = &quot;&quot;
+ If IsMissing(Tooltip) Or IsEmpty(Tooltip) Then Tooltip = &quot;&quot;
+ If IsMissing(Command) Or IsEmpty(Command) Then Command = &quot;&quot;
+ If IsMissing(Script) Or IsEmpty(Script) Then Script = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(MenuItem, &quot;MenuItem&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Name, &quot;Name&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Status, &quot;Status&quot;, ScriptForge.V_BOOLEAN) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Icon, &quot;Icon&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Tooltip, &quot;Tooltip&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Command, &quot;Command&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Script, &quot;Script&quot;, V_STRING) Then GoTo Catch
+ End If
+
+ If Len(Command) &gt; 0 Then
+ If Left(Command, Len(cstUnoPrefix)) = cstUnoPrefix Then sCommand = Command Else sCommand = cstUnoPrefix &amp; Command
+ Else
+ sCommand = Script &amp; cstScriptArg &amp; MenuHeader
+ End If
+
+Try:
+ iId = PopupMenu._AddItem(MenuItem, Name, cstCheck, Status, Icon, Tooltip, sCommand)
+
+Finally:
+ AddCheckBox = iId
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_Menu.AddCheckBox
+
+REM -----------------------------------------------------------------------------
+Public Function AddItem(Optional ByVal MenuItem As Variant _
+ , Optional ByVal Name As Variant _
+ , Optional ByVal Icon As Variant _
+ , Optional ByVal Tooltip As Variant _
+ , Optional ByVal Command As Variant _
+ , Optional ByVal Script As Variant _
+ ) As Integer
+&apos;&apos;&apos; Insert in the popup menu a new entry
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MenuItem: The text to be displayed in the menu entry.
+&apos;&apos;&apos; It determines also the hierarchy of the popup menu
+&apos;&apos;&apos; It is made up of all the components (separated by the &quot;SubmenuCharacter&quot;) of the menu branch
+&apos;&apos;&apos; Example: A&gt;B&gt;C means &quot;C&quot; is a new entry in submenu &quot;A =&gt; B =&gt;&quot;
+&apos;&apos;&apos; If the last component is equal to &quot;---&quot;, a line separator is inserted and all other arguments are ignored
+&apos;&apos;&apos; Name: The name identifying the item. Default = the last component of MenuItem.
+&apos;&apos;&apos; Icon: The path name of the icon to be displayed, without leading path separator
+&apos;&apos;&apos; The icons are stored in one of the &lt;install folder&gt;/share/config/images_*.zip files
+&apos;&apos;&apos; The exact file depends on the user options about the current icon set
+&apos;&apos;&apos; Use the (normal) slash &quot;/&quot; as path separator
+&apos;&apos;&apos; Example: &quot;cmd/sc_cut.png&quot;
+&apos;&apos;&apos; Tooltip: The help text to be displayed as a tooltip
+&apos;&apos;&apos; Command: A menu command like &quot;.uno:About&quot;. The validity of the command is not checked.
+&apos;&apos;&apos; Script: a Basic or Python script (determined by its URI notation) to be run when the item is clicked
+&apos;&apos;&apos; Read https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification
+&apos;&apos;&apos; Next string argument will be passed to the called script : a comma-separated string of 4 components:
+&apos;&apos;&apos; - the menu header
+&apos;&apos;&apos; - the name of the clicked menu item
+&apos;&apos;&apos; - the numeric identifier of the clicked menu item
+&apos;&apos;&apos; - &quot;0&quot;
+&apos;&apos;&apos; Arguments Command and Script are mutually exclusive.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The numeric identification of the newly inserted item
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim iId1 As Integer, iId2 As Integer
+&apos;&apos;&apos; iId1 = myMenu.AddItem(&quot;Menu top&gt;Normal item 1&quot;, Icon := &quot;cmd.sc_cut.png&quot;, Command := &quot;About&quot;)
+&apos;&apos;&apos; iId2 = myMenu.AddItem(&quot;Menu top&gt;Normal item 2&quot;, Script := &quot;vnd.sun.star.script:myLib.Module1.ThisSub?language=Basic&amp;location=document&quot;)
+
+Dim iId As Integer &apos; Return value
+Dim sCommand As String &apos; Alias of either Command or Script
+
+Const cstThisSub = &quot;SFWidgets.Menu.AddItem&quot;
+Const cstSubArgs = &quot;MenuItem, [Name=&quot;&quot;&quot;&quot;], [Icon=&quot;&quot;&quot;&quot;], [Tooltip=&quot;&quot;&quot;&quot;], [Command=&quot;&quot;&quot;&quot;], [Script=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ iId = 0
+
+Check:
+ If IsMissing(Name) Or IsEmpty(Name) Then Name = &quot;&quot;
+ If IsMissing(Icon) Or IsEmpty(Icon) Then Icon = &quot;&quot;
+ If IsMissing(Tooltip) Or IsEmpty(Tooltip) Then Tooltip = &quot;&quot;
+ If IsMissing(Command) Or IsEmpty(Command) Then Command = &quot;&quot;
+ If IsMissing(Script) Or IsEmpty(Script) Then Script = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(MenuItem, &quot;MenuItem&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Name, &quot;Name&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Icon, &quot;Icon&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Tooltip, &quot;Tooltip&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Command, &quot;Command&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Script, &quot;Script&quot;, V_STRING) Then GoTo Catch
+ End If
+
+ If Len(Command) &gt; 0 Then
+ If Left(Command, Len(cstUnoPrefix)) = cstUnoPrefix Then sCommand = Command Else sCommand = cstUnoPrefix &amp; Command
+ Else
+ sCommand = Script &amp; cstScriptArg &amp; MenuHeader
+ End If
+
+Try:
+ iId = PopupMenu._AddItem(MenuItem, Name, cstNormal, False, Icon, Tooltip, sCommand)
+
+Finally:
+ AddItem = iId
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_Menu.AddItem
+
+REM -----------------------------------------------------------------------------
+Public Function AddRadioButton(Optional ByVal MenuItem As Variant _
+ , Optional ByVal Name As Variant _
+ , Optional ByVal Status As Variant _
+ , Optional ByVal Icon As Variant _
+ , Optional ByVal Tooltip As Variant _
+ , Optional ByVal Command As Variant _
+ , Optional ByVal Script As Variant _
+ ) As Integer
+&apos;&apos;&apos; Insert in the popup menu a new entry as a radio button
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; MenuItem: The text to be displayed in the menu entry.
+&apos;&apos;&apos; It determines also the hieAddCheckBoxrarchy of the popup menu
+&apos;&apos;&apos; It is made up of all the components (separated by the &quot;SubmenuCharacter&quot;) of the menu branch
+&apos;&apos;&apos; Example: A&gt;B&gt;C means &quot;C&quot; is a new entry in submenu &quot;A =&gt; B =&gt;&quot;
+&apos;&apos;&apos; If the last component is equal to the &quot;SeparatorCharacter&quot;, a line separator is inserted
+&apos;&apos;&apos; Name: The name identifying the item. Default = the last component of MenuItem.
+&apos;&apos;&apos; Status: when True the item is selected. Default = False
+&apos;&apos;&apos; Icon: The path name of the icon to be displayed, without leading path separator
+&apos;&apos;&apos; The icons are stored in one of the &lt;install folder&gt;/share/config/images_*.zip files
+&apos;&apos;&apos; The exact file depends on the user options about the current icon set
+&apos;&apos;&apos; Use the (normal) slash &quot;/&quot; as path separator
+&apos;&apos;&apos; Example: &quot;cmd/sc_cut.png&quot;
+&apos;&apos;&apos; Tooltip: The help text to be displayed as a tooltip
+&apos;&apos;&apos; Command: A menu command like &quot;.uno:About&quot;. The validity of the command is not checked.
+&apos;&apos;&apos; Script: a Basic or Python script (determined by its URI notation) to be run when the item is clicked
+&apos;&apos;&apos; Read https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification
+&apos;&apos;&apos; Next string argument will be passed to the called script : a comma-separated string of 4 components:
+&apos;&apos;&apos; - the menu header
+&apos;&apos;&apos; - the name of the clicked menu item
+&apos;&apos;&apos; - the numeric identifier of theclicked menu item
+&apos;&apos;&apos; - &quot;1&quot; when the status is &quot;checked&quot;, otherwide &quot;0&quot;
+&apos;&apos;&apos; Arguments Command and Script are mutually exclusive.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The numeric identification of the newly inserted item
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim iId As Integer
+&apos;&apos;&apos; iId = myMenu.AddRadioButton(&quot;Menu top&gt;Radio item&quot;, Status := True, Command := &quot;Bold&quot;)
+
+Dim iId As Integer &apos; Return value
+Dim sCommand As String &apos; Alias of either Command or Script
+
+Const cstThisSub = &quot;SFWidgets.Menu.AddRadioButton&quot;
+Const cstSubArgs = &quot;MenuItem, [Name=&quot;&quot;&quot;&quot;], [Status=False], [Icon=&quot;&quot;&quot;&quot;], [Tooltip=&quot;&quot;&quot;&quot;], [Command=&quot;&quot;&quot;&quot;], [Script=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ iId = 0
+
+Check:
+ If IsMissing(Name) Or IsEmpty(Name) Then Name = &quot;&quot;
+ If IsMissing(Status) Or IsEmpty(Status) Then Status = False
+ If IsMissing(Icon) Or IsEmpty(Icon) Then Icon = &quot;&quot;
+ If IsMissing(Tooltip) Or IsEmpty(Tooltip) Then Tooltip = &quot;&quot;
+ If IsMissing(Command) Or IsEmpty(Command) Then Command = &quot;&quot;
+ If IsMissing(Script) Or IsEmpty(Script) Then Script = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(MenuItem, &quot;MenuItem&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Name, &quot;Name&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Status, &quot;Status&quot;, ScriptForge.V_BOOLEAN) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Icon, &quot;Icon&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Tooltip, &quot;Tooltip&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Command, &quot;Command&quot;, V_STRING) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(Script, &quot;Script&quot;, V_STRING) Then GoTo Catch
+ End If
+
+ If Len(Command) &gt; 0 Then
+ If Left(Command, Len(cstUnoPrefix)) = cstUnoPrefix Then sCommand = Command Else sCommand = cstUnoPrefix &amp; Command
+ Else
+ sCommand = Script &amp; cstScriptArg &amp; MenuHeader
+ End If
+
+Try:
+ iId = PopupMenu._AddItem(MenuItem, Name, cstRadio, Status, Icon, Tooltip, sCommand)
+
+Finally:
+ AddRadioButton = iId
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_Menu.AddRadioButton
+
+REM -----------------------------------------------------------------------------
+Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
+&apos;&apos;&apos; Return the actual value of the given property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; PropertyName: the name of the property as a string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The actual value of the property
+&apos;&apos;&apos; If the property does not exist, returns Null
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; see the exceptions of the individual properties
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myModel.GetProperty(&quot;MyProperty&quot;)
+
+Const cstThisSub = &quot;SFWidgets.Menu.GetProperty&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
+ End If
+
+Try:
+ GetProperty = _PropertyGet(PropertyName)
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_Menu.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the Model service as an array
+
+ Methods = Array( _
+ &quot;AddCheckBox&quot; _
+ , &quot;AddItem&quot; _
+ , &quot;AddRadioButton&quot; _
+ )
+
+End Function &apos; SFWidgets.SF_Menu.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Timer a.AddItem(&quot;B&gt;B1&quot;)class as an array
+
+ Properties = Array( _
+ &quot;ShortcutCharacter&quot; _
+ , &quot;SubmenuCharacter&quot; _
+ )
+
+End Function &apos; SFWidgets.SF_Menu.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function SetProperty(Optional ByVal PropertyName As Variant _
+ , Optional ByRef Value As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Set a new value to the given property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; PropertyName: the name of the property as a string
+&apos;&apos;&apos; Value: its new value
+&apos;&apos;&apos; Exceptions
+&apos;&apos;&apos; ARGUMENTERROR The property does not exist
+
+Const cstThisSub = &quot;SFWidgets.Menu.SetProperty&quot;
+Const cstSubArgs = &quot;PropertyName, Value&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ SetProperty = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
+ End If
+
+Try:
+ SetProperty = _PropertySet(PropertyName, Value)
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_Menu.SetProperty
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Sub _Initialize(ByRef poComponent As Object _
+ , psMenuHeader As String _
+ , psBefore As String _
+ , piBefore As Integer _
+ , psSubmenuChar As String _
+ )
+&apos;&apos;&apos; Complete the object creation process:
+&apos;&apos;&apos; - Initialize the internal properties
+&apos;&apos;&apos; - Initialize the menubar
+&apos;&apos;&apos; - Determine the position and the internal id of the new menu
+&apos;&apos;&apos; - Create the menu and its attached popup menu
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; poComponent: the parent component where the menubar is to be searched for
+&apos;&apos;&apos; psMenuHeader: the header of the new menu. May or not contain a tilde &quot;~&quot;
+&apos;&apos;&apos; psBefore, piBefore: the menu before which to create the new menu, as a string or as a number
+&apos;&apos;&apos; psSubmenuChar: the submenus separator
+
+Dim oLayout As Object &apos; com.sun.star.comp.framework.LayoutManager
+Dim sName As String &apos; Menu name
+Dim iMenuId As Integer &apos; Menu identifier
+Dim i As Integer
+Const cstTilde = &quot;~&quot;
+
+Try:
+ &apos; Initialize the menubar
+ Set oLayout = poComponent.CurrentController.Frame.LayoutManager
+ Set MenuBar = oLayout.getElement(&quot;private:resource/menubar/menubar&quot;).XMenuBar
+
+ &apos; Determine the new menu identifier and its position
+ &apos; Identifier = largest current identifier + 1
+ MenuHeader = psMenuHeader
+ With MenuBar
+ For i = 0 To .ItemCount - 1
+ iMenuId = .getItemId(i)
+ If iMenuId &gt;= MenuId Then MenuId = iMenuId + 1
+ If piBefore &gt; 0 And piBefore = i + 1 Then
+ MenuPosition = piBefore
+ Else
+ sName = .getItemText(iMenuId)
+ If sName = psBefore Or Replace(sName, cstTilde, &quot;&quot;) = psBefore Then MenuPosition = i + 1
+ End If
+ Next i
+ If MenuPosition = 0 Then MenuPosition = .ItemCount + 1
+ End With
+
+ &apos; Store the submenu character
+ If Len(psSubmenuChar) &gt; 0 Then SubmenuChar = psSubmenuChar
+
+ &apos; Create the menu and the attached top popup menu
+ MenuBar.insertItem(MenuId, MenuHeader, 0, MenuPosition - 1)
+ PopupMenu = SFWidgets.SF_Register._NewPopupMenu(Array(Nothing, 0, 0, SubmenuChar))
+ PopupMenu.MenubarMenu = True &apos; Special indicator for menus depending on menubar
+ MenuBar.setPopupMenu(MenuId, PopupMenu.MenuRoot)
+
+ &apos; Initialize the listener on the top branch
+ SFWidgets.SF_MenuListener.SetMenuListener(PopupMenu.MenuRoot)
+
+Finally:
+ Exit Sub
+End Sub &apos; SFWidgets.SF_Menu._Initialize
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertyGet(Optional ByVal psProperty As String) As Variant
+&apos;&apos;&apos; Return the value of the named property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psProperty: the name of the property
+
+Dim vGet As Variant &apos; Return value
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;SFWidgets.Menu.get&quot; &amp; psProperty
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ _PropertyGet = Null
+
+ Select Case UCase(psProperty)
+ Case UCase(&quot;ShortcutCharacter&quot;)
+ _PropertyGet = _UnderlineAccessKeyChar
+ Case UCase(&quot;SubmenuCharacter&quot;)
+ _PropertyGet = SubmenuChar
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_Menu._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the SF_Menu instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[Menu]: Name, Type (dialogname)
+ _Repr = &quot;[Menu]: &quot; &amp; SF_String.Represent(PopupMenu.MenuTree.Keys()) &amp; &quot;, &quot; &amp; SF_String.Represent(PopupMenu.MenuIdentification.Items())
+
+End Function &apos; SFWidgets.SF_Menu._Repr
+
+REM ============================================ END OF SFWIDGETS.SF_MENU
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfwidgets/SF_MenuListener.xba b/wizards/source/sfwidgets/SF_MenuListener.xba
new file mode 100644
index 000000000000..0b1f2b6fd0e5
--- /dev/null
+++ b/wizards/source/sfwidgets/SF_MenuListener.xba
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_MenuListener" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFWidgets library is one of the associated libraries. ===
+REM === Full documentation is available on https://help.libreoffice.org/ ===
+REM =======================================================================================================================
+
+Option Compatible
+Option Explicit
+
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+&apos;&apos;&apos; SF_MenuListener
+&apos;&apos;&apos; ===============
+&apos;&apos;&apos; The current module is dedicated to the management of menu events + listeners, triggered by user actions,
+&apos;&apos;&apos; which cannot be defined with the Basic IDE
+&apos;&apos;&apos;
+&apos;&apos;&apos; Concerned listeners:
+&apos;&apos;&apos; com.sun.star.awt.XMenuListener
+&apos;&apos;&apos; allowing a user to select a menu command in user menus preset in the menubar
+&apos;&apos;&apos;
+&apos;&apos;&apos; The described events/listeners are processed by UNO listeners
+&apos;&apos;&apos;
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ============================================================= PRIVATE MEMBERS
+
+Dim MenuListener As Object &apos; com.sun.star.awt.XMenuListener
+
+REM =========================================================== PRIVATE CONSTANTS
+
+Private Const _MenuListenerPrefix = &quot;_SFMENU_&quot;
+Private Const _MenuListener = &quot;com.sun.star.awt.XMenuListener&quot;
+Private Const cstUnoPrefix = &quot;.uno:&quot;
+Private Const cstScriptArg = &quot;:::&quot;
+
+REM ================================================================== EXCEPTIONS
+
+REM ============================================================== PUBLIC METHODS
+
+REM -----------------------------------------------------------------------------
+Public Sub SetMenuListener(poSubmenu As Object)
+&apos;&apos;&apos; Arm a menu listener on a submenu
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; poSubmenu: the targeted submenu
+
+Try:
+ If IsNull(MenuListener) Then Set MenuListener = CreateUnoListener(_MenuListenerPrefix, _MenuListener)
+ poSubmenu.addMenuListener(MenuListener)
+
+Finally:
+ Exit Sub
+End Sub &apos; SFWidgets.SF_MenuListener.SetMenuListener
+
+REM ============================================================= PRIVATE METHODS
+
+REM -----------------------------------------------------------------------------
+Sub _SFMENU_itemSelected(Optional poEvent As Object) &apos; com.sun.star.awt.MenuEvent
+&apos;&apos;&apos; Execute the command or the script associated with the actually selected item
+&apos;&apos;&apos; When a script, next argument is provided:
+&apos;&apos;&apos; a comma-separated string with 4 components
+&apos;&apos;&apos; - the menu header
+&apos;&apos;&apos; - the name of the selected menu entry (without tilde &quot;~&quot;)
+&apos;&apos;&apos; - the numeric identifier of the selected menu entry
+&apos;&apos;&apos; - the new status of the selected menu entry (&quot;0&quot; or &quot;1&quot;). Always &quot;0&quot; for usual items.
+
+Dim iMenuId As Integer
+Dim oMenu As Object &apos; stardiv.Toolkit.VCLXPopupMenu
+Dim sCommand As String &apos; Command associated with menu entry
+Dim bType As Boolean &apos; True when status is meaningful: item is radio button or checkbox
+Dim bStatus As Boolean &apos; Status of the menu item, always False for normal items
+Dim oFrame As Object &apos; com.sun.star.comp.framework.Frame
+Dim oDispatcher As Object &apos; com.sun.star.frame.DispatchHelper
+Dim oSession As Object &apos; SF_Session service
+Dim vScript As Variant &apos; Split command in script/argument
+Dim oArgs() As new com.sun.star.beans.PropertyValue
+
+ On Local Error GoTo Catch &apos; Avoid stopping event scripts
+
+Try:
+ iMenuId = poEvent.MenuId
+ oMenu = poEvent.Source
+
+ With oMenu
+ &apos; Collect command (script or menu command) and status radiobttons and checkboxes
+ sCommand = .getCommand(iMenuId)
+ bStatus = .isItemChecked(iMenuId)
+ End With
+
+ If Len(sCommand) &gt; 0 Then
+ If Left(sCommand, Len(cstUnoPrefix)) = cstUnoPrefix Then
+ &apos; Execute uno command
+ Set oFrame = StarDesktop.CurrentComponent.CurrentController.Frame &apos; A menu has been clicked necessarily in the current window
+ Set oDispatcher = ScriptForge.SF_Utils._GetUNOService(&quot;DispatchHelper&quot;)
+ oDispatcher.executeDispatch(oFrame, sCommand, &quot;&quot;, 0, oArgs())
+ Else
+ &apos; Execute script
+ Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
+ vScript = Split(sCommand, cstScriptArg)
+ oSession._ExecuteScript(vScript(0), vScript(1) &amp; &quot;,&quot; &amp; Iif(bStatus, &quot;1&quot;, &quot;0&quot;)) &apos; Return value is ignored
+ End If
+ End If
+
+Finally:
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; SFWidgets.SF_MenuListener._SFMENU_itemSelected
+
+REM -----------------------------------------------------------------------------
+Sub _SFMENU_itemHighlighted(Optional poEvent As Object) &apos; com.sun.star.awt.MenuEvent
+ Exit Sub
+End Sub &apos; SFWidgets.SF_MenuListener._SFMENU_itemHighlighted
+
+Sub _SFMENU_itemActivated(Optional poEvent As Object) &apos; com.sun.star.awt.MenuEvent
+ Exit Sub
+End Sub &apos; SFWidgets.SF_MenuListener._SFMENU_itemActivated
+
+Sub _SFMENU_itemDeactivated(Optional poEvent As Object) &apos; com.sun.star.awt.MenuEvent
+ Exit Sub
+End Sub &apos; SFWidgets.SF_MenuListener._SFMENU_itemDeactivated
+
+Sub _SFMENU_disposing(Optional poEvent As Object) &apos; com.sun.star.awt.MenuEvent
+ Exit Sub
+End Sub &apos; SFWidgets.SF_MenuListener._SFMENU_disposing
+
+REM ============================================ END OF SFDIALOGS.SF_DIALOGLISTENER
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfwidgets/SF_PopupMenu.xba b/wizards/source/sfwidgets/SF_PopupMenu.xba
index 8f231983551a..3d5ba65a80f8 100644
--- a/wizards/source/sfwidgets/SF_PopupMenu.xba
+++ b/wizards/source/sfwidgets/SF_PopupMenu.xba
@@ -22,7 +22,7 @@ Option Explicit
&apos;&apos;&apos; provide the coordinates of the topleft edge of the menu versus the actual component.
&apos;&apos;&apos;
&apos;&apos;&apos; The menu is described from top to bottom. Each menu item receives a numeric and a string identifier.
-&apos;&apos;&apos; The execute() method returns the item selected by the user.
+&apos;&apos;&apos; The Execute() method returns the item selected by the user.
&apos;&apos;&apos;
&apos;&apos;&apos; Menu items are either:
&apos;&apos;&apos; - usual items
@@ -34,7 +34,7 @@ Option Explicit
&apos;&apos;&apos; Definitions:
&apos;&apos;&apos; SubmenuCharacter: the character or the character string that identifies how menus are cascading
&apos;&apos;&apos; Default = &quot;&gt;&quot;
-&apos;&apos;&apos; Can be set when invocating the PopupMenu service
+&apos;&apos;&apos; Can be set when invoking the PopupMenu service
&apos;&apos;&apos; ShortcutCharacter: the underline access key character
&apos;&apos;&apos; Default = &quot;~&quot;
&apos;&apos;&apos;
@@ -45,14 +45,38 @@ Option Explicit
&apos;&apos;&apos; &apos; or
&apos;&apos;&apos; Set myMenu = CreateScriptService(&quot;SFWidgets.PopupMenu&quot;, , X, Y, &quot; | &quot;) &apos; Use X and Y coordinates to place the menu
&apos;&apos;&apos;
-&apos;&apos;&apos; Example 1: simulate an extract of the View menu in the menubar of the Basic IDE
+&apos;&apos;&apos; Menus and submenus
+&apos;&apos;&apos; To create a popup menu with submenus, use the character defined in the
+&apos;&apos;&apos; SubmenuCharacter property while creating the menu entry to define where it will be
+&apos;&apos;&apos; placed. For instance, consider the following menu/submenu hierarchy.
+&apos;&apos;&apos; Item A
+&apos;&apos;&apos; Item B &gt; Item B.1
+&apos;&apos;&apos; Item B.2
+&apos;&apos;&apos; ------ (line separator)
+&apos;&apos;&apos; Item C &gt; Item C.1 &gt; Item C.1.1
+&apos;&apos;&apos; Item C.1.2
+&apos;&apos;&apos; Item C &gt; Item C.2 &gt; Item C.2.1
+&apos;&apos;&apos; Item C.2.2
+&apos;&apos;&apos; Next code will create the menu/submenu hierarchy
+&apos;&apos;&apos; With myMenu
+&apos;&apos;&apos; .AddItem(&quot;Item A&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item B&gt;Item B.1&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item B&gt;Item B.2&quot;)
+&apos;&apos;&apos; .AddItem(&quot;---&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.1&gt;Item C.1.1&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.1&gt;Item C.1.2&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.2&gt;Item C.2.1&quot;)
+&apos;&apos;&apos; .AddItem(&quot;Item C&gt;Item C.2&gt;Item C.2.2&quot;)
+&apos;&apos;&apos; End With
+&apos;&apos;&apos;
+&apos;&apos;&apos; Example 1: simulate a subset of the View menu in the menubar of the Basic IDE
&apos;&apos;&apos; Sub OpenMenu(Optional poMouseEvent As Object)
&apos;&apos;&apos; Dim myMenu As Object, vChoice As Variant
&apos;&apos;&apos; Set myMenu = CreateScriptService(&quot;SFWidgets.PopupMenu&quot;, poMouseEvent)
&apos;&apos;&apos; With myMenu
&apos;&apos;&apos; .AddCheckBox(&quot;View&gt;Toolbars&gt;Dialog&quot;)
-&apos;&apos;&apos; .AddCheckBox(&quot;View&gt;Toolbars&gt;Find&quot;, STatus := True)
-&apos;&apos;&apos; .AddCheckBox(&quot;View&gt;Status Bar&quot;, STatus := True)
+&apos;&apos;&apos; .AddCheckBox(&quot;View&gt;Toolbars&gt;Find&quot;, Status := True)
+&apos;&apos;&apos; .AddCheckBox(&quot;View&gt;Status Bar&quot;, Status := True)
&apos;&apos;&apos; .AddItem(&quot;View&gt;Full Screen&quot;, Name := &quot;FULLSCREEN&quot;)
&apos;&apos;&apos; vChoice = .Execute(False) &apos; When 1st checkbox is clicked, return &quot;Dialog&quot;
&apos;&apos;&apos; &apos; When last item is clicked, return &quot;FULLSCREEN&quot;
@@ -74,7 +98,7 @@ Option Explicit
&apos;&apos;&apos; myDoc.Dispose()
&apos;&apos;&apos; myMenu.Dispose()
&apos;&apos;&apos; End Sub
-
+&apos;&apos;&apos;
&apos;&apos;&apos;
&apos;&apos;&apos; Detailed user documentation:
&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_popupmenu.html?DbPAR=BASIC
@@ -98,6 +122,7 @@ Private MenuRoot As Object &apos; stardiv.vcl.PopupMenu or com.sun.star.awt.X
Private LastItem As Integer &apos; Every item has its entry number. This is the last one
Private Rectangle As Object &apos; com.sun.star.awt.Rectangle
Private PeerWindow As Object &apos; com.sun.star.awt.XWindowPeer
+Private MenubarMenu As Boolean &apos; When True, the actual popup menu depends on a menubar item
REM ============================================================ MODULE CONSTANTS
@@ -105,6 +130,7 @@ Private Const _UnderlineAccessKeyChar = &quot;~&quot;
Private Const _DefaultSubmenuChar = &quot;&gt;&quot;
Private Const _SeparatorChar = &quot;---&quot;
Private Const _IconsDirectory = &quot;private:graphicrepository/&quot; &apos; Refers to &lt;install folder&gt;/share/config/images_*.zip.
+Private Const cstUnoPrefix = &quot;.uno:&quot;
Private Const cstNormal = &quot;N&quot;
Private Const cstCheck = &quot;C&quot;
Private Const cstRadio = &quot;R&quot;
@@ -122,6 +148,8 @@ Private Sub Class_Initialize()
Set MenuRoot = Nothing
LastItem = 0
Set Rectangle = Nothing
+ Set PeerWindow = Nothing
+ MenubarMenu = False
End Sub &apos; SFWidgets.SF_PopupMenu Constructor
REM -----------------------------------------------------------------------------
@@ -187,7 +215,7 @@ Public Function AddCheckBox(Optional ByVal MenuItem As Variant _
Dim iId As Integer &apos; Return value
Const cstThisSub = &quot;SFWidgets.PopupMenu.AddCheckBox&quot;
-Const cstSubArgs = &quot;MenuItem, [Name = &quot;&quot;&quot;&quot;], [Status = False], [Icon = &quot;&quot;&quot;&quot;], [Tooltip = &quot;&quot;&quot;&quot;]&quot;
+Const cstSubArgs = &quot;MenuItem, [Name=&quot;&quot;&quot;&quot;], [Status=False], [Icon=&quot;&quot;&quot;&quot;], [Tooltip=&quot;&quot;&quot;&quot;]&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
iId = 0
@@ -228,7 +256,7 @@ Public Function AddItem(Optional ByVal MenuItem As Variant _
&apos;&apos;&apos; It determines also the hierarchy of the popup menu
&apos;&apos;&apos; It is made up of all the components (separated by the &quot;SubmenuCharacter&quot;) of the menu branch
&apos;&apos;&apos; Example: A&gt;B&gt;C means &quot;C&quot; is a new entry in submenu &quot;A =&gt; B =&gt;&quot;
-&apos;&apos;&apos; If the last component is equal to the &quot;SeparatorCharacter&quot;, a line separator is inserted
+&apos;&apos;&apos; If the last component is equal to &quot;---&quot;, a line separator is inserted and all other arguments are ignored
&apos;&apos;&apos; Name: The name to be returned by the Execute() method if this item is clicked
&apos;&apos;&apos; Default = the last component of MenuItem
&apos;&apos;&apos; Icon: The path name of the icon to be displayed, without leading path separator
@@ -247,7 +275,7 @@ Public Function AddItem(Optional ByVal MenuItem As Variant _
Dim iId As Integer &apos; Return value
Const cstThisSub = &quot;SFWidgets.PopupMenu.AddItem&quot;
-Const cstSubArgs = &quot;MenuItem, [Name = &quot;&quot;&quot;&quot;], [Icon = &quot;&quot;&quot;&quot;], [Tooltip = &quot;&quot;&quot;&quot;]&quot;
+Const cstSubArgs = &quot;MenuItem, [Name=&quot;&quot;&quot;&quot;], [Icon=&quot;&quot;&quot;&quot;], [Tooltip=&quot;&quot;&quot;&quot;]&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
iId = 0
@@ -307,7 +335,7 @@ Public Function AddRadioButton(Optional ByVal MenuItem As Variant _
Dim iId As Integer &apos; Return value
Const cstThisSub = &quot;SFWidgets.PopupMenu.AddRadioButton&quot;
-Const cstSubArgs = &quot;MenuItem, [Name = &quot;&quot;&quot;&quot;], [Status = False], [Icon = &quot;&quot;&quot;&quot;], [Tooltip = &quot;&quot;&quot;&quot;]&quot;
+Const cstSubArgs = &quot;MenuItem, [Name=&quot;&quot;&quot;&quot;], [Status=False], [Icon=&quot;&quot;&quot;&quot;], [Tooltip=&quot;&quot;&quot;&quot;]&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
iId = 0
@@ -360,7 +388,7 @@ Public Function Execute(Optional ByVal ReturnId As Variant) As Variant
Dim vMenuItem As Variant &apos; Return value
Const cstThisSub = &quot;SFWidgets.PopupMenu.Execute&quot;
-Const cstSubArgs = &quot;[ReturnId = True]&quot;
+Const cstSubArgs = &quot;[ReturnId=True]&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
vMenuItem = 0
@@ -374,7 +402,7 @@ Check:
Try:
vMenuItem = MenuRoot.Execute(PeerWindow, Rectangle, com.sun.star.awt.PopupMenuDirection.EXECUTE_DEFAULT)
- If Not ReturnId Then vMenuItem = MenuIdentification.Item(Str(vMenuItem))
+ If Not ReturnId Then vMenuItem = MenuIdentification.Item(CStr(vMenuItem))
Finally:
Execute = vMenuItem
@@ -483,6 +511,7 @@ Public Function _AddItem(ByVal MenuItem As String _
, ByVal Status As Boolean _
, ByVal Icon As String _
, ByVal Tooltip As String _
+ , Optional ByVal Command As String _
) As Integer
&apos;&apos;&apos; Insert in the popup menu a new entry
&apos;&apos;&apos; Args:
@@ -501,6 +530,9 @@ Public Function _AddItem(ByVal MenuItem As String _
&apos;&apos;&apos; Use the (normal) slash &quot;/&quot; as path separator
&apos;&apos;&apos; Example: &quot;cmd/sc_cut.png&quot;
&apos;&apos;&apos; Tooltip: The help text to be displayed as a tooltip
+&apos;&apos;&apos; Command: only for menubar menus
+&apos;&apos;&apos; Either a uo command like &quot;.uno:About&quot;
+&apos;&apos;&apos; or a script to be run: script URI ::: string argument to be passed to the script
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The numeric identification of the newly inserted item
@@ -510,9 +542,12 @@ Dim sMenu As String &apos; Submenu where to attach the new item, as a string
Dim oMenu As Object &apos; Submenu where to attach the new item, as an object
Dim sName As String &apos; The text displayed in the menu box
Dim oImage As Object &apos; com.sun.star.graphic.XGraphic
+Dim sCommand As String &apos; Alias of Command completed with arguments
+Const cstCommandSep = &quot;,&quot;
On Local Error GoTo Catch
iId = 0
+ If IsMissing(Command) Then Command = &quot;&quot;
Try:
&apos; Run through the upper menu tree
@@ -534,16 +569,16 @@ Try:
Case cstNormal
.insertItem(LastItem, sName, 0, -1)
Case cstCheck
- .insertItem(LastItem, sName, com.sun.star.awt.MenuItemStyle.CHECKABLE, -1)
+ .insertItem(LastItem, sName, com.sun.star.awt.MenuItemStyle.CHECKABLE + com.sun.star.awt.MenuItemStyle.AUTOCHECK, -1)
.checkItem(LastItem, Status)
Case cstRadio
- .insertItem(LastItem, sName, com.sun.star.awt.MenuItemStyle.RADIOCHECK, -1)
+ .insertItem(LastItem, sName, com.sun.star.awt.MenuItemStyle.RADIOCHECK + com.sun.star.awt.MenuItemStyle.AUTOCHECK, -1)
.checkItem(LastItem, Status)
End Select
&apos; Store the ID - Name relation
If Len(Name) = 0 Then Name = Replace(sName, _UnderlineAccessKeyChar, &quot;&quot;)
- MenuIdentification.Add(Str(LastItem), Name)
+ MenuIdentification.Add(CStr(LastItem), Name)
&apos; Add the icon when relevant
If Len(Icon) &gt; 0 Then
@@ -553,6 +588,16 @@ Try:
&apos; Add the tooltip when relevant
If Len(Tooltip) &gt; 0 Then .setTipHelpText(LastItem, Tooltip)
+
+ &apos; Add the command: UNO command or script to run - menubar menus only
+ If Len(Command) &gt; 0 Then
+ If Left(Command, Len(cstUnoPrefix)) = cstUnoPrefix Then
+ sCommand = Command
+ Else
+ sCommand = Command &amp; cstCommandSep &amp; Name &amp; cstCommandSep &amp; CStr(LastItem)
+ End If
+ .setCommand(LastItem, sCommand)
+ End If
End If
End With
@@ -566,7 +611,7 @@ Catch:
End Function &apos; SFWidgets.SF_PopupMenu._AddItem
REM -----------------------------------------------------------------------------
-Private Function _GetImageFromURL(psUrl as String) As Object
+Private Function _GetImageFromURL(ByVal psUrl as String) As Object
&apos;&apos;&apos; Returns a com.sun.star.graphic.XGraphic instance based on the given URL
&apos;&apos;&apos; The returned object is intended to be inserted as an icon in the popup menu
&apos;&apos;&apos; Derived from &quot;Useful Macro Information For OpenOffice&quot; By Andrew Pitonyak
@@ -593,7 +638,7 @@ Finally:
Exit Function
Catch:
GoTo Finally
-End Function &apos; SFWidgets.SF°PopupMenu._GetImageFromUrl
+End Function &apos; SFWidgets.SF_PopupMenu._GetImageFromUrl
REM -----------------------------------------------------------------------------
Private Function _GetPopupMenu(ByVal psSubmenu As String) As Object
@@ -635,6 +680,7 @@ Try:
LastItem = LastItem + 1
oLastMenu.insertItem(LastItem, vSplit(i), 0, -1)
Set oMenu = CreateUnoService(&quot;stardiv.vcl.PopupMenu&quot;)
+ If MenubarMenu Then SFWidgets.SF_MenuListener.SetMenuListener(oMenu)
MenuTree.Add(sMenu, oMenu)
oLastMenu.setPopupMenu(LastItem, oMenu)
Set oLastMenu = oMenu
@@ -722,7 +768,7 @@ End Function &apos; SFWidgets.SF_PopupMenu._PropertyGet
REM -----------------------------------------------------------------------------
Private Function _Repr() As String
-&apos;&apos;&apos; Convert the Model instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Convert the SF_PopupMenu instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Return:
&apos;&apos;&apos; &quot;[PopupMenu]: Name, Type (dialogname)
diff --git a/wizards/source/sfwidgets/SF_Register.xba b/wizards/source/sfwidgets/SF_Register.xba
index 4dbb84f03104..2c58b858d1e9 100644
--- a/wizards/source/sfwidgets/SF_Register.xba
+++ b/wizards/source/sfwidgets/SF_Register.xba
@@ -20,8 +20,12 @@ Option Explicit
&apos;&apos;&apos; The main methods in this module allow the current library to cling to ScriptForge
&apos;&apos;&apos; - RegisterScriptServices
&apos;&apos;&apos; Register the list of services implemented by the current library
+&apos;&apos;&apos; - _NewMenu
+&apos;&apos;&apos; Create a new menu service instance.
+&apos;&apos;&apos; Called from SFDocuments services with CreateMenu()
&apos;&apos;&apos; - _NewPopupMenu
-&apos;&apos;&apos; Create a new popup menu service instance
+&apos;&apos;&apos; Create a new popup menu service instance.
+&apos;&apos;&apos; Called from CreateScriptService()
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
REM ================================================================== EXCEPTIONS
@@ -46,7 +50,8 @@ Public Sub RegisterScriptServices() As Variant
&apos;&apos;&apos; &quot;libraryname.modulename.function&quot;
With GlobalScope.ScriptForge.SF_Services
- .RegisterService(&quot;PopupMenu&quot;, &quot;SFWidgets.SF_Register._NewPopupMenu&quot;) &apos; Reference to the function initializing the service
+ .RegisterService(&quot;Menu&quot;, &quot;SFWidgets.SF_Register._NewMenu&quot;) &apos; Reference to the function initializing the service
+ .RegisterService(&quot;PopupMenu&quot;, &quot;SFWidgets.SF_Register._NewPopupMenu&quot;) &apos; id.
End With
End Sub &apos; SFWidgets.SF_Register.RegisterScriptServices
@@ -54,13 +59,63 @@ End Sub &apos; SFWidgets.SF_Register.RegisterScriptServices
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
+Public Function _NewMenu(Optional ByVal pvArgs As Variant) As Object
+&apos;&apos;&apos; Create a new instance of the SF_Menu class
+&apos;&apos;&apos; [called internally from SFDocuments.Document.CreateMenu() ONLY]
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Component: the com.sun.star.lang.XComponent where to find the menubar to plug the new menu in
+&apos;&apos;&apos; Header: the name/header of the menu
+&apos;&apos;&apos; Before: the place where to put the new menu on the menubar (string or number &gt;= 1)
+&apos;&apos;&apos; When not found =&gt; last position
+&apos;&apos;&apos; SubmenuChar: the delimiter used in menu trees. Default = &quot;&gt;&quot;
+&apos;&apos;&apos; Returns: the instance or Nothing
+
+Dim oMenu As Object &apos; Return value
+Dim oComponent As Object &apos; The document or formdocument&apos;s component - com.sun.star.lang.XComponent
+Dim sHeader As String &apos; Menu header
+Dim sBefore As String &apos; Position of menu as a string
+Dim iBefore As Integer &apos; as a number
+Dim sSubmenuChar As String &apos; Delimiter in menu trees
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oMenu = Nothing
+
+Check:
+ &apos; Types and number of arguments are not checked because internal call only
+ Set oComponent = pvArgs(0)
+ sHeader = pvArgs(1)
+ Select Case VarType(pvArgs(2))
+ Case V_STRING : sBefore = pvArgs(2)
+ iBefore = 0
+ Case Else : sBefore = &quot;&quot;
+ iBefore = pvArgs(2)
+ End Select
+ sSubmenuChar = pvArgs(3)
+
+Try:
+ If Not IsNull(oComponent) Then
+ Set oMenu = New SF_Menu
+ With oMenu
+ Set .[Me] = oMenu
+ ._Initialize(oComponent, sHeader, sBefore, iBefore, sSubmenuChar)
+ End With
+ End If
+
+Finally:
+ Set _NewMenu = oMenu
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFWidgets.SF_Register._NewMenu
+
+REM -----------------------------------------------------------------------------
Public Function _NewPopupMenu(Optional ByVal pvArgs As Variant) As Object
&apos;&apos;&apos; Create a new instance of the SF_PopupMenu class
-&apos; Args:
+&apos;&apos;&apos; Args:
&apos;&apos;&apos; Event: a mouse event
&apos;&apos;&apos; If the event has no source or is not a mouse event, the menu is displayed above ThisComponent
&apos;&apos;&apos; X, Y: forced coordinates
-&apos;&apos;&apos; SubmenuChar: Delimiter in menu trees
+&apos;&apos;&apos; SubmenuChar: Delimiter used in menu trees
&apos;&apos;&apos; Returns: the instance or Nothing
Dim oMenu As Object &apos; Return value
@@ -86,6 +141,7 @@ Check:
If Not ScriptForge.SF_Utils._Validate(Event, &quot;Event&quot;, ScriptForge.V_OBJECT) Then GoTo Finally
If Not ScriptForge.SF_Utils._Validate(X, &quot;X&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
If Not ScriptForge.SF_Utils._Validate(Y, &quot;Y&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SubmenuChar, &quot;SubmenuChar&quot;, V_STRING) Then GoTo Finally
Set oMenu = Nothing
Try:
diff --git a/wizards/source/sfwidgets/script.xlb b/wizards/source/sfwidgets/script.xlb
index a32c363d4ac6..40e9f4c23df2 100644
--- a/wizards/source/sfwidgets/script.xlb
+++ b/wizards/source/sfwidgets/script.xlb
@@ -4,4 +4,6 @@
<library:element library:name="__License"/>
<library:element library:name="SF_Register"/>
<library:element library:name="SF_PopupMenu"/>
+ <library:element library:name="SF_Menu"/>
+ <library:element library:name="SF_MenuListener"/>
</library:library> \ No newline at end of file