Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

VLoadingIndicator.java 9.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*
  2. * Copyright 2000-2013 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.client;
  17. import com.google.gwt.dom.client.Style.Display;
  18. import com.google.gwt.dom.client.Style.Position;
  19. import com.google.gwt.user.client.DOM;
  20. import com.google.gwt.user.client.Element;
  21. import com.google.gwt.user.client.Timer;
  22. /**
  23. * Class representing the loading indicator for Vaadin applications. The loading
  24. * indicator has four states: "triggered", "first", "second" and "third". When
  25. * {@link #trigger()} is called the indicator moves to its "triggered" state and
  26. * then transitions from one state to the next when the timeouts specified using
  27. * the set*StateDelay methods occur.
  28. *
  29. * @author Vaadin Ltd
  30. * @since 7.1
  31. */
  32. public class VLoadingIndicator {
  33. private static final String PRIMARY_STYLE_NAME = "v-loading-indicator";
  34. private ApplicationConnection connection;
  35. private int firstDelay = 300;
  36. private int secondDelay = 1500;
  37. private int thirdDelay = 5000;
  38. /**
  39. * Timer with method for checking if it has been cancelled. This class is a
  40. * workaround for a IE8 problem which causes a timer to be fired even if it
  41. * has been cancelled.
  42. *
  43. * @author Vaadin Ltd
  44. * @since 7.1
  45. */
  46. private abstract static class LoadingIndicatorTimer extends Timer {
  47. private boolean cancelled = false;
  48. @Override
  49. public void cancel() {
  50. super.cancel();
  51. cancelled = true;
  52. }
  53. @Override
  54. public void schedule(int delayMillis) {
  55. super.schedule(delayMillis);
  56. cancelled = false;
  57. }
  58. @Override
  59. public void scheduleRepeating(int periodMillis) {
  60. super.scheduleRepeating(periodMillis);
  61. cancelled = false;
  62. }
  63. /**
  64. * Checks if this timer has been cancelled.
  65. *
  66. * @return true if the timer has been cancelled, false otherwise
  67. */
  68. public boolean isCancelled() {
  69. return cancelled;
  70. }
  71. }
  72. private Timer firstTimer = new LoadingIndicatorTimer() {
  73. @Override
  74. public void run() {
  75. if (isCancelled()) {
  76. // IE8 does not properly cancel the timer in all cases.
  77. return;
  78. }
  79. show();
  80. }
  81. };
  82. private Timer secondTimer = new LoadingIndicatorTimer() {
  83. @Override
  84. public void run() {
  85. if (isCancelled()) {
  86. // IE8 does not properly cancel the timer in all cases.
  87. return;
  88. }
  89. getElement().setClassName(PRIMARY_STYLE_NAME);
  90. getElement().addClassName("second");
  91. // For backwards compatibility only
  92. getElement().addClassName(PRIMARY_STYLE_NAME + "-delay");
  93. }
  94. };
  95. private Timer thirdTimer = new LoadingIndicatorTimer() {
  96. @Override
  97. public void run() {
  98. if (isCancelled()) {
  99. // IE8 does not properly cancel the timer in all cases.
  100. return;
  101. }
  102. getElement().setClassName(PRIMARY_STYLE_NAME);
  103. getElement().addClassName("third");
  104. // For backwards compatibility only
  105. getElement().addClassName(PRIMARY_STYLE_NAME + "-wait");
  106. }
  107. };
  108. private Element element;
  109. /**
  110. * Returns the delay (in ms) which must pass before the loading indicator
  111. * moves into the "first" state and is shown to the user
  112. *
  113. * @return The delay (in ms) until moving into the "first" state. Counted
  114. * from when {@link #trigger()} is called.
  115. */
  116. public int getFirstDelay() {
  117. return firstDelay;
  118. }
  119. /**
  120. * Sets the delay (in ms) which must pass before the loading indicator moves
  121. * into the "first" state and is shown to the user
  122. *
  123. * @param firstDelay
  124. * The delay (in ms) until moving into the "first" state. Counted
  125. * from when {@link #trigger()} is called.
  126. */
  127. public void setFirstDelay(int firstDelay) {
  128. this.firstDelay = firstDelay;
  129. }
  130. /**
  131. * Returns the delay (in ms) which must pass before the loading indicator
  132. * moves to its "second" state.
  133. *
  134. * @return The delay (in ms) until the loading indicator moves into its
  135. * "second" state. Counted from when {@link #trigger()} is called.
  136. */
  137. public int getSecondDelay() {
  138. return secondDelay;
  139. }
  140. /**
  141. * Sets the delay (in ms) which must pass before the loading indicator moves
  142. * to its "second" state.
  143. *
  144. * @param secondDelay
  145. * The delay (in ms) until the loading indicator moves into its
  146. * "second" state. Counted from when {@link #trigger()} is
  147. * called.
  148. */
  149. public void setSecondDelay(int secondDelay) {
  150. this.secondDelay = secondDelay;
  151. }
  152. /**
  153. * Returns the delay (in ms) which must pass before the loading indicator
  154. * moves to its "third" state.
  155. *
  156. * @return The delay (in ms) until the loading indicator moves into its
  157. * "third" state. Counted from when {@link #trigger()} is called.
  158. */
  159. public int getThirdDelay() {
  160. return thirdDelay;
  161. }
  162. /**
  163. * Sets the delay (in ms) which must pass before the loading indicator moves
  164. * to its "third" state.
  165. *
  166. * @param thirdDelay
  167. * The delay (in ms) from the event until changing the loading
  168. * indicator into its "third" state. Counted from when
  169. * {@link #trigger()} is called.
  170. */
  171. public void setThirdDelay(int thirdDelay) {
  172. this.thirdDelay = thirdDelay;
  173. }
  174. /**
  175. * Triggers displaying of this loading indicator. The loading indicator will
  176. * actually be shown by {@link #show()} when the "first" delay (as specified
  177. * by {@link #getFirstDelay()}) has passed.
  178. * <p>
  179. * The loading indicator will be hidden if shown when calling this method.
  180. * </p>
  181. */
  182. public void trigger() {
  183. hide();
  184. firstTimer.schedule(getFirstDelay());
  185. }
  186. /**
  187. * Shows the loading indicator in its standard state and triggers timers for
  188. * transitioning into the "second" and "third" states.
  189. */
  190. public void show() {
  191. // Reset possible style name and display mode
  192. getElement().setClassName(PRIMARY_STYLE_NAME);
  193. getElement().addClassName("first");
  194. getElement().getStyle().setDisplay(Display.BLOCK);
  195. // Schedule the "second" loading indicator
  196. int secondTimerDelay = getSecondDelay() - getFirstDelay();
  197. if (secondTimerDelay >= 0) {
  198. secondTimer.schedule(secondTimerDelay);
  199. }
  200. // Schedule the "third" loading indicator
  201. int thirdTimerDelay = getThirdDelay() - getFirstDelay();
  202. if (thirdTimerDelay >= 0) {
  203. thirdTimer.schedule(thirdTimerDelay);
  204. }
  205. }
  206. /**
  207. * Returns the {@link ApplicationConnection} which uses this loading
  208. * indicator
  209. *
  210. * @return The ApplicationConnection for this loading indicator
  211. */
  212. public ApplicationConnection getConnection() {
  213. return connection;
  214. }
  215. /**
  216. * Sets the {@link ApplicationConnection} which uses this loading indicator.
  217. * Only used internally.
  218. *
  219. * @param connection
  220. * The ApplicationConnection for this loading indicator
  221. */
  222. void setConnection(ApplicationConnection connection) {
  223. this.connection = connection;
  224. }
  225. /**
  226. * Hides the loading indicator (if visible). Cancels any possibly running
  227. * timers.
  228. */
  229. public void hide() {
  230. firstTimer.cancel();
  231. secondTimer.cancel();
  232. thirdTimer.cancel();
  233. getElement().getStyle().setDisplay(Display.NONE);
  234. }
  235. /**
  236. * Returns whether or not the loading indicator is showing.
  237. *
  238. * @return true if the loading indicator is visible, false otherwise
  239. */
  240. public boolean isVisible() {
  241. if (getElement().getStyle().getDisplay()
  242. .equals(Display.NONE.getCssName())) {
  243. return false;
  244. }
  245. return true;
  246. }
  247. /**
  248. * Returns the root element of the loading indicator
  249. *
  250. * @return The loading indicator DOM element
  251. */
  252. public Element getElement() {
  253. if (element == null) {
  254. element = DOM.createDiv();
  255. element.getStyle().setPosition(Position.ABSOLUTE);
  256. getConnection().getUIConnector().getWidget().getElement()
  257. .appendChild(element);
  258. }
  259. return element;
  260. }
  261. }