summaryrefslogtreecommitdiffstats
path: root/docs/superpowers
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-19 10:46:45 +0200
committerDanilo M. <danix@danix.xyz>2026-08-19 10:46:45 +0200
commita36fff5617f16ac1d17c0c52f2112a20c4fa9336 (patch)
tree7da72c963d071fe1563a4b4d9912b03dfad6d21a /docs/superpowers
parent98918f4c5f4e05aef1309de823e78da1f50c732d (diff)
downloadqtmaildir-a36fff5617f16ac1d17c0c52f2112a20c4fa9336.tar.gz
qtmaildir-a36fff5617f16ac1d17c0c52f2112a20c4fa9336.zip
feat(pane): offer Select all, and report what a copy copied
Items 115 and 117, both from the user's notes. Select all was never in Chromium's menu for this pane, measured by hand with a selection active and against a build with removeBrowserActions() reverted, so the filter is not what removed it. MessageView::addPaneActions() supplies it, static and taking the menu, mirroring removeBrowserActions() beside it. Two comments claiming the standard menu already offered it are corrected; either would have sent the next reader down the same three wrong theories the item records. The copy entries all worked and none of them said so. Four now report through the pane's existing statusMessage, each naming what it copied rather than saying "Copied", which is the item's own constraint when three of them sit together in one menu. Connected to the page's own QActions, so the report follows the entry wherever it is triggered from. The two differ in what can be tested, and the tests say so rather than papering over it. The copy path is fully covered: triggering the action runs the production path, and mutations for a duplicated message and an unwired entry both fail. addPaneActions() is covered, but showBodyContextMenu() CALLING it is not and cannot be, since createStandardContextMenu() returns nothing outside a real context-menu event; a mutation deleting that call leaves the suite green, measured. The call site is a hand test and the test file records that so nobody adds an assertion that appears to cover it. The copy strings are QT_TR_NOOP inside an array, which CLAUDE.md warns extracts nothing at file scope. Verified rather than assumed: lupdate found all four under the MessageView context, because the array sits inside a member function. 387 finished, 0 unfinished. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'docs/superpowers')
-rw-r--r--docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md124
-rw-r--r--docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md92
2 files changed, 126 insertions, 90 deletions
diff --git a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md
index ef51b5c..783e4ed 100644
--- a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md
+++ b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md
@@ -6699,3 +6699,127 @@ database directly.
**Verified:** clean build with no warnings from any changed file, 24 of 24
suites over three consecutive runs, 211 tests in `test_mainwindow`. Every one of
the spec's six testing bullets has a test, each mutation-checked.
+
+## 115. A copy from the message pane gives no confirmation
+
+**Observed (user, 2026-08-17):** Copy link address, Copy image address and Copy
+image all work, and none of them says so. The user asked for "a small
+'link copied' transient that appears and disappears after a few seconds".
+
+**Cause:** not a defect, unbuilt. These are Chromium's own menu entries and it
+does not report success; nothing in this application is listening to them.
+
+**Copy image was thought to be broken and is not**; see item 116 in the
+closed-items file, which is worth reading for how a stale clipboard reading
+produced a confident wrong cause.
+
+All three work. Copy image was briefly filed as broken (item 116) and is not:
+the pixels reach the clipboard correctly, and the reading that said otherwise
+was taken off a stale clipboard. So this item covers the confirmation for Copy
+link address, Copy image address and Copy image alike.
+
+**Approach.** `MessageView::statusMessage` already exists and the status bar
+already expires its messages (item 33), so this is one connection per action and
+no new widget, no new timer. `QWebEnginePage::action()` gives each entry's
+QAction; connect `triggered` and emit the appropriate string.
+
+**Constraints.**
+
+- The message must name what was copied. "Copied" alone is worse than nothing
+ when three entries sit next to each other in the same menu.
+- Do not build a floating overlay for this. The status bar is where this
+ application reports transient results, and a second mechanism for the same
+ job is the kind of thing item 45 recorded when two Sync buttons disagreed.
+- Depends on nothing; can be built alongside 114 since both touch the same menu.
+
+**Size: XS.**
+
+**Built 2026-08-19.** Four entries report through the pane's existing
+`statusMessage`: Copy, Copy link address, Copy image and Copy image address,
+each naming what it copied rather than saying "Copied". Connected to the PAGE's
+own QActions in the constructor, which are the same instances the standard
+context menu holds, so the report follows the entry wherever it is triggered
+from and no menu of ours is involved.
+
+That is also what makes this fully testable, unlike item 117 beside it:
+triggering the action runs the production path with no context-menu event
+needed. The test enables each action first, since Chromium disables a copy entry
+when there is nothing of that kind under the cursor and `trigger()` on a
+disabled QAction emits nothing at all, which would have left the loop asserting
+nothing while looking thorough. Two mutations fail it: a duplicated message, and
+one entry left unwired.
+
+The strings are `QT_TR_NOOP` inside an array, which CLAUDE.md warns extracts
+NOTHING at file scope. Verified rather than assumed: `lupdate` found all four
+under the `MessageView` context with no warning, because the array sits inside
+a member function where the class context exists.
+
+## 117. The message pane offers no Select all
+
+**Observed (user, 2026-08-17):** right-clicking a body selection offers Copy and
+the search entries, and no Select all. Noticed while hand-testing item 100.
+
+**NOT caused by item 100, and this was verified rather than argued.** The user
+ran a build with `src/messageview.cpp` and `src/messageview.h` reverted to HEAD,
+so `removeBrowserActions()` did not exist, and reported the same menu: Copy and
+the search entries only. Chromium's standard menu for this pane has never
+carried Select all.
+
+**Three wrong theories preceded that measurement**, which is the part worth
+recording, because each was plausible and each cost a round trip:
+
+1. *The separator sweep removed it.* Disproved with a standalone program
+ reproducing the sweep against a realistic menu: it drops the leading
+ separator and keeps every action.
+2. *Chromium omits it when there is no selection.* Killed by the user, who had a
+ selection at the time.
+3. *A probe will show what the real menu holds.* `createStandardContextMenu()`
+ returns NULL outside an actual context-menu event, on the offscreen platform
+ and on a real display alike, so two probe attempts measured nothing.
+
+The lesson is the one item 100 had already written down and the agent did not
+follow: **a menu built by hand proves nothing about the menu Chromium builds.**
+`theBodyMenuDropsTheBrowsersOwnActions` constructs its own QMenu, which is right
+for testing the filter and useless for testing what is offered. That test now
+says so, and deliberately does NOT assert on SelectAll, since a passing
+assertion there would read as a guarantee the code does not make.
+
+**Approach.** Add it explicitly rather than hoping Chromium supplies it. The
+action already exists as `QWebEnginePage::SelectAll` and works; only the menu
+entry is missing.
+
+- `menu->addAction(page->action(QWebEnginePage::SelectAll))` in
+ `showBodyContextMenu`, placed beside Copy rather than appended after the
+ search entries.
+- Worth considering a `Ctrl+A` binding for the pane at the same time, though
+ note the pane is not the only focusable widget and the query bar has its own
+ claim on that key. Check `KeyMap::defaultBindings()` before adding one.
+
+**Constraints.**
+
+- **A test for this cannot use a hand-built menu.** That is the trap above. The
+ honest options are asserting the action is in the menu the production code
+ returns, which needs a real context-menu event, or leaving it to a hand test
+ and saying so. Do not write a test that constructs a QMenu and calls it
+ covered.
+- Select all selects the rendered body, not the header label, which is a
+ separate widget with its own selection. That is probably the desired
+ behaviour but should be looked at rather than assumed.
+
+**Size: XS.**
+
+**Built 2026-08-19** as `MessageView::addPaneActions()`, static and taking the
+menu, mirroring `removeBrowserActions()` beside it. Two stale comments went with
+it: both `showBodyContextMenu()` and the header of `removeBrowserActions()`
+claimed Select all was among the entries the standard menu supplied and that the
+filter preserved. Neither was true, and either would have sent the next reader
+back down the same three wrong theories.
+
+**The call site is not covered, and the test says so rather than pretending.**
+`addPaneActions()` has a test and a mutation dropping the entry fails it. A
+mutation deleting the CALL from `showBodyContextMenu()` leaves the whole suite
+green, measured, because `createStandardContextMenu()` returns nothing outside a
+real context-menu event and the offscreen platform cannot deliver one. The
+honest options the entry named were an assertion on the production menu or a
+hand test; the first is impossible here, so it is the second, recorded in the
+test so nobody adds an assertion that appears to cover it.
diff --git a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
index 335b3d3..be52da9 100644
--- a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
+++ b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
@@ -179,9 +179,9 @@ taking that too literally.
| 112 | Toggle unread on a whole thread cannot reach "all unread" on a partly-read thread | defect | S | open, found 2026-08-17. A toggle over a UNION has no direction on a mixed thread |
| 113 | No way to see a message's HTML source | information | S | open, 2026-08-17. Chromium's own View source cannot work here; needs our own plain-text dialog. Item 100 removed the dead entry, which was an overreach: the user had not asked for it |
| 114 | Save image is offered on every image and does nothing | defect | S | open, found 2026-08-17 by right-clicking a real image. No `downloadRequested` handler exists anywhere, so the request is emitted and never answered |
-| 115 | A copy from the message pane gives no confirmation | presentation | XS | open, 2026-08-17. Copy link address, Copy image address and Copy image all work, silently. `statusMessage` already exists and already expires |
+| 115 | A copy from the message pane gives no confirmation | presentation | XS | **done** 2026-08-19, unreleased. Four entries report, each naming what it copied; connected to the page's own QActions, so the entry is covered wherever it is triggered from |
| 116 | Copy image copies markup instead of the image | defect | XS | **dropped** 2026-08-17, same day. NOT A DEFECT: `wl-paste --list-types` run immediately after a copy reports `image/png`, `application/x-qt-image` and 30 more image flavours. The clipboard is correct and Chromium is behaving. The earlier "text only" reading was taken minutes late off a clipboard that had been overwritten, and a whole cause was theorised on it |
-| 117 | The message pane offers no Select all | workflow | XS | open, found 2026-08-17. NOT caused by item 100: verified by hand against a build with that filter reverted, and the menu holds Copy and the search entries either way |
+| 117 | The message pane offers no Select all | workflow | XS | **done** 2026-08-19, unreleased. `addPaneActions()` supplies it. The call site is NOT covered by a test and cannot be: the production menu needs a real context-menu event. Stated in the test rather than faked |
| 118 | No way to empty the trash from inside the app | workflow | S | open, 2026-08-17. **Blocked on 103**, which creates the trash in the first place. Deliberately left out of 103's spec at the user's request rather than squeezed in |
| 119 | The unsynced-changes count cannot be opened to see what it counts | information | S | open, 2026-08-19, from the notes. One of the four things it sums carries no message ids at all, so a list cannot be complete without a change to how the count is kept |
@@ -717,94 +717,6 @@ for the network to satisfy it.
**Size: S.**
-## 115. A copy from the message pane gives no confirmation
-
-**Observed (user, 2026-08-17):** Copy link address, Copy image address and Copy
-image all work, and none of them says so. The user asked for "a small
-'link copied' transient that appears and disappears after a few seconds".
-
-**Cause:** not a defect, unbuilt. These are Chromium's own menu entries and it
-does not report success; nothing in this application is listening to them.
-
-**Copy image was thought to be broken and is not**; see item 116 in the
-closed-items file, which is worth reading for how a stale clipboard reading
-produced a confident wrong cause.
-
-All three work. Copy image was briefly filed as broken (item 116) and is not:
-the pixels reach the clipboard correctly, and the reading that said otherwise
-was taken off a stale clipboard. So this item covers the confirmation for Copy
-link address, Copy image address and Copy image alike.
-
-**Approach.** `MessageView::statusMessage` already exists and the status bar
-already expires its messages (item 33), so this is one connection per action and
-no new widget, no new timer. `QWebEnginePage::action()` gives each entry's
-QAction; connect `triggered` and emit the appropriate string.
-
-**Constraints.**
-
-- The message must name what was copied. "Copied" alone is worse than nothing
- when three entries sit next to each other in the same menu.
-- Do not build a floating overlay for this. The status bar is where this
- application reports transient results, and a second mechanism for the same
- job is the kind of thing item 45 recorded when two Sync buttons disagreed.
-- Depends on nothing; can be built alongside 114 since both touch the same menu.
-
-**Size: XS.**
-
-## 117. The message pane offers no Select all
-
-**Observed (user, 2026-08-17):** right-clicking a body selection offers Copy and
-the search entries, and no Select all. Noticed while hand-testing item 100.
-
-**NOT caused by item 100, and this was verified rather than argued.** The user
-ran a build with `src/messageview.cpp` and `src/messageview.h` reverted to HEAD,
-so `removeBrowserActions()` did not exist, and reported the same menu: Copy and
-the search entries only. Chromium's standard menu for this pane has never
-carried Select all.
-
-**Three wrong theories preceded that measurement**, which is the part worth
-recording, because each was plausible and each cost a round trip:
-
-1. *The separator sweep removed it.* Disproved with a standalone program
- reproducing the sweep against a realistic menu: it drops the leading
- separator and keeps every action.
-2. *Chromium omits it when there is no selection.* Killed by the user, who had a
- selection at the time.
-3. *A probe will show what the real menu holds.* `createStandardContextMenu()`
- returns NULL outside an actual context-menu event, on the offscreen platform
- and on a real display alike, so two probe attempts measured nothing.
-
-The lesson is the one item 100 had already written down and the agent did not
-follow: **a menu built by hand proves nothing about the menu Chromium builds.**
-`theBodyMenuDropsTheBrowsersOwnActions` constructs its own QMenu, which is right
-for testing the filter and useless for testing what is offered. That test now
-says so, and deliberately does NOT assert on SelectAll, since a passing
-assertion there would read as a guarantee the code does not make.
-
-**Approach.** Add it explicitly rather than hoping Chromium supplies it. The
-action already exists as `QWebEnginePage::SelectAll` and works; only the menu
-entry is missing.
-
-- `menu->addAction(page->action(QWebEnginePage::SelectAll))` in
- `showBodyContextMenu`, placed beside Copy rather than appended after the
- search entries.
-- Worth considering a `Ctrl+A` binding for the pane at the same time, though
- note the pane is not the only focusable widget and the query bar has its own
- claim on that key. Check `KeyMap::defaultBindings()` before adding one.
-
-**Constraints.**
-
-- **A test for this cannot use a hand-built menu.** That is the trap above. The
- honest options are asserting the action is in the menu the production code
- returns, which needs a real context-menu event, or leaving it to a hand test
- and saying so. Do not write a test that constructs a QMenu and calls it
- covered.
-- Select all selects the rendered body, not the header label, which is a
- separate widget with its own selection. That is probably the desired
- behaviour but should be looked at rather than assumed.
-
-**Size: XS.**
-
## 118. No way to empty the trash from inside the app
**Observed (user, 2026-08-17):** raised while reviewing item 103's spec, as