summaryrefslogtreecommitdiff
path: root/wizards/source
diff options
context:
space:
mode:
Diffstat (limited to 'wizards/source')
-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
12 files changed, 1069 insertions, 35 deletions
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 = "SFDocuments"
Case "dialog", "dialogevent" : sLibrary = "SFDialogs"
Case "database" : sLibrary = "SFDatabases"
- Case "popupmenu" : sLibrary = "SFWidgets"
+ Case "menu", "popupmenu" : sLibrary = "SFWidgets"
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
''' Execute the script expressed in the scripting framework_URI notation
''' Args:
''' psScript: read https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification
-''' poEvent: the event object which triggered the execution. It is given as argument to the called script
+''' pvArg: the unique argument to pass to the called script.
+''' It is often an event object that triggered the execution of the script.
''' Returns:
''' 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)
' Execute script
If UCase(sLanguage) = "BASIC" Then
- _ExecuteScript = ExecuteBasicScript(sScope, sScript, poEvent)
+ _ExecuteScript = ExecuteBasicScript(sScope, sScript, pvArg)
Else ' 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, "SaveAsk", V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SaveAsk, "SaveAsk", ScriptForge.V_BOOLEAN) Then GoTo Finally
End If
Try:
@@ -442,12 +442,15 @@ Public Function Methods() As Variant
Methods = Array( _
"Activate" _
, "CloseDocument" _
+ , "CloseFormDocument" _
+ , "CreateMenu" _
, "FormDocuments" _
, "Forms" _
, "GetDatabase" _
, "IsLoaded" _
, "OpenFormDocument" _
, "PrintOut" _
+ , "RemoveMenu" _
, "RunCommand" _
, "Save" _
, "SaveAs" _
@@ -792,6 +795,19 @@ Public Function Activate() As Boolean
End Function ' 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 ' SFDocuments.SF_Base.CreateMenu
+
+REM -----------------------------------------------------------------------------
+Public Function RemoveMenu(Optional ByVal MenuHeader As Variant) As Boolean
+ RemoveMenu = [_Super].RemoveMenu(MenuHeader)
+End Function ' SFDocuments.SF_Base.RemoveMenu
+
+REM -----------------------------------------------------------------------------
Public Sub RunCommand(Optional ByVal Command As Variant)
[_Super].RunCommand(Command)
End Sub ' 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
, "CopyToCell" _
, "CopyToRange" _
, "CreateChart" _
+ , "CreateMenu" _
, "DAvg" _
, "DCount" _
, "DMax" _
@@ -1665,6 +1666,7 @@ Public Function Methods() As Variant
, "OpenRangeSelector" _
, "Printf" _
, "PrintOut" _
+ , "RemoveMenu" _
, "RemoveSheet" _
, "RenameSheet" _
, "RunCommand" _
@@ -2889,9 +2891,9 @@ Check:
If Not ScriptForge.SF_Utils._ValidateArray(SortKeys, "SortKeys", 1, V_NUMERIC, True) Then GoTo Finally
If Not ScriptForge.SF_Utils._Validate(DestinationCell, "DestinationCell", V_STRING) Then GoTo Finally
If Not ScriptForge.SF_Utils._ValidateArray(SortOrder, "SortOrder", 1, V_STRING, True) Then GoTo Finally
- If Not ScriptForge.SF_Utils._Validate(ContainsHeader, "ContainsHeader", V_BOOLEAN) Then GoTo Finally
- If Not ScriptForge.SF_Utils._Validate(CaseSensitive, "CaseSensitive", V_BOOLEAN) Then GoTo Finally
- If Not ScriptForge.SF_Utils._Validate(SortColumns, "SortColumns", V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(ContainsHeader, "ContainsHeader", ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(CaseSensitive, "CaseSensitive", ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SortColumns, "SortColumns", ScriptForge.V_BOOLEAN) Then GoTo Finally
End If
Set oRangeAddress = _ParseAddress(Range)
If Len(DestinationCell) > 0 Then Set oDestRange = _ParseAddress(DestinationCell)
@@ -3068,6 +3070,14 @@ Public Function CloseDocument(Optional ByVal SaveAsk As Variant) As Boolean
End Function ' 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 ' 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 ' SFDocuments.SF_Calc.ExportAsPDF
REM -----------------------------------------------------------------------------
+Public Function RemoveMenu(Optional ByVal MenuHeader As Variant) As Boolean
+ RemoveMenu = [_Super].RemoveMenu(MenuHeader)
+End Function ' SFDocuments.SF_Calc.RemoveMenu
+
+REM -----------------------------------------------------------------------------
Public Sub RunCommand(Optional ByVal Command As Variant)
[_Super].RunCommand(Command)
End Sub ' 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, "SaveAsk", V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SaveAsk, "SaveAsk", ScriptForge.V_BOOLEAN) Then GoTo Finally
End If
Try:
@@ -460,6 +460,63 @@ Catch:
End Function ' 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
+''' Create a new menu entry in the document's menubar
+''' The menu is not intended to be saved neither in the LibreOffice global environment, nor in the document
+''' The method returns a SFWidgets.Menu instance. Its methods let define the menu further.
+''' Args:
+''' MenuHeader: the name/header of the menu
+''' Before: the place where to put the new menu on the menubar (string or number >= 1)
+''' When not found => last position
+''' SubmenuChar: the delimiter used in menu trees. Default = ">"
+''' _Document: undocumented argument to designate the document where the menu will be located
+''' Returns:
+''' A SFWidgets.Menu instance or Nothing
+''' Examples:
+''' Dim oMenu As Object
+''' Set oMenu = oDoc.CreateMenu("My menu", Before := "Styles")
+''' With oMenu
+''' .AddItem("Item 1", Command := "About")
+''' '...
+''' .Dispose() ' When definition is complete, the menu instance may be disposed
+''' End With
+''' ' ...
+
+Dim oMenu As Object ' return value
+Const cstThisSub = "SFDocuments.Document.CreateMenu"
+Const cstSubArgs = "MenuHeader, [Before=""""], [SubmenuChar="">""]"
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oMenu = Nothing
+
+Check:
+ If IsMissing(Before) Or IsEmpty(Before) Then Before = ""
+ If IsMissing(SubmenuChar) Or IsEmpty(SubmenuChar) Then SubmenuChar = ""
+ 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, "MenuHeader", V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Before, "Before", V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SubmenuChar, "SubmenuChar", V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set oMenu = ScriptForge.SF_Services.CreateScriptService("SFWidgets.Menu", _Document, MenuHeader, Before, SubmenuChar)
+
+Finally:
+ Set CreateMenu = oMenu
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function ' 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, "FileName") Then GoTo Finally
- If Not SF_Utils._Validate(Overwrite, "Overwrite", V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(Overwrite, "Overwrite", ScriptForge.V_BOOLEAN) Then GoTo Finally
If Not SF_Utils._Validate(Pages, "Pages", V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Password, "Password", V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Watermark, "Watermark", V_STRING) Then GoTo Finally
@@ -596,8 +653,10 @@ Public Function Methods() As Variant
Methods = Array( _
"Activate" _
, "CloseDocument" _
+ , "CreateMenu" _
, "ExportAsPDF" _
, "PrintOut" _
+ , "RemoveMenu" _
, "RunCommand" _
, "Save" _
, "SaveAs" _
@@ -687,6 +746,73 @@ Public Function Properties() As Variant
End Function ' SFDocuments.SF_Document.Properties
REM -----------------------------------------------------------------------------
+Public Function RemoveMenu(Optional ByVal MenuHeader As Variant _
+ , Optional ByRef _Document As Variant _
+) As Boolean
+''' Remove a menu entry in the document's menubar
+''' The removal is not intended to be saved neither in the LibreOffice global environment, nor in the document
+''' Args:
+''' MenuHeader: the name/header of the menu, without tilde "~", as a case-sensitive string
+''' _Document: undocumented argument to designate the document where the menu is located
+''' Returns:
+''' True when successful
+''' Examples:
+''' oDoc.RemoveMenu("File")
+''' ' ...
+
+Dim bRemove As Boolean ' Return value
+Dim oLayout As Object ' com.sun.star.comp.framework.LayoutManager
+Dim oMenuBar As Object ' com.sun.star.awt.XMenuBar or stardiv.Toolkit.VCLXMenuBar
+Dim sName As String ' Menu name
+Dim iMenuId As Integer ' Menu identifier
+Dim iMenuPosition As Integer ' Menu position >= 0
+Dim i As Integer
+Const cstTilde = "~"
+
+Const cstThisSub = "SFDocuments.Document.RemoveMenu"
+Const cstSubArgs = "MenuHeader"
+
+ 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, "MenuHeader", V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set oLayout = _Document.CurrentController.Frame.LayoutManager
+ Set oMenuBar = oLayout.getElement("private:resource/menubar/menubar").XMenuBar
+
+ ' 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, "")
+ If MenuHeader= sName Then
+ iMenuPosition = i
+ Exit For
+ End If
+ Next i
+ ' Remove the found menu item
+ If iMenuPosition >= 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 ' SFDocuments.SF_Document.RemoveMenu
+
+REM -----------------------------------------------------------------------------
Public Sub RunCommand(Optional ByVal Command As Variant)
''' Run on the document the given menu command. The command is executed without arguments
''' 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, "FileName") Then GoTo Finally
- If Not SF_Utils._Validate(Overwrite, "Overwrite", V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(Overwrite, "Overwrite", ScriptForge.V_BOOLEAN) Then GoTo Finally
If Not SF_Utils._Validate(Password, "Password", V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(FilterName, "FilterName", V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(FilterOptions, "FilterOptions", 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, "FileName") Then GoTo Finally
- If Not SF_Utils._Validate(Overwrite, "Overwrite", V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(Overwrite, "Overwrite", ScriptForge.V_BOOLEAN) Then GoTo Finally
If Not SF_Utils._Validate(Password, "Password", V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(FilterName, "FilterName", V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(FilterOptions, "FilterOptions", 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( _
"Activate" _
, "CloseDocument" _
+ , "CreateMenu" _
, "ExportAsPDF" _
, "Forms" _
, "PrintOut" _
+ , "RemoveMenu" _
, "RunCommand" _
, "Save" _
, "SaveAs" _
@@ -493,6 +495,14 @@ Public Function CloseDocument(Optional ByVal SaveAsk As Variant) As Boolean
End Function ' 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 ' 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 ' SFDocuments.SF_Writer.ExportAsPDF
REM -----------------------------------------------------------------------------
+Public Function RemoveMenu(Optional ByVal MenuHeader As Variant) As Boolean
+ RemoveMenu = [_Super].RemoveMenu(MenuHeader)
+End Function ' SFDocuments.SF_Writer.RemoveMenu
+
+REM -----------------------------------------------------------------------------
Public Sub RunCommand(Optional ByVal Command As Variant)
[_Super].RunCommand(Command)
End Sub ' 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