Symptom: With dark mode enabled, the Swing main window's spectrum chrome and
menu bar were dark (FlatLaf) but tables, tabbed panes and the inner content
area were light/Metal coloured.
Root cause: LookAndFeelFactory.installJideExtension installs JIDE's
Metal-flavored UI defaults (VsnetMetalUtils etc.) into the live UIDefaults
table, overwriting FlatLaf's standard component colors and fonts for keys
like Table.background, TabbedPane.foreground, Panel.background.
Fix: After the JIDE install, walk a fresh FlatLaf UIDefaults table and put
every key back into the active defaults, skipping anything Jide-prefixed.
JIDE's UI delegate registrations live under Jide* keys that FlatLaf does
not define, so they survive untouched while the standard Swing color and
font keys are restored to their dark equivalents.
Also strengthen the JavaFX dark stylesheet: explicit borders on text fields,
tables, titled panes, split-pane dividers and separators so components have
more defining outlines in dark mode.
JIDE 3.6.18's LookAndFeelFactory contains compile-time
\`instanceof com.sun.java.swing.plaf.windows.WindowsLookAndFeel\` checks in
multiple methods, including a JIDE PropertyChangeListener that fires on every
UIManager.setLookAndFeel call. On Linux and macOS JDKs the class is genuinely
absent from java.desktop, so the JVM throws NoClassDefFoundError the first time
JIDE's dispatch code is executed (during JFrame init and again from
JideSplitPane.updateUI on each LAF change).
Two complementary fixes:
1. Pass an explicit MetalLookAndFeel instance to the 3-arg
installJideExtension(UIDefaults, LookAndFeel, int) overload so JIDE's Metal
branch matches first and never falls through to the Windows branch in the
normal install path.
2. Add a no-op stub class at com.sun.java.swing.plaf.windows.WindowsLookAndFeel
so that the compile-time class reference resolves on non-Windows JDKs. The
stub reports isSupportedLookAndFeel = false and is never instantiated -
JIDE only uses it for instanceof comparisons against the active LAF, which
always return false in our setup. On Windows JDKs the real class in
java.desktop is loaded by the platform classloader and shadows this stub.
- Apply Swing LAF synchronously on the calling thread so the main JFrame's RootPane
has a populated UIDefaults set when constructed. Previously the LAF install was
scheduled via EventQueue.invokeLater, so JFrame construction raced ahead and threw
"no ComponentUI class for: javax.swing.JPanel".
- Call LookAndFeelFactory.installJideExtension(VSNET_STYLE) with an explicit style
instead of the no-arg auto-detection variant. The auto-detection path probes
com.sun.java.swing.plaf.windows.WindowsLookAndFeel via Class.forName, which is
absent on non-Windows JDKs and threw ClassNotFoundException at startup.
- Bounce only the SwingUtilities.updateComponentTreeUI walk through the EDT so it
redraws already-realized windows on theme toggle.
- Add darkMode boolean preference to ApplicationPreference (persisted via java.util.prefs)
- Add ToggleSwitch labeled "Dark Mode" to ApplicationPreferenceEditor
- Add ThemeManager singleton that listens for preference updates and applies/removes
the dark stylesheet to all registered JavaFX Scenes and swaps the Swing LAF
- Add sdrtrunk_dark.css with dark styling for controls, tables, menus, dialogs, charts
- Add FlatLaf dependency for full Swing dark theming (replaces previous OS-specific
MetalLookAndFeel setup; FlatLaf works cross-platform)
- Register all Stages created in JavaFxWindowManager with the ThemeManager and walk
Window.getWindows() at apply-time so unregistered dialogs/alerts also pick up the theme
- Add Foojay toolchain resolver to settings.gradle so Gradle can auto-provision JDK 25