Subversion Repositories eFlore/Applications.cel

Rev

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