Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
44 changes: 44 additions & 0 deletions application/accessible.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,25 @@
#include <QAccessibleWidget>
#include <QMap>
#include <QObject>
#include <QMetaEnum>

Check warning on line 40 in application/accessible.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QMetaEnum> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QWidget>

Check warning on line 41 in application/accessible.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QWidget> not found. Please note: Cppcheck does not need standard library headers to get proper results.

// Include custom widget headers for accessible factory
#include "loglistview.h"
#include "logtreeview.h"
#include "filtercontent.h"
#include "displaycontent.h"
#include "logperiodbutton.h"
#include "lognormalbutton.h"
#include "logiconbutton.h"
#include "logcombox.h"
#include "logspinnerwidget.h"
#include "logdetailinfowidget.h"
#include "logdetailedit.h"
#include "exportprogressdlg.h"
#include "logcollectormain.h"
#include "logviewheaderview.h"

inline constexpr char kSeparator[] { "_" };

inline QString getObjPrefix(QAccessible::Role r)
Expand Down Expand Up @@ -257,11 +273,39 @@

/********************** 添加accessible ***********************/
SET_FORM_ACCESSIBLE(QWidget,m_w->objectName())
SET_FORM_ACCESSIBLE(LogListView,"LogListView")
SET_FORM_ACCESSIBLE(LogTreeView,"LogTreeView")
SET_FORM_ACCESSIBLE(FilterContent,"FilterContent")
SET_FORM_ACCESSIBLE(DisplayContent,"DisplayContent")
SET_BUTTON_ACCESSIBLE(LogPeriodButton,"LogPeriodButton")
SET_BUTTON_ACCESSIBLE(LogNormalButton,"LogNormalButton")
SET_BUTTON_ACCESSIBLE(LogIconButton,"LogIconButton")
SET_FORM_ACCESSIBLE(LogCombox,"LogCombox")
SET_FORM_ACCESSIBLE(LogSpinnerWidget,"LogSpinnerWidget")
SET_FORM_ACCESSIBLE(logDetailInfoWidget,"logDetailInfoWidget")
SET_FORM_ACCESSIBLE(logDetailEdit,"logDetailEdit")
SET_FORM_ACCESSIBLE(ExportProgressDlg,"ExportProgressDlg")
SET_FORM_ACCESSIBLE(LogCollectorMain,"LogCollectorMain")
SET_FORM_ACCESSIBLE(LogViewHeaderView,"LogViewHeaderView")

QAccessibleInterface *accessibleFactory(const QString &classname, QObject *object)
{
QAccessibleInterface *interface = nullptr;
USE_ACCESSIBLE(classname, QWidget);
USE_ACCESSIBLE(classname, LogListView);
USE_ACCESSIBLE(classname, LogTreeView);
USE_ACCESSIBLE(classname, FilterContent);
USE_ACCESSIBLE(classname, DisplayContent);
USE_ACCESSIBLE(classname, LogPeriodButton);
USE_ACCESSIBLE(classname, LogNormalButton);
USE_ACCESSIBLE(classname, LogIconButton);
USE_ACCESSIBLE(classname, LogCombox);
USE_ACCESSIBLE(classname, LogSpinnerWidget);
USE_ACCESSIBLE(classname, logDetailInfoWidget);
USE_ACCESSIBLE(classname, logDetailEdit);
USE_ACCESSIBLE(classname, ExportProgressDlg);
USE_ACCESSIBLE(classname, LogCollectorMain);
USE_ACCESSIBLE(classname, LogViewHeaderView);

return interface;
}
Expand Down
5 changes: 5 additions & 0 deletions application/displaycontent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,12 @@ void DisplayContent::initUI()
// set table for display log data
initTableView();
m_treeView->setMinimumHeight(100);
m_treeView->setAccessibleName("logTreeView");
m_treeView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);

//noResultLabel
noResultLabel = new DLabel(this);
noResultLabel->setAccessibleName("noResultLabel");
DPalette pa = DPaletteHelper::instance()->palette(noResultLabel);
pa.setBrush(DPalette::WindowText, pa.color(DPalette::TextTips));
noResultLabel->setPalette(pa);
Expand All @@ -120,6 +122,7 @@ void DisplayContent::initUI()

//notAuditLabel
notAuditLabel = new DLabel(this);
notAuditLabel->setAccessibleName("notAuditLabel");
DPalette auditPa = DPaletteHelper::instance()->palette(notAuditLabel);
auditPa.setBrush(DPalette::WindowText, auditPa.color(DPalette::TextTips));
noResultLabel->setPalette(auditPa);
Expand All @@ -128,12 +131,14 @@ void DisplayContent::initUI()
notAuditLabel->setAlignment(Qt::AlignCenter);

noCoredumpctlLabel = new DLabel(this);
noCoredumpctlLabel->setAccessibleName("noCoredumpctlLabel");
noCoredumpctlLabel->setPalette(pa);
noCoredumpctlLabel->setText(DApplication::translate("Waring", "Unable to obtain crash information, please install systemd-coredump."));
DFontSizeManager::instance()->bind(noCoredumpctlLabel, DFontSizeManager::T4);
noCoredumpctlLabel->setAlignment(Qt::AlignCenter);

noPermissionLabel = new DLabel(this);
noPermissionLabel->setAccessibleName("noPermissionLabel");
noPermissionLabel->setPalette(pa);
noPermissionLabel->setText(DApplication::translate("Warning", "You do not have permission to view it"));
DFontSizeManager::instance()->bind(noPermissionLabel, DFontSizeManager::T4);
Expand Down
3 changes: 3 additions & 0 deletions application/logcollectormain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,16 @@ void LogCollectorMain::initUI()
m_logCatelogue = new LogListView(this);
m_logCatelogue->setMaximumWidth(LEFT_LIST_WIDTH);
m_logCatelogue->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_logCatelogue->setObjectName("logTypeSelectList");
m_logCatelogue->setAccessibleName("left_side_bar");

m_hSplitter->addWidget(m_logCatelogue);
m_hSplitter->setStretchFactor(0, 1);

m_vLayout = new QVBoxLayout;
/** topRight frame */
m_topRightWgt = new FilterContent();
m_topRightWgt->setAccessibleName("filterWidget");
// m_topRightWgt->setMinimumWidth(8000);
// m_topRightWgt->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
m_vLayout->addWidget(m_topRightWgt);
Expand Down
88 changes: 88 additions & 0 deletions tests/at/at-spi-implementation-checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# deepin-log-viewer AT-SPI Implementation Checklist

## Pre-Implementation Coverage Baseline

**Scan Method**: Manual static analysis of source code (libclang AST scan unavailable due to build dependency issues; alternative local source analysis performed with annotations where limitations exist).

**Limitation Note**: Full libclang scan not possible due to missing build dependencies (Qt6Core5Compat, polkit-qt6 dev headers, gio-qt6). Analysis was performed via manual source examination of all header files and key cpp files.

### Pre-Status Summary
- Custom widget classes: 15
- Widget classes with AT-SPI registration: 1 (QWidget only)
- Widget classes with setAccessibleName() instances: ~10
- **Estimated coverage**: ~30% (only QWidget fallback was registered)

## Changes Applied

### 1. AT-SPI Factory Registration (accessible.h)
**File**: `application/accessible.h`

**What changed**: Added 14 new class-level AT-SPI registrations for all custom widget types used in the application.

**Details**:
- Added includes for all custom widget headers
- Registered the following widget types with SET_FORM_ACCESSIBLE:
- `LogListView` - "LogListView" form
- `LogTreeView` - "LogTreeView" form
- `FilterContent` - "FilterContent" form
- `DisplayContent` - "DisplayContent" form
- `LogPeriodButton` - "LogPeriodButton" button (with press action)
- `LogNormalButton` - "LogNormalButton" button (with press action)
- `LogIconButton` - "LogIconButton" button (with press action)
- `LogCombox` - "LogCombox" form
- `LogSpinnerWidget` - "LogSpinnerWidget" form
- `logDetailInfoWidget` - "logDetailInfoWidget" form
- `logDetailEdit` - "logDetailEdit" form
- `ExportProgressDlg` - "ExportProgressDlg" form
- `LogCollectorMain` - "LogCollectorMain" form
- `LogViewHeaderView` - "LogViewHeaderView" form
- Updated accessibleFactory to match all new types

**Reason**: These widget types had no AT-SPI registration at all. Without registration, accessibility tools cannot identify these custom widgets.

### 2. LogTreeView Accessible Name (displaycontent.cpp)
**File**: `application/displaycontent.cpp`

