123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773 |
- /*
- * Copyright 2000-2018 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
- package com.vaadin.v7.ui;
-
- import java.lang.reflect.Method;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Locale;
-
- import org.jsoup.nodes.Attributes;
- import org.jsoup.nodes.Element;
-
- import com.vaadin.event.Action;
- import com.vaadin.event.ShortcutAction;
- import com.vaadin.event.ShortcutListener;
- import com.vaadin.server.AbstractErrorMessage;
- import com.vaadin.server.CompositeErrorMessage;
- import com.vaadin.server.ErrorMessage;
- import com.vaadin.shared.util.SharedUtil;
- import com.vaadin.ui.Component;
- import com.vaadin.ui.declarative.DesignAttributeHandler;
- import com.vaadin.ui.declarative.DesignContext;
- import com.vaadin.v7.data.Buffered;
- import com.vaadin.v7.data.BufferedValidatable;
- import com.vaadin.v7.data.Property;
- import com.vaadin.v7.data.Validatable;
- import com.vaadin.v7.data.Validator;
- import com.vaadin.v7.data.Validator.InvalidValueException;
- import com.vaadin.v7.data.util.converter.Converter;
- import com.vaadin.v7.data.util.converter.Converter.ConversionException;
- import com.vaadin.v7.data.util.converter.ConverterUtil;
- import com.vaadin.v7.shared.AbstractFieldState;
-
- /**
- * <p>
- * Abstract field component for implementing buffered property editors. The
- * field may hold an internal value, or it may be connected to any data source
- * that implements the {@link Property} interface. <code>AbstractField</code>
- * implements that interface itself, too, so accessing the Property value
- * represented by it is straightforward.
- * </p>
- *
- * <p>
- * AbstractField also provides the {@link Buffered} interface for buffering the
- * data source value. By default the Field is in write through-mode and
- * {@link #setWriteThrough(boolean)}should be called to enable buffering.
- * </p>
- *
- * <p>
- * The class also supports {@link Validator validators} to make sure the value
- * contained in the field is valid.
- * </p>
- *
- * @author Vaadin Ltd.
- * @since 3.0
- *
- * @deprecated This class is, apart from the rename, identical to the Vaadin 7
- * {@code com.vaadin.ui.AbstractField}. It is provided for
- * compatibility and migration purposes. As of 8.0, new field
- * implementations should extend the new
- * {@link com.vaadin.ui.AbstractField} instead.
- */
- @SuppressWarnings("serial")
- @Deprecated
- public abstract class AbstractField<T> extends AbstractLegacyComponent
- implements Field<T>, Property.ReadOnlyStatusChangeListener,
- Property.ReadOnlyStatusChangeNotifier, Action.ShortcutNotifier {
-
- /* Private members */
-
- /**
- * Value of the abstract field.
- */
- private T value;
-
- /**
- * A converter used to convert from the data model type to the field type
- * and vice versa.
- */
- private Converter<T, Object> converter = null;
- /**
- * Connected data-source.
- */
- private Property<?> dataSource = null;
-
- /**
- * The list of validators.
- */
- private LinkedList<Validator> validators = null;
-
- /**
- * True if field is in buffered mode, false otherwise
- */
- private boolean buffered;
-
- /**
- * Flag to indicate that the field is currently committing its value to the
- * datasource.
- */
- private boolean committingValueToDataSource = false;
-
- /**
- * Current source exception.
- */
- private Buffered.SourceException currentBufferedSourceException = null;
-
- /**
- * Are the invalid values allowed in fields ?
- */
- private boolean invalidAllowed = true;
-
- /**
- * Are the invalid values committed ?
- */
- private boolean invalidCommitted = false;
-
- /**
- * The error message for the exception that is thrown when the field is
- * required but empty.
- */
- private String requiredError = "";
-
- /**
- * The error message that is shown when the field value cannot be converted.
- */
- private String conversionError = "Could not convert value to {0}";
-
- /**
- * Is automatic validation enabled.
- */
- private boolean validationVisible = true;
-
- private boolean valueWasModifiedByDataSourceDuringCommit;
-
- /**
- * Whether this field is currently registered as listening to events from
- * its data source.
- *
- * @see #setPropertyDataSource(Property)
- * @see #addPropertyListeners()
- * @see #removePropertyListeners()
- */
- private boolean isListeningToPropertyEvents = false;
-
- /**
- * The locale used when setting the value.
- */
- private Locale valueLocale = null;
-
- /* Component basics */
-
- /*
- * Paints the field. Don't add a JavaDoc comment here, we use the default
- * documentation from the implemented interface.
- */
-
- /**
- * Returns true if the error indicator be hidden when painting the component
- * even when there are errors.
- *
- * This is a mostly internal method, but can be overridden in subclasses
- * e.g. if the error indicator should also be shown for empty fields in some
- * cases.
- *
- * @return true to hide the error indicator, false to use the normal logic
- * to show it when there are errors
- */
- protected boolean shouldHideErrors() {
- // getErrorMessage() can still return something else than null based on
- // validation etc.
- return isRequired() && isEmpty() && getComponentError() == null;
- }
-
- /**
- * Returns the type of the Field. The methods <code>getValue</code> and
- * <code>setValue</code> must be compatible with this type: one must be able
- * to safely cast the value returned from <code>getValue</code> to the given
- * type and pass any variable assignable to this type as an argument to
- * <code>setValue</code>.
- *
- * @return the type of the Field
- */
- @Override
- public abstract Class<? extends T> getType();
-
- /**
- * The abstract field is read only also if the data source is in read only
- * mode.
- */
- @Override
- public boolean isReadOnly() {
- return super.isReadOnly()
- || dataSource != null && dataSource.isReadOnly();
- }
-
- /**
- * Changes the readonly state and throw read-only status change events.
- *
- * @see com.vaadin.ui.Component#setReadOnly(boolean)
- */
- @Override
- public void setReadOnly(boolean readOnly) {
- super.setReadOnly(readOnly);
- fireReadOnlyStatusChange();
- }
-
- /**
- * Tests if the invalid data is committed to datasource.
- *
- * @see BufferedValidatable#isInvalidCommitted()
- */
- @Override
- public boolean isInvalidCommitted() {
- return invalidCommitted;
- }
-
- /**
- * Sets if the invalid data should be committed to datasource.
- *
- * @see BufferedValidatable#setInvalidCommitted(boolean)
- */
- @Override
- public void setInvalidCommitted(boolean isCommitted) {
- invalidCommitted = isCommitted;
- }
-
- /*
- * Saves the current value to the data source Don't add a JavaDoc comment
- * here, we use the default documentation from the implemented interface.
- */
- @Override
- public void commit()
- throws Buffered.SourceException, InvalidValueException {
- if (dataSource != null && !dataSource.isReadOnly()) {
- if (isInvalidCommitted() || isValid()) {
- try {
-
- // Commits the value to datasource.
- valueWasModifiedByDataSourceDuringCommit = false;
- committingValueToDataSource = true;
- getPropertyDataSource().setValue(getConvertedValue());
- } catch (final Throwable e) {
-
- // Sets the buffering state.
- SourceException sourceException = new Buffered.SourceException(
- this, e);
- setCurrentBufferedSourceException(sourceException);
-
- // Throws the source exception.
- throw sourceException;
- } finally {
- committingValueToDataSource = false;
- }
- } else {
- /*
- * An invalid value and we don't allow them, throw the exception
- */
- validate();
- }
- }
-
- // The abstract field is not modified anymore
- if (isModified()) {
- setModified(false);
- }
-
- // If successful, remove set the buffering state to be ok
- if (getCurrentBufferedSourceException() != null) {
- setCurrentBufferedSourceException(null);
- }
-
- if (valueWasModifiedByDataSourceDuringCommit) {
- valueWasModifiedByDataSourceDuringCommit = false;
- fireValueChange(false);
- }
-
- }
-
- /*
- * Updates the value from the data source. Don't add a JavaDoc comment here,
- * we use the default documentation from the implemented interface.
- */
- @Override
- public void discard() throws Buffered.SourceException {
- updateValueFromDataSource();
- }
-
- /**
- * Gets the value from the data source. This is only here because of clarity
- * in the code that handles both the data model value and the field value.
- *
- * @return The value of the property data source
- */
- private Object getDataSourceValue() {
- return dataSource.getValue();
- }
-
- /**
- * Returns the field value. This is always identical to {@link #getValue()}
- * and only here because of clarity in the code that handles both the data
- * model value and the field value.
- *
- * @return The value of the field
- */
- private T getFieldValue() {
- // Give the value from abstract buffers if the field if possible
- if (dataSource == null || isBuffered() || isModified()) {
- return getInternalValue();
- }
-
- // There is no buffered value so use whatever the data model provides
- return convertFromModel(getDataSourceValue());
- }
-
- /*
- * Has the field been modified since the last commit()? Don't add a JavaDoc
- * comment here, we use the default documentation from the implemented
- * interface.
- */
- @Override
- public boolean isModified() {
- return getState(false).modified;
- }
-
- private void setModified(boolean modified) {
- getState().modified = modified;
- }
-
- /**
- * Sets the buffered mode of this Field.
- * <p>
- * When the field is in buffered mode, changes will not be committed to the
- * property data source until {@link #commit()} is called.
- * </p>
- * <p>
- * Setting buffered mode from true to false will commit any pending changes.
- * </p>
- * <p>
- *
- * </p>
- *
- * @since 7.0.0
- * @param buffered
- * true if buffered mode should be turned on, false otherwise
- */
- @Override
- public void setBuffered(boolean buffered) {
- if (this.buffered == buffered) {
- return;
- }
- this.buffered = buffered;
- if (!buffered) {
- commit();
- }
- }
-
- /**
- * Checks the buffered mode of this Field.
- *
- * @return true if buffered mode is on, false otherwise
- */
- @Override
- public boolean isBuffered() {
- return buffered;
- }
-
- // LegacyPropertyHelper has been removed in Vaadin 8
-
- /* Property interface implementation */
-
- /**
- * Gets the current value of the field.
- *
- * <p>
- * This is the visible, modified and possible invalid value the user have
- * entered to the field.
- * </p>
- *
- * <p>
- * Note that the object returned is compatible with getType(). For example,
- * if the type is String, this returns Strings even when the underlying
- * datasource is of some other type. In order to access the converted value,
- * use {@link #getConvertedValue()} and to access the value of the property
- * data source, use {@link Property#getValue()} for the property data
- * source.
- * </p>
- *
- * <p>
- * Since Vaadin 7.0, no implicit conversions between other data types and
- * String are performed, but a converter is used if set.
- * </p>
- *
- * @return the current value of the field.
- */
- @Override
- public T getValue() {
- return getFieldValue();
- }
-
- /**
- * Sets the value of the field.
- *
- * @param newFieldValue
- * the New value of the field.
- * @throws Property.ReadOnlyException
- */
- @Override
- public void setValue(T newFieldValue)
- throws Property.ReadOnlyException, Converter.ConversionException {
- setValue(newFieldValue, false);
- }
-
- /**
- * Sets the value of the field.
- *
- * @param newFieldValue
- * the New value of the field.
- * @param repaintIsNotNeeded
- * True if caller is sure that repaint is not needed.
- * @throws Property.ReadOnlyException
- * @throws Converter.ConversionException
- * @throws InvalidValueException
- */
- protected void setValue(T newFieldValue, boolean repaintIsNotNeeded) {
- setValue(newFieldValue, repaintIsNotNeeded, false);
- }
-
- /**
- * Sets the value of the field.
- *
- * @since 7.5.7
- * @param newFieldValue
- * the New value of the field.
- * @param repaintIsNotNeeded
- * True if caller is sure that repaint is not needed.
- * @param ignoreReadOnly
- * True if the read-only check should be ignored
- * @throws Property.ReadOnlyException
- * @throws Converter.ConversionException
- * @throws InvalidValueException
- */
- protected void setValue(T newFieldValue, boolean repaintIsNotNeeded,
- boolean ignoreReadOnly) throws Property.ReadOnlyException,
- Converter.ConversionException, InvalidValueException {
-
- if (!SharedUtil.equals(newFieldValue, getInternalValue())) {
-
- // Read only fields can not be changed
- if (!ignoreReadOnly && isReadOnly()) {
- throw new Property.ReadOnlyException();
- }
- try {
- T doubleConvertedFieldValue = convertFromModel(
- convertToModel(newFieldValue));
- if (!SharedUtil.equals(newFieldValue,
- doubleConvertedFieldValue)) {
- newFieldValue = doubleConvertedFieldValue;
- repaintIsNotNeeded = false;
- }
- } catch (Throwable t) {
- // Ignore exceptions in the conversion at this stage. Any
- // conversion error will be handled later by validate().
- }
-
- // Repaint is needed even when the client thinks that it knows the
- // new state if validity of the component may change
- if (repaintIsNotNeeded && (isRequired() || hasValidators()
- || getConverter() != null)) {
- repaintIsNotNeeded = false;
- }
-
- if (!isInvalidAllowed()) {
- /*
- * If invalid values are not allowed the value must be validated
- * before it is set. If validation fails, the
- * InvalidValueException is thrown and the internal value is not
- * updated.
- */
- validate(newFieldValue);
- }
-
- // Changes the value
- setInternalValue(newFieldValue);
- setModified(dataSource != null);
-
- valueWasModifiedByDataSourceDuringCommit = false;
- // In not buffering, try to commit
- if (!isBuffered() && dataSource != null
- && (isInvalidCommitted() || isValid())) {
- try {
-
- // Commits the value to datasource
- committingValueToDataSource = true;
- getPropertyDataSource()
- .setValue(convertToModel(newFieldValue));
-
- // The buffer is now unmodified
- setModified(false);
-
- } catch (final Throwable e) {
-
- // Sets the buffering state
- currentBufferedSourceException = new Buffered.SourceException(
- this, e);
- markAsDirty();
-
- // Throws the source exception
- throw currentBufferedSourceException;
- } finally {
- committingValueToDataSource = false;
- }
- }
-
- // If successful, remove set the buffering state to be ok
- if (getCurrentBufferedSourceException() != null) {
- setCurrentBufferedSourceException(null);
- }
-
- if (valueWasModifiedByDataSourceDuringCommit) {
- /*
- * Value was modified by datasource. Force repaint even if
- * repaint was not requested.
- */
- valueWasModifiedByDataSourceDuringCommit = repaintIsNotNeeded = false;
- }
-
- // Fires the value change
- fireValueChange(repaintIsNotNeeded);
-
- }
- }
-
- @Deprecated
- static boolean equals(Object value1, Object value2) {
- return SharedUtil.equals(value1, value2);
- }
-
- /* External data source */
-
- /**
- * Gets the current data source of the field, if any.
- *
- * @return the current data source as a Property, or <code>null</code> if
- * none defined.
- */
- @Override
- public Property getPropertyDataSource() {
- return dataSource;
- }
-
- /**
- * <p>
- * Sets the specified Property as the data source for the field. All
- * uncommitted changes are replaced with a value from the new data source.
- * </p>
- *
- * <p>
- * If the datasource has any validators, the same validators are added to
- * the field. Because the default behavior of the field is to allow invalid
- * values, but not to allow committing them, this only adds visual error
- * messages to fields and do not allow committing them as long as the value
- * is invalid. After the value is valid, the error message is not shown and
- * the commit can be done normally.
- * </p>
- *
- * <p>
- * If the data source implements {@link Property.ValueChangeNotifier} and/or
- * {@link Property.ReadOnlyStatusChangeNotifier}, the field registers itself
- * as a listener and updates itself according to the events it receives. To
- * avoid memory leaks caused by references to a field no longer in use, the
- * listener registrations are removed on {@link AbstractField#detach()
- * detach} and re-added on {@link AbstractField#attach() attach}.
- * </p>
- *
- * <p>
- * Note: before 6.5 we actually called discard() method in the beginning of
- * the method. This was removed to simplify implementation, avoid excess
- * calls to backing property and to avoid odd value change events that were
- * previously fired (developer expects 0-1 value change events if this
- * method is called). Some complex field implementations might now need to
- * override this method to do housekeeping similar to discard().
- * </p>
- *
- * @param newDataSource
- * the new data source Property.
- */
- @Override
- public void setPropertyDataSource(Property newDataSource) {
-
- // Saves the old value
- final Object oldValue = getInternalValue();
-
- // Stop listening to the old data source
- removePropertyListeners();
-
- // Sets the new data source
- dataSource = newDataSource;
- getState().propertyReadOnly = dataSource == null ? false
- : dataSource.isReadOnly();
-
- // Check if the current converter is compatible.
- if (newDataSource != null
- && !ConverterUtil.canConverterPossiblyHandle(getConverter(),
- getType(), newDataSource.getType())) {
- // There is no converter set or there is no way the current
- // converter can be compatible.
- setConverter(newDataSource.getType());
- }
- // Gets the value from source. This requires that a valid converter has
- // been set.
- try {
- if (dataSource != null) {
- T fieldValue = convertFromModel(getDataSourceValue());
- setInternalValue(fieldValue);
- }
- setModified(false);
- if (getCurrentBufferedSourceException() != null) {
- setCurrentBufferedSourceException(null);
- }
- } catch (final Throwable e) {
- setCurrentBufferedSourceException(
- new Buffered.SourceException(this, e));
- setModified(true);
- throw getCurrentBufferedSourceException();
- }
-
- // Listen to new data source if possible
- addPropertyListeners();
-
- // Copy the validators from the data source
- if (dataSource instanceof Validatable) {
- final Collection<Validator> validators = ((Validatable) dataSource)
- .getValidators();
- if (validators != null) {
- for (final Validator v : validators) {
- addValidator(v);
- }
- }
- }
-
- // Fires value change if the value has changed
- T value = getInternalValue();
- if (value != oldValue && (value != null && !value.equals(oldValue)
- || value == null)) {
- fireValueChange(false);
- }
- }
-
- /**
- * Retrieves a converter for the field from the converter factory defined
- * for the application. Clears the converter if no application reference is
- * available or if the factory returns null.
- *
- * @param datamodelType
- * The type of the data model that we want to be able to convert
- * from
- */
- public void setConverter(Class<?> datamodelType) {
- Converter<T, ?> c = (Converter<T, ?>) ConverterUtil
- .getConverter(getType(), datamodelType, getSession());
- setConverter(c);
- }
-
- /**
- * Convert the given value from the data source type to the UI type.
- *
- * @param newValue
- * The data source value to convert.
- * @return The converted value that is compatible with the UI type or the
- * original value if its type is compatible and no converter is set.
- * @throws Converter.ConversionException
- * if there is no converter and the type is not compatible with
- * the data source type.
- */
- private T convertFromModel(Object newValue) {
- return convertFromModel(newValue, getLocale());
- }
-
- /**
- * Convert the given value from the data source type to the UI type.
- *
- * @param newValue
- * The data source value to convert.
- * @return The converted value that is compatible with the UI type or the
- * original value if its type is compatible and no converter is set.
- * @throws Converter.ConversionException
- * if there is no converter and the type is not compatible with
- * the data source type.
- */
- private T convertFromModel(Object newValue, Locale locale) {
- return ConverterUtil.convertFromModel(newValue, getType(),
- getConverter(), locale);
- }
-
- /**
- * Convert the given value from the UI type to the data source type.
- *
- * @param fieldValue
- * The value to convert. Typically returned by
- * {@link #getFieldValue()}
- * @return The converted value that is compatible with the data source type.
- * @throws Converter.ConversionException
- * if there is no converter and the type is not compatible with
- * the data source type.
- */
- private Object convertToModel(T fieldValue)
- throws Converter.ConversionException {
- return convertToModel(fieldValue, getLocale());
- }
-
- /**
- * Convert the given value from the UI type to the data source type.
- *
- * @param fieldValue
- * The value to convert. Typically returned by
- * {@link #getFieldValue()}
- * @param locale
- * The locale to use for the conversion
- * @return The converted value that is compatible with the data source type.
- * @throws Converter.ConversionException
- * if there is no converter and the type is not compatible with
- * the data source type.
- */
- private Object convertToModel(T fieldValue, Locale locale)
- throws Converter.ConversionException {
- Class<?> modelType = getModelType();
- try {
- return ConverterUtil.convertToModel(fieldValue,
- (Class<Object>) modelType, getConverter(), locale);
- } catch (ConversionException e) {
- throw new ConversionException(getConversionError(modelType, e), e);
- }
- }
-
- /**
- * Retrieves the type of the currently used data model. If the field has no
- * data source then the model type of the converter is used.
- *
- * @since 7.1
- * @return The type of the currently used data model or null if no data
- * source or converter is set.
- */
- protected Class<?> getModelType() {
- Property<?> pd = getPropertyDataSource();
- if (pd != null) {
- return pd.getType();
- } else if (getConverter() != null) {
- return getConverter().getModelType();
- }
- return null;
- }
-
- /**
- * Returns the conversion error with {0} replaced by the data source type
- * and {1} replaced by the exception (localized) message.
- *
- * @since 7.1
- * @param dataSourceType
- * the type of the data source
- * @param e
- * a conversion exception which can provide additional
- * information
- * @return The value conversion error string with parameters replaced.
- */
- protected String getConversionError(Class<?> dataSourceType,
- ConversionException e) {
- String conversionError = getConversionError();
-
- if (conversionError != null) {
- if (dataSourceType != null) {
- conversionError = conversionError.replace("{0}",
- dataSourceType.getSimpleName());
- }
- if (e != null) {
- conversionError = conversionError.replace("{1}",
- e.getLocalizedMessage());
- }
- }
- return conversionError;
- }
-
- /**
- * Returns the current value (as returned by {@link #getValue()}) converted
- * to the data source type.
- * <p>
- * This returns the same as {@link AbstractField#getValue()} if no converter
- * has been set. The value is not necessarily the same as the data source
- * value e.g. if the field is in buffered mode and has been modified.
- * </p>
- *
- * @return The converted value that is compatible with the data source type
- */
- public Object getConvertedValue() {
- return convertToModel(getFieldValue());
- }
-
- /**
- * Sets the value of the field using a value of the data source type. The
- * value given is converted to the field type and then assigned to the
- * field. This will update the property data source in the same way as when
- * {@link #setValue(Object)} is called.
- *
- * @param value
- * The value to set. Must be the same type as the data source.
- */
- public void setConvertedValue(Object value) {
- setValue(convertFromModel(value));
- }
-
- /* Validation */
-
- /**
- * Adds a new validator for the field's value. All validators added to a
- * field are checked each time the its value changes.
- *
- * @param validator
- * the new validator to be added.
- */
- @Override
- public void addValidator(Validator validator) {
- if (validators == null) {
- validators = new LinkedList<Validator>();
- }
- validators.add(validator);
- markAsDirty();
- }
-
- /**
- * Gets the validators of the field.
- *
- * @return An unmodifiable collection that holds all validators for the
- * field.
- */
- @Override
- public Collection<Validator> getValidators() {
- if (validators == null) {
- return Collections.emptyList();
- } else {
- return Collections.unmodifiableCollection(validators);
- }
- }
-
- private boolean hasValidators() {
- return validators != null && !validators.isEmpty();
- }
-
- /**
- * Removes the validator from the field.
- *
- * @param validator
- * the validator to remove.
- */
- @Override
- public void removeValidator(Validator validator) {
- if (validators != null) {
- validators.remove(validator);
- }
- markAsDirty();
- }
-
- /**
- * Removes all validators from the field.
- */
- @Override
- public void removeAllValidators() {
- if (validators != null) {
- validators.clear();
- }
- markAsDirty();
- }
-
- /**
- * Tests the current value against registered validators if the field is not
- * empty. If the field is empty it is considered valid if it is not required
- * and invalid otherwise. Validators are never checked for empty fields.
- *
- * In most cases, {@link #validate()} should be used instead of
- * {@link #isValid()} to also get the error message.
- *
- * @return <code>true</code> if all registered validators claim that the
- * current value is valid or if the field is empty and not required,
- * <code>false</code> otherwise.
- */
- @Override
- public boolean isValid() {
-
- try {
- validate();
- return true;
- } catch (InvalidValueException e) {
- return false;
- }
- }
-
- /**
- * Checks the validity of the Field.
- *
- * A field is invalid if it is set as required (using
- * {@link #setRequired(boolean)} and is empty, if one or several of the
- * validators added to the field indicate it is invalid or if the value
- * cannot be converted provided a converter has been set.
- *
- * The "required" validation is a built-in validation feature. If the field
- * is required and empty this method throws an EmptyValueException with the
- * error message set using {@link #setRequiredError(String)}.
- *
- * @see Validatable#validate()
- */
- @Override
- public void validate() throws Validator.InvalidValueException {
-
- if (isRequired() && isEmpty()) {
- throw new Validator.EmptyValueException(requiredError);
- }
- validate(getFieldValue());
- }
-
- /**
- * Validates that the given value pass the validators for the field.
- * <p>
- * This method does not check the requiredness of the field.
- *
- * @param fieldValue
- * The value to check
- * @throws Validator.InvalidValueException
- * if one or several validators fail
- */
- protected void validate(T fieldValue)
- throws Validator.InvalidValueException {
-
- Object valueToValidate = fieldValue;
-
- // If there is a converter we start by converting the value as we want
- // to validate the converted value
- if (getConverter() != null) {
- try {
- valueToValidate = getConverter().convertToModel(fieldValue,
- getModelType(), getLocale());
- } catch (ConversionException e) {
- throw new InvalidValueException(
- getConversionError(getConverter().getModelType(), e));
- }
- }
-
- List<InvalidValueException> validationExceptions = new ArrayList<InvalidValueException>();
- if (validators != null) {
- // Gets all the validation errors
- for (Validator v : validators) {
- try {
- v.validate(valueToValidate);
- } catch (final Validator.InvalidValueException e) {
- validationExceptions.add(e);
- }
- }
- }
-
- // If there were no errors
- if (validationExceptions.isEmpty()) {
- return;
- }
-
- // If only one error occurred, throw it forwards
- if (validationExceptions.size() == 1) {
- throw validationExceptions.get(0);
- }
-
- InvalidValueException[] exceptionArray = validationExceptions.toArray(
- new InvalidValueException[validationExceptions.size()]);
-
- // Create a composite validator and include all exceptions
- throw new Validator.InvalidValueException(null, exceptionArray);
- }
-
- /**
- * Fields allow invalid values by default. In most cases this is wanted,
- * because the field otherwise visually forget the user input immediately.
- *
- * @return true if invalid values are allowed.
- * @see Validatable#isInvalidAllowed()
- */
- @Override
- public boolean isInvalidAllowed() {
- return invalidAllowed;
- }
-
- /**
- * Fields allow invalid values by default. In most cases this is wanted,
- * because the field otherwise visually forget the user input immediately.
- * <p>
- * In common setting where the user wants to assure the correctness of the
- * datasource, but allow temporarily invalid contents in the field, the user
- * should add the validators to datasource, that should not allow invalid
- * values. The validators are automatically copied to the field when the
- * datasource is set.
- * </p>
- *
- * @see Validatable#setInvalidAllowed(boolean)
- */
- @Override
- public void setInvalidAllowed(boolean invalidAllowed)
- throws UnsupportedOperationException {
- this.invalidAllowed = invalidAllowed;
- }
-
- /**
- * Error messages shown by the fields are composites of the error message
- * thrown by the superclasses (that is the component error message),
- * validation errors and buffered source errors.
- *
- * @see com.vaadin.ui.AbstractComponent#getErrorMessage()
- */
- @Override
- public ErrorMessage getErrorMessage() {
-
- /*
- * Check validation errors only if automatic validation is enabled.
- * Empty, required fields will generate a validation error containing
- * the requiredError string. For these fields the exclamation mark will
- * be hidden but the error must still be sent to the client.
- */
- Validator.InvalidValueException validationError = null;
- if (isValidationVisible()) {
- try {
- validate();
- } catch (Validator.InvalidValueException e) {
- if (!e.isInvisible()) {
- validationError = e;
- }
- }
- }
-
- // Check if there are any systems errors
- final ErrorMessage superError = super.getErrorMessage();
-
- // Return if there are no errors at all
- if (superError == null && validationError == null
- && getCurrentBufferedSourceException() == null) {
- return null;
- }
-
- // Throw combination of the error types
- return new CompositeErrorMessage(new ErrorMessage[] { superError,
- AbstractErrorMessage
- .getErrorMessageForException(validationError),
- AbstractErrorMessage.getErrorMessageForException(
- getCurrentBufferedSourceException()) });
-
- }
-
- /* Value change events */
-
- private static final Method VALUE_CHANGE_METHOD;
-
- static {
- try {
- VALUE_CHANGE_METHOD = Property.ValueChangeListener.class
- .getDeclaredMethod("valueChange",
- new Class[] { Property.ValueChangeEvent.class });
- } catch (final NoSuchMethodException e) {
- // This should never happen
- throw new RuntimeException(
- "Internal error finding methods in AbstractField");
- }
- }
-
- /*
- * Adds a value change listener for the field. Don't add a JavaDoc comment
- * here, we use the default documentation from the implemented interface.
- */
- @Override
- public void addValueChangeListener(Property.ValueChangeListener listener) {
- addListener(AbstractField.ValueChangeEvent.class, listener,
- VALUE_CHANGE_METHOD);
- // ensure "automatic immediate handling" works
- markAsDirty();
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #addValueChangeListener(Property.ValueChangeListener)}
- */
- @Override
- @Deprecated
- public void addListener(Property.ValueChangeListener listener) {
- addValueChangeListener(listener);
- }
-
- /*
- * Removes a value change listener from the field. Don't add a JavaDoc
- * comment here, we use the default documentation from the implemented
- * interface.
- */
- @Override
- public void removeValueChangeListener(
- Property.ValueChangeListener listener) {
- removeListener(AbstractField.ValueChangeEvent.class, listener,
- VALUE_CHANGE_METHOD);
- // ensure "automatic immediate handling" works
- markAsDirty();
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removeValueChangeListener(Property.ValueChangeListener)}
- */
- @Override
- @Deprecated
- public void removeListener(Property.ValueChangeListener listener) {
- removeValueChangeListener(listener);
- }
-
- /**
- * Emits the value change event. The value contained in the field is
- * validated before the event is created.
- */
- protected void fireValueChange(boolean repaintIsNotNeeded) {
- fireEvent(new AbstractField.ValueChangeEvent(this));
- if (!repaintIsNotNeeded) {
- markAsDirty();
- }
- }
-
- /* Read-only status change events */
-
- private static final Method READ_ONLY_STATUS_CHANGE_METHOD;
-
- static {
- try {
- READ_ONLY_STATUS_CHANGE_METHOD = Property.ReadOnlyStatusChangeListener.class
- .getDeclaredMethod("readOnlyStatusChange", new Class[] {
- Property.ReadOnlyStatusChangeEvent.class });
- } catch (final NoSuchMethodException e) {
- // This should never happen
- throw new RuntimeException(
- "Internal error finding methods in AbstractField");
- }
- }
-
- /**
- * React to read only status changes of the property by requesting a
- * repaint.
- *
- * @see Property.ReadOnlyStatusChangeListener
- */
- @Override
- public void readOnlyStatusChange(Property.ReadOnlyStatusChangeEvent event) {
- boolean readOnly = event.getProperty().isReadOnly();
-
- boolean shouldFireChange = isReadOnly() != readOnly
- || getState().propertyReadOnly != readOnly;
-
- getState().propertyReadOnly = readOnly;
-
- if (shouldFireChange) {
- fireReadOnlyStatusChange();
- }
- }
-
- /**
- * An <code>Event</code> object specifying the Property whose read-only
- * status has changed.
- *
- * @author Vaadin Ltd.
- * @since 3.0
- */
- @Deprecated
- public static class ReadOnlyStatusChangeEvent extends Component.Event
- implements Property.ReadOnlyStatusChangeEvent {
-
- /**
- * New instance of text change event.
- *
- * @param source
- * the Source of the event.
- */
- public ReadOnlyStatusChangeEvent(AbstractField source) {
- super(source);
- }
-
- /**
- * Property where the event occurred.
- *
- * @return the Source of the event.
- */
- @Override
- public Property getProperty() {
- return (Property) getSource();
- }
- }
-
- /*
- * Adds a read-only status change listener for the field. Don't add a
- * JavaDoc comment here, we use the default documentation from the
- * implemented interface.
- */
- @Override
- public void addReadOnlyStatusChangeListener(
- Property.ReadOnlyStatusChangeListener listener) {
- addListener(Property.ReadOnlyStatusChangeEvent.class, listener,
- READ_ONLY_STATUS_CHANGE_METHOD);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #addReadOnlyStatusChangeListener(Property.ReadOnlyStatusChangeListener)}
- */
- @Override
- @Deprecated
- public void addListener(Property.ReadOnlyStatusChangeListener listener) {
- addReadOnlyStatusChangeListener(listener);
- }
-
- /*
- * Removes a read-only status change listener from the field. Don't add a
- * JavaDoc comment here, we use the default documentation from the
- * implemented interface.
- */
- @Override
- public void removeReadOnlyStatusChangeListener(
- Property.ReadOnlyStatusChangeListener listener) {
- removeListener(Property.ReadOnlyStatusChangeEvent.class, listener,
- READ_ONLY_STATUS_CHANGE_METHOD);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removeReadOnlyStatusChangeListener(Property.ReadOnlyStatusChangeListener)}
- */
- @Override
- @Deprecated
- public void removeListener(Property.ReadOnlyStatusChangeListener listener) {
- removeReadOnlyStatusChangeListener(listener);
- }
-
- /**
- * Emits the read-only status change event. The value contained in the field
- * is validated before the event is created.
- */
- protected void fireReadOnlyStatusChange() {
- fireEvent(new AbstractField.ReadOnlyStatusChangeEvent(this));
- }
-
- /**
- * This method listens to data source value changes and passes the changes
- * forwards.
- *
- * Changes are not forwarded to the listeners of the field during internal
- * operations of the field to avoid duplicate notifications.
- *
- * @param event
- * the value change event telling the data source contents have
- * changed.
- */
- @Override
- public void valueChange(Property.ValueChangeEvent event) {
- if (!isBuffered()) {
- if (committingValueToDataSource) {
- boolean propertyNotifiesOfTheBufferedValue = SharedUtil.equals(
- event.getProperty().getValue(), getInternalValue());
- if (!propertyNotifiesOfTheBufferedValue) {
- /*
- * Property (or chained property like PropertyFormatter) now
- * reports different value than the one the field has just
- * committed to it. In this case we respect the property
- * value.
- *
- * Still, we don't fire value change yet, but instead
- * postpone it until "commit" is done. See setValue(Object,
- * boolean) and commit().
- */
- readValueFromProperty(event);
- valueWasModifiedByDataSourceDuringCommit = true;
- }
- } else if (!isModified()) {
- readValueFromProperty(event);
- fireValueChange(false);
- }
- }
- }
-
- private void readValueFromProperty(Property.ValueChangeEvent event) {
- setInternalValue(convertFromModel(event.getProperty().getValue()));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void focus() {
- super.focus();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.Component.Focusable#getTabIndex()
- */
- @Override
- public int getTabIndex() {
- return getState(false).tabIndex;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.Component.Focusable#setTabIndex(int)
- */
- @Override
- public void setTabIndex(int tabIndex) {
- getState().tabIndex = tabIndex;
- }
-
- /**
- * Returns the internal field value, which might not match the data source
- * value e.g. if the field has been modified and is not in write-through
- * mode.
- *
- * This method can be overridden by subclasses together with
- * {@link #setInternalValue(Object)} to compute internal field value at
- * runtime. When doing so, typically also {@link #isModified()} needs to be
- * overridden and care should be taken in the management of the empty state
- * and buffering support.
- *
- * @return internal field value
- */
- protected T getInternalValue() {
- return value;
- }
-
- /**
- * Sets the internal field value. This is purely used by AbstractField to
- * change the internal Field value. It does not trigger valuechange events.
- * It can be overridden by the inheriting classes to update all dependent
- * variables.
- *
- * Subclasses can also override {@link #getInternalValue()} if necessary.
- *
- * @param newValue
- * the new value to be set.
- */
- protected void setInternalValue(T newValue) {
- value = newValue;
- valueLocale = getLocale();
- if (validators != null && !validators.isEmpty()) {
- markAsDirty();
- }
- }
-
- /**
- * Notifies the component that it is connected to an application.
- *
- * @see com.vaadin.ui.Component#attach()
- */
- @Override
- public void attach() {
- super.attach();
-
- localeMightHaveChanged();
- if (!isListeningToPropertyEvents) {
- addPropertyListeners();
- if (!isModified() && !isBuffered()) {
- // Update value from data source
- updateValueFromDataSource();
- }
- }
- }
-
- @Override
- public void setLocale(Locale locale) {
- super.setLocale(locale);
- localeMightHaveChanged();
- }
-
- private void localeMightHaveChanged() {
- if (!SharedUtil.equals(valueLocale, getLocale())) {
- // The locale HAS actually changed
-
- if (dataSource != null && !isModified()) {
- // When we have a data source and the internal value is directly
- // read from that we want to update the value
- T newInternalValue = convertFromModel(
- getPropertyDataSource().getValue());
- if (!SharedUtil.equals(newInternalValue, getInternalValue())) {
- setInternalValue(newInternalValue);
- fireValueChange(false);
- }
- } else if (dataSource == null && converter != null) {
- /*
- * No data source but a converter has been set. The same issues
- * as above but we cannot use propertyDataSource. Convert the
- * current value back to a model value using the old locale and
- * then convert back using the new locale. If this does not
- * match the field value we need to set the converted value
- * again.
- */
- Object convertedValue = convertToModel(getInternalValue(),
- valueLocale);
- T newinternalValue = convertFromModel(convertedValue);
- if (!SharedUtil.equals(getInternalValue(), newinternalValue)) {
- setInternalValue(newinternalValue);
- fireValueChange(false);
- }
- }
- }
- }
-
- @Override
- public void detach() {
- super.detach();
- // Stop listening to data source events on detach to avoid a potential
- // memory leak. See #6155.
- removePropertyListeners();
- }
-
- @Override
- public boolean isRequired() {
- return getState(false).required;
- }
-
- @Override
- public void setRequired(boolean required) {
- getState().required = required;
- }
-
- /**
- * Set the error that is show if this field is required, but empty. When
- * setting requiredMessage to be "" or null, no error pop-up or exclamation
- * mark is shown for a empty required field. This faults to "". Even in
- * those cases isValid() returns false for empty required fields.
- *
- * @param requiredMessage
- * Message to be shown when this field is required, but empty.
- */
- @Override
- public void setRequiredError(String requiredMessage) {
- requiredError = requiredMessage;
- markAsDirty();
- }
-
- @Override
- public String getRequiredError() {
- return requiredError;
- }
-
- /**
- * Gets the error that is shown if the field value cannot be converted to
- * the data source type.
- *
- * @return The error that is shown if conversion of the field value fails
- */
- public String getConversionError() {
- return conversionError;
- }
-
- /**
- * Sets the error that is shown if the field value cannot be converted to
- * the data source type. If {0} is present in the message, it will be
- * replaced by the simple name of the data source type. If {1} is present in
- * the message, it will be replaced by the ConversionException message.
- *
- * @param valueConversionError
- * Message to be shown when conversion of the value fails
- */
- public void setConversionError(String valueConversionError) {
- this.conversionError = valueConversionError;
- markAsDirty();
- }
-
- @Override
- public boolean isEmpty() {
- return getFieldValue() == null;
- }
-
- @Override
- public void clear() {
- setValue(null);
- }
-
- /**
- * Is automatic, visible validation enabled?
- *
- * If automatic validation is enabled, any validators connected to this
- * component are evaluated while painting the component and potential error
- * messages are sent to client. If the automatic validation is turned off,
- * isValid() and validate() methods still work, but one must show the
- * validation in their own code.
- *
- * @return True, if automatic validation is enabled.
- */
- public boolean isValidationVisible() {
- return validationVisible;
- }
-
- /**
- * Enable or disable automatic, visible validation.
- *
- * If automatic validation is enabled, any validators connected to this
- * component are evaluated while painting the component and potential error
- * messages are sent to client. If the automatic validation is turned off,
- * isValid() and validate() methods still work, but one must show the
- * validation in their own code.
- *
- * @param validateAutomatically
- * True, if automatic validation is enabled.
- */
- public void setValidationVisible(boolean validateAutomatically) {
- if (validationVisible != validateAutomatically) {
- markAsDirty();
- validationVisible = validateAutomatically;
- }
- }
-
- /**
- * Sets the current buffered source exception.
- *
- * @param currentBufferedSourceException
- */
- public void setCurrentBufferedSourceException(
- Buffered.SourceException currentBufferedSourceException) {
- this.currentBufferedSourceException = currentBufferedSourceException;
- markAsDirty();
- }
-
- /**
- * Gets the current buffered source exception.
- *
- * @return The current source exception
- */
- protected Buffered.SourceException getCurrentBufferedSourceException() {
- return currentBufferedSourceException;
- }
-
- /**
- * A ready-made {@link ShortcutListener} that focuses the given
- * {@link Focusable} (usually a {@link Field}) when the keyboard shortcut is
- * invoked.
- *
- * @deprecated Replaced in 8.0 with {@link com.vaadin.event.FocusShortcut}
- */
- @Deprecated
- public static class FocusShortcut extends ShortcutListener {
- protected Focusable focusable;
-
- /**
- * Creates a keyboard shortcut for focusing the given {@link Focusable}
- * using the shorthand notation defined in {@link ShortcutAction}.
- *
- * @param focusable
- * to focused when the shortcut is invoked
- * @param shorthandCaption
- * caption with keycode and modifiers indicated
- */
- public FocusShortcut(Focusable focusable, String shorthandCaption) {
- super(shorthandCaption);
- this.focusable = focusable;
- }
-
- /**
- * Creates a keyboard shortcut for focusing the given {@link Focusable}.
- *
- * @param focusable
- * to focused when the shortcut is invoked
- * @param keyCode
- * keycode that invokes the shortcut
- * @param modifiers
- * modifiers required to invoke the shortcut
- */
- public FocusShortcut(Focusable focusable, int keyCode,
- int... modifiers) {
- super(null, keyCode, modifiers);
- this.focusable = focusable;
- }
-
- /**
- * Creates a keyboard shortcut for focusing the given {@link Focusable}.
- *
- * @param focusable
- * to focused when the shortcut is invoked
- * @param keyCode
- * keycode that invokes the shortcut
- */
- public FocusShortcut(Focusable focusable, int keyCode) {
- this(focusable, keyCode, null);
- }
-
- @Override
- public void handleAction(Object sender, Object target) {
- focusable.focus();
- }
- }
-
- private void updateValueFromDataSource() {
- if (dataSource != null) {
-
- // Gets the correct value from datasource
- T newFieldValue;
- try {
-
- // Discards buffer by overwriting from datasource
- newFieldValue = convertFromModel(getDataSourceValue());
-
- // If successful, remove set the buffering state to be ok
- if (getCurrentBufferedSourceException() != null) {
- setCurrentBufferedSourceException(null);
- }
- } catch (final Throwable e) {
- // FIXME: What should really be done here if conversion fails?
-
- // Sets the buffering state
- currentBufferedSourceException = new Buffered.SourceException(
- this, e);
- markAsDirty();
-
- // Throws the source exception
- throw currentBufferedSourceException;
- }
-
- final boolean wasModified = isModified();
- setModified(false);
-
- // If the new value differs from the previous one
- if (!SharedUtil.equals(newFieldValue, getInternalValue())) {
- setInternalValue(newFieldValue);
- fireValueChange(false);
- } else if (wasModified) {
- // If the value did not change, but the modification status did
- markAsDirty();
- }
- }
- }
-
- /**
- * Gets the converter used to convert the property data source value to the
- * field value.
- *
- * @return The converter or null if none is set.
- */
- public Converter<T, Object> getConverter() {
- return converter;
- }
-
- /**
- * Sets the converter used to convert the field value to property data
- * source type. The converter must have a presentation type that matches the
- * field type.
- *
- * @param converter
- * The new converter to use.
- */
- public void setConverter(Converter<T, ?> converter) {
- this.converter = (Converter<T, Object>) converter;
- markAsDirty();
- }
-
- @Override
- protected AbstractFieldState getState() {
- return (AbstractFieldState) super.getState();
- }
-
- @Override
- protected AbstractFieldState getState(boolean markAsDirty) {
- return (AbstractFieldState) super.getState(markAsDirty);
- }
-
- @Override
- public void beforeClientResponse(boolean initial) {
- super.beforeClientResponse(initial);
-
- // Hide the error indicator if needed
- getState().hideErrors = shouldHideErrors();
- }
-
- /**
- * Registers this as an event listener for events sent by the data source
- * (if any). Does nothing if
- * <code>isListeningToPropertyEvents == true</code>.
- */
- private void addPropertyListeners() {
- if (!isListeningToPropertyEvents) {
- if (dataSource instanceof Property.ValueChangeNotifier) {
- ((Property.ValueChangeNotifier) dataSource).addListener(this);
- }
- if (dataSource instanceof Property.ReadOnlyStatusChangeNotifier) {
- ((Property.ReadOnlyStatusChangeNotifier) dataSource)
- .addListener(this);
- }
- isListeningToPropertyEvents = true;
- }
- }
-
- /**
- * Stops listening to events sent by the data source (if any). Does nothing
- * if <code>isListeningToPropertyEvents == false</code>.
- */
- private void removePropertyListeners() {
- if (isListeningToPropertyEvents) {
- if (dataSource instanceof Property.ValueChangeNotifier) {
- ((Property.ValueChangeNotifier) dataSource)
- .removeListener(this);
- }
- if (dataSource instanceof Property.ReadOnlyStatusChangeNotifier) {
- ((Property.ReadOnlyStatusChangeNotifier) dataSource)
- .removeListener(this);
- }
- isListeningToPropertyEvents = false;
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.AbstractComponent#readDesign(org.jsoup.nodes .Element,
- * com.vaadin.ui.declarative.DesignContext)
- */
- @Override
- public void readDesign(Element design, DesignContext designContext) {
- super.readDesign(design, designContext);
- Attributes attr = design.attributes();
- if (design.hasAttr("readonly")) {
- setReadOnly(DesignAttributeHandler.readAttribute("readonly", attr,
- Boolean.class));
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.AbstractComponent#getCustomAttributes()
- */
- @Override
- protected Collection<String> getCustomAttributes() {
- Collection<String> attributes = super.getCustomAttributes();
- attributes.add("readonly");
- // must be handled by subclasses
- attributes.add("value");
- attributes.add("converted-value");
- return attributes;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.ui.AbstractComponent#writeDesign(org.jsoup.nodes.Element
- * , com.vaadin.ui.declarative.DesignContext)
- */
- @Override
- public void writeDesign(Element design, DesignContext designContext) {
- super.writeDesign(design, designContext);
- AbstractField<?> def = designContext.getDefaultInstance(this);
- Attributes attr = design.attributes();
- // handle readonly
- DesignAttributeHandler.writeAttribute("readonly", attr,
- super.isReadOnly(), def.isReadOnly(), Boolean.class,
- designContext);
- }
- }
|