Skip to content

A JavaFX UI for KeY - #3993

Draft
wadoon wants to merge 337 commits into
mainfrom
weigl/ocfx
Draft

wadoon wants to merge 337 commits into
mainfrom
weigl/ocfx

Conversation

@wadoon

@wadoon wadoon commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

JavaFX UI for KeY — feature-complete port + reviewer polish

This PR completes the JavaFX migration of the KeY UI (key.ui.fx + keyext.*.fx) and incorporates the reviewer-visual-test feedback. All 11 work packages are merged; the latest 20 commits fix the CI gate and address the reviewer's issue list, one commit per item.

Work packages (WP-1 … WP-11)

  • WP-1/2 window frame, menus, sequent view + proof tree (structure, filters, search, popups)
  • WP-3 strategy selection view (presets/stash, live settings), sequent printing fixes
  • WP-4/5/6 caching, exploration, slicing extension ports
  • WP-7 test generation + SMT solver runs (undoable apply, per-solver options)
  • WP-8 proof management (multi-proof TaskTree, statistics)
  • WP-9 real-flow integration asserts (autosave, minimize-interaction, source consistency, interactive contract E2E)
  • WP-10 proof-closed/input-freeze/notification flows
  • WP-11 docs switchover (FX-default build/docs, SWING-RETIREMENT.md), CI verify sweep (key.ui.fx/ci/verify-sweep.sh + 44-job push matrix in .github/workflows/ui-verify.yml)

Reviewer round (Oct 12–13)

  • CI: spotlessCheck over all modules green again (the keyext.*.fx ports had missed the format gate).
  • Drawers resizable: drawer content area and the main area (west | workspace | east) are real SplitPanes with draggable dividers; multi-panel proportions resizable; divider positions persisted in layout.properties and restored at startup.
  • "Loaded Proofs" is the first drawer item.
  • Toolbar: buttons show text beside the icons; automation + SMT are SplitMenuButtons (Swing DropdownSelectionButton parity: automation dropdown = the four proof macros, SMT dropdown = the usable solver unions; separate Start/Stop buttons removed, like Swing).
  • Notifications appear in the lower right corner; "About KeY…" is a real dialog again.
  • Settings dialog: labels top-aligned and always visible (only editors shrink); panels grow vertically (Javac Options no longer cut off); heatmap description as left-aligned subtitle.
  • Load Options dialog: button margin to the frame, checkbox aligned to the input column; profile list confirmed complete (JavaDL, JavaDL+Permissions, Well-Definedness, Information Flow via DefaultProfileResolver services).
  • Strategy panel: logarithmic slider for max rule applications (Swing MaxRuleAppSlider parity), section separators, gear menu opens at the button (was: top-left corner of the desktop).
  • Sequent view restorable via View > Show Sequent; known-types and proof-statistics dialogs grow vertically.
  • Proof tree filters factored out: ProofTreeFilterF interface + ViewSettingsFilterF; new filter = new class + one addFilter(...) line in the constructor (context menu + exclusivity derived from the list).
  • Verify harnesses moved to src/test: ProofTreeVerifyF, DialogsVerifyF, JoinMergeVerifyF, TacletMatchVerifyF and the four extension harnesses no longer ship in src/main; the app dispatches them reflectively and the run task carries the test outputs — all key.fx.verify.* flags unchanged.

Quality gates

  • Every commit gated: :key.ui.fx:spotlessApply :key.ui.fx:compileJava :key.ui.fx:test (+ full-repo spotlessCheck).
  • Local verify sweep of the affected flows (drawer, drawerlayout, treefilters, prooftree, dialogs, tacletmatch, joinmerge, proofmgmt-all, rightclickmacro) — see results below.
  • CI: CodeQuality (spotless), Tests (module tests), and the UI verify sweep (44 per-flag jobs on push, ubuntu-latest, artifacts per flag).

CI sweep greenness (second round, 6469fa9e01)

