ScriptForge (SFWidgets) new Toolbar and ToolbarButton services

Each component has its own set of toolbars, depending
on the component type (Calc, Writer, Basic IDE, ...).
In the context of the actual class, a toolbar
is presumed defined statically:
  - either by the application
  - or by a customization done by the user.
The definition of a toolbar can be stored
in the application configuration files
or in the current document.

Changes made by scripts to toolbars stored
in the application are persistent. They are valid
for all documents of the same type.

Note that the menubar and the statusbar
are not considered toolbars in this context.

A toolbar consists in a series of graphical
controls to trigger actions.
  The "Toolbar" service gives access to the "ToolbarButton" service to manage
  the individual buttons belonging to the toolbar.

The "Toolbar" service is triggered from next
services: Document, Calc, Writer, Base, FormDocument
and Datasheet. All those components might host toolbars.

Proposed properties in the Toolbar service:
  BuiltIn
  Docked
  HasGlobalScope
  Name
  ResourceURL
  Visible (r/w)
  XUIElement
Proposed method:
  ToolbarButtons()

Proposed properties in the ToolbarButton service:
  Caption
  Height
  Index
  OnClick (r/w)
  Parent
  TipText (r/w)
  Visible (r/w)
  X
  Y
(The Height, Width, X, Y properties allow for
easy hook of a popup menu to tye button)
Proposed method:
  Execute()

Both services are available both from Basic and Python user scripts.
An update of the dcumentation help is required.

