/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.eas.client.forms.components.model; import com.eas.client.forms.Forms; import com.eas.client.forms.components.rt.HasEditable; import com.eas.client.forms.components.rt.HasEmptyText; import com.eas.client.forms.components.rt.VComboBox; import com.eas.design.Designable; import com.eas.design.Undesignable; import com.eas.script.HasPublished; import com.eas.script.NoPublisherException; import com.eas.script.ScriptFunction; import com.eas.script.Scripts; import java.awt.BorderLayout; import java.awt.Component; import java.awt.EventQueue; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListCellRenderer; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JTable; import jdk.nashorn.api.scripting.AbstractJSObject; import jdk.nashorn.api.scripting.JSObject; import jdk.nashorn.internal.runtime.JSType; /** * * @author mg */ public class ModelCombo extends ModelComponentDecorator<VComboBox<JSObject>, Object> implements HasPublished, HasEmptyText, HasEditable { private static final String CONSTRUCTOR_JSDOC = "" + "/**\n" + " * A model component that combines a button or editable field and a drop-down list.\n" + " */"; protected Object injected; protected JSObject displayList; protected JSObject boundToList; protected String displayField; @ScriptFunction(jsDoc = CONSTRUCTOR_JSDOC) public ModelCombo() { super(); setDecorated(new VComboBox()); decorated.setRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(JList<? extends Object> list, Object value, int index, boolean isSelected, boolean cellHasFocus) { setText(renderValue(value)); return this; } }); } @ScriptFunction(name = "value", jsDoc = JS_VALUE_JSDOC) @Undesignable @Override public Object getJsValue() { return super.getJsValue(); } @ScriptFunction @Override public void setJsValue(Object aValue) { Object oldValue = getJsValue(); if (oldValue != aValue) { DefaultComboBoxModel<JSObject> dm = ((DefaultComboBoxModel<JSObject>) decorated.getModel()); int newValueIndex = dm.getIndexOf(aValue); if (injected != null) { int injectedValueIndex = dm.getIndexOf(injected); if (injectedValueIndex != -1) { dm.removeElementAt(injectedValueIndex); } } injected = null; if (aValue instanceof JSObject && newValueIndex == -1) { dm.addElement((JSObject) aValue); injected = aValue; } setValue(aValue); } } @Override public JSObject getPublished() { if (published == null) { JSObject publisher = Scripts.getSpace().getPublisher(this.getClass().getName()); if (publisher == null || !publisher.isFunction()) { throw new NoPublisherException(); } published = (JSObject) publisher.call(null, new Object[]{this}); } return published; } protected boolean listChangedEnqueued; protected void enqueueListChanged() { listChangedEnqueued = true; EventQueue.invokeLater(() -> { if (listChangedEnqueued) { listChangedEnqueued = false; refill(); } }); } protected void unbindList() { if (boundToList != null) { Scripts.unlisten(boundToList); boundToList = null; } } protected void bindList() { if (displayList != null && Scripts.isInitialized()) { boundToList = Scripts.getSpace().listen(displayList, "length", new AbstractJSObject() { @Override public Object call(Object thiz, Object... args) { enqueueListChanged(); return null; } }); } } private static final String DISPLAY_LIST_JSDOC = "" + "/**\n" + "* List of displayed options in a dropdown list of the component.\n" + "*/"; @ScriptFunction(jsDoc = DISPLAY_LIST_JSDOC) @Designable(category = "model") public JSObject getDisplayList() { return displayList; } @ScriptFunction public void setDisplayList(JSObject aValue) throws Exception { if (displayList != aValue) { unbindList(); displayList = aValue; bindList(); refill(); decorated.revalidate(); decorated.repaint(); } } protected void refill() { JSObject value = (JSObject) getJsValue(); DefaultComboBoxModel<JSObject> dm = ((DefaultComboBoxModel<JSObject>) decorated.getModel()); dm.removeAllElements(); boolean valueMet = false; if (displayList != null && list) { int length = JSType.toInteger(displayList.getMember("length")); for (int i = 0; i < length; i++) { Object oItem = displayList.getSlot(i); if (oItem instanceof JSObject) { if (oItem.equals(value)) { valueMet = true; } dm.addElement((JSObject) oItem); } } } if (value != null) { if (!valueMet) { dm.addElement(value); injected = value; } dm.setSelectedItem(value); } } private static final String DISPLAY_FIELD_JSDOC = "" + "/**\n" + "* Display field of the component.\n" + "*/"; @ScriptFunction(jsDoc = DISPLAY_FIELD_JSDOC) @Designable(category = "model") public String getDisplayField() { return displayField; } @ScriptFunction public void setDisplayField(String aField) throws Exception { if (displayField == null ? aField != null : !displayField.equals(aField)) { displayField = aField; decorated.revalidate(); decorated.repaint(); } } private static final String LIST_JSDOC = "" + "/**\n" + "* Determines if component shown as a list.\n" + "*/"; protected boolean list = true; @ScriptFunction(jsDoc = LIST_JSDOC) public boolean getList() throws Exception { return list; } @ScriptFunction public void setList(boolean aValue) throws Exception { if (list != aValue) { list = aValue; refill(); decorated.revalidate(); decorated.repaint(); } } @ScriptFunction(jsDoc = EDITABLE_JSDOC) @Override public boolean getEditable() { return decorated.isEditable(); } @ScriptFunction @Override public void setEditable(boolean aValue) { decorated.setEditable(aValue); } @ScriptFunction public String getText() throws Exception { return decorated.getText(); } @ScriptFunction public void setText(String aValue) throws Exception { decorated.setText(aValue); } @ScriptFunction @Override public String getEmptyText() { return decorated.getEmptyText(); } @ScriptFunction @Override public void setEmptyText(String aValue) { decorated.setEmptyText(aValue); } private String renderValue(Object aValue) { return aValue instanceof JSObject ? JSType.toString(ModelWidget.getPathData((JSObject) aValue, displayField)) : ""; } @Override protected void setupCellRenderer(JTable table, int row, int column, boolean isSelected) { removeAll(); String rendered = renderValue(getValue()); JLabel rendererLine = new JLabel(rendered); rendererLine.setOpaque(false); add(rendererLine, BorderLayout.CENTER); } @Override public boolean isFieldContentModified() { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } }