/* * Ext GWT - Ext for GWT * Copyright(c) 2007-2009, Ext JS, LLC. * licensing@extjs.com * * http://extjs.com/license */ package com.extjs.gxt.ui.client.widget.form; import java.util.List; import com.extjs.gxt.ui.client.core.El; import com.extjs.gxt.ui.client.core.XTemplate; import com.extjs.gxt.ui.client.data.ModelData; import com.extjs.gxt.ui.client.event.ComponentEvent; import com.extjs.gxt.ui.client.event.Events; import com.extjs.gxt.ui.client.event.Listener; import com.extjs.gxt.ui.client.event.SelectionChangedEvent; import com.extjs.gxt.ui.client.event.SelectionChangedListener; import com.extjs.gxt.ui.client.event.SelectionProvider; import com.extjs.gxt.ui.client.store.ListStore; import com.extjs.gxt.ui.client.widget.ComponentHelper; import com.extjs.gxt.ui.client.widget.ListView; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; /** * A multi-select list field. * * <dl> * <dt>Inherited Events:</dt> * <dd>Field Focus</dd> * <dd>Field Blur</dd> * <dd>Field Change</dd> * <dd>Field Invalid</dd> * <dd>Field Valid</dd> * <dd>Field KeyPress</dd> * <dd>Field SpecialKey</dd> * <dd>BoxComponent Move</dd> * <dd>BoxComponent Resize</dd> * <dd>Component Enable</dd> * <dd>Component Disable</dd> * <dd>Component BeforeHide</dd> * <dd>Component Hide</dd> * <dd>Component BeforeShow</dd> * <dd>Component Show</dd> * <dd>Component Attach</dd> * <dd>Component Detach</dd> * <dd>Component BeforeRender</dd> * <dd>Component Render</dd> * <dd>Component BrowserEvent</dd> * <dd>Component BeforeStateRestore</dd> * <dd>Component StateRestore</dd> * <dd>Component BeforeStateSave</dd> * <dd>Component SaveState</dd> * </dl> * * @param <D> the model type */ public class ListField<D extends ModelData> extends Field<D> implements SelectionProvider<D> { protected ListView<D> listView; protected ListStore<D> store; protected int listHeight = 100; protected int listWidth = 200; private XTemplate template; private String listStyle = "x-combo-list"; private String selectedStyle = "x-combo-selected"; private String itemSelector; private El input; private String valueField; public ListField() { listView = new ListView<D>(); setPropertyEditor(new ListModelPropertyEditor<D>()); } public void addSelectionChangedListener(SelectionChangedListener<D> listener) { addListener(Events.SelectionChange, listener); } @Override public void disable() { super.disable(); listView.disable(); } @Override public void enable() { super.enable(); listView.enable(); } /** * Returns the display field. * * @return the display field */ public String getDisplayField() { return getPropertyEditor().getDisplayProperty(); } /** * Returns the item selector. * * @return the item selector */ public String getItemSelector() { return itemSelector; } /** * Returns the field's list view. * * @return the list view */ public ListView<D> getListView() { return listView; } @Override public ListModelPropertyEditor<D> getPropertyEditor() { return (ListModelPropertyEditor<D>) propertyEditor; } @Override public String getRawValue() { return ""; } public List<D> getSelection() { return listView.getSelectionModel().getSelectedItems(); } /** * Returns the field's store. * * @return the store */ public ListStore<D> getStore() { return store; } /** * Returns the custom template. * * @return the template */ public XTemplate getTemplate() { return template; } @Override public D getValue() { List<D> sel = getSelection(); if (sel.size() > 1) { return sel.get(0); } return null; } public String getValueField() { return valueField; } public void removeSelectionListener(SelectionChangedListener<D> listener) { removeListener(Events.SelectionChange, listener); } /** * Sets the display field. * * @param displayField the display field */ public void setDisplayField(String displayField) { getPropertyEditor().setDisplayProperty(displayField); } /** * This setting is required if a custom XTemplate has been specified. * * @param itemSelector the item selector */ public void setItemSelector(String itemSelector) { this.itemSelector = itemSelector; } @Override public void setPropertyEditor(PropertyEditor<D> propertyEditor) { assert propertyEditor instanceof ListModelPropertyEditor : "PropertyEditor must be a ModelPropertyEditor instance"; super.setPropertyEditor(propertyEditor); } public void setSelection(List<D> selection) { if (selection.size() > 0) { setValue(selection.get(0)); listView.getSelectionModel().setSelection(selection); } else { setValue(null); } } /** * Sets the list field's list store. * * @param store the store */ public void setStore(ListStore<D> store) { this.store = store; } /** * Sets the field's template used to render the list. * * @param html the html frament */ public void setTemplate(String html) { assertPreRender(); template = XTemplate.create(html); } /** * Sets the field's template used to render the list. * * @param template */ public void setTemplate(XTemplate template) { assertPreRender(); this.template = template; } /** * Sets the field's value field. * * @param valueField the value field */ public void setValueField(String valueField) { this.valueField = valueField; } @Override protected void doAttachChildren() { super.doAttachChildren(); ComponentHelper.doAttach(listView); } @Override protected void doDetachChildren() { super.doDetachChildren(); ComponentHelper.doDetach(listView); } @Override protected El getFocusEl() { return el(); } @Override protected El getInputEl() { return input; } @Override protected void onClick(ComponentEvent ce) { super.onClick(ce); input.focus(); } @Override protected void onFocus(ComponentEvent ce) { super.onFocus(ce); } @Override protected void onRender(Element parent, int index) { setElement(DOM.createDiv(), parent, index); setStyleName("x-form-list"); if (width != null) { setWidth(width); } else { setWidth(listWidth); } input = new El(DOM.createInputText()); input.dom.getStyle().setProperty("left", "-500"); input.dom.getStyle().setProperty("position", "absolute"); getElement().appendChild(input.dom); if (template == null) { String html = "<tpl for=\".\"><div class='x-combo-list-item'>{" + getDisplayField() + "}</div></tpl>"; template = XTemplate.create(html); } listView.setBorders(false); listView.setTemplate(template); listView.setStyleName(listStyle); listView.setItemSelector(itemSelector != null ? itemSelector : ".x-combo-list-item"); listView.setStore(store); listView.setSelectStyle(selectedStyle); listView.setOverStyle("x-combo-over"); listView.getSelectionModel().addListener(Events.SelectionChange, new Listener<SelectionChangedEvent<D>>() { public void handleEvent(SelectionChangedEvent<D> se) { onSelectionChange(se.getSelection()); } }); if (height != null) { listView.setHeight(height); } else { listView.setHeight(listHeight); } listView.render(getElement()); disableTextSelection(true); DOM.sinkEvents(input.dom, Event.FOCUSEVENTS); sinkEvents(Event.ONCLICK); super.onRender(parent, index); } @Override protected void onResize(int width, int height) { super.onResize(width, height); if (height != -1) { listView.setHeight(height); } } protected void onSelectionChange(List<D> sel) { String prop = valueField != null ? valueField : listView.getDisplayProperty(); StringBuffer sb = new StringBuffer(); for (D m : sel) { sb.append(m.get(prop)); sb.append(","); } String s = sb.toString(); if (sb.length() > 1) { s = s.substring(0, s.length() - 1); } input.setValue(s); } @Override protected boolean validateValue(String value) { return true; } }