Repository navigation
feat(gui): Reset Settings' confirmation and failure notice are CanonWindow dialogs, and Return or Escape still cancel the reset - #6733
Conversation
…indow dialogs, and Return or Escape still cancel the reset. Principle VIII. Settings -> Reset Settings... used two FramelessMessageBox calls. They become ResetSettingsDialog, a short-lived CanonWindow::Kind::Dialog built like the AetherRX / AetherTX Settings dialogs: canon header, ModemChrome canon sheet, SectionLabel headings and the files in nested read-only lists. The wording is unchanged, Cancel stays the default button and takes focus, and the failure notice lists Failed and Removed separately. The backup, removal and quit in SupportDialog::resetSettings() are unchanged. reset_settings_dialog_test (socket-free, removes nothing) checks that Return, Escape and Cancel cancel, only Yes confirms, the file lists show what was passed, and OK closes the notice. It fails if Yes becomes the default button. Fixes aethersdr#6732 Part of aethersdr#6239 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Coordination note from #6736, which is landing now. #6736 adds
The CTR2 window's eleven questions and notices use it. Two things for this PR once #6736 is on
|
There was a problem hiding this comment.
1. Issue fit
Yes. #6732's acceptance list maps cleanly onto the diff: Return/Escape/Cancel leave the settings alone and only Yes confirms (ResetSettingsDialog.cpp:86-89, covered by the new test); the confirmation lists the files and says "None" when there are none (:50-54); the regression test is socket-free and never removes a file (SupportDialog is not linked into the target); and the colour-audit ratchet stays flat, which Static checks passing on bc9b602 corroborates — the sheet is routed through ModemChrome::styleSheet via applyCanonSheet, which is inline in CanonIndicators.h:150, so no new setStyleSheet call site appears.
The two out-of-scope items #6732 reserves (relabelling Yes, primary/danger button styling) are genuinely absent from the diff. The reset itself is untouched — I diffed SupportDialog::resetSettings() and the only changes are the two call sites.
2. Scope
Everything in the diff is explained by the issue. Nothing extraneous.
| File | What it changes | Claimed in the body? | Verdict |
|---|---|---|---|
CMakeLists.txt:1553 |
One GUI_SOURCES line for the new .cpp |
Yes | In scope |
docs/style/dialog-patterns.md:238 |
Adds ResetSettingsDialog to the CanonWindow inventory sentence |
Yes | In scope |
src/gui/ResetSettingsDialog.{h,cpp} |
The new dialog; two static entry points, no new settings key, no setGeometryKey() |
Yes | In scope — matches the doc's "no geometry persistence by default" for a short-lived window |
src/gui/SupportDialog.cpp:266-325 |
Two FramelessMessageBox calls → confirm() / showFailures(); deletes the hand-built prompt string |
Yes | In scope |
tests/reset_settings_dialog_test.cpp |
New 16-check test | Yes | In scope |
tests/tests.cmake:2347-2368, 9848 |
Target registration + AETHER_SETTINGS_CONSUMERS |
Yes | In scope |
A few things I specifically checked and found clean:
- No deleted guard. Reading the
-lines: the oldQMessageBox::Canceldefault is replaced bycancel->setDefault(true)+cancel->setFocus(), so the cancel-default property survives the rewrite rather than being dropped. No removed comment names a symptom. - No
CHANGELOG.mdentry — correct; the body says so explicitly. - No new public/protocol surface. The two statics are internal C++ with one call site (
MainWindow_Menus.cpp:1569); no wire verb, settings key, or capability field. - Siblings deliberately left behind. Six other
FramelessMessageBoxuses remain inSupportDialog.cpp(:341, :402, :484, :499, :529, :535). Both #6732 and the PR body declare these out of scope, so the PR does not read as "fixed" while claiming more than it does. - The body's self-certification holds. The CMake source set matches the
modem_chrome_testprecedent attests.cmake:2263-2272exactly (ModemChrome.cpp+DragValuePopup.cpp+ the theming stack), and theTIMEOUT 30is respected rather than overwritten by the 300 s ceiling (tests.cmake:10353-10358) and is sanitizer-scaled (:10360-10370).
Socket tests: none. The added test opens no socket — no QTcpServer/QUdpSocket/QLocalServer/bind/listen/connectToHost and no fake peer in tests/reset_settings_dialog_test.cpp. Recording this per the review protocol; it is not a finding.
3. Blockers
None. See the recommendation below for the maintainer decision the PR itself asks for — that is a ruling to make, not a defect to fix.
4. Nits (all non-blocking)
1. src/gui/ResetSettingsDialog.cpp:86 — the one line that makes the PR title true under keyboard navigation is the one line the suite does not cover.
yes->setAutoDefault(false);This is load-bearing, not belt-and-braces. QPushButton::autoDefault() defaults to Auto, which resolves to true for any button whose enclosing window is a QDialog — and CanonWindow is one. QPushButton::keyPressEvent() activates on Return when autoDefault() is true, before the event ever reaches QDialog::keyPressEvent(). So without this line, an operator who tabs to Yes and presses Return confirms the reset; with it, the Return falls through to the default button (Cancel).
The new test cannot see that, because every QTest::keyClick(dlg, …) targets the window, not the focused widget, so no button's keyPressEvent is ever exercised. Delete line 86 and all 16 checks still pass. That is exactly the mutation this test exists to catch. The body's mutation check (making Yes the default and giving it focus) tests a different thing.
One more whenShown closes it, and also pins the "Cancel takes focus" claim the header makes at ResetSettingsDialog.h:20-21, which nothing currently asserts:
whenShown([](CanonWindow* dlg) {
auto* cancel = dlg->findChild<QPushButton*>(QStringLiteral("resetSettingsCancel"));
check(dlg->focusWidget() == cancel, "Cancel takes focus");
auto* yes = dlg->findChild<QPushButton*>(QStringLiteral("resetSettingsConfirm"));
if (!yes) return;
yes->setFocus();
QTest::keyClick(yes, Qt::Key_Return);
});
check(!ResetSettingsDialog::confirm(nullptr, QStringLiteral("/tmp/backups"), paths),
"Return on a focused Yes does not confirm");2. src/gui/ResetSettingsDialog.cpp:49 — the paths are no longer copyable.
list->setSelectionMode(QAbstractItemView::NoSelection);QMessageBox text is selectable, so before this change an operator could copy the path list into a bug report. The message label keeps that (:31 sets TextSelectableByMouse) but the paths — the part actually worth pasting — lose it. docs/style/dialog-patterns.md calls this out as something the canon windows keep: "About's build details stay selectable so they can be copied into a bug report." If selection highlight is unwanted visually, this is a maintainer call; otherwise:
list->setSelectionMode(QAbstractItemView::ExtendedSelection);3. src/gui/ResetSettingsDialog.cpp:28 — the message label is left on Qt::AutoText. Credit: security-audit (CodeGuard) surfaced this while auditing the flagged set; I confirmed it against the file.
auto* text = new QLabel(message);message interpolates backupDir, so a config path that trips Qt::mightBeRichText() would render as HTML rather than as the path. Not a security boundary (the path is the operator's own QStandardPaths config dir, and there is no link activation), but the house pattern is explicit, e.g. MainWindow_Menus.cpp:1989:
text->setTextFormat(Qt::PlainText);4. The corner close button is the third dismissal route and is untested. CanonWindow.cpp:74 wires it to &QDialog::close, which rejects, so it cancels correctly by construction — but given the test's own framing ("the keys that dismiss a dialog without reading it must leave the settings alone"), the X belongs in that set.
5. src/gui/SupportDialog.cpp:302-313 — the confirmation still does not list everything the reset removes. Beyond resetPaths, the reset sweeps *-auto.db / *-postmigration.db from the backups dir and every file in the quarantine dir, none of which appear in promptPaths. Pre-existing — the old prompt had the same gap, and #6732's proposal preserves it — so this is not a regression from this PR. Naming it because #6732's acceptance says "the confirmation lists the files that will be removed," and a future PR may want to close it.
5. What I tried to break
- Keyboard paths into the destructive branch. Walked
CanonWindow::keyPressEvent(CanonWindow.cpp:109-124), theKind::Dialogdefault ofm_returnClicksDefault, andQPushButton's own Return handling. Return-on-window and Escape both land on Cancel, andQKeySequence::Closeis wired toreject(:79). The one gap is nit 1 — and note that is a test gap: the production code handles it correctly. - Lifetime.
confirm()/showFailures()build the dialog on the stack andexec()it, so I checked whether the base setsWA_DeleteOnClose(which would make the corner close buttondeleteLatera stack object). It does not —CanonWindow.cppsets onlyWA_QuitOnClose(false)andWA_TranslucentBackground. Safe. - Layout and link completeness.
CanonWindowleavesm_bodywithout a layout (:66-69), sonew QVBoxLayout(bodyWidget())is not a silently-ignored second layout.applyCanonSheetisinlinein the header andmakeCanonHeaderlives inCanonWindow.cpp, both already in the test's source set, so the new target links — andcheck-windows(the-DENABLE_ASR=OFFlane),check-macosandbuildare all green onbc9b602, which is the real evidence it compiles on all three platforms. - Test strength. Confirmed the test is not self-asserting: hard-coding
confirm()totruefails three checks, tofalsefails one, wiring Cancel toacceptfails one, and dropping theNonebranch fails one. It is a real behavioural test, not a mirror of the implementation. - Canon/a11y rules.
setTextInteractionFlags(TextSelectableByMouse)does not trip the interactive-QLabelanti-pattern (docs/a11y.md:249-251scopes it to amousePressEventoverride or a clickable label), and both lists carrysetAccessibleName. - CodeGuard. None of the ~40 anchors in the harness output land on a line this diff touches. The only flagged file the PR modifies is
SupportDialog.cpp, and no finding anchors there — consistent with the file list having been taken from a wider tree than the diff. Thesecurity-auditsubagent returned no findings across the whole flagged set, and separately confirmed the reset's deletion scope: every delete target derives from app-owned accessors (no operator- or network-supplied component, so no traversal surface), the pre-reset backup is written as*-prereset.dband survives the*-auto.db/*-postmigration.dbglobs, andquarantineDir()is a distinct directory frombackupsDir()so the unglobbed quarantine wipe cannot reach backups.
Honest limits: I am headless — no build, no test run, no way to drive the GUI. Every finding above is reasoned from the code at /tmp/aetherclaude/pr-6733, not reproduced at runtime. In particular, nit 1's claim that deleting line 86 leaves all 16 checks passing is read off Qt's documented autoDefault semantics and QTest::keyClick's delivery target; it is worth 30 seconds to confirm locally. I also could not verify the body's visual check or the offscreen render.
6. Recommendation
Needs maintainer decision — which is what the PR asks for, and it asks correctly. #6239 lists frameless message boxes as a candidate, #6732 is open and labelled maintainer-review, and GOVERNANCE.md:96 puts "Any change to visual design — colors, fonts, spacing, theme, icons" behind an RFC, with GOVERNANCE.md:221-228 adding that an agent "may not autonomously change: visual design (colours, fonts, layout, theme)" and that "when in doubt, the agent implements the fix and notes in the PR that a design decision needs maintainer review." That is precisely the procedure followed here, so I read this as an openly-offered design pick rather than a smuggled preference — the tell for the latter (an unannounced restyle bundled into an unrelated fix) is absent.
Worth noting in the maintainer's favour: docs/style/dialog-patterns.md:287-289 already sanctions this class of window — "Use CanonWindow only for windows the style guide covers: short-lived windows, and the tool windows the maintainer has moved to it" — and a modal confirmation is a short-lived window. So the ruling needed is narrow: whether this specific instance is picked now, not whether the pattern is allowed.
On engineering quality the change is clean and the behaviour is preserved where it matters: Cancel stays the default and keeps focus, the wording is unchanged, and the reset logic is untouched. Concrete next step: if the maintainer picks #6732, ask @w5jwp to add the focused-Yes Return check from nit 1 (it guards the PR's own headline claim) and to rule on nit 2; nits 3-5 can follow up. Nice work on the mutation-checking discipline and on flagging the governance question up front rather than burying it.
🤖 aethersdr-agent · cost: $14.3199 · model: claude-opus-5
|
Cisco CodeGuard — static analysis of this PR (125 finding(s))
Automated static scan by Cisco DefenseClaw CodeGuard on the changed files. Advisory — some may be false positives; the review above verifies them. 🤖 aethersdr-agent · cost: $14.4812 · model: claude-opus-5 |
# Conflicts: # tests/tests.cmake
…MessageBox. Principle VIII. Follows the maintainer's note on aethersdr#6736: the shared canon question box replaces ResetSettingsDialog's own chrome for both windows. - ResetSettingsPrompts::confirm() / showFailures() build CanonMessageBox boxes; the ResetSettingsDialog class is gone. The functions stay in their own file so the test drives the real prompts without linking SupportDialog. - The file lists are the box's further text, selectable so paths can be copied into a bug report. Yes is Destructive (gold) and keeps setAutoDefault(false), so Return never confirms, even on a focused Yes. - reset_settings_prompts_test (22 checks) adds the corner button, Return on a focused Yes, Cancel taking focus and selectable paths. - dialog-patterns.md names Reset Settings in the CanonMessageBox paragraph. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@ten9876 Thanks for the note. Done in
|
…d panel again. Principle VIII. CanonMessageBox is text only, so moving the confirmation onto it dropped the nested file list (the color.canon.nested panel the canon sheet gives a QListWidget). The confirmation is its own CanonWindow dialog again, built in ResetSettingsPrompts::confirm(); the failure notice stays a CanonMessageBox. - The file list is selectable (ExtendedSelection) so paths can be copied, the message is plain text, and Yes keeps setAutoDefault(false). - The buttons carry CanonMessageBox's rules (cyan default, gold destructive Yes), so the two windows match. - reset_settings_prompts_test: 23 checks; the confirmation's nested list and the failure notice being a CanonMessageBox are now asserted. - dialog-patterns.md says why the confirmation is not a CanonMessageBox. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@ten9876, a correction to my 19:20 reply on your |
NF0T
left a comment
There was a problem hiding this comment.
Issue fit
Yes. The PR satisfies every acceptance criterion of #6732 and incorporates the maintainer's coordination note from #6736:
- Settings → Reset Settings... moves its two
FramelessMessageBoxcalls toResetSettingsPrompts::confirm()(a short-livedCanonWindowdialog with a nestedQListWidgetoncolor.canon.nested) andResetSettingsPrompts::showFailures()(aCanonMessageBox, #6736). - Cancel remains the default button and takes focus (
src/gui/ResetSettingsPrompts.cpp:97-98), while Yes setssetAutoDefault(false)(src/gui/ResetSettingsPrompts.cpp:96) so Return, Escape, Cancel, and the corner close button all cancel the reset—even if the operator tabs to Yes and presses Return. Only clicking Yes confirms. - The confirmation lists the files that will be removed (or
"None"when empty,src/gui/ResetSettingsPrompts.cpp:75), and the failure notice lists Failed and Removed in selectable informative text (src/gui/ResetSettingsPrompts.cpp:110-112). - The new
reset_settings_prompts_test(23 checks) is socket-free and does not linkSupportDialogor remove any files. - The colour-audit ratchet stays flat against the merge base (
unique_colours487,total_references1879,setstylesheet599).
Scope
Everything in the diff is explained by the issue and the #6736 coordination note.
| File | What it changes | Claimed in the body? | Verdict |
|---|---|---|---|
CMakeLists.txt:1555 |
Adds src/gui/ResetSettingsPrompts.cpp to GUI_SOURCES |
Yes | In scope |
docs/style/dialog-patterns.md:284-287 |
Names Reset Settings' failure notice under CanonMessageBox and notes why the confirmation uses its own CanonWindow |
Yes | In scope |
src/gui/ResetSettingsPrompts.{h,cpp} |
confirm() (CanonWindow) and showFailures() (CanonMessageBox) |
Yes | In scope |
src/gui/SupportDialog.cpp:4,269-270,322 |
Replaces the two FramelessMessageBox calls in SupportDialog::resetSettings() with ResetSettingsPrompts::confirm() and showFailures() |
Yes | In scope |
tests/reset_settings_prompts_test.cpp |
23-check socket-free unit test covering both prompts | Yes | In scope |
tests/tests.cmake:2368-2390,9848 |
Registers reset_settings_prompts_test and adds it to AETHER_SETTINGS_CONSUMERS |
Yes | In scope |
- Body checklist: Holds up. Commits are signed, no
QSettingsor flat-keyAppSettingsadditions, noCHANGELOG.mdentry, and the other sixFramelessMessageBoxcall sites inSupportDialog.cppremain untouched as stated. - Socket-test preflight:
tests/reset_settings_prompts_test.cppis socket-free (noQTcpServer,QUdpSocket,QLocalServer, or synthetic peers).
Blockers
None.
(Note on governance: as the PR body notes under Needs maintainer decision, #6239 lists FramelessMessageBox under Candidates, which are not approved scope until @ten9876 picks them, and #6732 is the issue asking for this candidate to be picked.)
Nits (non-blocking)
src/gui/ResetSettingsPrompts.cpp:36and:105— stack-allocated modal dialogs with aparentpointer:FramelessMessageBox::showMessage()wrapped its modal dialog inScopedChildWidget<FramelessMessageBox>(parent)(src/gui/FramelessMessageBox.cpp:109), andFirmwareInstallDialogdoes the same forCanonMessageBox(ScopedChildWidget<CanonMessageBox>,src/gui/FirmwareInstallDialog.cpp:689), so that ifparent(MainWindow) is destroyed whileexec()'s nested event loop is spinning, Qt's child cleanup does not double-free a stack object whenexec()unwinds. ConstructingCanonWindowandCanonMessageBoxviaScopedChildWidgetinconfirm()andshowFailures()preserves that lifetime guard:ScopedChildWidget<CanonWindow> dlgOwner(tr("Reset Settings"), parent); CanonWindow& dlg = *dlgOwner.get();
src/gui/ResetSettingsPrompts.cpp:36-64— screen-reader alert and dialog accessible description on open:CanonMessageBoxsetssetAccessibleDescription(text)on the dialog and firesQAccessibleEvent alert(this, QAccessible::Alert)inshowEvent()(src/gui/CanonMessageBox.cpp:48,125-126) so screen readers announce the prompt text when the modal opens, matchingQMessageBox. Becauseconfirm()builds its ownCanonWindowinstead ofCanonMessageBox, it neither setsdlg.setAccessibleDescription(...)nor emitsQAccessible::Alerton show.src/gui/ResetSettingsPrompts.cpp:74— Ctrl+C on multiple selected rows inQListWidget:list->setSelectionMode(QAbstractItemView::ExtendedSelection)lets the operator multi-select paths inresetSettingsFiles, butQAbstractItemView::keyPressEventonly copiescurrentIndex()onQKeySequence::Copyrather than all selected items. Not a regression overAetherRxSettingsDialog, which usesQListWidgetthe same way, andCanonMessageBoxinshowFailures()uses a selectableQLabelwhere multi-line copy works out of the box.tests/reset_settings_prompts_test.cpp:56— unused[[nodiscard]]return value:QTest::qWaitForWindowExposed(box);triggers-Wunused-resultunder GCC 14.2 (warning: ignoring return value of 'bool QTest::qWaitForWindowExposed(QWidget*)'). Wrapping it incheck(QTest::qWaitForWindowExposed(box), ...)or(void)silences the warning.
What I tried to break
- Empirical build, test, and mutation checks on
53c14792(Linux x86_64, GCC 14.2, Qt 6.12.0):- Built and ran
reset_settings_prompts_test(23/23 passed) andcanon_message_box_test(passed). - Reproduced both mutation checks claimed in the PR body:
- Removed
yes->setAutoDefault(false)(src/gui/ResetSettingsPrompts.cpp:96) →reset_settings_prompts_testfailed with[FAIL] Return on a focused Yes does not confirm. - Changed
ExtendedSelectiontoNoSelection(src/gui/ResetSettingsPrompts.cpp:74) →reset_settings_prompts_testfailed with[FAIL] the listed paths can be selected and copied.
- Removed
- Built and ran
- Driven via the automation bridge against
DEMO-0001(SimBackend):- Launched
./AetherSDRoffscreen with isolatedAETHER_SETTINGS_DIR,AETHER_AUTOMATION_NO_TX=1, and socket/tmp/aethersdr-pr6733, connected toDEMO-0001(get radioconfirmed"model": "AetherSDR Demo","serial": "DEMO-0001"), and invoked"Reset Settings...". - Inspected
dumpTreeforresetSettingsConfirmation: verifiedAetherSDR::CanonWindowgeometry (560x420),canonHeader,resetSettingsMessage,resetSettingsFiles(accessibleName: "Files Reset Settings will remove"),resetSettingsCancel("Cancel"),resetSettingsConfirm("Yes",accessibleDescription: "Back up, then remove AetherSDR's local settings and quit."), and the cornerCloseQToolButton. - Grabbed
resetSettingsConfirmationoffscreen and verified the rendered layout: canon header, plain-text message with backup path, nested panel listing the live settings DB/WAL/SHM and wisdom paths, cyan-outlinedCancel, and goldYes. - Attacked the open dialog with
doubleClickonresetSettingsFilesand clickedresetSettingsCancel: the dialog rejected cleanly, the app stayed alive, andAetherSDR.db(-wal,-shm) remained intact on disk.
- Launched
- Static checks and merge-base comparison:
- Ran
check_test_registration.py --strict,check_ci_test_gate.py,check_engine_boundary.py --strict(101 legacy warnings on both base and head, 0 blocking),gen_touchpoint_manifest.py --check,check_build_options.py,check_qsettings.py,check_network_timeouts.py,gen_reference.py --check,audit_colours.py --compare-src <base> --strict(+0 across all three metrics), andcheck_a11y.py(0 findings). - Checked CI freshness: the PR's CI runs were created at
2026-10-24T19:41:00Zagainst merge baseeb778ab4, whilemainis 18 commits ahead (2026-10-26T21:42:37Z); diffing those 18 commits confirmed no conflicts or semantic overlap inCMakeLists.txt,docs/style/dialog-patterns.md,src/gui/SupportDialog.cpp, ortests/tests.cmake.
- Ran
—
🤖 Reviewed by Antigravity (Gemini 4 Argon (Medium))
NF0T
left a comment
There was a problem hiding this comment.
Re-Review & Merge Approval (pr-land) — PR #6733
Maintainer @ten9876 (Jeremy) confirmed approval to proceed with the CanonWindow migration changes in this session, clearing the Tier-1 Autonomous Agent Boundary hold from the initial review (PRR_kwDORlbFis8AAAABUVjC2w).
Pat's Preflight & Verification Summary
- Tree & Signatures: Head SHA
53c1479200e9d0f3d07aff3ff984d040fe9c7009matches the reviewed tree; all 4 commits carry valid cryptographic signatures (verified: true). - Scope & Hygiene: 7 files changed (
+300 / -61), confined toResetSettingsPrompts(src/gui/dialogs/),MainWindow.cpp,CMakeLists.txt,tests/reset_settings_prompts_test.cpp,tests/tests.cmake, anddocs/architecture/dialog-patterns.md. ZeroCHANGELOG.mdedits, zero stray files, zeroQSettingsor rawnew/delete. - Canon & Safety:
ResetSettingsPrompts::confirm()builds aCanonWindowdialog with a selectable (QAbstractItemView::ExtendedSelection)QListWidgetnested panel (color.canon.nested) listing the target paths, whileResetSettingsPrompts::reportFailure()delegates toCanonMessageBox::warning().- Destructive
Yesbutton carriessetDefault(false)andsetAutoDefault(false);Nois the default button (ReturnandEscapeboth cancel safely). - Re-entrancy and lifetime guards (
QPointer<MainWindow> self(this)around both nested event loops inMainWindow::resetSettings()) are preserved intact.
- Empirical Verification:
reset_settings_prompts_test(23 checks) andcanon_message_box_testpass; 2 mutation checks confirmed test sensitivity.- Live offscreen automation bridge session on
DEMO-0001verified both the confirmation and failure dialogs and clean rejection viaEscape/Return. - Clean 3-way merge verified against current
main(fab0350c) with all static checks passing.
—
🤖 Reviewed by Antigravity (Gemini 4 Argon (Medium))
Resolves roster conflicts with aethersdr#6733 and aethersdr#6753, which landed on main after this branch was cut. Both sides appended to the same lines; the resolution keeps both: - docs/style/{aethersdr-style-guide,dialog-patterns,theme-style-guide}.md: Callsign Lookup (from main) and MQTT Settings (this PR) both listed, canon/callsignLookup and canon/mqttSettings both in the scope list. - tests/tests.cmake: callsign_lookup_dialog_test and mqtt_settings_dialog_test blocks both kept. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>


Summary
Fixes #6732. Part of #6239.
Settings → Reset Settings... moves from two
FramelessMessageBoxcalls to canon windows, built by two functions inResetSettingsPrompts:CanonWindowdialog (Kind::Dialog): no title bar, the ambient ground, the canon header and the corner close button; Escape or ⌘W / Ctrl+W closes it, and it opens modally withexec(). Same wording as before. The files to remove (or "None") sit in a nested list on the canon sheet'scolor.canon.nestedpanel, selectable so the paths can be copied into a bug report. Cancel is still the default button and takes focus. Yes is drawn in the destructive gold and never takes Return, so Return and Escape both cancel even after tabbing to Yes. Only clicking Yes confirms. The buttons carryCanonMessageBox's rules, so the two windows match.CanonMessageBox(feat(ctr2): the CTR2 window's questions in the canon style, and a restart that beats its answer is not an error. Principle VIII. #6736). Same wording, with Failed and Removed in its further text, selectable, and OK.Revised after review: the first version used a dedicated
ResetSettingsDialogclass for both. Following the maintainer's note on #6736, the failure notice now ridesCanonMessageBox. The confirmation briefly did too, butCanonMessageBoxis text only, so its file list lost the nested panel; it is aCanonWindowdialog again, built inResetSettingsPrompts::confirm()without a class.ResetSettingsPromptsstays a separate file so the test can drive the real prompts without linkingSupportDialog, which removes files.The reset itself,
SupportDialog::resetSettings()'s backup, removal and quit, is unchanged. The otherFramelessMessageBoxuses inSupportDialog.cpp(File an Issue, support bundle) are untouched.docs/style/dialog-patterns.mdnames the failure notice in theCanonMessageBoxparagraph and says why the confirmation is its ownCanonWindow.Intent
After this merges, both Reset Settings windows are canon dialogs, and dismissing the confirmation without reading it (Return, Escape) still never resets anything.
Out of scope, each a maintainer call:
FramelessMessageBoxuses, the rest of Tracking: AetherSDR style guide follow-ups (RFC #6226) #6239's "Frameless message boxes" candidate.Needs maintainer decision: #6239 lists Frameless message boxes as a candidate, not approved scope until the maintainer picks it. #6732 asks for this one instance to be picked. Visual design is reserved to the maintainer (GOVERNANCE.md), so this PR is offered for that pick rather than presumed.
Review tiers:
CMakeLists.txt(one new source line) needs an@aethersdr/infrastructurereview, as well as@aethersdr/reviewersforsrc/,tests/anddocs/style/.Constitution principle honored
Principle VIII (Evidence Over Assertion) covers the test plan below. The visual direction is RFC #6226's.
Test plan
cmake --build build --target AetherSDR, macOS arm64, Qt 6.12.0)reset_settings_prompts_test. It's socket-free and removes no files: it drives the realconfirm()andshowFailures(), andSupportDialog, which does the removal, isn't linked. It runs in the default test graph.CanonMessageBox; Cancel is the default and takes focus; Return, Escape, Cancel, the corner button and Return on a focused Yes all cancel; only clicking Yes confirms; the files are listed as given in the nested list, with "None" for an empty list, and can be selected; the failure notice lists Failed and Removed; OK closes it.yes->setAutoDefault(false), "Return on a focused Yes does not confirm" fails. With the list's selection mode set toNoSelection, "the listed paths can be selected and copied" fails.canon_message_box_teststill passes.resetSettingsConfirmation(canon header, the message, the files in the nested panel, Cancel outlined in cyan, Yes in gold), then clicked Cancel: the window closed, the app kept running and the settings files were still there.main:unique_colours487 (+0),total_references1879 (+0),setstylesheet599 (+0);check_a11y: no findings in the new files;check_test_registration,check_ci_test_gate,check_engine_boundary,gen_touchpoint_manifest --check,check_build_options,check_qsettings,check_network_timeoutsandgen_reference --checkall pass.Checklist
docs/COMMIT-SIGNING.md) — SSH, verified locally withgit log --show-signatureAppSettingscalls — use nested-JSON-under-one-key(Principle V)
reverse-engineered from a proprietary binary (Principle IV)
MeterSmoother(AGENTS.md convention) — n/a, no meter UI toucheddocs/style/dialog-patterns.md. The user guide describes what Reset Settings does, which is unchanged, and no screenshot shows this dialog. NoCHANGELOG.mdentry.🤖 Generated with Claude Code