Subversion Repositories eFlore/Applications.cel

Rev

Rev 2692 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2602 aurelien 1
package org.tela_botanica.client.util.autocompletion;
2
 
3
import java.util.ArrayList;
4
import java.util.Iterator;
5
import java.util.List;
6
import java.util.Map;
7
 
2734 mathias 8
import org.tela_botanica.client.util.Util;
2602 aurelien 9
 
10
import com.google.gwt.core.client.Callback;
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.event.logical.shared.SelectionEvent;
15
import com.google.gwt.event.logical.shared.SelectionHandler;
16
import com.google.gwt.event.logical.shared.ValueChangeEvent;
17
import com.google.gwt.event.logical.shared.ValueChangeHandler;
18
import com.google.gwt.http.client.Request;
19
import com.google.gwt.http.client.RequestBuilder;
20
import com.google.gwt.http.client.RequestCallback;
21
import com.google.gwt.http.client.RequestException;
22
import com.google.gwt.http.client.Response;
23
import com.google.gwt.http.client.URL;
24
import com.google.gwt.user.client.Event;
25
import com.google.gwt.user.client.Timer;
26
import com.google.gwt.user.client.Window;
27
import com.google.gwt.user.client.ui.Label;
28
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
29
import com.google.gwt.user.client.ui.SuggestBox;
30
import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay;
31
import com.google.gwt.user.client.ui.TextBox;
32
import com.google.gwt.user.client.ui.SuggestOracle;
33
import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
34
import com.gwtext.client.widgets.BoxComponent;
35
import com.gwtext.client.widgets.Panel;
36
import com.gwtext.client.widgets.event.PanelListenerAdapter;
37
import com.gwtext.client.widgets.layout.FitLayout;
38
 
