Class SJEditorPane

java.lang.Object
com.vaadin.flow.component.Component
com.vaadin.flow.component.AbstractField<com.vaadin.flow.component.richtexteditor.RichTextEditor, String>
com.vaadin.flow.component.AbstractSinglePropertyField<com.vaadin.flow.component.richtexteditor.RichTextEditor, String>
com.vaadin.flow.component.richtexteditor.RichTextEditor
com.vaadin.swingbridge.surrogates.SJEditorPane
All Implemented Interfaces:
com.vaadin.flow.component.AttachNotifier, com.vaadin.flow.component.CompositionNotifier, com.vaadin.flow.component.DetachNotifier, com.vaadin.flow.component.HasElement, com.vaadin.flow.component.HasEnabled, com.vaadin.flow.component.HasSize, com.vaadin.flow.component.HasStyle, com.vaadin.flow.component.HasTheme, com.vaadin.flow.component.HasValue<com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent<com.vaadin.flow.component.richtexteditor.RichTextEditor, String>, String>, com.vaadin.flow.component.HasValueAndElement<com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent<com.vaadin.flow.component.richtexteditor.RichTextEditor, String>, String>, com.vaadin.flow.component.InputNotifier, com.vaadin.flow.component.KeyNotifier, com.vaadin.flow.component.shared.HasThemeVariant<com.vaadin.flow.component.richtexteditor.RichTextEditorVariant>, com.vaadin.flow.data.value.HasValueChangeMode, ComponentMixin, ContainerMixin, EnterClaims.Claimant, JComponentMixin, Serializable

public class SJEditorPane extends com.vaadin.flow.component.richtexteditor.RichTextEditor implements JComponentMixin, EnterClaims.Claimant
Surrogate for JEditorPane — the single, unconditional peer behind vaadinx.swing.JEditorPane (SD_sjeditorpane_rte). Extends Vaadin RichTextEditor directly (is-a), so one peer covers read-only display, editable HTML, and a runtime view↔edit toggle:
SJEditorPane pane = new SJEditorPane("text/html", "<p>hi</p>");
pane.setEditable(false);        // read-only: hides the RTE toolbar
pane.setEditable(true);         // back to editing — no peer swap
String html = pane.getText();   // reads RTE's htmlValue back
HTML round-trips through RTE's setValue/getValue (HTML is the Flow default — no asDelta()); editable maps to setReadOnly(!editable). Replaces the deleted read-only Div peer (SD_sjeditorpane_div).

Lossy HTML subset — display and edit (R_vaadin_first)

RTE accepts only p, br, h1–h6, strong/em/u/s, a, ol/ul/li (no nesting), blockquote, pre, img (base64 data-URLs only — no web-URL images); <b>→<strong>, unknown tags→<p>. No tables, no arbitrary CSS. Because RTE is the only peer, this hits read-only display too: a report with tables loses them — the accepted regression from the deleted Div (SD_sjeditorpane_rte). RTE's subset normalization doubles as a sanitizer, so it is safer for user-supplied HTML than the Div's raw innerHTML was. A migrator needing faithful static HTML drops to a Vaadin Html/Div in that one view.

Content type

Only "text/html" is honored — RTE speaks HTML. "text/plain" / "text/rtf" field-round-trip but drop-and-WARN (no EditorKit pipeline; paintComponent is permanently OOS per R_match_swing_errors sub-bucket (b)). Default is the JDK's "text/plain", but setText writes markup either way (R_layouts_close_enough close-enough — typical use sets "text/html" first).

setPage(URL) — synchronous fetch

setPage(URL) opens the URL via URLConnection, reads the bytes synchronously, decodes them using HtmlCharset (Content-Type charset → <meta> declaration → UTF-8), forces contentType="text/html", writes through setText(String), and fires the "page" PCE. Relative links in the loaded page resolve against it — see fireHyperlinkActivated(String).

Accepted divergences (R_layouts_close_enough): the fetch is server-side (it resolves from the Vaadin app's network reach, not the browser's), skips EditorKit content-type dispatch, and is synchronous-only (blocks the request thread — fine for small/local fetches). A non-HTML media type and a URL fragment each WARN: the content is rendered as HTML regardless, and there is no scrollToReference counterpart.

Deliberately unlike the JDK: every call re-fetches. The JDK skips the load when the URL already equals the displayed one, and forcing a reload there means clearing the document's stream-description property — a document-model hook that does not exist here. Copying the skip without the escape hatch would leave a "reload this page" button permanently dead, so re-fetching is the best-effort choice (R_best_effort_behaviour): both the ordinary case and the reload case work.

addHyperlinkListener(HyperlinkListener) delivers ACTIVATED when the user clicks a link in a pane that is not editable, matching Swing, where HTMLEditorKit.LinkController activates a link only on a non-editable pane (in an editor a click positions the caret). A delegated click listener in the RTE's shadow root reports the href; see HYPERLINK_HOOK_JS for why the listener cannot sit on the host element. Hover (ENTERED / EXITED) is not wired.

Author CSS for the rendered content

addCssRule(String) styles the pane's content — the peer half of HTMLEditorKit's StyleSheet.addRule. The stylesheet is injected into this instance's shadow root, so it reaches content RTE renders there while staying confined to this pane. Appearance only: structure Quill's model refuses (tables) is gone before any rule could apply.

What drops-and-WARNs (R_vaadin_first)

