Class SJSpinner

java.lang.Object
com.vaadin.flow.component.Component
com.vaadin.flow.component.AbstractField<com.vaadin.flow.component.customfield.CustomField<Object>, Object>
com.vaadin.flow.component.customfield.CustomField<Object>
com.vaadin.swingbridge.surrogates.SJSpinner
All Implemented Interfaces:
com.vaadin.flow.component.AttachNotifier, com.vaadin.flow.component.BlurNotifier<com.vaadin.flow.component.customfield.CustomField<Object>>, com.vaadin.flow.component.DetachNotifier, com.vaadin.flow.component.Focusable<com.vaadin.flow.component.customfield.CustomField<Object>>, com.vaadin.flow.component.FocusNotifier<com.vaadin.flow.component.customfield.CustomField<Object>>, com.vaadin.flow.component.HasElement, com.vaadin.flow.component.HasEnabled, com.vaadin.flow.component.HasHelper, com.vaadin.flow.component.HasLabel, com.vaadin.flow.component.HasSize, com.vaadin.flow.component.HasStyle, com.vaadin.flow.component.HasTheme, com.vaadin.flow.component.HasValidation, com.vaadin.flow.component.HasValue<com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent<com.vaadin.flow.component.customfield.CustomField<Object>, Object>, Object>, com.vaadin.flow.component.HasValueAndElement<com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent<com.vaadin.flow.component.customfield.CustomField<Object>, Object>, Object>, com.vaadin.flow.component.shared.HasTooltip, com.vaadin.flow.component.shared.HasValidationProperties, com.vaadin.flow.component.shared.InputField<com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent<com.vaadin.flow.component.customfield.CustomField<Object>, Object>, Object>, ComponentMixin, ContainerMixin, EnterClaims.Claimant, JComponentMixin, Serializable

public class SJSpinner extends com.vaadin.flow.component.customfield.CustomField<Object> implements JComponentMixin, EnterClaims.Claimant
Surrogate for JSpinner (SD_sjspinner). Extends Vaadin CustomField and carries a swappable inner Vaadin field whose concrete type is picked from the installed SpinnerModel's value type: IntegerField for SpinnerNumberModel(Integer), LongField for SpinnerNumberModel(Long), NumberField for Double/Float/BigDecimal/BigInteger, DatePicker for SpinnerDateModel, Select for SpinnerListModel, and a read-only TextField fallback for unknown SpinnerModel implementations (so a migrated app at least boots instead of crashing at construction).

Why CustomField, not a single leaf primitive

JSpinner's API allows swapping the model to a different-typed one at runtime (spinner.setModel(new SpinnerDateModel())); no single Vaadin leaf primitive can morph from a numeric input into a date picker into a select. CustomField is the Vaadin-native vehicle for composing a value-carrying field from swappable child components — on setModel(SpinnerModel) we tear down the old inner, add the new one, and rewire the listener chain.

Model flow

The installed SpinnerModel is the source of truth (R_swing_is_truth). Our ChangeListener on the model fans out to user ChangeListeners, pushes the model's value / bounds / step through to the inner field, and calls CustomField.updateValue() so HasValue observers see the change through Vaadin channels too. Browser-originated edits land on our explicit HasValue listener on the inner field (wrapped in SHelper.callSwing(Runnable), R_callswing_envelope); we coerce the peer-typed value back to the model's type and write it through the model, which fires ChangeEvent and closes the loop. The standard preventPeerEvents flag (R_swing_is_truth) guards against peer→model→peer re-entry.

Read-only propagation

setReadOnly(boolean) is the user-facing bit; the inner field's read-only state is userReadOnly || fallbackForcesReadOnly. For unknown-model-type fallback (see createInnerFieldFor(SpinnerModel)) the TextField stays locked regardless, so a migrated app can't silently accept unparseable typed input into a model we can't round-trip.

Editor surface