The push sweep surfaced six red flags. Compared against the previous run, five were already red before this round (red since WP-11); only drawerlayout was a regression of the Loaded-Proofs-first order. Fixed one commit each, each verified locally through the real sweep runner first:

  • dialogs — the contract e2e read the property as an example path while the recipes pass =1 as a request for the default demo (→ examples/1 not found); =1/blank now selects the default demo, real paths still override.
  • joinmerge-gcd — the recipe passes maxsteps= empty, which crashed Integer.parseInt in the harness field initializer; blank/malformed values fall back to the default.
  • proofmgmt-all — a proof load activates the proof before the Loaded Proofs view registers it, so the selection sync found no row and never retried ("highlighted row is not the selected proof"); TaskTreeF.addProof re-syncs when the selected proof's row appears.
  • drawerlayout — the reorder assertion used item 0 ("Loaded Proofs", collapsed by default — the content area only hosts expanded items); it now reorders the first expanded item.
  • minimizeinteraction — the harness's flag change raced the worker's selectedTaclet (the unarmed leg still ran armed) and the leg booleans were crossed; the legs now latch-join the FX-thread flag change and read armed = no dialog && applied, unarmed = dialog && !applied. This exposed a product bug: WindowUserInterfaceControlF.completeAndApplyTacletMatch constructed the taclet dialog Stage on the calling thread (a Stage cannot be built off the FX thread) — the construction now hops via FxUtil.runAndWait (on-FX callers unchanged), and the harness dialog watcher polls Window.getWindows() through callAndWait (FX-restricted in JavaFX 25).
  • loadingexit — the recipe never passed a demo sequent although the hook runs in the demo-load callback, so the app never reached the exit flow and the job ran into its 45-min timeout; the recipe passes the demo now (locally: exit-code=0, PASS).

The windows key.util WeakValueInternerTest failure is a pre-existing flaky concurrency test outside this port's scope (FX sources only); re-run on occurrence.

wadoon added 30 commits October 8, 2026 22:48
…layout slots F10-F12/Ctrl+F10)

* weigl/ocfx-docking:
  key.ui.fx: docking: make the shutdown layout save robust - cache the arrangement on the FX thread and persist the cached snapshot if the scene graph is already dying; hook now catches Throwable and traces to stderr
  key.ui.fx: docking: fromSwingSpec defaults unspecified modifiers to UP (Swing KeyStroke parity)
  key.ui.fx: docking: remove duplicated java.util.List import
  key.ui.fx: docking: tab context menu, maximize, named layout slots with F10-F12/Ctrl+F10, docking self test

# Conflicts:
#	key.ui.fx/build.gradle
#	key.ui.fx/src/main/java/de/uka/ilkd/key/gui/fx/MainWindowF.java
…pletion registry, IssueDialogF/AutoDismissDialogF/LogViewF)

* weigl/ocfx-seam:
  key.ui.fx: seam: load failures surface in the IssueDialogF (parity with the ProblemLoader branch of Swing taskFinishedInternal, WindowUserInterfaceControl.java:236-244)
  key.ui.fx: seam: remove duplicated shown field declaration
  key.ui.fx: seam: IssueDialogF.wasShown survives the modal dismissal (self test reports after OK)
  key.ui.fx: seam: View menu entry for LogViewF (Swing trigger is a status-line extension button; no FX extension SPI yet)
  key.ui.fx: seam: wire WindowUserInterfaceControlF into the load path, View menu log view, uicontrol self test (key.fx.verify.uicontrol)
  key.ui.fx: seam: port the Swing dialog trio (IssueDialog, AutoDismissDialog, LogView) + per-run logback file appender
  key.ui.fx: seam: WindowUserInterfaceControlF routes core callbacks into the FX window and hosts the rule-completion registry

# Conflicts:
#	key.ui.fx/build.gradle
#	key.ui.fx/src/main/java/de/uka/ilkd/key/gui/fx/MainWindowF.java
#	key.ui.fx/src/main/resources/de/uka/ilkd/key/gui/fx/theme/key-dark.css
#	key.ui.fx/src/main/resources/de/uka/ilkd/key/gui/fx/theme/key-light.css
…riants, ApplyTacletDialogF base)

* weigl/ocfx-tacletmatch:
  key.ui.fx: tacletmatch: style the redesigned dialog scene with the active theme (dark theme fix)
  key.ui.fx: tacletmatch: run the classic-dialog assertion before the destructive apply step
  key.ui.fx: tacletmatch: self test asserts the classic table dialog (render, cancel) and shows it; hold-classic screenshot mode
  key.ui.fx: tacletmatch: self test prefers proposable skolem applications (deeper candidates via getTacletAppAtAndBelow)
  key.ui.fx: tacletmatch: classic table-based completion dialog and if-selection panel
  key.ui.fx: tacletmatch: key.fx.verify.tacletmatch self test hooked into the demo load
  key.ui.fx: tacletmatch: redesigned taclet match dialog with shared apply semantics and theme styles
  key.ui.fx: tacletmatch: port match/instantiation/assumes/result-preview panels with match highlighting
  key.ui.fx: tacletmatch: port shared helpers (text, printing, styling, palette, responsive split, assumes-input logic)