Change-Id: I43cb523b52e3d6362994557d74c4ef9faa220507
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147925
Tested-by: Jean-Pierre Ledure <jp@ledure.be>
Reviewed-by: Jean-Pierre Ledure <jp@ledure.be>
Tested-by: Jenkins
diff --git a/wizards/Package_sfwidgets.mk b/wizards/Package_sfwidgets.mk
index 3e2041a..75fc0bd 100644
--- a/wizards/Package_sfwidgets.mk
+++ b/wizards/Package_sfwidgets.mk
@@ -24,6 +24,8 @@ $(eval $(call gb_Package_add_files,wizards_basicsrvsfwidgets,$(LIBO_SHARE_FOLDER
	SF_MenuListener.xba \
	SF_PopupMenu.xba \
	SF_Register.xba \
	SF_Toolbar.xba \
	SF_ToolbarButton.xba \
	__License.xba \
	dialog.xlb \
	script.xlb \
diff --git a/wizards/source/scriptforge/SF_PythonHelper.xba b/wizards/source/scriptforge/SF_PythonHelper.xba
index ffec0af..f7345d4 100644
--- a/wizards/source/scriptforge/SF_PythonHelper.xba
+++ b/wizards/source/scriptforge/SF_PythonHelper.xba
@@ -791,11 +791,15 @@ Try:
						Case &quot;SFDialogs.DialogControl&quot;
							If Script = &quot;SetTableData&quot; Then	vReturn = vBasicObject.SetTableData(vArgs(0), vArgs(1), vArgs(2))
						Case &quot;SFDocuments.Document&quot;
							If Script = &quot;Forms&quot; Then		vReturn = vBasicObject.Forms(vArgs(0))
							Select Case Script
								Case &quot;Forms&quot;			:	vReturn = vBasicObject.Forms(vArgs(0))
								Case &quot;Toolbars&quot;			:	vReturn = vBasicObject.Toolbars(vArgs(0))
							End Select
						Case &quot;SFDocuments.Base&quot;
							Select Case Script
								Case &quot;FormDocuments&quot;	:	vReturn = vBasicObject.FormDocuments()
								Case &quot;Forms&quot;			:	vReturn = vBasicObject.Forms(vArgs(0), vArgs(1))
								Case &quot;Toolbars&quot;			:	vReturn = vBasicObject.Toolbars(vArgs(0))
							End Select
						Case &quot;SFDocuments.Calc&quot;
							Select Case Script
@@ -806,6 +810,7 @@ Try:
								Case &quot;SetArray&quot;			:	vReturn = vBasicObject.SetArray(vArgs(0), vArgs(1))
								Case &quot;SetFormula&quot;		:	vReturn = vBasicObject.SetFormula(vArgs(0), vArgs(1))
								Case &quot;SetValue&quot;			:	vReturn = vBasicObject.SetValue(vArgs(0), vArgs(1))
								Case &quot;Toolbars&quot;			:	vReturn = vBasicObject.Toolbars(vArgs(0))
							End Select
						Case &quot;SFDocuments.Form&quot;
							Select Case Script
@@ -815,7 +820,14 @@ Try:
						Case &quot;SFDocuments.FormControl&quot;
							If Script = &quot;Controls&quot; Then		vReturn = vBasicObject.Controls(vArgs(0))
						Case &quot;SFDocuments.FormDocument&quot;
							If Script = &quot;Forms&quot; Then		vReturn = vBasicObject.Forms(vArgs(0))
							Select Case Script
								Case &quot;Forms&quot;			:	vReturn = vBasicObject.Forms(vArgs(0))
								Case &quot;Toolbars&quot;			:	vReturn = vBasicObject.Toolbars(vArgs(0))
							End Select
						Case &quot;SFWidgets.Toolbar&quot;
							Select Case Script
								Case &quot;ToolbarButtons&quot;	:	vReturn = vBasicObject.ToolbarButtons(vArgs(0))
							End Select
					End Select
				End If
			
diff --git a/wizards/source/scriptforge/SF_Root.xba b/wizards/source/scriptforge/SF_Root.xba
index 8c9a0db..2966866 100644
--- a/wizards/source/scriptforge/SF_Root.xba
+++ b/wizards/source/scriptforge/SF_Root.xba
@@ -80,6 +80,8 @@ Private PackageProvider		As Object	&apos; com.sun.star.comp.deployment.PackageIn
Private MailService			As Object	&apos; com.sun.star.system.SimpleCommandMail or com.sun.star.system.SimpleSystemMail
Private GraphicExportFilter	As Object	&apos; com.sun.star.drawing.GraphicExportFilter
Private Toolkit				As Object	&apos; com.sun.star.awt.Toolkit
Private ModuleUIConfigurationManagerSupplier	As Object
										&apos; com.sun.star.ui.ModuleUIConfigurationManagerSupplier

&apos;	Specific persistent services objects or properties
Private FileSystemNaming	As String	&apos; If &quot;SYS&quot;, file and folder naming is based on operating system notation
@@ -149,6 +151,7 @@ Private Sub Class_Initialize()
	Set MailService = Nothing
	Set GraphicExportFilter = Nothing
	Set Toolkit = Nothing
	Set ModuleUIConfigurationManagerSupplier = Nothing
	OSName = &quot;&quot;
	SFDialogs = Empty
	SFForms = Empty
diff --git a/wizards/source/scriptforge/SF_Services.xba b/wizards/source/scriptforge/SF_Services.xba
index 8de43d3..f5e0545 100644
--- a/wizards/source/scriptforge/SF_Services.xba
+++ b/wizards/source/scriptforge/SF_Services.xba
@@ -131,7 +131,8 @@ Try:
			Case &quot;dialog&quot;, &quot;dialogevent&quot;			:	sLibrary = &quot;SFDialogs&quot;
			Case &quot;database&quot;, &quot;datasheet&quot;			:	sLibrary = &quot;SFDatabases&quot;
			Case &quot;unittest&quot;							:	sLibrary = &quot;SFUnitTests&quot;
			Case &quot;menu&quot;, &quot;popupmenu&quot;				:	sLibrary = &quot;SFWidgets&quot;
			Case &quot;menu&quot;, &quot;popupmenu&quot;, &quot;toolbar&quot;, &quot;toolbarbutton&quot;
														sLibrary = &quot;SFWidgets&quot;
			Case Else
		End Select
	Else
diff --git a/wizards/source/scriptforge/SF_UI.xba b/wizards/source/scriptforge/SF_UI.xba
index 4b96ac3..b01f613 100644
--- a/wizards/source/scriptforge/SF_UI.xba
+++ b/wizards/source/scriptforge/SF_UI.xba
@@ -56,6 +56,15 @@ Type Window
	ParentName				As String		&apos;	Identifier of the parent Base file when Window is a subcomponent
End Type

Type _Toolbar				&apos;	Proto-toolbar object. Passed to the &quot;Toolbar&quot; service, a full ScriptForge Toolbar object will be returned
	Component				As Object		&apos;	com.sun.star.lang.XComponent
	ResourceURL				As String		&apos;	Toolbar internal name
	UIName					As String		&apos;	Toolbar external name, may be &quot;&quot;
	UIConfigurationManager	As Object		&apos;	com.sun.star.ui.XUIConfigurationManager
	ElementsInfoIndex		As Long			&apos;	Index of the toolbar in the getElementsInfo(0) array
	Storage					As Long			&apos;	One of the toolbar location constants
End Type

&apos;	The progress/status bar of the active window
&apos;Private oStatusBar			As Object		&apos;	com.sun.star.task.XStatusIndicator

@@ -86,6 +95,11 @@ Const cstMACROEXECNORMAL		= 0		&apos;	Default, execution depends on user configu
Const cstMACROEXECNEVER			= 1		&apos;	Macros are not executed
Const cstMACROEXECALWAYS		= 2		&apos;	Macros are always executed

&apos;	Toolbar locations
Const cstBUILTINTOOLBAR			= 0		&apos;	Standard toolbar
Const cstCUSTOMTOOLBAR			= 1		&apos;	Toolbar added by user and stored in the LibreOffice application
Const cstCUSTOMDOCTOOLBAR		= 2		&apos;	Toolbar added by user solely for a single document

REM ===================================================== CONSTRUCTOR/DESTRUCTOR

REM -----------------------------------------------------------------------------
@@ -1277,7 +1291,7 @@ Dim FSO As Object					&apos;	Alias for SF_FileSystem
				.WindowFileName = SF_Utils._GetPropertyValue(poComponent.Args, &quot;URL&quot;)
				If Len(.WindowFileName) &gt; 0 Then .WindowName = FSO.GetName(FSO._ConvertFromUrl(.WindowFileName))
				.DocumentType = BASEDOCUMENT
			Case &quot;org.openoffice.comp.dbu.ODatasourceBrowser&quot;		&apos;	Base datasheet (table, query or sql in read mode
			Case &quot;org.openoffice.comp.dbu.ODatasourceBrowser&quot;		&apos;	Base datasheet (table, query or sql) in read mode
				Set .Frame = poComponent.Frame
				If Not IsEmpty(poComponent.Selection) Then		&apos;	Empty for (F4) DatasourceBrowser !!
					vSelection = poComponent.Selection
@@ -1333,6 +1347,132 @@ Catch:
End Function		&apos;	ScriptForge.SF_UI._IdentifyWindow

REM -----------------------------------------------------------------------------
Public Function _ListToolbars(ByRef poComponent As Object) As Object
&apos;&apos;&apos;	Returns a SF_Dictionary object containing a list of all available
&apos;&apos;&apos;	toolbars in the given component
&apos;&apos;&apos;	A toolbar may be located:
&apos;&apos;&apos;		- builtin in the LibreOffice configuration, but dependent on the component type
&apos;&apos;&apos;		- added by the user and stored in the LibreOffice configuration of the user
&apos;&apos;&apos;		- added by the user and stored in the component/document itself
&apos;&apos;&apos;	The output dictionary has as
&apos;&apos;&apos;		key: the UIName of the toolbar when not blank, otherwise the last component of its ResourceURL
&apos;&apos;&apos;		item: a _Toolbar object (see top of module)
&apos;&apos;&apos;	Menubar, statusbar and popup menus are ignored.
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		poComponent: any component in desktop, typically a document but not only

Dim oToolbarsDict As Object					&apos;	Return value
Dim oWindow As Object						&apos;	Window type
Dim oConfigMgr As Object					&apos;	com.sun.star.ui.ModuleUIConfigurationManagerSupplier
Dim sConfigurationManager As String			&apos;	Derived from the component&apos;s type
Dim oUIConfigMgr As Object					&apos;	com.sun.star.comp.framework.ModuleUIConfigurationManager
Dim vCommandBars As Variant					&apos;	Array of  bars in component
Dim vCommandBar As Variant					&apos;	Array of PropertyValue about a single bar
Dim oToolbar As Object						&apos;	Toolbar description as a _Toolbar object
Dim sResourceURL As String					&apos;	Toolbar internal name as &quot;private:resource/toolbar/...&quot;
Dim sUIName As String						&apos;	Toolbar external name, may be zero-length string
Dim sBarName As String						&apos;	External bar name: either UIName or last component of resource URL
Dim i As Long

Const cstCUSTOM = &quot;custom_&quot;

Check:
&apos;	On Local Error GoTo Catch
	If IsNull(poComponent) Then GoTo Catch

Try:
	Set oToolbarsDict = CreateScriptService(&quot;Dictionary&quot;)
	Set oWindow = _IdentifyWindow(poComponent)

	&apos;	1. Collect all builtin and custom toolbars stored in the LibreOffice configuration files

	&apos;		Derive the name of the UI configuration manager from the component type
	With oWindow
		Select Case .WindowName
			Case BASICIDE		:	sConfigurationManager = &quot;com.sun.star.script.BasicIDE&quot;
			Case WELCOMESCREEN	:	sConfigurationManager = &quot;com.sun.star.frame.StartModule&quot;
			Case Else
				Select Case .DocumentType
					Case BASEDOCUMENT		:	sConfigurationManager = &quot;com.sun.star.sdb.OfficeDatabaseDocument&quot;
					Case CALCDOCUMENT		:	sConfigurationManager = &quot;com.sun.star.sheet.SpreadsheetDocument&quot;
					Case DRAWDOCUMENT		:	sConfigurationManager = &quot;com.sun.star.drawing.DrawingDocument&quot;
					Case FORMDOCUMENT		:	sConfigurationManager = &quot;com.sun.star.sdb.FormDesign&quot;
					Case IMPRESSDOCUMENT	:	sConfigurationManager = &quot;com.sun.star.presentation.PresentationDocument&quot;
					Case MATHDOCUMENT		:	sConfigurationManager = &quot;com.sun.star.formula.FormulaProperties&quot;
					Case WRITERDOCUMENT		:	sConfigurationManager = &quot;com.sun.star.text.TextDocument&quot;
					Case TABLEDATA, QUERYDATA, SQLDATA
												sConfigurationManager = &quot;com.sun.star.sdb.DataSourceBrowser&quot;
					Case Else				:	sConfigurationManager = &quot;&quot;
				End Select
		End Select
	End With
	Set oConfigMgr = SF_Utils._GetUNOService(&quot;ModuleUIConfigurationManagerSupplier&quot;)
	Set oUIConfigMgr = oConfigMgr.getUIConfigurationManager(sConfigurationManager)
	vCommandBars = oUIConfigMgr.getUIElementsInfo(com.sun.star.ui.UIElementType.TOOLBAR)

	&apos;		Ignore statusbar, menubar and popup menus. Store toolbars in dictionary
	For i = 0 To UBound(vCommandBars)
		vCommandBar = vCommandBars(i)
		sResourceURL = SF_Utils._GetPropertyValue(vCommandBar, &quot;ResourceURL&quot;)
		sUIName = SF_Utils._GetPropertyValue(vCommandBar, &quot;UIName&quot;)
		If Len(sUIName) &gt; 0 Then sBarName = sUIName Else sBarName = Split(sResourceURL, &quot;/&quot;)(2)
		&apos;	Store a new entry in the returned dictionary
		If Not oToolbarsDict.Exists(sBarName) Then
			Set oToolbar = New _Toolbar
			With oToolbar
				Set .Component = poComponent
				.ResourceURL = sResourceURL
				.UIName = sUIName
				Set .UIConfigurationManager = oUIConfigMgr
				.ElementsInfoIndex = i
				&apos;	Distinguish builtin and custom toolbars stored in the applcation
				If SF_String.StartsWith(sBarName, cstCUSTOM, CaseSensitive := True) Then
					.Storage = cstCUSTOMTOOLBAR
					sBarName = Mid(sBarName, Len(cstCUSTOM) + 1)
				Else
					.Storage = cstBUILTINTOOLBAR
				End If
			End With
			oToolbarsDict.Add(sBarName, oToolbar)
		End If
	Next i

	&apos;	2. Collect all toolbars stored in the current component/document

	&apos;	Some components (e.g. datasheets) cannot contain own toolbars
	If SF_Session.HasUnoMethod(poComponent, &quot;getUIConfigurationManager&quot;) Then
		Set oUIConfigMgr = poComponent.getUIConfigurationManager
		vCommandBars = oUIConfigMgr.getUIElementsInfo(com.sun.star.ui.UIElementType.TOOLBAR)
		For i = 0 To UBound(vCommandBars)
			vCommandBar = vCommandBars(i)
			sResourceURL = SF_Utils._GetPropertyValue(vCommandBar, &quot;ResourceURL&quot;)
			sUIName = SF_Utils._GetPropertyValue(vCommandBar, &quot;UIName&quot;)
			If Len(sUIName) &gt; 0 Then sBarName = sUIName Else sBarName = Split(sResourceURL, &quot;/&quot;)(2)
			&apos;	Store a new entry in the returned dictionary
			If Not oToolbarsDict.Exists(sBarName) Then
				Set oToolbar = New _Toolbar
				With oToolbar
					Set .Component = poComponent
					.ResourceURL = sResourceURL
					.UIName = sUIName
					Set .UIConfigurationManager = oUIConfigMgr
					.ElementsInfoIndex = i
					.Storage = cstCUSTOMDOCTOOLBAR
				End With
				oToolbarsDict.Add(sBarName, oToolbar)
			End If
		Next i
	End If

Finally:
	Set _ListToolbars = oToolbarsDict
	Exit Function
Catch:
	Set oToolbarsDict = Nothing
	GoTo Finally
End Function		&apos;	ScriptForge.SF_UI._ListToolbars

REM -----------------------------------------------------------------------------
Public Function _PosSize() As Object
&apos;&apos;&apos;	Returns the PosSize structure of the active window

diff --git a/wizards/source/scriptforge/SF_Utils.xba b/wizards/source/scriptforge/SF_Utils.xba
index d01d66a..c19f815 100644
--- a/wizards/source/scriptforge/SF_Utils.xba
+++ b/wizards/source/scriptforge/SF_Utils.xba
@@ -153,7 +153,7 @@ Finally:
End Function	&apos;	ScriptForge.SF_Utils._CStrToDate

REM -----------------------------------------------------------------------------
Public Function _EnterFunction(ByVal psSub As String, Optional ByVal psArgs As String)
Public Function _EnterFunction(ByVal psSub As String, Optional ByVal psArgs As String) As Boolean
&apos;&apos;&apos;	Called on top of each public function
&apos;&apos;&apos;	Used to trace routine in/outs (debug mode)
&apos;&apos;&apos;		and to allow the explicit mention of the user call which caused an error
@@ -426,6 +426,11 @@ Dim oDefaultContext As Object
					End If
				End If
				Set _GetUNOService = .MailService
			Case &quot;ModuleUIConfigurationManagerSupplier&quot;
				If IsEmpty(.ModuleUIConfigurationManagerSupplier) Or IsNull(.ModuleUIConfigurationManagerSupplier) Then
					Set .ModuleUIConfigurationManagerSupplier = CreateUnoService(&quot;com.sun.star.ui.ModuleUIConfigurationManagerSupplier&quot;)
				End If
				Set _GetUNOService = .ModuleUIConfigurationManagerSupplier
			Case &quot;Number2Text&quot;
				If IsEmpty(.Number2Text) Or IsNull(.Number2Text) Then
					Set .Number2Text = CreateUnoService(&quot;com.sun.star.linguistic2.NumberText&quot;)
diff --git a/wizards/source/scriptforge/python/scriptforge.py b/wizards/source/scriptforge/python/scriptforge.py
index a67dca4..7208ff81 100644
--- a/wizards/source/scriptforge/python/scriptforge.py
+++ b/wizards/source/scriptforge/python/scriptforge.py
@@ -1806,6 +1806,9 @@ class SFDatabases:
        def RemoveMenu(self, menuheader):
            return self.ExecMethod(self.vbMethod, 'RemoveMenu', menuheader)

        def Toolbars(self, toolbarname = ''):
            return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'Toolbars', toolbarname)


# #####################################################################################################################
#                       SFDialogs CLASS    (alias of SFDialogs Basic library)                                       ###
@@ -2022,6 +2025,9 @@ class SFDocuments:
        def SetPrinter(self, printer = '', orientation = '', paperformat = ''):
            return self.ExecMethod(self.vbMethod, 'SetPrinter', printer, orientation, paperformat)

        def Toolbars(self, toolbarname = ''):
            return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'Toolbars', toolbarname)

    # #########################################################################
    # SF_Base CLASS
    # #########################################################################
@@ -2590,6 +2596,46 @@ class SFWidgets:
        def Execute(self, returnid = True):
            return self.ExecMethod(self.vbMethod, 'Execute', returnid)

    # #########################################################################
    # SF_Toolbar CLASS
    # #########################################################################
    class SF_Toolbar(SFServices):
        """
            Each component has its own set of toolbars, depending on the component type
            (Calc, Writer, Basic IDE, ...).
            In the context of the actual class, a toolbar is presumed defined statically:
                - either by the application
                - or by a customization done by the user.
            """
        # Mandatory class properties for service registration
        serviceimplementation = 'basic'
        servicename = 'SFWidgets.Toolbar'
        servicesynonyms = ('toolbar', 'sfwidgets.toolbar')
        serviceproperties = dict(BuiltIn = False, Docked = False, HasGlobalScope = False, Name = False,
                                 ResourceURL = False, Visible = True, XUIElement = False)

        def ToolbarButtons(self, buttonname = ''):
            return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'ToolbarButtons', buttonname)

    # #########################################################################
    # SF_ToolbarButton CLASS
    # #########################################################################
    class SF_ToolbarButton(SFServices):
        """
            A toolbar consists in a series of graphical controls to trigger actions.
            The "Toolbar" service gives access to the "ToolbarButton" service to manage
            the individual buttons belonging to the toolbar.
            """
        # Mandatory class properties for service registration
        serviceimplementation = 'basic'
        servicename = 'SFWidgets.ToolbarButton'
        servicesynonyms = ('toolbarbutton', 'sfwidgets.toolbarbutton')
        serviceproperties = dict(Caption = False, Height = False, Index = False, OnClick = True, Parent = False,
                                 TipText = True, Visible = True, Width = False, X = False, Y = False)

        def Execute(self):
            return self.ExecMethod(self.vbMethod, 'Execute')


# ##############################################False##################################################################
#                           CreateScriptService()                                                                   ###
diff --git a/wizards/source/sfdatabases/SF_Datasheet.xba b/wizards/source/sfdatabases/SF_Datasheet.xba
index 12b7f9e..775984f 100644
--- a/wizards/source/sfdatabases/SF_Datasheet.xba
+++ b/wizards/source/sfdatabases/SF_Datasheet.xba
@@ -66,6 +66,9 @@ Private _ControlModel		As Object		&apos; com.sun.star.awt.XControlModel - com.su
Private _ControlView		As Object		&apos; com.sun.star.awt.XControl - org.openoffice.comp.dbu.ODatasourceBrowser
Private _ColumnHeaders		As Variant		&apos; List of column headers as an array of strings

&apos;	Cache for static toolbar descriptions
Private _Toolbars				As Object	&apos; SF_Dictionary instance to hold toolbars stored in application or in document

REM ============================================================ MODULE CONSTANTS

REM ====================================================== CONSTRUCTOR/DESTRUCTOR
@@ -89,6 +92,7 @@ Private Sub Class_Initialize()
	Set _ControlModel = Nothing
	Set _ControlView = Nothing
	_ColumnHeaders = Array()
	Set _Toolbars = Nothing
End Sub		&apos;	SFDatabases.SF_Datasheet Constructor

REM -----------------------------------------------------------------------------
@@ -682,6 +686,50 @@ Catch:
	GoTo Finally
End Function	&apos;	SFDatabases.SF_Datasheet.SetProperty

REM -----------------------------------------------------------------------------
Public Function Toolbars(Optional ByVal ToolbarName As Variant) As Variant
&apos;&apos;&apos;	Returns either a list of the available toolbar names in the actual document
&apos;&apos;&apos;	or a Toolbar object instance.
&apos;&apos;&apos;	[Function identical with SFDocuments.SF_Document.Toolbars()]
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		ToolbarName: the usual name of one of the available toolbars
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		A zero-based array of toolbar names when the argument is absent,
&apos;&apos;&apos;		or a new Toolbar object instance from the SF_Widgets library.

Const cstThisSub = &quot;SFDatabases.Datasheet.Toolbars&quot;
Const cstSubArgs = &quot;[ToolbarName=&quot;&quot;&quot;&quot;]&quot;

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch

Check:
	If IsMissing(ToolbarName) Or IsEmpty(ToolbarName) Then ToolbarName = &quot;&quot;
	If IsNull(_Toolbars) Then _Toolbars = ScriptForge.SF_UI._ListToolbars(_Component)
	If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
		If Not _IsStillAlive() Then GoTo Finally
		If VarType(ToolbarName) = V_STRING Then
			If Len(ToolbarName) &gt; 0 Then
				If Not ScriptForge.SF_Utils._Validate(ToolbarName, &quot;ToolbarName&quot;, V_STRING, _Toolbars.Keys()) Then GoTo Finally
			End If
		Else
			If Not ScriptForge.SF_Utils._Validate(ToolbarName, &quot;ToolbarName&quot;, V_STRING) Then GoTo Finally	&apos;	Manage here the VarType error
		End If
	End If

Try:
	If Len(ToolbarName) = 0 Then
		Toolbars = _Toolbars.Keys()
	Else
		Toolbars = CreateScriptService(&quot;SFWidgets.Toolbar&quot;, _Toolbars.Item(ToolbarName))
	End If

Finally:
	ScriptForge.SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	SF_Databases.SF_Datasheet.Toolbars

REM =========================================================== PRIVATE FUNCTIONS

REM -----------------------------------------------------------------------------
diff --git a/wizards/source/sfdocuments/SF_Base.xba b/wizards/source/sfdocuments/SF_Base.xba
index e39b251..cc5ab48 100644
--- a/wizards/source/sfdocuments/SF_Base.xba
+++ b/wizards/source/sfdocuments/SF_Base.xba
@@ -948,6 +948,11 @@ Public Function SaveCopyAs(Optional ByVal FileName As Variant _
	SaveCopyAs = [_Super].SaveCopyAs(FileName, Overwrite, Password, FilterName, FilterOptions)
End Function   &apos;   SFDocuments.SF_Base.SaveCopyAs

REM -----------------------------------------------------------------------------
Public Function Toolbars(Optional ByVal ToolbarName As Variant) As Variant
	Toolbars = [_Super].Toolbars(ToolbarName)
End Function	&apos;	SFDocuments.SF_Base.Toolbars

REM =========================================================== PRIVATE FUNCTIONS

REM -----------------------------------------------------------------------------
diff --git a/wizards/source/sfdocuments/SF_Calc.xba b/wizards/source/sfdocuments/SF_Calc.xba
index dfd66fb..fe71b69 100644
--- a/wizards/source/sfdocuments/SF_Calc.xba
+++ b/wizards/source/sfdocuments/SF_Calc.xba
@@ -3780,6 +3780,11 @@ Public Function SetPrinter(Optional ByVal Printer As Variant _
	SetPrinter = [_Super].SetPrinter(Printer, Orientation, PaperFormat)
End Function	&apos;   SFDocuments.SF_Calc.SetPrinter

REM -----------------------------------------------------------------------------
Public Function Toolbars(Optional ByVal ToolbarName As Variant) As Variant
	Toolbars = [_Super].Toolbars(ToolbarName)
End Function	&apos;	SFDocuments.SF_Calc.Toolbars

REM =========================================================== PRIVATE FUNCTIONS

REM -----------------------------------------------------------------------------
diff --git a/wizards/source/sfdocuments/SF_Document.xba b/wizards/source/sfdocuments/SF_Document.xba
index 879d90c..2233aeb 100644
--- a/wizards/source/sfdocuments/SF_Document.xba
+++ b/wizards/source/sfdocuments/SF_Document.xba
@@ -80,6 +80,9 @@ Private _DocumentType			As String		&apos;	Writer, Calc, ...
Private _DocumentProperties		As Object		&apos;	Dictionary of document properties
Private _CustomProperties		As Object		&apos;	Dictionary of custom properties

&apos;	Cache for static toolbar descriptions
Private _Toolbars				As Object		&apos;	SF_Dictionary instance to hold toolbars stored in application or in document

REM ============================================================ MODULE CONSTANTS

Const ISDOCFORM = 1				&apos;	Form is stored in a Writer document
@@ -101,6 +104,7 @@ Private Sub Class_Initialize()
	_DocumentType = &quot;&quot;
	Set _DocumentProperties = Nothing
	Set _CustomProperties = Nothing
	Set _Toolbars = Nothing
End Sub		&apos;	SFDocuments.SF_Document Constructor

REM -----------------------------------------------------------------------------
@@ -417,7 +421,7 @@ Try:
	Set oContainer = _Frame.ContainerWindow
	With oContainer
		If .isVisible() = False Then .setVisible(True)
		.IsMinimized = False
		If .IsMinimized Then .IsMinimized = False
		.setFocus()
		.toFront()				&apos;	Force window change in Linux
		Wait 1					&apos;	Bypass desynchro issue in Linux
@@ -1357,6 +1361,49 @@ Catch:
	GoTo Finally
End Function	&apos;	SFDocuments.SF_Document.SetProperty

REM -----------------------------------------------------------------------------
Public Function Toolbars(Optional ByVal ToolbarName As Variant) As Variant
&apos;&apos;&apos;	Returns either a list of the available toolbar names in the actual document
&apos;&apos;&apos;	or a Toolbar object instance.
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		ToolbarName: the usual name of one of the available toolbars
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		A zero-based array of toolbar names when the argument is absent,
&apos;&apos;&apos;		or a new Toolbar object instance from the SF_Widgets library.

Const cstThisSub = &quot;SFDocuments.Document.Toolbars&quot;
Const cstSubArgs = &quot;[ToolbarName=&quot;&quot;&quot;&quot;]&quot;

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch

Check:
	If IsMissing(ToolbarName) Or IsEmpty(ToolbarName) Then ToolbarName = &quot;&quot;
	If IsNull(_Toolbars) Then _Toolbars = ScriptForge.SF_UI._ListToolbars(_Component)
	If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
		If Not _IsStillAlive() Then GoTo Finally
		If VarType(ToolbarName) = V_STRING Then
			If Len(ToolbarName) &gt; 0 Then
				If Not ScriptForge.SF_Utils._Validate(ToolbarName, &quot;ToolbarName&quot;, V_STRING, _Toolbars.Keys()) Then GoTo Finally
			End If
		Else
			If Not ScriptForge.SF_Utils._Validate(ToolbarName, &quot;ToolbarName&quot;, V_STRING) Then GoTo Finally	&apos;	Manage here the VarType error
		End If
	End If

Try:
	If Len(ToolbarName) = 0 Then
		Toolbars = _Toolbars.Keys()
	Else
		Toolbars = CreateScriptService(&quot;SFWidgets.Toolbar&quot;, _Toolbars.Item(ToolbarName))
	End If

Finally:
	ScriptForge.SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	SFDocuments.SF_Document.Toolbars

REM =========================================================== PRIVATE FUNCTIONS

REM -----------------------------------------------------------------------------
diff --git a/wizards/source/sfdocuments/SF_FormDocument.xba b/wizards/source/sfdocuments/SF_FormDocument.xba
index f0dfa51..a619ac1 100644
--- a/wizards/source/sfdocuments/SF_FormDocument.xba
+++ b/wizards/source/sfdocuments/SF_FormDocument.xba
@@ -535,6 +535,11 @@ Public Function SetPrinter(Optional ByVal Printer As Variant _
	SetPrinter = [_Super].SetPrinter(Printer, Orientation, PaperFormat)
End Function	&apos;   SFDocuments.SF_FormDocument.SetPrinter

REM -----------------------------------------------------------------------------
Public Function Toolbars(Optional ByVal ToolbarName As Variant) As Variant
	Toolbars = [_Super].Toolbars(ToolbarName)
End Function	&apos;	SFDocuments.SF_FormDocument.Toolbars

REM =========================================================== PRIVATE FUNCTIONS

REM -----------------------------------------------------------------------------
diff --git a/wizards/source/sfdocuments/SF_Writer.xba b/wizards/source/sfdocuments/SF_Writer.xba
index d19b18d..685fd20 100644
--- a/wizards/source/sfdocuments/SF_Writer.xba
+++ b/wizards/source/sfdocuments/SF_Writer.xba
@@ -574,6 +574,11 @@ Public Function SetPrinter(Optional ByVal Printer As Variant _
	SetPrinter = [_Super].SetPrinter(Printer, Orientation, PaperFormat)
End Function	&apos;   SFDocuments.SF_Writer.SetPrinter

REM -----------------------------------------------------------------------------
Public Function Toolbars(Optional ByVal ToolbarName As Variant) As Variant
	Toolbars = [_Super].Toolbars(ToolbarName)
End Function	&apos;	SFDocuments.SF_Writer.Toolbars

REM =========================================================== PRIVATE FUNCTIONS

REM -----------------------------------------------------------------------------
diff --git a/wizards/source/sfwidgets/SF_Register.xba b/wizards/source/sfwidgets/SF_Register.xba
index 7dc2708..d2c4245 100644
--- a/wizards/source/sfwidgets/SF_Register.xba
+++ b/wizards/source/sfwidgets/SF_Register.xba
@@ -52,6 +52,8 @@ Public Sub RegisterScriptServices() As Variant
	With GlobalScope.ScriptForge.SF_Services
		.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.
		.RegisterService(&quot;Toolbar&quot;,				&quot;SFWidgets.SF_Register._NewToolbar&quot;)		&apos;	id.
		.RegisterService(&quot;ToolbarButton&quot;,		&quot;SFWidgets.SF_Register._NewToolbarButton&quot;)		&apos;	id.
	End With

End Sub			&apos;	SFWidgets.SF_Register.RegisterScriptServices
@@ -131,6 +133,7 @@ Dim oSession As Object				:	Set oSession = ScriptForge.SF_Services.CreateScriptS
Dim oUi As Object					:	Set oUi = ScriptForge.SF_Services.CreateScriptService(&quot;ScriptForge.UI&quot;)

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	Set oMenu = Nothing

Check:
	&apos;	Check and get arguments, their number may vary
@@ -145,7 +148,6 @@ Check:
	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:
	&apos;	Find and identify the control that triggered the popup menu
@@ -186,5 +188,70 @@ Catch:
	GoTo Finally
End Function	&apos;	SFWidgets.SF_Register._NewPopupMenu

REM ============================================== END OF SFWidgets.SF_REGISTER
REM -----------------------------------------------------------------------------
Public Function _NewToolbar(Optional ByVal pvArgs As Variant) As Object
&apos;&apos;&apos;	Create a new instance of the SF_Toolbar class
&apos;&apos;&apos;	The &quot;Toolbar&quot; service must not be invoked directly in a user script
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		ToolbarDesc: a proto-toolbar object type. See ScriptForge.SF_UI for a detailed description
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		the instance or Nothing

Dim oToolbar As Object			&apos;	Return value
Dim oToolbarDesc As Object		&apos;	A proto-toolbar description

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	Set oToolbar = Nothing

Check:
	Set oToolbarDesc = pvArgs(0)

Try:
	Set oToolbar = New SF_Toolbar
	With oToolbar
		Set .[Me] = oToolbar
		._Initialize(oToolbarDesc)
	End With

Finally:
	Set _NewToolbar = oToolbar
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	SFWidgets.SF_Register._NewToolbar

REM -----------------------------------------------------------------------------
Public Function _NewToolbarButton(Optional ByVal pvArgs As Variant) As Object
&apos;&apos;&apos;	Create a new instance of the SF_ToolbarButton class
&apos;&apos;&apos;	The &quot;ToolbarButton&quot; service must not be invoked directly in a user script
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		ToolbarButtonDesc: a proto-toolbarButton object type. See SFWidgets.SF_Toolbar for a detailed description
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		the instance or Nothing

Dim oToolbarButton As Object		&apos;	Return value
Dim oToolbarButtonDesc As Object	&apos;	A proto-toolbarbutton description

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	Set oToolbarButton = Nothing

Check:
	Set oToolbarButtonDesc = pvArgs(0)

Try:
	Set oToolbarButton = New SF_ToolbarButton
	With oToolbarButton
		Set .[Me] = oToolbarButton
		._Initialize(oToolbarButtonDesc)
	End With

Finally:
	Set _NewToolbarButton = oToolbarButton
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	SFWidgets.SF_Register._NewToolbarButton


REM ============================================== END OF SFWIDGETS.SF_REGISTER
</script:module>
\ No newline at end of file
\ No newline at end of file
diff --git a/wizards/source/sfwidgets/SF_Toolbar.xba b/wizards/source/sfwidgets/SF_Toolbar.xba
new file mode 100644
index 0000000..16089e4
--- /dev/null
+++ b/wizards/source/sfwidgets/SF_Toolbar.xba
@@ -0,0 +1,541 @@
<?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_Toolbar" 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_Toolbar
&apos;&apos;&apos;	==========
&apos;&apos;&apos;		Hide/show a toolbar related to a component/document.
&apos;&apos;&apos;
&apos;&apos;&apos;		Each component has its own set of toolbars, depending on the component type
&apos;&apos;&apos;		(Calc, Writer, Basic IDE, ...).
&apos;&apos;&apos;		In the context of the actual class, a toolbar is presumed defined statically:
&apos;&apos;&apos;			- either by the application
&apos;&apos;&apos;			- or by a customization done by the user.
&apos;&apos;&apos;		The definition of a toolbar can be stored in the application configuration files
&apos;&apos;&apos;		or in a specific document.
&apos;&apos;&apos;		Changes made by scripts to toolbars stored in the application are persistent.
&apos;&apos;&apos;		They are valid for all documents of the same type.
&apos;&apos;&apos;
&apos;&apos;&apos;		Note that the menubar and the statusbar are not considered toolbars in this context.
&apos;&apos;&apos;
&apos;&apos;&apos;		A toolbar consists in a series of graphical controls to trigger actions.
&apos;&apos;&apos;		The &quot;Toolbar&quot; service gives access to the &quot;ToolbarButton&quot; service to manage
&apos;&apos;&apos;		the individual buttons belonging to the toolbar.
&apos;&apos;&apos;
&apos;&apos;&apos;		The name of a toolbar is either:
&apos;&apos;&apos;			- its so-called UIName when it is available,
&apos;&apos;&apos;			- or the last component of the resource URL: &quot;private:resource/toolbar/the-name-here&quot;
&apos;&apos;&apos;
&apos;&apos;&apos;		Service invocation:
&apos;&apos;&apos;			The Toolbars() method returns the list of available toolbar names
&apos;&apos;&apos;			The Toolbars(toolbarname) returns a Toolbar service
&apos;&apos;&apos;			It is available from
&apos;&apos;&apos;				- the UI service to access the toolbars of the Basic IDE (&quot;BASICIDE&quot;),
&apos;&apos;&apos;				  the start center (&quot;WELCOMESCREEN&quot;) or the active window
&apos;&apos;&apos;				- the Document, Calc, Writer, Datasheet, FormDocument services to access
&apos;&apos;&apos;				  their respective set of toolbars.
&apos;&apos;&apos;			Example:
&apos;&apos;&apos;				Dim oCalc As Object, oToolbar As Object
&apos;&apos;&apos;				Set oCalc = CreateScriptService(&quot;Calc&quot;, &quot;myFile.ods&quot;)
&apos;&apos;&apos;				Set oToolbar = oCalc.Toolbars(&quot;findbar&quot;)

REM ================================================================== EXCEPTIONS

REM ============================================================= PRIVATE MEMBERS

Private [Me]					As Object
Private ObjectType				As String		&apos; Must be TOOLBAR
Private ServiceName 			As String

Private _Component				As Object		&apos; com.sun.star.lang.XComponent
Private _ResourceURL			As String		&apos; Toolbar internal name
Private _UIName					As String		&apos; Toolbar external name, may be &quot;&quot;
Private _UIConfigurationManager	As Object		&apos; com.sun.star.ui.XUIConfigurationManager
Private _ElementsInfoIndex		As Long			&apos; Index of the toolbar in the getElementsInfo(0) array
Private _Storage				As Long			&apos; One of the toolbar location constants
Private _LayoutManager			As Object		&apos; com.sun.star.comp.framework.LayoutManager

Private _ToolbarButtons			As Object		&apos; SF_Dictionary of toolbar buttons

Type _ToolbarButton
	Toolbar						As Object		&apos; The actual SF_Toolbar object instance
	Index						As Long			&apos; Entry number in buttons lists
	Label						As String		&apos; Label (static description)
	AccessibleName				As String		&apos; Name found in accessible context
	Element						As Object		&apos; com.sun.star.ui.XUIElement
End Type

REM ============================================================ MODULE CONSTANTS

&apos;	Toolbar locations
Private Const cstBUILTINTOOLBAR			= 0		&apos; Standard toolbar
Private Const cstCUSTOMTOOLBAR			= 1		&apos; Toolbar added by user and stored in the LibreOffice application
Private Const cstCUSTOMDOCTOOLBAR		= 2		&apos; Toolbar added by user solely for a single document

REM ====================================================== CONSTRUCTOR/DESTRUCTOR

REM -----------------------------------------------------------------------------
Private Sub Class_Initialize()
	Set [Me] = Nothing
	ObjectType = &quot;TOOLBAR&quot;
	ServiceName = &quot;SFWidgets.Toolbar&quot;
	Set _Component = Nothing
	_ResourceURL = &quot;&quot;
	_UIName = &quot;&quot;
	Set _UIConfigurationManager = Nothing
	_ElementsInfoIndex = -1
	_Storage = 0
	Set _LayoutManager = Nothing
	Set _ToolbarButtons = Nothing
End Sub		&apos;	SFWidgets.SF_Toolbar Constructor

REM -----------------------------------------------------------------------------
Private Sub Class_Terminate()
	Call Class_Initialize()
End Sub		&apos;	SFWidgets.SF_Toolbar Destructor

REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
	Call Class_Terminate()
	Set Dispose = Nothing
End Function	&apos;	SFWidgets.SF_Toolbar Explicit Destructor

REM ================================================================== PROPERTIES

REM -----------------------------------------------------------------------------
Property Get BuiltIn() As Boolean
&apos;&apos;&apos;	Returns True when the toolbar is part of the set of standard toolbars shipped with the application.
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myToolbar.BuiltIn

	BuiltIn = _PropertyGet(&quot;BuiltIn&quot;)

End Property	&apos;	SFWidgets.SF_Toolbar.BuiltIn (get)

REM -----------------------------------------------------------------------------
Property Get Docked() As Variant
&apos;&apos;&apos;	Returns True when the toolbar is active in the window and Docked.
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myToolbar.Docked

	Docked = _PropertyGet(&quot;Docked&quot;)

End Property	&apos;	SFWidgets.SF_Toolbar.Docked (get)

REM -----------------------------------------------------------------------------
Property Get HasGlobalScope() As Boolean
&apos;&apos;&apos;	Returns True when the toolbar is available in all documents of the same type
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myToolbar.HasGlobalScope

	HasGlobalScope = _PropertyGet(&quot;HasGlobalScope&quot;)

End Property	&apos;	SFWidgets.SF_Toolbar.HasGlobalScope (get)

REM -----------------------------------------------------------------------------
Property Get Name() As String
&apos;&apos;&apos;	Returns the name of the toolbar
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myToolbar.Name

	Name = _PropertyGet(&quot;Name&quot;)

End Property	&apos;	SFWidgets.SF_Toolbar.Name (get)

REM -----------------------------------------------------------------------------
Property Get ResourceURL() As String
&apos;&apos;&apos;	Returns True when the toolbar is avaialble in all documents of the same type
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myToolbar.ResourceURL

	ResourceURL = _PropertyGet(&quot;ResourceURL&quot;)

End Property	&apos;	SFWidgets.SF_Toolbar.ResourceURL (get)

REM -----------------------------------------------------------------------------
Property Get Visible() As Variant
&apos;&apos;&apos;	Returns True when the toolbar is active in the window and visible.
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myToolbar.Visible

	Visible = _PropertyGet(&quot;Visible&quot;)

End Property	&apos;	SFWidgets.SF_Toolbar.Visible (get)

REM -----------------------------------------------------------------------------
Property Let Visible(ByVal pvVisible As Variant)
&apos;&apos;&apos;	Sets the visible status of the toolbar.
&apos;&apos;&apos;	When the toolbar is not yet active i the window, it is first created.
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		myToolbar.Visible = True

	_PropertySet(&quot;Visible&quot;, pvVisible)

End Property	&apos;	SFWidgets.SF_Toolbar.Visible (let)

REM -----------------------------------------------------------------------------
Property Get XUIElement() As Variant
&apos;&apos;&apos;	Returns the com.sun.star.ui.XUIElement UNO object corresponding with the toolbar
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myToolbar.XUIElement

	XUIElement = _PropertyGet(&quot;XUIElement&quot;)

End Property	&apos;	SFWidgets.SF_Toolbar.XUIElement (get)

REM ===================================================================== METHODS

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;		myToolbar.GetProperty(&quot;Visible&quot;)

Const cstThisSub = &quot;SFWidgets.Toolbar.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_Toolbar.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;ToolbarButtons&quot; _
					)

End Function	&apos;	SFWidgets.SF_Toolbar.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;BuiltIn&quot; _
					, &quot;Docked&quot; _
					, &quot;HasGlobalScope&quot; _
					, &quot;Name&quot; _
					, &quot;ResourceURL&quot; _
					, &quot;Visible&quot; _
					, &quot;XUIElement&quot; _
					)

End Function	&apos;	SFWidgets.SF_Toolbar.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.Toolbar.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_Toolbar.SetProperty

REM -----------------------------------------------------------------------------
Public Function ToolbarButtons(Optional ByVal ButtonName As Variant) As Variant
&apos;&apos;&apos;	Returns either a list of the available toolbar button names in the actual toolbar
&apos;&apos;&apos;	or a ToolbarButton object instance.
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		ButtonName: the usual name of one of the available buttons in the actual toolbar
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		A zero-based array of button names when the argument is absent,
&apos;&apos;&apos;		or a new ToolbarButton object instance.
&apos;&apos;&apos;		An inactive toolbar has no buttons =&gt; the actual method forces the toolbar to be made visible first.

Const cstThisSub = &quot;SFWidgets.Toolbar.ToolbarButtons&quot;
Const cstSubArgs = &quot;[ButtonName=&quot;&quot;&quot;&quot;]&quot;

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch

Check:
	If IsMissing(ButtonName) Or IsEmpty(ButtonName) Then ButtonName = &quot;&quot;
	&apos;	Store button descriptions in cache
	_CollectAllButtons()
	If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
		If VarType(ButtonName) = V_STRING Then
			If Len(ButtonName) &gt; 0 Then
				If Not ScriptForge.SF_Utils._Validate(ButtonName, &quot;ButtonName&quot;, V_STRING, _ToolbarButtons.Keys()) Then GoTo Finally
			End If
		Else
			If Not ScriptForge.SF_Utils._Validate(ButtonName, &quot;ButtonName&quot;, V_STRING) Then GoTo Finally	&apos;	Manage here the VarType error
		End If
	End If

Try:
	If Len(ButtonName) = 0 Then
		ToolbarButtons = _ToolbarButtons.Keys()
	Else
		ToolbarButtons = CreateScriptService(&quot;SFWidgets.ToolbarButton&quot;, _ToolbarButtons.Item(ButtonName))
	End If

Finally:
	ScriptForge.SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	SFWidgets.SF_Toolbar.ToolbarButtons

REM =========================================================== PRIVATE FUNCTIONS

REM -----------------------------------------------------------------------------
Private Sub _CollectAllButtons()
&apos;&apos;&apos;	Stores a SF_Dictionary object instance, with
&apos;&apos;&apos;	- key = name of the button
&apos;&apos;&apos;	- item = a _ButtonDesc object type
&apos;&apos;&apos;	into _ToolbarButtons, a cache for all buttons.
&apos;&apos;&apos;	The toolbar is made visible before collecting the buttons.
&apos;&apos;&apos;
&apos;&apos;&apos;	The name of the buttons is derived either from:
&apos;&apos;&apos;		- the Label property of the static toolbar and toolbar buttons  definitions
&apos;&apos;&apos;		- or the AccessibleName property of the AccessibleContext of the button
&apos;&apos;&apos;	whichever is found first.
&apos;&apos;&apos;	Separators are skipped.
&apos;&apos;&apos;	If there are homonyms (&gt;= 2 buttons having the same name), only the 1st one is retained.

Dim oElement As Object				&apos;	com.sun.star.ui.XUIElement
Dim oSettings As Object				&apos;	com.sun.star.container.XIndexAccess
Dim vProperties() As Variant		&apos;	Array of property alues
Dim iType As Integer				&apos;	Separators have type = 1, others have Type = 0
Dim oAccessible As Object			&apos;	com.sun.star.accessibility.XAccessible
Dim sLabel As String				&apos;	Label in static description
Dim sAccessibleName As String		&apos;	Name in AccessibleContext
Dim sButtonName As String			&apos;	Key part in dictionary entry
Dim oButton As Object				&apos;	Item part in dictionary entry
Dim i As Long

	On Local Error GoTo Catch
	If Not IsNull(_ToolbarButtons) Then GoTo Finally		&apos;	Do not redo the job if already done

Try:
	&apos;	Force the visibility of the toolbar
	Visible = True

	Set _ToolbarButtons = ScriptForge.SF_Services.CreateScriptService(&quot;ScriptForge.Dictionary&quot;)
	Set oElement = _LayoutManager.getElement(_ResourceURL)
	Set oSettings = oElement.getSettings(True)

	With oSettings
		For i = 0 To .Count - 1
			vProperties = .getByIndex(i)
			iType = ScriptForge.SF_Utils._GetPropertyValue(vProperties, &quot;Type&quot;)
			If iType = 0 Then		&apos;	Usual button
				sLabel = ScriptForge.SF_Utils._GetPropertyValue(vProperties, &quot;Label&quot;)
				If Len(sLabel) = 0 Then
					Set oAccessible = oElement.RealInterface.AccessibleContext.getAccessibleChild(i)
					sAccessibleName = oAccessible.AccessibleName
				Else
					sAccessibleName = &quot;&quot;
				End If
				&apos;	Store in dictionary
				sButtonName = sLabel &amp; sAccessibleName		&apos;	At least 1 of them is blank
				If Len(sButtonName) &gt; 0 Then
					Set oButton = New _ToolbarButton
					With oButton
						Set .Toolbar = [Me]
						.Index = i
						.Label = sLabel
						.AccessibleName = sAccessibleName
						Set .Element = oElement
					End With
					With _ToolbarButtons
						If Not .Exists(sButtonName) Then .Add(sButtonName, oButton)
					End With
				End If
			End If
		Next i
	End With

Finally:
	Exit Sub
Catch:
	&apos;	_ToolbarButtons is left unchanged
	GoTo Finally
End Sub			&apos;	SFWidgets.SF_Toolbar._CollectAllButtons

REM -----------------------------------------------------------------------------
Public Sub _Initialize(ByRef poToolbar As Object)
&apos;&apos;&apos;	Complete the object creation process:
&apos;&apos;&apos;		- Initialize the toolbar descriptioner use
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		poToolbar: the toolbar description as a ui._Toolbr object

Try:
	&apos;	Store the static description
	With poToolbar
		_Component = .Component
		_ResourceURL = .ResourceURL
		_UIName = .UIName
		_UIConfigurationManager = .UIConfigurationManager
		_ElementsInfoIndex = .ElementsInfoIndex
		_Storage = .Storage
	End With

	&apos;	Complement
	If Len(_UIName) = 0 Then _UIName = Split(_ResourceURL, &quot;/&quot;)(2)
	Set _LayoutManager = _Component.CurrentController.Frame.LayoutManager

Finally:
	Exit Sub
End Sub			&apos;	SFWidgets.SF_Toolbar._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 oElement As Object						&apos;	com.sun.star.ui.XUIElement
Dim cstThisSub As String
Const cstSubArgs = &quot;&quot;

	cstThisSub = &quot;SFWidgets.Toolbar.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;BuiltIn&quot;)
			_PropertyGet = ( _Storage = cstBUILTINTOOLBAR )
		Case UCase(&quot;Docked&quot;)
			Set oElement = _LayoutManager.getElement(_ResourceURL)
			If Not IsNull(oElement) Then _PropertyGet = _LayoutManager.isElementDocked(_ResourceURL) Else _PropertyGet = False
		Case UCase(&quot;HasGlobalScope&quot;)
			_PropertyGet = ( _Storage = cstBUILTINTOOLBAR Or _Storage = cstCUSTOMTOOLBAR )
		Case UCase(&quot;Name&quot;)
			_PropertyGet = _UIName
		Case UCase(&quot;ResourceURL&quot;)
			_PropertyGet = _ResourceURL
		Case UCase(&quot;Visible&quot;)
			Set oElement = _LayoutManager.getElement(_ResourceURL)
			If Not IsNull(oElement) Then _PropertyGet = _LayoutManager.isElementVisible(_ResourceURL) Else _PropertyGet = False
		Case UCase(&quot;XUIElement&quot;)
			_PropertyGet = _LayoutManager.getElement(_ResourceURL)
		Case Else
			_PropertyGet = Null
	End Select

Finally:
	ScriptForge.SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	SFWidgets.SF_Toolbar._PropertyGet

REM -----------------------------------------------------------------------------
Private Function _PropertySet(Optional ByVal psProperty As String _
								, Optional ByVal pvValue As Variant _
								) As Boolean
&apos;&apos;&apos;	Set the new value of the named property
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		psProperty: the name of the property
&apos;&apos;&apos;		pvValue: the new value of the given property

Dim bSet As Boolean							&apos;	Return value
Dim oElement As Object						&apos;	com.sun.star.ui.XUIElement
Dim bVisible As Boolean						&apos;	Actual Visible state

Dim cstThisSub As String
Const cstSubArgs = &quot;Value&quot;

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	bSet = False

	cstThisSub = &quot;SFWidgets.Toolbar.set&quot; &amp; psProperty
	ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

	bSet = True
	Select Case UCase(psProperty)
		Case UCase(&quot;Visible&quot;)
			If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, ScriptForge.V_BOOLEAN) Then GoTo Catch
			With _LayoutManager
				Set oElement = .getElement(_ResourceURL)
				If Not IsNull(oElement) Then bVisible = .isElementVisible(_ResourceURL) Else bVisible = False
				&apos;	If there is no change, do nothing
				If Not bVisible = pvValue Then
					If IsNull(oElement) And pvValue Then .createElement(_ResourceURL)
					If pvValue Then .showElement(_ResourceURL) Else .hideElement(_ResourceURL)
				End If
			End With
		Case Else
			bSet = False
	End Select

Finally:
	_PropertySet = bSet
	ScriptForge.SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	bSet = False
	GoTo Finally
End Function	&apos;	SFWidgets.SF_Toolbar._PropertySet

REM -----------------------------------------------------------------------------
Private Function _Repr() As String
&apos;&apos;&apos;	Convert the SF_Toolbar instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;	Return:
&apos;&apos;&apos;		&quot;[Toolbar]: Name, Type (dialogname)
	_Repr = &quot;[Toolbar]: &quot; &amp; _UIName &amp; &quot; - &quot; &amp; _ResourceURL

End Function	&apos;	SFWidgets.SF_Toolbar._Repr

REM ============================================ END OF SFWIDGETS.SF_TOOLBAR
</script:module>
\ No newline at end of file
diff --git a/wizards/source/sfwidgets/SF_ToolbarButton.xba b/wizards/source/sfwidgets/SF_ToolbarButton.xba
new file mode 100644
index 0000000..58c594f
--- /dev/null
+++ b/wizards/source/sfwidgets/SF_ToolbarButton.xba
@@ -0,0 +1,565 @@
<?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_ToolbarButton" 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_ToolbarButton
&apos;&apos;&apos;	================
&apos;&apos;&apos;		Hide/show toolbar elements, read and update their current behaviour..
&apos;&apos;&apos;
&apos;&apos;&apos;		A toolbar consists in a series of graphical controls to trigger actions.
&apos;&apos;&apos;		The &quot;Toolbar&quot; service gives access to the &quot;ToolbarButton&quot; service to manage
&apos;&apos;&apos;		the individual buttons belonging to the toolbar.
&apos;&apos;&apos;
&apos;&apos;&apos;		Changes made by scripts to buttons belonging to toolbars stored in the application
&apos;&apos;&apos;		are persistent. They are valid for all documents of the same type.
&apos;&apos;&apos;
&apos;&apos;&apos;		The name of a toolbar button is either:
&apos;&apos;&apos;			- in custom toolbars, a predefined name given at its creation,
&apos;&apos;&apos;			- in standard toolbars, a localized name as read in the Tools + Customize ... dialog box
&apos;&apos;&apos;
&apos;&apos;&apos;		Service invocation:
&apos;&apos;&apos;			It is available only from an active Toolbar service.
&apos;&apos;&apos;			Example:
&apos;&apos;&apos;				Dim oCalc As Object, oToolbar As Object, oToolbarButton As Object
&apos;&apos;&apos;				Set oCalc = CreateScriptService(&quot;Calc&quot;, &quot;myFile.ods&quot;)
&apos;&apos;&apos;				Set oToolbar = oCalc.Toolbars(&quot;findbar&quot;)
&apos;&apos;&apos;				Set oToolbarButton = oToolbar.ToolbarButtons(&quot;Find Next&quot;)

REM ================================================================== EXCEPTIONS

REM ============================================================= PRIVATE MEMBERS

Private [Me]					As Object
Private ObjectType				As String		&apos; Must be TOOLBARBUTTON
Private ServiceName 			As String
Private [_Parent]				As Object		&apos; SF_Toolbar instance owning the button

Private _Index					As Long			&apos; Entry number in buttons lists
Private _Label					As String		&apos; Label (static description)
Private _AccessibleName			As String		&apos; Name found in accessible context
Private _Element				As Object		&apos; com.sun.star.ui.XUIElement

Private _CommandURL				As String		&apos; Uno command or script

Private _Height					As Long			&apos; Height may be cached
Private _Width					As Long			&apos; Width may be cached

REM ============================================================ MODULE CONSTANTS

REM ====================================================== CONSTRUCTOR/DESTRUCTOR

REM -----------------------------------------------------------------------------
Private Sub Class_Initialize()
	Set [Me] = Nothing
	ObjectType = &quot;TOOLBARBUTTON&quot;
	ServiceName = &quot;SFWidgets.ToolbarButton&quot;
	Set [_Parent] = Nothing
	_Index = -1
	_Label = &quot;&quot;
	_AccessibleName = &quot;&quot;
	Set _Element = Nothing
	_CommandURL = &quot;&quot;
	_Height = 0
	_Width = 0
End Sub		&apos;	SFWidgets.SF_ToolbarButton Constructor

REM -----------------------------------------------------------------------------
Private Sub Class_Terminate()
	Call Class_Initialize()
End Sub		&apos;	SFWidgets.SF_ToolbarButton Destructor

REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
	Call Class_Terminate()
	Set Dispose = Nothing
End Function	&apos;	SFWidgets.SF_ToolbarButton Explicit Destructor

REM ================================================================== PROPERTIES

REM -----------------------------------------------------------------------------
Property Get Caption() As String
&apos;&apos;&apos;	Returns the name of the button
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myButton.Caption

	Caption = _PropertyGet(&quot;Caption&quot;)

End Property	&apos;	SFWidgets.SF_ToolbarButton.Caption (get)

REM -----------------------------------------------------------------------------
Property Get Height() As Long
&apos;&apos;&apos;	Returns the height in pixels of the button
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myButton.Height

	Height = _PropertyGet(&quot;Height&quot;)

End Property	&apos;	SFWidgets.SF_ToolbarButton.Height (get)

REM -----------------------------------------------------------------------------
Property Get Index() As Long
&apos;&apos;&apos;	Returns the index of the button
&apos;&apos;&apos;		- in the Settings (com.sun.star.container.XIndexAccess) of the parent toolbar
&apos;&apos;&apos;		- in the AccessibleContext (com.sun.star.comp.toolkit.AccessibleToolBox) of the parent toolbar
&apos;&apos;&apos;	Both should be identical: the range number of the button in the toolbar, hidden buttons and separators included.
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myButton.Index

	Index = _PropertyGet(&quot;Index&quot;)

End Property	&apos;	SFWidgets.SF_ToolbarButton.Index (get)

REM -----------------------------------------------------------------------------
Property Get OnClick() As Variant
&apos;&apos;&apos;	Returns the UNO command or the script (expressed in the scripting framework_URI notation) run when the button is clicked
&apos;&apos;&apos;	Read https://wiki.documentfoundation.org/Documentation/DevGuide/Scripting_Framework#Scripting_Framework_URI_Specification
&apos;&apos;&apos;	Note that no event object is passed to the script.
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myButton.OnClick

	OnClick = _PropertyGet(&quot;OnClick&quot;)

End Property	&apos;	SFWidgets.SF_ToolbarButton.OnClick (get)

REM -----------------------------------------------------------------------------
Property Let OnClick(ByVal pvOnClick As Variant)
&apos;&apos;&apos;	Sets the UNO command or the script (expressed in the scripting framework_URI notation) to trigger when the button is clicked
&apos;&apos;&apos;	It is highly recommended to not modify standard buttons.
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		myButton.OnClick = &quot;.uno:About&quot;
&apos;&apos;&apos;		myButton.OnClick = &quot;vnd.sun.star.script:XrayTool._Main.Xray?language=Basic&amp;location=application&quot;

	_PropertySet(&quot;OnClick&quot;, pvOnClick)

End Property	&apos;	SFWidgets.SF_ToolbarButton.OnClick (let)

REM -----------------------------------------------------------------------------
Property Get Parent() As Object
&apos;&apos;&apos;	Returns the parent toolbar as a SF_Toolbar object instance
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		Set oToolbar = myButton.Parent

	Set Parent = _PropertyGet(&quot;Parent&quot;)

End Property	&apos;	SFWidgets.SF_ToolbarButton.Parent (get)

REM -----------------------------------------------------------------------------
Property Get TipText() As Variant
&apos;&apos;&apos;	Specifies the text that appears in a screentip when you hold the mouse pointer over the button
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myButton.TipText

	TipText = _PropertyGet(&quot;TipText&quot;)

End Property	&apos;	SFWidgets.SF_ToolbarButton.TipText (get)

REM -----------------------------------------------------------------------------
Property Let TipText(ByVal pvTipText As Variant)
&apos;&apos;&apos;	Sets the screentip associated with the actual toolbar button
&apos;&apos;&apos;	It is highly recommended to not modify standard buttons.
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		myButton.TipText = &quot;Click here&quot;

	_PropertySet(&quot;TipText&quot;, pvTipText)

End Property	&apos;	SFWidgets.SF_ToolbarButton.TipText (let)

REM -----------------------------------------------------------------------------
Property Get Visible() As Variant
&apos;&apos;&apos;	Returns True when the toolbar button is visible. Otherwise False.
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myButton.Visible

	Visible = _PropertyGet(&quot;Visible&quot;)

End Property	&apos;	SFWidgets.SF_ToolbarButton.Visible (get)

REM -----------------------------------------------------------------------------
Property Let Visible(ByVal pvVisible As Variant)
&apos;&apos;&apos;	Sets the visible status of the toolbar button.
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		myButton.Visible = True

	_PropertySet(&quot;Visible&quot;, pvVisible)

End Property	&apos;	SFWidgets.SF_ToolbarButton.Visible (let)

REM -----------------------------------------------------------------------------
Property Get Width() As Long
&apos;&apos;&apos;	Returns the width in pixels of the button
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myButton.Width

	Width = _PropertyGet(&quot;Width&quot;)

End Property	&apos;	SFWidgets.SF_ToolbarButton.Width (get)

REM -----------------------------------------------------------------------------
Property Get X() As Long
&apos;&apos;&apos;	Returns the X (horizontal) coordinate in pixels of the top-left corner of the button
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myButton.X

	X = _PropertyGet(&quot;X&quot;)

End Property	&apos;	SFWidgets.SF_ToolbarButton.X (get)

REM -----------------------------------------------------------------------------
Property Get Y() As Long
&apos;&apos;&apos;	Returns the Y (vertical) coordinate in pixels of the top-left corner of the button
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;		MsgBox myButton.Y

	Y = _PropertyGet(&quot;Y&quot;)

End Property	&apos;	SFWidgets.SF_ToolbarButton.Y (get)

REM ===================================================================== METHODS

REM -----------------------------------------------------------------------------
Public Function Execute() As Variant
&apos;&apos;&apos;	Execute the command stored in the toolbar button.
&apos;&apos;&apos;	The command can be a UNO command or a Basic/Python script (expressed in the scripting framework_URI notation)
&apos;&apos;&apos;	Read https://wiki.documentfoundation.org/Documentation/DevGuide/Scripting_Framework#Scripting_Framework_URI_Specification
&apos;&apos;&apos;	No argument is passed to the script to execute.
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The output of the script or Null
&apos;&apos;&apos;	Examples:
&apos;&apos;&apos;		result = myButton.Execute()

Dim vResult As Variant				&apos;	Return value
Dim sCommand As String				&apos;	Command associated with button
Dim oFrame As Object				&apos;	com.sun.star.comp.framework.Frame
Dim oDispatcher As Object			&apos;	com.sun.star.frame.DispatchHelper
Dim vScript As Variant				&apos;	Split command in script/argument
Dim oSession As Object				:	Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;ScriptForge.Session&quot;)
Dim oArgs() As new com.sun.star.beans.PropertyValue
Const cstUnoPrefix					= &quot;.uno:&quot;