**What changed**: Added `setAccessibleName("logTreeView")` to the LogTreeView instance created in `initUI()`.

**Details**:
- Line: After `initTableView()`
- Reason: The main log data table needs a recognizable accessible name

### 3. Status Labels Accessible Names (displaycontent.cpp)
**File**: `application/displaycontent.cpp`

**What changed**: Added accessible names to 4 status labels used for displaying empty/no-data states.

**Details**:
- `noResultLabel` → "noResultLabel"
- `notAuditLabel` → "notAuditLabel"
- `noCoredumpctlLabel` → "noCoredumpctlLabel"
- `noPermissionLabel` → "noPermissionLabel"

### 4. Splitter Path Widgets (logcollectormain.cpp)
**File**: `application/logcollectormain.cpp`

**What changed**: Added setObjectName and setAccessibleName to widgets in the SPLITTER_TYPE code path.

**Details**:
- `m_logCatelogue` → objectName: "logTypeSelectList", accessibleName: "left_side_bar"
- `m_topRightWgt` → accessibleName: "filterWidget"

## Post-Implementation Coverage Estimate

### Post-Status Summary
- Custom widget classes: 15
- Widget classes with AT-SPI registration: 15 (100%)
- Widget classes with explicit setAccessibleName(): ~12
- **Estimated coverage**: 85-90%

## Verification Assertions (for AT Test Framework)
1. The main window's accessible name should be "LogCollectorMain" (SET_FORM_ACCESSIBLE fallback)
2. The sidebar list can be located by accessibleName "left_side_bar"
3. The filter area can be located by accessibleName "filterWidget"
4. The data table can be located by accessibleName "logTreeView"
5. The detail widget can be located by accessibleName "detailInfoWidget"
6. Export button is named "Export All" (DIconButton)
7. Refresh button is named "Refresh Now" (DIconButton)
8. All custom buttons (LogPeriodButton, LogNormalButton, LogIconButton) are identifiable by their class fallback names
39 changes: 39 additions & 0 deletions tests/at/expected-at-spi-elements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# deepin-log-viewer Expected AT-SPI Elements

## Expected AT-SPI Element List

| # | AccessibleName | Role | Derivation Chain | Location |
|---|---------------|------|------------------|----------|
| 1 | left_side_bar | Form | setAccessibleName() | `logcollectormain.cpp:161` (non-splitter path), `logcollectormain.cpp:120` (splitter path) |
| 2 | filterWidget | Form | setAccessibleName() | `logcollectormain.cpp:167` (non-splitter path), `logcollectormain.cpp:129` (splitter path) |
| 3 | logTreeView | Form | accessibleName | `displaycontent.cpp:110` |
| 4 | spinnerWidget | Form | setAccessibleName() | `displaycontent.cpp:144` |
| 5 | spinnerWidget_K | Form | setAccessibleName() | `displaycontent.cpp:147` |
| 6 | detailInfoWidget | Form | setAccessibleName() | `displaycontent.cpp:152` |
| 7 | ExportProgressDlg | Form | setAccessibleName() | `displaycontent.cpp:178` |
| 8 | Export All | Button | setAccessibleName() | `logcollectormain.cpp:233` |
| 9 | Refresh Now | Button | setAccessibleName() | `logcollectormain.cpp:239` |
| 10 | refresh_interval_menu | Menu | setAccessibleName() | `logcollectormain.cpp:200` |
| 11 | centralWidget | Form | setAccessibleName() | `logcollectormain.cpp:180` (non-splitter path) |
| 12 | searchEdt | Form | objectName | `logcollectormain.cpp:182` (non-splitter path) |
| 13 | searchChildEdt | Text | objectName | `logcollectormain.cpp:183` (non-splitter path) |
| 14 | LogListView | Form | SET_FORM_ACCESSIBLE fallback | `accessible.h:277` |
| 15 | LogTreeView | Form | SET_FORM_ACCESSIBLE fallback | `accessible.h:278` |
| 16 | FilterContent | Form | SET_FORM_ACCESSIBLE fallback | `accessible.h:279` |
| 17 | DisplayContent | Form | SET_FORM_ACCESSIBLE fallback | `accessible.h:280` |
| 18 | LogPeriodButton | Button | SET_BUTTON_ACCESSIBLE fallback | `accessible.h:281` |
| 19 | LogNormalButton | Button | SET_BUTTON_ACCESSIBLE fallback | `accessible.h:282` |
| 20 | LogIconButton | Button | SET_BUTTON_ACCESSIBLE fallback | `accessible.h:283` |
| 21 | LogCombox | Form | SET_FORM_ACCESSIBLE fallback | `accessible.h:284` |
| 22 | LogSpinnerWidget | Form | SET_FORM_ACCESSIBLE fallback | `accessible.h:285` |
| 23 | logDetailInfoWidget | Form | SET_FORM_ACCESSIBLE fallback | `accessible.h:286` |
| 24 | logDetailEdit | Form | SET_FORM_ACCESSIBLE fallback | `accessible.h:287` |
| 25 | ExportProgressDlg | Form | SET_FORM_ACCESSIBLE fallback | `accessible.h:288` |
| 26 | LogCollectorMain | Form | SET_FORM_ACCESSIBLE fallback | `accessible.h:289` |
| 27 | LogViewHeaderView | Form | SET_FORM_ACCESSIBLE fallback | `accessible.h:290` |

