View Javadoc
1   package org.vaadin.jonatan.contexthelp;
2   
3   import com.vaadin.event.ShortcutAction;
4   import com.vaadin.server.AbstractExtension;
5   import com.vaadin.v7.ui.AbstractField;
6   import com.vaadin.ui.Component;
7   import com.vaadin.ui.UI;
8   import org.vaadin.jonatan.contexthelp.widgetset.client.ui.ContextHelpServerRpc;
9   import org.vaadin.jonatan.contexthelp.widgetset.client.ui.ContextHelpState;
10  import org.vaadin.jonatan.contexthelp.widgetset.client.ui.Placement;
11  
12  /**
13   * The ContextHelp component offers contextual help for fields or groups of
14   * fields. By default, the help bubbles are opened by the user by pressing the
15   * F1 key. You can also specify to programmatically open certain help bubbles
16   * (e.g. via a button click) or to have the help bubble follow focus.
17   * 
18   * @author Jonatan Kronqvist
19   * 
20   */
21  public class ContextHelp extends AbstractExtension {
22  	private static final long serialVersionUID = 3852216539762314709L;
23  
24  	private static int helpComponentIdCounter = 0;
25  
26  	private HelpProvider helpProvider;
27  
28      private ContextHelpServerRpct/client/ui/ContextHelpServerRpc.html#ContextHelpServerRpc">ContextHelpServerRpc rpc = new ContextHelpServerRpc() {
29  
30  		@Override
31  		public void selectComponent(String id) {
32  			getState().selectedComponentId = id;
33              String helpHTML = helpProvider.getHtmlForId(id);
34              if (id != null && !id.equals("") && helpHTML != null) {
35                  getState().helpHTML = helpHTML;
36                  Placement placement = helpProvider.getPlacementForId(id);
37                  getState().placement = placement == null ? Placement.AUTO : placement;
38                  getState().hidden = false;
39              } else {
40  				getState().hidden = true;
41  			}
42  		}
43  
44  		@Override
45  		public void setHidden(boolean hidden) {
46  			getState().hidden = hidden;
47  		}
48      };
49  
50  	
51  	public ContextHelp() {
52  		helpProvider = new DefaultHelpProvider();
53  		registerRpc(rpc);
54  	}
55  	
56      @Override
57      public ContextHelpState getState() {
58          return (ContextHelpState) super.getState();
59      }
60  
61  	/**
62  	 * Registers a help text for a given component. The help text is in HTML
63  	 * format and can be formatted as such and styled with inline CSS. It is
64  	 * also possible to provide classnames for elements in the HTML and provide
65  	 * the CSS rules in the Vaadin theme.
66  	 * 
67  	 * Note that if this method is to be used only if you do not use a custom
68  	 * {@link HelpProvider}.
69  	 * 
70  	 * @param component
71  	 *            the component for which to register the help text.
72  	 * @param help
73  	 *            the help text in HTML.
74  	 */
75  	public void addHelpForComponent(Component component, String help) {
76  		if (helpProvider instanceof DefaultHelpProvider) {
77  			if (component.getId() == null) {
78  				component.setId(generateComponentId());
79  			}
80  			((DefaultHelpProvider) helpProvider).addHelpForId(
81  					component.getId(), help);
82  		}
83  	}
84  
85  	/**
86  	 * Registers a help text for a given component. The help text is in HTML
87  	 * format and can be formatted as such and styled with inline CSS. It is
88  	 * also possible to provide classnames for elements in the HTML and provide
89  	 * the CSS rules in the Vaadin theme.
90  	 * 
91  	 * Note that if this method is to be used only if you do not use a custom
92  	 * {@link HelpProvider}.
93  	 * 
94  	 * @param component
95  	 *            the component for which to register the help text.
96  	 * @param help
97  	 *            the help text in HTML.
98  	 * @param placement
99  	 *            where the help bubble should be placed.
100 	 */
101 	public void addHelpForComponent(Component component, String help,
102 			Placement placement) {
103 		addHelpForComponent(component, help);
104 		setPlacement(component, placement);
105 	}
106 
107 	private String generateComponentId() {
108 		return "help_" + helpComponentIdCounter++;
109 	}
110 
111 	/**
112 	 * Programmatically show the help bubble for a given component.
113 	 * 
114 	 * @param component
115 	 *            the component for which to show the help bubble.
116 	 */
117 	public void showHelpFor(Component component) {
118         if (component.getId() != null) {
119             if (component instanceof AbstractField) {
120                 ((AbstractField)component).focus();
121             }
122 			getState().selectedComponentId = component.getId();
123             String helpHTML = helpProvider.getHtmlForId(component.getId());
124             if (helpHTML != null) {
125                 getState().helpHTML = helpHTML;
126             }
127             Placement placement = helpProvider.getPlacementForId(component.getId());
128             getState().placement = placement == null ? Placement.AUTO : placement;
129 			getState().hidden = false;
130 		}
131 	}
132 
133 	/**
134 	 * Programmatically hide the help bubble.
135 	 */
136 	public void hideHelp() {
137 		getState().selectedComponentId = null;
138 		getState().hidden = true;
139 	}
140 
141 	/**
142 	 * This setting causes the help bubble to be displayed when a field is
143 	 * focused, and removed when the focus moves away from the field. If focus
144 	 * moves to a new field, the help bubble for this new field is shown.
145 	 * 
146 	 * @param followFocus
147 	 *            true (enabled) or false (disabled).
148 	 */
149 	public void setFollowFocus(boolean followFocus) {
150 		getState().followFocus = followFocus;
151 		getState().selectedComponentId = "";
152 	}
153 
154 	/**
155 	 * @return whether the help bubble follows focus or is opened with the F1
156 	 *         key.
157 	 */
158 	public boolean isFollowFocus() {
159 		return getState().followFocus;
160 	}
161 
162 	/**
163 	 * Specifies where the help bubble should be placed in relation to the
164 	 * component. This is only active for the specified component. The default
165 	 * is to place the help bubble to the right of components and if it doesn't
166 	 * fit there, ContextHelp attempts to place it below followed by above the
167 	 * component.
168 	 * 
169 	 * Note that if this method is to be used only if you do not use a custom
170 	 * {@link HelpProvider}.
171 	 * 
172 	 * @param component
173 	 *            the component for which to define the placement of the help
174 	 *            bubble.
175 	 * @param placement
176 	 *            the placement of the help bubble.
177 	 */
178 	public void setPlacement(Component component, Placement placement) {
179 		if (helpProvider instanceof DefaultHelpProvider) {
180 			((DefaultHelpProvider) helpProvider).setPlacementOfId(
181 					component.getId(), placement);
182 		}
183 	}
184 
185 	/**
186 	 * Sets the key that is used for opening the help bubble. Use the key codes
187 	 * found in {@link ShortcutAction.KeyCode}
188 	 * 
189 	 * @param helpKey
190 	 *            the key code for the key that opens the help bubble.
191 	 */
192 	public void setHelpKey(int helpKey) {
193 		getState().helpKey = helpKey;
194 	}
195 
196 	/**
197 	 * @return the key code for the key that opens the help bubble.
198 	 */
199 	public int getHelpKey() {
200 		return getState().helpKey;
201 	}
202 
203 	/**
204 	 * @return whether the bubble is automatically hidden when the field is
205 	 *         unfocused.
206 	 */
207 	public boolean isHideOnBlur() {
208 		return getState().hideOnBlur;
209 	}
210 
211 	/**
212 	 * Set whether the bubble should be automatically hidden when the field is
213 	 * unfocused.
214 	 * 
215 	 * This feature is still EXPERIMENTAL, as hiding of the bubble lags in some
216 	 * instances when the component it is attached to is removed (navigated away
217 	 * from) if you don't hide the bubble manually before switching views.
218 	 * 
219 	 * @param hideOnBlur
220 	 */
221 	public void setHideOnBlur(boolean hideOnBlur) {
222 		getState().hideOnBlur = hideOnBlur;
223 	}
224 
225 	/**
226 	 * Sets the {@link HelpProvider} to be used for looking up help texts for
227 	 * components. By default the {@link DefaultHelpProvider} is used.
228 	 * 
229 	 * @param helpProvider
230 	 *            the HelpProvider.
231 	 */
232 	public void setHelpProvider(HelpProvider helpProvider) {
233 		this.helpProvider = helpProvider;
234 	}
235 
236 	/**
237 	 * @return The HelpProvider instance that is used for looking up help text
238 	 *         for components.
239 	 */
240 	public HelpProvider getHelpProvider() {
241 		return helpProvider;
242 	}
243 
244     /**
245      * Add this extension to the target UI.
246      *
247      * @param ui
248      *            the connector to attach this extension to
249      */
250     public void extend(UI ui) {
251         super.extend(ui);
252     }
253 }