選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

AbstractField.java 53KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612
  1. /*
  2. * Copyright 2011 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.ui;
  17. import java.io.Serializable;
  18. import java.lang.reflect.Method;
  19. import java.util.ArrayList;
  20. import java.util.Collection;
  21. import java.util.Collections;
  22. import java.util.Iterator;
  23. import java.util.LinkedList;
  24. import java.util.List;
  25. import java.util.logging.Logger;
  26. import com.vaadin.data.Buffered;
  27. import com.vaadin.data.Property;
  28. import com.vaadin.data.Validatable;
  29. import com.vaadin.data.Validator;
  30. import com.vaadin.data.Validator.InvalidValueException;
  31. import com.vaadin.data.util.converter.Converter;
  32. import com.vaadin.data.util.converter.Converter.ConversionException;
  33. import com.vaadin.data.util.converter.ConverterUtil;
  34. import com.vaadin.event.Action;
  35. import com.vaadin.event.ShortcutAction;
  36. import com.vaadin.event.ShortcutListener;
  37. import com.vaadin.server.AbstractErrorMessage;
  38. import com.vaadin.server.CompositeErrorMessage;
  39. import com.vaadin.server.ErrorMessage;
  40. import com.vaadin.shared.AbstractFieldState;
  41. /**
  42. * <p>
  43. * Abstract field component for implementing buffered property editors. The
  44. * field may hold an internal value, or it may be connected to any data source
  45. * that implements the {@link com.vaadin.data.Property}interface.
  46. * <code>AbstractField</code> implements that interface itself, too, so
  47. * accessing the Property value represented by it is straightforward.
  48. * </p>
  49. *
  50. * <p>
  51. * AbstractField also provides the {@link com.vaadin.data.Buffered} interface
  52. * for buffering the data source value. By default the Field is in write
  53. * through-mode and {@link #setWriteThrough(boolean)}should be called to enable
  54. * buffering.
  55. * </p>
  56. *
  57. * <p>
  58. * The class also supports {@link com.vaadin.data.Validator validators} to make
  59. * sure the value contained in the field is valid.
  60. * </p>
  61. *
  62. * @author Vaadin Ltd.
  63. * @since 3.0
  64. */
  65. @SuppressWarnings("serial")
  66. public abstract class AbstractField<T> extends AbstractComponent implements
  67. Field<T>, Property.ReadOnlyStatusChangeListener,
  68. Property.ReadOnlyStatusChangeNotifier, Action.ShortcutNotifier {
  69. /* Private members */
  70. private static final Logger logger = Logger.getLogger(AbstractField.class
  71. .getName());
  72. /**
  73. * Value of the abstract field.
  74. */
  75. private T value;
  76. /**
  77. * A converter used to convert from the data model type to the field type
  78. * and vice versa.
  79. */
  80. private Converter<T, Object> converter = null;
  81. /**
  82. * Connected data-source.
  83. */
  84. private Property<?> dataSource = null;
  85. /**
  86. * The list of validators.
  87. */
  88. private LinkedList<Validator> validators = null;
  89. /**
  90. * True if field is in buffered mode, false otherwise
  91. */
  92. private boolean buffered;
  93. /**
  94. * Flag to indicate that the field is currently committing its value to the
  95. * datasource.
  96. */
  97. private boolean committingValueToDataSource = false;
  98. /**
  99. * Current source exception.
  100. */
  101. private Buffered.SourceException currentBufferedSourceException = null;
  102. /**
  103. * Are the invalid values allowed in fields ?
  104. */
  105. private boolean invalidAllowed = true;
  106. /**
  107. * Are the invalid values committed ?
  108. */
  109. private boolean invalidCommitted = false;
  110. /**
  111. * The error message for the exception that is thrown when the field is
  112. * required but empty.
  113. */
  114. private String requiredError = "";
  115. /**
  116. * The error message that is shown when the field value cannot be converted.
  117. */
  118. private String conversionError = "Could not convert value to {0}";
  119. /**
  120. * Is automatic validation enabled.
  121. */
  122. private boolean validationVisible = true;
  123. private boolean valueWasModifiedByDataSourceDuringCommit;
  124. /**
  125. * Whether this field is currently registered as listening to events from
  126. * its data source.
  127. *
  128. * @see #setPropertyDataSource(Property)
  129. * @see #addPropertyListeners()
  130. * @see #removePropertyListeners()
  131. */
  132. private boolean isListeningToPropertyEvents = false;
  133. /* Component basics */
  134. /*
  135. * Paints the field. Don't add a JavaDoc comment here, we use the default
  136. * documentation from the implemented interface.
  137. */
  138. /**
  139. * Returns true if the error indicator be hidden when painting the component
  140. * even when there are errors.
  141. *
  142. * This is a mostly internal method, but can be overridden in subclasses
  143. * e.g. if the error indicator should also be shown for empty fields in some
  144. * cases.
  145. *
  146. * @return true to hide the error indicator, false to use the normal logic
  147. * to show it when there are errors
  148. */
  149. protected boolean shouldHideErrors() {
  150. // getErrorMessage() can still return something else than null based on
  151. // validation etc.
  152. return isRequired() && isEmpty() && getComponentError() == null;
  153. }
  154. /**
  155. * Returns the type of the Field. The methods <code>getValue</code> and
  156. * <code>setValue</code> must be compatible with this type: one must be able
  157. * to safely cast the value returned from <code>getValue</code> to the given
  158. * type and pass any variable assignable to this type as an argument to
  159. * <code>setValue</code>.
  160. *
  161. * @return the type of the Field
  162. */
  163. @Override
  164. public abstract Class<? extends T> getType();
  165. /**
  166. * The abstract field is read only also if the data source is in read only
  167. * mode.
  168. */
  169. @Override
  170. public boolean isReadOnly() {
  171. return super.isReadOnly()
  172. || (dataSource != null && dataSource.isReadOnly());
  173. }
  174. /**
  175. * Changes the readonly state and throw read-only status change events.
  176. *
  177. * @see com.vaadin.ui.Component#setReadOnly(boolean)
  178. */
  179. @Override
  180. public void setReadOnly(boolean readOnly) {
  181. super.setReadOnly(readOnly);
  182. fireReadOnlyStatusChange();
  183. }
  184. /**
  185. * Tests if the invalid data is committed to datasource.
  186. *
  187. * @see com.vaadin.data.BufferedValidatable#isInvalidCommitted()
  188. */
  189. @Override
  190. public boolean isInvalidCommitted() {
  191. return invalidCommitted;
  192. }
  193. /**
  194. * Sets if the invalid data should be committed to datasource.
  195. *
  196. * @see com.vaadin.data.BufferedValidatable#setInvalidCommitted(boolean)
  197. */
  198. @Override
  199. public void setInvalidCommitted(boolean isCommitted) {
  200. invalidCommitted = isCommitted;
  201. }
  202. /*
  203. * Saves the current value to the data source Don't add a JavaDoc comment
  204. * here, we use the default documentation from the implemented interface.
  205. */
  206. @Override
  207. public void commit() throws Buffered.SourceException, InvalidValueException {
  208. if (dataSource != null && !dataSource.isReadOnly()) {
  209. if ((isInvalidCommitted() || isValid())) {
  210. try {
  211. // Commits the value to datasource.
  212. valueWasModifiedByDataSourceDuringCommit = false;
  213. committingValueToDataSource = true;
  214. getPropertyDataSource().setValue(getConvertedValue());
  215. } catch (final Throwable e) {
  216. // Sets the buffering state.
  217. SourceException sourceException = new Buffered.SourceException(
  218. this, e);
  219. setCurrentBufferedSourceException(sourceException);
  220. // Throws the source exception.
  221. throw sourceException;
  222. } finally {
  223. committingValueToDataSource = false;
  224. }
  225. } else {
  226. /* An invalid value and we don't allow them, throw the exception */
  227. validate();
  228. }
  229. }
  230. // The abstract field is not modified anymore
  231. if (isModified()) {
  232. setModified(false);
  233. }
  234. // If successful, remove set the buffering state to be ok
  235. if (getCurrentBufferedSourceException() != null) {
  236. setCurrentBufferedSourceException(null);
  237. }
  238. if (valueWasModifiedByDataSourceDuringCommit) {
  239. valueWasModifiedByDataSourceDuringCommit = false;
  240. fireValueChange(false);
  241. }
  242. }
  243. /*
  244. * Updates the value from the data source. Don't add a JavaDoc comment here,
  245. * we use the default documentation from the implemented interface.
  246. */
  247. @Override
  248. public void discard() throws Buffered.SourceException {
  249. updateValueFromDataSource();
  250. }
  251. /**
  252. * Gets the value from the data source. This is only here because of clarity
  253. * in the code that handles both the data model value and the field value.
  254. *
  255. * @return The value of the property data source
  256. */
  257. private Object getDataSourceValue() {
  258. return dataSource.getValue();
  259. }
  260. /**
  261. * Returns the field value. This is always identical to {@link #getValue()}
  262. * and only here because of clarity in the code that handles both the data
  263. * model value and the field value.
  264. *
  265. * @return The value of the field
  266. */
  267. private T getFieldValue() {
  268. // Give the value from abstract buffers if the field if possible
  269. if (dataSource == null || isBuffered() || isModified()) {
  270. return getInternalValue();
  271. }
  272. // There is no buffered value so use whatever the data model provides
  273. return convertFromDataSource(getDataSourceValue());
  274. }
  275. /*
  276. * Has the field been modified since the last commit()? Don't add a JavaDoc
  277. * comment here, we use the default documentation from the implemented
  278. * interface.
  279. */
  280. @Override
  281. public boolean isModified() {
  282. return getState().modified;
  283. }
  284. private void setModified(boolean modified) {
  285. getState().modified = modified;
  286. }
  287. /**
  288. * Sets the buffered mode of this Field.
  289. * <p>
  290. * When the field is in buffered mode, changes will not be committed to the
  291. * property data source until {@link #commit()} is called.
  292. * </p>
  293. * <p>
  294. * Setting buffered mode from true to false will commit any pending changes.
  295. * </p>
  296. * <p>
  297. *
  298. * </p>
  299. *
  300. * @since 7.0.0
  301. * @param buffered
  302. * true if buffered mode should be turned on, false otherwise
  303. */
  304. @Override
  305. public void setBuffered(boolean buffered) {
  306. if (this.buffered == buffered) {
  307. return;
  308. }
  309. this.buffered = buffered;
  310. if (!buffered) {
  311. commit();
  312. }
  313. }
  314. /**
  315. * Checks the buffered mode of this Field.
  316. *
  317. * @return true if buffered mode is on, false otherwise
  318. */
  319. @Override
  320. public boolean isBuffered() {
  321. return buffered;
  322. }
  323. /* Property interface implementation */
  324. /**
  325. * Returns the (field) value converted to a String using toString().
  326. *
  327. * @see java.lang.Object#toString()
  328. * @deprecated As of 7.0, use {@link #getValue()} to get the value of the
  329. * field, {@link #getConvertedValue()} to get the field value
  330. * converted to the data model type or
  331. * {@link #getPropertyDataSource()} .getValue() to get the value
  332. * of the data source.
  333. */
  334. @Deprecated
  335. @Override
  336. public String toString() {
  337. logger.warning("You are using AbstractField.toString() to get the value for a "
  338. + getClass().getSimpleName()
  339. + ". This will not be supported starting from Vaadin 7.1 "
  340. + "(your debugger might call toString() and cause this message to appear).");
  341. final Object value = getFieldValue();
  342. if (value == null) {
  343. return null;
  344. }
  345. return value.toString();
  346. }
  347. /**
  348. * Gets the current value of the field.
  349. *
  350. * <p>
  351. * This is the visible, modified and possible invalid value the user have
  352. * entered to the field.
  353. * </p>
  354. *
  355. * <p>
  356. * Note that the object returned is compatible with getType(). For example,
  357. * if the type is String, this returns Strings even when the underlying
  358. * datasource is of some other type. In order to access the converted value,
  359. * use {@link #getConvertedValue()} and to access the value of the property
  360. * data source, use {@link Property#getValue()} for the property data
  361. * source.
  362. * </p>
  363. *
  364. * <p>
  365. * Since Vaadin 7.0, no implicit conversions between other data types and
  366. * String are performed, but a converter is used if set.
  367. * </p>
  368. *
  369. * @return the current value of the field.
  370. */
  371. @Override
  372. public T getValue() {
  373. return getFieldValue();
  374. }
  375. /**
  376. * Sets the value of the field.
  377. *
  378. * @param newFieldValue
  379. * the New value of the field.
  380. * @throws Property.ReadOnlyException
  381. */
  382. @Override
  383. public void setValue(T newFieldValue) throws Property.ReadOnlyException,
  384. Converter.ConversionException {
  385. setValue(newFieldValue, false);
  386. }
  387. /**
  388. * Sets the value of the field.
  389. *
  390. * @param newFieldValue
  391. * the New value of the field.
  392. * @param repaintIsNotNeeded
  393. * True iff caller is sure that repaint is not needed.
  394. * @throws Property.ReadOnlyException
  395. */
  396. protected void setValue(T newFieldValue, boolean repaintIsNotNeeded)
  397. throws Property.ReadOnlyException, Converter.ConversionException,
  398. InvalidValueException {
  399. if (!equals(newFieldValue, getInternalValue())) {
  400. // Read only fields can not be changed
  401. if (isReadOnly()) {
  402. throw new Property.ReadOnlyException();
  403. }
  404. // Repaint is needed even when the client thinks that it knows the
  405. // new state if validity of the component may change
  406. if (repaintIsNotNeeded
  407. && (isRequired() || getValidators() != null || getConverter() != null)) {
  408. repaintIsNotNeeded = false;
  409. }
  410. if (!isInvalidAllowed()) {
  411. /*
  412. * If invalid values are not allowed the value must be validated
  413. * before it is set. If validation fails, the
  414. * InvalidValueException is thrown and the internal value is not
  415. * updated.
  416. */
  417. validate(newFieldValue);
  418. }
  419. // Changes the value
  420. setInternalValue(newFieldValue);
  421. setModified(dataSource != null);
  422. valueWasModifiedByDataSourceDuringCommit = false;
  423. // In not buffering, try to commit
  424. if (!isBuffered() && dataSource != null
  425. && (isInvalidCommitted() || isValid())) {
  426. try {
  427. // Commits the value to datasource
  428. committingValueToDataSource = true;
  429. getPropertyDataSource().setValue(
  430. convertToModel(newFieldValue));
  431. // The buffer is now unmodified
  432. setModified(false);
  433. } catch (final Throwable e) {
  434. // Sets the buffering state
  435. currentBufferedSourceException = new Buffered.SourceException(
  436. this, e);
  437. markAsDirty();
  438. // Throws the source exception
  439. throw currentBufferedSourceException;
  440. } finally {
  441. committingValueToDataSource = false;
  442. }
  443. }
  444. // If successful, remove set the buffering state to be ok
  445. if (getCurrentBufferedSourceException() != null) {
  446. setCurrentBufferedSourceException(null);
  447. }
  448. if (valueWasModifiedByDataSourceDuringCommit) {
  449. /*
  450. * Value was modified by datasource. Force repaint even if
  451. * repaint was not requested.
  452. */
  453. valueWasModifiedByDataSourceDuringCommit = repaintIsNotNeeded = false;
  454. }
  455. // Fires the value change
  456. fireValueChange(repaintIsNotNeeded);
  457. }
  458. }
  459. private static boolean equals(Object value1, Object value2) {
  460. if (value1 == null) {
  461. return value2 == null;
  462. }
  463. return value1.equals(value2);
  464. }
  465. /* External data source */
  466. /**
  467. * Gets the current data source of the field, if any.
  468. *
  469. * @return the current data source as a Property, or <code>null</code> if
  470. * none defined.
  471. */
  472. @Override
  473. public Property getPropertyDataSource() {
  474. return dataSource;
  475. }
  476. /**
  477. * <p>
  478. * Sets the specified Property as the data source for the field. All
  479. * uncommitted changes are replaced with a value from the new data source.
  480. * </p>
  481. *
  482. * <p>
  483. * If the datasource has any validators, the same validators are added to
  484. * the field. Because the default behavior of the field is to allow invalid
  485. * values, but not to allow committing them, this only adds visual error
  486. * messages to fields and do not allow committing them as long as the value
  487. * is invalid. After the value is valid, the error message is not shown and
  488. * the commit can be done normally.
  489. * </p>
  490. *
  491. * <p>
  492. * If the data source implements
  493. * {@link com.vaadin.data.Property.ValueChangeNotifier} and/or
  494. * {@link com.vaadin.data.Property.ReadOnlyStatusChangeNotifier}, the field
  495. * registers itself as a listener and updates itself according to the events
  496. * it receives. To avoid memory leaks caused by references to a field no
  497. * longer in use, the listener registrations are removed on
  498. * {@link AbstractField#detach() detach} and re-added on
  499. * {@link AbstractField#attach() attach}.
  500. * </p>
  501. *
  502. * <p>
  503. * Note: before 6.5 we actually called discard() method in the beginning of
  504. * the method. This was removed to simplify implementation, avoid excess
  505. * calls to backing property and to avoid odd value change events that were
  506. * previously fired (developer expects 0-1 value change events if this
  507. * method is called). Some complex field implementations might now need to
  508. * override this method to do housekeeping similar to discard().
  509. * </p>
  510. *
  511. * @param newDataSource
  512. * the new data source Property.
  513. */
  514. @Override
  515. public void setPropertyDataSource(Property newDataSource) {
  516. // Saves the old value
  517. final Object oldValue = getInternalValue();
  518. // Stop listening to the old data source
  519. removePropertyListeners();
  520. // Sets the new data source
  521. dataSource = newDataSource;
  522. getState().propertyReadOnly = dataSource == null ? false : dataSource
  523. .isReadOnly();
  524. // Check if the current converter is compatible.
  525. if (newDataSource != null
  526. && !ConverterUtil.canConverterHandle(getConverter(), getType(),
  527. newDataSource.getType())) {
  528. // Changing from e.g. Number -> Double should set a new converter,
  529. // changing from Double -> Number can keep the old one (Property
  530. // accepts Number)
  531. // Set a new converter if there is a new data source and
  532. // there is no old converter or the old is incompatible.
  533. setConverter(newDataSource.getType());
  534. }
  535. // Gets the value from source
  536. try {
  537. if (dataSource != null) {
  538. T fieldValue = convertFromDataSource(getDataSourceValue());
  539. setInternalValue(fieldValue);
  540. }
  541. setModified(false);
  542. if (getCurrentBufferedSourceException() != null) {
  543. setCurrentBufferedSourceException(null);
  544. }
  545. } catch (final Throwable e) {
  546. setCurrentBufferedSourceException(new Buffered.SourceException(
  547. this, e));
  548. setModified(true);
  549. }
  550. // Listen to new data source if possible
  551. addPropertyListeners();
  552. // Copy the validators from the data source
  553. if (dataSource instanceof Validatable) {
  554. final Collection<Validator> validators = ((Validatable) dataSource)
  555. .getValidators();
  556. if (validators != null) {
  557. for (final Iterator<Validator> i = validators.iterator(); i
  558. .hasNext();) {
  559. addValidator(i.next());
  560. }
  561. }
  562. }
  563. // Fires value change if the value has changed
  564. T value = getInternalValue();
  565. if ((value != oldValue)
  566. && ((value != null && !value.equals(oldValue)) || value == null)) {
  567. fireValueChange(false);
  568. }
  569. }
  570. /**
  571. * Retrieves a converter for the field from the converter factory defined
  572. * for the application. Clears the converter if no application reference is
  573. * available or if the factory returns null.
  574. *
  575. * @param datamodelType
  576. * The type of the data model that we want to be able to convert
  577. * from
  578. */
  579. public void setConverter(Class<?> datamodelType) {
  580. Converter<T, ?> c = (Converter<T, ?>) ConverterUtil.getConverter(
  581. getType(), datamodelType, getSession());
  582. setConverter(c);
  583. }
  584. /**
  585. * Convert the given value from the data source type to the UI type.
  586. *
  587. * @param newValue
  588. * The data source value to convert.
  589. * @return The converted value that is compatible with the UI type or the
  590. * original value if its type is compatible and no converter is set.
  591. * @throws Converter.ConversionException
  592. * if there is no converter and the type is not compatible with
  593. * the data source type.
  594. */
  595. private T convertFromDataSource(Object newValue) {
  596. return ConverterUtil.convertFromModel(newValue, getType(),
  597. getConverter(), getLocale());
  598. }
  599. /**
  600. * Convert the given value from the UI type to the data source type.
  601. *
  602. * @param fieldValue
  603. * The value to convert. Typically returned by
  604. * {@link #getFieldValue()}
  605. * @return The converted value that is compatible with the data source type.
  606. * @throws Converter.ConversionException
  607. * if there is no converter and the type is not compatible with
  608. * the data source type.
  609. */
  610. private Object convertToModel(T fieldValue)
  611. throws Converter.ConversionException {
  612. Class<?> modelType = null;
  613. Property pd = getPropertyDataSource();
  614. if (pd != null) {
  615. modelType = pd.getType();
  616. } else if (getConverter() != null) {
  617. modelType = getConverter().getModelType();
  618. }
  619. try {
  620. return ConverterUtil.convertToModel(fieldValue,
  621. (Class<Object>) modelType, getConverter(), getLocale());
  622. } catch (ConversionException e) {
  623. throw new ConversionException(getConversionError(modelType), e);
  624. }
  625. }
  626. /**
  627. * Returns the conversion error with {0} replaced by the data source type.
  628. *
  629. * @param dataSourceType
  630. * The type of the data source
  631. * @return The value conversion error string with parameters replaced.
  632. */
  633. protected String getConversionError(Class<?> dataSourceType) {
  634. if (dataSourceType == null) {
  635. return getConversionError();
  636. } else {
  637. return getConversionError().replace("{0}",
  638. dataSourceType.getSimpleName());
  639. }
  640. }
  641. /**
  642. * Returns the current value (as returned by {@link #getValue()}) converted
  643. * to the data source type.
  644. * <p>
  645. * This returns the same as {@link AbstractField#getValue()} if no converter
  646. * has been set. The value is not necessarily the same as the data source
  647. * value e.g. if the field is in buffered mode and has been modified.
  648. * </p>
  649. *
  650. * @return The converted value that is compatible with the data source type
  651. */
  652. public Object getConvertedValue() {
  653. return convertToModel(getFieldValue());
  654. }
  655. /**
  656. * Sets the value of the field using a value of the data source type. The
  657. * value given is converted to the field type and then assigned to the
  658. * field. This will update the property data source in the same way as when
  659. * {@link #setValue(Object)} is called.
  660. *
  661. * @param value
  662. * The value to set. Must be the same type as the data source.
  663. */
  664. public void setConvertedValue(Object value) {
  665. setValue(convertFromDataSource(value));
  666. }
  667. /* Validation */
  668. /**
  669. * Adds a new validator for the field's value. All validators added to a
  670. * field are checked each time the its value changes.
  671. *
  672. * @param validator
  673. * the new validator to be added.
  674. */
  675. @Override
  676. public void addValidator(Validator validator) {
  677. if (validators == null) {
  678. validators = new LinkedList<Validator>();
  679. }
  680. validators.add(validator);
  681. markAsDirty();
  682. }
  683. /**
  684. * Gets the validators of the field.
  685. *
  686. * @return An unmodifiable collection that holds all validators for the
  687. * field.
  688. */
  689. @Override
  690. public Collection<Validator> getValidators() {
  691. if (validators == null) {
  692. return Collections.emptyList();
  693. } else {
  694. return Collections.unmodifiableCollection(validators);
  695. }
  696. }
  697. /**
  698. * Removes the validator from the field.
  699. *
  700. * @param validator
  701. * the validator to remove.
  702. */
  703. @Override
  704. public void removeValidator(Validator validator) {
  705. if (validators != null) {
  706. validators.remove(validator);
  707. }
  708. markAsDirty();
  709. }
  710. /**
  711. * Removes all validators from the field.
  712. */
  713. @Override
  714. public void removeAllValidators() {
  715. if (validators != null) {
  716. validators.clear();
  717. }
  718. markAsDirty();
  719. }
  720. /**
  721. * Tests the current value against registered validators if the field is not
  722. * empty. If the field is empty it is considered valid if it is not required
  723. * and invalid otherwise. Validators are never checked for empty fields.
  724. *
  725. * In most cases, {@link #validate()} should be used instead of
  726. * {@link #isValid()} to also get the error message.
  727. *
  728. * @return <code>true</code> if all registered validators claim that the
  729. * current value is valid or if the field is empty and not required,
  730. * <code>false</code> otherwise.
  731. */
  732. @Override
  733. public boolean isValid() {
  734. try {
  735. validate();
  736. return true;
  737. } catch (InvalidValueException e) {
  738. return false;
  739. }
  740. }
  741. /**
  742. * Checks the validity of the Field.
  743. *
  744. * A field is invalid if it is set as required (using
  745. * {@link #setRequired(boolean)} and is empty, if one or several of the
  746. * validators added to the field indicate it is invalid or if the value
  747. * cannot be converted provided a converter has been set.
  748. *
  749. * The "required" validation is a built-in validation feature. If the field
  750. * is required and empty this method throws an EmptyValueException with the
  751. * error message set using {@link #setRequiredError(String)}.
  752. *
  753. * @see com.vaadin.data.Validatable#validate()
  754. */
  755. @Override
  756. public void validate() throws Validator.InvalidValueException {
  757. if (isRequired() && isEmpty()) {
  758. throw new Validator.EmptyValueException(requiredError);
  759. }
  760. validate(getFieldValue());
  761. }
  762. /**
  763. * Validates that the given value pass the validators for the field.
  764. * <p>
  765. * This method does not check the requiredness of the field.
  766. *
  767. * @param fieldValue
  768. * The value to check
  769. * @throws Validator.InvalidValueException
  770. * if one or several validators fail
  771. */
  772. protected void validate(T fieldValue)
  773. throws Validator.InvalidValueException {
  774. Object valueToValidate = fieldValue;
  775. // If there is a converter we start by converting the value as we want
  776. // to validate the converted value
  777. if (getConverter() != null) {
  778. try {
  779. valueToValidate = getConverter().convertToModel(fieldValue,
  780. getLocale());
  781. } catch (Exception e) {
  782. throw new InvalidValueException(
  783. getConversionError(getConverter().getModelType()));
  784. }
  785. }
  786. List<InvalidValueException> validationExceptions = new ArrayList<InvalidValueException>();
  787. if (validators != null) {
  788. // Gets all the validation errors
  789. for (Validator v : validators) {
  790. try {
  791. v.validate(valueToValidate);
  792. } catch (final Validator.InvalidValueException e) {
  793. validationExceptions.add(e);
  794. }
  795. }
  796. }
  797. // If there were no errors
  798. if (validationExceptions.isEmpty()) {
  799. return;
  800. }
  801. // If only one error occurred, throw it forwards
  802. if (validationExceptions.size() == 1) {
  803. throw validationExceptions.get(0);
  804. }
  805. InvalidValueException[] exceptionArray = validationExceptions
  806. .toArray(new InvalidValueException[validationExceptions.size()]);
  807. // Create a composite validator and include all exceptions
  808. throw new Validator.InvalidValueException(null, exceptionArray);
  809. }
  810. /**
  811. * Fields allow invalid values by default. In most cases this is wanted,
  812. * because the field otherwise visually forget the user input immediately.
  813. *
  814. * @return true iff the invalid values are allowed.
  815. * @see com.vaadin.data.Validatable#isInvalidAllowed()
  816. */
  817. @Override
  818. public boolean isInvalidAllowed() {
  819. return invalidAllowed;
  820. }
  821. /**
  822. * Fields allow invalid values by default. In most cases this is wanted,
  823. * because the field otherwise visually forget the user input immediately.
  824. * <p>
  825. * In common setting where the user wants to assure the correctness of the
  826. * datasource, but allow temporarily invalid contents in the field, the user
  827. * should add the validators to datasource, that should not allow invalid
  828. * values. The validators are automatically copied to the field when the
  829. * datasource is set.
  830. * </p>
  831. *
  832. * @see com.vaadin.data.Validatable#setInvalidAllowed(boolean)
  833. */
  834. @Override
  835. public void setInvalidAllowed(boolean invalidAllowed)
  836. throws UnsupportedOperationException {
  837. this.invalidAllowed = invalidAllowed;
  838. }
  839. /**
  840. * Error messages shown by the fields are composites of the error message
  841. * thrown by the superclasses (that is the component error message),
  842. * validation errors and buffered source errors.
  843. *
  844. * @see com.vaadin.ui.AbstractComponent#getErrorMessage()
  845. */
  846. @Override
  847. public ErrorMessage getErrorMessage() {
  848. /*
  849. * Check validation errors only if automatic validation is enabled.
  850. * Empty, required fields will generate a validation error containing
  851. * the requiredError string. For these fields the exclamation mark will
  852. * be hidden but the error must still be sent to the client.
  853. */
  854. Validator.InvalidValueException validationError = null;
  855. if (isValidationVisible()) {
  856. try {
  857. validate();
  858. } catch (Validator.InvalidValueException e) {
  859. if (!e.isInvisible()) {
  860. validationError = e;
  861. }
  862. }
  863. }
  864. // Check if there are any systems errors
  865. final ErrorMessage superError = super.getErrorMessage();
  866. // Return if there are no errors at all
  867. if (superError == null && validationError == null
  868. && getCurrentBufferedSourceException() == null) {
  869. return null;
  870. }
  871. // Throw combination of the error types
  872. return new CompositeErrorMessage(
  873. new ErrorMessage[] {
  874. superError,
  875. AbstractErrorMessage
  876. .getErrorMessageForException(validationError),
  877. AbstractErrorMessage
  878. .getErrorMessageForException(getCurrentBufferedSourceException()) });
  879. }
  880. /* Value change events */
  881. private static final Method VALUE_CHANGE_METHOD;
  882. static {
  883. try {
  884. VALUE_CHANGE_METHOD = Property.ValueChangeListener.class
  885. .getDeclaredMethod("valueChange",
  886. new Class[] { Property.ValueChangeEvent.class });
  887. } catch (final java.lang.NoSuchMethodException e) {
  888. // This should never happen
  889. throw new java.lang.RuntimeException(
  890. "Internal error finding methods in AbstractField");
  891. }
  892. }
  893. /*
  894. * Adds a value change listener for the field. Don't add a JavaDoc comment
  895. * here, we use the default documentation from the implemented interface.
  896. */
  897. @Override
  898. public void addValueChangeListener(Property.ValueChangeListener listener) {
  899. addListener(AbstractField.ValueChangeEvent.class, listener,
  900. VALUE_CHANGE_METHOD);
  901. }
  902. /**
  903. * @deprecated As of 7.0, replaced by
  904. * {@link #addValueChangeListener(com.vaadin.data.Property.ValueChangeListener)}
  905. **/
  906. @Override
  907. @Deprecated
  908. public void addListener(Property.ValueChangeListener listener) {
  909. addValueChangeListener(listener);
  910. }
  911. /*
  912. * Removes a value change listener from the field. Don't add a JavaDoc
  913. * comment here, we use the default documentation from the implemented
  914. * interface.
  915. */
  916. @Override
  917. public void removeValueChangeListener(Property.ValueChangeListener listener) {
  918. removeListener(AbstractField.ValueChangeEvent.class, listener,
  919. VALUE_CHANGE_METHOD);
  920. }
  921. /**
  922. * @deprecated As of 7.0, replaced by
  923. * {@link #removeValueChangeListener(com.vaadin.data.Property.ValueChangeListener)}
  924. **/
  925. @Override
  926. @Deprecated
  927. public void removeListener(Property.ValueChangeListener listener) {
  928. removeValueChangeListener(listener);
  929. }
  930. /**
  931. * Emits the value change event. The value contained in the field is
  932. * validated before the event is created.
  933. */
  934. protected void fireValueChange(boolean repaintIsNotNeeded) {
  935. fireEvent(new AbstractField.ValueChangeEvent(this));
  936. if (!repaintIsNotNeeded) {
  937. markAsDirty();
  938. }
  939. }
  940. /* Read-only status change events */
  941. private static final Method READ_ONLY_STATUS_CHANGE_METHOD;
  942. static {
  943. try {
  944. READ_ONLY_STATUS_CHANGE_METHOD = Property.ReadOnlyStatusChangeListener.class
  945. .getDeclaredMethod(
  946. "readOnlyStatusChange",
  947. new Class[] { Property.ReadOnlyStatusChangeEvent.class });
  948. } catch (final java.lang.NoSuchMethodException e) {
  949. // This should never happen
  950. throw new java.lang.RuntimeException(
  951. "Internal error finding methods in AbstractField");
  952. }
  953. }
  954. /**
  955. * React to read only status changes of the property by requesting a
  956. * repaint.
  957. *
  958. * @see Property.ReadOnlyStatusChangeListener
  959. */
  960. @Override
  961. public void readOnlyStatusChange(Property.ReadOnlyStatusChangeEvent event) {
  962. getState().propertyReadOnly = event.getProperty().isReadOnly();
  963. }
  964. /**
  965. * An <code>Event</code> object specifying the Property whose read-only
  966. * status has changed.
  967. *
  968. * @author Vaadin Ltd.
  969. * @since 3.0
  970. */
  971. public static class ReadOnlyStatusChangeEvent extends Component.Event
  972. implements Property.ReadOnlyStatusChangeEvent, Serializable {
  973. /**
  974. * New instance of text change event.
  975. *
  976. * @param source
  977. * the Source of the event.
  978. */
  979. public ReadOnlyStatusChangeEvent(AbstractField source) {
  980. super(source);
  981. }
  982. /**
  983. * Property where the event occurred.
  984. *
  985. * @return the Source of the event.
  986. */
  987. @Override
  988. public Property getProperty() {
  989. return (Property) getSource();
  990. }
  991. }
  992. /*
  993. * Adds a read-only status change listener for the field. Don't add a
  994. * JavaDoc comment here, we use the default documentation from the
  995. * implemented interface.
  996. */
  997. @Override
  998. public void addReadOnlyStatusChangeListener(
  999. Property.ReadOnlyStatusChangeListener listener) {
  1000. addListener(Property.ReadOnlyStatusChangeEvent.class, listener,
  1001. READ_ONLY_STATUS_CHANGE_METHOD);
  1002. }
  1003. /**
  1004. * @deprecated As of 7.0, replaced by
  1005. * {@link #addReadOnlyStatusChangeListener(com.vaadin.data.Property.ReadOnlyStatusChangeListener)}
  1006. **/
  1007. @Override
  1008. @Deprecated
  1009. public void addListener(Property.ReadOnlyStatusChangeListener listener) {
  1010. addReadOnlyStatusChangeListener(listener);
  1011. }
  1012. /*
  1013. * Removes a read-only status change listener from the field. Don't add a
  1014. * JavaDoc comment here, we use the default documentation from the
  1015. * implemented interface.
  1016. */
  1017. @Override
  1018. public void removeReadOnlyStatusChangeListener(
  1019. Property.ReadOnlyStatusChangeListener listener) {
  1020. removeListener(Property.ReadOnlyStatusChangeEvent.class, listener,
  1021. READ_ONLY_STATUS_CHANGE_METHOD);
  1022. }
  1023. /**
  1024. * @deprecated As of 7.0, replaced by
  1025. * {@link #removeReadOnlyStatusChangeListener(com.vaadin.data.Property.ReadOnlyStatusChangeListener)}
  1026. **/
  1027. @Override
  1028. @Deprecated
  1029. public void removeListener(Property.ReadOnlyStatusChangeListener listener) {
  1030. removeReadOnlyStatusChangeListener(listener);
  1031. }
  1032. /**
  1033. * Emits the read-only status change event. The value contained in the field
  1034. * is validated before the event is created.
  1035. */
  1036. protected void fireReadOnlyStatusChange() {
  1037. fireEvent(new AbstractField.ReadOnlyStatusChangeEvent(this));
  1038. }
  1039. /**
  1040. * This method listens to data source value changes and passes the changes
  1041. * forwards.
  1042. *
  1043. * Changes are not forwarded to the listeners of the field during internal
  1044. * operations of the field to avoid duplicate notifications.
  1045. *
  1046. * @param event
  1047. * the value change event telling the data source contents have
  1048. * changed.
  1049. */
  1050. @Override
  1051. public void valueChange(Property.ValueChangeEvent event) {
  1052. if (!isBuffered()) {
  1053. if (committingValueToDataSource) {
  1054. boolean propertyNotifiesOfTheBufferedValue = equals(event
  1055. .getProperty().getValue(), getInternalValue());
  1056. if (!propertyNotifiesOfTheBufferedValue) {
  1057. /*
  1058. * Property (or chained property like PropertyFormatter) now
  1059. * reports different value than the one the field has just
  1060. * committed to it. In this case we respect the property
  1061. * value.
  1062. *
  1063. * Still, we don't fire value change yet, but instead
  1064. * postpone it until "commit" is done. See setValue(Object,
  1065. * boolean) and commit().
  1066. */
  1067. readValueFromProperty(event);
  1068. valueWasModifiedByDataSourceDuringCommit = true;
  1069. }
  1070. } else if (!isModified()) {
  1071. readValueFromProperty(event);
  1072. fireValueChange(false);
  1073. }
  1074. }
  1075. }
  1076. private void readValueFromProperty(Property.ValueChangeEvent event) {
  1077. setInternalValue(convertFromDataSource(event.getProperty().getValue()));
  1078. }
  1079. /**
  1080. * {@inheritDoc}
  1081. */
  1082. @Override
  1083. public void focus() {
  1084. super.focus();
  1085. }
  1086. /*
  1087. * (non-Javadoc)
  1088. *
  1089. * @see com.vaadin.ui.Component.Focusable#getTabIndex()
  1090. */
  1091. @Override
  1092. public int getTabIndex() {
  1093. return getState().tabIndex;
  1094. }
  1095. /*
  1096. * (non-Javadoc)
  1097. *
  1098. * @see com.vaadin.ui.Component.Focusable#setTabIndex(int)
  1099. */
  1100. @Override
  1101. public void setTabIndex(int tabIndex) {
  1102. getState().tabIndex = tabIndex;
  1103. }
  1104. /**
  1105. * Returns the internal field value, which might not match the data source
  1106. * value e.g. if the field has been modified and is not in write-through
  1107. * mode.
  1108. *
  1109. * This method can be overridden by subclasses together with
  1110. * {@link #setInternalValue(Object)} to compute internal field value at
  1111. * runtime. When doing so, typically also {@link #isModified()} needs to be
  1112. * overridden and care should be taken in the management of the empty state
  1113. * and buffering support.
  1114. *
  1115. * @return internal field value
  1116. */
  1117. protected T getInternalValue() {
  1118. return value;
  1119. }
  1120. /**
  1121. * Sets the internal field value. This is purely used by AbstractField to
  1122. * change the internal Field value. It does not trigger valuechange events.
  1123. * It can be overridden by the inheriting classes to update all dependent
  1124. * variables.
  1125. *
  1126. * Subclasses can also override {@link #getInternalValue()} if necessary.
  1127. *
  1128. * @param newValue
  1129. * the new value to be set.
  1130. */
  1131. protected void setInternalValue(T newValue) {
  1132. value = newValue;
  1133. if (validators != null && !validators.isEmpty()) {
  1134. markAsDirty();
  1135. }
  1136. }
  1137. /**
  1138. * Notifies the component that it is connected to an application.
  1139. *
  1140. * @see com.vaadin.ui.Component#attach()
  1141. */
  1142. @Override
  1143. public void attach() {
  1144. super.attach();
  1145. if (!isListeningToPropertyEvents) {
  1146. addPropertyListeners();
  1147. if (!isModified() && !isBuffered()) {
  1148. // Update value from data source
  1149. updateValueFromDataSource();
  1150. }
  1151. }
  1152. }
  1153. @Override
  1154. public void detach() {
  1155. super.detach();
  1156. // Stop listening to data source events on detach to avoid a potential
  1157. // memory leak. See #6155.
  1158. removePropertyListeners();
  1159. }
  1160. /**
  1161. * Is this field required. Required fields must filled by the user.
  1162. *
  1163. * If the field is required, it is visually indicated in the user interface.
  1164. * Furthermore, setting field to be required implicitly adds "non-empty"
  1165. * validator and thus isValid() == false or any isEmpty() fields. In those
  1166. * cases validation errors are not painted as it is obvious that the user
  1167. * must fill in the required fields.
  1168. *
  1169. * On the other hand, for the non-required fields isValid() == true if the
  1170. * field isEmpty() regardless of any attached validators.
  1171. *
  1172. *
  1173. * @return <code>true</code> if the field is required, otherwise
  1174. * <code>false</code>.
  1175. */
  1176. @Override
  1177. public boolean isRequired() {
  1178. return getState().required;
  1179. }
  1180. /**
  1181. * Sets the field required. Required fields must filled by the user.
  1182. *
  1183. * If the field is required, it is visually indicated in the user interface.
  1184. * Furthermore, setting field to be required implicitly adds "non-empty"
  1185. * validator and thus isValid() == false or any isEmpty() fields. In those
  1186. * cases validation errors are not painted as it is obvious that the user
  1187. * must fill in the required fields.
  1188. *
  1189. * On the other hand, for the non-required fields isValid() == true if the
  1190. * field isEmpty() regardless of any attached validators.
  1191. *
  1192. * @param required
  1193. * Is the field required.
  1194. */
  1195. @Override
  1196. public void setRequired(boolean required) {
  1197. getState().required = required;
  1198. }
  1199. /**
  1200. * Set the error that is show if this field is required, but empty. When
  1201. * setting requiredMessage to be "" or null, no error pop-up or exclamation
  1202. * mark is shown for a empty required field. This faults to "". Even in
  1203. * those cases isValid() returns false for empty required fields.
  1204. *
  1205. * @param requiredMessage
  1206. * Message to be shown when this field is required, but empty.
  1207. */
  1208. @Override
  1209. public void setRequiredError(String requiredMessage) {
  1210. requiredError = requiredMessage;
  1211. markAsDirty();
  1212. }
  1213. @Override
  1214. public String getRequiredError() {
  1215. return requiredError;
  1216. }
  1217. /**
  1218. * Gets the error that is shown if the field value cannot be converted to
  1219. * the data source type.
  1220. *
  1221. * @return The error that is shown if conversion of the field value fails
  1222. */
  1223. public String getConversionError() {
  1224. return conversionError;
  1225. }
  1226. /**
  1227. * Sets the error that is shown if the field value cannot be converted to
  1228. * the data source type. If {0} is present in the message, it will be
  1229. * replaced by the simple name of the data source type.
  1230. *
  1231. * @param valueConversionError
  1232. * Message to be shown when conversion of the value fails
  1233. */
  1234. public void setConversionError(String valueConversionError) {
  1235. this.conversionError = valueConversionError;
  1236. markAsDirty();
  1237. }
  1238. /**
  1239. * Is the field empty?
  1240. *
  1241. * In general, "empty" state is same as null. As an exception, TextField
  1242. * also treats empty string as "empty".
  1243. */
  1244. protected boolean isEmpty() {
  1245. return (getFieldValue() == null);
  1246. }
  1247. /**
  1248. * Is automatic, visible validation enabled?
  1249. *
  1250. * If automatic validation is enabled, any validators connected to this
  1251. * component are evaluated while painting the component and potential error
  1252. * messages are sent to client. If the automatic validation is turned off,
  1253. * isValid() and validate() methods still work, but one must show the
  1254. * validation in their own code.
  1255. *
  1256. * @return True, if automatic validation is enabled.
  1257. */
  1258. public boolean isValidationVisible() {
  1259. return validationVisible;
  1260. }
  1261. /**
  1262. * Enable or disable automatic, visible validation.
  1263. *
  1264. * If automatic validation is enabled, any validators connected to this
  1265. * component are evaluated while painting the component and potential error
  1266. * messages are sent to client. If the automatic validation is turned off,
  1267. * isValid() and validate() methods still work, but one must show the
  1268. * validation in their own code.
  1269. *
  1270. * @param validateAutomatically
  1271. * True, if automatic validation is enabled.
  1272. */
  1273. public void setValidationVisible(boolean validateAutomatically) {
  1274. if (validationVisible != validateAutomatically) {
  1275. markAsDirty();
  1276. validationVisible = validateAutomatically;
  1277. }
  1278. }
  1279. /**
  1280. * Sets the current buffered source exception.
  1281. *
  1282. * @param currentBufferedSourceException
  1283. */
  1284. public void setCurrentBufferedSourceException(
  1285. Buffered.SourceException currentBufferedSourceException) {
  1286. this.currentBufferedSourceException = currentBufferedSourceException;
  1287. markAsDirty();
  1288. }
  1289. /**
  1290. * Gets the current buffered source exception.
  1291. *
  1292. * @return The current source exception
  1293. */
  1294. protected Buffered.SourceException getCurrentBufferedSourceException() {
  1295. return currentBufferedSourceException;
  1296. }
  1297. /**
  1298. * A ready-made {@link ShortcutListener} that focuses the given
  1299. * {@link Focusable} (usually a {@link Field}) when the keyboard shortcut is
  1300. * invoked.
  1301. *
  1302. */
  1303. public static class FocusShortcut extends ShortcutListener {
  1304. protected Focusable focusable;
  1305. /**
  1306. * Creates a keyboard shortcut for focusing the given {@link Focusable}
  1307. * using the shorthand notation defined in {@link ShortcutAction}.
  1308. *
  1309. * @param focusable
  1310. * to focused when the shortcut is invoked
  1311. * @param shorthandCaption
  1312. * caption with keycode and modifiers indicated
  1313. */
  1314. public FocusShortcut(Focusable focusable, String shorthandCaption) {
  1315. super(shorthandCaption);
  1316. this.focusable = focusable;
  1317. }
  1318. /**
  1319. * Creates a keyboard shortcut for focusing the given {@link Focusable}.
  1320. *
  1321. * @param focusable
  1322. * to focused when the shortcut is invoked
  1323. * @param keyCode
  1324. * keycode that invokes the shortcut
  1325. * @param modifiers
  1326. * modifiers required to invoke the shortcut
  1327. */
  1328. public FocusShortcut(Focusable focusable, int keyCode, int... modifiers) {
  1329. super(null, keyCode, modifiers);
  1330. this.focusable = focusable;
  1331. }
  1332. /**
  1333. * Creates a keyboard shortcut for focusing the given {@link Focusable}.
  1334. *
  1335. * @param focusable
  1336. * to focused when the shortcut is invoked
  1337. * @param keyCode
  1338. * keycode that invokes the shortcut
  1339. */
  1340. public FocusShortcut(Focusable focusable, int keyCode) {
  1341. this(focusable, keyCode, null);
  1342. }
  1343. @Override
  1344. public void handleAction(Object sender, Object target) {
  1345. focusable.focus();
  1346. }
  1347. }
  1348. private void updateValueFromDataSource() {
  1349. if (dataSource != null) {
  1350. // Gets the correct value from datasource
  1351. T newFieldValue;
  1352. try {
  1353. // Discards buffer by overwriting from datasource
  1354. newFieldValue = convertFromDataSource(getDataSourceValue());
  1355. // If successful, remove set the buffering state to be ok
  1356. if (getCurrentBufferedSourceException() != null) {
  1357. setCurrentBufferedSourceException(null);
  1358. }
  1359. } catch (final Throwable e) {
  1360. // FIXME: What should really be done here if conversion fails?
  1361. // Sets the buffering state
  1362. currentBufferedSourceException = new Buffered.SourceException(
  1363. this, e);
  1364. markAsDirty();
  1365. // Throws the source exception
  1366. throw currentBufferedSourceException;
  1367. }
  1368. final boolean wasModified = isModified();
  1369. setModified(false);
  1370. // If the new value differs from the previous one
  1371. if (!equals(newFieldValue, getInternalValue())) {
  1372. setInternalValue(newFieldValue);
  1373. fireValueChange(false);
  1374. } else if (wasModified) {
  1375. // If the value did not change, but the modification status did
  1376. markAsDirty();
  1377. }
  1378. }
  1379. }
  1380. /**
  1381. * Gets the converter used to convert the property data source value to the
  1382. * field value.
  1383. *
  1384. * @return The converter or null if none is set.
  1385. */
  1386. public Converter<T, Object> getConverter() {
  1387. return converter;
  1388. }
  1389. /**
  1390. * Sets the converter used to convert the field value to property data
  1391. * source type. The converter must have a presentation type that matches the
  1392. * field type.
  1393. *
  1394. * @param converter
  1395. * The new converter to use.
  1396. */
  1397. public void setConverter(Converter<T, ?> converter) {
  1398. this.converter = (Converter<T, Object>) converter;
  1399. markAsDirty();
  1400. }
  1401. @Override
  1402. protected AbstractFieldState getState() {
  1403. return (AbstractFieldState) super.getState();
  1404. }
  1405. @Override
  1406. public void beforeClientResponse(boolean initial) {
  1407. super.beforeClientResponse(initial);
  1408. // Hide the error indicator if needed
  1409. getState().hideErrors = shouldHideErrors();
  1410. }
  1411. /**
  1412. * Registers this as an event listener for events sent by the data source
  1413. * (if any). Does nothing if
  1414. * <code>isListeningToPropertyEvents == true</code>.
  1415. */
  1416. private void addPropertyListeners() {
  1417. if (!isListeningToPropertyEvents) {
  1418. if (dataSource instanceof Property.ValueChangeNotifier) {
  1419. ((Property.ValueChangeNotifier) dataSource).addListener(this);
  1420. }
  1421. if (dataSource instanceof Property.ReadOnlyStatusChangeNotifier) {
  1422. ((Property.ReadOnlyStatusChangeNotifier) dataSource)
  1423. .addListener(this);
  1424. }
  1425. isListeningToPropertyEvents = true;
  1426. }
  1427. }
  1428. /**
  1429. * Stops listening to events sent by the data source (if any). Does nothing
  1430. * if <code>isListeningToPropertyEvents == false</code>.
  1431. */
  1432. private void removePropertyListeners() {
  1433. if (isListeningToPropertyEvents) {
  1434. if (dataSource instanceof Property.ValueChangeNotifier) {
  1435. ((Property.ValueChangeNotifier) dataSource)
  1436. .removeListener(this);
  1437. }
  1438. if (dataSource instanceof Property.ReadOnlyStatusChangeNotifier) {
  1439. ((Property.ReadOnlyStatusChangeNotifier) dataSource)
  1440. .removeListener(this);
  1441. }
  1442. isListeningToPropertyEvents = false;
  1443. }
  1444. }
  1445. }