From d5b1984d6a6e95efb61c22b3bb14cf1f5e7c9ecd Mon Sep 17 00:00:00 2001 From: Heng Sin Low Date: Sat, 21 Feb 2009 08:56:23 +0000 Subject: [PATCH] Merge Rev. 8553 minor - avoid double registration of the same listener Rev. 8561 [ 2617300 ] Reimplement grid view using Grid instead of Listbox [ 2621916 ] Enhance short cut key support --- .classpath | 297 ++++++------ .../WEB-INF/src/metainfo/zk/lang-addon.xml | 4 +- .../webui/component/CWindowToolbar.java | 77 +++- .../webui/component/CompositeADTab.java | 1 - .../adempiere/webui/component/GridPanel.java | 156 ++++--- .../component/GridTabListItemRenderer.java | 67 ++- .../webui/component/GridTabRowRenderer.java | 410 +++++++++++++++++ .../webui/component/GridTableListModel.java | 52 ++- .../adempiere/webui/component/ListPanel.java | 429 ++++++++++++++++++ .../adempiere/webui/editor/WButtonEditor.java | 3 +- .../org/adempiere/webui/editor/WEditor.java | 3 +- .../org/adempiere/webui/panel/ADTabpanel.java | 60 ++- .../adempiere/webui/panel/ADWindowPanel.java | 13 +- .../adempiere/webui/util/SortComparator.java | 146 ++++++ 14 files changed, 1480 insertions(+), 238 deletions(-) create mode 100644 zkwebui/WEB-INF/src/org/adempiere/webui/component/GridTabRowRenderer.java create mode 100644 zkwebui/WEB-INF/src/org/adempiere/webui/component/ListPanel.java create mode 100755 zkwebui/WEB-INF/src/org/adempiere/webui/util/SortComparator.java diff --git a/.classpath b/.classpath index a7d20c8a12..ef925ceedc 100644 --- a/.classpath +++ b/.classpath @@ -1,148 +1,149 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/zkwebui/WEB-INF/src/metainfo/zk/lang-addon.xml b/zkwebui/WEB-INF/src/metainfo/zk/lang-addon.xml index a5817a028f..4c75955e2a 100644 --- a/zkwebui/WEB-INF/src/metainfo/zk/lang-addon.xml +++ b/zkwebui/WEB-INF/src/metainfo/zk/lang-addon.xml @@ -19,8 +19,8 @@ Copyright (C) 2007 Ashley G Ramdass (ADempiere WebUI). org.adempiere.webui.AdempiereWebUI - 0.2 + 1.0 - + diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/CWindowToolbar.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/CWindowToolbar.java index 0a1d264c6a..b3dfaabb2c 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/component/CWindowToolbar.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/CWindowToolbar.java @@ -27,6 +27,7 @@ import java.util.logging.Level; import org.adempiere.webui.LayoutUtils; import org.adempiere.webui.event.ToolbarListener; +import org.adempiere.webui.session.SessionManager; import org.compiere.model.MRole; import org.compiere.util.CLogger; import org.compiere.util.Env; @@ -80,12 +81,17 @@ public class CWindowToolbar extends FToolbar implements EventListener private Event event; private Map keyMap = new HashMap(); + private Map altKeyMap = new HashMap(); + private Map ctrlKeyMap = new HashMap(); private boolean embedded; // Elaine 2008/12/04 /** Show Personal Lock */ public boolean isPersonalLock = MRole.getDefault().isPersonalLock(); + + private int windowNo = 0; + /** Last Modifier of Action Event */ // public int lastModifiers; // @@ -203,6 +209,34 @@ public class CWindowToolbar extends FToolbar implements EventListener return buttons.get(name); } + /** VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */ + public static final int VK_A = 0x41; + public static final int VK_B = 0x42; + public static final int VK_C = 0x43; + public static final int VK_D = 0x44; + public static final int VK_E = 0x45; + public static final int VK_F = 0x46; + public static final int VK_G = 0x47; + public static final int VK_H = 0x48; + public static final int VK_I = 0x49; + public static final int VK_J = 0x4A; + public static final int VK_K = 0x4B; + public static final int VK_L = 0x4C; + public static final int VK_M = 0x4D; + public static final int VK_N = 0x4E; + public static final int VK_O = 0x4F; + public static final int VK_P = 0x50; + public static final int VK_Q = 0x51; + public static final int VK_R = 0x52; + public static final int VK_S = 0x53; + public static final int VK_T = 0x54; + public static final int VK_U = 0x55; + public static final int VK_V = 0x56; + public static final int VK_W = 0x57; + public static final int VK_X = 0x58; + public static final int VK_Y = 0x59; + public static final int VK_Z = 0x5A; + private void configureKeyMap() { keyMap.put(KeyEvent.F1, btnHelp); @@ -216,6 +250,22 @@ public class CWindowToolbar extends FToolbar implements EventListener keyMap.put(KeyEvent.F9, btnHistoryRecords); keyMap.put(KeyEvent.F11, btnReport); keyMap.put(KeyEvent.F12, btnPrint); + + altKeyMap.put(KeyEvent.LEFT, btnParentRecord); + altKeyMap.put(KeyEvent.RIGHT, btnDetailRecord); + altKeyMap.put(KeyEvent.UP, btnPrevious); + altKeyMap.put(KeyEvent.DOWN, btnNext); + altKeyMap.put(KeyEvent.PAGE_UP, btnFirst); + altKeyMap.put(KeyEvent.PAGE_DOWN, btnLast); + altKeyMap.put(VK_P, btnReport); + altKeyMap.put(VK_Z, btnIgnore); + + ctrlKeyMap.put(VK_I, btnProductInfo); + ctrlKeyMap.put(VK_P, btnPrint); + ctrlKeyMap.put(VK_N, btnNew); + ctrlKeyMap.put(VK_S, btnSave); + ctrlKeyMap.put(VK_X, btnDelete); + ctrlKeyMap.put(VK_F, btnFind); } protected void addSeparator() @@ -251,7 +301,7 @@ public class CWindowToolbar extends FToolbar implements EventListener } else if (eventName.equals(Events.ON_CTRL_KEY)) { KeyEvent keyEvent = (KeyEvent) event; - this.onCtrlKeyEvent(keyEvent.getKeyCode()); + this.onCtrlKeyEvent(keyEvent); } } @@ -429,9 +479,26 @@ public class CWindowToolbar extends FToolbar implements EventListener return event; } - public void onCtrlKeyEvent(int keycode) { + private void onCtrlKeyEvent(KeyEvent keyEvent) { if (isRealVisible()) { - ToolBarButton btn = keyMap.get(keycode); + ToolBarButton btn = null; + if (keyEvent.isAltKey() && !keyEvent.isCtrlKey() && !keyEvent.isShiftKey()) + { + if (keyEvent.getKeyCode() == VK_X) + { + if (windowNo > 0) + SessionManager.getAppDesktop().closeWindow(windowNo); + } + else + { + btn = altKeyMap.get(keyEvent.getKeyCode()); + } + } + else if (!keyEvent.isAltKey() && keyEvent.isCtrlKey() && !keyEvent.isShiftKey()) + btn = ctrlKeyMap.get(keyEvent.getKeyCode()); + else if (!keyEvent.isAltKey() && !keyEvent.isCtrlKey() && !keyEvent.isShiftKey()) + btn = keyMap.get(keyEvent.getKeyCode()); + if (btn != null && !btn.isDisabled() && btn.isVisible()) { Events.sendEvent(btn, new Event(Events.ON_CLICK, btn)); } @@ -467,5 +534,9 @@ public class CWindowToolbar extends FToolbar implements EventListener btn.setVisible(visible); } } + + public void setWindowNo(int windowNo) { + this.windowNo = windowNo; + } } diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/CompositeADTab.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/CompositeADTab.java index 3a788580b4..badd82d88c 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/component/CompositeADTab.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/CompositeADTab.java @@ -64,7 +64,6 @@ public class CompositeADTab extends AbstractADTab } else { window.setPage(page); } - window.setCtrlKeys("#f1#f2#f3#f4#f5#f6#f7#f8#f9#f10#f11#f12"); return window; } diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridPanel.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridPanel.java index dbc076407f..e00a2423a7 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridPanel.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridPanel.java @@ -12,7 +12,6 @@ *****************************************************************************/ package org.adempiere.webui.component; - import java.util.HashMap; import java.util.List; import java.util.Map; @@ -21,22 +20,25 @@ import javax.swing.table.AbstractTableModel; import org.adempiere.webui.LayoutUtils; import org.adempiere.webui.editor.WEditor; +import org.adempiere.webui.util.SortComparator; import org.compiere.model.GridField; import org.compiere.model.GridTab; import org.compiere.model.GridTable; import org.compiere.model.MSysConfig; import org.compiere.util.DisplayType; +import org.compiere.util.Env; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.Events; import org.zkoss.zkex.zul.Borderlayout; import org.zkoss.zkex.zul.Center; import org.zkoss.zkex.zul.South; +import org.zkoss.zul.Column; import org.zkoss.zul.Paging; import org.zkoss.zul.event.ZulEvents; /** - * + * Grid view implemented using the Grid component. * @author Low Heng Sin * */ @@ -48,7 +50,7 @@ public class GridPanel extends Borderlayout implements EventListener private static final long serialVersionUID = 1L; - private Listbox listbox = null; + private Grid listbox = null; private int pageSize = 100; @@ -67,7 +69,7 @@ public class GridPanel extends Borderlayout implements EventListener private Paging paging; - private GridTabListItemRenderer renderer; + private GridTabRowRenderer renderer; private South south; @@ -78,17 +80,24 @@ public class GridPanel extends Borderlayout implements EventListener this(0); } + /** + * @param windowNo + */ public GridPanel(int windowNo) { this.windowNo = windowNo; - listbox = new Listbox(); + listbox = new Grid(); south = new South(); this.appendChild(south); //default paging size pageSize = MSysConfig.getIntValue(PAGE_SIZE_KEY, 100); } - + + /** + * + * @param gridTab + */ public void init(GridTab gridTab) { if (init) return; @@ -108,29 +117,45 @@ public class GridPanel extends Borderlayout implements EventListener this.init = true; } + /** + * + * @return boolean + */ public boolean isInit() { return init; } - public void activate(GridTab gridTab) { - if (isInit()) - refresh(gridTab); - else + /** + * call when tab is activated + * @param gridTab + */ + public void activate(GridTab gridTab) { + if (!isInit()) { init(gridTab); + } } + /** + * refresh after switching from form view + * @param gridTab + */ public void refresh(GridTab gridTab) { - this.gridTab = gridTab; - tableModel = gridTab.getTableModel(); - gridField = ((GridTable)tableModel).getFields(); - - updateModel(); - - updateListIndex(); + if (this.gridTab != gridTab) + { + init = false; + init(gridTab); + } + else + { + if (renderer != null) + renderer.stopEditing(false); + + listbox.setModel(listModel); + } } /** - * Update listbox index to sync with grid current row pointer changes + * Update current row from model */ public void updateListIndex() { int rowIndex = gridTab.isOpen() ? gridTab.getCurrentRow() : -1; @@ -139,27 +164,25 @@ public class GridPanel extends Borderlayout implements EventListener paging.setTotalSize(gridTab.getRowCount()); int pgIndex = rowIndex % pageSize; int pgNo = (rowIndex - pgIndex) / pageSize; + if (listModel.getPage() != pgNo) { listModel.setPage(pgNo); } - if (paging.getActivePage() != pgNo) + if (paging.getActivePage() != pgNo) { paging.setActivePage(pgNo); - if (listbox.getSelectedIndex() != pgIndex) { - renderer.stopEditing(false); - listModel.updateComponent(listbox.getSelectedIndex()); - listModel.updateComponent(pgIndex); - listbox.setSelectedIndex(pgIndex); - } + } + renderer.stopEditing(false); + listModel.updateComponent(pgIndex); } else { - if (listbox.getSelectedIndex() != rowIndex) { - renderer.stopEditing(false); - listModel.updateComponent(listbox.getSelectedIndex()); - listModel.updateComponent(rowIndex); - listbox.setSelectedIndex(rowIndex); - } + renderer.stopEditing(false); + listModel.updateComponent(rowIndex); } } + /** + * set paging size + * @param pageSize + */ public void setPageSize(int pageSize) { this.pageSize = pageSize; @@ -170,6 +193,10 @@ public class GridPanel extends Borderlayout implements EventListener this.getChildren().clear(); } + /** + * toggle visibility + * @param bool + */ public void showGrid(boolean bool) { if (bool) @@ -182,8 +209,11 @@ public class GridPanel extends Borderlayout implements EventListener { if (init) return; - ListHead header = new ListHead(); - header.setSizable(true); + Columns columns = new Columns(); + listbox.appendChild(columns); + columns.setSizable(true); + columns.setMenupopup("auto"); + columns.setColumnsgroup(false); Map colnames = new HashMap(); int index = 0; @@ -193,9 +223,10 @@ public class GridPanel extends Borderlayout implements EventListener { colnames.put(index, gridField[i].getHeader()); index++; - ListHeader colHeader = new ListHeader(); - colHeader.setSort("auto"); - colHeader.setLabel(gridField[i].getHeader()); + org.zkoss.zul.Column column = new Column(); + column.setSortAscending(new SortComparator(i, true, Env.getLanguage(Env.getCtx()))); + column.setSortDescending(new SortComparator(i, false, Env.getLanguage(Env.getCtx()))); + column.setLabel(gridField[i].getHeader()); int l = DisplayType.isNumeric(gridField[i].getDisplayType()) ? 100 : gridField[i].getDisplayLength() * 9; if (gridField[i].getHeader().length() * 9 > l) @@ -204,11 +235,10 @@ public class GridPanel extends Borderlayout implements EventListener l = MAX_COLUMN_WIDTH; else if ( l < MIN_COLUMN_WIDTH) l = MIN_COLUMN_WIDTH; - colHeader.setWidth(Integer.toString(l) + "px"); - header.appendChild(colHeader); + column.setWidth(Integer.toString(l) + "px"); + columns.appendChild(column); } } - listbox.appendChild(header); } private void render() @@ -216,9 +246,8 @@ public class GridPanel extends Borderlayout implements EventListener LayoutUtils.addSclass("adtab-grid-panel", this); listbox.setVflex(true); - listbox.addEventListener(Events.ON_SELECT, this); - - LayoutUtils.addSclass("adtab-grid", listbox); + listbox.setFixedLayout(true); + listbox.addEventListener(Events.ON_CLICK, this); updateModel(); @@ -234,12 +263,13 @@ public class GridPanel extends Borderlayout implements EventListener paging.setDetailed(true); south.appendChild(paging); paging.addEventListener(ZulEvents.ON_PAGING, this); - this.getParent().invalidate(); + renderer.setPaging(paging); } else { south.setVisible(false); } + } private void updateModel() { @@ -247,12 +277,18 @@ public class GridPanel extends Borderlayout implements EventListener listModel.setPageSize(pageSize); if (renderer != null) renderer.stopEditing(false); - renderer = new GridTabListItemRenderer(gridTab, windowNo); - listbox.setItemRenderer(renderer); - listbox.setModel(listModel); + renderer = new GridTabRowRenderer(gridTab, windowNo); + + listbox.setRowRenderer(renderer); + listbox.setModel(listModel); } + /** + * deactivate panel + */ public void deactivate() { + if (renderer != null) + renderer.stopEditing(false); } public void onEvent(Event event) throws Exception @@ -261,34 +297,33 @@ public class GridPanel extends Borderlayout implements EventListener return; else if (event.getTarget() == listbox) { - int index = listbox.getSelectedIndex(); - onSelectedRowChange(index); + Object data = event.getData(); + if (data != null && data instanceof org.zkoss.zul.Row) + { + int index = listbox.getRows().getChildren().indexOf(data); + onSelectedRowChange(index); + } } else if (event.getTarget() == paging) { int pgNo = paging.getActivePage(); if (pgNo != listModel.getPage()) { - listbox.clearSelection(); listModel.setPage(pgNo); - listbox.setSelectedIndex(0); onSelectedRowChange(0); } } } private void onSelectedRowChange(int index) { - if (updateModelIndex()) { + if (updateModelIndex(index)) { listModel.updateComponent(index); - listbox.setSelectedIndex(index); } else if (!renderer.isInitialize()) { listModel.updateComponent(index); - listbox.setSelectedIndex(index); } } - private boolean updateModelIndex() { - int rowIndex = listbox.getSelectedIndex(); + private boolean updateModelIndex(int rowIndex) { if (pageSize > 0) { int start = listModel.getPage() * listModel.getPageSize(); rowIndex = start + rowIndex; @@ -302,10 +337,17 @@ public class GridPanel extends Borderlayout implements EventListener return false; } - public Listbox getListbox() { + /** + * @return Grid + */ + public Grid getListbox() { return listbox; } - + + /** + * Validate display properties of fields of current row + * @param col + */ public void dynamicDisplay(int col) { if (!gridTab.isOpen()) { diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridTabListItemRenderer.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridTabListItemRenderer.java index d47e678b42..ab8fbea987 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridTabListItemRenderer.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridTabListItemRenderer.java @@ -43,19 +43,22 @@ import org.zkoss.zul.Listcell; import org.zkoss.zul.Listitem; import org.zkoss.zul.ListitemRenderer; import org.zkoss.zul.ListitemRendererExt; +import org.zkoss.zul.Paging; +import org.zkoss.zul.RendererCtrl; /** * ListItem renderer for GridTab list box. * @author hengsin * */ -public class GridTabListItemRenderer implements ListitemRenderer, ListitemRendererExt { +public class GridTabListItemRenderer implements ListitemRenderer, ListitemRendererExt, RendererCtrl { private static final int MAX_TEXT_LENGTH = 60; private GridTab gridTab; private int windowNo; private GridTabDataBinder dataBinder; private Map editors = new HashMap(); + private Paging paging; /** * @@ -90,6 +93,9 @@ public class GridTabListItemRenderer implements ListitemRenderer, ListitemRender editors.put(gridField[i], WebEditorFactory.getEditor(gridField[i], true)); int rowIndex = listitem.getIndex(); + if (paging != null && paging.getPageSize() > 0) { + rowIndex = (paging.getActivePage() * paging.getPageSize()) + rowIndex; + } Listcell cell = null; if (rowIndex == gridTab.getCurrentRow() && gridField[i].isEditable(true)) { cell = getEditorCell(gridField[i], values[i], i); @@ -232,6 +238,8 @@ public class GridTabListItemRenderer implements ListitemRenderer, ListitemRender return item; } + private Map> lookupCache = null; + private String getDisplayText(Object value, int columnIndex) { if (value == null) @@ -244,9 +252,36 @@ public class GridTabListItemRenderer implements ListitemRenderer, ListitemRender } else if (gridField[columnIndex].isLookup()) { + if (value == null) return ""; + + if (lookupCache != null) + { + Map cache = lookupCache.get(columnIndex); + if (cache != null && cache.size() >0) + { + String text = cache.get(value); + if (text != null) + { + return text; + } + } + } NamePair namepair = gridField[columnIndex].getLookup().get(value); if (namepair != null) - return namepair.getName(); + { + String text = namepair.getName(); + if (lookupCache != null) + { + Map cache = lookupCache.get(columnIndex); + if (cache == null) + { + cache = new HashMap(); + lookupCache.put(columnIndex, cache); + } + cache.put(value, text); + } + return text; + } else return ""; } @@ -310,4 +345,32 @@ public class GridTabListItemRenderer implements ListitemRenderer, ListitemRender return editorList; } + + /** + * @param paging + */ + public void setPaging(Paging paging) { + this.paging = paging; + } + + /** + * @see RendererCtrl#doCatch(Throwable) + */ + public void doCatch(Throwable ex) throws Throwable { + lookupCache = null; + } + + /** + * @see RendererCtrl#doFinally() + */ + public void doFinally() { + lookupCache = null; + } + + /** + * @see RendererCtrl#doTry() + */ + public void doTry() { + lookupCache = new HashMap>(); + } } diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridTabRowRenderer.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridTabRowRenderer.java new file mode 100644 index 0000000000..368afddbae --- /dev/null +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridTabRowRenderer.java @@ -0,0 +1,410 @@ +/****************************************************************************** + * Copyright (C) 2008 Low Heng Sin * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + *****************************************************************************/ +package org.adempiere.webui.component; + +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.adempiere.webui.editor.WButtonEditor; +import org.adempiere.webui.editor.WEditor; +import org.adempiere.webui.editor.WEditorPopupMenu; +import org.adempiere.webui.editor.WebEditorFactory; +import org.adempiere.webui.event.ContextMenuListener; +import org.adempiere.webui.panel.AbstractADWindowPanel; +import org.adempiere.webui.session.SessionManager; +import org.adempiere.webui.util.GridTabDataBinder; +import org.adempiere.webui.window.ADWindow; +import org.compiere.model.GridField; +import org.compiere.model.GridTab; +import org.compiere.util.DisplayType; +import org.compiere.util.NamePair; +import org.zkoss.zk.ui.Component; +import org.zkoss.zk.ui.HtmlBasedComponent; +import org.zkoss.zk.ui.event.Event; +import org.zkoss.zk.ui.event.EventListener; +import org.zkoss.zk.ui.event.Events; +import org.zkoss.zul.Div; +import org.zkoss.zul.Grid; +import org.zkoss.zul.Paging; +import org.zkoss.zul.RendererCtrl; +import org.zkoss.zul.Row; +import org.zkoss.zul.RowRenderer; +import org.zkoss.zul.RowRendererExt; + +/** + * Row renderer for GridTab grid. + * @author hengsin + * + */ +public class GridTabRowRenderer implements RowRenderer, RowRendererExt, RendererCtrl { + + private static final int MAX_TEXT_LENGTH = 60; + private GridTab gridTab; + private int windowNo; + private GridTabDataBinder dataBinder; + private Map editors = new HashMap(); + private Paging paging; + + private Map> lookupCache = null; + private RowListener rowListener; + + /** + * + * @param gridTab + * @param windowNo + */ + public GridTabRowRenderer(GridTab gridTab, int windowNo) { + this.gridTab = gridTab; + this.windowNo = windowNo; + this.dataBinder = new GridTabDataBinder(gridTab); + } + + private WEditor getEditorCell(GridField gridField, Object object, int i) { + WEditor editor = editors.get(gridField); + if (editor != null) { + if (editor instanceof WButtonEditor) + { + Object window = SessionManager.getAppDesktop().findWindow(windowNo); + if (window != null && window instanceof ADWindow) + { + AbstractADWindowPanel windowPanel = ((ADWindow)window).getADWindowPanel(); + ((WButtonEditor)editor).addActionListener(windowPanel); + } + } + else + { + editor.addValueChangeListener(dataBinder); + } + gridField.removePropertyChangeListener(editor); + gridField.addPropertyChangeListener(editor); + editor.setValue(gridField.getValue()); + + //streach component to fill grid cell + if (editor.getComponent() instanceof Textbox) + ((HtmlBasedComponent)editor.getComponent()).setWidth("98%"); + else + editor.fillHorizontal(); + } + return editor; + } + + private int getColumnIndex(GridField field) { + GridField[] fields = gridTab.getFields(); + for(int i = 0; i < fields.length; i++) { + if (fields[i] == field) + return i; + } + return 0; + } + + private Component createReadonlyCheckbox(Object value) { + Checkbox checkBox = new Checkbox(); + if (value != null && "true".equalsIgnoreCase(value.toString())) + checkBox.setChecked(true); + else + checkBox.setChecked(false); + checkBox.setDisabled(true); + return checkBox; + } + + private String getDisplayText(Object value, GridField gridField) + { + if (value == null) + return ""; + + if (gridField.isEncryptedField()) + { + return "********"; + } + else if (gridField.isLookup()) + { + if (value == null) return ""; + + if (lookupCache != null) + { + Map cache = lookupCache.get(gridField.getColumnName()); + if (cache != null && cache.size() >0) + { + String text = cache.get(value); + if (text != null) + { + return text; + } + } + } + NamePair namepair = gridField.getLookup().get(value); + if (namepair != null) + { + String text = namepair.getName(); + if (lookupCache != null) + { + Map cache = lookupCache.get(gridField.getColumnName()); + if (cache == null) + { + cache = new HashMap(); + lookupCache.put(gridField.getColumnName(), cache); + } + cache.put(value, text); + } + return text; + } + else + return ""; + } + else if (gridTab.getTableModel().getColumnClass(getColumnIndex(gridField)).equals(Timestamp.class)) + { + SimpleDateFormat dateFormat = DisplayType.getDateFormat(DisplayType.Date); + return dateFormat.format((Timestamp)value); + } + else if (DisplayType.isNumeric(gridField.getDisplayType())) + { + return DisplayType.getNumberFormat(gridField.getDisplayType()).format(value); + } + else if (DisplayType.Button == gridField.getDisplayType()) + { + return ""; + } + else if (DisplayType.Image == gridField.getDisplayType()) + { + if (value == null || (Integer)value <= 0) + return ""; + else + return "..."; + } + else + return value.toString(); + } + + private Component getDisplayComponent(Object value, GridField gridField) { + Component component; + if (gridField.getDisplayType() == DisplayType.YesNo) { + component = createReadonlyCheckbox(value); + } else { + String text = getDisplayText(value, gridField); + String display = text; + if (text != null && text.length() > MAX_TEXT_LENGTH) + display = text.substring(0, MAX_TEXT_LENGTH - 3) + "..."; + Label label = new Label(display); + if (text != null && text.length() > MAX_TEXT_LENGTH) + label.setTooltiptext(text); + component = label; + } + return component; + } + + /** + * Is renderer initialize + * @return boolean + */ + public boolean isInitialize() { + return !editors.isEmpty(); + } + + /** + * + * @return active editor list + */ + public List getEditors() { + List editorList = new ArrayList(); + if (!editors.isEmpty()) + editorList.addAll(editors.values()); + + return editorList; + } + + /** + * @param paging + */ + public void setPaging(Paging paging) { + this.paging = paging; + } + + /** + * Detach all editor and optionally set the current value of the editor as cell label. + * @param updateCellLabel + */ + public void stopEditing(boolean updateCellLabel) { + Row row = null; + for (Entry entry : editors.entrySet()) { + if (entry.getValue().getComponent().getParent() != null) { + Component child = entry.getValue().getComponent(); + Div div = null; + while (div == null && child != null) { + Component parent = child.getParent(); + if (parent instanceof Div && parent.getParent() instanceof Row) + div = (Div)parent; + else + child = parent; + } + Component component = div.getFirstChild(); + if (updateCellLabel) { + if (component instanceof Label) { + Label label = (Label)component; + label.setValue(getDisplayText(entry.getValue().getValue(), entry.getValue().getGridField())); + } else if (component instanceof Checkbox) { + Checkbox checkBox = (Checkbox)component; + Object value = entry.getValue().getValue(); + if (value != null && "true".equalsIgnoreCase(value.toString())) + checkBox.setChecked(true); + else + checkBox.setChecked(false); + } + } + component.setVisible(true); + if (row == null) + row = ((Row)div.getParent()); + + entry.getValue().getComponent().detach(); + entry.getKey().removePropertyChangeListener(entry.getValue()); + entry.getValue().removeValuechangeListener(dataBinder); + } + } + if (row != null) + row.setStyle(null); + } + + /** + * @param row + * @param data + * @see RowRenderer#render(Row, Object) + */ + public void render(Row row, Object data) throws Exception { + //don't render if not visible + for(Component c = row.getParent(); c != null; c = c.getParent()) { + if (!c.isVisible()) + return; + } + if (rowListener == null) + rowListener = new RowListener((Grid)row.getParent().getParent()); + + Object[] values = (Object[])data; + int columnCount = gridTab.getTableModel().getColumnCount(); + GridField[] gridField = gridTab.getFields(); + Grid grid = (Grid) row.getParent().getParent(); + org.zkoss.zul.Columns columns = grid.getColumns(); + + int rowIndex = row.getParent().getChildren().indexOf(row); + if (paging != null && paging.getPageSize() > 0) { + rowIndex = (paging.getActivePage() * paging.getPageSize()) + rowIndex; + } + + int colIndex = -1; + for (int i = 0; i < columnCount; i++) { + if (!gridField[i].isDisplayed()) { + continue; + } + colIndex ++; + if (editors.get(gridField[i]) == null) + editors.put(gridField[i], WebEditorFactory.getEditor(gridField[i], true)); + + Div div = new Div(); + String divStyle = "border: none; width: 100%; "; + org.zkoss.zul.Column column = (org.zkoss.zul.Column) columns.getChildren().get(colIndex); + if (column.isVisible()) { + Component component = getDisplayComponent(values[i], gridField[i]); + div.appendChild(component); + if (rowIndex == gridTab.getCurrentRow() && gridField[i].isEditable(true)) { + WEditor editor = getEditorCell(gridField[i], values[i], i); + div.appendChild(editor.getComponent()); + + WEditorPopupMenu popupMenu = editor.getPopupMenu(); + + if (popupMenu != null) + { + popupMenu.addMenuListener((ContextMenuListener)editor); + div.appendChild(popupMenu); + } + component.setVisible(false); + } + + if (DisplayType.YesNo == gridField[i].getDisplayType() || DisplayType.Image == gridField[i].getDisplayType()) { + divStyle += "text-align:center; "; + } + else if (DisplayType.isNumeric(gridField[i].getDisplayType())) { + divStyle += "text-align:right; "; + } + } + div.setStyle(divStyle); + row.appendChild(div); + } + + if (rowIndex == gridTab.getCurrentRow()) { + row.setStyle("border-top: 1px solid #6f97d2; border-bottom: 1px solid #6f97d2"); + } + row.addEventListener(Events.ON_CLICK, rowListener); + } + + /** + * @see ListitemRendererExt#getControls() + */ + public int getControls() { + return DETACH_ON_RENDER; + } + + /** + * @see RowRendererExt#newCell(Row) + */ + public Component newCell(Row row) { + return null; + } + + /** + * @see RowRendererExt#newRow(Grid) + */ + public Row newRow(Grid grid) { + return null; + } + + /** + * @see RendererCtrl#doCatch(Throwable) + */ + public void doCatch(Throwable ex) throws Throwable { + lookupCache = null; + } + + /** + * @see RendererCtrl#doFinally() + */ + public void doFinally() { + lookupCache = null; + } + + /** + * @see RendererCtrl#doTry() + */ + public void doTry() { + lookupCache = new HashMap>(); + } + + class RowListener implements EventListener { + + private Grid _grid; + + public RowListener(Grid grid) { + _grid = grid; + } + + public void onEvent(Event event) throws Exception { + if (Events.ON_CLICK.equals(event.getName())) { + Event evt = new Event(Events.ON_CLICK, _grid, event.getTarget()); + Events.sendEvent(_grid, evt); + } + } + + } +} diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridTableListModel.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridTableListModel.java index 5252560100..44d6c66f04 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridTableListModel.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/GridTableListModel.java @@ -14,8 +14,10 @@ package org.adempiere.webui.component; import java.util.Comparator; -import org.compiere.model.DataStatusEvent; -import org.compiere.model.DataStatusListener; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; + +import org.adempiere.webui.util.SortComparator; import org.compiere.model.GridField; import org.compiere.model.GridTable; import org.zkoss.zk.ui.Executions; @@ -30,10 +32,14 @@ import org.zkoss.zul.event.ListDataEvent; * @author Low Heng Sin * */ -public class GridTableListModel extends AbstractListModel implements DataStatusListener, ListModelExt { +public class GridTableListModel extends AbstractListModel implements TableModelListener, ListModelExt { + private static final long serialVersionUID = 1L; + private GridTable tableModel; + @SuppressWarnings("unused") private GridField[] gridField; + @SuppressWarnings("unused") private int windowNo; private int pageSize = -1; @@ -48,7 +54,7 @@ public class GridTableListModel extends AbstractListModel implements DataStatusL this.tableModel = tableModel; this.windowNo = windowNo; gridField = tableModel.getFields(); - tableModel.addDataStatusListener(this); + tableModel.addTableModelListener(this); } /** @@ -131,17 +137,6 @@ public class GridTableListModel extends AbstractListModel implements DataStatusL } } - /** - * @param e - * @see DataStatusListener#dataStatusChanged(DataStatusEvent) - */ - public void dataStatusChanged(DataStatusEvent e) { - if (Executions.getCurrent() != null) { - fireEvent(ListDataEvent.CONTENTS_CHANGED, -1, -1); - } - - } - /** * Request components that attached to this model to re-render a row. * @param row @@ -167,11 +162,34 @@ public class GridTableListModel extends AbstractListModel implements DataStatusL * @param ascending * @see ListModelExt#sort(Comparator, boolean) */ + @SuppressWarnings("unchecked") public void sort(Comparator cmpr, boolean ascending) { //use default zk comparator - ListitemComparator lic = (ListitemComparator) cmpr; - tableModel.sort(lic.getListheader().getColumnIndex(), ascending); + if (cmpr instanceof ListitemComparator) { + ListitemComparator lic = (ListitemComparator) cmpr; + tableModel.sort(lic.getListheader().getColumnIndex(), ascending); + } else if (cmpr instanceof SortComparator) { + SortComparator sc = (SortComparator)cmpr; + tableModel.sort(sc.getColumnIndex(), ascending); + } fireEvent(ListDataEvent.CONTENTS_CHANGED, -1, -1); } + /** + * @param e + * @see TableModelListener#tableChanged(TableModelEvent) + */ + public void tableChanged(TableModelEvent e) { + if (Executions.getCurrent() != null) { + if (e.getLastRow() == Integer.MAX_VALUE) + { + fireEvent(ListDataEvent.CONTENTS_CHANGED, -1, -1); + } + else + { + fireEvent(ListDataEvent.CONTENTS_CHANGED, e.getFirstRow(), e.getLastRow()); + } + } + } + } diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/ListPanel.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/ListPanel.java new file mode 100644 index 0000000000..a07b4daf82 --- /dev/null +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/ListPanel.java @@ -0,0 +1,429 @@ +/****************************************************************************** + * Copyright (C) 2008 Low Heng Sin * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + *****************************************************************************/ +package org.adempiere.webui.component; + + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.table.AbstractTableModel; + +import org.adempiere.webui.LayoutUtils; +import org.adempiere.webui.editor.WEditor; +import org.compiere.model.GridField; +import org.compiere.model.GridTab; +import org.compiere.model.GridTable; +import org.compiere.model.MSysConfig; +import org.compiere.util.DisplayType; +import org.zkoss.zk.ui.event.Event; +import org.zkoss.zk.ui.event.EventListener; +import org.zkoss.zk.ui.event.Events; +import org.zkoss.zkex.zul.Borderlayout; +import org.zkoss.zkex.zul.Center; +import org.zkoss.zkex.zul.South; +import org.zkoss.zul.Paging; +import org.zkoss.zul.event.ZulEvents; + +/** + * Grid view implemented using the Listbox component + * @author Low Heng Sin + * + */ +public class ListPanel extends Borderlayout implements EventListener +{ + private static final int MIN_COLUMN_WIDTH = 100; + + private static final int MAX_COLUMN_WIDTH = 300; + + private static final long serialVersionUID = 1L; + + private Listbox listbox = null; + + private int pageSize = 100; + + private GridField[] gridField; + private AbstractTableModel tableModel; + + private int numColumns = 5; + + private int windowNo; + + private GridTab gridTab; + + private boolean init; + + private GridTableListModel listModel; + + private Paging paging; + + private GridTabListItemRenderer renderer; + + private South south; + + public static final String PAGE_SIZE_KEY = "ZK_PAGING_SIZE"; + + public ListPanel() + { + this(0); + } + + /** + * @param windowNo + */ + public ListPanel(int windowNo) + { + this.windowNo = windowNo; + listbox = new Listbox(); + south = new South(); + this.appendChild(south); + + //default paging size + pageSize = MSysConfig.getIntValue(PAGE_SIZE_KEY, 100); + } + + /** + * + * @param gridTab + */ + public void init(GridTab gridTab) + { + if (init) return; + + this.gridTab = gridTab; + tableModel = gridTab.getTableModel(); + + numColumns = tableModel.getColumnCount(); + + gridField = ((GridTable)tableModel).getFields(); + + setupColumns(); + render(); + + updateListIndex(true); + + this.init = true; + } + + /** + * + * @return boolean + */ + public boolean isInit() { + return init; + } + + /** + * + * @param gridTab + */ + public void activate(GridTab gridTab) { + if (isInit()) + { + if (this.gridTab != gridTab) + { + init = false; + init(gridTab); + } + else + { + if (renderer != null) + renderer.stopEditing(false); + + int oldSelected = listbox.getSelectedIndex(); + updateListIndex(false); + if (listbox.getSelectedIndex() == oldSelected && oldSelected >= 0) + listModel.updateComponent(oldSelected); + } + } + else + init(gridTab); + } + + /** + * + * @param gridTab + */ + public void refresh(GridTab gridTab) { + if (this.gridTab != gridTab) + { + init = false; + init(gridTab); + } + else + { + renderer.stopEditing(false); + listbox.setModel(listModel); + updateListIndex(true); + } + } + + /** + * Update listbox selection to sync with grid current row pointer changes + */ + public void updateListIndex() { + updateListIndex(false); + } + + /** + * Update listbox selection to sync with grid current row pointer changes + * @param updateSelectionOnly if true, doesn't attempt to refresh current row from model + */ + public void updateListIndex(boolean updateSelectionOnly) { + int rowIndex = gridTab.isOpen() ? gridTab.getCurrentRow() : -1; + if (pageSize > 0) { + if (paging.getTotalSize() != gridTab.getRowCount()) + paging.setTotalSize(gridTab.getRowCount()); + int pgIndex = rowIndex % pageSize; + int pgNo = (rowIndex - pgIndex) / pageSize; + + boolean pgChange = false; + if (listModel.getPage() != pgNo) { + listModel.setPage(pgNo); + pgChange = true; + } + if (paging.getActivePage() != pgNo) { + paging.setActivePage(pgNo); + } + if (listbox.getSelectedIndex() != pgIndex) { + if (!updateSelectionOnly) { + renderer.stopEditing(false); + if (!pgChange) { + listModel.updateComponent(listbox.getSelectedIndex()); + } + listModel.updateComponent(pgIndex); + } + listbox.setSelectedIndex(pgIndex); + } + } else { + if (listbox.getSelectedIndex() != rowIndex) { + if (!updateSelectionOnly) { + renderer.stopEditing(false); + listModel.updateComponent(listbox.getSelectedIndex()); + listModel.updateComponent(rowIndex); + } + listbox.setSelectedIndex(rowIndex); + } + } + } + + /** + * Set paging size + * @param pageSize + */ + public void setPageSize(int pageSize) + { + this.pageSize = pageSize; + } + + public void clear() + { + this.getChildren().clear(); + } + + /** + * + * @param bool + */ + public void showGrid(boolean bool) + { + if (bool) + this.setVisible(true); + else + this.setVisible(false); + } + + private void setupColumns() + { + if (init) return; + + ListHead header = new ListHead(); + header.setSizable(true); + + Map colnames = new HashMap(); + int index = 0; + for (int i = 0; i < numColumns; i++) + { + if (gridField[i].isDisplayed()) + { + colnames.put(index, gridField[i].getHeader()); + index++; + ListHeader colHeader = new ListHeader(); + colHeader.setSort("auto"); + colHeader.setLabel(gridField[i].getHeader()); + int l = DisplayType.isNumeric(gridField[i].getDisplayType()) + ? 100 : gridField[i].getDisplayLength() * 9; + if (gridField[i].getHeader().length() * 9 > l) + l = gridField[i].getHeader().length() * 9; + if (l > MAX_COLUMN_WIDTH) + l = MAX_COLUMN_WIDTH; + else if ( l < MIN_COLUMN_WIDTH) + l = MIN_COLUMN_WIDTH; + colHeader.setWidth(Integer.toString(l) + "px"); + header.appendChild(colHeader); + } + } + listbox.appendChild(header); + } + + private void render() + { + LayoutUtils.addSclass("adtab-grid-panel", this); + + listbox.setVflex(true); + listbox.setFixedLayout(true); + listbox.addEventListener(Events.ON_SELECT, this); + + LayoutUtils.addSclass("adtab-grid", listbox); + + updateModel(); + + Center center = new Center(); + center.appendChild(listbox); + this.appendChild(center); + + if (pageSize > 0) + { + paging = new Paging(); + paging.setPageSize(pageSize); + paging.setTotalSize(tableModel.getRowCount()); + paging.setDetailed(true); + south.appendChild(paging); + paging.addEventListener(ZulEvents.ON_PAGING, this); + renderer.setPaging(paging); + this.getParent().invalidate(); + } + else + { + south.setVisible(false); + } + + } + + private void updateModel() { + listModel = new GridTableListModel((GridTable)tableModel, windowNo); + listModel.setPageSize(pageSize); + if (renderer != null) + renderer.stopEditing(false); + renderer = new GridTabListItemRenderer(gridTab, windowNo); + + listbox.setItemRenderer(renderer); + listbox.setModel(listModel); + } + + /** + * deactive panel + */ + public void deactivate() { + if (renderer != null) + renderer.stopEditing(false); + } + + public void onEvent(Event event) throws Exception + { + if (event == null) + return; + else if (event.getTarget() == listbox) + { + int index = listbox.getSelectedIndex(); + onSelectedRowChange(index); + } + else if (event.getTarget() == paging) + { + int pgNo = paging.getActivePage(); + if (pgNo != listModel.getPage()) + { + listbox.clearSelection(); + listModel.setPage(pgNo); + listbox.setSelectedIndex(0); + onSelectedRowChange(0); + } + } + } + + private void onSelectedRowChange(int index) { + if (updateModelIndex()) { + listModel.updateComponent(index); + listbox.setSelectedIndex(index); + } else if (!renderer.isInitialize()) { + listModel.updateComponent(index); + listbox.setSelectedIndex(index); + } + } + + private boolean updateModelIndex() { + int rowIndex = listbox.getSelectedIndex(); + if (pageSize > 0) { + int start = listModel.getPage() * listModel.getPageSize(); + rowIndex = start + rowIndex; + } + + if (gridTab.getCurrentRow() != rowIndex) { + renderer.stopEditing(true); + gridTab.navigate(rowIndex); + return true; + } + return false; + } + + /** + * + * @return Listbox + */ + public Listbox getListbox() { + return listbox; + } + + /** + * validate the display properties of fields of current row + * @param col + */ + public void dynamicDisplay(int col) { + if (!gridTab.isOpen()) + { + return; + } + + // Selective + if (col > 0) + return; + + boolean noData = gridTab.getRowCount() == 0; + List list = renderer.getEditors(); + for (WEditor comp : list) + { + GridField mField = comp.getGridField(); + if (mField != null && mField.getIncluded_Tab_ID() <= 0) + { + if (noData) + { + comp.setReadWrite(false); + } + else + { + comp.dynamicDisplay(); + boolean rw = mField.isEditable(true); // r/w - check Context + comp.setReadWrite(rw); + } + } + } // all components + } + + /** + * + * @param windowNo + */ + public void setWindowNo(int windowNo) { + this.windowNo = windowNo; + } +} diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WButtonEditor.java b/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WButtonEditor.java index eb0343c9cc..4578c32979 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WButtonEditor.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WButtonEditor.java @@ -252,7 +252,8 @@ public class WButtonEditor extends WEditor public void addActionListener(ActionListener actionListener) { - actionListeners.add(actionListener); + if (!actionListeners.contains(actionListener)) + actionListeners.add(actionListener); } @Override diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WEditor.java b/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WEditor.java index 46897f39cd..4e27ea8c8e 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WEditor.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WEditor.java @@ -294,7 +294,8 @@ public abstract class WEditor implements EventListener, PropertyChangeListener return; } - listeners.add(listener); + if (!listeners.contains(listener)) + listeners.add(listener); } public boolean removeValuechangeListener(ValueChangeListener listener) diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/panel/ADTabpanel.java b/zkwebui/WEB-INF/src/org/adempiere/webui/panel/ADTabpanel.java index ce4e7ebb78..3a1da7fad2 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/panel/ADTabpanel.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/panel/ADTabpanel.java @@ -168,6 +168,13 @@ DataStatusListener, IADTabpanel } + /** + * + * @param winPanel + * @param windowNo + * @param gridTab + * @param gridWindow + */ public void init(AbstractADWindowPanel winPanel, int windowNo, GridTab gridTab, GridWindow gridWindow) { @@ -218,6 +225,9 @@ DataStatusListener, IADTabpanel listPanel.setWindowNo(windowNo); } + /** + * Create UI components if not already created + */ public void createUI() { if (uiCreated) return; @@ -489,6 +499,10 @@ DataStatusListener, IADTabpanel return new Space(); } + /** + * Validate display properties of fields of current row + * @param col + */ public void dynamicDisplay (int col) { if (!gridTab.isOpen()) @@ -595,11 +609,17 @@ DataStatusListener, IADTabpanel logger.config(gridTab.toString() + " - fini - " + (col<=0 ? "complete" : "seletive")); } // dynamicDisplay + /** + * @return String + */ public String getDisplayLogic() { return gridTab.getDisplayLogic(); } + /** + * @return String + */ public String getTitle() { return gridTab.getName(); @@ -621,36 +641,63 @@ DataStatusListener, IADTabpanel return gridTab.getTabLevel(); } + /** + * Is panel need refresh + * @return boolean + */ public boolean isCurrent() { return gridTab != null ? gridTab.isCurrent() : false; } + /** + * + * @return windowNo + */ public int getWindowNo() { return windowNo; } + /** + * Retrieve from db + */ public void query() { gridTab.query(false); } + /** + * Retrieve from db + * @param onlyCurrentRows + * @param onlyCurrentDays + * @param maxRows + */ public void query (boolean onlyCurrentRows, int onlyCurrentDays, int maxRows) { gridTab.query(onlyCurrentRows, onlyCurrentDays, maxRows); } + /** + * @return GridTab + */ public GridTab getGridTab() { return gridTab; } + /** + * Refresh current row + */ public void refresh() { gridTab.dataRefresh(); } + /** + * Activate/deactivate panel + * @param activate + */ public void activate(boolean activate) { active = activate; @@ -693,6 +740,10 @@ DataStatusListener, IADTabpanel } + /** + * @param event + * @see EventListener#onEvent(Event) + */ public void onEvent(Event event) { if (event.getTarget() instanceof Listbox) @@ -735,6 +786,10 @@ DataStatusListener, IADTabpanel gridTab.navigate(row); } + /** + * @param e + * @see DataStatusListener#dataStatusChanged(DataStatusEvent) + */ public void dataStatusChanged(DataStatusEvent e) { //ignore background event @@ -863,6 +918,9 @@ DataStatusListener, IADTabpanel } } + /** + * Toggle between form and grid view + */ public void switchRowPresentation() { if (formComponent.isVisible()) { formComponent.setVisible(false); @@ -871,7 +929,7 @@ DataStatusListener, IADTabpanel } listPanel.setVisible(!formComponent.isVisible()); if (listPanel.isVisible()) { - listPanel.activate(gridTab); + listPanel.refresh(gridTab); } } diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/panel/ADWindowPanel.java b/zkwebui/WEB-INF/src/org/adempiere/webui/panel/ADWindowPanel.java index 3ae22bab68..1b0406c69c 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/panel/ADWindowPanel.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/panel/ADWindowPanel.java @@ -30,6 +30,7 @@ import org.adempiere.webui.session.SessionManager; import org.compiere.model.GridWindow; import org.compiere.model.MQuery; import org.compiere.util.CLogger; +import org.zkforge.keylistener.Keylistener; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.HtmlBasedComponent; import org.zkoss.zk.ui.event.Events; @@ -39,7 +40,6 @@ import org.zkoss.zkex.zul.North; import org.zkoss.zkex.zul.South; import org.zkoss.zkex.zul.West; import org.zkoss.zul.Tab; -import org.zkoss.zul.Window; /** * @@ -99,7 +99,8 @@ public class ADWindowPanel extends AbstractADWindowPanel n.setCollapsible(false); n.setHeight("30px"); toolbar.setHeight("30px"); - toolbar.setParent(n); + toolbar.setParent(n); + toolbar.setWindowNo(getWindowNo()); } South s = new South(); @@ -130,9 +131,11 @@ public class ADWindowPanel extends AbstractADWindowPanel ((Tabpanel)parent).setOnCloseHandler(handler); } - if (!isEmbedded() && adTab.getComponent() instanceof Window) { - Window w = (Window) adTab.getComponent(); - w.addEventListener(Events.ON_CTRL_KEY, toolbar); + if (!isEmbedded()) { + Keylistener keyListener = new Keylistener(); + statusBar.appendChild(keyListener); + keyListener.setCtrlKeys("#f1#f2#f3#f4#f5#f6#f7#f8#f9#f10#f11#f12^f^i^n^s^x@#left@#right@#up@#down@#pgup@#pgdn@p^p@z@x"); + keyListener.addEventListener(Events.ON_CTRL_KEY, toolbar); } return layout; diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/util/SortComparator.java b/zkwebui/WEB-INF/src/org/adempiere/webui/util/SortComparator.java new file mode 100755 index 0000000000..eea67026eb --- /dev/null +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/util/SortComparator.java @@ -0,0 +1,146 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + * For the text or an alternative of this public license, you may reach us * + * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * + * or via info@compiere.org or http://www.compiere.org/license.html * + *****************************************************************************/ +package org.adempiere.webui.util; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.text.Collator; +import java.util.Comparator; + +import org.compiere.util.Language; +import org.compiere.util.NamePair; + +/** + * Default comparator, adapted from MSort + * @author hengsin + */ +public final class SortComparator implements Comparator, Serializable +{ + /** + * generated + */ + private static final long serialVersionUID = 1265701980018071753L; + + private int columnIndex; + + /** + * @param columnIndex + * @param ascending + * @param language + */ + public SortComparator (int columnIndex, boolean ascending, Language language) + { + // Create string collator for login language - teo_sarca, [ 1672820 ] + m_collator = Collator.getInstance(language.getLocale()); + + setSortAsc(ascending); + + this.columnIndex = columnIndex; + } // MSort + + /** Multiplier */ + private int m_multiplier = 1; // Asc by default + + /** String Collator */ + private Collator m_collator = null; + + /** + * Sort Ascending + * @param ascending if true sort ascending + */ + public void setSortAsc (boolean ascending) + { + if (ascending) + m_multiplier = 1; + else + m_multiplier = -1; + } // setSortAsc + + + /************************************************************************** + * Compare Data of two entities + * @param o1 object + * @param o2 object + * @return comparator + */ + public int compare (Object o1, Object o2) + { + // Get Objects to compare + Object cmp1 = o1; + if (cmp1 instanceof NamePair) + cmp1 = ((NamePair)cmp1).getName(); + + Object cmp2 = o2; + if (cmp2 instanceof NamePair) + cmp2 = ((NamePair)cmp2).getName(); + + // Comparing Null values + if (cmp1 == null) + { + if (cmp2 == null) + return 0; + return -1 * m_multiplier; + } + if (cmp2 == null) + return 1 * m_multiplier; + + /** + * compare different data types + */ + + // String + if (cmp1 instanceof String && cmp2 instanceof String) + { + return m_collator.compare(cmp1, cmp2) * m_multiplier; // teo_sarca [ 1672820 ] + } + // Date + else if (cmp1 instanceof Timestamp && cmp2 instanceof Timestamp) + { + Timestamp t = (Timestamp)cmp1; + return t.compareTo((Timestamp)cmp2) * m_multiplier; + } + // BigDecimal + else if (cmp1 instanceof BigDecimal && cmp2 instanceof BigDecimal) + { + BigDecimal d = (BigDecimal)cmp1; + return d.compareTo((BigDecimal)cmp2) * m_multiplier; + } + // Integer + else if (cmp1 instanceof Integer && cmp2 instanceof Integer) + { + Integer d = (Integer)cmp1; + return d.compareTo((Integer)cmp2) * m_multiplier; + } + // Double + else if (cmp1 instanceof Double && cmp2 instanceof Double) + { + Double d = (Double)cmp1; + return d.compareTo((Double)cmp2) * m_multiplier; + } + + // Convert to string value + String s = cmp1.toString(); + return m_collator.compare(s, cmp2.toString()) * m_multiplier; // teo_sarca [ 1672820 ] + } // compare + + + public int getColumnIndex() { + return columnIndex; + } + +} // SortComparator