Deferred per [D_emulator_surrogate_split] — getEditor / setEditor / createEditor all WARN and return null; commitEdit is a no-op (the peer listener already mirrors edits into the model on every value change). Migrated code that reaches through getEditor() for JFormattedTextField features will see the WARN.
See Also:
  • Constructor Details

    • SJSpinner

      public SJSpinner()
    • SJSpinner

      public SJSpinner(SpinnerModel model)
  • Method Details

    • setDatePattern

      public void setDatePattern(String pattern)
      Apply a JDK SimpleDateFormat-shaped pattern (e.g. "yyyy-MM-dd", "MM/dd/yyyy") to the underlying Vaadin DatePicker via DatePicker.setI18n(DatePicker.DatePickerI18n). No-op when the inner field isn't a DatePicker (the model isn't date-typed).

      R_layouts_close_enough best-effort: Vaadin's DatePickerI18n.setDateFormat accepts JDK-shaped patterns directly for the date components yyyy / MM / dd / d / M / yy; time components in the pattern (e.g. "yyyy-MM-dd HH:mm") are dropped silently — Vaadin DatePicker is date-only by construction. Mirrors SD_maskformatter_regex's SJFormattedDatePicker stance.

      Pattern is also stored on the surrogate so a subsequent setModel(SpinnerDateModel) swap re-applies it to the freshly- built DatePicker (see ensureInnerFieldMatches(SpinnerModel)).

    • getDatePattern

      public String getDatePattern()
    • generateModelValue

      protected Object generateModelValue()
      Specified by:
      generateModelValue in class com.vaadin.flow.component.customfield.CustomField<Object>
    • setPresentationValue

      protected void setPresentationValue(Object newPresentationValue)
      Specified by:
      setPresentationValue in class com.vaadin.flow.component.customfield.CustomField<Object>
    • setReadOnly

      public void setReadOnly(boolean readOnly)
      Specified by:
      setReadOnly in interface com.vaadin.flow.component.HasValue<com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent<com.vaadin.flow.component.customfield.CustomField<Object>, Object>, Object>
      Specified by:
      setReadOnly in interface com.vaadin.flow.component.HasValueAndElement<com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent<com.vaadin.flow.component.customfield.CustomField<Object>, Object>, Object>
    • setValue

      public void setValue(Object value)

      JSpinner-shape behaviour: route through the model so migrated code sees the same contract as JDK JSpinner — IllegalArgumentException on out-of-range, ClassCastException on wrong type. We deliberately bypass CustomField's internal setModelValue path; the subsequent model ChangeEvent fans out to fanOutModelChange() which calls CustomField.updateValue() and so keeps CustomField's internal bookkeeping in sync.

      Specified by:
      setValue in interface com.vaadin.flow.component.HasValue<com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent<com.vaadin.flow.component.customfield.CustomField<Object>, Object>, Object>
      Overrides:
      setValue in class com.vaadin.flow.component.AbstractField<com.vaadin.flow.component.customfield.CustomField<Object>, Object>
    • getValue

      public Object getValue()
      Specified by:
      getValue in interface com.vaadin.flow.component.HasValue<com.vaadin.flow.component.AbstractField.ComponentValueChangeEvent<com.vaadin.flow.component.customfield.CustomField<Object>, Object>, Object>
      Overrides:
      getValue in class com.vaadin.flow.component.AbstractField<com.vaadin.flow.component.customfield.CustomField<Object>, Object>
    • getModel

      public SpinnerModel getModel()
    • setModel

      public void setModel(SpinnerModel newModel)
    • getNextValue

      public Object getNextValue()
    • getPreviousValue

      public Object getPreviousValue()
    • addChangeListener

      public void addChangeListener(ChangeListener l)
    • removeChangeListener

      public void removeChangeListener(ChangeListener l)
    • getChangeListeners

      public ChangeListener[] getChangeListeners()
    • fireStateChanged

      protected void fireStateChanged()
    • getEditor

      public com.vaadin.flow.component.Component getEditor()
    • setEditor

      public void setEditor(com.vaadin.flow.component.Component editor)
    • commitEdit

      public void commitEdit()
    • claimsEnter

      public boolean claimsEnter()
      The editor's rule: Swing's spinner editor is a JFormattedTextField, so Enter commits an edit and only an unedited editor lets it through.
      Specified by:
      claimsEnter in interface EnterClaims.Claimant
    • getUIClassID

      public String getUIClassID()
      Description copied from interface: JComponentMixin
      Deliberate no-op — L&F key.
      Specified by:
      getUIClassID in interface JComponentMixin