setContentType for non-HTML types; at-rules passed to addCssRule(String). setEditorKit / setDocument etc. live on the emulator and never reach here.
See Also:
  • Constructor Details

    • SJEditorPane

      public SJEditorPane()
    • SJEditorPane

      public SJEditorPane(String type, String text)
      Content-type + initial text. Other ctors (URL forms) sit on the emulator.
  • Method Details

    • getText

      public String getText()
      Returns the RTE's current HTML value. Round-trip is lossy per R_vaadin_first — RTE normalizes to its supported subset (see class javadoc), so setText(s); getText() may not be byte-for-byte s. The emulator's Document keeps a faithful copy for its own getText; this reads what the editor actually holds.
    • setText

      public void setText(String t)
      Writes t into RTE's HTML value. null normalises to empty string (RTE's empty value; matches JDK's "clear the document").
    • getContentType

      public String getContentType()
    • setContentType

      public void setContentType(String type)
      Resolve the type the way the JDK does and keep the result; only "text/html" is honored for rendering, everything else WARNs per R_vaadin_first — RTE renders HTML, and EditorKit-driven rendering is OOS once Graphics paint is off the table (R_match_swing_errors sub-bucket (b)).

      The argument is not what the getter answers, and that is the JDK's contract, not an approximation. javax.swing.JEditorPane keeps no content-type field: getContentType() returns the installed EditorKit's type, and a type with no registered kit installs the plain kit — so setContentType("ADMIN") reads back as "text/plain", and a ";charset=…" parameter list never survives the round trip. SB-Emulators stored the string verbatim and answered it back, inventing a content type the desktop cannot report (D_return_value_audit).

      The four types with kits registered by default are the JDK's own (text/plain, text/html, text/rtf, application/rtf); the lookup is an exact-string one there, so "TEXT/HTML" resolves to the plain kit as it does here. A migrator's registerEditorKitForContentType is not honored — kit-driven rendering has no path to the peer — so a custom type resolves to text/plain where the desktop would echo it.

    • getPage

      public URL getPage()
      The URL most recently passed to setPage(URL), or null if no page has been loaded. Returns the caller's URL, not the post-redirect one.
    • setPage

      public void setPage(URL page) throws IOException
      Fetch the URL's content synchronously and render it as HTML. Bytes decode via URLConnection.getContentEncoding() when present, else UTF-8. Forces contentType="text/html" and fires the "page" PCE.
      Throws:
      IOException - if the fetch fails — the same checked exception the JDK declares, so migrators' catch-and-degrade code still works.
    • setPage

      public void setPage(String url) throws IOException
      Parse the string and dispatch to setPage(URL).
      Throws:
      MalformedURLException - if url will not parse — the same IOException subtype the JDK throws (it goes through new URL(String)), so migrated catch (IOException) handlers still catch it. URI.create(...).toURL() raises an unchecked IllegalArgumentException for some malformed inputs, which such a handler would miss (R_match_swing_errors).
      IOException
    • isEditable

      public boolean isEditable()
      Reads !isReadOnly() — RTE read-only mode hides the toolbar.
    • setEditable

      public void setEditable(boolean b)
      Maps to setReadOnly(!b) and fires the "editable" PCE. Both states — and a runtime toggle between them — ride the one RTE peer.
    • addCssRule

      public void addCssRule(String css)
      Apply author CSS to the pane's rendered content — the peer-side half of HTMLEditorKit's StyleSheet.addRule. Accepts a single rule or a whole stylesheet's worth; selectors are rewritten to reach RTE's content element (see RteCssRules).

      Only appearance is reachable this way. Structure RTE's model refuses — tables above all — is dropped as the value enters Quill, before any stylesheet could matter, so no rule brings it back (SD_sjeditorpane_rte).

      At-rules (@media and friends) are skipped and WARN: the rest of the sheet still applies.

    • getCssRules

      public List<String> getCssRules()
      The rules applied so far, in the order they were added.
    • addHyperlinkListener

      public void addHyperlinkListener(HyperlinkListener l)
      Add a listener notified when the user activates a link in a read-only pane. Only ACTIVATED is delivered; ENTERED / EXITED hover events have no counterpart wired (the JDK guarantees no delivery cadence for them, and nothing in the surveyed field code reads them).

      The client hook is installed lazily on the first registration, so a pane nobody listens to keeps the browser's own navigation behaviour. One consequence worth knowing: once a listener has been added, links stop navigating natively even if every listener is later removed — the hook stays installed. That direction matches Swing (where a link click never navigates on its own) so it is left as-is.

    • removeHyperlinkListener

      public void removeHyperlinkListener(HyperlinkListener l)
    • getHyperlinkListeners

      public HyperlinkListener[] getHyperlinkListeners()
    • fireHyperlinkActivated

      protected void fireHyperlinkActivated(String href)
      Fan out an ACTIVATED event, matching what Swing's LinkController builds: getDescription() is the raw href as authored and getURL() is that href resolved — so a relative link resolves against getPage(), the nearest thing we have to HTMLDocument.getBase(). An href that cannot form a URL (a bare fragment, an unresolvable relative path with no page loaded) yields a null URL, as it does in Swing, rather than dropping the event — the description still carries the href.

      The source element argument is always null: we have no HTMLDocument element model to point at (plan slice 4).

    • getUIClassID

      public String getUIClassID()
      JDK JEditorPane returns "EditorPaneUI". We don't drive a pluggable ComponentUI (R_layouts_close_enough — Vaadin owns the DOM), but keep the ID so migrated code that introspects via BeanInfo finds the expected value.
      Specified by:
      getUIClassID in interface JComponentMixin
    • claimsEnter

      public boolean claimsEnter()
      Enter inserts a line break while editable — Swing's insert-break binding.
      Specified by:
      claimsEnter in interface EnterClaims.Claimant