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.

CustomField.java 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. * Copyright 2000-2018 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.util.Collections;
  18. import java.util.Iterator;
  19. import com.vaadin.data.HasValue;
  20. import com.vaadin.shared.ui.customfield.CustomFieldState;
  21. /**
  22. * A {@link HasValue} whose UI content can be constructed by the user, enabling
  23. * the creation of e.g. form fields by composing Vaadin components.
  24. * Customization of both the visual presentation and the logic of the field is
  25. * possible.
  26. * <p>
  27. * Subclasses must implement {@link #initContent()}.
  28. * <p>
  29. * Most custom fields can simply compose a user interface that calls the methods
  30. * {@link #doSetValue(Object)} and {@link #getValue()} when necessary.
  31. *
  32. * @param <T>
  33. * field value type
  34. *
  35. * @since 8.0
  36. */
  37. public abstract class CustomField<T> extends AbstractField<T>
  38. implements HasComponents {
  39. /**
  40. * The root component implementing the custom component.
  41. */
  42. private Component root = null;
  43. /**
  44. * Constructs a new custom field.
  45. *
  46. * <p>
  47. * The component is implemented by wrapping the methods of the composition
  48. * root component given as parameter. The composition root must be set
  49. * before the component can be used.
  50. * </p>
  51. */
  52. public CustomField() {
  53. // expand horizontally by default
  54. setWidth(100, Unit.PERCENTAGE);
  55. }
  56. /**
  57. * Constructs the content and notifies it that the {@link CustomField} is
  58. * attached to a window.
  59. *
  60. * @see com.vaadin.ui.Component#attach()
  61. */
  62. @Override
  63. public void attach() {
  64. // First call super attach to notify all children (none if content has
  65. // not yet been created)
  66. super.attach();
  67. // If the content has not yet been created, create and attach it at
  68. // this point by calling getContent()
  69. getContent();
  70. }
  71. /**
  72. * Returns the content (UI) of the custom component.
  73. *
  74. * @return Component
  75. */
  76. protected Component getContent() {
  77. if (null == root) {
  78. root = initContent();
  79. root.setParent(this);
  80. }
  81. return root;
  82. }
  83. /**
  84. * Create the content component or layout for the field. Subclasses of
  85. * {@link CustomField} should implement this method.
  86. *
  87. * Note that this method is called when the CustomField is attached to a
  88. * layout or when {@link #getContent()} is called explicitly for the first
  89. * time. It is only called once for a {@link CustomField}.
  90. *
  91. * @return {@link Component} representing the UI of the CustomField
  92. */
  93. protected abstract Component initContent();
  94. // Size related methods
  95. // TODO might not be necessary to override but following the pattern from
  96. // AbstractComponentContainer
  97. @Override
  98. public void setHeight(float height, Unit unit) {
  99. super.setHeight(height, unit);
  100. markAsDirtyRecursive();
  101. }
  102. @Override
  103. public void setWidth(float width, Unit unit) {
  104. super.setWidth(width, unit);
  105. markAsDirtyRecursive();
  106. }
  107. @Override
  108. protected CustomFieldState getState() {
  109. return (CustomFieldState) super.getState();
  110. }
  111. @Override
  112. protected CustomFieldState getState(boolean markAsDirty) {
  113. return (CustomFieldState) super.getState(markAsDirty);
  114. }
  115. // ComponentContainer methods
  116. @Override
  117. public Iterator<Component> iterator() {
  118. // Can't use getContent() here as this will cause an infinite loop if
  119. // initContent happens to all iterator(). This happens if you do
  120. // setWidth...
  121. if (root != null) {
  122. return Collections.singletonList(root).iterator();
  123. } else {
  124. return Collections.<Component> emptyList().iterator();
  125. }
  126. }
  127. /**
  128. * Sets the component to which all methods from the {@link Focusable}
  129. * interface should be delegated.
  130. * <p>
  131. * Set this to a wrapped field to include that field in the tabbing order,
  132. * to make it receive focus when {@link #focus()} is called and to make it
  133. * be correctly focused when used as a Grid editor component.
  134. * <p>
  135. * By default, {@link Focusable} events are handled by the super class and
  136. * ultimately ignored.
  137. *
  138. * @param focusDelegate
  139. * the focusable component to which focus events are redirected
  140. */
  141. public void setFocusDelegate(Focusable focusDelegate) {
  142. getState().focusDelegate = focusDelegate;
  143. }
  144. private Focusable getFocusable() {
  145. return (Focusable) getState(false).focusDelegate;
  146. }
  147. @Override
  148. public void focus() {
  149. if (getFocusable() != null) {
  150. getFocusable().focus();
  151. } else {
  152. super.focus();
  153. }
  154. }
  155. @Override
  156. public int getTabIndex() {
  157. if (getFocusable() != null) {
  158. return getFocusable().getTabIndex();
  159. } else {
  160. return super.getTabIndex();
  161. }
  162. }
  163. @Override
  164. public void setTabIndex(int tabIndex) {
  165. if (getFocusable() != null) {
  166. getFocusable().setTabIndex(tabIndex);
  167. } else {
  168. super.setTabIndex(tabIndex);
  169. }
  170. }
  171. }