Const cstThisSub = &quot;SFWidgets.ToolbarButton.Execute&quot;
Const cstSubArgs = &quot;&quot;

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	vResult = Null

Check:
	ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	sCommand = GetProperty(&quot;OnClick&quot;)
	If Len(sCommand) &gt; 0 Then
		&apos;	A button has been clicked necessarily in the current window (Document) or one of its subcomponents (FormDocument)
		Set oFrame = StarDesktop.ActiveFrame
		If oFrame.Frames.Count &gt; 0 Then Set oFrame = oFrame.getActiveFrame()
		&apos;	Command or script ?
		If ScriptForge.SF_String.StartsWith(sCommand, cstUnoPrefix) Then
			&apos;	Execute uno command
			Set oDispatcher = ScriptForge.SF_Utils._GetUNOService(&quot;DispatchHelper&quot;)
			oDispatcher.executeDispatch(oFrame, sCommand, &quot;&quot;, 0, oArgs())
			oFrame.activate()
		Else
			&apos;	Execute script
			vResult = oSession._ExecuteScript(sCommand)
		End If
	End If

Finally:
	Execute = vResult
	ScriptForge.SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	SFWidgets.SF_ToolbarButton.Execute

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;		myToolbar.GetProperty(&quot;Visible&quot;)

Const cstThisSub = &quot;SFWidgets.ToolbarButton.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_ToolbarButton.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;Execute&quot; _
					)

