Feat: add HeaderInfoTableWidget for displaying device information#650
Conversation
Reviewer's GuideIntroduces a new HeaderInfoTableWidget and its custom delegate to display device key-value information in a rounded, themable table with alternating row colors and dynamic height, using DTK palettes for active/inactive states and a custom frame border and divider line. Sequence diagram for updating and painting HeaderInfoTableWidgetsequenceDiagram
actor User
participant DeviceDetailsView
participant HeaderInfoTableWidget
participant HeaderInfoDelegate
participant DApplication
participant DPaletteHelper
User->>DeviceDetailsView: selectDevice(device)
DeviceDetailsView->>DeviceDetailsView: buildKeyValuePairs(device)
DeviceDetailsView->>HeaderInfoTableWidget: updateData(data)
HeaderInfoTableWidget->>HeaderInfoTableWidget: resetTableContents()
HeaderInfoTableWidget->>HeaderInfoTableWidget: setRowCount(nRow)
loop for each row
HeaderInfoTableWidget->>DApplication: activeWindow()
DApplication-->>HeaderInfoTableWidget: window
HeaderInfoTableWidget->>DPaletteHelper: palette(widget)
DPaletteHelper-->>HeaderInfoTableWidget: palette
HeaderInfoTableWidget->>HeaderInfoTableWidget: createItemsAndSetBackground()
end
HeaderInfoTableWidget->>HeaderInfoTableWidget: adjustFixedHeight()
Note over HeaderInfoTableWidget: Qt triggers paintEvent and delegate paint during rendering
HeaderInfoTableWidget->>HeaderInfoTableWidget: paintEvent(event)
HeaderInfoTableWidget->>DApplication: activeWindow()
DApplication-->>HeaderInfoTableWidget: window
HeaderInfoTableWidget->>DPaletteHelper: palette(widget)
DPaletteHelper-->>HeaderInfoTableWidget: palette
HeaderInfoTableWidget->>HeaderInfoTableWidget: drawRoundedBorderAndDivider()
HeaderInfoTableWidget->>HeaderInfoDelegate: paint(painter, option, index)
HeaderInfoDelegate->>DApplication: activeWindow()
DApplication-->>HeaderInfoDelegate: window
HeaderInfoDelegate->>DPaletteHelper: palette(widget)
DPaletteHelper-->>HeaderInfoDelegate: palette
alt itemSelected
HeaderInfoDelegate->>HeaderInfoDelegate: setHighlightedTextColor()
else itemNotSelected
HeaderInfoDelegate->>HeaderInfoDelegate: setNormalTextColor()
end
HeaderInfoDelegate->>HeaderInfoDelegate: QStyledItemDelegate::paint()
Class diagram for the new HeaderInfoTableWidget and HeaderInfoDelegateclassDiagram
class DWidget
class DTableWidget
DTableWidget --|> DWidget
class HeaderInfoDelegate {
+HeaderInfoDelegate(QObject *parent)
+void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
}
class HeaderInfoTableWidget {
+HeaderInfoTableWidget(DWidget *parent)
+void updateData(QList~QPair~QString,QString~~ data)
+void paintEvent(QPaintEvent *event)
-void initUI()
-void resetTableContents()
-HeaderInfoDelegate *m_delegate
}
HeaderInfoTableWidget --|> DTableWidget
HeaderInfoTableWidget *-- HeaderInfoDelegate
class DApplication
class DPaletteHelper
class DPalette
HeaderInfoTableWidget ..> DApplication : uses
HeaderInfoTableWidget ..> DPaletteHelper : uses
HeaderInfoTableWidget ..> DPalette : uses
HeaderInfoDelegate ..> DApplication : uses
HeaderInfoDelegate ..> DPaletteHelper : uses
HeaderInfoDelegate ..> DPalette : uses
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 3 issues, and left some high level feedback:
- The vertical divider position is currently hard-coded to 179 while the column width is set to 180; consider deriving the divider x-position from the actual first-column width (e.g.,
columnWidth(0)) to keep layout consistent if column sizing changes. - In
updateData,setFixedHeight(0)for the empty case may cause layout glitches; it can be safer to use a minimal height or rely on sizeHint to avoid the widget effectively disappearing in some layouts.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The vertical divider position is currently hard-coded to 179 while the column width is set to 180; consider deriving the divider x-position from the actual first-column width (e.g., `columnWidth(0)`) to keep layout consistent if column sizing changes.
- In `updateData`, `setFixedHeight(0)` for the empty case may cause layout glitches; it can be safer to use a minimal height or rely on sizeHint to avoid the widget effectively disappearing in some layouts.
## Individual Comments
### Comment 1
<location path="deepin-devicemanager/src/Widget/headerinfotablewidget.cpp" line_range="49-55" />
<code_context>
+ }
+
+ // 调整控件高度,使内容刚好完全显示,不出现垂直滚动条
+ if (nRow > 0) {
+ // 为了保持底部圆角,给表格高度留出 2px 余量;避免内容铺满viewport导致圆角被覆盖
+ setFixedHeight(ROW_HEIGHT * nRow + 2);
+ } else {
+ setFixedHeight(0);
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Avoid assuming row height equals ROW_HEIGHT when setting the table height.
`ROW_HEIGHT * nRow` only works if every row is exactly `ROW_HEIGHT`, but actual row heights can vary with styles, fonts, or DPI, leading to gaps or unexpected scrollbars. Instead, derive the height from the table itself, e.g.:
```cpp
int totalHeight = verticalHeader()->length();
setFixedHeight(totalHeight + 2);
```
This preserves the 2px margin while matching the real row heights.
```suggestion
// 调整控件高度,使内容刚好完全显示,不出现垂直滚动条
if (nRow > 0) {
// 为了保持底部圆角,给表格高度留出 2px 余量;避免内容铺满 viewport 导致圆角被覆盖
// 不再假设每行高度等于 ROW_HEIGHT,而是从 verticalHeader() 实际计算所有行的总高度
int totalHeight = 0;
if (auto *vh = verticalHeader()) {
totalHeight = vh->length();
} else {
// 兜底:如果 verticalHeader 不可用,则退回到原有的按行数估算高度逻辑
totalHeight = ROW_HEIGHT * nRow;
}
setFixedHeight(totalHeight + 2);
} else {
setFixedHeight(0);
}
```
</issue_to_address>
### Comment 2
<location path="deepin-devicemanager/src/Widget/headerinfotablewidget.cpp" line_range="114-119" />
<code_context>
+ painter.drawRoundedRect(rectIn, radius, radius);
+
+ // Draw vertical divider between first and second columns (same as DetailTreeView)
+ QLine vline(rect.topLeft().x() + 179, rect.topLeft().y(), rect.bottomLeft().x() + 179, rect.bottomLeft().y());
+ painter.drawLine(vline);
+}
+
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Avoid hardcoding the vertical divider position; derive it from the column geometry instead.
The `179` offset assumes a fixed first-column width of 180, so the divider will misalign if that width changes (e.g. user resize or style/layout updates). Instead, compute the divider position from the actual column geometry, e.g.:
```cpp
int dividerX = columnViewportPosition(1); // or columnWidth(0)
QLine vline(rect.topLeft().x() + dividerX - 1,
rect.topLeft().y(),
rect.bottomLeft().x() + dividerX - 1,
rect.bottomLeft().y());
```
This keeps the divider aligned with runtime column width changes.
```suggestion
painter.drawRoundedRect(rectIn, radius, radius);
// Draw vertical divider between first and second columns (same as DetailTreeView)
const int dividerX = columnViewportPosition(1);
if (dividerX > 0) {
QLine vline(rect.topLeft().x() + dividerX - 1,
rect.topLeft().y(),
rect.bottomLeft().x() + dividerX - 1,
rect.bottomLeft().y());
painter.drawLine(vline);
}
}
```
</issue_to_address>
### Comment 3
<location path="deepin-devicemanager/src/Widget/headerinfotablewidget.cpp" line_range="26" />
<code_context>
+ initUI();
+}
+
+void HeaderInfoTableWidget::updateData(const QList<QPair<QString, QString>> &data)
+{
+ resetTableContents();
</code_context>
<issue_to_address>
**issue (complexity):** Consider extracting shared palette logic, cell creation, border drawing, and height calculation into small helpers with named constants to remove duplication and magic numbers while preserving behavior.
You can keep the current behavior while trimming quite a bit of complexity with a few small, local helpers and constants.
### 1. Remove duplicated palette / color-group logic
`updateData` and `paintEvent` both compute `wnd`, `cg`, and `palette`. Centralize this:
```cpp
namespace {
constexpr int kBorderRadius = 8;
constexpr int kBorderWidth = 1;
constexpr int kDividerSectionIndex = 0; // divider after column 0
constexpr int kHeightPadding = 2;
inline DPalette::ColorGroup currentColorGroup() {
return DApplication::activeWindow() ? DPalette::Active : DPalette::Inactive;
}
inline DPalette currentPalette(const QWidget *w) {
return DPaletteHelper::instance()->palette(w);
}
} // namespace
```
Then in `updateData` and `paintEvent`:
```cpp
void HeaderInfoTableWidget::updateData(const QList<QPair<QString, QString>> &data)
{
resetTableContents();
const int nRow = data.size();
setRowCount(nRow);
const auto cg = currentColorGroup();
const auto palette = currentPalette(this);
const QColor colorEven = palette.color(cg, DPalette::Base);
const QColor colorOdd = palette.color(cg, DPalette::ItemBackground);
...
}
```
```cpp
void HeaderInfoTableWidget::paintEvent(QPaintEvent *event)
{
DTableWidget::paintEvent(event);
const auto cg = currentColorGroup();
const auto palette = currentPalette(this);
...
}
```
### 2. Factor out cell creation to avoid duplicated item setup
The first/second column logic is copy-pasted. A tiny helper keeps flags/background logic in one place:
```cpp
QTableWidgetItem *HeaderInfoTableWidget::createCell(const QString &text,
int row,
int column,
const QColor &bg)
{
auto *item = new QTableWidgetItem(text);
item->setFlags(item->flags() & ~Qt::ItemIsSelectable);
item->setBackground(bg);
setItem(row, column, item);
return item;
}
```
Use it in the loop:
```cpp
for (int i = 0; i < nRow; ++i) {
const QColor bg = (i % 2 == 0) ? colorEven : colorOdd;
createCell(data[i].first, i, 0, bg);
createCell(data[i].second, i, 1, bg);
}
```
Now any change to flags/background is made once.
### 3. Extract border/drawer logic from `paintEvent` and remove magic numbers
Right now `paintEvent` mixes: base painting, geometry, rounded border, and divider. You can still call it from `paintEvent`, but move the details out and replace magic numbers with named constants:
```cpp
void HeaderInfoTableWidget::drawBorder(QPainter &painter,
const QRect &rect,
const DPalette &palette,
DPalette::ColorGroup cg) const
{
const QRect outerRect = rect.adjusted(0, 0, -1, -1);
const QRect innerRect(
outerRect.x() + kBorderWidth,
outerRect.y() + kBorderWidth,
outerRect.width() - 2 * kBorderWidth,
outerRect.height() - 2 * kBorderWidth
);
QPainterPath outerPath;
outerPath.addRoundedRect(outerRect, kBorderRadius, kBorderRadius);
QPainterPath innerPath;
innerPath.addRoundedRect(innerRect, kBorderRadius, kBorderRadius);
const QPainterPath framePath = outerPath.subtracted(innerPath);
const QBrush frameBrush(palette.color(cg, DPalette::FrameBorder));
painter.fillPath(framePath, frameBrush);
QPen pen = painter.pen();
pen.setWidth(kBorderWidth);
pen.setColor(palette.color(cg, DPalette::FrameBorder));
painter.setPen(pen);
painter.drawRoundedRect(innerRect, kBorderRadius, kBorderRadius);
}
```
For the divider, derive it from the header instead of using `179`:
```cpp
void HeaderInfoTableWidget::drawColumnDivider(QPainter &painter, const QRect &rect) const
{
const auto *header = horizontalHeader();
if (!header || header->count() <= kDividerSectionIndex)
return;
// Divider at the end of the first section
const int dividerX = header->sectionPosition(kDividerSectionIndex) +
header->sectionSize(kDividerSectionIndex);
const QLine vline(dividerX, rect.top(), dividerX, rect.bottom());
painter.drawLine(vline);
}
```
Then `paintEvent` becomes shorter and easier to follow:
```cpp
void HeaderInfoTableWidget::paintEvent(QPaintEvent *event)
{
DTableWidget::paintEvent(event);
const auto cg = currentColorGroup();
const auto palette = currentPalette(this);
QPainter painter(viewport());
painter.setRenderHint(QPainter::Antialiasing, true);
const QRect rect = viewport()->rect();
drawBorder(painter, rect, palette, cg);
drawColumnDivider(painter, rect);
}
```
### 4. Isolate height logic and remove `+ 2` magic number
`ROW_HEIGHT * nRow + 2` is non-obvious. Use a constant and a helper:
```cpp
void HeaderInfoTableWidget::updateFixedHeight(int rowCount)
{
if (rowCount > 0) {
setFixedHeight(ROW_HEIGHT * rowCount + kHeightPadding);
} else {
setFixedHeight(0);
}
}
```
Call it from `updateData`:
```cpp
void HeaderInfoTableWidget::updateData(const QList<QPair<QString, QString>> &data)
{
...
updateFixedHeight(nRow);
}
```
This keeps all behavior (rounded corners, colors, height behavior) intact but reduces duplication, centralizes layout-related numbers, and makes future tweaks safer and cheaper.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
/forcemerge |
1 similar comment
|
/forcemerge |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: GongHeng2017, max-lvs The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
/forcemerge |
1 similar comment
|
/forcemerge |
|
/merge |
eba0fa4 to
cffa1c9
Compare
|
Note
详情{
"deepin-devicemanager/src/Tool/commontools.cpp": [
{
"line": " return \"https://driver.uniontech.com/api/v1/drive/search\";",
"line_number": 167,
"rule": "S35",
"reason": "Url link | 162cef9d4a"
},
{
"line": " return \"https://driver.uniontech.com/api/v1/drive/search\";",
"line_number": 171,
"rule": "S35",
"reason": "Url link | 162cef9d4a"
},
{
"line": " return \"https://drive-pre.uniontech.com/api/v1/drive/search\";",
"line_number": 173,
"rule": "S35",
"reason": "Url link | 0e010283c1"
}
]
} |
Add a custom table widget with rounded border and alternating row colors for displaying device information as key-value pairs. - Add HeaderInfoDelegate for custom text color handling in selection - Add HeaderInfoTableWidget with rounded border painting and vertical divider - Support dynamic height adjustment based on content - Use DPalette for consistent theming with active/inactive states Log: add feature for cpu info show. Task: https://pms.uniontech.com/task-view-387697.html
cffa1c9 to
b8f46c8
Compare
|
Note
详情{
"deepin-devicemanager/src/Tool/commontools.cpp": [
{
"line": " return \"https://driver.uniontech.com/api/v1/drive/search\";",
"line_number": 167,
"rule": "S35",
"reason": "Url link | 162cef9d4a"
},
{
"line": " return \"https://driver.uniontech.com/api/v1/drive/search\";",
"line_number": 171,
"rule": "S35",
"reason": "Url link | 162cef9d4a"
},
{
"line": " return \"https://drive-pre.uniontech.com/api/v1/drive/search\";",
"line_number": 173,
"rule": "S35",
"reason": "Url link | 0e010283c1"
}
]
} |
deepin pr auto reviewGit Diff 代码审查报告1. 语法逻辑审查1.1 头文件包含
1.2 HeaderInfoDelegate 类
1.3 HeaderInfoTableWidget 类
2. 代码质量审查2.1 命名规范
2.2 代码结构
2.3 代码注释
3. 代码性能审查3.1 内存管理
3.2 绘制性能
3.3 颜色获取
4. 代码安全审查4.1 空指针检查
4.2 边界检查
4.3 资源管理
5. 改进建议
6. 总体评价这段代码实现了自定义表格控件,用于显示带有圆角边框和交替行颜色的信息表格。代码结构清晰,遵循了 Qt 和 DTK 的开发规范。主要改进点在于性能优化、资源管理和一些细节处理,如硬编码值的替换和文档注释的添加。 |
|
/merge |
|
This pr force merged! (status: unknown) |
3 similar comments
|
This pr force merged! (status: unknown) |
|
This pr force merged! (status: unknown) |
|
This pr force merged! (status: unknown) |
|
This pr cannot be merged! (status: unknown) |
Add a custom table widget with rounded border and alternating row colors for displaying device information as key-value pairs.
Log: add feature for cpu info show.
Task: https://pms.uniontech.com/task-view-387697.html
Summary by Sourcery
Introduce a styled table widget and delegate for displaying header/device information with theming support.
New Features: