gui: Options, Scheduler, Speed Limiter, Batch, Grabber, and the tray icon
Continues the build order past the Add-URL/File-Info/Progress dialog flow.
- OptionsDialog: General/Save To/Connection/Downloads/Proxy/Sounds tabs, every
control bound to a real settings.* key (contracts/schema/types/Settings.
schema.json). The spec's File Types and Site Logins tabs have no settings.*
backing (categories go through category.upsert, credentials through the
Secret Service) so they don't exist here — a tab either binds to a real key
or isn't shipped. diffChanged() sends only what actually changed, matching
settings.set's "changed[] names exactly what took effect" contract.
- SchedulerDialog: per-queue schedule (schedule.get/set) plus maxConcurrent/
onComplete (queue.upsert), Start Now/Stop. Queue.schema.json already carries
the schedule so queue.list alone seeds the window.
- SpeedLimiterDialog: the live global limiter (limiter.get/set) — a different
thing from Options' downloads.speedLimit* default. buildParams() enforces
the schema's "0 with enabled true must not be offered".
- BatchDialog: clipboard-blob and {start..end}-wildcard tabs sharing one
category/queue/start-mode footer into download.addBatch.
- GrabberWizard: 4-step QWizard (project label -> start URL/depth/filters ->
file-type filter -> review), grabber.start feeding a poll+event.grabber.
progress-driven review page, Finish = grabber.harvest for the checked files.
- TrayIcon: active-count tooltip, Show/Add URL/Pause All/Resume All/Speed
Limiter submenu/Quit. Quit only closes the GUI — there is no RPC to stop
veloxd itself, filed as a new gap in daemon-requests-m1.md. MainWindow now
also hides to tray instead of closing when general.minimizeToTray is set.
Every dialog's non-widget logic (diffChanged, buildSchedule, buildParams,
parseUrlBlob/expandWildcard/buildAddBatchParams, buildFileTypes/
buildStartParams/buildHarvestParams) is a static pure function with its own
test, same shape as FileInfoDialog::buildSpec from the previous round.
Verified end-to-end against a running mockd under ASan+UBSan: all five
surfaces render real data (settings.get values, queue.list's two seeded
queues, limiter.get, a live grabber.start/status crawl returning 3 files) with
no sanitizer reports. gui-check (non-ASan) and dev (ASan+UBSan) presets both
build the whole repo clean; all gui-labeled ctest targets pass.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NSCdCWFXBTSBBK3MzWtJiC
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
// The Options dialog. Lane GUI.
|
||||
//
|
||||
// docs/03-gui-spec.md §4: every control here maps 1:1 onto a settings.* key from
|
||||
// contracts/schema/types/Settings.schema.json. The spec's "File Types" and "Site Logins"
|
||||
// tabs have no backing key (per-category extension lists live on Category via
|
||||
// category.upsert, not settings.*; login credentials go to the Secret Service) — a real
|
||||
// tab either binds to a real key or does not exist here, so those two are left out rather
|
||||
// than shipped as fake affordances.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QJsonObject>
|
||||
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QSpinBox;
|
||||
class QTabWidget;
|
||||
|
||||
namespace velox::gui {
|
||||
namespace rpc {
|
||||
class RpcClient;
|
||||
} // namespace rpc
|
||||
|
||||
class OptionsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OptionsDialog(rpc::RpcClient *client, QWidget *parent = nullptr);
|
||||
|
||||
/// The settings.* keys every tab's controls bind to, in the order settings.get is
|
||||
/// called with. Exposed so a test can assert nothing here drifts from the schema.
|
||||
static QStringList allKeys();
|
||||
|
||||
/// Pure: keys in `current` whose value differs from `original` (or is altogether
|
||||
/// absent from `original`). settings.set is documented to write and broadcast exactly
|
||||
/// the keys present in its params, so sending only what actually changed matters.
|
||||
static QJsonObject diffChanged(const QJsonObject &original, const QJsonObject ¤t);
|
||||
|
||||
private slots:
|
||||
void onSettingsLoaded(const QJsonObject &values);
|
||||
void apply();
|
||||
|
||||
private:
|
||||
void buildGeneralTab();
|
||||
void buildSaveToTab();
|
||||
void buildConnectionTab();
|
||||
void buildDownloadsTab();
|
||||
void buildProxyTab();
|
||||
void buildSoundsTab();
|
||||
void populateFrom(const QJsonObject &values);
|
||||
QJsonObject currentValues() const;
|
||||
void browseInto(QLineEdit *target, bool pickFile);
|
||||
|
||||
rpc::RpcClient *client_;
|
||||
QJsonObject original_; // last-known-saved values, keyed by settings.* name
|
||||
QTabWidget *tabs_;
|
||||
QLabel *statusLabel_;
|
||||
|
||||
// General
|
||||
QCheckBox *launchOnLogin_;
|
||||
QCheckBox *minimizeToTray_;
|
||||
QCheckBox *showDropTarget_;
|
||||
QCheckBox *confirmOnExit_;
|
||||
QComboBox *language_;
|
||||
QCheckBox *checkForUpdates_;
|
||||
|
||||
// Save To
|
||||
QLineEdit *defaultDir_;
|
||||
QLineEdit *tempDir_;
|
||||
QComboBox *fileExistsPolicy_;
|
||||
QCheckBox *createSubfolderPerSite_;
|
||||
|
||||
// Connection
|
||||
QComboBox *connectionPreset_;
|
||||
QSpinBox *maxSegmentsPerDownload_;
|
||||
QComboBox *bufferBytes_;
|
||||
QSpinBox *maxConcurrentDownloads_;
|
||||
QSpinBox *timeoutSec_;
|
||||
QSpinBox *maxRetries_;
|
||||
QSpinBox *retryBackoffSec_;
|
||||
QSpinBox *maxTotalBufferMiB_;
|
||||
QSpinBox *maxActiveSegments_;
|
||||
|
||||
// Downloads
|
||||
QCheckBox *speedLimitEnabled_;
|
||||
QSpinBox *speedLimitKiBps_;
|
||||
QLineEdit *virusScanCommand_;
|
||||
QLineEdit *postDownloadCommand_;
|
||||
QComboBox *duplicatePolicy_;
|
||||
QCheckBox *verifyChecksums_;
|
||||
|
||||
// Proxy
|
||||
QComboBox *proxyMode_;
|
||||
QLineEdit *proxyHost_;
|
||||
QSpinBox *proxyPort_;
|
||||
QLineEdit *proxyUsername_;
|
||||
QLineEdit *proxyBypassHosts_;
|
||||
QLineEdit *proxyPacUrl_;
|
||||
|
||||
// Sounds
|
||||
QCheckBox *soundsEnabled_;
|
||||
QLineEdit *soundOnComplete_;
|
||||
QLineEdit *soundOnQueueComplete_;
|
||||
QLineEdit *soundOnError_;
|
||||
};
|
||||
|
||||
} // namespace velox::gui
|
||||
Reference in New Issue
Block a user