End Function	&apos;	SFWidgets.SF_ToolbarButton.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;Caption&quot; _
					, &quot;Height&quot; _
					, &quot;Index&quot; _
					, &quot;OnClick&quot; _
					, &quot;Parent&quot; _
					, &quot;TipText&quot; _
					, &quot;Visible&quot; _
					, &quot;Width&quot; _
					, &quot;X&quot; _
					, &quot;Y&quot; _
					)

End Function	&apos;	SFWidgets.SF_ToolbarButton.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.ToolbarButton.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_ToolbarButton.SetProperty

REM =========================================================== PRIVATE FUNCTIONS

REM -----------------------------------------------------------------------------
Private Function _GetPosition() As Object
&apos;&apos;&apos;	Determine the position of the top-left corner of the actual button.
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		a com.sun.star.awt.Rectangle structure

Dim oElement As Object						&apos;	com.sun.star.ui.XUIElement
Dim oAccessible As Object					&apos;	com.sun.star.comp.toolkit.AccessibleToolBoxItem
Dim oAccessibleButton As Object				&apos;	com.sun.star.comp.toolkit.AccessibleToolBoxItem
Dim oAccessibleParent As Object				&apos;	com.sun.star.comp.toolkit.AccessibleToolBoxItem
Dim oRect As Object							&apos;	Return value As com.sun.star.awt.Rectangle

