wizards/source/scriptforge/SF_Platform.xba | 28 +++++++--- wizards/source/scriptforge/script.xlb | 26 ++++----- wizards/source/sfdocuments/SF_Calc.xba | 7 ++ wizards/source/sfdocuments/SF_Writer.xba | 2 wizards/source/sfwidgets/SF_Toolbar.xba | 70 ++++++++++++++++++++++++-- wizards/source/sfwidgets/SF_ToolbarButton.xba | 26 +++++++-- 6 files changed, 126 insertions(+), 33 deletions(-)
New commits: commit 1c81dbad870c2befad699e14e3694d684cf3064d Author: Jean-Pierre Ledure <[email protected]> AuthorDate: Tue Sep 30 16:09:54 2025 +0200 Commit: Xisco Fauli <[email protected]> CommitDate: Wed Oct 1 12:39:44 2025 +0200 ScriptForge fix tdf#168409 AccessibleContext Extract from above bug report: The accessibility UNO API is unpublished and for LibreOffice-internal use only and subject to change by design. The com.sub.star.accessibility.AccessibleContext service is used in ScriptForge to determine the location on the screen, in pixels, of next window subsets: (1) a Calc cell or cellrange => calc.XRectangle(range) property (2) a toolbarbutton in a docked toolbar => toolbar.ToolbarButtons(buttonname) method In both situations, SF offers a facility to display a well-positioned popup menu triggered by a mouse left- or right-click. The situation of the API is as follows: - fully available in 25.2 - partially available in 25.8 (1) is not broken (2) is broken - fully vanished in 26.2 The gradual phase-out of the API requires, to fix the bug, a tiered adaptation of the code. The choice is made to incorporate, where appropriate, a switch to the right code snippet based on the run LibreOffice version: 25.2, 25.8 or 26.2. Now the behaviours in 25.2 and 25.8 are identical. In 26.2, a different location is returned for undocked toolbars. The solution used for 26.2 must be considered as still subject to change. The emergency is to fix the issue in 25.8, which is currently broken. With the actual patch, the compatibility between releases is restored, both in Basic and Pythonuser scripts, and does not need any documentation revision. Change-Id: I29b4ccca3f11eca39e5a1841d3cfd744d5eb1fe3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191670 Tested-by: Jenkins Reviewed-by: Jean-Pierre Ledure <[email protected]> Signed-off-by: Xisco Fauli <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191708 Reviewed-by: Michael Weghorn <[email protected]> diff --git a/wizards/source/scriptforge/SF_Platform.xba b/wizards/source/scriptforge/SF_Platform.xba index c5baf10f6f4c..d0b40c81161c 100644 --- a/wizards/source/scriptforge/SF_Platform.xba +++ b/wizards/source/scriptforge/SF_Platform.xba @@ -347,26 +347,40 @@ Catch: End Function ' ScriptForge.SF_Platform._GetPrinters REM ----------------------------------------------------------------------------- -Public Function _GetProductName() as String -''' Returns Office product and version numbers found in configuration registry +Public Function _GetProductName(Optional ByVal pvNumber As Variant) as Variant +''' Returns Office product and version numbers found in configuration registry as a string, +''' or the version number only, as a Single +''' Args: +''' pvNumber: when True (default = False), returns the version number as a Single. +''' For internal use only. +''' ''' Derived from the Tools library Dim oProdNameAccess as Object ' configmgr.RootAccess Dim sProdName as String Dim sVersion as String +Dim sngVersion As Single +Dim vVersion As Variant ' Array of version subcomponents +Dim sDecimalPoint As String Dim sVendor As String On Local Error GoTo Catch ' Prevent any error + If IsMissing(pvNumber) Or IsEmpty(pvNumber) Then pvNumber = False _GetProductName = "" Try: Set oProdNameAccess = SF_Utils._GetRegistryKeyContent("org.openoffice.Setup/Product") - sProdName = oProdNameAccess.ooName - sVersion = oProdNameAccess.ooSetupVersionAboutBox - sVendor = oProdNameAccess.ooVendor - - _GetProductName = sProdName & " " & sVersion & " (" & sVendor & ")" + If pvNumber Then ' Return the version number + vVersion = Split(oProdNameAccess.ooSetupVersionAboutBox, ".") + sDecimalPoint = Mid(CStr(1.2), 2, 1) + If UBound(vVersion) > 0 Then _GetProductName = CSng(vVersion(0) & sDecimalPoint & vVersion(1)) Else _GetProductName = CSng(0.0) + Else ' Return the verbose version string + sProdName = oProdNameAccess.ooName + sVersion = oProdNameAccess.ooSetupVersionAboutBox + sVendor = oProdNameAccess.ooVendor + _GetProductName = sProdName & " " & sVersion & " (" & sVendor & ")" + End If Finally: Exit Function diff --git a/wizards/source/scriptforge/script.xlb b/wizards/source/scriptforge/script.xlb index af8f6a75dc96..0a510dbc4109 100644 --- a/wizards/source/scriptforge/script.xlb +++ b/wizards/source/scriptforge/script.xlb @@ -2,22 +2,22 @@ <!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd"> <library:library xmlns:library="http://openoffice.org/2000/library" library:name="ScriptForge" library:readonly="false" library:passwordprotected="false"> <library:element library:name="_CodingConventions"/> - <library:element library:name="_ModuleModel"/> - <library:element library:name="SF_String"/> - <library:element library:name="__License"/> - <library:element library:name="SF_Root"/> + <library:element library:name="SF_Session"/> + <library:element library:name="SF_Dictionary"/> + <library:element library:name="SF_Exception"/> + <library:element library:name="SF_UI"/> + <library:element library:name="SF_Services"/> + <library:element library:name="SF_PythonHelper"/> + <library:element library:name="SF_Platform"/> + <library:element library:name="SF_Array"/> <library:element library:name="SF_TextStream"/> <library:element library:name="SF_Utils"/> - <library:element library:name="SF_Platform"/> - <library:element library:name="SF_PythonHelper"/> + <library:element library:name="SF_String"/> + <library:element library:name="_ModuleModel"/> <library:element library:name="SF_L10N"/> <library:element library:name="SF_Region"/> - <library:element library:name="SF_Array"/> - <library:element library:name="SF_UI"/> - <library:element library:name="SF_Services"/> - <library:element library:name="SF_Session"/> - <library:element library:name="SF_Exception"/> - <library:element library:name="SF_Dictionary"/> + <library:element library:name="SF_Root"/> + <library:element library:name="__License"/> <library:element library:name="SF_FileSystem"/> <library:element library:name="SF_Timer"/> -</library:library> \ No newline at end of file +</library:library> diff --git a/wizards/source/sfdocuments/SF_Calc.xba b/wizards/source/sfdocuments/SF_Calc.xba index b627413c8164..69f17353e2ed 100644 --- a/wizards/source/sfdocuments/SF_Calc.xba +++ b/wizards/source/sfdocuments/SF_Calc.xba @@ -5374,7 +5374,12 @@ Try: Set oController = _Component.CurrentController Set oXRange = _ParseAddress(psRange).XCellRange ' Grab the window location on the screen - Set oLocation = oController.ComponentWindow.AccessibleContext.LocationOnScreen + Select Case ScriptForge.SF_Platform._GetProductName(True) ' Get a sortable release number + Case <= 25.8 + Set oLocation = oController.ComponentWindow.AccessibleContext.LocationOnScreen + Case Else + Set oLocation = oController.ComponentWindow.getProperty("XAccessible").LocationOnScreen + End Select With oRect .X = oXRange.Position.X diff --git a/wizards/source/sfdocuments/SF_Writer.xba b/wizards/source/sfdocuments/SF_Writer.xba index 307f9f6682c4..dab61fcfe0d6 100644 --- a/wizards/source/sfdocuments/SF_Writer.xba +++ b/wizards/source/sfdocuments/SF_Writer.xba @@ -1047,7 +1047,7 @@ Dim i As Long End Select ' Body - Case oStr.IsRegex(psTextRange, "\|0\s*?BODY\s*\|?") + Case oStr.IsRegex(psTextRange, "\|?\s*BODY\s*\|?") Set .Text = _Component.Text Set .Anchor = .Text.Start Set .Cursor = .Text.createTextCursor() diff --git a/wizards/source/sfwidgets/SF_Toolbar.xba b/wizards/source/sfwidgets/SF_Toolbar.xba index 1f8329ed1423..6ed2a7fa1ca7 100644 --- a/wizards/source/sfwidgets/SF_Toolbar.xba +++ b/wizards/source/sfwidgets/SF_Toolbar.xba @@ -67,7 +67,7 @@ Private _Component As Object ' com.sun.star.lang.XComponent Private _ResourceURL As String ' Toolbar internal name Private _UIName As String ' Toolbar external name, may be "" Private _UIConfigurationManager As Object ' com.sun.star.ui.XUIConfigurationManager -Private _ElementsInfoIndex As Long ' Index of the toolbar in the getElementsInfo(0) array +Private _ElementsInfoIndex As Long ' Index of the toolbar in the UIConfigurationManager.getElementsInfo(0) array Private _Storage As Long ' One of the toolbar location constants Private _LayoutManager As Object ' com.sun.star.comp.framework.LayoutManager @@ -342,8 +342,8 @@ REM =========================================================== PRIVATE FUNCTION REM ----------------------------------------------------------------------------- Private Sub _CollectAllButtons() ''' Stores a SF_Dictionary object instance, with -''' - key = name of the button -''' - item = a _ButtonDesc object type +''' - key = name of the button +''' - item = a _ButtonDesc object type ''' into _ToolbarButtons, a cache for all buttons. ''' The toolbar is made visible before collecting the buttons. ''' @@ -358,6 +358,7 @@ Dim oElement As Object ' com.sun.star.ui.XUIElement Dim oSettings As Object ' com.sun.star.container.XIndexAccess Dim vProperties() As Variant ' Array of property values Dim iType As Integer ' Separators have type = 1, others have Type = 0 +Dim oAccessibleContext As Object ' Toolbar's com.sun.star.accessibility.XAccessibleContext Dim oAccessible As Object ' com.sun.star.accessibility.XAccessible Dim sLabel As String ' Label in static description Dim sAccessibleName As String ' Name in AccessibleContext @@ -373,7 +374,15 @@ Try: Visible = True Set _ToolbarButtons = ScriptForge.SF_Services.CreateScriptService("ScriptForge.Dictionary", True) ' with case-sensitive comparison of keys + + ' Find the com.sun.star.ui.XUIElement of the toolbar Set oElement = _LayoutManager.getElement(_ResourceURL) + + ' Determine the accessible context of the toolbar + Set oAccessibleContext = _GetAccessibleContext(oElement) + If IsNull(oAccessibleContext) Then GoTo Catch + + ' The settings contain the info that we need Set oSettings = oElement.getSettings(True) With oSettings @@ -383,7 +392,7 @@ Try: If iType = 0 Then ' Usual button sLabel = ScriptForge.SF_Utils._GetPropertyValue(vProperties, "Label") If Len(sLabel) = 0 Then - Set oAccessible = oElement.RealInterface.AccessibleContext.getAccessibleChild(i) + Set oAccessible = oAccessibleContext.getAccessibleChild(i) sAccessibleName = oAccessible.AccessibleName Else sAccessibleName = "" @@ -414,12 +423,63 @@ Catch: GoTo Finally End Sub ' SFWidgets.SF_Toolbar._CollectAllButtons +REM ----------------------------------------------------------------------------- +Public Function _GetAccessibleContext(poElement As Object) As Object +''' Determine the accessible context of the toolbar +''' See bug https://bugs.documentfoundation.org/show_bug.cgi?id=168409 +''' Finding the accessible context is release-dependent due to phase-out of unpublished API +''' Args: +''' poElement: the com.sun.star.ui.XUIElement describing the toolbar + +Dim dVersion As Single ' LibreOffice release number +Dim oElement As Object ' com.sun.star.ui.XUIElement +Dim bFloating As Boolean ' True when poElement is not docked +Dim lIndex As Long ' Index of the toolbar in the LayoutManager.getElements array +Dim oAccessibleContext As Object ' Toolbar's com.sun.star.accessibility.XAccessibleContext + +Check: + On Local Error GoTo Catch + Set oAccessibleContext = Nothing + If IsNull(poElement) Then GoTo Catch + +Try: + dVersion = ScriptForge.SF_Platform._GetProductName(True) ' Get a sortable release number + + With poElement.RealInterface + Select Case dVersion + Case <= 25.2 : Set oAccessibleContext = .AccessibleContext + Case 25.8 + ' Find the com.sun.star.ui.XUIElement of the toolbar and its index in the list + lIndex = -1 + bFloating = poElement.RealInterface.isFloating() + For Each oElement In _LayoutManager.getElements() + ' When undocked, count undocked elements only, otherwise count all elements + If bFloating Then + If oElement.RealInterface.isFloating() Then lIndex = lIndex + 1 + Else + lIndex = lIndex + 1 + End If + If oElement.ResourceURL = _ResourceURL Then Exit For + Next oElement + Set oAccessibleContext = .AccessibleContext.AccessibleParent.AccessibleContext.getAccessibleChild(lIndex) + Case >= 26.2 : Set oAccessibleContext = .getProperty("XAccessible") + Case Else : GoTo Catch + End Select + End With + +Finally: + Set _GetAccessibleContext = oAccessibleContext + Exit Function +Catch: + GoTo Finally +End Function ' ' SFWidgets.SF_Toolbar._GetAccessibleContext + REM ----------------------------------------------------------------------------- Public Sub _Initialize(ByRef poToolbar As Object) ''' Complete the object creation process: ''' - Initialize the toolbar descriptioner use ''' Args: -''' poToolbar: the toolbar description as a ui._Toolbr object +''' poToolbar: the toolbar description as a ui._Toolbar object Try: ' Store the static description diff --git a/wizards/source/sfwidgets/SF_ToolbarButton.xba b/wizards/source/sfwidgets/SF_ToolbarButton.xba index a5c3ccd03064..07ae7eaaa0a1 100644 --- a/wizards/source/sfwidgets/SF_ToolbarButton.xba +++ b/wizards/source/sfwidgets/SF_ToolbarButton.xba @@ -400,19 +400,33 @@ Dim oRect As Object ' Return value As com.sun.star.awt.Rectangle Try: Set oElement = _Element.GetSettings(True).getByIndex(_Index) Set oRect = CreateUnoStruct("com.sun.star.awt.Rectangle") + + ' The button must be visible If ScriptForge.SF_Utils._GetPropertyValue(oElement, "IsVisible") Then - Set oAccessible = _Element.getRealInterface().getAccessibleContext() ' Toolbar level + Set oAccessible = [_Parent]._GetAccessibleContext(_Element) ' Toolbar level Set oAccessibleParent = oAccessible.getAccessibleParent() ' Window level Set oAccessibleButton = oAccessible.getAccessibleChild(_Index) ' Toolbar button level + ' The X and Y coordinates are always computed correctly when the toolbar is docked. ' When the toolbar is floating, the Y ordinate may be overestimated with the height of - ' the tabbed bar or similar. However no mean has been found to get that height via code. + ' the tabbed bar. 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 + ' See bug https://bugs.documentfoundation.org/show_bug.cgi?id=168409 + ' Finding the button coordinates is release-dependent due to phase-out of unpublished API + Select case ScriptForge.SF_Platform._GetProductName(True) ' Get a sortable release number + Case <= 25.8 + .X = oAccessible.Location.X + oAccessibleButton.Location.X + oAccessibleParent.PosSize.X + .Y = oAccessible.Location.Y + oAccessibleButton.Location.Y + oAccessibleParent.PosSize.Y + Case Else ' >= 26.2 + .X = oAccessible.LocationOnScreen.X + oAccessibleButton.Location.X - oAccessibleParent.LocationOnScreen.X + .Y = oAccessible.LocationOnScreen.Y + oAccessibleButton.Location.Y - oAccessibleParent.LocationOnScreen.Y + End Select + If _Height = 0 Then _Height = oAccessibleButton.Size.Height + .Height = _Height + If _Width = 0 Then _Width = oAccessibleButton.Size.Width + .Width = _Width End With + Else With oRect .X = -1 : .Y = -1 : .Height = 0 : .Width = 0