39
@SuppressWarnings("unchecked")
40
public abstract class AutoCompletionComboBox extends Panel {
41
 
42
	Label label = null;
43
	MultiWordSuggestOracle msu = null;
44
	SuggestBox suggestions = null;
45
	DefaultSuggestionDisplay sgd = null;
46
 
47
	Callback<String, String> surCopierColler = null;
48
 
49
	SuggestOracle.Request requeteOracle;
50
    SuggestOracle.Callback callBackOracle;
51
 
52
	Timer suggestionTimer = null;
53
    int tempsAvantRequete = 500;
54
 
55
    Map<String, String> possibilites = null;
56
 
57
    String urlRequete = "";
58
 
59
	public AutoCompletionComboBox(String nomLabel, String urlRequete) {
60
 
61
		this.setStyleName("champAutoComplete");
62
 
63
		this.label = new Label(nomLabel+":");
64
		this.urlRequete = urlRequete;
65
 
66
		sgd = new SuggestBox.DefaultSuggestionDisplay();
67
		msu = new MultiWordSuggestOracle() {
68
			@Override
69
			public void requestSuggestions(Request request, Callback callback) {
70
				List<MultiWordSuggestion> retenus = new ArrayList<MultiWordSuggestion>();
71
				Iterator<String> it = possibilites.keySet().iterator();
72
			    while (it.hasNext()) {
73
			    	String cle = it.next();
2734 mathias 74
			    	String cleAffichee = preTraiterValeurAvantAffichage(cle);
75
					MultiWordSuggestion muWoSug = new MultiWordSuggestion(cle, cleAffichee);
2602 aurelien 76
					retenus.add(muWoSug);
77
			    }
78
 
79
				Response reponse = new Response(retenus);
80
				callback.onSuggestionsReady(request, reponse);
81
			}
82
		};
83
 
84
		suggestions = new SuggestBox(msu, new TextBox(), sgd) {
85
			public void onBrowserEvent(Event event) {
86
			    switch (event.getTypeInt()) {
87
			        case Event.ONPASTE: {
88
			        	if(surCopierColler != null) {
89
			        		surCopierColler.onSuccess(suggestions.getValueBox().getValue());
90
			        	}
91
			        }
92
			        break;
93
			        default:
2692 aurelien 94
			        	// WTF: Curieux bloc qui est nécessaire car si on appelle pas super.onBrowserEvent
95
			        	// aucun évènement ne fonctionne et si on le fait, cela génère des nullPointerException
96
			        	// donc on transige en l'appelant dans un try catch
97
			        	try {
98
			        		super.onBrowserEvent(event);
99
			        	} catch (Exception e) {
100
			        		// à priori rien à faire
101
			        	}
2602 aurelien 102
			    }
103
 
104
			}
105
		};
106
 
107
		suggestions.setAutoSelectEnabled(false);
108
		setLayout(new FitLayout());
109
		add(label);
110
		add(suggestions);
111
		gererEvenements();
112
	}
113
 
114
	public void gererEvenements() {
115
		suggestions.addKeyDownHandler(new KeyDownHandler() {
116
 
117
		    @Override
118
		    public void onKeyDown(KeyDownEvent event) {
119
		    	// Lorsque la liste de suggestions est ouverte, une frappe sur entrée selectionne la valeur
120
		    	// Si elle est fermée, elle déclenche la fonction abstraite de validation (utile pour les champs
121
		    	// du genre station, milieu etc... et la saisie d'obs rapide
122
				if(event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
123
					if((sgd == null || !sgd.isSuggestionListShowing())) {
124
						onValidationSaisie();
2734 mathias 125
						Util.LogVersFirebug("je passe ici");
2602 aurelien 126
						event.stopPropagation();
127
						return;
128
					} else {
2734 mathias 129
						Util.LogVersFirebug("je passe là");
2602 aurelien 130
						// Dans les autres cas, un appui sur entrée ne doit pas redéclencher l'autcomplétion
131
						return;
132
					}
133
				}
134
 
2640 aurelien 135
				if(event.getNativeKeyCode() == KeyCodes.KEY_DOWN) {
136
					// Un appui sur flèche bas permet de demander toute la liste
137
					if(!sgd.isSuggestionListShowing()) {
138
						requeteToutesSuggestions();
139
					}
140
				}
141
 
2602 aurelien 142
				// Tout autre frappe d'un caractère "normal" déclenche le timer d'autocomplétion
143
				if(!KeyDownEvent.isArrow(event.getNativeKeyCode())) {
144
					gererTimer();
145
				}
146
		    }
147
 
148
		});
149
 
150
		requeteOracle = new SuggestOracle.Request();
151
		callBackOracle = new SuggestOracle.Callback() {
152
 
153
			public void onSuggestionsReady(SuggestOracle.Request request, SuggestOracle.Response response) {
154
				suggestions.showSuggestionList();
155
			}
156
	    };
157
 
2734 mathias 158
	    suggestions.addSelectionHandler(new SelectionHandler<SuggestOracle.Suggestion>(){
2602 aurelien 159
			@Override
160
			public void onSelection(SelectionEvent<Suggestion> event) {
161
				onSelectionValeur();
162
			}
163
		});
164
 
165
	    suggestions.addValueChangeHandler(new ValueChangeHandler<String>() {
166
			@Override
167
			public void onValueChange(ValueChangeEvent<String> event) {
168
				onModificationValeur();
169
			}
170
		});
171
 
172
	    surCopierColler = new Callback<String, String>() {
173
			@Override
174
			public void onSuccess(String result) {
175
				gererTimer();
176
			}
177
 
178
			@Override
179
			public void onFailure(String reason) {
180
				// rien à faire ça n'échoue jamais
181
			}
182
		};
183
 
184
		addListener(new PanelListenerAdapter() {
185
 
186
			@Override
187
			public void onResize(BoxComponent component, int adjWidth, int adjHeight,
188
					int rawWidth, int rawHeight) {
189
				redimensionner(rawWidth);
190
			}
191
		});
192
	}
193
 
194
	public void redimensionner(final int largeur) {
195
		suggestions.setWidth((largeur - label.getOffsetWidth() - 13)+"px");
196
	}
197
 
198
	public void gererTimer() {
199
		if(suggestionTimer == null) {
200
			suggestionTimer = new Timer() {
201
				public void run() {
202
					requeteSuggestions();
203
				}
204
			};
205
			suggestionTimer.schedule(tempsAvantRequete);
206
		} else {
207
			suggestionTimer.schedule(tempsAvantRequete);
208
		}
209
	}
210
 
211
	public void setTempsAvantRequete(int temps) {
212
		tempsAvantRequete = temps;
213
	}
214
 
215
	public int getTempsAvantRequete(int temps) {
216
		return tempsAvantRequete;
217
	}
218
 
2640 aurelien 219
	public void requeteToutesSuggestions() {
220
		// Cette méthode permet de demander l'autocomplétion même si
221
		// la valeur saisie est vide (cas de l'appui sur flèche bas)
222
		envoyerRequeteSuggestions("*");
223
	}
224
 
2602 aurelien 225
	public void requeteSuggestions() {
226
		// Suppression des espaces et caractères inutiles
2603 aurelien 227
		String valeur = suggestions.getValue().trim().isEmpty() ? null : suggestions.getValue().trim();
2602 aurelien 228
 
229
		// ceci permet au composant qui utilise l'autocomplétion
2603 aurelien 230
		// d'annuler une requete et également d'éviter de faire une requête lors du vidage du champ
2607 aurelien 231
		if(valeur == null) {
2602 aurelien 232
			return;
233
		}
2640 aurelien 234
		envoyerRequeteSuggestions(valeur);
235
	}
236
 
237
	private void envoyerRequeteSuggestions(final String valeur) {
2607 aurelien 238
		final String urlRequeteFmt = preTraiterUrlRequete(urlRequete, valeur);
239
		RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, urlRequeteFmt) ;
2602 aurelien 240
		try {
241
			rb.sendRequest(null, new RequestCallback() {
242
				public void onError(final Request request, final Throwable exception) {
243
					// TODO Auto-generated method stub
244
				}
245
 
246
				public void onResponseReceived(final Request request,
247
						final Response response) {
2640 aurelien 248
					surReponseRequete(valeur, response);
2602 aurelien 249
				}
250
			}) ;
251
 
252
		} catch (RequestException e) {
253
			// TODO Auto-generated catch block
254
			e.printStackTrace();
255
		}
256
	}