Try:
	Set oElement = _Element.GetSettings(True).getByIndex(_Index)
	Set oRect = CreateUnoStruct(&quot;com.sun.star.awt.Rectangle&quot;)
	If ScriptForge.SF_Utils._GetPropertyValue(oElement, &quot;IsVisible&quot;) Then
		Set oAccessible = _Element.getRealInterface().getAccessibleContext()	&apos;	Toolbar level
		Set oAccessibleParent = oAccessible.getAccessibleParent()				&apos;	Window level
		Set oAccessibleButton = oAccessible.getAccessibleChild(_Index)			&apos;	Toolbar button level
		&apos;	The X and Y coordinates are always computed correctly when the toolbar is docked.
		&apos;	When the toolbar is floating, the Y ordinate may be overestimated with the height of
		&apos;	the tabbed bar or similar. However no mean has been found to get that height via code.
		With oRect
			.X = oAccessible.Location.X + oAccessibleButton.Location.X + oAccessibleParent.PosSize.X
			.Y = oAccessible.Location.Y + oAccessibleButton.Location.Y + oAccessibleParent.PosSize.Y
			.Height = oAccessibleButton.Size.Height
			.Width = oAccessibleButton.Size.Width
		End With
	Else
		With oRect
			.X = -1	:	.Y = -1	:	.Height = 0	:	.Width = 0
		End With
	End If

Finally:
	Set _GetPosition = oRect
	Exit Function
End Function	&apos;	SFWidgets.SF_ToolbarButton._GetPosition

REM -----------------------------------------------------------------------------
Public Sub _Initialize(ByRef poToolbarButton As Object)
&apos;&apos;&apos;	Complete the object creation process:
&apos;&apos;&apos;		- Initialize the toolbar descriptioner use
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		poToolbarButton: the toolbar description as a ui._Toolbr object

Try:
	&apos;	Store the static description
	With poToolbarButton
		Set [_Parent] = .Toolbar
		_Index = .Index
		_Label = .Label
		_AccessibleName = .AccessibleName
		Set _Element = .Element
	End With

	&apos;	Complement
	_CommandURL = ScriptForge.SF_Utils._GetPropertyValue(_Element.getSettings(True).getByIndex(_Index), &quot;CommandURL&quot;)

Finally:
	Exit Sub
End Sub			&apos;	SFWidgets.SF_ToolbarButton._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 sTooltip As String						&apos;	ToolTip text
Dim oElement As Object						&apos;	com.sun.star.ui.XUIElement
Dim cstThisSub As String
Const cstSubArgs = &quot;&quot;

	cstThisSub = &quot;SFWidgets.ToolbarButton.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;Caption&quot;)
			_PropertyGet = Iif(Len(_Label) &gt; 0, _Label, _AccessibleName)
		Case UCase(&quot;Height&quot;)
			If _Height &gt; 0 Then _PropertyGet = _Height else _PropertyGet = _GetPosition().Height
		Case UCase(&quot;Index&quot;)
			_PropertyGet = _Index
		Case UCase(&quot;OnClick&quot;)
			Set oElement = _Element.GetSettings(True).getByIndex(_Index)
			_PropertyGet = ScriptForge.SF_Utils._GetPropertyValue(oElement, &quot;CommandURL&quot;)
		Case UCase(&quot;Parent&quot;)
			Set _PropertyGet = [_Parent]
		Case UCase(&quot;TipText&quot;)
			Set oElement = _Element.GetSettings(True).getByIndex(_Index)
			sTooltip = ScriptForge.SF_Utils._GetPropertyValue(oElement, &quot;Tooltip&quot;)
			If Len(sTooltip) &gt; 0 Then _PropertyGet = sTooltip Else _PropertyGet = Iif(Len(_Label) &gt; 0, _Label, _AccessibleName)
		Case UCase(&quot;Visible&quot;)
			Set oElement = _Element.GetSettings(True).getByIndex(_Index)
			_PropertyGet = ScriptForge.SF_Utils._GetPropertyValue(oElement, &quot;IsVisible&quot;)
		Case UCase(&quot;Width&quot;)
			If _Width &gt; 0 Then _PropertyGet = _Width else _PropertyGet = _GetPosition().Width
		Case UCase(&quot;X&quot;)
			_PropertyGet = _GetPosition().X
		Case UCase(&quot;Y&quot;)
			_PropertyGet = _GetPosition().Y
		Case Else
			_PropertyGet = Null
	End Select