## Notes
- All custom widget types now have class-level AT-SPI registration in `accessible.h`
- Widgets like LogListView and FilterContent also have explicit setAccessibleName() in addition to the class-level registration
- The `SET_FORM_ACCESSIBLE` macro provides a fallback name when `setAccessibleName()` is not set
- All widget names use English and PascalCase convention
139 changes: 139 additions & 0 deletions tests/at/ui-map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# deepin-log-viewer AT-SPI UI Map

## Application Overview
- **Application**: Log Viewer (deepin-log-viewer)
- **Purpose**: View and export system logs
- **Framework**: Qt6 / DTK6 with DMainWindow

## Component Tree (Mermaid)

```mermaid
graph TD
main[LogCollectorMain / DMainWindow]
titlebar[Titlebar]
searchEdt[DSearchEdit - Search]
refreshIntervalMenu[DMenu - Refresh Interval]
exportAllBtn[DIconButton - Export All]
refreshBtn[DIconButton - Refresh Now]

hLayout[QHBoxLayout]
logCatelogue[LogListView - Site bar]
splitterVertical[QSplitter]
filterContent[FilterContent]
displayContent[DisplayContent]

filterContent --> period[Period Buttons Group]
filterContent --> filterLine[Filter Line]
filterLine --> lvTxt[DLabel - Level]
filterLine --> cbx_lv[LogCombox - Level]
filterLine --> dnflvTxt[DLabel - DNF Level]
filterLine --> cbx_dnf_lv[LogCombox - DNF Level]
filterLine --> appTxt[DLabel - Application]
filterLine --> cbx_app[LogCombox - Application]
filterLine --> submoduleTxt[DLabel - Submodule]
filterLine --> cbx_submodule[LogCombox - Submodule]
filterLine --> statusTxt[DLabel - Status]
filterLine --> cbx_status[LogCombox - Status]
filterLine --> typeTxt[DLabel - Event Type]
filterLine --> typeCbx[LogCombox - Event Type]
filterLine --> auditTypeTxt[DLabel - Audit Type]
filterLine --> auditTypeCbx[LogCombox - Audit Type]
filterLine --> exportBtn[LogNormalButton - Export]

displayContent --> splitter[DSplitter]
splitter --> treeView[LogTreeView]
splitter --> spinnerWgt[LogSpinnerWidget]
splitter --> spinnerWgt_K[LogSpinnerWidget_K]
splitter --> detailWgt[logDetailInfoWidget]
detailWgt --> textBrowser[logDetailEdit]

logCatelogue --> systemLog[System Log]
logCatelogue --> kernelLog[Kernel Log]
logCatelogue --> bootLog[Boot Log]
logCatelogue --> dpkgLog[dpkg Log]
logCatelogue --> kwinLog[Kwin Log]
logCatelogue --> xorgLog[Xorg Log]
logCatelogue --> appLog[Application Log]
logCatelogue --> coredumpLog[Coredump Log]
logCatelogue --> bootShutdownEvent[Boot-Shutdown Event]
logCatelogue --> authLog[Auth Log]
logCatelogue --> auditLog[Audit Log]
logCatelogue --> otherLog[Other Log]
logCatelogue --> customLog[Custom Log]

period --> allBtn[LogPeriodButton - All]
period --> todayBtn[LogPeriodButton - Today]
period --> threeDayBtn[LogPeriodButton - 3 Days]
period --> lastWeekBtn[LogPeriodButton - 1 Week]
period --> lastMonthBtn[LogPeriodButton - 1 Month]
period --> threeMonthBtn[LogPeriodButton - 3 Months]

main --> mainWindow[centralWidget / DWidget]
subgraph Export Dialog
exportDlg[ExportProgressDlg / DDialog]
end
```

