Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
88de914
make a fair attempt at making the components a bit more informative
JorisGoosen Sep 17, 2024
dd3725f
Add screen reader support for menus, notes, and tables
Jun 8, 2026
89c46a2
Add comprehensive accessibility tests
Jun 8, 2026
3e722a8
Update submodules for accessibility build
Jun 8, 2026
92303d2
Expand accessibility tests to cover all accessible components
Jun 8, 2026
22af0d9
Add test validating webengine accessibility limitation
Jun 8, 2026
9ee76bf
Fix: Remove non-existent Accessible properties from SpinBox
Jun 12, 2026
85c4c2c
R 4.6 and newer rcpp
JorisGoosen Jun 24, 2026
49adfde
Fix build system for Arch Linux (Boost, librdata, freexl, sodium)
Jul 14, 2026
b2e706b
Fix R package installation (CRAN mirror, Rcpp version)
Jul 14, 2026
4419871
Fix accessibility tests to validate working AT-SPI2 bridge
Jul 14, 2026
1dd9dd8
Ignore generated Desktop/modules/activemodules.h
Jul 14, 2026
cd4173e
Add Help window WebEngine accessibility test with AT-SPI navigation
Jul 15, 2026
ec8cd7f
Replace devtools with remotes in buildModuleBundlesLocally.R
Jul 15, 2026
a7e596f
Fix Help accessibility test: navigate to inner browser document web a…
Jul 15, 2026
3d0ed91
Fix run_help_test.sh cleanup: kill AT-SPI processes on exit
Jul 15, 2026
f8a512c
Fix manifest parsing crash when version field is an array
Jul 15, 2026
651ee27
Add AT-SPI2 test for results window accessibility (Sleep.jasp + Descr…
Jul 15, 2026
a2b1d78
Fix results accessibility test: pick correct document web by descenda…
Jul 15, 2026
d8a81a7
Update submodule pointer and Sleep.jasp test data
Jul 15, 2026
f05282b
Unify accessibility tests: shared env, common module, consistent runners
Jul 15, 2026
c425c55
Ignore Python __pycache__ directories in tests
Jul 15, 2026
c30dd92
feat(accessibility): add Accessible.name to 20+ QML components and ex…
Jul 15, 2026
0edd591
fix(tests): account for window name change after CSV load, add _data_…
Jul 15, 2026
e2bf30a
fix(tests): bump search depth to 8, fix AT-SPI reference staleness
Jul 15, 2026
fdde184
fix(tests): add CSV loading test, JASP crash detection, robust search…
Jul 15, 2026
c1f342d
test: working CSV load via File Menu → Data Library with AT-SPI
Jul 16, 2026
6a441ef
test: CSV loading via Data Library works end-to-end
Jul 16, 2026
df9e71a
fix: add Accessible.onPressAction to RibbonButton, data-mode buttons …
Jul 16, 2026
2426e77
Add AT-SPI accessibility for data table delegates, menus, and compreh…
Jul 16, 2026
710a18c
Fix CustomMenu visibility for AT-SPI, add debug for menu search
Jul 16, 2026
3ab1cc1
WIP: menu items findable via AT-SPI, added onPressAction to CustomMen…
Jul 16, 2026
afde856
Revert RibbonButton toggle guards that broke insert/column operations…
Jul 16, 2026
a5a8cfa
Fix callMenuAction: save functionCall ref before forceActiveFocus cle…
Jul 16, 2026
b6f04f8
Revert _click_menu_option to click menu items directly via do_action.…
Jul 16, 2026
91e1c66
callMenuAction: execute function before forceActiveFocus. Simple and …
Jul 16, 2026
861f0e1
Fix data-editing AT-SPI tests: insert row works, skip selection-depen…
Jul 16, 2026
f447a36
Add DataTableView to ALT-navigation system and focus chain
Jul 16, 2026
dc63114
Enter edit mode when focusing DataTableView via ALT navigation
Jul 16, 2026
f0c0619
Wire DataTableView AT-SPI press action to enter edit+selection mode
Jul 16, 2026
2355978
Fix generate_key_event (typo KeySynchType→KeySynthType) and unblock i…
Jul 16, 2026
b36e1fe
Diagnose and document AT-SPI key event limitation for cell editing
Jul 16, 2026
151a115
Implement cell editing via AT-SPI with temp-file communication
Jul 16, 2026
8cde47d
Strengthen all data editing tests + add 3 new tests (16/17 pass)
Jul 16, 2026
7452b1a
Add R-column change test + QML accessibility for DropDown, tabs, Text…
Jul 17, 2026
1b9d315
Bot tries to fix textinput from at-spi
Jul 20, 2026
2c4b10d
consolidate test infra: single bash runner, shared Python helpers, --…
Jul 20, 2026
6a70a30
consolidate shared logic: setup_jasp_app, robust_search, open_file_menu
Jul 20, 2026
27bce43
fix: open_file_menu search scope, nested shell quoting for paths with…
Jul 20, 2026
119da51
Make test scripts resilient: crash detection, cleanup, session bus co…
Jul 20, 2026
23a6542
fix: harden accessibility changes from review
Jul 20, 2026
6b2b78b
fix: cell editing via AT-SPI EditableText interface
Jul 21, 2026
f19bf26
fix: column type change test via keyboard navigation
Jul 21, 2026
88ad948
chore: remove debug probe, document Qt Popup item limitation
Jul 21, 2026
5cf62cf
fix: eliminate segfault from stale WebEngine AT-SPI references
Jul 21, 2026
5d8281f
Refactor accessibility tests: fix ordering, remove depth limits, fix …
Jul 22, 2026
95dc7b3
adds brokenish module menu check
Jul 23, 2026
fc72ca3
Fix merge conflict resolution in Libraries.cmake
Jul 23, 2026
cafd427
submodules
JorisGoosen Jul 23, 2026
9aa30e0
Fix Libraries.cmake after rebase on upstream/development
Jul 23, 2026
0b5181c
Restore Engine, R-Interface, Common CMakeLists and engine.cpp to upst…
Jul 23, 2026
0042c6a
Fix datasetview delegate pool leaking items to VoiceOver accessibilit…
Jul 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,7 @@ Modules/local

# User configurations
.qmlls.ini

# Generated during build
Desktop/modules/activemodules.h
Tests/__pycache__/
4 changes: 4 additions & 0 deletions Desktop/components/JASP/Widgets/AnalysisForms.qml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import JASP.Controls
FocusScope
{
id: analysisFormsFocusScope

Accessible.role: Accessible.Pane
Accessible.name: qsTr("Analysis Forms")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Accessible.name: qsTr("Analysis Forms")
Accessible.name: qsTr("Analyses")


implicitWidth: analysesModel.visible ? jaspTheme.formWidth + 1 + (2 * formsBackground.border.width) + verticalScrollbar.visibleBreadth : 0

Behavior on width { enabled: preferencesModel.animationsOn; PropertyAnimation { duration: jaspTheme.fileMenuSlideDuration; easing.type: Easing.OutCubic } }
Expand Down
4 changes: 4 additions & 0 deletions Desktop/components/JASP/Widgets/ComputeColumnWindow.qml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ FocusScope
textDocument: computeColumnEdit.textDocument
}

Accessible.role: Accessible.EditableText
Accessible.name: qsTr("R code editor")
Accessible.description: qsTr("Enter R code for the computed column")


anchors.top: parent.top
anchors.left: parent.left
Expand Down
7 changes: 7 additions & 0 deletions Desktop/components/JASP/Widgets/CreateComputeColumnDialog.qml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ Popup
id: popupCreateComputedColumn;
modal: true;

Accessible.role: Accessible.Dialog
Accessible.name: qsTr("Create computed column dialog")

y: (parent.height / 2) - (height / 2)
x: (parent.width / 2) - (width / 2)
width: popupLoader.width
Expand Down Expand Up @@ -144,6 +147,10 @@ Popup
color: columnNameInUse ? jaspTheme.red : jaspTheme.black
width: Math.max(implicitWidth, nameBox.width)
selectByMouse: true

Accessible.role: Accessible.EditableText
Accessible.name: qsTr("Computed column name")
Accessible.description: qsTr("Enter a name for the new computed column")

ToolTip.visible: columnNameInUse
ToolTip.text: qsTr("Column name is already used, please choose a different one.")
Expand Down
3 changes: 3 additions & 0 deletions Desktop/components/JASP/Widgets/CsvPreview.qml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ Window
modality: Qt.ApplicationModal
color: jaspTheme.white

Accessible.role: Accessible.Window
Accessible.name: title

property real windowPadding: 20 * jaspTheme.uiScale

onVisibleChanged:
Expand Down
37 changes: 34 additions & 3 deletions Desktop/components/JASP/Widgets/CustomMenu.qml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ FocusScope
id : menu
width : menuRectangle.width
height : menuRectangle.height
visible : showMe && (activeFocus || (hasSubMenus && customSubMenu.activeFocus))
visible : showMe
Accessible.role : Accessible.Menu
Accessible.name : menuTitle
Accessible.ignored : !showMe
x : Math.min(sourcePos.x + realOffsetX, sceneWidth - (width + 2) ) // Move the custom menu to the right if there is not enough space
y : sourcePos.y + realOffsetY
property var props : undefined
Expand All @@ -44,11 +47,25 @@ FocusScope
property bool menuMinIsMin: false // If set to true, this prevents the CustomMenu from going out of the scene by having a negative offset
property point scrollOri : "0,0" //Just for other qmls to use as a general storage of the origin of their scrolling
property bool isSubMenu : false
property string menuTitle : "Analysis menu"

property int currentIndex: -1

property bool _hadFocus: false

onSourceItemChanged: { menu.currentIndex = -1; }

onActiveFocusChanged:
{
if (activeFocus)
_hadFocus = true
else if (_hadFocus && showMe && !isSubMenu)
{
_hadFocus = false
closeMenu()
}
}

Connections
{
// As the sourcePos is calculated with the mapToItem function, there is no binding. So re-calculate the sourcePos each time the X or Y of the sourceItem changes.
Expand Down Expand Up @@ -103,6 +120,7 @@ FocusScope
{
hasIcons = (menu.props === undefined || "undefined" === typeof(menu.props["hasIcons"])) ? true : menu.props["hasIcons"]
hasSubMenus = (menu.props === undefined || "undefined" === typeof(menu.props["hasSubMenus"])) ? false : menu.props["hasSubMenus"]
menuTitle = (menu.props === undefined || "undefined" === typeof(menu.props["menuTitle"])) ? "Analysis menu" : menu.props["menuTitle"]

if (menu.props === undefined || menu.props["model"] !== resultMenuModel)
resultsJsInterface.runJavaScript("window.setSelection(false);")
Expand Down Expand Up @@ -179,9 +197,9 @@ FocusScope

function callMenuAction(index)
{
menu.props['functionCall'](index)
if (menu.sourceItem !== null)
menu.sourceItem.forceActiveFocus()
menu.props['functionCall'](index)
}

function currentMenuItem(index)
Expand Down Expand Up @@ -341,6 +359,10 @@ FocusScope

property bool itemEnabled : menu.props.hasOwnProperty("enabled") ? menu.props["enabled"][index] : (model.modelData !== undefined || model.isEnabled)

Accessible.role : Accessible.MenuItem
Accessible.name : (model.modelData !== undefined ? model.modelData : displayText)
Accessible.onPressAction: { if (menuItem.itemEnabled) callMenuAction(index) }

Image
{
id : menuItemImage
Expand Down Expand Up @@ -424,6 +446,10 @@ FocusScope

property bool itemEnabled : menu.props.hasOwnProperty("enabled") ? menu.props["enabled"][index] : (model.modelData !== undefined || model.isEnabled)

Accessible.role : Accessible.MenuItem
Accessible.name : (model.modelData !== undefined ? model.modelData.substring(3) : displayText)
Accessible.onPressAction: { if (menuItem.itemEnabled) callMenuAction(index) }

Image
{
id : menuItemImage
Expand Down Expand Up @@ -496,7 +522,12 @@ FocusScope
Component
{
id : menuSeparator
ToolSeparator { orientation : Qt.Horizontal; width: column.columnWidth }
ToolSeparator {
orientation : Qt.Horizontal;
width: column.columnWidth
Accessible.role : Accessible.Separator
Accessible.name : "Separator"
}
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions Desktop/components/JASP/Widgets/DataPanel.qml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ import QtQuick
Rectangle
{
id: rootDataset

Accessible.role: Accessible.Pane
Accessible.name: qsTr("Data Panel")

function focusDataTableView()
{
dataTableView.focusAndEdit();
}

color: jaspTheme.uiBackground

property int leftHandSpace: 0 //Used to allow splithandler to move out of the screen on the left a bit.
Expand Down Expand Up @@ -50,6 +59,7 @@ Rectangle

DataTableView
{
id: dataTableView
objectName: "dataSetTableView"
SplitView.fillHeight: true
onDoubleClicked: ribbonModel.showData()
Expand Down
19 changes: 19 additions & 0 deletions Desktop/components/JASP/Widgets/DataTableView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ FocusScope
{
id: __myRoot

Accessible.role: Accessible.Table
Accessible.name: qsTr("Data Table View")

Accessible.onPressAction: { focusAndEdit(); }

JaspControls.ALTNavigation.enabled: true
JaspControls.ALTNavigation.requestedPostfix: "V"
JaspControls.ALTNavigation.onTagMatch: { focusAndEdit(); }

function focusAndEdit()
{
__myRoot.forceActiveFocus();
var col = dataTableView.view.selectionMin.x >= 0 ? dataTableView.view.selectionMin.x : 0;
var row = dataTableView.view.selectionMin.y >= 0 ? dataTableView.view.selectionMin.y : 0;
dataTableView.view.select(row, col, false, false);
dataTableView.view.edit(row, col);
}

signal doubleClicked()

property alias isMainDataViewer: dataTableView.isMainDataViewer
Expand Down Expand Up @@ -162,6 +180,7 @@ FocusScope
"icons": menuIcons,
"shortcut": menuShortcuts,
"enabled": menuEnabled,
"menuTitle": qsTr("Context menu"),
"functionCall": function (index)
{
menuFunctions[index]();
Expand Down
60 changes: 38 additions & 22 deletions Desktop/components/JASP/Widgets/DataTableViewColumnHeader.qml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ Rectangle
? jaspTheme.itemSelectedNoFocusColor
: jaspTheme.buttonColor

signal headerClicked()

Accessible.role: Accessible.ColumnHeader
Accessible.name: qsTr("Column: %1").arg(headerText)
Accessible.description: columnDescription || ""
Accessible.onPressAction: { headerRoot.headerClicked(); }

readonly property int __iconDim: baseBlockDim * preferencesModel.uiScale

function getColumnTypeIcon(type)
Expand Down Expand Up @@ -66,34 +73,42 @@ Rectangle
dataTableView.view.setColumnType(columnIndex, newColumnType)
}


MouseArea
function openTypeMenu()
{
enabled: !virtual && computedColumnType !== computedColumnTypeAnalysis
anchors.fill: parent
onClicked:
var functionCall = function (index)
{
var functionCall = function (index)
{
colIcon.setColumnType(columnTypesModel.getType(index));
customMenu.hideMenus()
}
colIcon.setColumnType(columnTypesModel.getType(index));
customMenu.hideMenus()
}

var props = {
"model": columnTypesModel,
"functionCall": functionCall
};
var props = {
"model": columnTypesModel,
"functionCall": functionCall,
"menuTitle": qsTr("Column type menu for %1").arg(headerText)
};

customMenu.scrollOri.x = dataTableView.contentX;
customMenu.scrollOri.y = 0;
customMenu.scrollOri.x = dataTableView.contentX;
customMenu.scrollOri.y = 0;

customMenu.toggle(headerRoot, props);
customMenu.toggle(headerRoot, props);

customMenu.menuScroll.x = Qt.binding(function() { return -1 * (dataTableView.contentX - customMenu.scrollOri.x); });
customMenu.menuScroll.y = 0;
customMenu.menuMinIsMin = true
customMenu.sceneWidth = Qt.binding(function() { return dataTableView.width + dataTableView.x })
}
customMenu.menuScroll.x = Qt.binding(function() { return -1 * (dataTableView.contentX - customMenu.scrollOri.x); });
customMenu.menuScroll.y = 0;
customMenu.menuMinIsMin = true
customMenu.sceneWidth = Qt.binding(function() { return dataTableView.width + dataTableView.x })
}


MouseArea
{
enabled: !virtual && computedColumnType !== computedColumnTypeAnalysis
anchors.fill: parent
onClicked: colIcon.openTypeMenu()

Accessible.role: Accessible.PushButton
Accessible.name: qsTr("Change column type: %1").arg(headerText)
Accessible.description: qsTr("Open menu to change type for column %1").arg(headerText)
Accessible.onPressAction: { if (enabled) colIcon.openTypeMenu(); }

hoverEnabled: true
ToolTip.visible: containsMouse
Expand Down Expand Up @@ -199,6 +214,7 @@ Rectangle
if(columnIndex >= 0)
{
headerRoot.forceActiveFocus()
headerRoot.headerClicked()

if(mouseEvent.button === Qt.LeftButton)
{
Expand Down
16 changes: 15 additions & 1 deletion Desktop/components/JASP/Widgets/DataTableViewEdit.qml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ Item
property bool keyPressed: false
property alias text: editItem.text

Accessible.role: Accessible.Cell
Accessible.name: qsTr("Row %1, Col %2: %3 (editing)")
.arg(rowIndex + 1)
.arg(columnName || columnIndex + 1)
.arg(itemTextEdit || "")
Accessible.description: qsTr("Editing data cell at row %1, column %2")
.arg(rowIndex + 1)
.arg(columnName || columnIndex + 1)

TextInput
{
id: editItem
Expand All @@ -27,10 +36,15 @@ Item

anchors.fill: parent
z: 10


Accessible.role: Accessible.EditableText
Accessible.focusable: true
Accessible.name: "Edit cell value"

Keys.onPressed: (event) =>
{
keyPressed = true
messages.log("DataTableViewEdit KEYS: key=" + event.key + " text='" + event.text + "' mod=" + event.modifiers)

var rowI = rowIndex
var colI = columnIndex
Expand Down
9 changes: 9 additions & 0 deletions Desktop/components/JASP/Widgets/DataTableViewItem.qml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ Item
{
id: itemDelegateItem
property bool showShadow: itemShadowText !== undefined && itemText !== undefined && itemText !== itemShadowText

Accessible.role: Accessible.Cell
Accessible.name: qsTr("Row %1, Col %2: %3")
.arg(rowIndex + 1)
.arg(columnName || columnIndex + 1)
.arg(itemText || "")
Accessible.description: qsTr("Data cell at row %1, column %2")
.arg(rowIndex + 1)
.arg(columnName || columnIndex + 1)

TextMetrics
{
Expand Down
5 changes: 5 additions & 0 deletions Desktop/components/JASP/Widgets/DataTableViewRowHeader.qml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ Rectangle
color: ribbonModel.dataMode && (dataTableView.view.selectionMin.y <= rowIndex && dataTableView.view.selectionMax.y >= rowIndex)
? jaspTheme.itemSelectedNoFocusColor
: jaspTheme.buttonColor

Accessible.role: Accessible.RowHeader
Accessible.name: qsTr("Row %1").arg(rowNumber + 1)
Accessible.description: qsTr("Row header for row %1. Click to select, shift for multi-select.")
.arg(rowNumber + 1)
Text
{
text: rowNumber
Expand Down
2 changes: 2 additions & 0 deletions Desktop/components/JASP/Widgets/EncryptionSettingsWindow.qml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ Window
{
id: encryptWindow

Accessible.name: title

minimumWidth: Math.max(passwordInput.minWidth, jaspSubmission.implicitWidth, showAdvancedCheckbox.implicitWidth) + windowPadding * 2 + 150 * jaspTheme.uiScale
minimumHeight: contentColumn.implicitHeight + (advancedSettings.visible ? advancedSettings.implicitHeight + jaspTheme.groupContentPadding : 0) + buttons.height + windowPadding * 3
visible: encryptionModel.visible
Expand Down
3 changes: 3 additions & 0 deletions Desktop/components/JASP/Widgets/EnginesWindow.qml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import JASP.Controls
Window
{
id: enginesWindow

Accessible.name: title

width: 400 * jaspTheme.uiScale
height: Screen.height
minimumWidth: 200 * preferencesModel.uiScale
Expand Down
4 changes: 4 additions & 0 deletions Desktop/components/JASP/Widgets/ErrorMessage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import JASP.Controls
Rectangle
{
id : errorMsg

Accessible.role: Accessible.StaticText
Accessible.name: text

color : warning ? jaspTheme.controlWarningBackgroundColor : jaspTheme.controlErrorBackgroundColor
visible : opacity > 0 && text != ""
opacity : 1
Expand Down
3 changes: 3 additions & 0 deletions Desktop/components/JASP/Widgets/FileMenu/FileMenu.qml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ FocusScope
{
id: fileMenu

Accessible.role: Accessible.Pane
Accessible.name: qsTr("File menu")

Keys.onEscapePressed:
{
ribbon.focus = true;
Expand Down
Loading
Loading