From e667bcfa1749e6a9179b0900305f3179076dc63c Mon Sep 17 00:00:00 2001 From: Niklas Johansson Date: Tue, 2 Feb 2016 15:06:58 +0100 Subject: Add tool to check for duplicate accelerators The tool mentioned in tdf#94865. It should be possible to use in any installed locale. It uses the accessibility api to read the menus and retrieve the menu items and it's associated accelerator keys. Change-Id: I3abe1bff526db15e40c5cf792588c5eda1fbedad Reviewed-on: https://gerrit.libreoffice.org/22039 Tested-by: Jenkins Reviewed-by: Jan Holesovsky --- officecfg/util/AcceleratorKeyChecker.fodt | 771 ++++++++++++++++++++++++++++++ 1 file changed, 771 insertions(+) create mode 100644 officecfg/util/AcceleratorKeyChecker.fodt (limited to 'officecfg/util') diff --git a/officecfg/util/AcceleratorKeyChecker.fodt b/officecfg/util/AcceleratorKeyChecker.fodt new file mode 100644 index 000000000000..f6aba7ae97ff --- /dev/null +++ b/officecfg/util/AcceleratorKeyChecker.fodt @@ -0,0 +1,771 @@ + + + + 2015-09-24T00:23:17.4500000002016-02-12T08:27:37.426000000PT2H10M43S75LibreOfficeDev/5.2.0.0.alpha0$Windows_x86 LibreOffice_project/f14d271d31e75de09821cf1766c7ab2a9c6e0461 + + + 0 + 0 + 26407 + 15162 + true + false + + + view2 + 11382 + 4362 + 0 + 0 + 26405 + 15161 + 0 + 1 + false + 100 + false + + + + + false + + + Bröllopsgäster + 1 + true + false + false + true + false + true + true + + true + + false + 0 + true + false + false + false + 0 + false + true + false + high-resolution + false + false + false + false + false + true + false + false + false + false + true + false + true + false + + false + false + false + false + true + false + 1854555 + false + false + false + false + false + 3406469 + false + true + false + true + true + true + false + false + false + false + 0 + true + false + false + true + true + true + false + true + false + true + false + false + true + + false + false + + + + + + + + + REM ***** BASIC ***** +Dim ROLEMAP As Object + +Sub Main +' msgbox getNameOfAccessibleRole(40) +' msgbox getNameOfAccessibleRole(57) +End Sub + +Function getNameOfAccessibleRole(sID As Integer) + If IsNull(ROLEMAP) Then + initializeRoleMap + End If + If ROLEMAP.containsKey(sID) Then + getNameOfAccessibleRole = ROLEMAP.get(sID) + Else + MsgBox "Could not find the name for the AccessibleRole: " & sID + End If +End Function + +Sub initializeRoleMap + ROLEMAP = com.sun.star.container.EnumerableMap.create("short", "string") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.UNKNOWN, "UNKNOWN") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.ALERT, "ALERT") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.COLUMN_HEADER, "COLUMN_HEADER") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.CANVAS, "CANVAS") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.CHECK_BOX, "CHECK_BOX") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.CHECK_MENU_ITEM, "CHECK_MENU_ITEM") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.COLOR_CHOOSER, "COLOR_CHOOSER") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.COMBO_BOX, "COMBO_BOX") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.DATE_EDITOR, "DATE_EDITOR") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.DESKTOP_ICON, "DESKTOP_ICON") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.DESKTOP_PANE, "DESKTOP_PANE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.DIRECTORY_PANE, "DIRECTORY_PANE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.DIALOG, "DIALOG") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.DOCUMENT, "DOCUMENT") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.EMBEDDED_OBJECT, "EMBEDDED_OBJECT") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.END_NOTE, "END_NOTE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.FILE_CHOOSER, "FILE_CHOOSER") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.FILLER, "FILLER") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.FONT_CHOOSER, "FONT_CHOOSER") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.FOOTER, "FOOTER") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.FOOTNOTE, "FOOTNOTE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.FRAME, "FRAME") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.GLASS_PANE, "GLASS_PANE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.GRAPHIC, "GRAPHIC") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.GROUP_BOX, "GROUP_BOX") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.HEADER, "HEADER") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.HEADING, "HEADING") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.HYPER_LINK, "HYPER_LINK") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.ICON, "ICON") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.INTERNAL_FRAME, "INTERNAL_FRAME") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.LABEL, "LABEL") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.LAYERED_PANE, "LAYERED_PANE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.LIST, "LIST") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.LIST_ITEM, "LIST_ITEM") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.MENU, "MENU") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.MENU_BAR, "MENU_BAR") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.MENU_ITEM, "MENU_ITEM") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.OPTION_PANE, "OPTION_PANE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.PAGE_TAB, "PAGE_TAB") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.PAGE_TAB_LIST, "PAGE_TAB_LIST") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.PANEL, "PANEL") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.PARAGRAPH, "PARAGRAPH") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.PASSWORD_TEXT, "PASSWORD_TEXT") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.POPUP_MENU, "POPUP_MENU") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.PUSH_BUTTON, "PUSH_BUTTON") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.PROGRESS_BAR, "PROGRESS_BAR") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.RADIO_BUTTON, "RADIO_BUTTON") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.RADIO_MENU_ITEM, "RADIO_MENU_ITEM") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.ROW_HEADER, "ROW_HEADER") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.ROOT_PANE, "ROOT_PANE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.SCROLL_BAR, "SCROLL_BAR") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.SCROLL_PANE, "SCROLL_PANE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.SHAPE, "SHAPE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.SEPARATOR, "SEPARATOR") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.SLIDER, "SLIDER") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.SPIN_BOX, "SPIN_BOX") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.SPLIT_PANE, "SPLIT_PANE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.STATUS_BAR, "STATUS_BAR") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.TABLE, "TABLE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.TABLE_CELL, "TABLE_CELL") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.TEXT, "TEXT") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.TEXT_FRAME, "TEXT_FRAME") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.TOGGLE_BUTTON, "TOGGLE_BUTTON") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.TOOL_BAR, "TOOL_BAR") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.TOOL_TIP, "TOOL_TIP") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.TREE, "TREE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.VIEW_PORT, "VIEW_PORT") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.WINDOW, "WINDOW") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.BUTTON_DROPDOWN, "BUTTON_DROPDOWN") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.BUTTON_MENU, "BUTTON_MENU") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.CAPTION, "CAPTION") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.CHART, "CHART") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.EDIT_BAR, "EDIT_BAR") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.FORM, "FORM") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.IMAGE_MAP, "IMAGE_MAP") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.NOTE, "NOTE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.PAGE, "PAGE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.RULER, "RULER") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.SECTION, "SECTION") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.TREE_ITEM, "TREE_ITEM") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.TREE_TABLE, "TREE_TABLE") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.COMMENT, "COMMENT") + ROLEMAP.put (com.sun.star.accessibility.AccessibleRole.COMMENT_END, "COMMENT_END") +End Sub + + + + + REM ***** BASIC ***** +Option Explicit + +Dim oReportCursor As Object +Dim oReportDoc As Object +Dim oReportTable As Object +Dim oComponentName As String +Dim sMenuName As String +Dim hasSubMenu As String +Dim keybinding1 As Object +Dim keybinding2 As Object +Dim accKeyBinding As String + +Sub testmenus +Dim sAccName As String +Dim i As Integer, j As Integer, iMenuBarIndex As Integer +Dim oAccChild As Object, oAccContext As Object, accMenu As Object +Dim ComponentsToCheck As Variant, oComponent As Object + + GlobalScope.BasicLibraries.LoadLibrary("Tools") + + oReportDoc = CreateNewDocument("swriter") + oReportCursor = oReportDoc.getText().createTextCursor() + + ComponentsToCheck() = Array("Writer", "Calc", "Impress","Draw", "Math") + For Each oComponentName In ComponentsToCheck + oComponent = CreateNewDocument("s" & LCase(oComponentName)) + AccReportHeading(oComponentName, 1) + + oAccContext = getAccessibleContextOfDocument(oComponent) + + For i = 0 To oAccContext.getAccessibleChildCount -1 + oAccChild = oAccContext.getAccessibleChild(i).getAccessibleContext() + sAccName = getNameOfAccessibleRole(oAccChild.AccessibleRole) + If sAccName = "MENU_BAR" Then + iMenuBarIndex = i + AccReportHeading("Top Level Menu") + insertReportTable(Array("Name", "Accelerator key", "Has submenu"), oComponentName & "-Top_Level_Menu") + For j = 0 To oAccChild.getAccessibleChildCount -1 + hasSubMenu = "" + accMenu = oAccChild.getAccessibleChild(j).getAccessibleContext() + sMenuName = accMenu.AccessibleName + keybinding1 = accMenu.getAccessibleActionKeyBinding(0).getAccessibleKeyBinding(0) + If accMenu.getAccessibleActionKeyBinding(0).getAccessibleKeyBindingCount() > 1 Then + keybinding2 = accMenu.getAccessibleActionKeyBinding(0).getAccessibleKeyBinding(1) + End If + accKeyBinding = makeKeyStrokeReadable(keybinding1(0), True) + If accMenu.AccessibleChildCount > 0 Then hasSubMenu = "Yes" + insertReportTableContent(Array(sMenuName, accKeyBinding, hasSubMenu)) + Next + End If + Next + AddMenuTables oAccContext.getAccessibleChild(iMenuBarIndex).getAccessibleContext + + DisposeDocument(oComponent) + Next + CheckTableAndMarkupDuplicates +End Sub + +Sub AddMenuTables(accMenuBar) +Dim i As Integer, accMenu As Object + For i = 0 To accMenuBar.getAccessibleChildCount-1 + accMenu = accMenuBar.getAccessibleChild(i) + sMenuName = accMenu.AccessibleName + AccReportHeading(accMenu.AccessibleName) + insertReportTable(Array("Name", "Accelerator key", "Has submenu"), oComponentName & "-" & sMenuName) + FillMenuTable accMenu, 2 + HandleSubMenues accMenu + Next +End Sub + +Sub HandleSubMenues(accMenu, Optional HeadingLevel as Integer) +Dim i As Integer, accMenuItem As Object, sSubMenuName As String + If isMissing(HeadingLevel) Then HeadingLevel = 3 + For i = 0 To accMenu.getAccessibleChildCount-1 + accMenuItem = accMenu.getAccessibleChild(i) + If getNameOfAccessibleRole(accMenuItem.getAccessibleRole) = "MENU" Then + sSubMenuName = accMenuItem.AccessibleName + AccReportHeading(sSubMenuName, HeadingLevel) + insertReportTable(Array("Name", "Accelerator key", "Has submenu"), oComponentName & "-" & sMenuName & "-" & sSubMenuName) + FillMenuTable accMenuItem + ' Take care of submenues of submenues + ' Example in Writer: Insert - Shape - Line + HandleSubMenues accMenuItem, HeadingLevel + 1 + End If + Next +End Sub + +Sub FillMenuTable(accMenu) +Dim i As Integer, accMenuItem As Object + 'Check if it is a menu, and open it + If getNameOfAccessibleRole(accMenu.getAccessibleRole) = "MENU" Then + accMenu.doAccessibleAction(0) + End If + For i = 0 To accMenu.getAccessibleChildCount-1 + accMenuItem = accMenu.getAccessibleChild(i) + Select Case getNameOfAccessibleRole(accMenuItem.getAccessibleRole) + Case "MENU_ITEM", "CHECK_MENU_ITEM", "RADIO_MENU_ITEM" + hasSubMenu = "" + sMenuName = accMenuItem.AccessibleName + keybinding1 = accMenuItem.getAccessibleActionKeyBinding(0).getAccessibleKeyBinding(0) + accKeyBinding = makeKeyStrokeReadable(keybinding1(0)) + insertReportTableContent(Array(sMenuName, accKeyBinding, hasSubMenu)) + Case "MENU" + hasSubMenu = "Yes" + sMenuName = accMenuItem.AccessibleName + keybinding1 = accMenuItem.getAccessibleActionKeyBinding(0).getAccessibleKeyBinding(0) + accKeyBinding = makeKeyStrokeReadable(keybinding1(0)) + insertReportTableContent(Array(sMenuName, accKeyBinding, hasSubMenu)) + End Select + Next +End Sub + +Function getAccessibleContextOfDocument(oDoc) +Dim oContainerWindow As Object + oContainerWindow = oDoc.getCurrentController().getFrame().getContainerWindow() + getAccessibleContextOfDocument = oContainerWindow.getAccessibleContext() +End Function + +Function makeKeyStrokeReadable(oKeyStroke, Optional bIgnoreAltModifier) +Dim sModifiers As String, sMod As String + If isMissing(bIgnoreAltModifier) Then bIgnoreAltModifier = false + + sModifiers = cStr(oKeyStroke.Modifiers) + Select Case sModifiers + Case "1" + sMod = "Shift + " + Case "2" + sMod = "Ctrl + " + Case "3" + sMod = "Ctrl + Shift + " + Case "4" + If bIgnoreAltModifier Then + sMod = "" + Else + sMod = "Alt + " + End If + Case "5" + sMod = "Shift + Alt + " + Case "6" + sMod = "Ctrl + Alt + " + Case "7" + sMod = "Ctrl + Shift + Alt + " + Case "0" + sMod = "" + Case Else + sMod = "Are you using Mac? Not sure if this is supported on Mac? Your modifier is: " & sModifiers + End Select + makeKeyStrokeReadable = sMod & UCase(oKeyStroke.KeyChar) +End Function + +Sub AccReport(sString) + oReportCursor.setString(sString) + oReportCursor.collapseToEnd() +End Sub + +Sub AccReportHeading(sString as string, Optional HeadingLevel as integer) +If IsMissing(HeadingLevel) Then HeadingLevel = 2 + oReportCursor.collapseToEnd() + oReportCursor.ParaStyleName = "Heading " & HeadingLevel + oReportCursor.setString(sString & chr(13)) + oReportCursor.collapseToEnd() +End Sub + +Sub insertReportTable(sColumns(), sTableName As String) +Dim noColumns As Integer, i As Integer +Dim oCell As Object + noColumns = UBound(sColumns) + oReportTable = oReportDoc.createInstance ("com.sun.star.text.TextTable") + oReportTable.initialize(2, noColumns+1) + oReportTable.HeaderRowCount = 1 + oReportTable.RepeatHeadline = true + sTableName = Replace(sTableName, " ", "_") + sTableName = Replace(sTableName, ".", "") + oReportTable.Name = sTableName + oReportCursor.getText().insertTextContent(oReportCursor, oReportTable, False) + + For i = 0 To noColumns + oCell = oReportTable.getCellByPosition( i, 0 ) + oCell.setString(sColumns(i)) + Next +End Sub + +Sub insertReportTableContent(sColumns()) +Dim noColumns As Integer, iRows As Integer, i As Integer +Dim oCell As Object + noColumns = UBound(sColumns) + iRows = oReportTable.getRows().Count + If iRows = 2 Then + oCell = oReportTable.getCellByPosition(0, iRows-1) + If oCell.getString() <> "" Then + oReportTable.getRows().insertByIndex(iRows,1) + Else + iRows = iRows-1 + End If + Else + oReportTable.getRows().insertByIndex(iRows,1) + End If + + For i = 0 To noColumns + oCell = oReportTable.getCellByPosition( i, iRows ) + oCell.setString(sColumns(i)) + Next +End Sub + +Sub CheckTableAndMarkupDuplicates +Dim iTable As Integer, oTable As Object +Dim i As Integer, j As Integer +Dim sAccKey1 As String, sAccKey2 As String + For iTable = 0 To oReportDoc.TextTables.Count-1 + oTable = oReportDoc.TextTables(iTable) + 'First row is a header so we can start at the second row (1) + For i = 1 To oTable.getRows.Count-1 + For j = i + 1 To oTable.getRows.Count-1 + sAccKey1 = oTable.getCellByPosition(1, i).getString() + sAccKey2 = oTable.getCellByPosition(1, j).getString() + If sAccKey1 = sAccKey2 Then + If oTable.getCellByPosition(2, i).getString() = "Yes" Then + oTable.getRows().getByIndex(i).BackColor = RGB(255, 0, 0) + Else + oTable.getRows().getByIndex(i).BackColor = RGB(255, 255, 0) + End If + If oTable.getCellByPosition(2, j).getString() = "Yes" Then + oTable.getRows().getByIndex(j).BackColor = RGB(255, 0, 0) + Else + oTable.getRows().getByIndex(j).BackColor = RGB(255, 255,0) + End If + End If + Next + Next + Next +End Sub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Accelerator key check + This document contains some code to traverse the menus and generate a reports the contents of the main menu items and it's accelerator keys. If there is a duplicate and the menu item has a sub menu then that means that the user wont be able to reach the second menu item with the same accelerator key. Therefore it will be marked with a red background color. If it has the same key but don't have a sub-menu it is marked with a yellow background, this is still a problem that should be fixed but the problem is just not quite as severe. + + If nothing happens when you press Generate report then the macros have probably been blocked for security reasons. To allow the report tobe generated you need change this setting. To do this: + + + Go to ToolsOptions (or if your'e using Mac LibreOffice → Preferences...) + + + In the tree list to the left of the dialog navigate to LibreOffice → Security + + + Click on the button Macro security... + + + Set the Security Level to Medium + + + Close and reopen this document + + + You will get a warning that the document contains macros, click the button Enable Macros. + + + Of course you need to pay attention when this dialog shows up and don't blindly allow macros to run if you don't know where it comes from and what it does. + + + \ No newline at end of file -- cgit