gui: RPC client, download table model, and a live main window
First vertical slice of velox-gui, built entirely against tools/mockd (no daemon dependency): - rpc/: RpcConnection runs a QLocalSocket on a worker thread with newline-delimited JSON-RPC framing, drives the session.hello / session.subscribe handshake, and reconnects with exponential backoff (250 ms -> 8 s). RpcClient is the main-thread face: marshals calls onto the worker, delivers replies as main-thread callbacks, re-emits server notifications as typed Qt signals, and issues the one-shot download.list on reaching Connected. - models/DownloadTableModel: QAbstractTableModel over TaskSummary. A progress batch is a row patch with a narrow dataChanged over the value columns only; beginResetModel() is reserved for the initial load and a reconnect resync. - widgets/ProgressDelegate: in-cell progress bar for the Status column. - mainwindow/MainWindow: the table, a status-bar connection dot, an offline banner instead of a modal, dialog-free pause/resume/stop actions, and QSettings column/geometry persistence. - gui/CMakeLists.txt links velox::proto (never velox::core, ADR 0009) and self-guards on the veloxproto target so main keeps configuring if it is ever absent again. - i18n from the first commit: every string via tr(), plus an Arabic .ts stub for the RTL check. - tests/: headless QTest for the model — proves the progress patch is a narrow dataChanged and never resets the model. Verified end-to-end against `mockd --tasks 300`: handshake, initial list, live progress batches applied to the model, and a clean Reconnecting -> Connected recovery when mockd is bounced mid-run. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_016Ne28kx4VreeBWZv82Nksd
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
#include "widgets/ProgressDelegate.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionProgressBar>
|
||||
|
||||
#include "models/DownloadTableModel.hpp"
|
||||
|
||||
namespace velox::gui {
|
||||
|
||||
void ProgressDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const {
|
||||
const QVariant progressVar = index.data(DownloadTableModel::ProgressRole);
|
||||
const double progress = progressVar.isValid() ? progressVar.toDouble() : -1.0;
|
||||
|
||||
if (progress < 0.0) {
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
return;
|
||||
}
|
||||
|
||||
QStyleOptionViewItem opt(option);
|
||||
initStyleOption(&opt, index);
|
||||
// We draw the bar ourselves; suppress the default text so it is not painted twice.
|
||||
opt.text.clear();
|
||||
QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
|
||||
style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget);
|
||||
|
||||
QStyleOptionProgressBar bar;
|
||||
bar.state = option.state | QStyle::State_Horizontal;
|
||||
bar.direction = option.direction;
|
||||
bar.rect = option.rect.adjusted(3, 3, -3, -3);
|
||||
bar.fontMetrics = option.fontMetrics;
|
||||
bar.palette = option.palette;
|
||||
bar.minimum = 0;
|
||||
bar.maximum = 10000;
|
||||
bar.progress = static_cast<int>(progress * 10000.0);
|
||||
bar.textVisible = true;
|
||||
bar.textAlignment = Qt::AlignCenter;
|
||||
bar.text = index.data(Qt::DisplayRole).toString();
|
||||
|
||||
style->drawControl(QStyle::CE_ProgressBar, &bar, painter, opt.widget);
|
||||
}
|
||||
|
||||
} // namespace velox::gui
|
||||
@@ -0,0 +1,23 @@
|
||||
// In-cell progress bar for the Status column. Lane GUI.
|
||||
//
|
||||
// docs/03-gui-spec.md §1: "Progress bar drawn by a QStyledItemDelegate in the Status
|
||||
// column." Reads DownloadTableModel::ProgressRole; falls back to plain text for rows with
|
||||
// no measurable progress (unknown size, or a non-downloading state).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
namespace velox::gui {
|
||||
|
||||
class ProgressDelegate : public QStyledItemDelegate {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using QStyledItemDelegate::QStyledItemDelegate;
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
};
|
||||
|
||||
} // namespace velox::gui
|
||||
Reference in New Issue
Block a user