/** * */ package org.sinnlabs.dbvim.ui.db; import static org.zkoss.lang.Generics.cast; import java.util.AbstractSequentialList; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.NoSuchElementException; import org.sinnlabs.dbvim.config.ConfigLoader; import org.sinnlabs.dbvim.db.Database; import org.sinnlabs.dbvim.db.DatabaseFactory; import org.sinnlabs.dbvim.db.Entry; import org.sinnlabs.dbvim.db.Value; import org.sinnlabs.dbvim.db.exceptions.DatabaseOperationException; import org.sinnlabs.dbvim.evaluator.AbstractVariableSet; import org.sinnlabs.dbvim.evaluator.DatabaseConditionBuilder; import org.sinnlabs.dbvim.evaluator.exceptions.ParseException; import org.sinnlabs.dbvim.form.FormFieldResolver; import org.sinnlabs.dbvim.form.FormFieldResolverFactory; import org.sinnlabs.dbvim.model.Form; import org.sinnlabs.dbvim.script.Record; import org.sinnlabs.dbvim.ui.IField; import org.sinnlabs.dbvim.ui.annotations.EventType; import org.sinnlabs.dbvim.ui.annotations.WireEvent; import org.sinnlabs.dbvim.zk.model.IFormComposer; import org.zkoss.zk.ui.AbstractComponent; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Executions; import org.zkoss.zk.ui.UiException; import org.zkoss.zk.ui.event.CreateEvent; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.Events; import org.zkoss.zk.ui.select.Selectors; import org.zkoss.zk.ui.select.annotation.Listen; import org.zkoss.zk.ui.select.annotation.Wire; import org.zkoss.zul.Idspace; import org.zkoss.zul.Listbox; import org.zkoss.zul.Listcell; import org.zkoss.zul.Listheader; import org.zkoss.zul.Listitem; import com.mysql.jdbc.StringUtils; /** * Class represents Table field * @author peter.liverovsky * */ public class TableField extends Idspace { /** * */ private static final long serialVersionUID = -2657721752963776218L; protected String formName; protected String qualification; protected Form form; protected FormFieldResolver resolver; protected IFormComposer composer; protected List<IField<?>> selectFields; protected Database db; protected boolean isChildable = true; private transient List<TableColumnField> _items; private int _hdcnt = 1; @Wire private Listbox lstData; /* gatters and setters */ public String getFormName() { return formName; } public void setFormName(String form) throws Exception { formName = form; loadForm(); } public String getQualification() { return qualification; } public void setQualification(String q) { qualification = q; } public List<TableColumnField> getTableColumns() { return _items; } public TableField() { super(); // initialize component after all attributes are loaded addEventListener(Events.ON_CREATE, new EventListener<CreateEvent>() { @Override public void onEvent(CreateEvent e) throws Exception { onCreate(e.getArg()); } }); selectFields = new ArrayList<IField<?>>(); /* get the composer */ if (Executions.getCurrent().getArg() != null) { @SuppressWarnings("unchecked") Map<String, Object> args = (Map<String, Object>) Executions.getCurrent().getArg(); Object c = args.get("composer"); if ( c!= null) composer = (IFormComposer) c; } /* Create the ui */ isChildable = true; Executions.createComponents("/components/tablefield.zul", this, null); Selectors.wireVariables(this, this, null); Selectors.wireComponents(this, this, false); Selectors.wireEventListeners(this, this); // lock the component isChildable = false; init(); } @WireEvent(EventType.CHANGE_FORM_MODE) public void setFieldMode(int mode) { lstData.getItems().clear(); } @WireEvent(EventType.FORM_LOADED) public void onFormLoaded() throws Exception { // initialize resolver and database object if (form == null) return; if (resolver == null) { resolver = FormFieldResolverFactory.getResolver(form); db = DatabaseFactory.createInstance(form, resolver); } for (TableColumnField column : _items) { IField<?> f = resolver.getFields().get(column.getField()); if (f == null) { throw new IllegalArgumentException("Cannot find field id: " + column.getField() + " on form: " + form); } selectFields.add(f); } if (qualification == null) qualification= ""; } @WireEvent(EventType.ENTRY_LOADED) public void onEntryLoaded(Entry e) throws ParseException, DatabaseOperationException { loadData(); } @Listen("onClick = #btnRefresh") public void refreshTable() throws ParseException, DatabaseOperationException { loadData(); } private void loadData() throws ParseException, DatabaseOperationException { lstData.getItems().clear(); AbstractVariableSet<Value<?>> variables = DatabaseConditionBuilder.buildVariablesFromFields(composer.getFields()); List<Entry> entries = db.query(selectFields, qualification, 0, variables); for (Entry entry : entries) { Listitem item = new Listitem(); for (Value<?> v : entry.getValues()) { if (v.getValue() != null) item.appendChild(new Listcell(v.getValue().toString())); else item.appendChild(new Listcell("")); } item.setValue(entry); lstData.getItems().add(item); } } /** * Returns table records * @return */ public List<Record> getRecords() { List<Record> records = new ArrayList<Record>(lstData.getItemCount()); for(Listitem i : lstData.getItems()) { Entry e = i.getValue(); Record r = new Record(); for (int k=0; k<e.getValues().size(); k++) { r.getValues().put(selectFields.get(k).getId(), e.getValues().get(k).getValue()); } records.add(r); } return records; } @Override public void beforeChildAdded(Component child, Component refChild) { // if component is locked if (!isChildable) { if (!(child instanceof TableColumnField)) throw new UiException("Wrong child: " + child); } super.beforeChildAdded(child, refChild); } @Override public boolean insertBefore(Component child, Component insertBefore) { boolean ret = super.insertBefore(child, insertBefore); if ((child instanceof TableColumnField) && ret) { updateHeaders(); } return ret; } @Override public boolean appendChild(Component child) { boolean ret = super.appendChild(child); if (ret && (child instanceof TableColumnField)) { updateHeaders(); } return ret; } private void loadForm() throws Exception { if (StringUtils.isNullOrEmpty(formName)) { return; } Form f = ConfigLoader.getInstance().getForms().queryForId(formName); if (f == null) { return; } // we can not create resolver here, because it may cause infinity loop, so init it later form = f; } protected void updateHeaders() { if (_items == null) return; lstData.getListhead().getChildren().clear(); for(TableColumnField column : _items) { Listheader header = new Listheader(); header.setSort("auto"); header.setLabel(column.getLabel()); lstData.getListhead().appendChild(header); } } public void onCreate(Map<?,?> args) throws Exception { } @SuppressWarnings("unchecked") public <T extends Component> List<T> getChildren() { return (List<T>) new Children(); } private void init() { _items = new AbstractSequentialList<TableColumnField>() { public ListIterator<TableColumnField> listIterator(int index) { return new ItemIter(index); } public boolean add(TableColumnField field) { if (super.add(field)) { updateHeaders(); return true; } return false; } public void add(int index, TableColumnField element) { super.add(index, element); updateHeaders(); } public boolean addAll(Collection<? extends TableColumnField> c) { boolean ret = super.addAll(c); updateHeaders(); return ret; } public boolean addAll(int index, Collection<? extends TableColumnField> c) { boolean ret = super.addAll(index, c); updateHeaders(); return ret; } public TableColumnField get(int j) { final Component o = TableField.this.getChildren().get(j + _hdcnt); if (o instanceof TableColumnField) return (TableColumnField)o; throw new IndexOutOfBoundsException("Wrong index: " + j); } public int size() { int sz = getChildren().size() - _hdcnt; return sz; } /** * override for update headers * * @since 3.5.1 */ protected void removeRange(int fromIndex, int toIndex) { ListIterator<TableColumnField> it = listIterator(toIndex); for (int n = toIndex - fromIndex; --n >= 0 && it.hasPrevious();) { it.previous(); it.remove(); } updateHeaders(); } /** * Override to remove unnecessary Listitem re-indexing (when ROD is on, clear() is called frequently). */ public void clear() { super.clear(); updateHeaders(); } }; } private class ItemIter implements ListIterator<TableColumnField>, java.io.Serializable { /** * */ private static final long serialVersionUID = 705355367730620597L; private ListIterator<TableColumnField> _it; private int _j; private boolean _bNxt; private ItemIter(int index) { _j = index; } public void add(TableColumnField o) { prepare(); _it.add(o); ++_j; } public boolean hasNext() { return _j < _items.size(); } public boolean hasPrevious() { return _j > 0; } public TableColumnField next() { if (!hasNext()) //use _items.size() to control if reach listfoot throw new NoSuchElementException(); prepare(); final TableColumnField o = _it.next(); ++_j; _bNxt = true; return o; } public TableColumnField previous() { if (!hasPrevious()) //use _j >= 0 to control if reach listhead throw new NoSuchElementException(); prepare(); final TableColumnField o = _it.previous(); --_j; _bNxt = false; return o; } public int nextIndex() { return _j; } public int previousIndex() { return _j - 1; } public void remove() { if (_it == null) throw new IllegalStateException(); _it.remove(); if (_bNxt) --_j; updateHeaders(); } public void set(TableColumnField o) { if (_it == null) throw new IllegalStateException(); _it.set(o); updateHeaders(); } private void prepare() { if (_it == null) _it = cast(getChildren().listIterator(_j + _hdcnt)); } } protected class Children extends AbstractComponent.Children { protected void removeRange(int fromIndex, int toIndex) { ListIterator<Component> it = listIterator(toIndex); for (int n = toIndex - fromIndex; --n >= 0 && it.hasPrevious();) { it.previous(); it.remove(); } } }; }