1 package org.vaadin.aceeditor.client;
2
3 import java.util.LinkedList;
4 import java.util.List;
5
6 import com.google.gwt.core.client.GWT;
7 import com.google.gwt.event.dom.client.ChangeEvent;
8 import com.google.gwt.event.dom.client.ChangeHandler;
9 import com.google.gwt.event.dom.client.DoubleClickEvent;
10 import com.google.gwt.event.dom.client.DoubleClickHandler;
11 import com.google.gwt.event.dom.client.KeyCodes;
12 import com.google.gwt.event.dom.client.KeyDownEvent;
13 import com.google.gwt.event.dom.client.KeyDownHandler;
14 import com.google.gwt.user.client.Event;
15 import com.google.gwt.user.client.ui.HTML;
16 import com.google.gwt.user.client.ui.Image;
17 import com.google.gwt.user.client.ui.ListBox;
18 import com.vaadin.client.ui.VOverlay;
19
20 public class SuggestPopup extends VOverlay implements KeyDownHandler,
21 DoubleClickHandler, ChangeHandler {
22 protected ListBox choiceList;
23
24 protected String startOfValue = "";
25
26 public interface SuggestionSelectedListener {
27 void suggestionSelected(TransportSuggestion s);
28 void noSuggestionSelected();
29 }
30
31 protected SuggestionSelectedListener listener;
32
33 protected VOverlay descriptionPopup;
34
35 protected List<TransportSuggestion> suggs;
36 protected List<TransportSuggestion> visibleSuggs = new LinkedList<TransportSuggestion>();
37
38 protected boolean showDescriptions = true;
39
40 protected Image loadingImage;
41
42 public static final int WIDTH = 150;
43 public static final int HEIGHT = 200;
44
45 public static final int DESCRIPTION_WIDTH = 225;
46
47
48 public void setSuggestionSelectedListener(SuggestionSelectedListener ssl) {
49 listener = ssl;
50 }
51
52 public SuggestPopup() {
53 super(true);
54 setWidth(WIDTH + "px");
55 SuggestionResources resources = GWT.create(SuggestionResources.class);
56 loadingImage = new Image(resources.loading());
57 setWidget(loadingImage);
58 }
59
60 protected void createChoiceList() {
61 choiceList = new ListBox();
62 choiceList.setStyleName("list");
63 choiceList.addKeyDownHandler(this);
64 choiceList.addDoubleClickHandler(this);
65 choiceList.addChangeHandler(this);
66 choiceList.setStylePrimaryName("aceeditor-suggestpopup-list");
67 setWidget(choiceList);
68 }
69
70 protected void startLoading() {
71 if (descriptionPopup!=null) {
72 descriptionPopup.hide();
73 }
74 setWidget(loadingImage);
75 }
76
77 public void setSuggestions(List<TransportSuggestion> suggs) {
78 this.suggs = suggs;
79 createChoiceList();
80 populateList();
81 if (choiceList.getItemCount() == 0) {
82 close();
83 }
84 }
85
86 protected void populateList() {
87 choiceList.clear();
88 visibleSuggs.clear();
89 int i = 0;
90 for (TransportSuggestion s : suggs) {
91 if (s.suggestionText.toLowerCase().startsWith(startOfValue)) {
92 visibleSuggs.add(s);
93 choiceList.addItem(s.displayText, "" + i);
94 }
95 i++;
96 }
97 if (choiceList.getItemCount() > 0) {
98 int vic = Math.max(2, Math.min(10, choiceList.getItemCount()));
99 choiceList.setVisibleItemCount(vic);
100 choiceList.setSelectedIndex(0);
101 this.onChange(null);
102 }
103 }
104
105 public void close() {
106 hide();
107 if (listener != null)
108 listener.noSuggestionSelected();
109 }
110
111 @Override
112 public void hide() {
113 super.hide();
114 if (descriptionPopup != null)
115 descriptionPopup.hide();
116 descriptionPopup = null;
117 }
118
119 @Override
120 public void hide(boolean ac) {
121 super.hide(ac);
122 if (ac) {
123
124
125 if (listener != null)
126 listener.noSuggestionSelected();
127 }
128 if (descriptionPopup != null)
129 descriptionPopup.hide();
130 descriptionPopup = null;
131 }
132
133
134 public void onKeyDown(KeyDownEvent event) {
135 int keyCode = event.getNativeKeyCode();
136 if (keyCode == KeyCodes.KEY_ENTER
137 && choiceList.getSelectedIndex() != -1) {
138 event.preventDefault();
139 event.stopPropagation();
140 select();
141 } else if (keyCode == KeyCodes.KEY_ESCAPE) {
142 event.preventDefault();
143 close();
144 }
145 }
146
147
148 public void onDoubleClick(DoubleClickEvent event) {
149 event.preventDefault();
150 event.stopPropagation();
151 select();
152 }
153
154 @Override
155 public void onBrowserEvent(Event event) {
156 if (event.getTypeInt() == Event.ONCONTEXTMENU) {
157 event.stopPropagation();
158 event.preventDefault();
159 return;
160 }
161 super.onBrowserEvent(event);
162 }
163
164 public void up() {
165 if (suggs==null) {
166 return;
167 }
168 int current = this.choiceList.getSelectedIndex();
169 int next = (current - 1 >= 0) ? current - 1 : 0;
170 this.choiceList.setSelectedIndex(next);
171
172
173
174 this.onChange(null);
175 }
176
177 public void down() {
178 if (suggs==null) {
179 return;
180 }
181 int current = this.choiceList.getSelectedIndex();
182 int next = (current + 1 < choiceList.getItemCount()) ? current + 1
183 : current;
184 this.choiceList.setSelectedIndex(next);
185
186
187
188 this.onChange(null);
189 }
190
191 public void select() {
192 if (suggs==null) {
193 return;
194 }
195
196 int selected = choiceList.getSelectedIndex();
197 if (listener != null) {
198 if (selected == -1) {
199 this.hide();
200 listener.noSuggestionSelected();
201 } else {
202 startLoading();
203 listener.suggestionSelected(visibleSuggs.get(selected));
204 }
205 }
206 }
207
208 @Override
209 public void onChange(ChangeEvent event) {
210 if (descriptionPopup == null) {
211 createDescriptionPopup();
212 }
213
214 int selected = choiceList.getSelectedIndex();
215 String descr = visibleSuggs.get(selected).descriptionText;
216
217 if (descr != null && !descr.isEmpty()) {
218 ((HTML) descriptionPopup.getWidget()).setHTML(descr);
219 if (showDescriptions) {
220 descriptionPopup.show();
221 }
222 } else {
223 descriptionPopup.hide();
224 }
225 }
226
227 @Override
228 public void setPopupPosition(int left, int top) {
229 super.setPopupPosition(left, top);
230 if (descriptionPopup!=null) {
231 updateDescriptionPopupPosition();
232 }
233 }
234
235 protected void updateDescriptionPopupPosition() {
236 int x = getAbsoluteLeft() + WIDTH;
237 int y = getAbsoluteTop();
238 descriptionPopup.setPopupPosition(x, y);
239 if (descriptionPopup!=null) {
240 descriptionPopup.setPopupPosition(x, y);
241 }
242 }
243
244 protected void createDescriptionPopup() {
245 descriptionPopup = new VOverlay();
246 descriptionPopup.setOwner(getOwner());
247 descriptionPopup.setStylePrimaryName("aceeditor-suggestpopup-description");
248 HTML lbl = new HTML();
249 lbl.setWordWrap(true);
250 descriptionPopup.setWidget(lbl);
251 updateDescriptionPopupPosition();
252 descriptionPopup.setWidth(DESCRIPTION_WIDTH+"px");
253
254 }
255
256 public void setStartOfValue(String startOfValue) {
257 this.startOfValue = startOfValue.toLowerCase();
258 if (suggs==null) {
259 return;
260 }
261 populateList();
262 if (choiceList.getItemCount() == 0) {
263 close();
264 }
265 }
266
267 }