# Conflicts:
#	key.ui.fx/build.gradle
#	key.ui.fx/src/main/java/de/uka/ilkd/key/gui/fx/MainWindowF.java
#	key.ui.fx/src/main/resources/de/uka/ilkd/key/gui/fx/theme/key-dark.css
#	key.ui.fx/src/main/resources/de/uka/ilkd/key/gui/fx/theme/key-light.css
…on, predicate abstraction, self test)

* weigl/ocfx-joinmerge:
  key.ui.fx: joinmerge: show the join dialog for the screenshot window
  key.ui.fx: joinmerge: synthetic merge app fallback with harness parity check
  key.ui.fx: joinmerge: fix verify chain and add merge scan diagnostics
  key.ui.fx: joinmerge: join dialog, self-test hook and theme styles
  key.ui.fx: joinmerge: merge rule completion, partner selection and predicate abstraction dialogs

# Conflicts:
#	key.ui.fx/build.gradle
#	key.ui.fx/src/main/resources/de/uka/ilkd/key/gui/fx/theme/key-dark.css
#	key.ui.fx/src/main/resources/de/uka/ilkd/key/gui/fx/theme/key-light.css
…VisualizerF, NodeInfo visualizer registry, TermLabelMenuF)

* weigl/ocfx-lemmaorigin:
  key.ui.fx: lemmaorigin: the origin-visualizer self test prefers a node whose sequent carries origin labels
  key.ui.fx: lemmaorigin: improve the term-label self test: search the proof tree for a node whose sequent prints term labels (the root sequent of a freshly loaded problem has none)
  key.ui.fx: lemmaorigin: origin term label visualizer (OriginTermLabelVisualizerF) + node info visualizer registry (NodeInfoVisualizerF)
  key.ui.fx: lemmaorigin: port the term-labels View menu (TermLabelMenuF) + hide-package-prefix and origin-tracking toggles

# Conflicts:
#	key.ui.fx/build.gradle
#	key.ui.fx/src/main/java/de/uka/ilkd/key/gui/fx/MainWindowF.java
#	key.ui.fx/src/main/resources/de/uka/ilkd/key/gui/fx/theme/key-dark.css
#	key.ui.fx/src/main/resources/de/uka/ilkd/key/gui/fx/theme/key-light.css
…ialog, javac settings (JavaFX)

Ports the remaining small-dialog packages to JavaFX in key.ui.fx:

- profileloading/: LoadingOptionsDialogF (Swing KeYFileChooserLoadingOptions
  accessory) + WDLoadOptionPanelF (well-definedness profile). The JavaFX
  FileChooser has no accessory, so options are collected in a pre-load
  dialog; Cancel aborts like the Swing chooser. MainWindowF threads the
  LoadOptions through the load path (OpenFileAction.java:70-76 parity).
- soundiness/: SoundinessAnalyzer (HTML report) + SoundinessDialogF
  (JavaFX WebView). ShowSoundinessAction lives in the View menu until the
  FX proof-list dockable exists.
- plugins/javac/: JavacSettingsProviderF, registered in SettingsManagerF
  (Swing JavacExtension settings capability; FX extension SPI not ready).
- build.gradle: add javafx.web module (WebView) and key.core.wd dependency
  (WDLoadOptionPanelF); new key.fx.verify.profileloading/.profileloadingdialog/
  .soundiness/.javacsettings self-test flags.
…ons, soundiness report, javac settings)

* weigl/ocfx-smalldialogs:
  key.ui.fx: smalldialogs: profile loading options, soundiness report dialog, javac settings (JavaFX)
  key.ui.fx: help: port HelpFacade/HelpInfo as HelpFacadeF with F1 context help and self test

# Conflicts:
#	key.ui.fx/build.gradle
#	key.ui.fx/src/main/java/de/uka/ilkd/key/gui/fx/MainWindowF.java
…ral skeleton, partition helpers, comparator)
…ter and register the exception-failure task by default (S4)
…uentMenuModelF, SequentTermContextMenuF, right-click hit test, seam-wired taclet-match dialogs)