## Key UI Controls

### 1. Main Window (LogCollectorMain)
- **Class**: `LogCollectorMain` (extends `DMainWindow`)
- **AT-SPI Registration**: Via `SET_FORM_ACCESSIBLE(LogCollectorMain, ...)` in `accessible.h`
- **Children**:
- `DSearchEdit` (m_searchEdt)
- `DIconButton` (m_exportAllBtn) - with accessibleName "Export All"
- `DIconButton` (m_refreshBtn) - with accessibleName "Refresh Now"
- `DMenu` - refresh interval menu
- `LogListView` (m_logCatelogue) - with accessibleName "left_side_bar"
- `FilterContent` (m_topRightWgt) - with accessibleName "filterWidget"
- `DisplayContent` (m_midRightWgt) - with accessibleName from SET_FORM_ACCESSIBLE

### 2. Filter Content (FilterContent)
- **Class**: `FilterContent` (extends `DFrame`)
- **AT-SPI Registration**: Via `SET_FORM_ACCESSIBLE(FilterContent, ...)` in `accessible.h`
- **Children**:
- LogPeriodButton instances for time period selection
- LogCombox instances for filtering
- DLabel instances for filter descriptions
- LogNormalButton for export

### 3. Display Content (DisplayContent)
- **Class**: `DisplayContent` (extends `DWidget`)
- **AT-SPI Registration**: Via `SET_FORM_ACCESSIBLE(DisplayContent, ...)` in `accessible.h`
- **Children**:
- `LogTreeView` (m_treeView) - with accessibleName "logTreeView"
- `LogSpinnerWidget` (m_spinnerWgt) - with accessibleName "spinnerWidget"
- `LogSpinnerWidget` (m_spinnerWgt_K) - with accessibleName "spinnerWidget_K"
- `logDetailInfoWidget` (m_detailWgt) - with accessibleName "detailInfoWidget"
- `exportProgressDlg` (m_exportDlg) - with accessibleName "ExportProgressDlg"
- `DLabel` (noResultLabel) - with accessibleName "noResultLabel"
- `DLabel` (notAuditLabel) - with accessibleName "notAuditLabel"
- `DLabel` (noCoredumpctlLabel) - with accessibleName "noCoredumpctlLabel"
- `DLabel` (noPermissionLabel) - with accessibleName "noPermissionLabel"

### 4. Log List View (LogListView - Sidebar)
- **Class**: `LogListView` (extends `DListView`)
- **AT-SPI Registration**: Via `SET_FORM_ACCESSIBLE(LogListView, ...)` in `accessible.h`

### 5. Log Tree View (LogTreeView)
- **Class**: `LogTreeView` (extends `DTreeView`)
- **AT-SPI Registration**: Via `SET_FORM_ACCESSIBLE(LogTreeView, ...)` in `accessible.h`

### 6. Custom Button Types
- **LogPeriodButton**: `DPushButton` - AT-SPI via `SET_BUTTON_ACCESSIBLE`
- **LogNormalButton**: `DPushButton` - AT-SPI via `SET_BUTTON_ACCESSIBLE`
- **LogIconButton**: `QPushButton` - AT-SPI via `SET_BUTTON_ACCESSIBLE`
- **LogCombox**: `DComboBox` - AT-SPI via `SET_FORM_ACCESSIBLE`

### 7. Detail Widget
- **logDetailInfoWidget**: `DWidget` - AT-SPI via `SET_FORM_ACCESSIBLE(logDetailInfoWidget, ...)`
- Contains labels for daemon name, user, PID, etc.
- Contains `logDetailEdit` (DTextBrowser) for log message display

## File References
- `application/accessible.h` - AT-SPI factory and all SET_*_ACCESSIBLE macros
- `application/logcollectormain.cpp` - Main window setup
- `application/displaycontent.cpp` - Display content and detail area
- `application/filtercontent.cpp` - Filter controls
- `application/loglistview.cpp` - Log type sidebar
- `application/main.cpp` - Entry point with `QAccessible::installFactory`
Loading