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.

Button.java 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. @ITMillApache2LicenseForJavaFiles@
  3. */
  4. package com.itmill.toolkit.ui;
  5. import java.io.IOException;
  6. import java.lang.reflect.Method;
  7. import java.util.Map;
  8. import com.itmill.toolkit.data.Property;
  9. import com.itmill.toolkit.terminal.PaintException;
  10. import com.itmill.toolkit.terminal.PaintTarget;
  11. /**
  12. * A generic button component.
  13. *
  14. * @author IT Mill Ltd.
  15. * @version
  16. * @VERSION@
  17. * @since 3.0
  18. */
  19. public class Button extends AbstractField {
  20. /* Private members */
  21. boolean switchMode = false;
  22. /**
  23. * Creates a new push button. The value of the push button is allways false
  24. * and they are immediate by default.
  25. *
  26. */
  27. public Button() {
  28. setSwitchMode(false);
  29. }
  30. /**
  31. * Creates a new push button.
  32. *
  33. * The value of the push button is allways false and they are immediate by
  34. * default.
  35. *
  36. * @param caption
  37. * the Button caption.
  38. */
  39. public Button(String caption) {
  40. setCaption(caption);
  41. setSwitchMode(false);
  42. }
  43. /**
  44. * Creates a new push button with click listener.
  45. *
  46. * @param caption
  47. * the Button caption.
  48. * @param listener
  49. * the Button click listener.
  50. */
  51. public Button(String caption, ClickListener listener) {
  52. this(caption);
  53. addListener(listener);
  54. }
  55. /**
  56. * Creates a new push button with a method listening button clicks. Using
  57. * this method is discouraged because it cannot be checked during
  58. * compilation. Use
  59. * {@link #Button(String, com.itmill.toolkit.ui.Button.ClickListener)}
  60. * instead. The method must have either no parameters, or only one parameter
  61. * of Button.ClickEvent type.
  62. *
  63. * @param caption
  64. * the Button caption.
  65. * @param target
  66. * the Object having the method for listening button clicks.
  67. * @param methodName
  68. * the name of the method in target object, that receives button
  69. * click events.
  70. */
  71. public Button(String caption, Object target, String methodName) {
  72. this(caption);
  73. addListener(ClickEvent.class, target, methodName);
  74. }
  75. /**
  76. * Creates a new switch button with initial value.
  77. *
  78. * @param state
  79. * the Initial state of the switch-button.
  80. * @param initialState
  81. */
  82. public Button(String caption, boolean initialState) {
  83. setCaption(caption);
  84. setValue(new Boolean(initialState));
  85. setSwitchMode(true);
  86. }
  87. /**
  88. * Creates a new switch button that is connected to a boolean property.
  89. *
  90. * @param state
  91. * the Initial state of the switch-button.
  92. * @param dataSource
  93. */
  94. public Button(String caption, Property dataSource) {
  95. setCaption(caption);
  96. setSwitchMode(true);
  97. setPropertyDataSource(dataSource);
  98. }
  99. /**
  100. * Gets component UIDL tag.
  101. *
  102. * @return the Component UIDL tag as string.
  103. */
  104. public String getTag() {
  105. return "button";
  106. }
  107. /**
  108. * Paints the content of this component.
  109. *
  110. * @param event
  111. * the PaintEvent.
  112. * @throws IOException
  113. * if the writing failed due to input/output error.
  114. * @throws PaintException
  115. * if the paint operation failed.
  116. */
  117. public void paintContent(PaintTarget target) throws PaintException {
  118. super.paintContent(target);
  119. if (isSwitchMode()) {
  120. target.addAttribute("type", "switch");
  121. }
  122. boolean state;
  123. try {
  124. state = ((Boolean) getValue()).booleanValue();
  125. } catch (final NullPointerException e) {
  126. state = false;
  127. }
  128. target.addVariable(this, "state", state);
  129. }
  130. /**
  131. * Invoked when the value of a variable has changed. Button listeners are
  132. * notified if the button is clicked.
  133. *
  134. * @param source
  135. * @param variables
  136. */
  137. public void changeVariables(Object source, Map variables) {
  138. super.changeVariables(source, variables);
  139. if (!isReadOnly() && variables.containsKey("state")) {
  140. // Gets the new and old button states
  141. final Boolean newValue = (Boolean) variables.get("state");
  142. final Boolean oldValue = (Boolean) getValue();
  143. if (isSwitchMode()) {
  144. // For switch button, the event is only sent if the
  145. // switch state is changed
  146. if (newValue != null && !newValue.equals(oldValue)
  147. && !isReadOnly()) {
  148. setValue(newValue);
  149. fireClick();
  150. }
  151. } else {
  152. // Only send click event if the button is pushed
  153. if (newValue.booleanValue()) {
  154. fireClick();
  155. }
  156. // If the button is true for some reason, release it
  157. if (oldValue.booleanValue()) {
  158. setValue(new Boolean(false));
  159. }
  160. }
  161. }
  162. }
  163. /**
  164. * Checks if it is switchMode.
  165. *
  166. * @return <code>true</code> if it is in Switch Mode, otherwise
  167. * <code>false</code>.
  168. */
  169. public boolean isSwitchMode() {
  170. return switchMode;
  171. }
  172. /**
  173. * Sets the switchMode.
  174. *
  175. * @param switchMode
  176. * The switchMode to set.
  177. */
  178. public void setSwitchMode(boolean switchMode) {
  179. this.switchMode = switchMode;
  180. if (!switchMode) {
  181. setImmediate(true);
  182. setValue(new Boolean(false));
  183. }
  184. }
  185. /**
  186. * Get the boolean value of the button state.
  187. *
  188. * @return True iff the button is pressed down or checked.
  189. */
  190. public boolean booleanValue() {
  191. return ((Boolean) getValue()).booleanValue();
  192. }
  193. /**
  194. * Sets immediate mode. Push buttons can not be set in non-immediate mode.
  195. *
  196. * @see com.itmill.toolkit.ui.AbstractComponent#setImmediate(boolean)
  197. */
  198. public void setImmediate(boolean immediate) {
  199. // Push buttons are always immediate
  200. super.setImmediate(!isSwitchMode() || immediate);
  201. }
  202. /**
  203. * The type of the button as a property.
  204. *
  205. * @see com.itmill.toolkit.data.Property#getType()
  206. */
  207. public Class getType() {
  208. return Boolean.class;
  209. }
  210. /* Click event */
  211. private static final Method BUTTON_CLICK_METHOD;
  212. /* Button style with no decorations. Looks like a link, acts like a button */
  213. public static final String STYLE_LINK = "link";
  214. static {
  215. try {
  216. BUTTON_CLICK_METHOD = ClickListener.class.getDeclaredMethod(
  217. "buttonClick", new Class[] { ClickEvent.class });
  218. } catch (final java.lang.NoSuchMethodException e) {
  219. // This should never happen
  220. throw new java.lang.RuntimeException(
  221. "Internal error finding methods in Button");
  222. }
  223. }
  224. /**
  225. * Click event. This event is thrown, when the button is clicked.
  226. *
  227. * @author IT Mill Ltd.
  228. * @version
  229. * @VERSION@
  230. * @since 3.0
  231. */
  232. public class ClickEvent extends Component.Event {
  233. /**
  234. * Serial generated by eclipse.
  235. */
  236. private static final long serialVersionUID = 3546647602931118393L;
  237. /**
  238. * New instance of text change event.
  239. *
  240. * @param source
  241. * the Source of the event.
  242. */
  243. public ClickEvent(Component source) {
  244. super(source);
  245. }
  246. /**
  247. * Gets the Button where the event occurred.
  248. *
  249. * @return the Source of the event.
  250. */
  251. public Button getButton() {
  252. return (Button) getSource();
  253. }
  254. }
  255. /**
  256. * Button click listener
  257. *
  258. * @author IT Mill Ltd.
  259. * @version
  260. * @VERSION@
  261. * @since 3.0
  262. */
  263. public interface ClickListener {
  264. /**
  265. * Button has been pressed.
  266. *
  267. * @param event
  268. * Button click event.
  269. */
  270. public void buttonClick(ClickEvent event);
  271. }
  272. /**
  273. * Adds the button click listener.
  274. *
  275. * @param listener
  276. * the Listener to be added.
  277. */
  278. public void addListener(ClickListener listener) {
  279. addListener(ClickEvent.class, listener, BUTTON_CLICK_METHOD);
  280. }
  281. /**
  282. * Removes the button click listener.
  283. *
  284. * @param listener
  285. * the Listener to be removed.
  286. */
  287. public void removeListener(ClickListener listener) {
  288. removeListener(ClickEvent.class, listener, BUTTON_CLICK_METHOD);
  289. }
  290. /**
  291. * Emits the options change event.
  292. */
  293. protected void fireClick() {
  294. fireEvent(new Button.ClickEvent(this));
  295. }
  296. }