This is how I did it

Create a ComboBoxModel class that holds the data model, an ArrayList
of ComboBoxKeyValue interface
So you can feed the model with various types of objects that
implements the interface.

public interface ComboBoxKeyValue
  {
  /**
   * Implementors must provide a way to get the key
   * @return
   */
  public Object getComboKey ();

  /**
   * And this is the value to display
   * @return
   */
  public String getComboValue ();
  }


Then you create a ComboBox class that extends ListBox
The constructor of ComboBox wants a ComboBoxModel to get the data
from.
On constructor the combo register with the model (yes it becomes a two
way binding and a possible memory leak, this is the reason that in the
ComboBoxModel I had a check for too many registrations)
so it is possible for the model to update the combo when data changes.
What happens next is that the combo is filled with the model and the
interesting thing is that since the data is an array list, the index
in the arrya remains constant (if nobody touches the data)
So it is possible whn the data is selected to go back to the model and
pick the object that was used to create the entry in the list.

I could post the code but it is a bit longish and it would swamp the
post.
Oh, whatever....

public class ComboBox extends ListBox
  {
  private static final String classname="ComboBox.";

  private final ComboBoxModel comboModel;
  private final ComboChangeHandler changeHandler;

  private Object selected_key;

  public ComboBox(ComboBoxModel comboModel)
    {
    this.comboModel = comboModel;
    this.changeHandler = new ComboChangeHandler();

    // register to receive data change events
    comboModel.registerComboBox(this);

    // register to receive change events
    addChangeHandler(changeHandler);

    // if there is any data in the model then fill teh combo up
    fillCombo();
    }

  /**
   * This is needed to match the model, so the actual object are the
same.
   * @param selected_key
   */
  public void setSelectedKey(int selected_key )
    {
    setSelectedKey(Integer.valueOf(selected_key));
    }

  /**
   * The program decides what should be my selected key.
   * I should go into the model and find out what is the index
   * if nothing is selected then it should display nothing...
   * @param selected_key
   */
  public void setSelectedKey ( Object selected_key )
    {
    this.selected_key = selected_key;

    int new_index = comboModel.getKeyIndex(selected_key);

    // this does not generate a selected change
    setSelectedIndex(new_index);
    }

  public Object getSelectedKey ()
    {
    return selected_key;
    }

  /**
   * If this combo selected key is an integere and is not null it will
return its value
   * othervise it returns the default value
   * @param defaultValue
   * @return
   */
  public int getSelectedKey (int defaultValue )
    {
    Object selected = getSelectedKey();
    if ( selected==null) return defaultValue;

    if ( selected instanceof Integer ) return ((Integer)
selected).intValue();

    return defaultValue;
    }

  /**
   * At any time you can call this one to fill the combo with the
model values
   */
  void fillCombo ()
    {
    super.clear();  // clear all items from the combo
    int item_count = comboModel.getKeyValueCount();
    for (int index=0; index<item_count; index++ )
      {
      ComboBoxKeyValue value = comboModel.getKeyValue(index);
      super.addItem(value.getComboValue());
      }
    }

  public void finalize() throws Throwable
    {
    super.finalize();
    comboModel.removeComboBox(this);
    }

  public String toString()
    {
    return "combo id="+selected_key;
    }

private class ComboChangeHandler implements ChangeHandler
  {
  public void onChange(ChangeEvent changeEvent)
    {
    int index = getSelectedIndex();
    if ( index < 0 || index >=comboModel.getKeyValueCount() ) return;

    ComboBoxKeyValue keyval = comboModel.getKeyValue(index);
    if ( keyval == null ) return;

    selected_key = keyval.getComboKey();
    }
  }


  }


public class ComboBoxModel
  {
  private static final String classname="ComboBoxModel.";

  private final ArrayList<ComboBox>comboBoxList;
  private final ArrayList<ComboBoxKeyValue>keyValueList;

  /**
   * Constructor
   */
  public ComboBoxModel()
    {
    comboBoxList = new ArrayList<ComboBox>();
    keyValueList = new ArrayList<ComboBoxKeyValue>();
    }

  /**
   * If you want that a combo is updated when a new dataset arrives
you
   * have to register with the model.
   * Actually it is the combo that register itself.
   * @param comboBox
   */
  void registerComboBox ( ComboBox comboBox )
    {
    if ( comboBox == null )
      {
      // this should really never happen
      Window.alert(classname+"registerComboBox: ERROR
comboBox==null");
      return;
      }

    int listSize = comboBoxList.size();
    if ( listSize > 200 )
      {
      // this should really never happen
      Window.alert(classname+"registerComboBox: WARNING comboBox.size()
="+listSize);
      // but I go on so I can finish whatever I am doing
      }

    if ( comboBoxList.contains(comboBox) )
      {
      // this should really never happen
      Window.alert(classname+"registerComboBox: NOTICE already
contains="+comboBox);
      return;
      }

    comboBoxList.add(comboBox);
    }

  /**
   * If you ever garbage collect the combo you MUST deregister from
the model !!!
   * I can add it to finalize but it is a bit riscy
   * @param comboBox
   * @return
   */
  boolean removeComboBox (ComboBox comboBox )
    {
    if ( comboBox == null ) return false;

    GWT.log(classname+"removeComboBox: "+comboBox,null);

    return comboBoxList.remove(comboBox);
    }

  public void addKeyValue (int key, String value)
    {
    addKeyValue(Integer.valueOf(key),value);
    }

  public void addKeyValue (Object key, String value)
    {
    if ( value == null ) return;

    GenericKeyValue item = new GenericKeyValue(key,value);

    keyValueList.add(item);
    }

  public void setKeyValueList ( ArrayList<? extends ComboBoxKeyValue>
keyValueList )
    {
    this.keyValueList.clear();
    addKeyValue(null,"");
    this.keyValueList.addAll(keyValueList);

    // now I need to go to all the combo boxes and refresh the content
    for ( int index=0; index<comboBoxList.size(); index++)
      {
      ComboBox item = comboBoxList.get(index);
      item.fillCombo();
      }
    }

  int getKeyIndex ( Object key )
    {
    // I know, see the setKeyValueList that the first element is the
null one.
    if ( key == null ) return 0;

    int items_count = getKeyValueCount();
    for (int index=1; index<items_count; index++)
      {
      ComboBoxKeyValue value = getKeyValue(index);
      if ( key.equals(value.getComboKey())) return index;
      }

    return 0;
    }

  /**
   * Combo boxex may ask how big the data value is
   * @return
   */
  int getKeyValueCount ()
    {
    return keyValueList.size();
    }

  /**
   * Then they can get one by one the elements.
   * @param index
   * @return
   */
  ComboBoxKeyValue getKeyValue ( int index )
    {
    return keyValueList.get(index);
    }


public static class GenericKeyValue implements ComboBoxKeyValue
  {
  private final Object key;
  private final String value;

  public GenericKeyValue(Object key, String value)
    {
    this.key = key;
    this.value = value;
    }

  public Object getComboKey()
    {
    return key;
    }

  public String getComboValue()
    {
    return value;
    }
  }


  }


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Google Web Toolkit" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/Google-Web-Toolkit?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to