Finally:
	ScriptForge.SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	SFWidgets.SF_ToolbarButton._PropertyGet

REM -----------------------------------------------------------------------------
Private Function _PropertySet(Optional ByVal psProperty As String _
								, Optional ByVal pvValue As Variant _
								) As Boolean
&apos;&apos;&apos;	Set the new value of the named property
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		psProperty: the name of the property
&apos;&apos;&apos;		pvValue: the new value of the given property

Dim bSet As Boolean							&apos;	Return value
Dim oSettings As Object						&apos;	com.sun.star.container.XIndexAccess
Dim vProperties As Variant					&apos;	Array of PropertyValues
Dim bVisible As Boolean						&apos;	Actual Visible state

Dim cstThisSub As String
Const cstSubArgs = &quot;Value&quot;

Check:
	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	bSet = False

	cstThisSub = &quot;SFWidgets.ToolbarButton.set&quot; &amp; psProperty
	ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	bSet = True
	Set oSettings = _Element.getSettings(True)
	vProperties = oSettings.getByIndex(_Index)

	Select Case UCase(psProperty)
		Case UCase(&quot;OnClick&quot;)
			If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, V_STRING) Then GoTo Catch
			ScriptForge.SF_Utils._SetPropertyValue(vProperties, &quot;CommandURL&quot;, pvValue)
		Case UCase(&quot;TipText&quot;)
			If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, V_STRING) Then GoTo Catch
			ScriptForge.SF_Utils._SetPropertyValue(vProperties, &quot;Tooltip&quot;, pvValue)
		Case UCase(&quot;Visible&quot;)
			If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;Value&quot;, ScriptForge.V_BOOLEAN) Then GoTo Catch
			ScriptForge.SF_Utils._SetPropertyValue(vProperties, &quot;IsVisible&quot;, pvValue)
		Case Else
			bSet = False
	End Select

	oSettings.replaceByIndex(_Index, vProperties)
	_Element.setSettings(oSettings)

