package com.eas.bound;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.eas.client.IdGenerator;
import com.eas.client.converters.StringValueConverter;
import com.eas.core.Utils;
import com.eas.ui.CommonResources;
import com.eas.ui.HasEmptyText;
import com.eas.ui.JavaScriptObjectKeyProvider;
import com.eas.ui.PublishedCell;
import com.eas.ui.events.ActionEvent;
import com.eas.ui.events.ActionHandler;
import com.eas.ui.events.HasActionHandlers;
import com.eas.widgets.WidgetsUtils;
import com.eas.widgets.boxes.StyledListBox;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.OptionElement;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.HasName;
import com.google.gwt.user.client.ui.HasValue;
public class ModelCombo extends ModelDecoratorBox<JavaScriptObject> implements HasEmptyText, HasActionHandlers {
protected static final String CUSTOM_DROPDOWN_CLASS = "combo-field-custom-dropdown";
protected JavaScriptObjectKeyProvider rowKeyProvider = new JavaScriptObjectKeyProvider();
protected String keyForNullValue = String.valueOf(IdGenerator.genId());
protected String emptyText;
protected JavaScriptObject displayList;
protected String displayField;
protected HandlerRegistration boundToList;
protected HandlerRegistration boundToListElements;
protected Runnable onRedraw;
protected InputElement nonListMask = Document.get().createTextInputElement();
protected OptionElement nullOption;
protected boolean list = true;
public ModelCombo() {
super(new StyledListBox<JavaScriptObject>());
StyledListBox<JavaScriptObject> box = (StyledListBox<JavaScriptObject>) decorated;
box.addItem("...", keyForNullValue, null, "");
nullOption = box.getItem(0);
box.getElement().addClassName(CUSTOM_DROPDOWN_CLASS);
box.getElement().getStyle().setOverflow(Style.Overflow.HIDDEN);
CommonResources.INSTANCE.commons().ensureInjected();
box.getElement().addClassName(CommonResources.INSTANCE.commons().withoutDropdown());
nonListMask.setReadOnly(true);
nonListMask.addClassName(CommonResources.INSTANCE.commons().borderSized());
nonListMask.getStyle().setPosition(Style.Position.ABSOLUTE);
nonListMask.getStyle().setDisplay(Style.Display.NONE);
nonListMask.getStyle().setTop(0, Style.Unit.PX);
nonListMask.getStyle().setLeft(0, Style.Unit.PX);
nonListMask.getStyle().setWidth(100, Style.Unit.PCT);
nonListMask.getStyle().setHeight(100, Style.Unit.PCT);
getElement().insertFirst(nonListMask);
selectButton.getElement().addClassName("decorator-select-combo");
clearButton.getElement().addClassName("decorator-clear-combo");
}
@Override
public void setFocus(boolean focused) {
if (list) {
super.setFocus(focused);
} else {
nonListMask.focus();
}
}
@Override
protected int organizeButtonsContent() {
int right = super.organizeButtonsContent();
if (nonListMask != null) {
nonListMask.getStyle().setPaddingRight(right, Style.Unit.PX);
}
return right;
}
public Runnable getOnRedraw() {
return onRedraw;
}
public void setOnRedraw(Runnable aValue) {
onRedraw = aValue;
}
protected int actionHandlers;
protected HandlerRegistration valueChangeReg;
@Override
public HandlerRegistration addActionHandler(ActionHandler handler) {
final HandlerRegistration superReg = super.addHandler(handler, ActionEvent.getType());
if (actionHandlers == 0) {
valueChangeReg = addValueChangeHandler(new ValueChangeHandler<JavaScriptObject>() {
@Override
public void onValueChange(ValueChangeEvent<JavaScriptObject> event) {
if (!settingValue){
ActionEvent.fire(ModelCombo.this, ModelCombo.this);
}
}
});
}
actionHandlers++;
return new HandlerRegistration() {
@Override
public void removeHandler() {
superReg.removeHandler();
actionHandlers--;
if (actionHandlers == 0) {
assert valueChangeReg != null : "Erroneous use of addActionHandler/removeHandler detected in ModelCombo";
valueChangeReg.removeHandler();
valueChangeReg = null;
}
}
};
}
@Override
public void setValue(JavaScriptObject aValue, boolean fireEvents) {
JavaScriptObject oldValue = getValue();
if (oldValue != aValue) {
super.setValue(aValue, fireEvents);
nonListMask.setValue(calcLabel(aValue));
}
}
@Override
protected void onAttach() {
super.onAttach();
}
@Override
protected void clearValue() {
try {
setJsValue(null, true);
ActionEvent.fire(this, this);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public JavaScriptObject convert(Object aValue) {
return aValue instanceof JavaScriptObject ? (JavaScriptObject) aValue : null;
}
@Override
protected void rebind() {
super.rebind();
rebindList();
}
protected void rebindList() {
try {
StyledListBox<JavaScriptObject> listBox = (StyledListBox<JavaScriptObject>) decorated;
listBox.setSelectedIndex(-1);
listBox.clear();
listBox.addItem(calcLabel(null), keyForNullValue, null, "");
listBox.setSelectedIndex(0);
if (list) {
boolean valueMet = false;
if (displayList != null) {
JavaScriptObject value = getValue();
List<JavaScriptObject> jsoList = new JsArrayList(displayList);
for (int i = 0; i < jsoList.size(); i++) {
JavaScriptObject item = jsoList.get(i);
if (item != null) {
String itemLabel = calcLabel(item);
listBox.addItem(itemLabel, item.hashCode() + "", item, "");
if (value == item) {
valueMet = true;
listBox.setSelectedIndex(listBox.getItemCount() - 1);
}
}
}
}
if(!valueMet){
clearValue();
}
}
nonListMask.setValue(calcLabel(getValue()));
if (onRedraw != null) {
onRedraw.run();
}
} catch (Exception e) {
Logger.getLogger(ModelCombo.class.getName()).log(Level.SEVERE, e.getMessage(), e);
}
}
public String calcLabel(JavaScriptObject aValue) {
String nullText = emptyText != null && !emptyText.isEmpty() ? emptyText : "..." ;
String labelText = aValue != null ? new StringValueConverter().convert(Utils.getPathData(aValue, displayField))
: nullText;
PublishedCell cell = WidgetsUtils.calcValuedPublishedCell(published, onRender, aValue,
labelText != null ? labelText : "", null);
if (cell != null && cell.getDisplay() != null && !cell.getDisplay().isEmpty()) {
labelText = cell.getDisplay();
}
return labelText;
}
protected HasValue<JavaScriptObject> getDecorated() {
return ((HasValue<JavaScriptObject>) decorated);
}
public String getText() {
return list ? ((StyledListBox<JavaScriptObject>) decorated).getText() : nonListMask.getValue()/* value in nonListMask is exactly text */;
}
@Override
public void setText(String text) {
}
@Override
public String getEmptyText() {
return emptyText;
}
@Override
public void setEmptyText(String aValue) {
emptyText = aValue;
nullOption.setInnerText(aValue);
WidgetsUtils.applyEmptyText(getElement(), emptyText);
}
@Override
public void setPublished(JavaScriptObject aValue) {
super.setPublished(aValue);
if (published != null) {
publish(this, published);
}
}
private native static void publish(ModelCombo aWidget, JavaScriptObject aPublished)/*-{
var B = @com.eas.core.Predefine::boxing;
aPublished.redraw = function() {
aWidget.@com.eas.bound.ModelCombo::rebind()();
};
Object.defineProperty(aPublished, "emptyText", {
get : function() {
return aWidget.@com.eas.ui.HasEmptyText::getEmptyText()();
},
set : function(aValue) {
aWidget.@com.eas.ui.HasEmptyText::setEmptyText(Ljava/lang/String;)(aValue!=null?''+aValue:null);
}
});
Object.defineProperty(aPublished, "value", {
get : function() {
return B.boxAsJs(aWidget.@com.eas.bound.ModelCombo::getJsValue()());
},
set : function(aValue) {
if (aValue != null) {
aWidget.@com.eas.bound.ModelCombo::setJsValue(Ljava/lang/Object;)(B.boxAsJava(aValue));
} else {
aWidget.@com.eas.bound.ModelCombo::setJsValue(Ljava/lang/Object;)(null);
}
}
});
Object.defineProperty(aPublished, "text", {
get : function() {
return aWidget.@com.eas.bound.ModelCombo::getText()();
}
});
Object.defineProperty(aPublished, "displayList", {
get : function() {
return aWidget.@com.eas.bound.ModelCombo::getDisplayList()();
},
set : function(aValue) {
aWidget.@com.eas.bound.ModelCombo::setDisplayList(Lcom/google/gwt/core/client/JavaScriptObject;)(aValue);
}
});
Object.defineProperty(aPublished, "displayField", {
get : function() {
return aWidget.@com.eas.bound.ModelCombo::getDisplayField()();
},
set : function(aValue) {
aWidget.@com.eas.bound.ModelCombo::setDisplayField(Ljava/lang/String;)(aValue != null ? '' + aValue : null);
}
});
Object.defineProperty(aPublished, "list", {
get : function() {
return aWidget.@com.eas.bound.ModelCombo::isList()();
},
set : function(aValue) {
aWidget.@com.eas.bound.ModelCombo::setList(Z)(false != aValue);
}
});
}-*/;
public boolean isList() {
return list;
}
public void setList(boolean aValue) {
if (list != aValue) {
list = aValue;
StyledListBox<JavaScriptObject> listBox = (StyledListBox<JavaScriptObject>) decorated;
if (list) {
listBox.getElement().addClassName(CUSTOM_DROPDOWN_CLASS);
listBox.getElement().getStyle().clearVisibility();
nonListMask.getStyle().setDisplay(Style.Display.NONE);
selectButton.getElement().addClassName("decorator-select-combo");
clearButton.getElement().addClassName("decorator-clear-combo");
nonListMask.removeClassName("form-control");
} else {
listBox.getElement().removeClassName(CUSTOM_DROPDOWN_CLASS);
listBox.getElement().getStyle().setVisibility(Style.Visibility.HIDDEN);
nonListMask.getStyle().setDisplay(Style.Display.INLINE_BLOCK);
selectButton.getElement().removeClassName("decorator-select-combo");
clearButton.getElement().removeClassName("decorator-clear-combo");
nonListMask.addClassName("form-control");
}
rebindList();
}
}
public Object getJsValue() {
return Utils.toJs(getValue());
}
public void setJsValue(Object aValue) throws Exception {
setJsValue(aValue, true);
}
public void setJsValue(Object aValue, boolean fireEvents) throws Exception {
setValue(convert(aValue), fireEvents);
}
public JavaScriptObject getDisplayList() {
return displayList;
}
protected ScheduledCommand changesQueued;
protected void enqueueListChanges() {
changesQueued = new ScheduledCommand() {
@Override
public void execute() {
if (changesQueued == this) {
changesQueued = null;
rebindList();
}
}
};
Scheduler.get().scheduleDeferred(changesQueued);
}
protected boolean readdQueued;
private void enqueueListReadd() {
readdQueued = true;
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
if (readdQueued) {
readdQueued = false;
if (boundToListElements != null) {
boundToListElements.removeHandler();
boundToListElements = null;
}
if (displayList != null) {
boundToListElements = Utils.listenElements(displayList, new Utils.OnChangeHandler() {
@Override
public void onChange(JavaScriptObject anEvent) {
enqueueListChanges();
}
});
}
rebindList();
}
}
});
}
protected void bindList() {
if (displayList != null) {
boundToList = Utils.listenPath(displayList, "length", new Utils.OnChangeHandler() {
@Override
public void onChange(JavaScriptObject anEvent) {
enqueueListReadd();
}
});
enqueueListReadd();
}
}
protected void unbindList() {
if (boundToList != null) {
boundToList.removeHandler();
boundToList = null;
enqueueListReadd();
}
}
public void setDisplayList(JavaScriptObject aValue) {
if (displayList != aValue) {
unbindList();
displayList = aValue;
bindList();
}
}
public String getDisplayField() {
return displayField;
}
public void setDisplayField(String aValue) {
if (displayField != null ? !displayField.equals(aValue) : aValue != null) {
unbindList();
displayField = aValue;
bindList();
}
}
@Override
protected void setReadonly(boolean aValue) {
}
@Override
protected boolean isReadonly() {
return false;
}
}