New file |
0,0 → 1,1499 |
package org.tela_botanica.client.composants; |
|
import java.util.ArrayList; |
import java.util.Iterator; |
import java.util.List; |
|
import org.tela_botanica.client.modeles.aDonnee; |
import org.tela_botanica.client.util.Debug; |
import org.tela_botanica.client.util.UtilString; |
|
import com.extjs.gxt.ui.client.GXT; |
import com.extjs.gxt.ui.client.Style.Scroll; |
import com.extjs.gxt.ui.client.core.El; |
import com.extjs.gxt.ui.client.core.XDOM; |
import com.extjs.gxt.ui.client.core.XTemplate; |
import com.extjs.gxt.ui.client.data.BaseModelData; |
import com.extjs.gxt.ui.client.data.BasePagingLoadConfig; |
import com.extjs.gxt.ui.client.data.ModelData; |
import com.extjs.gxt.ui.client.data.PagingLoadConfig; |
import com.extjs.gxt.ui.client.data.PagingLoader; |
import com.extjs.gxt.ui.client.event.BaseEvent; |
import com.extjs.gxt.ui.client.event.ComponentEvent; |
import com.extjs.gxt.ui.client.event.DomEvent; |
import com.extjs.gxt.ui.client.event.Events; |
import com.extjs.gxt.ui.client.event.FieldEvent; |
import com.extjs.gxt.ui.client.event.ListViewEvent; |
import com.extjs.gxt.ui.client.event.Listener; |
import com.extjs.gxt.ui.client.event.PreviewEvent; |
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.store.StoreEvent; |
import com.extjs.gxt.ui.client.store.StoreListener; |
import com.extjs.gxt.ui.client.util.BaseEventPreview; |
import com.extjs.gxt.ui.client.util.DelayedTask; |
import com.extjs.gxt.ui.client.util.KeyNav; |
import com.extjs.gxt.ui.client.util.Util; |
import com.extjs.gxt.ui.client.widget.CheckBoxListView; |
import com.extjs.gxt.ui.client.widget.ComponentHelper; |
import com.extjs.gxt.ui.client.widget.LayoutContainer; |
import com.extjs.gxt.ui.client.widget.ListView; |
import com.extjs.gxt.ui.client.widget.form.ComboBox; |
import com.extjs.gxt.ui.client.widget.form.ListModelPropertyEditor; |
import com.extjs.gxt.ui.client.widget.form.PropertyEditor; |
import com.extjs.gxt.ui.client.widget.form.TriggerField; |
import com.extjs.gxt.ui.client.widget.form.ComboBox.ComboBoxMessages; |
import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction; |
import com.extjs.gxt.ui.client.widget.form.TextField.TextFieldMessages; |
import com.extjs.gxt.ui.client.widget.toolbar.PagingToolBar; |
import com.google.gwt.dom.client.Document; |
import com.google.gwt.dom.client.InputElement; |
import com.google.gwt.event.dom.client.KeyCodes; |
import com.google.gwt.user.client.Command; |
import com.google.gwt.user.client.DeferredCommand; |
import com.google.gwt.user.client.Element; |
import com.google.gwt.user.client.Event; |
import com.google.gwt.user.client.ui.RootPanel; |
|
|
public class ChampComboBoxMultiSelect<D extends ModelData> extends TriggerField<D> implements SelectionProvider<D> { |
|
/** |
* ComboBox error messages. |
*/ |
public class ComboBoxMessages extends TextFieldMessages { |
|
private String loadingText = GXT.MESSAGES.loadMask_msg(); |
private String valueNoutFoundText; |
|
/** |
* Returns the loading text. |
* |
* @return the loading text |
*/ |
public String getLoadingText() { |
return loadingText; |
} |
|
/** |
* Returns the value not found error text. |
* |
* @return the error text |
*/ |
public String getValueNoutFoundText() { |
return valueNoutFoundText; |
} |
|
/** |
* Sets the loading text. |
* |
* @param loadingText the loading text |
*/ |
public void setLoadingText(String loadingText) { |
this.loadingText = loadingText; |
} |
|
/** |
* When using a name/value combo, if the value passed to setValue is not |
* found in the store, valueNotFoundText will be displayed as the field text |
* if defined. |
* |
* @param valueNoutFoundText |
*/ |
public void setValueNoutFoundText(String valueNoutFoundText) { |
this.valueNoutFoundText = valueNoutFoundText; |
} |
|
} |
|
/** |
* TriggerAction enum. |
*/ |
public enum TriggerAction { |
ALL, QUERY; |
} |
|
protected boolean autoComplete = false; |
protected boolean delayedCheck; |
protected String lastQuery; |
|
protected ListStore<D> store; |
private String allQuery = ""; |
private BaseEventPreview eventPreview; |
private boolean expanded; |
private El footer; |
private boolean forceSelection; |
private InputElement hiddenInput; |
private String itemSelector; |
private String lastSelectionText; |
private boolean lazyRender = true, initialized; |
private LayoutContainer list; |
private String listAlign = "tl-bl?"; |
private String listStyle = "x-combo-list"; |
private int maxHeight = 300; |
private int minChars = 4; |
private int minListWidth = 70; |
private String mode = "remote"; |
private int pageSize; |
private PagingToolBar pageTb; |
private int queryDelay = 500; |
private D selectedItem; |
private String selectedStyle = "x-combo-selected"; |
private StoreListener<D> storeListener; |
private DelayedTask taTask, dqTask; |
private XTemplate template; |
private TriggerAction triggerAction = TriggerAction.QUERY; |
private boolean typeAhead; |
private int typeAheadDelay = 250; |
private boolean useQueryCache = true; |
private String valueField; |
|
//+----------------------------------------------------------------------------------------------------------------+ |
// Attributs modifiés ou ajoutés |
private CheckBoxListView<D> listView = null; |
private String valueFieldSeparator = aDonnee.SEPARATEUR_VALEURS; |
private String rawSeparator = ", "; |
private List<D> listeInitiale = new ArrayList<D>(); |
private boolean initialisation = false; |
private boolean premierAppel = true; |
//+----------------------------------------------------------------------------------------------------------------+ |
|
//+----------------------------------------------------------------------------------------------------------------+ |
// Constructeur modifiés |
public ChampComboBoxMultiSelect() { |
messages = new ComboBoxMessages(); |
listView = new CheckBoxListView<D>(); |
setPropertyEditor(new ListModelPropertyEditor<D>()); |
monitorWindowResize = true; |
windowResizeDelay = 0; |
initComponent(); |
setTriggerAction(TriggerAction.ALL); |
} |
//+----------------------------------------------------------------------------------------------------------------+ |
|
public void addSelectionChangedListener(SelectionChangedListener<D> listener) { |
addListener(Events.SelectionChange, listener); |
} |
|
@Override |
public void clear() { |
getStore().clearFilters(); |
boolean f = forceSelection; |
forceSelection = false; |
super.clear(); |
forceSelection = f; |
} |
|
/** |
* Clears any text/value currently set in the field. |
*/ |
public void clearSelections() { |
setRawValue(""); |
lastSelectionText = ""; |
applyEmptyText(); |
value = null; |
} |
|
/** |
* Execute a query to filter the dropdown list. Fires the BeforeQuery event |
* prior to performing the query allowing the query action to be canceled if |
* needed. |
* |
* @param q the query |
* @param forceAll true to force the query to execute even if there are |
* currently fewer characters in the field than the minimum specified |
* by the minChars config option. It also clears any filter |
* previously saved in the current store |
*/ |
public void doQuery(String q, boolean forceAll) { |
if (q == null) { |
q = ""; |
} |
|
FieldEvent fe = new FieldEvent(this); |
fe.setValue(q); |
if (!fireEvent(Events.BeforeQuery, fe)) { |
return; |
} |
|
if (forceAll || q.length() >= minChars) { |
if (!useQueryCache || !q.equals(lastQuery)) { |
lastQuery = q; |
if (mode.equals("local")) { |
selectedItem = null; |
store.filter(getDisplayField(), q); |
onLoad(null); |
} else { |
expand(); |
store.getLoader().load(getParams(q)); |
} |
} else { |
selectedItem = null; |
onLoad(null); |
} |
} |
} |
|
/** |
* Returns the all query. |
* |
* @return the all query |
*/ |
public String getAllQuery() { |
return allQuery; |
} |
|
/** |
* Returns the display field. |
* |
* @return the display field |
*/ |
public String getDisplayField() { |
return getPropertyEditor().getDisplayProperty(); |
} |
|
/** |
* Returns true if the field's value is forced to one of the value in the |
* list. |
* |
* @return the force selection state |
*/ |
public boolean getForceSelection() { |
return forceSelection; |
} |
|
/** |
* Returns the item selector. |
* |
* @return the item selector |
*/ |
public String getItemSelector() { |
return itemSelector; |
} |
|
/** |
* Returns the list's list align value. |
* |
* @return the list align value |
*/ |
public String getListAlign() { |
return listAlign; |
} |
|
/** |
* Returns the list style. |
* |
* @return the list style |
*/ |
public String getListStyle() { |
return listStyle; |
} |
|
/** |
* Returns the loading text. |
* |
* @return the loading text |
*/ |
public String getLoadingText() { |
return getMessages().getLoadingText(); |
} |
|
/** |
* Returns the dropdown list's max height. |
* |
* @return the max height |
*/ |
public int getMaxHeight() { |
return maxHeight; |
} |
|
@Override |
public ComboBoxMessages getMessages() { |
return (ComboBoxMessages) messages; |
} |
|
/** |
* Returns the min characters used for autocompete and typeahead. |
* |
* @return the minimum number of characters |
*/ |
public int getMinChars() { |
return minChars; |
} |
|
/** |
* Returns the dropdown list's min width. |
* |
* @return the min width |
*/ |
public int getMinListWidth() { |
return minListWidth; |
} |
|
/** |
* Returns the page size. |
* |
* @return the page size |
*/ |
public int getPageSize() { |
return pageSize; |
} |
|
/** |
* Returns the combo's paging tool bar. |
* |
* @return the tool bar |
*/ |
public PagingToolBar getPagingToolBar() { |
return pageTb; |
} |
|
@Override |
public ListModelPropertyEditor<D> getPropertyEditor() { |
return (ListModelPropertyEditor<D>) propertyEditor; |
} |
|
/** |
* Returns the query delay. |
* |
* @return the query delay |
*/ |
public int getQueryDelay() { |
return queryDelay; |
} |
|
/** |
* Returns the selected style. |
* |
* @return the selected style |
*/ |
public String getSelectedStyle() { |
return selectedStyle; |
} |
|
|
/** |
* Returns the combo's store. |
* |
* @return the store |
*/ |
public ListStore<D> getStore() { |
return store; |
} |
|
/** |
* Returns the custom template. |
* |
* @return the template |
*/ |
public XTemplate getTemplate() { |
return template; |
} |
|
/** |
* Returns the trigger action. |
* |
* @return the trigger action |
*/ |
public TriggerAction getTriggerAction() { |
return triggerAction; |
} |
|
/** |
* Returns the type ahead delay in milliseconds. |
* |
* @return the type ahead delay |
*/ |
public int getTypeAheadDelay() { |
return typeAheadDelay; |
} |
|
/** |
* Returns the value field name. |
* |
* @return the value field name |
*/ |
public String getValueField() { |
return valueField; |
} |
|
|
|
/** |
* Returns <code>true</code> if the panel is expanded. |
* |
* @return the expand state |
*/ |
public boolean isExpanded() { |
return expanded; |
} |
|
/** |
* Returns true if lazy rendering is enabled. |
* |
* @return true of lazy rendering |
*/ |
public boolean isLazyRender() { |
return lazyRender; |
} |
|
/** |
* Returns true if type ahead is enabled. |
* |
* @return the type ahead state |
*/ |
public boolean isTypeAhead() { |
return typeAhead; |
} |
|
/** |
* Returns the state if the query cache is used or not. |
* |
* @return the useQueryCache state |
*/ |
public boolean isUseQueryCache() { |
return useQueryCache; |
} |
|
public void removeSelectionListener(SelectionChangedListener<D> listener) { |
removeListener(Events.SelectionChange, listener); |
} |
|
@Override |
public void reset() { |
getStore().clearFilters(); |
boolean f = forceSelection; |
forceSelection = false; |
super.reset(); |
forceSelection = f; |
} |
|
public void select(D sel) { |
if (listView != null && sel != null) { |
int index = store.indexOf(sel); |
selectedItem = sel; |
if (index < listView.getElements().size()) { |
listView.getSelectionModel().select(sel, false); |
fly(listView.getElement(index)).scrollIntoView(listView.getElement(), false); |
} |
} |
} |
|
/** |
* Select an item in the dropdown list by its numeric index in the list. This |
* function does NOT cause the select event to fire. The list must expanded |
* for this function to work, otherwise use #setValue. |
* |
* @param index the index of the item to select |
*/ |
public void select(int index) { |
select(store.getAt(index)); |
} |
|
/** |
* The text query to send to the server to return all records for the list |
* with no filtering (defaults to ''). |
* |
* @param allQuery the all query |
*/ |
public void setAllQuery(String allQuery) { |
this.allQuery = allQuery; |
} |
|
/** |
* The underlying data field name to bind to this ComboBox (defaults to |
* 'text'). |
* |
* @param displayField the display field |
*/ |
public void setDisplayField(String displayField) { |
getPropertyEditor().setDisplayProperty(displayField); |
} |
|
/** |
* Sets the panel's expand state. |
* |
* @param expand <code>true<code> true to expand |
*/ |
public void setExpanded(boolean expand) { |
this.expanded = expand; |
if (isRendered()) { |
if (expand) { |
expand(); |
} else { |
collapse(); |
} |
} |
} |
|
/** |
* Sets whether the combo's value is restricted to one of the values in the |
* list, false to allow the user to set arbitrary text into the field |
* (defaults to false). |
* |
* @param forceSelection true to force selection |
*/ |
public void setForceSelection(boolean forceSelection) { |
this.forceSelection = forceSelection; |
} |
|
/** |
* This setting is required if a custom XTemplate has been specified. |
* |
* @param itemSelector the item selector |
*/ |
public void setItemSelector(String itemSelector) { |
this.itemSelector = itemSelector; |
} |
|
/** |
* True to lazily render the combo's drop down list (default to true, |
* pre-render). |
* |
* @param lazyRender true to lazy render the drop down list |
*/ |
public void setLazyRender(boolean lazyRender) { |
this.lazyRender = lazyRender; |
} |
|
/** |
* Sets a valid anchor position value. See {@link El#alignTo} for details on |
* supported anchor positions (defaults to 'tl-bl?'). |
* |
* @param listAlign the new list align value |
*/ |
public void setListAlign(String listAlign) { |
this.listAlign = listAlign; |
} |
|
/** |
* Sets the style for the drop down list (defaults to 'x-combo-list'); |
* |
* @param listStyle the list style |
*/ |
public void setListStyle(String listStyle) { |
this.listStyle = listStyle; |
} |
|
/** |
* Sets the loading text. |
* |
* @param loadingText the loading text |
*/ |
public void setLoadingText(String loadingText) { |
getMessages().setLoadingText(loadingText); |
} |
|
/** |
* Sets the maximum height in pixels of the dropdown list before scrollbars |
* are shown (defaults to 300). |
* |
* @param maxHeight the max hieght |
*/ |
public void setMaxHeight(int maxHeight) { |
this.maxHeight = maxHeight; |
} |
|
/** |
* Sets the minimum number of characters the user must type before |
* autocomplete and typeahead active (defaults to 4 if remote, or 0 if local). |
* |
* @param minChars |
*/ |
public void setMinChars(int minChars) { |
this.minChars = minChars; |
} |
|
/** |
* Sets the minimum width of the dropdown list in pixels (defaults to 70, will |
* be ignored if listWidth has a higher value). |
* |
* @param minListWidth the min width |
*/ |
public void setMinListWidth(int minListWidth) { |
this.minListWidth = minListWidth; |
} |
|
/** |
* Sets the page size. Only applies when using a paging toolbar. |
* |
* @param pageSize the page size |
*/ |
public void setPageSize(int pageSize) { |
assertPreRender(); |
this.pageSize = pageSize; |
if (pageSize > 0) { |
if (pageTb != null) { |
pageTb.setPageSize(pageSize); |
} else { |
pageTb = new PagingToolBar(pageSize); |
} |
} else { |
pageTb = null; |
} |
} |
|
@Override |
public void setPropertyEditor(PropertyEditor<D> propertyEditor) { |
assert propertyEditor instanceof ListModelPropertyEditor<?> : "PropertyEditor must be a ListModelPropertyEditor instance"; |
super.setPropertyEditor(propertyEditor); |
} |
|
/** |
* The length of time in milliseconds to delay between the start of typing and |
* sending the query to filter the dropdown list. |
* |
* @param queryDelay the query delay |
*/ |
public void setQueryDelay(int queryDelay) { |
this.queryDelay = queryDelay; |
} |
|
@Override |
public void setRawValue(String text) { |
if (rendered) { |
if (text == null) { |
String msg = getMessages().getValueNoutFoundText(); |
text = msg != null ? msg : ""; |
} |
getInputEl().setValue(text); |
} |
} |
|
/** |
* Sets the CSS style name to apply to the selected item in the dropdown list |
* (defaults to 'x-combo-selected'). |
* |
* @param selectedStyle the selected style |
*/ |
public void setSelectedStyle(String selectedStyle) { |
this.selectedStyle = selectedStyle; |
} |
|
/** |
* Sets the template fragment to be used for the text of each combo list item. |
* |
* <pre> |
* |
* <code> combo.setSimpleTemplate("{abbr} {name}"); </code> |
* |
* </pre> |
* |
* @param html the html used only for the text of each item in the list |
*/ |
public void setSimpleTemplate(String html) { |
assertPreRender(); |
html = "<tpl for=\".\"><div class=x-combo-list-item>" + html + "</div></tpl>"; |
template = XTemplate.create(html); |
} |
|
/** |
* Sets the combo's store. |
* |
* @param store the store |
*/ |
public void setStore(ListStore<D> store) { |
this.store = store; |
} |
|
/** |
* Sets the custom template used to render the combo's drop down list.Use this |
* to create custom UI layouts for items in the list. |
* <p> |
* If you wish to preserve the default visual look of list items, add the CSS |
* class name 'x-combo-list-item' to the template's container element. |
* |
* @param html the html |
*/ |
public void setTemplate(String html) { |
assertPreRender(); |
template = XTemplate.create(html); |
} |
|
/** |
* Sets the custom template used to render the combo's drop down list. |
* |
* @param template the template |
*/ |
public void setTemplate(XTemplate template) { |
assertPreRender(); |
this.template = template; |
} |
|
/** |
* The action to execute when the trigger field is activated. Use |
* {@link TriggerAction#ALL} to run the query specified by the allQuery config |
* option (defaults to {@link TriggerAction#QUERY}). |
* |
* @param triggerAction the trigger action |
*/ |
public void setTriggerAction(TriggerAction triggerAction) { |
this.triggerAction = triggerAction; |
} |
|
/** |
* True to populate and autoselect the remainder of the text being typed after |
* a configurable delay ({@link #typeAheadDelay}) if it matches a known value |
* (defaults to false) |
* |
* @param typeAhead |
*/ |
public void setTypeAhead(boolean typeAhead) { |
this.typeAhead = typeAhead; |
if (rendered) { |
if (typeAhead && taTask == null) { |
taTask = new DelayedTask(new Listener<BaseEvent>() { |
public void handleEvent(BaseEvent be) { |
onTypeAhead(); |
} |
}); |
} else if (!typeAhead && taTask != null) { |
taTask.cancel(); |
taTask = null; |
} |
} |
} |
|
/** |
* The length of time in milliseconds to wait until the typeahead text is |
* displayed if typeAhead = true (defaults to 250). |
* |
* @param typeAheadDelay the type ahead delay |
*/ |
public void setTypeAheadDelay(int typeAheadDelay) { |
this.typeAheadDelay = typeAheadDelay; |
} |
|
/** |
* Set this to false to disable the last query cache (defaults to true). |
* |
* When set to false the store gets queried on each expand for the data that |
* should get displayed in the list. If you use a loader, than each time the |
* ComboBox gets expanded, the server gets asked for the data. |
* |
* You want to do this for example, if you filter the content of this ComboBox |
* against some selection in another field. |
* |
* @param useQueryCache the useQueryCache to set |
*/ |
public void setUseQueryCache(boolean useQueryCache) { |
this.useQueryCache = useQueryCache; |
} |
|
/** |
* Sets the model field used to retrieve the "value" from the model. If |
* specified, a hidden form field will contain the value. The hidden form |
* field name will be the combo's field name plus "-hidden". |
* |
* @param valueField the value field name |
*/ |
public void setValueField(String valueField) { |
this.valueField = valueField; |
} |
|
protected void collapseIf(PreviewEvent pe) { |
if (!list.el().isOrHasChild(pe.getTarget()) && !el().isOrHasChild(pe.getTarget())) { |
collapse(); |
} |
} |
|
protected D findModel(String property, String value) { |
if (value == null) return null; |
for (D model : store.getModels()) { |
if (value.equals(getPropertyEditor().getStringValue(model))) { |
return model; |
} |
} |
return null; |
} |
|
protected void fireKey(FieldEvent fe) { |
if (fe.isNavKeyPress() && !isExpanded() && !delayedCheck) { |
fireEvent(Events.SpecialKey, fe); |
} |
} |
|
@Override |
protected El getFocusEl() { |
return input; |
} |
|
protected PagingLoadConfig getParams(String query) { |
BasePagingLoadConfig config = new BasePagingLoadConfig(); |
config.setLimit(pageSize); |
config.setOffset(0); |
config.set("query", query); |
return config; |
} |
|
protected boolean hasFocus() { |
return hasFocus || expanded; |
} |
|
@SuppressWarnings("unchecked") |
protected void initComponent() { |
storeListener = new StoreListener<D>() { |
|
@Override |
public void storeBeforeDataChanged(StoreEvent<D> se) { |
onBeforeLoad(se); |
} |
|
@Override |
public void storeDataChanged(StoreEvent<D> se) { |
onLoad(se); |
} |
|
}; |
|
eventPreview = new BaseEventPreview() { |
@Override |
protected boolean onPreview(PreviewEvent pe) { |
switch (pe.getType().getEventCode()) { |
case Event.ONSCROLL: |
case Event.ONMOUSEWHEEL: |
case Event.ONMOUSEDOWN: |
collapseIf(pe); |
} |
return true; |
} |
}; |
eventPreview.setAutoHide(false); |
|
new KeyNav(this) { |
public void onDown(ComponentEvent ce) { |
ce.cancelBubble(); |
if (!isExpanded()) { |
onTriggerClick(ce); |
} else { |
selectNext(); |
} |
} |
|
@Override |
public void onEnter(ComponentEvent ce) { |
if (expanded) { |
ce.cancelBubble(); |
onViewClick(ce, false); |
delayedCheck = true; |
unsetDelayCheck(); |
} |
} |
|
@Override |
public void onEsc(ComponentEvent ce) { |
if (expanded) { |
ce.cancelBubble(); |
collapse(); |
} |
} |
|
@Override |
public void onTab(ComponentEvent ce) { |
if (expanded) { |
onViewClick(ce, false); |
} |
} |
|
@Override |
public void onUp(ComponentEvent ce) { |
if (expanded) { |
ce.cancelBubble(); |
selectPrev(); |
} |
} |
|
}; |
} |
|
protected void onBeforeLoad(StoreEvent<D> se) { |
if (!hasFocus()) { |
return; |
} |
if (expanded) { |
restrict(); |
} |
} |
|
@Override |
protected void onDetach() { |
collapse(); |
super.onDetach(); |
if (eventPreview != null) { |
eventPreview.remove(); |
} |
} |
|
protected void onEmptyResults() { |
collapse(); |
} |
|
@Override |
protected void onKeyDown(FieldEvent fe) { |
if (fe.getKeyCode() == KeyCodes.KEY_TAB) { |
if (expanded) { |
onViewClick(fe, false); |
} |
} |
super.onKeyDown(fe); |
} |
|
@Override |
protected void onKeyUp(FieldEvent fe) { |
super.onKeyUp(fe); |
if (isEditable() && (!fe.isSpecialKey() || fe.getKeyCode() == KeyCodes.KEY_BACKSPACE || fe.getKeyCode() == 46)) { |
// last key |
dqTask.delay(queryDelay); |
} |
} |
|
protected void onLoad(StoreEvent<D> se) { |
if (!isAttached() || !hasFocus()) { |
return; |
} |
if (store.getCount() > 0) { |
if (expanded) { |
restrict(); |
} else { |
expand(); |
} |
|
if (lastQuery != null && lastQuery.equals(allQuery)) { |
if (isEditable()) { |
selectAll(); |
} |
} else { |
if (typeAhead) { |
taTask.delay(typeAheadDelay); |
} |
} |
if (!selectByValue(getRawValue())) { |
select(0); |
} |
} else { |
onEmptyResults(); |
} |
} |
|
protected void onRender(Element parent, int index) { |
super.onRender(parent, index); |
initList(); |
|
if (!autoComplete) { |
getInputEl().dom.setAttribute("autocomplete", "off"); |
} |
|
if (mode.equals("local")) { |
minChars = 0; |
} |
|
dqTask = new DelayedTask(new Listener<BaseEvent>() { |
public void handleEvent(BaseEvent be) { |
initQuery(); |
} |
}); |
|
if (valueField != null) { |
hiddenInput = Document.get().createHiddenInputElement().cast(); |
hiddenInput.setName(getName() + "-hidden"); |
getElement().appendChild(hiddenInput); |
} |
|
if (typeAhead) { |
taTask = new DelayedTask(new Listener<BaseEvent>() { |
public void handleEvent(BaseEvent be) { |
onTypeAhead(); |
} |
}); |
} |
eventPreview.getIgnoreList().add(getElement()); |
} |
|
protected void onSelect(D model, int index) { |
FieldEvent fe = new FieldEvent(this); |
if (fireEvent(Events.BeforeSelect, fe)) { |
setValue(model); |
collapse(); |
fireEvent(Events.Select, fe); |
} |
} |
|
protected void onTriggerClick(ComponentEvent ce) { |
super.onTriggerClick(ce); |
if (expanded) { |
collapse(); |
} else { |
onFocus(null); |
if (triggerAction == TriggerAction.ALL) { |
doQuery(allQuery, true); |
} else { |
doQuery(getRawValue(), true); |
} |
|
} |
getInputEl().focus(); |
} |
|
protected void onTypeAhead() { |
if (store.getCount() > 0) { |
D m = store.getAt(0); |
String newValue = propertyEditor.getStringValue(m); |
int len = newValue.length(); |
int selStart = getRawValue().length(); |
if (selStart != len) { |
setRawValue(newValue); |
select(selStart, newValue.length()); |
} |
} |
} |
|
protected void onViewClick(DomEvent de, boolean focus) { |
int idx = -1; |
// when testing in selenium the items will not be selected as the mouse |
// is not moved during the test |
Element elem = listView.findElement(de.getTarget()); |
if (elem != null) { |
idx = listView.indexOf(elem); |
} else { |
D sel = listView.getSelectionModel().getSelectedItem(); |
if (sel != null) { |
idx = store.indexOf(sel); |
} |
} |
if (idx != -1) { |
D sel = store.getAt(idx); |
onSelect(sel, idx); |
} |
|
if (focus) { |
DeferredCommand.addCommand(new Command() { |
public void execute() { |
focus(); |
} |
}); |
} |
} |
|
protected void onWindowResize(int width, int height) { |
collapse(); |
} |
|
@Override |
protected void triggerBlur(ComponentEvent ce) { |
doForce(); |
super.triggerBlur(ce); |
} |
|
protected void unsetDelayCheck() { |
DeferredCommand.addCommand(new Command() { |
public void execute() { |
delayedCheck = false; |
} |
}); |
} |
|
@Override |
protected boolean validateBlur(DomEvent e, Element target) { |
return list == null || (list != null && !list.isVisible() && !list.getElement().isOrHasChild(target)); |
} |
|
@Override |
protected boolean validateValue(String value) { |
if (forceSelection) { |
boolean f = forceSelection; |
forceSelection = false; |
if (getValue() == null) { |
forceSelection = f; |
String rv = getRawValue(); |
if (getAllowBlank() && (rv == null || rv.equals(""))) { |
return true; |
} |
markInvalid(getMessages().getBlankText()); |
return false; |
} |
forceSelection = f; |
} |
return super.validateValue(value); |
} |
|
private void createList(boolean remove) { |
RootPanel.get().add(list); |
initialized = true; |
if (remove) { |
RootPanel.get().remove(list); |
} |
} |
|
private void initQuery() { |
doQuery(getRawValue(), false); |
} |
|
private void restrict() { |
list.el().setVisibility(false); |
listView.setHeight("auto"); |
list.setHeight("auto"); |
int w = Math.max(getWidth(), minListWidth); |
|
int fh = footer != null ? footer.getHeight() : 0; |
int fw = list.el().getFrameWidth("tb") + fh; |
|
int h = listView.getHeight() + fw; |
|
h = Math.min(h, maxHeight - fw); |
list.setSize(w, h); |
list.el().makePositionable(true); |
list.el().alignTo(getElement(), listAlign, null); |
|
h -= fh; |
|
int width = w - list.el().getFrameWidth("lr"); |
listView.syncSize(); |
listView.setSize(width, h - list.el().getFrameWidth("tb")); |
|
if (pageTb != null) { |
pageTb.setWidth(width); |
} |
|
int y = list.el().getY(); |
int b = y + h; |
int vh = XDOM.getViewportSize().height + XDOM.getBodyScrollTop(); |
if (b > vh) { |
y = y - (b - vh) - 5; |
list.el().setTop(y); |
} |
list.el().setVisibility(true); |
} |
|
private boolean selectByValue(String value) { |
D r = findModel(getDisplayField(), value); |
if (r != null) { |
select(r); |
return true; |
} |
return false; |
} |
|
private void selectNext() { |
int count = store.getCount(); |
if (count > 0) { |
int selectedIndex = store.indexOf(selectedItem); |
if (selectedIndex == -1) { |
select(0); |
} else if (selectedIndex < count - 1) { |
select(selectedIndex + 1); |
} |
} |
} |
|
private void selectPrev() { |
int count = store.getCount(); |
if (count > 0) { |
int selectedIndex = store.indexOf(selectedItem); |
if (selectedIndex == -1) { |
select(0); |
} else if (selectedIndex != 0) { |
select(selectedIndex - 1); |
} |
} |
} |
|
//+--------------------------------------------------------------------------------------------------------------------+ |
// Méthode modifiées |
|
@Override |
public D getValue() { |
return (D) new BaseModelData(); |
} |
|
@Override |
public void setValue(D value) { |
|
} |
|
public List<D> getSelection() { |
List<D> sel = new ArrayList<D>(); |
if (listeInitiale != null && initialisation == false) { |
sel = listeInitiale; |
if (listView.isRendered()) { |
initialisation = true; |
} |
Debug.log("GetSelection dans listeInitiale :"+sel.size()); |
} else if (listView.isRendered()) { |
sel = listView.getChecked(); |
} |
return sel; |
} |
|
public void setSelection(List<D> selection) { |
nettoyerListeDeCasesACocher(); |
for (D d : selection) { |
listView.setChecked(d, true); |
} |
} |
|
/** |
* Returns the combo's list view. |
* |
* @return the view |
*/ |
public CheckBoxListView<D> getListView() { |
return listView; |
} |
|
/** |
* Returns the combo's list view. |
* |
* @return the view |
*/ |
public CheckBoxListView<D> getView() { |
return listView; |
} |
|
/** |
* Sets the combo's view. |
* |
* @param view the view |
*/ |
public void setView(CheckBoxListView<D> view) { |
this.listView = view; |
} |
|
public String getRawSeparator() { |
return rawSeparator; |
} |
public void setRawSeparator(String rawSeparator) { |
this.rawSeparator = rawSeparator; |
} |
|
public void setValueFieldSeparator(String valueFieldSeparator) { |
this.valueFieldSeparator = valueFieldSeparator; |
} |
public String getValueFieldSeparator() { |
return valueFieldSeparator; |
} |
|
/** |
* Hides the dropdown list if it is currently expanded. Fires the |
* <i>Collapse</i> event on completion. |
*/ |
public void collapse() { |
if (!expanded) { |
return; |
} |
eventPreview.remove(); |
expanded = false; |
list.hide(); |
RootPanel.get().remove(list); |
fireEvent(Events.Collapse, new FieldEvent(this)); |
mettreAJour("collapse"); |
} |
|
/** |
* Expands the dropdown list if it is currently hidden. Fires the |
* <i>expand</i> event on completion. |
*/ |
public void expand() { |
if (expanded || !hasFocus) { |
return; |
} |
expanded = true; |
|
Debug.log("dans expand"); |
if (!initialized) { |
createList(false); |
} else { |
RootPanel.get().add(list); |
} |
|
list.show(); |
list.layout(); |
list.el().updateZIndex(0); |
restrict(); |
|
eventPreview.add(); |
|
fireEvent(Events.Expand, new FieldEvent(this)); |
|
if (premierAppel) { |
premierAppel = false; |
collapse(); |
expand(); |
Debug.log("premier appel"); |
} |
} |
|
protected void initList() { |
Debug.log("initialisation de la liste"); |
|
if (listView == null) { |
Debug.log("La vue de la liste était nulle"); |
setView(new CheckBoxListView<D>()); |
} |
|
String style = getListStyle(); |
listView.setStyleAttribute("overflowX", "hidden"); |
listView.setStyleName(style + "-inner"); |
listView.setStyleAttribute("padding", "0px"); |
listView.setSelectOnOver(true); |
listView.setBorders(false); |
listView.setStyleAttribute("backgroundColor", "white"); |
listView.setSelectStyle(getSelectedStyle()); |
listView.setLoadingText(getLoadingText()); |
|
if (getTemplate() == null) { |
listView.setDisplayProperty(getDisplayField()); |
} else { |
listView.setTemplate(getTemplate()); |
} |
|
setMaxHeight(0); |
|
list = new LayoutContainer() { |
@Override |
protected void onRender(Element parent, int index) { |
super.onRender(parent, index); |
eventPreview.getIgnoreList().add(getElement()); |
} |
}; |
list.setScrollMode(Scroll.NONE); |
list.setShim(true); |
list.setShadow(true); |
list.setBorders(true); |
list.setStyleName(style); |
list.hide(); |
|
assert store != null : "ComboBox needs a store"; |
|
|
list.add(listView); |
listView.show(); |
|
if (!lazyRender) { |
createList(true); |
} |
|
bindStore(store, true); |
}; |
|
protected void doForce() {} |
|
private void bindStore(ListStore<D> store, boolean initial) { |
if (this.store != null && !initial) { |
this.store.removeStoreListener(storeListener); |
if (store == null) { |
this.store = null; |
if (listView != null) { |
listView.setStore(null); |
} |
} |
} |
if (store != null) { |
this.store = store; |
if (store.getLoader() == null) { |
mode = "local"; |
} |
if (listView != null) { |
listView.setStore(store); |
} |
store.addStoreListener(storeListener); |
} |
} |
|
private void updateHiddenValue() { |
if (hiddenInput != null) { |
hiddenInput.setValue(collecterIdentifiants()); |
} |
} |
|
private void mettreAJour(String origine) { |
setSelection(getSelection()); |
setRawValue(collecterTexte()); |
updateHiddenValue(); |
Debug.log("Mise à jour "+origine+" : "+collecterTexte()); |
} |
|
private void nettoyerListeDeCasesACocher() { |
if (listView.isRendered()) { |
List<D> listeADecocher = listView.getChecked(); |
for (D d : listeADecocher) { |
listView.setChecked(d, false); |
} |
} |
} |
|
public void peupler(String identifiants) { |
peuplerAvecIdentifiant(identifiants); |
} |
|
public void peuplerAvecIdentifiant(String identifiants) { |
List<D> liste = parserChaine(identifiants, valueFieldSeparator, getValueField()); |
executerPeuplement(liste); |
} |
|
public void peuplerAvecTexte(String texte) { |
List<D> liste = parserChaine(texte, rawSeparator, getDisplayField()); |
executerPeuplement(liste); |
} |
|
private void executerPeuplement(List<D> liste) { |
listeInitiale = liste; |
initialisation = false; |
mettreAJour("executerPeuplement"); |
} |
|
public String collecter() { |
return collecterIdentifiants(); |
} |
|
public String collecterIdentifiants() { |
return executerCollecte(getSelection(), getValueField(), valueFieldSeparator); |
} |
|
public String collecterTexte() { |
return executerCollecte(getSelection(), getDisplayField(), rawSeparator); |
} |
|
private String executerCollecte(List<D> selection, String champCle, String separateur) { |
String chaineDeSortie = ""; |
Iterator<D> it = selection.iterator(); |
while (it.hasNext()) { |
D d = it.next(); |
chaineDeSortie += d.get(champCle); |
if (it.hasNext()) { |
chaineDeSortie += separateur; |
} |
} |
return chaineDeSortie; |
} |
|
private List<D> parserChaine(String chaineAAnalyser, String separateur, String champCle) { |
ArrayList<D> liste = new ArrayList<D>(); |
chaineAAnalyser = chaineAAnalyser.trim(); |
if (!UtilString.isEmpty(chaineAAnalyser)) { |
String[] valeurs = chaineAAnalyser.split(separateur); |
int nbreValeurs = valeurs.length; |
Debug.log("Executer peuplement : "+chaineAAnalyser+" - nbre : "+nbreValeurs); |
if (nbreValeurs > 0 && getStore() != null) { |
Debug.log("Executer peuplement : "+chaineAAnalyser+" - nbre : "+nbreValeurs); |
for (int i = 0; i < nbreValeurs; i++) { |
String valeur = valeurs[i]; |
D d = getStore().findModel(champCle, valeur); |
liste.add(d); |
} |
} |
} |
return liste; |
} |
|
public String formaterTexteEnIdentifiants(String texte) { |
List<D> liste = parserChaine(texte, rawSeparator, getDisplayField()); |
return executerCollecte(liste, getValueField(), valueFieldSeparator); |
} |
|
public String formaterIdentifiantsEnTexte(String identifiants) { |
List<D> liste = parserChaine(identifiants, valueFieldSeparator, getValueField()); |
return executerCollecte(liste, getDisplayField(), rawSeparator); |
} |
} |