@@ -74,22 +74,22 @@ static QString mapVersionStr ( const QString& versionStr )
7474// Subclass of QTreeWidgetItem that allows LVC_VERSION to sort by the UserRole data value
7575CMappedTreeWidgetItem::CMappedTreeWidgetItem ( QTreeWidget* owner ) : QTreeWidgetItem ( owner ), owner ( owner ) {}
7676
77- bool CMappedTreeWidgetItem::operator <( const QTreeWidgetItem& other ) const
77+ bool CMappedTreeWidgetItem::operator < ( const QTreeWidgetItem& other ) const
7878{
7979 if ( !owner )
80- return QTreeWidgetItem::operator <( other );
80+ return QTreeWidgetItem::operator < ( other );
8181
8282 int column = owner->sortColumn ();
8383
8484 // we only need this override for comparing server versions
8585 if ( column != CConnectDlg::LVC_VERSION )
86- return QTreeWidgetItem::operator <( other );
86+ return QTreeWidgetItem::operator < ( other );
8787
8888 QVariant lhs = data ( column, Qt::UserRole );
8989 QVariant rhs = other.data ( column, Qt::UserRole );
9090
9191 if ( !lhs.isValid () || !rhs.isValid () )
92- return QTreeWidgetItem::operator <( other );
92+ return QTreeWidgetItem::operator < ( other );
9393
9494 return lhs.toString () < rhs.toString ();
9595}
@@ -243,6 +243,9 @@ CConnectDlg::CConnectDlg ( CClientSettings* pNSetP, const bool bNewShowCompleteR
243243 // to get default return key behaviour working
244244 QObject::connect ( lvwServers, &QTreeWidget::activated, this , &CConnectDlg::OnConnectClicked );
245245
246+ // connect selection change for accessibility support
247+ QObject::connect ( lvwServers, &QTreeWidget::itemSelectionChanged, this , &CConnectDlg::OnServerListItemSelectionChanged );
248+
246249 // line edit
247250 QObject::connect ( edtFilter, &QLineEdit::textEdited, this , &CConnectDlg::OnFilterTextEdited );
248251
@@ -631,6 +634,75 @@ void CConnectDlg::OnServerAddrEditTextChanged ( const QString& )
631634 lvwServers->clearSelection ();
632635}
633636
637+ QString CConnectDlg::BuildAccessibleTextForItem ( const QTreeWidgetItem* pItem ) const
638+ {
639+ // Return early if item is null to avoid crashes
640+ if ( !pItem )
641+ {
642+ return QString ();
643+ }
644+
645+ // Check if this is a child item (musician) or parent item (server).
646+ // Child items have a parent and represent individual musicians connected to a server.
647+ // Parent items represent servers and contain multiple columns with server information.
648+ if ( pItem->parent () != nullptr )
649+ {
650+ // This is a musician/child item - announce the musician name
651+ return tr ( " Musician: %1" ).arg ( pItem->text ( LVC_NAME ) );
652+ }
653+
654+ // This is a server item - build accessible text with all available information.
655+ // Start with the server name, then append other columns that have data.
656+ QString accessibleText = tr ( " Server: %1" ).arg ( pItem->text ( LVC_NAME ) );
657+
658+ // Helper lambda to append column data if it exists
659+ auto appendColumnIfNotEmpty = [&] ( int column, const QString& label ) {
660+ QString value = pItem->text ( column );
661+ if ( !value.isEmpty () )
662+ {
663+ accessibleText += tr ( " , %1: %2" ).arg ( label ).arg ( value );
664+ }
665+ };
666+
667+ // Append all server information columns in the order they appear in the UI
668+ appendColumnIfNotEmpty ( LVC_PING , tr ( " Ping" ) );
669+ appendColumnIfNotEmpty ( LVC_CLIENTS , tr ( " Musicians" ) );
670+ appendColumnIfNotEmpty ( LVC_LOCATION , tr ( " Location" ) );
671+ appendColumnIfNotEmpty ( LVC_VERSION , tr ( " Version" ) );
672+
673+ return accessibleText;
674+ }
675+
676+ void CConnectDlg::UpdateAccessibilityForItem ( QTreeWidgetItem* pItem )
677+ {
678+ // Update the accessible description and notify the accessibility system
679+ // when items are selected. This improves screen reader support on all platforms,
680+ // including VoiceOver on macOS, NVDA/JAWS on Windows, and Orca on Linux.
681+ if ( !pItem )
682+ {
683+ return ;
684+ }
685+
686+ QString accessibleText = BuildAccessibleTextForItem ( pItem );
687+ lvwServers->setAccessibleDescription ( accessibleText );
688+ QAccessible::updateAccessibility ( new QAccessibleValueChangeEvent ( lvwServers, accessibleText ) );
689+ }
690+
691+ void CConnectDlg::OnServerListItemSelectionChanged ()
692+ {
693+ QList<QTreeWidgetItem*> selectedItems = lvwServers->selectedItems ();
694+
695+ if ( !selectedItems.isEmpty () )
696+ {
697+ UpdateAccessibilityForItem ( selectedItems.first () );
698+ }
699+ else
700+ {
701+ // Clear accessible description when nothing is selected
702+ lvwServers->setAccessibleDescription ( tr ( " Server list" ) );
703+ }
704+ }
705+
634706void CConnectDlg::OnCustomDirectoriesChanged ()
635707{
636708
0 commit comments