257
 
258
	public void surReponseRequete(String requete, Response response) {
259
		possibilites = parserResultatRequete(response);
260
		msu.clear();
261
		Iterator<String> it = possibilites.keySet().iterator();
262
	    while (it.hasNext()) {
263
	    	msu.add(possibilites.get(it.next()));
264
	    }
265
 
266
		requeteOracle.setQuery(requete);
2640 aurelien 267
		if(requete.equals("*")) {
268
			// TODO : il y a peut être une méthode plus simple
269
			// mais ceci permet d'afficher les suggestions en cas d'appui
270
			// sur bas lorsque la liste est vide
271
			msu.setDefaultSuggestionsFromText(possibilites.values());
272
			SuggestOracle.Request rq = new SuggestOracle.Request();
273
			rq.setQuery(null);
274
			msu.requestDefaultSuggestions(rq, callBackOracle);
275
		} else {
276
			msu.requestSuggestions(requeteOracle, callBackOracle);
277
		}
2602 aurelien 278
	}
279
 
280
	public String getText() {
281
		return suggestions.getText();
282
	}
283
 
2734 mathias 284
	public void setText(String texte) {
285
		suggestions.setText(texte);
286
	}
287
 
2602 aurelien 288
	public String getRawValue() {
289
		return suggestions.getText();
290
	}
2734 mathias 291
 
292
	public String getValue() {
293
		return suggestions.getValue();
294
	}
2602 aurelien 295
 
2734 mathias 296
	public void setValue(String valeur) {
297
		suggestions.setText(valeur);
2602 aurelien 298
	}
299
 
300
	public void reset() {
301
		suggestions.setValue("");
302
	}
303
 
304
	public void setTabIndex(int index) {
305
		suggestions.setTabIndex(index);
306
	}
307
 
2603 aurelien 308
	public String getLabelText() {
309
		return label.getText();
310
	}
311
 
312
	public int getFieldWidth() {
313
		return suggestions.getOffsetWidth();
314
	}
315
 
316
	public int getLabelWidth() {
317
		return label.getOffsetWidth();
318
	}
319
 
320
	public void agrandirChamp(int largeur) {
321
		suggestions.setWidth(largeur+"px");
322
	}
323
 
2734 mathias 324
	protected String preTraiterValeurAvantAffichage(String cle) {
325
		return possibilites.get(cle);
2607 aurelien 326
	}
327
	protected String preTraiterUrlRequete(String urlRequete, String valeur) {
328
		return urlRequete+URL.encodeQueryString(valeur);
329
	}
2602 aurelien 330
	protected abstract Map<String, String> parserResultatRequete(Response response);
331
	protected abstract void onModificationValeur();
332
	protected abstract void onSelectionValeur();
333
	protected abstract void onValidationSaisie();
334
}