Rev 2737 | Blame | Compare with Previous | Last modification | View Log | RSS feed
package org.tela_botanica.client.util.autocompletion;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.tela_botanica.client.cel2;
import org.tela_botanica.client.modeles.objets.Utilisateur;
import com.google.gwt.core.client.Callback;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.SuggestBox.SuggestionDisplay;
import com.google.gwt.user.client.ui.SuggestOracle;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
import com.gwtext.client.widgets.BoxComponent;
import com.gwtext.client.widgets.Component;
import com.gwtext.client.widgets.Container;
import com.gwtext.client.widgets.Panel;
import com.gwtext.client.widgets.event.PanelListener;
import com.gwtext.client.widgets.event.PanelListenerAdapter;
import com.gwtext.client.widgets.layout.FitLayout;
@SuppressWarnings("unchecked")
public abstract class AutoCompletionComboBox extends Panel {
Label label = null;
MultiWordSuggestOracle msu = null;
SuggestBox suggestions = null;
DefaultSuggestionDisplay sgd = null;
Callback<String, String> surCopierColler = null;
SuggestOracle.Request requeteOracle;
SuggestOracle.Callback callBackOracle;
Timer suggestionTimer = null;
int tempsAvantRequete = 500;
Map<String, String> possibilites = null;
String urlRequete = "";
public AutoCompletionComboBox(String nomLabel, String urlRequete) {
this.setStyleName("champAutoComplete");
this.label = new Label(nomLabel+":");
this.urlRequete = urlRequete;
sgd = new SuggestBox.DefaultSuggestionDisplay();
msu = new MultiWordSuggestOracle() {
@Override
public void requestSuggestions(Request request, Callback callback) {
List<MultiWordSuggestion> retenus = new ArrayList<MultiWordSuggestion>();
Iterator<String> it = possibilites.keySet().iterator();
while (it.hasNext()) {
String cle = it.next();
String cleAffichee = preTraiterValeurAvantAffichage(possibilites.get(cle));
MultiWordSuggestion muWoSug = new MultiWordSuggestion(possibilites.get(cle), cleAffichee);
retenus.add(muWoSug);
}
Response reponse = new Response(retenus);
callback.onSuggestionsReady(request, reponse);
}
};
suggestions = new SuggestBox(msu, new TextBox(), sgd) {
public void onBrowserEvent(Event event) {
switch (event.getTypeInt()) {
case Event.ONPASTE: {
if(surCopierColler != null) {
surCopierColler.onSuccess(suggestions.getValueBox().getValue());
}
}
break;
default:
// WTF: Curieux bloc qui est nécessaire car si on appelle pas super.onBrowserEvent
// aucun évènement ne fonctionne et si on le fait, cela génère des nullPointerException
// donc on transige en l'appelant dans un try catch
try {
super.onBrowserEvent(event);
} catch (Exception e) {
// à priori rien à faire
}
}
}
};
suggestions.setAutoSelectEnabled(false);
setLayout(new FitLayout());
add(label);
add(suggestions);
gererEvenements();
}
public void gererEvenements() {
suggestions.addKeyDownHandler(new KeyDownHandler() {
@Override
public void onKeyDown(KeyDownEvent event) {
// Lorsque la liste de suggestions est ouverte, une frappe sur entrée selectionne la valeur
// Si elle est fermée, elle déclenche la fonction abstraite de validation (utile pour les champs
// du genre station, milieu etc... et la saisie d'obs rapide
if(event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
if((sgd == null || !sgd.isSuggestionListShowing())) {
onValidationSaisie();
event.stopPropagation();
return;
} else {
// Dans les autres cas, un appui sur entrée ne doit pas redéclencher l'autcomplétion
return;
}
}
if(event.getNativeKeyCode() == KeyCodes.KEY_DOWN) {
// Un appui sur flèche bas permet de demander toute la liste
if(!sgd.isSuggestionListShowing()) {
requeteToutesSuggestions();
}
}
// Tout autre frappe d'un caractère "normal" déclenche le timer d'autocomplétion
if(!KeyDownEvent.isArrow(event.getNativeKeyCode())) {
gererTimer();
}
}
});
requeteOracle = new SuggestOracle.Request();
callBackOracle = new SuggestOracle.Callback() {
public void onSuggestionsReady(SuggestOracle.Request request, SuggestOracle.Response response) {
suggestions.showSuggestionList();
}
};
suggestions.addSelectionHandler(new SelectionHandler<SuggestOracle.Suggestion>(){
@Override
public void onSelection(SelectionEvent<Suggestion> event) {
onSelectionValeur();
}
});
suggestions.addValueChangeHandler(new ValueChangeHandler<String>() {
@Override
public void onValueChange(ValueChangeEvent<String> event) {
onModificationValeur();
}
});
surCopierColler = new Callback<String, String>() {
@Override
public void onSuccess(String result) {
gererTimer();
}
@Override
public void onFailure(String reason) {
// rien à faire ça n'échoue jamais
}
};
addListener(new PanelListenerAdapter() {
@Override
public void onResize(BoxComponent component, int adjWidth, int adjHeight,
int rawWidth, int rawHeight) {
redimensionner(rawWidth);
}
});
}
public void redimensionner(final int largeur) {
suggestions.setWidth((largeur - label.getOffsetWidth() - 13)+"px");
}
public void gererTimer() {
if(suggestionTimer == null) {
suggestionTimer = new Timer() {
public void run() {
requeteSuggestions();
}
};
suggestionTimer.schedule(tempsAvantRequete);
} else {
suggestionTimer.schedule(tempsAvantRequete);
}
}
public void setTempsAvantRequete(int temps) {
tempsAvantRequete = temps;
}
public int getTempsAvantRequete(int temps) {
return tempsAvantRequete;
}
public void requeteToutesSuggestions() {
// Cette méthode permet de demander l'autocomplétion même si
// la valeur saisie est vide (cas de l'appui sur flèche bas)
envoyerRequeteSuggestions("*");
}
public void requeteSuggestions() {
// Suppression des espaces et caractères inutiles
String valeur = suggestions.getValue().trim().isEmpty() ? null : suggestions.getValue().trim();
// ceci permet au composant qui utilise l'autocomplétion
// d'annuler une requete et également d'éviter de faire une requête lors du vidage du champ
if(valeur == null) {
return;
}
envoyerRequeteSuggestions(valeur);
}
private void envoyerRequeteSuggestions(final String valeur) {
final String urlRequeteFmt = preTraiterUrlRequete(urlRequete, valeur);
RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, urlRequeteFmt) ;
try {
rb.sendRequest(null, new RequestCallback() {
public void onError(final Request request, final Throwable exception) {
// TODO Auto-generated method stub
}
public void onResponseReceived(final Request request,
final Response response) {
surReponseRequete(valeur, response);
}
}) ;
} catch (RequestException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void surReponseRequete(String requete, Response response) {
possibilites = parserResultatRequete(response);
msu.clear();
Iterator<String> it = possibilites.keySet().iterator();
while (it.hasNext()) {
msu.add(possibilites.get(it.next()));
}
requeteOracle.setQuery(requete);
if(requete.equals("*")) {
// TODO : il y a peut être une méthode plus simple
// mais ceci permet d'afficher les suggestions en cas d'appui
// sur bas lorsque la liste est vide
msu.setDefaultSuggestionsFromText(possibilites.values());
SuggestOracle.Request rq = new SuggestOracle.Request();
rq.setQuery(null);
msu.requestDefaultSuggestions(rq, callBackOracle);
} else {
msu.requestSuggestions(requeteOracle, callBackOracle);
}
}
public String getText() {
return suggestions.getText();
}
public String getRawValue() {
return suggestions.getText();
}
public void setValue(String texte) {
suggestions.setText(texte);
}
public void reset() {
suggestions.setValue("");
}
public void setTabIndex(int index) {
suggestions.setTabIndex(index);
}
public String getLabelText() {
return label.getText();
}
public int getFieldWidth() {
return suggestions.getOffsetWidth();
}
public int getLabelWidth() {
return label.getOffsetWidth();
}
public void agrandirChamp(int largeur) {
suggestions.setWidth(largeur+"px");
}
protected String preTraiterValeurAvantAffichage(String valeur) {
return valeur;
}
protected String preTraiterUrlRequete(String urlRequete, String valeur) {
return urlRequete+URL.encodeQueryString(valeur);
}
protected abstract Map<String, String> parserResultatRequete(Response response);
protected abstract void onModificationValeur();
protected abstract void onSelectionValeur();
protected abstract void onValidationSaisie();
}