Subversion Repositories eFlore/Archives.cel-v1

Rev

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

/*
Auto-Completion Textbox for GWT
Copyright (C) 2006 Oliver Albers http://gwt.components.googlepages.com/

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

*/
package org.tela_botanica.client;


// TODO : traiter latence (augmenter en fonction rapidité saisie + texte vide)
// TODO : traiter Tab (selection)
// TODO : revoir traitement keyup, keydown

import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.client.HTTPRequest;
import com.google.gwt.user.client.ResponseTextHandler;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

import java.util.Vector;
import java.util.HashMap;



public class AutoCompleteAsyncTextBox extends TextBox
    implements KeyboardListener, ChangeListener, SourcesAutoCompleteAsyncTextBoxEvents {
   
  private String searchUrl = null; 
  private AutoCompleteAsyncTextBoxListenerCollection autoCompleteAsyncTextBoxListeners=null;  
    
  private HashMap cache = new HashMap();
  private boolean searching = false;
                  
  protected PopupPanel choicesPopup = new PopupPanel(true);
  protected ListBox choices = new ListBox();
  protected Vector items = new Vector(); 
  protected boolean popupAdded = false;
  protected boolean visible = false;
   
  /**
   * Default Constructor
   *
   */
  public AutoCompleteAsyncTextBox()
  {
    super();
    this.addKeyboardListener(this);
    choices.addChangeListener(this);
    this.setStyleName("AutoCompleteAsyncTextBox");
       
    choicesPopup.add(choices);
    choicesPopup.addStyleName("AutoCompleteChoices");
       
    choices.setStyleName("list");
    
  }

 
  
  public void addAutoCompleteAsyncTextBoxListener(AutoCompleteAsyncTextBoxListener listener) {
            if (autoCompleteAsyncTextBoxListeners == null) {
              autoCompleteAsyncTextBoxListeners = new AutoCompleteAsyncTextBoxListenerCollection();
            }
            autoCompleteAsyncTextBoxListeners.addElement(listener);
  }


 
  public void setSearchUrl(String url) {
          
          this.searchUrl=url;
  }
  
  private void doFetchURL(String match) {
          /*
           * Here we fetch the URL and call the handler
           */     
          
          if (this.searchUrl!=null && searching==false) {
                  searching=true;
              HTTPRequest.asyncGet(this.searchUrl + match, 
                            new ResponseTextHandler(){
                                public void onCompletion(String str) {
                          
                                        JSONValue jsonValue= JSONParser.parse(str);
                                        JSONArray jsonArray;
                                        JSONString jsonString;

                                        if ((jsonArray = jsonValue.isArray()) != null) {
                                                for (int i = 0; i < jsonArray.size(); ++i) {
                                                        if ((jsonString = (jsonArray.get(i)).isString()) != null) {
                                                                addItem(jsonString.stringValue());
                                                        }
                                                }
                                        }

                                        displayList();
                                    

                          
                          }       
                                
                                  

                            });

          }
  }

  
  /**
   * Not used at all
   */
  public void onKeyDown(Widget arg0, char arg1, int arg2) {
  }

  /**
   * Not used at all
   */
  public void onKeyPress(Widget arg0, char arg1, int arg2) {
         
            if(arg1 == KEY_DOWN)
            {
              int selectedIndex = choices.getSelectedIndex();
              selectedIndex++;
              if(selectedIndex >= choices.getItemCount())
              {
                selectedIndex = 0;
              }
              choices.setSelectedIndex(selectedIndex);
                   
              return;
            }
               
            if(arg1 == KEY_UP)
            {
              int selectedIndex = choices.getSelectedIndex();
              selectedIndex--;
              if(selectedIndex < 0)
              {
                selectedIndex = choices.getItemCount() - 1 ;
              }
              choices.setSelectedIndex(selectedIndex);
                   
              return;        
            }
          
          
  }

  /**
   * A key was released, start autocompletion
   */
  public void onKeyUp(Widget arg0, char arg1, int arg2) {


         if(arg1 == KEY_DOWN)
         {
                 return;

         }
         

         if(arg1 == KEY_UP)
         {
                 return;

         }

    if(arg1 == KEY_ENTER)
    {
      if(visible)
      {
        complete();
      }
      else {
         // Validation de l'entree : 
          if (autoCompleteAsyncTextBoxListeners!= null) {
              autoCompleteAsyncTextBoxListeners.fireTextBoxEnter(this, this.getText());
          }
          
          this.setText("");
      }
           
      return;
    }
       
    if(arg1 == KEY_ESCAPE)
    {
      choices.clear();
      items.clear();
      choicesPopup.hide();
      visible = false;
           
      return;
    }
       
   
 // Lancement appel 
    String text = this.getText();
    
    if(text.length() > 0)
    {
      items.clear();
      
      if (getFromCache(text)!=null) {
          items=getFromCache(text);
          displayList();
      }
      else {
          this.doFetchURL(text);
      }
    }
  }
    
  
  // Display assistant
  
    public void displayList() { 
        
        searching=false;
            if(this.items.size() > 0)
            {
                
              addToCache(this.getText(),(Vector) items.clone());
              
              choices.clear();
                   
              for(int i = 0; i < items.size(); i++)
              {
                choices.addItem((String) items.get(i));
              }
              
                   
              // if there is only one match and it is what is in the
              // text field anyways there is no need to show autocompletion
              if(items.size() == 1 && ((String) items.get(0)).compareTo(this.getText()) == 0)
              {
                choicesPopup.hide();
              } else {
                choices.setSelectedIndex(0);
                choices.setVisibleItemCount(items.size());
                       
                if(!popupAdded)
                {
                  RootPanel.get().add(choicesPopup);
                  popupAdded = true;
                }
                choicesPopup.show();
                visible = true;
                choicesPopup.setPopupPosition(this.getAbsoluteLeft(),
                this.getAbsoluteTop() + this.getOffsetHeight());
                //choicesPopup.setWidth(this.getOffsetWidth() + "px");
                choices.setWidth(this.getOffsetWidth() + "px");
              }
        
            } else {
              visible = false;
              choicesPopup.hide();
            }
          }

  /**
   * A mouseclick in the list of items
   */
  public void onChange(Widget arg0) {
    complete();
  }
 
  public void onClick(Widget arg0) {
    complete();
  }
   
  // add selected item to textbox
  protected void complete()
  {
    if(choices.getItemCount() > 0)
    {
      this.setText(choices.getItemText(choices.getSelectedIndex()));
    }

    visible=false;
    items.clear();
    choices.clear();
    choicesPopup.hide();
  }
  
  
  public void addItem(String item) {
          items.add(item);
  }
  
  private void addToCache (String query, Vector result)
  {
        cache.put(query.toLowerCase(),result);
  }

  private Vector getFromCache (String query)
  {
        return (Vector) cache.get(query.toLowerCase());
  }
  


  
}