Finally:
	_PropertySet = bSet
	ScriptForge.SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	bSet = False
	GoTo Finally
End Function	&apos;	SFWidgets.SF_ToolbarButton._PropertySet

REM -----------------------------------------------------------------------------
Private Function _Repr() As String
&apos;&apos;&apos;	Convert the SF_ToolbarButton instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;	Return:
&apos;&apos;&apos;		&quot;[Toolbar]: Name, Type (dialogname)
	_Repr = &quot;[ToolbarButton]: &quot; &amp; Iif(Len(_Label) &gt; 0, _Label, _AccessibleName) &amp; &quot; - &quot; &amp; _CommandURL

End Function	&apos;	SFWidgets.SF_ToolbarButton._Repr

REM ============================================ END OF SFWIDGETS.SF_TOOLBARBUTTON
</script:module>
\ No newline at end of file
diff --git a/wizards/source/sfwidgets/script.xlb b/wizards/source/sfwidgets/script.xlb
index 40e9f4c..06975e6 100644
--- a/wizards/source/sfwidgets/script.xlb
+++ b/wizards/source/sfwidgets/script.xlb
@@ -6,4 +6,6 @@
 <library:element library:name="SF_PopupMenu"/>
 <library:element library:name="SF_Menu"/>
 <library:element library:name="SF_MenuListener"/>
 <library:element library:name="SF_Toolbar"/>
 <library:element library:name="SF_ToolbarButton"/>
</library:library>
\ No newline at end of file
\ No newline at end of file