You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AbstractField.java 55KB

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