Class SJRootPane

java.lang.Object
com.vaadin.flow.component.Component
com.vaadin.flow.component.HtmlComponent
com.vaadin.flow.component.HtmlContainer
com.vaadin.flow.component.html.Div
com.vaadin.swingbridge.surrogates.SJRootPane
All Implemented Interfaces:
com.vaadin.flow.component.AttachNotifier, com.vaadin.flow.component.ClickNotifier<com.vaadin.flow.component.html.Div>, com.vaadin.flow.component.DetachNotifier, com.vaadin.flow.component.HasComponents, com.vaadin.flow.component.HasComponentsOfType<com.vaadin.flow.component.Component>, com.vaadin.flow.component.HasElement, com.vaadin.flow.component.HasEnabled, com.vaadin.flow.component.HasOrderedComponents, com.vaadin.flow.component.HasSize, com.vaadin.flow.component.HasStyle, com.vaadin.flow.component.HasText, ComponentMixin, ContainerMixin, JComponentMixin, Serializable

@StyleSheet("emul/swindow.css") public class SJRootPane extends com.vaadin.flow.component.html.Div implements JComponentMixin
Surrogate for JRootPane per SD_sjframe. Extends Div (so it carries JComponentMixin's client-property / border / PCE surface and participates in Registrations lookups) and holds the root-pane state JDK migrations expect: content / layered / glass pane references plus the default-button wiring with the Enter-key shortcut install.

Structural, and the containment is the JDK's

The Div base is the containment. A root pane holds {glassPane, layeredPane}, and the layered pane holds {menuBar, contentPane} — the JDK's own shape, which its class doc states outright: "(The JLayeredPane manages the menuBar and the contentPane.)" Both of the layered pane's children go into the same FRAME_CONTENT_LAYER, so the layered pane is not stacking them in z; RootLayout stacks them in y, reaching through the layered pane to do it. That y-stacking is reproduced as CSS — root pane a flex column, layered pane display: contents, bar flex: 0 0 auto, content pane flex: 1 1 auto — so the pane a migrator reaches through is the pane that renders. Classes and measurements live in emul/swindow.css.

Panes are created lazily, on first read, and attached as they are created; a root pane nobody reaches through allocates nothing. The JDK builds all three in its constructor, which the emulator layer reproduces by pushing its own AWT-typed panes' peers down through these setters before any getter runs (the two-layer typed-holder split, as with SJSlider's model). So the JDK call order is faithful where it is observable, without every surrogate window paying for three Divs it never shows.

Default-button Enter shortcut (only browser-side concern)

setDefaultButton(Button) installs a Vaadin Shortcuts registration: Enter anywhere in the UI fires the button's click, unless the focused component claims that Enter for itself — a text area's newline, a formatted field's commit (EnterClaims). The Button itself is the lifecycle owner — detach or GC removes the shortcut. Replacing or clearing the default button tears down the previous registration before wiring the new one so Enter doesn't briefly double-trigger during the swap. The click body funnels through SHelper.callSwing(Runnable) per R_callswing_envelope.

What the layered and glass panes do and do not do

Both are structural — they render, and the glass pane curtains. What stays unimplemented is the JDK's z-order use of the layered pane: layer constants round-trip but do not reorder anything, since Vaadin renders in DOM order and the components that would need real layering (JInternalFrame) render as Dialog overlays instead per D_internal_frames. The glass pane's one accepted gap is keyboard focus: it swallows mouse input but tab still reaches components behind it, exactly as real Swing's does unless the app also grabs focus (D_glasspane_structural/SD_glasspane_structural).

Standalone use