* weigl/ocfx-termmenu:
  key.ui.fx: termmenu: route load failures through the notification center and register the exception-failure task by default (S4)
  key.ui.fx: termmenu: extend tacletmatch self test with the seam-dispatched dialog step (S4)
  key.ui.fx: termmenu: wire completeAndApplyTacletMatch to the ported taclet-match dialogs (S4 seam)
  key.ui.fx: termmenu: key.fx.verify.termmenu headless self test of the sequent context menu
  key.ui.fx: termmenu: sequent view context-menu hit test (right-click shows the sequent menu)
  key.ui.fx: termmenu: headless unit test of SequentMenuModelF (structural skeleton, partition helpers, comparator)
  key.ui.fx: termmenu: JavaFX shell for the sequent context menu (SequentTermContextMenuF)
  key.ui.fx: termmenu: headless unit test of SequentMenuModelF (structural skeleton, partition helpers)
  key.ui.fx: termmenu: pure-Java model of the sequent context menu (SequentMenuModelF)
…MT Solvers… entry (SMTSettingsProviderF), Options line in the parity self-test

- Confirm Exit / Auto Save Proofs / Minimize Interaction / Right Click for Proof Macros /
  Ensure Source Consistency as CheckMenuItems initialized from and writing back to
  ProofIndependentSettings (ViewSettings / GeneralSettings), mirroring Swing
  ToggleConfirmExitAction, AutoSave, MinimizeInteraction, RightMouseClickToggleAction,
  EnsureSourceConsistencyToggleAction. Mediator/filter/macro wiring deferred: the FX
  KeYMediatorF has no setAutoSave, the goal-view taclet filter and the direct-macro
  right-click are not wired, the FX port has no source-consistency machinery (// menu: notes).
- SMT Solvers… replaced notYetImplemented() by the real settings-dialog entry focused on the
  new SMTSettingsProviderF (registered as SettingsManagerF.SMT_SETTINGS like Swing
  SettingsManager.SMT_SETTINGS): per-solver check boxes from SolverTypes.getSolverTypes()
  (initial state containsSolver, persisted via setActiveSolver) plus the four 1:1 persisted
  toggles (show results, store SMT/taclet translation, enable-on-load); the un-ported Swing
  options stay KNOWN-DEFERRED // menu:.
- verifyMenuParityReport() gains the OPTIONS_MENU_EXPECTED table and emits the third
  'Menu parity verification (Options):' PASS/FAIL line.
…user-defined taclets + Prove submenu, About menu via HostServices, File/About in the parity self-test
@wadoon

wadoon commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

Round 3 pushed (6469fa9e01 → 7b165fc054, 13 commits), one commit per feedback item:

  1. Status line — the "Theme: … · Font size: …" text is gone (06812a1d53).
  2. Sequent view closable — the dockable is now setClosable(false); View → "Show Sequent" still restores it (ec157f626a).
  3. Startup drawer state — Loaded Proofs and Proof Tree expanded, Goal List collapsed; the drawerlayout verify assertion was updated accordingly (cc5fc6f384).
  4. Empty drawer keeps a divider — a drawer with nothing expanded now leaves the SplitPane entirely (divider vanishes) and re-inserts on expansion with the saved position (3396d8fd73).
  5. Sequent text jumps on left click — root cause: .sequent-term-highlight / .sequent-search-match-current used -fx-font-weight: bold, so the run metrics changed on rebuild. Bold dropped, accent fill kept, both themes (a07469e957).
  6. Proof-tree context menu shows nothing — the click target is often a child node of the row cell, so the cell test failed; the handler now walks up the parent chain (2406bc89bc).
  7. Context menu blocking / not vanishing — the macro popup items are label-backed CustomMenuItems whose hideOnClick defaults to false, so the popup stayed open after a click; items now close it like Swing (f6f4137b72).
  8. Heatmap buttons — both got icons (shoe-prints glyph = Swing IconFactory.HEATMAP_* parity; cog for settings) (93a6be33c4).
  9. Toolbar text — all toolbar controls are icon-only now (main helper buttons, automation/SMT split buttons, caching/testgen/heatmap extension buttons); tooltips and accessible names keep discoverability (c4516f24c5).
  10. "All active settings" tree doesn't resize — tree and panel area now share a SplitPane (Swing uses a JSplitPane with divider 0.3), so both sides scale and the divider stays draggable (bdfc285fe3).
  11. "Load KeY Taclets" — the proof-environment build now runs off the FX thread (e9907bf4a0).
  12. Missing settings providers — ported Feature Flags, Parallel Prover (single/multi-core) and the three SMT translation panels as SMT children (old-translation panel gated behind the SMT_TRANS_OPTIONS feature flag, like Swing) (ffd5800c69).
  13. Extensions missing — the Soundiness extension is ported: new ContextMenuF.getProofListContextItems SPI slot, the Loaded-Proofs right-click popup (TaskTreeF), and SoundinessExtensionF; the soundiness verify now asserts the menu item (7b165fc054).

On item 7 of the earlier list (right-click macros in the Sequent view): the FX port already follows Swing (GeneralSettings.isRightClickMacro defaults to true, so right-click shows the Strategy Macros popup; left-click shows the taclet term menu) — the rightclickmacro verify confirms both modes. The stuck-popup symptom was the hideOnClick bug above.

All locally verified through the real sweep runner: drawerlayout drawer heatmap extensions soundiness termmenu rightclickmacro smt javacsettings — all PASS.

…tion dialog

onApplyException now puts the exception message into the dialog's status
line (warning glyph + full-text tooltip) and opens the modal issue dialog,
like Swing TacletMatchDialog.ButtonListener (TacletMatchDialog.java:367-372),
instead of only logging and toasting.
The bar and both label groups now use BASELINE_LEFT/BASELINE_RIGHT so
labels and taller controls share one text line (reviewer request,
Swing MainStatusLine look).
…tton

Swing JavacExtension is StatusLine+Startup+Settings; only the settings
provider had been ported. This adds the missing extension: a status-line
button that runs the javac check on proof selection (diagnostics cached
in the proof's user data) and opens the issue list on click.

Because key.ui (Swing) is not a dependency of key.ui.fx, the facade and
its diagnostic type are ported as JavaCompilerCheckFacadeF and
PositionedIssueStringF, checked against
key.ui/plugins/javac/JavaCompilerCheckFacade.java and
gui/PositionedIssueString.java. Unlike the Swing original, the check
completion is forwarded to the FX thread instead of blocking the UI
thread with get() (Swing JavacExtension.java:126-176).
The version label becomes a read-only borderless text field so the
version string (incl. the internal revision) can be selected and copied
into bug reports.
… late

The top area grows after the root's first layout pass (icon fonts and
theme styles settle late and raise the toolbar row's preferred height)
while the BorderPane keeps the center pane at the stale top height; the
transparent center pane then covers the toolbar row — buttons stay
visible but every mouse press picks the center pane instead of the
buttons (keyboard activation is unaffected, matching the reviewer
report "mouse clicks on the toolbar are ignored, keyboard events
work"). Late size changes of the top/bottom areas are now forwarded to
the root's layout, and one extra re-stack runs after the first pulses.
Diagnosed with a synthetic-click pick log on the live app: the toolbar
click picked the center StackPane at scene (23,45) while the top
spanned 0..60.
A drawer with no expanded item used to leave the main-area split
entirely, which also removed its toggle bar — the panels became
unreachable. The drawers are now permanent split members: a drawer
without expanded items collapses to its button bar (DrawerF.
collapseToButtonBar binds the width to the live strip width, so the
split pane clamps the divider at the strip) and expanding an item
restores the saved divider position.
The drawer toggles showed rotated text only. The glyphs mirror the tab
icons of the Swing panels: ProofTreeView PROOF_TREE (Sitemap), GoalList
FLAG_CHECKERED, InfoView INFO_CIRCLE, StrategySelectionView COG,
SlicingLeftPanel SLICE_ICON (AlignJustify); the proof list, the source
view and the exploration panel get semantic list/code glyphs and the
exploration compass. Extension left-panel tabs contribute their own tab
graphic (SlicingExtensionF sets the Swing-parity glyph, which needs the
ikonli dependency in keyext.slicing.fx).
Both tabs (By Target, By Proof) now place the selection list (contract
targets / proofs) and the contract panel in a SplitPane with a draggable
divider (0.4), replacing the fixed-width BorderPane side regions.
With icons the rotated buttons grew, so the strip pushed its last
toggle into the ToolBar overflow button (hidden = unreachable). The
button bar is now wrapped in a chrome-free ScrollPane (vertical strips
scroll vertically, horizontal bars horizontally) and the buttons lose
their default padding.

The collapsed drawer is no longer bound to the laid-out strip width
(feedback loop once the scrollbar reserves width): min/max clamp to the
content-driven bar pref width plus a scrollbar allowance, re-clamped
when the strip's laid-out width becomes known at the first layout pass
(the rotated buttons' groups report zero bounds before).
@wadoon

wadoon commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

Round 4 — reviewer items 15–23 processed (each its own commit, pushed as c81b675):

# Item Commit
15 Apply-Taclet dialog: failure hint e046d7e
16 Status bar baseline alignment 535b9bc
17 Javac check extension port f529913
18 Exploration "missing" not reproducible — menu, toolbar checkboxes and the drawer tab are all present; no change
19 About dialog: copyable version 6300894
20 Drawer toggle buttons: icons ffdbbc2 (+ c81b675 scroll strip)
21 Toolbar mouse clicks ignored 6400d49
22 Drawer toggles must never vanish 83a0a24 (+ c81b675)
23 Proof Management: split pane a78f836

Details:

  • Item 21 root cause: the root's top area grows after the first layout pass (icon fonts/theme styles settle late), and BorderPane keeps the center pane at the stale top height — the transparent center pane then covers the toolbar row: buttons stay visible but every press picks the center pane (keyboard unaffected, matching the report). Diagnosed with a synthetic-click pick log on the live app (toolbar click picked the center StackPane while the top spanned 0..60). Late size changes of top/bottom now forward requestLayout() to the root, plus one extra re-stack after show. Verified by clicking Open/About on the live app — the buttons receive the press and the About dialog opens.
  • Item 22: a drawer with no expanded item no longer leaves the split (that also removed its toggle bar — the panels became unreachable). Drawers are permanent split members; an empty drawer collapses to its button bar and expanding an item restores the saved divider. Verified live: the right "Source" strip stays visible while collapsed.
  • Item 20: toggle buttons show glyphs mirroring the Swing tab icons (ProofTreeView Sitemap, GoalList FlagCheckered, InfoView InfoCircle, StrategySelectionView Cog, SlicingLeftPanel AlignJustify), semantic list/code glyphs for the proof list and source view, and the exploration compass. Extension left-panel tabs contribute their own tab graphic. Since the icon-bearing buttons are taller, the strip now scrolls instead of showing the ToolBar overflow button — all toggles stay reachable.
  • Item 19: the version label is a read-only borderless text field, so the version (incl. the internal revision) can be selected and copied into bug reports.
  • Item 23: both tabs of the Proof Management dialog place the selection list (contract targets / proofs) and the contract panel in a SplitPane with a draggable divider (0.4).

Verify sweep for the affected flags (docking proofmgmt-all extensions exploration slicing) is running locally; CI will pick the flags up on this push.

sideRight/sideBottom compared the BorderPane slot against the plain
ToolBar; the bar is wrapped in the chrome-free scroller now.
The toolbar buttons are icon-only since c4516f2 (reviewer request:
tooltips and accessible names kept, visible text dropped); the verify
still asserted Button.getText and failed. It now checks the accessible
names.
@wadoon

wadoon commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

Follow-up on the CI run for c81b675: 95 checks green, 2 sweep jobs red — both were stale verify-harness expectations against newer UI structure, no product bugs:

  • sweep (drawer): DrawerF.selfTest's sideRight/sideBottom compared the BorderPane slot against the plain ToolBar, but the bar is wrapped in the chrome-free scroll pane since c81b675 (strip scrolls instead of the overflow button hiding toggles). e86a43b compares against the wrapper. Local retest: all drawer checks PASS.
  • sweep (testgen): TestgenVerifyF still asserted Button.getText(), but the toolbar buttons are icon-only since c4516f2 (accessible names kept) — that change landed after the last all-green full sweep, so the harness drift went unnoticed until now. 88a8fcb checks getAccessibleText(). Local retest: PASS.

Also re-verified locally after these fixes: slicing PASS (my earlier local failure was a persisted ParallelProverEnabled=true in ~/.key/v3.1 from status-bar clicking experiments — the extension attaches dependency trackers only while the single-core prover is active; CI's fresh settings use the code default false, so this is env-only), and the About dialog's version line verified selectable/copyable (triple-click selects, Ctrl+C puts the full version incl. internal revision on the clipboard).

…xtension)

The settings dialog lacked the "Extension Settings" provider (Swing
ExtensionManager, key.ui/extension/ExtensionManager.java:33-150, registered by
SettingsManager.java:62 right after the SMT provider): a checkbox per
discovered extension whose state persists as forbidden class names and takes
effect on the next restart.

- ExtensionSettingsF: the persisted disabled-class set, using the same
  "Extensions"/"disabled" section and key as the Swing ExtensionSettings, so
  the Swing app and the FX app share the persisted state.
- ExtensionManagerF: the panel (Swing parity) — the "Settings will be applied
  on next restart" subtitle, the flask explanation, per extension a checkbox
  (editable iff optional, ExtensionManager.java:68), the flask marker for
  experimental ones (:74-76), the italic Provides line (:104-112) and the
  description; apply writes the unchecked class names (:139-148). Swing's
  per-extension help button is not ported (only @HelpInfo-annotated extension
  classes get one; no FX extension class carries the annotation).
- KeYGuiExtensionFacadeF: discovery filters forbidden extensions like Swing
  loadExtensions (isNotForbidden: static block list + -P<fqn>=false,
  KeYGuiExtensionFacade.java:279-283+309-315); the contribution getters use
  contributingExtensions() (Swing getExtensionsStream filters isDisabled(),
  :290-294). The experimental-feature gating of Extension.isDisabled
  (Extension.java:57-63) is deliberately not applied — the FX port contributes
  every discovered extension unconditionally (pinned by the
  key.fx.verify.extensions self test), so the checkboxes reflect exactly what
  the FX app enforces. forbidClass is ported (:429-434).
- IconFactoryF: EXPERIMENTAL_EXTENSION flask key (Swing IconFactory).

Verified live: the panel lists all 12 extensions with the provides lines and
descriptions, Exploration carries the flask, the mandatory status-line
extensions have disabled checkboxes; unchecking + Apply persists the class
name into [Extensions]/disabled, and after a restart the disabled extension
contributes nothing (its menu is gone) while all others stay.
@wadoon

wadoon commented Oct 14, 2026

Copy link
Copy Markdown
Member Author

Round 5 — the extension settings in the settings dialog (09c13c39a4)

The dialog was missing the Extension Settings provider — Swing registers it in SettingsManager.getInstance() (SettingsManager.java:62, right after the SMT provider) and it is the checkbox panel ExtensionManager (key.ui/extension/ExtensionManager.java:33-150): one checkbox per discovered extension, persisted as forbidden class names, applied on the next restart. The five extension settings panels themselves (Isabelle Translation, TestGen, Heatmap, Proof Caching, Proof Slicing) were already present — the enable/disable panel was the missing piece.

Ported in 09c13c39a4:

Piece Swing original FX port
Persisted disabled-class set ExtensionSettings (Extensions/disabled section) ExtensionSettingsF — same section and key, so Swing and FX share the persisted state
Checkbox panel ExtensionManager (ExtensionManager.java:39-148) ExtensionManagerF — subtitle "Settings will be applied on next restart", flask explanation, checkbox (editable iff optional, :68), flask marker for experimental extensions (:74-76), italic Provides: line (:104-112), description
Enforcement at restart loadExtensions filters isNotForbidden (KeYGuiExtensionFacade.java:279-283), capability streams filter isDisabled() (:290-294) KeYGuiExtensionFacadeF: discovery filter (isNotForbidden, incl. -P<fqn>=false + forbidClass), all contribution getters route through contributingExtensions()

One deliberate divergence, documented in the code: Swing's Extension.isDisabled also gates experimental extensions on their feature flag (Extension.java:57-63) — the FX port contributes every discovered extension unconditionally (the key.fx.verify.extensions self test pins the 12 discovered providers), so the checkboxes reflect exactly what the FX app enforces. Swing's per-extension help button is not ported (only @HelpInfo-annotated classes get one; no FX extension class carries it).

Verified live: the dialog now shows Extensions between SMT and Taclet Options (Swing order); the panel lists all 12 extensions with provides lines and descriptions, Exploration carries the flask, and the mandatory status-line extensions have disabled checkboxes. Unchecking + Apply persists the class name into [Extensions]/disabled immediately; after a restart the disabled extension contributes nothing (its menu is gone) while all others stay. Local sweep extensions dialogs javacsettings: all PASS.

…width

Round-5 reviewer report: the expanded strip showed a beveled blank column.
Three causes, all fixed here:
- modena styles the vertical ToolBar itself (gradient, outer border, padding
  6/5); the strip ToolBar is now transparent with padding 0
- the strip scrollbar is a child of the ScrollPane skin, not of the ToolBar,
  so the old `.drawer-button-bar .scroll-bar` selectors matched nothing; the
  scroller carries the new drawer-strip style class and all scrollbar rules
  (track, arrows, thumb) live under it, slimmed to 6px
- the wrapper's own preferred size derives from the bars' laid widths while
  they still report the modena size, and its computed minimum carries the
  modena allowance too — both win the layout and keep a dead column; the
  size is now set explicitly (pref and min) from the strip tool bar's
  preference plus the slim scrollbar whenever it is visible

The toggles are flat (transparent, hover derived from the key border, the
focus ring strictly inside the bounds), the selected slab #818181 with white
text comes from the theme stylesheets instead of inline styles, matching
TornadoFX DrawerStyles.buttonArea (DrawerStyles.kt).
File/View/Proof/Options/About carry the same VK_F/V/P/O/A mnemonics as the
 Swing main window (MainWindow.java:993,1035,1084,1165); the extension
menus stay untouched. Menu lookups in the verify hooks compare the display
text via the new menuDisplayText helper since the menu texts now carry the
mnemonic marker.
JavaFX shows a black window for a short fraction of time at startup: the
window becomes visible before the first rendered frame is composited (also
JDK-8088179). The stage is shown visually transparent and faded in after
the first rendered frame; opacity must be small but not zero because a
stage with opacity 0 is never rendered/presented. The flash while resizing
is the Glass/GTK exposed-area handling and cannot be fixed from the
application side.
@wadoon

wadoon commented Oct 14, 2026

Copy link
Copy Markdown
Member Author

All round‑5 items addressed in three commits: a733934f2a (drawer strip), b3669ca12d (menu mnemonics), dd3acf19a0 (black window flash). Local sweep green for drawer drawerlayout sequentmenu colors themepersist.

1. Blank column next to the drawer toggles — turned out to be three stacked causes, all fixed in a733934f2a:

  • modena styles the vertical ToolBar itself (gradient fill, outer border, padding 6/5), so the strip read as a beveled slab column. The strip toolbar is now chrome‑free (transparent background, padding 0).
  • the strip scrollbar is a child of the ScrollPane skin, not of the ToolBar, so the previous .drawer-button-bar .scroll-bar selectors matched nothing. The scroller now carries a drawer-strip style class and all scrollbar rules (track, buttons, arrows, thumb, vertical/horizontal) live under it; the bar is slimmed to 6 px in Java at skin time because a CSS‑only preferred width races the first layout pass.
  • the remaining gap was a stale preferred size: the scroller's own preferred (and, decisively, minimum) size derives from the bars' laid widths while those still report the modena size, so ~16 px of dead column survived every CSS/Java fix. DrawerF.updateStripSize() now sets the wrapper's preferred and minimum size explicitly to the strip toolbar's preference plus the slim scrollbar whenever that is visible (height for top/bottom docking), hooked to the toolbar's width and the scrollbar visibility listeners.

Measured after the fix (pixel probes on the running app): the west strip is exactly toggle column + 6 px scrollbar (content area starts right at the strip's edge, previously ~16 px of blank), the east collapsed strip stays 22 px, no arrows, thumb derived from the key border.

2. Toggle look — the toggles are now flat: transparent background/insets/radius, hover derived from -key-border, and the focus ring paints strictly inside the button bounds (previously modena's ring/glow protruded and visually enlarged the pressed toggle, misaligning the strip). The selected state is the #818181 slab with white text, now coming from the theme stylesheets (light and dark) instead of the previous inline styles — parity with TornadoFX DrawerStyles.buttonArea.

3. Menu mnemonics — the five built‑in menus carry the Swing main window's mnemonics (_File, _View, _Proof, _Options, _About → F/V/P/O/A, MainWindow.java:993/1035/1084/1146/1165); extension menus are untouched. Verified in the running app: the underlined letters show while Alt is armed (JavaFX platform convention) and Alt+F opens the File menu. The verify hooks that matched menu texts now compare via a menuDisplayText helper.

4. Black window flash — dd3acf19a0 shows the stage at opacity 0.01 and fades it in with two Platform.runLater hops after the first rendered frame is presented. Opacity 0 itself is unusable: such a stage is never presented and stays black permanently (tested). The flash that remains while resizing is the window system's exposed‑area handling (Glass/GTK), not something the application can suppress; with the default accelerated pipeline it is barely visible, so it is documented in the code rather than hacked around.

5. "TestGen extension is missing" — I could not reproduce this in the current state: the extension is registered (TestgenExtensionF declares @Info(name = "Test case generation")), appears in its menu, the settings panel and the extensions row of the settings dialog, and the testgen flag of the headless self‑test passes. Could you point me to where exactly you saw the message (which menu/dialog/console line)? If it came from a stale build or an earlier commit, it may already be resolved — but I'd rather chase the exact spot than guess.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants