Class EHelper
vaadinx.* emulator — hand-written,
so it lives outside the generated vaadinx.awt.Component that would
otherwise clobber it on regeneration. A grab-bag by design; the members
cluster into seven families:
- Incompleteness hooks (R_match_swing_errors/D_never_fail_on_gaps) —
onUnimplemented(String, String, Object...),onUnsupported(String, String, Object...),onNoop(String, String),onUnsupportedPeerShape(String, String): WARN (or DEBUG/ERROR) and continue, never throw. - Thread hygiene —
checkUIThread(): the once-per-JVM report that emulator code reached its peer off the Vaadin UI thread, wired intoComponent.getPeer(); andrunInUIThread(boolean, Runnable), the synchronous Swing→peer write hop that lets such code work anyway. - The R_callswing_envelope callback seam —
callSwing(Runnable): the virtual-thread envelope every peer→Swing listener funnels through. - Live-UI resolution —
singleLiveUI(VaadinSession),onSessionLiveUI(VaadinSession, Runnable),awaitModal(Component, CompletableFuture): finding the one UI an app lives in across an F5 teleport (viaAppTab, D_session_scoped_pools/D_active_ui_pointer). - Peer↔emulator registry —
onCreated(Component, Component),getEmulator(Component), and the id/name stamping (applyEmulatorId(Component, String)). - Window registry —
getWindows()plus the three call-graph edges that feed it (onWindowCreated(Window),onWindowDisplayable(Window),onWindowUndisplayable(Window)) overWindowRegistry, whose undisplayable edge also armsAutoShutdown. - Enumeration + conversion —
getDialogs(),toVaadinIconComponent(String, Icon).
callSwing(Runnable) requires a current
UI; the live-UI family must hold the session lock.-
Field Summary
FieldsModifier and TypeFieldDescriptionTest-only capture sink foronUnimplemented(String, String, Object...),onUnsupported(String, String, Object...), andonUnsupportedPeerShape(String, String). -
Method Summary
Modifier and TypeMethodDescriptionstatic voidapplyChildCss(com.vaadin.flow.dom.Element target, Map<String, String> css) Apply per-child layout CSS to a single child's element — the counterpart toapplyContainerCss(Element, String, Map)for the per-child leg of aCssEmittingLayoutManagerpass (grid-area,justify-self,margin, …).static voidapplyContainerCss(com.vaadin.flow.dom.Element target, String layoutManagerName, Map<String, String> css) Apply a block of layout CSS to a Container's peer content element per D_layout_css_on_content.static voidapplyEmulatorId(com.vaadin.flow.component.Component peer, String name) Map a Swing name to the peer's HTML id, with a per-UI suffix counter to keep ids unique when two components share a Swing name (Swing'snamehas no uniqueness requirement; HTML'siddoes).static <T> TawaitBrowserRoundTrip(com.vaadin.flow.component.Component anchor, CompletableFuture<T> future) Waits for a browser round-trip — anexecuteJsresult, anExtendedClientDetailsrefresh — withFuture.get()'s contract.static voidawaitModal(com.vaadin.flow.component.Component anchor, CompletableFuture<?> closed) The modal-park seam: parks the calling UI fiber untilclosedcompletes, the session lock released so the click that closes the dialog can get in.static <T> TcallOnLiveUISync(com.vaadin.flow.server.VaadinSession session, Supplier<T> body) Runsbodyon the session's single live UI and returns its value to the calling background thread, blocking until it completes.static voidThe R_callswing_envelope seam: runsrunnable— a peer listener's Swing-side body — on a virtual thread so it can park on a modal dialog without blocking the Vaadin request thread.static voidReports, once per JVM, that emulator code reached its Vaadin peer from off the Vaadin UI thread.static ComponentemulatorFor(com.vaadin.flow.component.Component peer) Lenient, walking variant ofgetEmulator(Component): the emulator owningpeer, or the one owning its nearest Vaadin ancestor, ornullwhen no ancestor is a registered peer.static List<com.vaadin.flow.component.dialog.Dialog> EveryDialogattached to the current UI's component graph — the Vaadin-side view of our Windows.static ComponentgetEmulator(com.vaadin.flow.component.Component peer) The emulator (Component) whose peer is the given Vaadin component.EveryWindowthis app instance has constructed and not yet let go of, in construction order — the source of truth behindWindow.getWindows(),Window.getOwnerlessWindows()andFrame.getFrames().static booleanisShuttingDown(VaadinSession)for the current session — the form the throw-seams use, since they run inside the dispatch where the current session is set.static booleanisShuttingDown(com.vaadin.flow.server.VaadinSession session) static voidmarkShuttingDown(com.vaadin.flow.server.VaadinSession session) Marks the session as shutting down — set once at the top of the session-destroy →WINDOW_CLOSINGdispatch (D_shutdown_lifecycle), before any userWindowListenerruns.static voidRegister the 1:1 mappingpeer → emulator.static voidDeliberate no-op hook for Swing API that's redundant in the Vaadin world (layout invalidation, repaint, peer lifecycle).static voidonSessionLiveUI(com.vaadin.flow.server.VaadinSession session, Runnable swingBody) Delivers a Swing-side callback (aTimerfire, aSwingWorkerdone()/process()/PCE) onto the session's single live UI, from a non-UI thread (a scheduler or worker thread that holds no lock).static voidonUnimplemented(String className, String method, Object... args) Warn-and-continue stub hook.static voidonUnsupported(String className, String method, Object... args) Swing method we *have* implemented, but the underlying Vaadin peer can't honour this particular call — e.g.static voidonUnsupportedPeerShape(String className, String situation) ERROR-log hook for situations where emulation is fundamentally unable to honor a well-formed Swing request and the safest response is to do nothing — e.g. setting aLayoutManageron a Container whose peer content element isn't a plain<div>(D_layout_css_on_content).static voidstatic voidTheaddNotify()->allWindows.add(this)edge.static voidTheremoveNotify()->allWindows.remove(this)edge, and the one place a Window stops being displayable — so also whereAutoShutdownlearns the app may be over.static voidrelayModelEvent(Runnable runnable) Relays a surrogate's Swing-model event to the emulator's own listeners: throughcallSwing(Runnable)when a UI is current, inline on the calling thread otherwise.static voidreportUncaught(com.vaadin.flow.server.VaadinSession session, Throwable t) Hands an uncaught throwable to the session'sErrorHandler, acquiring the session lock first if the caller doesn't already hold it — the emulator'sEventDispatchThread.processException.static voidresetContainerCss(com.vaadin.flow.dom.Element target) Clear a container's layout CSS — the undo forapplyContainerCss(Element, String, Map), called fromContainer.setLayout(LayoutManager)when oneLayoutManagerreplaces another.static voidrunInUIThread(boolean callerPlansToBlockAfterwards, Runnable body) Runsbodyon the Vaadin UI thread and returns only once it has run — the seam a Swing→peer write goes through when it may be called from a background thread.static com.vaadin.flow.component.UIsingleLiveUI(com.vaadin.flow.server.VaadinSession session) The one UI an app lives in — the delivery target for an emulatorTimerfire, aSwingWorkercallback, and a parkedcallSwing(Runnable)continuation resuming after an F5.static com.vaadin.flow.component.ComponenttoVaadinIconComponent(String className, Icon icon)
-
Field Details
-
warnHook
Test-only capture sink foronUnimplemented(String, String, Object...),onUnsupported(String, String, Object...), andonUnsupportedPeerShape(String, String). Tests install a collector to assert "this path fires no stub-level WARNs" without having to reconfigure logging; production stays on the no-op default so call sites can feed the hook unconditionally (no null guards).Intentionally a plain field and not an AtomicReference: tests install the hook from a single thread around a known-single-threaded Karibu scenario, then restore the default; no cross-thread concurrency to defend against.
-
-
Method Details
-
onUnimplemented
-
checkUIThread
public static void checkUIThread()Reports, once per JVM, that emulator code reached its Vaadin peer from off the Vaadin UI thread. Never throws and never changes behaviour: SB-Emulators tolerates off-thread component work (it is what real Swing apps do, and Vaadin components happen to construct and mutate fine while detached), so this is an observation, not a gate.Wired into
Component.getPeer()rather than sprinkled over every mutator: the accessor is the one narrow waist between an emulator and its peer, so a new emulator method cannot forget it. Because the report is once per JVM, over-firing (a read, internal plumbing) costs nothing while under-firing is the failure — which is why the chokepoint is the accessor and not a curated list of write paths.Deliberately not routed through
warnHook: that channel is the stub-WARN inventory theWarnInventoryTestexit gates assert on, and this is thread hygiene in the migrator's own code, not an SB-Emulators gap.Defers to
SwingUtilities.isEventDispatchThread()for what "the UI thread" means, so there is exactly one answer to that question; a second copy would eventually disagree with the one migrators can call themselves. Silent during shutdown, where a UI-less teardown thread is expected rather than a mistake (R_callswing_envelope). -
runInUIThread
Runsbodyon the Vaadin UI thread and returns only once it has run — the seam a Swing→peer write goes through when it may be called from a background thread. One contract on every thread: inline when a UI is already current, otherwise the session lock is acquired and the body runs before this returns.Not
callSwing(Runnable)'s inverse and not its sibling:callSwingis the peer→Swing envelope (R_callswing_envelope) and spawns a virtual thread so a modal dialog can park. This is a Swing→peer write, which cannot park, so no VT is spawned and the body simply runs under the lock.Synchronous on purpose, and the reasoning is a decision, not a default. The alternative —
UI.access()— never runs inline even for a caller holding the lock (flow-server'sensureAccessQueuePurged: "if the lock is held by the current thread, we just release it knowing that the queue gets purged once the lock is ultimately released"), so it would defer every write past the end of the request and reorder background writes against inline ones. An app whose EDT blocks on a worker that needs the EDT deadlocks on real Swing too, so blocking here reproduces a JDK failure mode; deferring would invent an execution order Swing never had, which is what R_no_silent_improvements forbids. The lock is taken directly rather than viacallOnLiveUISync(VaadinSession, Supplier)'s queue-and-wait so a stall is attributable — a thread parked on a lock names its owner in a thread dump; one parked on a latch does not.Deliberately unbounded. A hand-rolled
tryLock+ current-instance dance is likelier to be wrong than the deadlock is to happen, so a slow hop is reported (seeSLOW_UI_HOP_MILLIS) rather than broken.No
EmulatorContexton the thread throws (R_match_swing_errors case (7), D_no_context_throws): the migrator started this work on a thread that never carried one, and the fix is one line at its construction —EmulatorContext.wrap(executor), orctx.run(...)for a hand-rolledThread. When the task came through a wrapped executor whose submitter had no context, the message says so and names the submit frames instead (D_submit_site). That throw does not depend oncallerPlansToBlockAfterwards: a missing context is a configuration error either way.Callers may block in a constructor through this —
new JLabel(icon)on a background thread waits for the session lock. That is a property no Swing constructor has, and it is the accepted cost of letting the icon arrive at all.Not the rejected "is this write cosmetic?" flag, which needed a taxonomy of peer operations nobody can finish. This asks whether the caller is about to block, which the caller always knows, and the set that answers yes is small and closed — the modal park and what funnels into it.
- Parameters:
callerPlansToBlockAfterwards- a modal show, not an ordinary write — the caller waits for a browser answer once this returns. (Named for the caller because this method always blocks; the flag is about what happens next.) It decides what a reachable session with no live UI means, and only that:falsekeeps R_decline_effect_only's bargain and drops the effect, since the state is stored and the event fires regardless;truethrows, because degrading would be followed by parking on a latch nothing can ever count down. Mandatory rather than defaulted so the question is answered at every site.- Throws:
IllegalStateException- if this thread carries noEmulatorContextBrowserSessionClosedError- ifcallerPlansToBlockAfterwardsand no live UI is reachable — a closed tab, or a session that went away while this waited
-
callSwing
The R_callswing_envelope seam: runsrunnable— a peer listener's Swing-side body — on a virtual thread so it can park on a modal dialog without blocking the Vaadin request thread. Every peer→Swing listener wraps its body in this:
100% coverage is the contract, not an optimization: one listener that fires directly instead of through here is one button whosebutton.addClickListener(e -> EHelper.callSwing(() -> { fireActionPerformed(...); // may call JOptionPane.showMessageDialog and park }));dialog.show()deadlocks the carrier thread. See D_callswing_funnel, D_callswing_loom, hard rule R_callswing_envelope.- Parameters:
runnable- the Swing-side callback body (fire events, mutate fields).- Throws:
IllegalStateException- ifUI.getCurrent()is null and the session is not shutting down — every legitimate live call site has a UI by construction, so a missing one is a programming error that should fail loudly, not silently no-op. The one carve-out is app shutdown (see the shutdown note below). Also when the Vaadin request itself is being handled on a virtual thread, which SB-Emulators cannot run on at all — seeassertRequestThreadIsNotVirtual().Implementation details
Re-entrant: when already inside an outer
callSwingcontinuation — e.g. a Swing listener mutated a peer and fired another peer event — the runnable runs inline; the outer VT can already park, and a nested VT would only waste machinery. This backstops the feedback cases R_swing_is_truth'spreventPeerEventsflag can't cover (events with no prior value to diff). "Inside a continuation" isUIFibers.isInUIFiber(), not a bareThread.isVirtual(): the two differ on a virtual request thread, where the bare check would silently take this path.Shutdown carve-out (R_callswing_envelope relaxation, D_shutdown_lifecycle). During app termination — a real browser-tab close, where
JFrame.dispatchShutdownClosingfiresWINDOW_CLOSINGand the peer tree detaches — the detach listeners funnelremoveNotifyback through here on the request-less tab-scope reaper thread, which has no current UI. That is expected teardown, not a programming error: the browser tab is gone, so there is nothing to push to. WhenisShuttingDown(), the runnable therefore runs inline instead of throwing (and instead of spinning the VT/UI.accessmachinery, which would buy nothing with no browser attached). Gated by our ownshuttingDownflag, set before the detach cascade, so it never masks a genuine missing-UI bug outside shutdown.Exceptions propagate to the session
ErrorHandlerviaUIFibers.runUntilPark(Runnable)— swallowing here would pre-empt user-configured error handling and hide bugs.
-
relayModelEvent
Relays a surrogate's Swing-model event to the emulator's own listeners: throughcallSwing(Runnable)when a UI is current, inline on the calling thread otherwise.// JList, re-firing the surrogate's forwarded selection event: EHelper.relayModelEvent(() -> fireSelectionValueChanged(first, last, adjusting));Only for bridges a Swing model mutated off the UI thread can reach (SD_background_model_hop); peer listeners keep
callSwingand its throw. A browser event always has a UI current, so no UI means an off-thread mutation on a component with no UI to hop to — and the JDK fires those on the mutating thread too. -
markShuttingDown
public static void markShuttingDown(com.vaadin.flow.server.VaadinSession session) Marks the session as shutting down — set once at the top of the session-destroy →WINDOW_CLOSINGdispatch (D_shutdown_lifecycle), before any userWindowListenerruns.Its one job is to turn the browser-round-trip seams into an actionable throw: once set, a modal-dialog park (
Dialog) or a blockingSwingWorker.get()/SwingUtilities.invokeAndWaitinside a shutdown listener throws a "shutting down"IllegalStateExceptioninstead of hanging on a browser that's already gone (or surfacing a cryptic generic error). Pure server-side cleanup (save, release, log) is unaffected. Not for dedup: session-destroy fires exactly once. -
isShuttingDown
public static boolean isShuttingDown(com.vaadin.flow.server.VaadinSession session) -
isShuttingDown
public static boolean isShuttingDown()isShuttingDown(VaadinSession)for the current session — the form the throw-seams use, since they run inside the dispatch where the current session is set. -
awaitModal
public static void awaitModal(com.vaadin.flow.component.Component anchor, CompletableFuture<?> closed) The modal-park seam: parks the calling UI fiber untilclosedcompletes, the session lock released so the click that closes the dialog can get in.The wait belongs to
anchor, the dialog's peer: when it stays detached — the session is destroyed, the tab closes — the wait ends rather than parking forever. On resumeUI.getCurrent()is the UI the anchor was last attached to, which is the live one after an F5@PreserveOnRefreshteleport.- Throws:
IllegalStateException- outside a UI fiber.BrowserSessionClosedError- if the anchor died, or the park was interrupted: nobody will answer, and anErroris what the migrated code'scatch (Exception e)can't swallow into a fabricated answer (R_match_swing_errors case (8)).callSwing(Runnable)ends the UI fiber quietly on it.
-
awaitBrowserRoundTrip
public static <T> T awaitBrowserRoundTrip(com.vaadin.flow.component.Component anchor, CompletableFuture<T> future) throws ExecutionException, InterruptedException Waits for a browser round-trip — anexecuteJsresult, anExtendedClientDetailsrefresh — withFuture.get()'s contract. Inside a UI fiber it parks, the session lock released so the response can get in, and the wait dies withanchor; on any other thread it is a plainfuture.get().futuremust be a plainCompletableFuture, never Vaadin'sDeadlockDetectingCompletableFuture, whoseget()refuses any caller thathasLock()— a UI fiber included (D_clipboard_future_bridge).- Throws:
BrowserSessionClosedError- ifanchordied, or the park was interrupted, as forawaitModal(Component, CompletableFuture).ExecutionExceptionInterruptedException
-
singleLiveUI
public static com.vaadin.flow.component.UI singleLiveUI(com.vaadin.flow.server.VaadinSession session) The one UI an app lives in — the delivery target for an emulatorTimerfire, aSwingWorkercallback, and a parkedcallSwing(Runnable)continuation resuming after an F5. Resolves purely through theAppTabidentityMainWindowRoutemaintains across an F5@PreserveOnRefreshteleport (the rebind re-binds the fresh UI to the app tab). Returnsnullwhen no liveAppTabis recorded.Pure, never guesses. There is deliberately no
getUIs()fallback: delivering to some arbitrary live UI could run app logic against the wrong (or a second-tab curtain) UI and produce unreproducible state. A null return is the fail-loud signal —onSessionLiveUI(VaadinSession, Runnable)drops the callback,callOnLiveUISync(VaadinSession, Supplier)throws. In production anAppTabis always set before any usercallSwing(MainWindowRoutemarks it beforebootstrap()), so null means a genuine teardown, not a missing identity. A plain (non-parking)callSwingnever needs this: it delivers to its invoking UI (seecallSwing(Runnable)andUIFibers#runUntilPark), which is why callSwing is inherently UI-local and not part of the orphan bug.Never throws here either — a genuine second browser tab is a D_active_ui_pointer curtain that never becomes the
AppTab, so the one-app-per-session invariant is enforced at attach, not by guessing among live UIs.Must be called while holding the session lock (
AppTab.liveUI()readsVaadinSession.getUIs(), which enforces it) — typically from insideonSessionLiveUI(VaadinSession, Runnable)'ssession.accessblock, which is also what guarantees an in-flight F5 has settled (theAppTabalready re-bound to the fresh UI) before this reads it (D_session_scoped_pools).- Returns:
- the app's delivery UI, or
nullif no liveAppTabis recorded (teardown, or an app that never marked one).
-
onSessionLiveUI
public static void onSessionLiveUI(com.vaadin.flow.server.VaadinSession session, Runnable swingBody) Delivers a Swing-side callback (aTimerfire, aSwingWorkerdone()/process()/PCE) onto the session's single live UI, from a non-UI thread (a scheduler or worker thread that holds no lock).The UI is resolved lazily, at delivery time — never captured eagerly at construction. That is what survives an F5
@PreserveOnRefreshteleport: the refresh runs inside one lock-holding request, so by the time this callback'ssession.accessblock gets the lock the transition has fully settled andsingleLiveUI(VaadinSession)sees exactly the new UI — independent of whether the framework created-then-closed (real Flow) or closed-then-created (Karibu). SeeUiScopedFeaturesF5Test.session.accessacquires the lock; inside it we resolve the live UI and hop to it viaUI.accessSynchronously(Command)(re-entrant on the already-held lock) socallSwing(Runnable)runs withUI.getCurrent()set — the R_callswing_envelope envelope the loom VT carrier needs. Anulllive UI (session going down) drops the callback silently. -
reportUncaught
Hands an uncaught throwable to the session'sErrorHandler, acquiring the session lock first if the caller doesn't already hold it — the emulator'sEventDispatchThread.processException.The lock is what this method is for:
getErrorHandler()is state access behindcheckHasLock(), whose defaultSessionLockCheckStrategyisASSERT— so an unlocked read blows up under-eaand passes silently in production.Deliberately no lookup chain, and in particular no
Thread.getDefaultUncaughtExceptionHandler()read — a migrated app's JVM-wide handler is ported to the session instead. Adding the read back is the plausible "improvement" this note exists to stop;UncaughtErrorRoutingTest.jvmWideHandlerIsNotConsultedis what goes red. Reasons:D_uncaught_handler_chain.- Parameters:
session-nulllogs here instead; no handler is reachable without one
-
callOnLiveUISync
public static <T> T callOnLiveUISync(com.vaadin.flow.server.VaadinSession session, Supplier<T> body) Runsbodyon the session's single live UI and returns its value to the calling background thread, blocking until it completes. The synchronous, result-returning sibling ofonSessionLiveUI(VaadinSession, Runnable): used when a background worker (SwingWorker.doInBackground) must read/write browser-backed state (e.g.localStoragepreferences) and needs the answer inline.
Mechanism (mirrors// on a SwingWorker VT (no current UI, session held via EmulatorContext): String v = EHelper.callOnLiveUISync(ctx.session(), () -> Preferences.userRoot().node("com/acme").get("k", "def"));SwingUtilities.invokeAndWait's block-until-done, plusonSessionLiveUI(VaadinSession, Runnable)'s UI resolution): queue onto the session viasession.access; inside, resolvesingleLiveUI(VaadinSession)and runbodyunderaccessSynchronously+callSwing(Runnable)so it has a current UI, the lock, and the loom carrier to park on a browser round-trip; latch the result/exception back andawaitit on the caller. The access queue is drained by@Pushin production (the mandatory-Push contract) /MockVaadin.runUIQueuein tests — the same draininvokeAndWaitdepends on. The caller must be a parkable (virtual) thread; aSwingWorkerworker thread is.Never hangs, fails loud. Unlike
onSessionLiveUI(which silently drops), every terminal state completes the latch: no live UI (tab/session gone), abodyexception, or the 30Ls timeout backstop all surface as a thrown exception (per D_prefs_scope_split / D_gap_severity_triage — loud over silently-stale). A thrown exception propagates out ofdoInBackgroundas the worker'sExecutionException.- Throws:
IllegalStateException- if no single live UI is reachable, the wait times out, or the wait is interrupted; anybodyruntime exception propagates as-is.
-
onNoop
Deliberate no-op hook for Swing API that's redundant in the Vaadin world (layout invalidation, repaint, peer lifecycle). Logs at DEBUG only — these get hit hot. No varargs on purpose: args don't add information at DEBUG for a "we ignored it by design" call. -
onUnsupported
Swing method we *have* implemented, but the underlying Vaadin peer can't honour this particular call — e.g.setEnabled(false)on a peer that doesn't implementHasEnabled. Distinct fromonUnimplemented(String, String, Object...): there, *we* haven't coded the behaviour yet; here, the peer is the blocker. WARN so it shows up in migration logs, but never throws — R_match_swing_errors. -
onUnsupportedPeerShape
ERROR-log hook for situations where emulation is fundamentally unable to honor a well-formed Swing request and the safest response is to do nothing — e.g. setting aLayoutManageron a Container whose peer content element isn't a plain<div>(D_layout_css_on_content). Louder thanonUnimplemented(String, String, Object...)'s WARN because the user has stepped into genuinely broken territory, not just unimplemented territory. Returns without throwing; R_match_swing_errors still applies. -
applyContainerCss
public static void applyContainerCss(com.vaadin.flow.dom.Element target, String layoutManagerName, Map<String, String> css) Apply a block of layout CSS to a Container's peer content element per D_layout_css_on_content. Gates on the element being a plain<div>: non-Div peers get aonUnsupportedPeerShape(String, String)ERROR log and no CSS is written — setting a LayoutManager on a JComponent whose peer isn't a Div (a JButton, a JTextField, ...) leaves children under the peer's own rendering rather than corrupting it.Takes the target
Elementrather than the Container soContainer.peerContentElement()stays protected — callers are the built-in LayoutManagers invaadinx.awt, which already have package access to resolve it.nullvalues remove the corresponding style property, mirroring thenull → inherit from parentcontract used elsewhere in the peer-CSS layer (seeComponent.setForeground(Color)). -
applyChildCss
Apply per-child layout CSS to a single child's element — the counterpart toapplyContainerCss(Element, String, Map)for the per-child leg of aCssEmittingLayoutManagerpass (grid-area,justify-self,margin, …). No<div>gate: a child is any element (a button, a field).nullvalues remove the property, absent keys are left untouched — so a fill-stretched cell can drop a field surrogate's inlinewidthwithout a non-filled sibling losing its columns size. -
resetContainerCss
public static void resetContainerCss(com.vaadin.flow.dom.Element target) Clear a container's layout CSS — the undo forapplyContainerCss(Element, String, Map), called fromContainer.setLayout(LayoutManager)when oneLayoutManagerreplaces another. Rationale for why the undo exists (and why per-child CSS is left alone) lives onLayoutCss.resetContainerCss(Element). -
onCreated
Register the 1:1 mappingpeer → emulator. Invoked fromComponent's constructor so lookup viagetEmulator(com.vaadin.flow.component.Component)never has to synthesize a fresh emulator. -
applyEmulatorId
Map a Swing name to the peer's HTML id, with a per-UI suffix counter to keep ids unique when two components share a Swing name (Swing'snamehas no uniqueness requirement; HTML'siddoes). FirstsetName("ok")→id="ok"; second →id="ok-2"; third →id="ok-3".null/ blank name removes the id.Surrogate-side tagging takes a different shape (
data-swing-nameattribute throughComponentMixin.setName(String)) because surrogates deliberately leave Vaadin'sidalone — seeSD_dropin_stance/NameStore. The id-vs-attribute split mirrors the stage-2 vs stage-3 layering: emulators own their peers and can stamp the id; surrogates respect the id semantic boundary.Falls back to
peer.setId(name)without disambiguation when called outside a UI context — pre-attach construction without a current UI is rare but possible, and an unsuffixed id is the same as the first- claim outcome. -
toVaadinIconComponent
public static com.vaadin.flow.component.Component toVaadinIconComponent(String className, Icon icon) Convert aIconto a VaadinComponentthe peer can install viaButton.setIcon(Component). Two icon-rendering paths funnel through here:- Path 1 —
ImageIcon: raster encoded as PNG and wrapped in a VaadinImageviaIcons.imageIconToVaadinImage(ImageIcon). - Path 2 (external) —
VaadinIconAdapter: freshVaadinIcon-glyph component built per call. Reaches us when migrated code sourced an icon viaUIManager.getIcon(Object).
Iconimpls log viaonUnimplemented(String, String, Object...)and returnnull(Path 3 — offscreen-paint of arbitrary Icon impls — is permanently deferred per R_match_swing_errors sub-bucket (b)).nullicon →null(callers interpret as "remove icon"). TheclassNameargument feeds the WARN message for non-recognizedIconinputs so migration logs identify which emulator surfaced the dropped icon. - Path 1 —
-
getEmulator
The emulator (Component) whose peer is the given Vaadin component. ThrowsNullPointerExceptionif the peer has no registered emulator — an internal invariant check (see D_peer_emulator_mapping). D_never_fail_on_gaps scopes to emulation incompleteness; this is an internal-plumbing invariant and unrelated. -
emulatorFor
Lenient, walking variant ofgetEmulator(Component): the emulator owningpeer, or the one owning its nearest Vaadin ancestor, ornullwhen no ancestor is a registered peer. Never throws.Needed wherever the starting point is a Vaadin component we did not choose —
com.vaadin.swingbridge.surrogates.FocusTracker's focus owner is the canonical case: the browser focuses the inner field of a composite peer (anSJSpinner'sNumberField), which is not itself a registered peer, so the answer sits one or two levels up. Focus landing on a Vaadin component the app added outside vaadinx has no emulator at all, andnullis the honest answer rather thangetEmulator(Component)'s invariant failure. -
getDialogs
EveryDialogattached to the current UI's component graph — the Vaadin-side view of our Windows. A Dialog that hasn't been opened (not in the tree) isn't returned. No retained list: the graph is the source of truth, which avoids the classic registry leak where disposed Windows linger in a static list.Returns an empty list when there's no current UI — the typical case for code running off-thread. Callers get "no windows" rather than an exception, matching D_never_fail_on_gaps's never-fail stance for queries.
We walk
Component.getChildren()recursively rather than callingComponentUtil.findComponents(Element, Consumer), because the latter short-circuits on the first component it finds below a given element — starting from UI it would accept UI and stop without ever reaching the Dialog children. -
getWindows
EveryWindowthis app instance has constructed and not yet let go of, in construction order — the source of truth behindWindow.getWindows(),Window.getOwnerlessWindows()andFrame.getFrames().Creation-based, as AWT is. A Window appears here from its constructor and stays while anything references it — never shown, hidden again, even
dispose()d. Displayability only decides whether the registry itself is what keeps it alive: while displayable it is pinned strongly, so a frame the app has dropped every reference to is still enumerable exactly as on the desktop. Details, and why the earlier walk-the-UI-graph shape was dropped, live onWindowRegistry.Returns an empty list when no app store resolves on this thread, matching
getDialogs()'s never-fail stance for queries (D_never_fail_on_gaps). -
onWindowCreated
-
onWindowDisplayable
TheaddNotify()->allWindows.add(this)edge. -
onWindowUndisplayable
TheremoveNotify()->allWindows.remove(this)edge, and the one place a Window stops being displayable — so also whereAutoShutdownlearns the app may be over.
-