A pure-surrogate caller can new SJRootPane() directly and it now renders: the panes attach themselves as they are lazily created, so adding the root pane to any Vaadin container gives a working root-pane-alike. This retires SD_sjframe's pure-surrogate-rendering limitation. The one thing a standalone pane cannot do is size itself against a window body — the emul-has-contentpane half of the chain is applied by whoever owns the host (see SHelper.markContentPaneSpan(Component, Component, Component)).
See Also:
  • Field Details

  • Constructor Details

    • SJRootPane

      public SJRootPane()
  • Method Details

    • getContentPane

      public com.vaadin.flow.component.Component getContentPane()
      The content pane, lazy-created and planted inside the layered pane on first read (which lazily creates that too) — JDK's "lazy default content pane" contract, made structural.
    • setContentPane

      public void setContentPane(com.vaadin.flow.component.Component newPane)
      Plant newPane as the layered pane's content child. JDK contract: null throws IllegalComponentStateException. Replacement does NOT migrate children (same as JRootPane.setContentPane) — callers that want to keep content must re-add to the new pane.

      Planted at the end of the layered pane, so a menu bar already present stays above it: the CSS column takes its order from the DOM, where RootLayout takes it from the menuBar field.

    • createContentPane

      protected com.vaadin.flow.component.Component createContentPane()
      Factory for the default content pane, called from getContentPane(). The JDK's returns a JPanel with a BorderLayout; a bare Div is the equivalent here, since the layout managers write their CSS onto whatever element they are given.
    • getLayeredPane

      public com.vaadin.flow.component.Component getLayeredPane()
      The layered pane, lazy-created and planted on first read.
    • setLayeredPane

      public void setLayeredPane(com.vaadin.flow.component.Component layered)
      Null throws IllegalComponentStateException per JDK.

      Faithfully does not migrate the menu bar or content pane into the new pane — the JDK's setLayeredPane only swaps its own child, leaving them parented to the outgoing pane, which is why nothing but a look-and-feel ever calls it.

    • createLayeredPane

      protected com.vaadin.flow.component.Component createLayeredPane()
      Factory for the default layered pane, called from getLayeredPane().
    • getGlassPane

      public com.vaadin.flow.component.Component getGlassPane()
      The glass pane — structural, and invisible by default as in the JDK, so a later setVisible(true) actually curtains the window body and swallows mouse input beneath it (D_glasspane_structural/SD_glasspane_structural).
    • setGlassPane

      public void setGlassPane(com.vaadin.flow.component.Component glass)
      Plant glass as this pane's first child — the JDK's index as well as its containment (rootPane.add(glassPane, 0)). Null throws IllegalComponentStateException per JDK.

      Visibility is the pane's own concern: an invisible glass pane is display: none, so the default neither paints nor blocks. The incoming pane's visibility is left as the caller set it, matching the JDK's documented "either order works" contract for swap-then-show.

    • createGlassPane

      protected com.vaadin.flow.component.Component createGlassPane()
      Factory for the default glass pane, called from getGlassPane(). The JDK's is an invisible transparent JPanel; ours is an invisible Div.
    • getJMenuBar

      public SJMenuBar getJMenuBar()
      null until setJMenuBar(SJMenuBar) plants one.
    • setJMenuBar

      public void setJMenuBar(SJMenuBar bar)
      Plant bar at index 0 of the layered pane, above the content pane — the JDK's containment (layeredPane.add(bar, FRAME_CONTENT_LAYER)), with the CSS column supplying what RootLayout supplies there. Pass null to detach.

      Index 0 is load-bearing here in a way it is not in Swing: RootLayout reads the menuBar field and ignores add order, while a flex column reads DOM order.

    • getDefaultButton

      public com.vaadin.flow.component.button.Button getDefaultButton()
      Currently-installed default button, or null when cleared.
    • setDefaultButton

      public void setDefaultButton(com.vaadin.flow.component.button.Button button)
      Install button as the root pane's default button — Enter anywhere inside the enclosing window triggers its click, unless the focused component claims it (EnterClaims). Replacing or clearing tears down the previous Enter shortcut first so the swap window doesn't double-trigger.

      Scoped via button as the listener owner — detach or GC of the button removes the shortcut automatically (UI-scoped shortcut with button-tied lifecycle, matching JDK's WHEN_IN_FOCUSED_WINDOW shape).

      Click body funnels through SHelper.callSwing(Runnable) per R_callswing_envelope. Fires "defaultButton" PCE on the surrogate's listener list; the emulator wrapper fires its own PCE on its own layer (two-layer convention, same as SJSlider / SJSpinner / SFrame).

    • setLayerEnterClaims

      public void setLayerEnterClaims(com.vaadin.flow.function.SerializablePredicate<com.vaadin.flow.component.Component> claims)
      Adds Enter claims the surrogates cannot know to the ones they declare as EnterClaims.Claimants:
      rootPane.setLayerEnterClaims(peer -> ComponentUtil.getData(peer, vaadinx.awt.Component.class)
              instanceof JTextField tf && tf.getActionListeners().length > 0);
      
      Parameters:
      claims - asked of the focused component and each ancestor below this pane, including ones that are no layer's peer
    • getUIClassID

      public String getUIClassID()
      JDK parity — some user code reads this reflectively for UIManager registration.
      Specified by:
      getUIClassID in interface JComponentMixin