From 421a92eb024966abe539f2fb646e1ed9cfd4a48c Mon Sep 17 00:00:00 2001 From: Heng Sin Low Date: Wed, 1 Oct 2008 22:45:11 +0000 Subject: [PATCH] * sync with branches/adempiere341 revision 6548 --- .../src/org/adempiere/webui/Desktop.java | 44 +- .../src/org/adempiere/webui/IDesktop.java | 6 + .../adempiere/webui/ZkContextProvider.java | 4 +- .../src/org/adempiere/webui/apps/AEnv.java | 6 +- .../webui/apps/form/WTreeMaintenance.java | 548 ++++++++++++++++++ .../org/adempiere/webui/apps/wf/WFEditor.java | 136 +++++ .../org/adempiere/webui/apps/wf/WFNode.java | 107 ++++ .../webui/apps/wf/WFNodeContainer.java | 212 +++++++ .../org/adempiere/webui/apps/wf/WFPanel.java | 246 ++++++++ .../webui/component/DatetimeBox.java | 128 ++++ .../adempiere/webui/component/EditorBox.java | 2 + .../webui/component/FilenameBox.java | 12 +- .../webui/component/Locationbox.java | 2 + .../adempiere/webui/component/NumberBox.java | 7 +- .../webui/component/PAttributebox.java | 4 +- .../adempiere/webui/component/Searchbox.java | 5 +- .../adempiere/webui/component/Searchbox2.java | 97 ---- .../webui/component/SimpleTreeModel.java | 8 + .../org/adempiere/webui/component/Urlbox.java | 3 +- .../adempiere/webui/editor/WDateEditor.java | 10 +- .../webui/editor/WDatetimeEditor.java | 189 ++++++ .../webui/editor/WebEditorFactory.java | 2 + .../src/org/adempiere/webui/panel/ADForm.java | 2 + .../org/adempiere/webui/panel/ADTabpanel.java | 9 +- .../webui/panel/AbstractADWindowPanel.java | 12 +- .../org/adempiere/webui/panel/MenuPanel.java | 2 +- .../src/org/adempiere/webui/util/OSTask.java | 206 +++++++ .../org/adempiere/webui/window/ADWindow.java | 14 +- .../adempiere/webui/window/FindWindow.java | 14 +- .../src/org/adempiere/webui/window/WTask.java | 193 ++++++ zkwebui/css/default.css.dsp | 12 +- 31 files changed, 2112 insertions(+), 130 deletions(-) create mode 100644 zkwebui/WEB-INF/src/org/adempiere/webui/apps/form/WTreeMaintenance.java create mode 100644 zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFEditor.java create mode 100644 zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFNode.java create mode 100644 zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFNodeContainer.java create mode 100644 zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFPanel.java create mode 100644 zkwebui/WEB-INF/src/org/adempiere/webui/component/DatetimeBox.java delete mode 100644 zkwebui/WEB-INF/src/org/adempiere/webui/component/Searchbox2.java create mode 100644 zkwebui/WEB-INF/src/org/adempiere/webui/editor/WDatetimeEditor.java create mode 100644 zkwebui/WEB-INF/src/org/adempiere/webui/util/OSTask.java create mode 100644 zkwebui/WEB-INF/src/org/adempiere/webui/window/WTask.java diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/Desktop.java b/zkwebui/WEB-INF/src/org/adempiere/webui/Desktop.java index 1c0221d567..2c7d3e3361 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/Desktop.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/Desktop.java @@ -28,6 +28,7 @@ import java.util.logging.Level; import org.adempiere.webui.apps.AEnv; import org.adempiere.webui.apps.ProcessDialog; import org.adempiere.webui.apps.graph.WPAPanel; +import org.adempiere.webui.apps.wf.WFPanel; import org.adempiere.webui.component.Button; import org.adempiere.webui.component.DesktopTabpanel; import org.adempiere.webui.component.Tabbox; @@ -44,9 +45,11 @@ import org.adempiere.webui.part.AbstractUIPart; import org.adempiere.webui.part.WindowContainer; import org.adempiere.webui.window.ADWindow; import org.adempiere.webui.window.InfoSchedule; +import org.adempiere.webui.window.WTask; import org.compiere.model.MMenu; import org.compiere.model.MQuery; import org.compiere.model.MRole; +import org.compiere.model.MTask; import org.compiere.model.MTree; import org.compiere.model.MTreeNode; import org.compiere.util.CLogger; @@ -728,6 +731,14 @@ public class Desktop extends AbstractUIPart implements MenuListener, Serializabl { openForm(menu.getAD_Form_ID()); } + else if(menu.getAction().equals(MMenu.ACTION_WorkFlow)) + { + openWorkflow(menu.getAD_Workflow_ID()); + } + else if(menu.getAction().equals(MMenu.ACTION_Task)) + { + openTask(menu.getAD_Task_ID()); + } else { throw new ApplicationException("Menu Action not yet implemented: " + menu.getAction()); @@ -736,6 +747,15 @@ public class Desktop extends AbstractUIPart implements MenuListener, Serializabl /** * + * @param taskId + */ + public void openTask(int taskId) { + MTask task = new MTask(Env.getCtx(), taskId, null); + new WTask(task.getName(), task); + } + + /** + * * @param processId * @param soTrx * @return ProcessDialog @@ -768,6 +788,19 @@ public class Desktop extends AbstractUIPart implements MenuListener, Serializabl return form; } + /** + * + * @param workflow_ID + */ + public void openWorkflow(int workflow_ID) { + WFPanel p = new WFPanel(); + p.load(workflow_ID); + + DesktopTabpanel tabPanel = new DesktopTabpanel(); + p.setParent(tabPanel); + windowContainer.addWindow(tabPanel, p.getWorkflow().getName(), true); + } + /** * * @param windowId @@ -777,10 +810,13 @@ public class Desktop extends AbstractUIPart implements MenuListener, Serializabl ADWindow adWindow = new ADWindow(Env.getCtx(), windowId); DesktopTabpanel tabPanel = new DesktopTabpanel(); - adWindow.createPart(tabPanel); - windowContainer.addWindow(tabPanel, adWindow.getTitle(), true); - - return adWindow; + if (adWindow.createPart(tabPanel) != null) { + windowContainer.addWindow(tabPanel, adWindow.getTitle(), true); + return adWindow; + } else { + //user cancel + return null; + } } /** diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/IDesktop.java b/zkwebui/WEB-INF/src/org/adempiere/webui/IDesktop.java index a58cc204b6..72b690137b 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/IDesktop.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/IDesktop.java @@ -103,4 +103,10 @@ public interface IDesktop { * @return ADWindow */ public ADWindow openWindow(int windowId); + + /** + * Open operating system task window + * @param task_ID + */ + public void openTask(int task_ID); } diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/ZkContextProvider.java b/zkwebui/WEB-INF/src/org/adempiere/webui/ZkContextProvider.java index 39cbe21099..c24241d31d 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/ZkContextProvider.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/ZkContextProvider.java @@ -29,8 +29,8 @@ import org.compiere.util.ContextProvider; */ public class ZkContextProvider implements ContextProvider { - private final ServerContextCallback callback = new ServerContextCallback(); - private final Properties context = (Properties) Enhancer.create(Properties.class, callback); + private final static ServerContextCallback callback = new ServerContextCallback(); + private final static Properties context = (Properties) Enhancer.create(Properties.class, callback); /** * Get server context proxy diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/apps/AEnv.java b/zkwebui/WEB-INF/src/org/adempiere/webui/apps/AEnv.java index fd568aa4c3..33c21e2175 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/apps/AEnv.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/apps/AEnv.java @@ -618,7 +618,11 @@ public final class AEnv if (zoomQuery == null || value != null) { zoomQuery = new MQuery(); // ColumnName might be changed in MTab.validateQuery - zoomQuery.addRestriction(lookup.getColumnName(), MQuery.EQUAL, value); + String column = lookup.getColumnName(); + //strip off table name, fully qualify name doesn't work when zoom into detail tab + if (column.indexOf(".") > 0) + column = column.substring(column.indexOf(".")+1); + zoomQuery.addRestriction(column, MQuery.EQUAL, value); zoomQuery.setRecordCount(1); // guess } int windowId = lookup.getZoom(zoomQuery); diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/apps/form/WTreeMaintenance.java b/zkwebui/WEB-INF/src/org/adempiere/webui/apps/form/WTreeMaintenance.java new file mode 100644 index 0000000000..68b1ba1ae4 --- /dev/null +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/apps/form/WTreeMaintenance.java @@ -0,0 +1,548 @@ +/****************************************************************************** + * 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.apps.form; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.logging.Level; + +import org.adempiere.webui.LayoutUtils; +import org.adempiere.webui.component.Button; +import org.adempiere.webui.component.Checkbox; +import org.adempiere.webui.component.Label; +import org.adempiere.webui.component.Listbox; +import org.adempiere.webui.component.Panel; +import org.adempiere.webui.component.SimpleListModel; +import org.adempiere.webui.component.SimpleTreeModel; +import org.adempiere.webui.panel.ADForm; +import org.adempiere.webui.session.SessionManager; +import org.adempiere.webui.window.FDialog; +import org.compiere.model.MRole; +import org.compiere.model.MTree; +import org.compiere.model.MTreeNode; +import org.compiere.model.MTree_Node; +import org.compiere.model.MTree_NodeBP; +import org.compiere.model.MTree_NodeMM; +import org.compiere.model.MTree_NodePR; +import org.compiere.util.CLogger; +import org.compiere.util.DB; +import org.compiere.util.Env; +import org.compiere.util.KeyNamePair; +import org.compiere.util.Msg; +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.East; +import org.zkoss.zkex.zul.North; +import org.zkoss.zul.ListModel; +import org.zkoss.zul.SimpleTreeNode; +import org.zkoss.zul.Space; +import org.zkoss.zul.Splitter; +import org.zkoss.zul.Tree; +import org.zkoss.zul.Treeitem; + +/** + * Tree Maintenance + * + * @author Jorg Janke + * @version $Id: VTreeMaintenance.java,v 1.3 2006/07/30 00:51:28 jjanke Exp $ + */ +public class WTreeMaintenance extends ADForm implements EventListener +{ + /** Active Tree */ + private MTree m_tree; + /** Logger */ + private static CLogger log = CLogger.getCLogger(WTreeMaintenance.class); + + + private Borderlayout mainLayout = new Borderlayout (); + private Panel northPanel = new Panel (); + private Label treeLabel = new Label (); + private Listbox treeField; + private Button bAddAll = new Button (); + private Button bAdd = new Button (); + private Button bDelete = new Button (); + private Button bDeleteAll = new Button (); + private Checkbox cbAllNodes = new Checkbox (); + private Label treeInfo = new Label (); + // + private Splitter splitPane = new Splitter(); + private Tree centerTree; + private Listbox centerList = new Listbox(); + + + @Override + public void initForm() + { + try + { + preInit(); + jbInit (); + action_loadTree(); + LayoutUtils.sendDeferLayoutEvent(mainLayout, 100); + } + catch (Exception ex) + { + log.log(Level.SEVERE, "VTreeMaintenance.init", ex); + } + } // init + + /** + * Fill Tree Combo + */ + private void preInit() + { + KeyNamePair[] trees = DB.getKeyNamePairs(MRole.getDefault().addAccessSQL( + "SELECT AD_Tree_ID, Name FROM AD_Tree WHERE TreeType NOT IN ('BB','PC') ORDER BY 2", + "AD_Tree", MRole.SQL_NOTQUALIFIED, MRole.SQL_RW), false); + treeField = new Listbox(trees); + treeField.setMold("select"); + treeField.addActionListener(this); + treeField.setSelectedIndex(0); + // + centerTree = new Tree(); + centerTree.addEventListener(Events.ON_SELECT, this); + } // preInit + + /** + * Static init + * @throws Exception + */ + private void jbInit () throws Exception + { + bAddAll.setSrc("images/FastBack24.png"); + bAdd.setSrc("images/StepBack24.png"); + bDelete.setSrc("images/StepForward24.png"); + bDeleteAll.setSrc("images/FastForward24.png"); + + this.setWidth("99%"); + this.setHeight("100%"); + this.setStyle("position: absolute; padding: 0; margin: 0"); + this.appendChild (mainLayout); + mainLayout.setWidth("100%"); + mainLayout.setHeight("100%"); + mainLayout.setStyle("position: absolute"); + + treeLabel.setText (Msg.translate(Env.getCtx(), "AD_Tree_ID")); + cbAllNodes.setEnabled (false); + cbAllNodes.setText (Msg.translate(Env.getCtx(), "IsAllNodes")); + treeInfo.setText (" "); + bAdd.setTooltiptext("Add to Tree"); + bAddAll.setTooltiptext("Add ALL to Tree"); + bDelete.setTooltiptext("Delete from Tree"); + bDeleteAll.setTooltiptext("Delete ALL from Tree"); + bAdd.addActionListener(this); + bAddAll.addActionListener(this); + bDelete.addActionListener(this); + bDeleteAll.addActionListener(this); + + North north = new North(); + mainLayout.appendChild(north); + north.appendChild(northPanel); + north.setHeight("28px"); + // + northPanel.appendChild (treeLabel); + northPanel.appendChild (new Space()); + northPanel.appendChild (treeField); + northPanel.appendChild (new Space()); + northPanel.appendChild (cbAllNodes); + northPanel.appendChild (new Space()); + northPanel.appendChild (treeInfo); + northPanel.appendChild (new Space()); + northPanel.appendChild (bAddAll); + northPanel.appendChild (new Space()); + northPanel.appendChild (bAdd); + northPanel.appendChild (new Space()); + northPanel.appendChild (bDelete); + northPanel.appendChild (new Space()); + northPanel.appendChild (bDeleteAll); + // + Center center = new Center(); + mainLayout.appendChild(center); + center.appendChild(centerTree); + center.setFlex(true); + center.setAutoscroll(true); + + East east = new East(); + mainLayout.appendChild(east); + east.appendChild(centerList); + east.setCollapsible(false); + east.setSplittable(true); + east.setWidth("45%"); + centerList.setVflex(true); + centerList.setFixedLayout(true); + centerList.addEventListener(Events.ON_SELECT, this); + } // jbInit + + /** + * Dispose + */ + public void dispose() + { + SessionManager.getAppDesktop().closeActiveWindow(); + } // dispose + + /** + * Action Listener + * @param e event + */ + public void onEvent (Event e) + { + if (e.getTarget() == treeField) + { + action_loadTree(); + LayoutUtils.sendDeferLayoutEvent(mainLayout, 100); + } + else if (e.getTarget() == bAddAll) + action_treeAddAll(); + else if (e.getTarget() == bAdd) + { + SimpleListModel model = (SimpleListModel) centerList.getModel(); + int i = centerList.getSelectedIndex(); + if (i >= 0) { + action_treeAdd((ListItem)model.getElementAt(i)); + } + } + + else if (e.getTarget() == bDelete) + { + SimpleListModel model = (SimpleListModel) centerList.getModel(); + int i = centerList.getSelectedIndex(); + if (i >= 0) { + action_treeDelete((ListItem)model.getElementAt(i)); + } + } + else if (e.getTarget() == bDeleteAll) + action_treeDeleteAll(); + else if (e.getTarget() == centerList) + onListSelection(e); + else if (e.getTarget() == centerTree) + onTreeSelection(e); + } // actionPerformed + + + /** + * Action: Fill Tree with all nodes + */ + private void action_loadTree() + { + KeyNamePair tree = treeField.getSelectedItem().toKeyNamePair(); + log.info("Tree=" + tree); + if (tree.getKey() <= 0) + { + SimpleListModel tmp = new SimpleListModel(); + centerList.setItemRenderer(tmp); + centerList.setModel(tmp); + return; + } + // Tree + m_tree = new MTree (Env.getCtx(), tree.getKey(), null); + cbAllNodes.setSelected(m_tree.isAllNodes()); + bAddAll.setEnabled(!m_tree.isAllNodes()); + bAdd.setEnabled(!m_tree.isAllNodes()); + bDelete.setEnabled(!m_tree.isAllNodes()); + bDeleteAll.setEnabled(!m_tree.isAllNodes()); + // + String fromClause = m_tree.getSourceTableName(false); // fully qualified + String columnNameX = m_tree.getSourceTableName(true); + String actionColor = m_tree.getActionColorName(); + // List + SimpleListModel model = new SimpleListModel(); + String sql = "SELECT t." + columnNameX + + "_ID,t.Name,t.Description,t.IsSummary," + + actionColor + + " FROM " + fromClause + // + " WHERE t.IsActive='Y'" // R/O + + " ORDER BY 2"; + sql = MRole.getDefault().addAccessSQL(sql, + "t", MRole.SQL_FULLYQUALIFIED, MRole.SQL_RO); + log.config(sql); + // + PreparedStatement pstmt = null; + ResultSet rs = null; + try + { + pstmt = DB.prepareStatement (sql, null); + rs = pstmt.executeQuery (); + while (rs.next ()) + { + ListItem item = new ListItem(rs.getInt(1), rs.getString(2), + rs.getString(3), "Y".equals(rs.getString(4)), rs.getString(5)); + model.addElement(item); + } + } + catch (Exception e) + { + log.log(Level.SEVERE, sql, e); + } + finally + { + DB.close(rs, pstmt); + rs = null; pstmt = null; + } + // List + log.config("#" + model.getSize()); + centerList.setItemRenderer(model); + centerList.setModel(model); + + // Tree + try { + centerTree.setModel(null); + } catch (Exception e) { + } + if (centerTree.getTreecols() != null) + centerTree.getTreecols().detach(); + if (centerTree.getTreefoot() != null) + centerTree.getTreefoot().detach(); + if (centerTree.getTreechildren() != null) + centerTree.getTreechildren().detach(); + + SimpleTreeModel.initADTree(centerTree, m_tree.getAD_Tree_ID(), m_WindowNo); + } // action_fillTree + + /** + * List Selection Listener + * @param e event + */ + private void onListSelection(Event e) + { + ListItem selected = null; + try + { + SimpleListModel model = (SimpleListModel) centerList.getModel(); + int i = centerList.getSelectedIndex(); + selected = (ListItem)model.getElementAt(i); + } + catch (Exception ex) + { + } + log.info("Selected=" + selected); + if (selected != null) // allow add if not in tree + { + SimpleTreeModel tm = (SimpleTreeModel) centerTree.getModel(); + SimpleTreeNode stn = tm.find(tm.getRoot(), selected.id); + if (stn != null) { + int[] path = tm.getPath(tm.getRoot(), stn); + Treeitem ti = centerTree.renderItemByPath(path); + ti.setSelected(true); + } + bAdd.setEnabled(stn == null); + } + } // valueChanged + + /** + * Tree selection + * @param e event + */ + private void onTreeSelection (Event e) + { + Treeitem ti = centerTree.getSelectedItem(); + SimpleTreeNode stn = (SimpleTreeNode) ti.getValue(); + MTreeNode tn = (MTreeNode)stn.getData(); + log.info(tn.toString()); + if (tn == null) + return; + ListModel model = centerList.getModel(); + int size = model.getSize(); + int index = -1; + for (index = 0; index < size; index++) + { + ListItem item = (ListItem)model.getElementAt(index); + if (item.id == tn.getNode_ID()) + break; + } + centerList.setSelectedIndex(index); + } // propertyChange + + /** + * Action: Add Node to Tree + * @param item item + */ + private void action_treeAdd(ListItem item) + { + log.info("Item=" + item); + if (item != null) + { + SimpleTreeModel model = (SimpleTreeModel) centerTree.getModel(); + SimpleTreeNode stn = model.find(model.getRoot(), item.id); + if (stn != null) { + MTreeNode tNode = (MTreeNode) stn.getData(); + tNode.setName(item.name); + tNode.setAllowsChildren(item.isSummary); + tNode.setImageIndicator(item.imageIndicator); + model.nodeUpdated(stn); + Treeitem ti = centerTree.renderItemByPath(model.getPath(model.getRoot(), stn)); + ti.setTooltiptext(item.description); + } else { + stn = new SimpleTreeNode(new MTreeNode(item.id, 0, item.name, item.description, 0, item.isSummary, + item.imageIndicator, false, null), new ArrayList()); + model.addNode(stn); + } + // May cause Error if in tree + if (m_tree.isProduct()) + { + MTree_NodePR node = new MTree_NodePR (m_tree, item.id); + node.save(); + } + else if (m_tree.isBPartner()) + { + MTree_NodeBP node = new MTree_NodeBP (m_tree, item.id); + node.save(); + } + else if (m_tree.isMenu()) + { + MTree_NodeMM node = new MTree_NodeMM (m_tree, item.id); + node.save(); + } + else + { + MTree_Node node = new MTree_Node (m_tree, item.id); + node.save(); + } + } + } // action_treeAdd + + /** + * Action: Delete Node from Tree + * @param item item + */ + private void action_treeDelete(ListItem item) + { + log.info("Item=" + item); + if (item != null) + { + SimpleTreeModel model = (SimpleTreeModel) centerTree.getModel(); + SimpleTreeNode stn = model.find(model.getRoot(), item.id); + if (stn != null) + model.removeNode(stn); + + // + if (m_tree.isProduct()) + { + MTree_NodePR node = MTree_NodePR.get (m_tree, item.id); + if (node != null) + node.delete(true); + } + else if (m_tree.isBPartner()) + { + MTree_NodeBP node = MTree_NodeBP.get (m_tree, item.id); + if (node != null) + node.delete(true); + } + else if (m_tree.isMenu()) + { + MTree_NodeMM node = MTree_NodeMM.get (m_tree, item.id); + if (node != null) + node.delete(true); + } + else + { + MTree_Node node = MTree_Node.get (m_tree, item.id); + if (node != null) + node.delete(true); + } + } + } // action_treeDelete + + + /** + * Action: Add All Nodes to Tree + */ + private void action_treeAddAll() + { + log.info(""); + ListModel model = centerList.getModel(); + int size = model.getSize(); + int index = -1; + for (index = 0; index < size; index++) + { + ListItem item = (ListItem)model.getElementAt(index); + action_treeAdd(item); + } + } // action_treeAddAll + + /** + * Action: Delete All Nodes from Tree + */ + private void action_treeDeleteAll() + { + log.info(""); + //TODO: translation + if (FDialog.ask(m_WindowNo, null, "Remove all item(s) from tree?")) { + ListModel model = centerList.getModel(); + int size = model.getSize(); + int index = -1; + for (index = 0; index < size; index++) + { + ListItem item = (ListItem)model.getElementAt(index); + action_treeDelete(item); + } + } + } // action_treeDeleteAll + + /************************************************************************** + * Tree Maintenance List Item + */ + class ListItem + { + /** + * ListItem + * @param ID + * @param Name + * @param Description + * @param summary + * @param ImageIndicator + */ + public ListItem (int ID, String Name, String Description, + boolean summary, String ImageIndicator) + { + id = ID; + name = Name; + description = Description; + isSummary = summary; + imageIndicator = ImageIndicator; + } // ListItem + + /** ID */ + public int id; + /** Name */ + public String name; + /** Description */ + public String description; + /** Summary */ + public boolean isSummary; + /** Indicator */ + public String imageIndicator; // Menu - Action + + /** + * To String + * @return String Representation + */ + public String toString () + { + String retValue = name; + if (description != null && description.length() > 0) + retValue += " (" + description + ")"; + return retValue; + } // toString + + } // ListItem + +} // VTreeMaintenance diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFEditor.java b/zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFEditor.java new file mode 100644 index 0000000000..f2106cb3f9 --- /dev/null +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFEditor.java @@ -0,0 +1,136 @@ +/****************************************************************************** + * 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.apps.wf; + +import java.awt.Dimension; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.util.logging.Level; + +import javax.imageio.ImageIO; + +import org.adempiere.webui.component.ConfirmPanel; +import org.adempiere.webui.component.ListItem; +import org.adempiere.webui.component.Listbox; +import org.adempiere.webui.component.ListboxFactory; +import org.adempiere.webui.component.VerticalBox; +import org.adempiere.webui.panel.ADForm; +import org.compiere.apps.wf.WFLine; +import org.compiere.model.MRole; +import org.compiere.util.DB; +import org.compiere.util.Env; +import org.compiere.util.KeyNamePair; +import org.compiere.wf.MWFNode; +import org.compiere.wf.MWFNodeNext; +import org.compiere.wf.MWorkflow; +import org.zkoss.image.AImage; +import org.zkoss.image.Image; +import org.zkoss.zk.ui.event.Event; +import org.zkoss.zk.ui.event.Events; +import org.zkoss.zul.Imagemap; +import org.zkoss.zul.Separator; + +/** + * + * TODO: implement support for edit + * @author Low Heng Sin + * + */ +public class WFEditor extends ADForm { + + private Listbox workflowList; + private Imagemap imageMap; + + @Override + protected void initForm() { + VerticalBox vbox = new VerticalBox(); + appendChild(vbox); + + String sql = MRole.getDefault().addAccessSQL( + "SELECT AD_Workflow_ID, Name FROM AD_Workflow ORDER BY 2", + "AD_Workflow", MRole.SQL_NOTQUALIFIED, MRole.SQL_RO); // all + KeyNamePair[] pp = DB.getKeyNamePairs(sql, true); + + workflowList = ListboxFactory.newDropdownListbox(); + for (KeyNamePair knp : pp) { + workflowList.addItem(knp); + } + workflowList.addEventListener(Events.ON_SELECT, this); + + vbox.appendChild(workflowList); + vbox.appendChild(new Separator()); + + imageMap = new Imagemap(); + vbox.appendChild(imageMap); + + ConfirmPanel confirmPanel = new ConfirmPanel(true); + confirmPanel.addActionListener(this); + vbox.appendChild(new Separator()); + vbox.appendChild(confirmPanel); + } + + @Override + public void onEvent(Event event) throws Exception { + if (event.getTarget().getId().equals(ConfirmPanel.A_CANCEL)) + this.detach(); + else if (event.getTarget().getId().equals(ConfirmPanel.A_OK)) + this.detach(); + else if (event.getTarget() == workflowList) { + ListItem item = workflowList.getSelectedItem(); + KeyNamePair knp = item != null ? item.toKeyNamePair() : null; + if (knp != null && knp.getKey() > 0) { + load(knp.getKey()); + } else { + Image dummy = null; + imageMap.setContent(dummy); + } + } + } + + private void load(int workflowId) { + // Get Workflow + MWorkflow wf = new MWorkflow (Env.getCtx(), workflowId, null); + WFNodeContainer nodeContainer = new WFNodeContainer(); + nodeContainer.setWorkflow(wf); + + // Add Nodes for Paint + MWFNode[] nodes = wf.getNodes(true, Env.getAD_Client_ID(Env.getCtx())); + for (int i = 0; i < nodes.length; i++) + { + WFNode wfn = new WFNode (nodes[i]); + nodeContainer.add (wfn); + // Add Lines + MWFNodeNext[] nexts = nodes[i].getTransitions(Env.getAD_Client_ID(Env.getCtx())); + for (int j = 0; j < nexts.length; j++) + nodeContainer.add (new WFLine (nexts[j])); + } + Dimension dimension = nodeContainer.getDimension(); + BufferedImage bi = new BufferedImage (dimension.width + 2, dimension.height + 2, BufferedImage.TYPE_INT_ARGB); + nodeContainer.paint(bi.createGraphics()); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + try { + ImageIO.write(bi, "png", os); + AImage imageContent = new AImage("workflow.png", os.toByteArray()); + imageMap.setWidth(dimension.width + "px"); + imageMap.setHeight(dimension.height + "px"); + imageMap.setContent(imageContent); + + } catch (Exception e) { + logger.log(Level.SEVERE, e.getLocalizedMessage(), e); + } + + } + + + +} diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFNode.java b/zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFNode.java new file mode 100644 index 0000000000..8c81b3d3e9 --- /dev/null +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFNode.java @@ -0,0 +1,107 @@ +/****************************************************************************** + * 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.apps.wf; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.font.LineBreakMeasurer; +import java.awt.font.TextAttribute; +import java.awt.font.TextLayout; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; + +import org.compiere.apps.wf.WFIcon; +import org.compiere.wf.MWFNode; + +/** + * + * @author Low Heng Sin + * + */ +public class WFNode { + + /** Size of the Node */ + private static Dimension s_size = new Dimension (120, 50); + private MWFNode m_node; + private WFIcon m_icon; + private Rectangle m_bounds; + + /** + * Create WF Node + * @param node model + */ + public WFNode (MWFNode node) { + m_node = node; + m_icon = new WFIcon(node.getAction()); + m_bounds = new Rectangle(m_node.getXPosition(), m_node.getYPosition(), s_size.width, + s_size.height); + } + + public void paint(Graphics2D g2D) { + m_icon.paintIcon(null, g2D, 0, 0); + // Paint Text + g2D.setPaint(Color.BLACK); + Font base = new Font(null); + Font font = new Font(base.getName(), Font.ITALIC | Font.BOLD, base.getSize()); + // + AttributedString aString = new AttributedString(m_node.getName(true)); + aString.addAttribute(TextAttribute.FONT, font); + aString.addAttribute(TextAttribute.FOREGROUND, Color.BLACK); + AttributedCharacterIterator iter = aString.getIterator(); + // + LineBreakMeasurer measurer = new LineBreakMeasurer(iter, g2D.getFontRenderContext()); + float width = s_size.width - m_icon.getIconWidth() - 2; + TextLayout layout = measurer.nextLayout(width); + float xPos = m_icon.getIconWidth(); + float yPos = layout.getAscent() + 2; + // + layout.draw(g2D, xPos, yPos); + width = s_size.width - 4; // 2 pt + while (measurer.getPosition() < iter.getEndIndex()) + { + layout = measurer.nextLayout(width); + yPos += layout.getAscent() + layout.getDescent() + layout.getLeading(); + layout.draw(g2D, 2, yPos); + } + } + + /** + * + * @return AD_WF_Node_ID + */ + public int getAD_WF_Node_ID() { + return m_node.getAD_WF_Node_ID(); + } + + public Rectangle getBounds() { + return m_bounds; + } + + public MWFNode getNode() { + return m_node; + } + + /** + * + * @param x + * @param y + * @param width + * @param height + */ + public void setBounds(int x, int y, int width, int height) { + m_bounds = new Rectangle(x, y, width, height); + } +} diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFNodeContainer.java b/zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFNodeContainer.java new file mode 100644 index 0000000000..7451e841c2 --- /dev/null +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFNodeContainer.java @@ -0,0 +1,212 @@ +/****************************************************************************** + * 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.apps.wf; + +import java.awt.*; +import java.util.*; + +import org.compiere.apps.wf.WFLine; +import org.compiere.util.*; +import org.compiere.wf.*; + +/** + * + * @author Low Heng Sin + * + */ +public class WFNodeContainer +{ + /** + * WFContentPanel + */ + public WFNodeContainer () + { + } // WFContentPanel + + /** Logger */ + private static CLogger log = CLogger.getCLogger(WFNodeContainer.class); + /** Node List */ + private ArrayList m_nodes = new ArrayList(); + /** Line List */ + private ArrayList m_lines = new ArrayList(); + + /** The Workflow */ + private MWorkflow m_wf = null; + + /** + * Set Workflow + * @param wf workflow + */ + public void setWorkflow (MWorkflow wf) + { + m_wf = wf; + } // setWorkflow + + + /** + * Remove All and their listeners + */ + public void removeAll () + { + m_nodes.clear(); + m_lines.clear(); + } // removeAll + + + /** + * Add Component and add Mouse Listener + * @param comp component + * @return component + */ + public void add (WFNode node) + { + m_nodes.add(node); + } // add + + /** + * + * @param line + */ + public void add(WFLine line) + { + m_lines.add(line); + } + + /** + * Create Lines. + * Called by WF Layout Manager + */ + protected void createLines() + { + log.fine("Lines #" + m_lines.size()); + for (int i = 0; i < m_lines.size(); i++) + { + WFLine line = (WFLine)m_lines.get(i); + Rectangle from = findBounds (line.getAD_WF_Node_ID()); + Rectangle to = findBounds (line.getAD_WF_Next_ID()); + line.setFromTo(from, to); + // same bounds as parent + // line.setBounds(0,0, width, height); + } // for all lines + } + + /** + * Get Bounds of WF Node Icon + * @param AD_WF_Node_ID node id + * @return bounds of node with ID or null + */ + private Rectangle findBounds (int AD_WF_Node_ID) + { + for (int i = 0; i < m_nodes.size(); i++) + { + WFNode node = (WFNode)m_nodes.get(i); + if (node.getAD_WF_Node_ID() == AD_WF_Node_ID) + return node.getBounds(); + } + return null; + } // findBounds + + public Dimension getDimension() + { + if (needLayout()) + updateLayout(); + + int width = 0; + int height = 0; + // Go through all node + for (int i = 0; i < m_nodes.size(); i++) + { + WFNode node = m_nodes.get(i); + Rectangle rect = node.getBounds(); + if (rect.x + rect.width > width) + width = rect.x + rect.width; + if (rect.y + rect.height > height) + height = rect.y + rect.height; + } // for all components + + return new Dimension(width, height); + } + + /************************************************************************** + * Paint Component. + * Paint Lines directly as not added. + * @param g graphics + */ + public void paint(Graphics2D g) + { + + for (int i = 0; i < m_nodes.size(); i++) + { + WFNode node = m_nodes.get(i); + Rectangle rect = node.getBounds(); + g.setColor(Color.BLACK); + g.drawRect(rect.x, rect.y, rect.width, rect.height); + Graphics2D t = (Graphics2D) g.create(rect.x, rect.y, rect.width, rect.height); + node.paint(t); + t.dispose(); + } // for all components + + createLines(); + + // Paint Lines + for (int i = 0; i < m_lines.size(); i++) + { + WFLine line = (WFLine)m_lines.get(i); + line.paint(g); + } + } // paint + + + private void updateLayout() { + int x = 5; + int y = 5;for (int i = 0; i < m_nodes.size(); i++) + { + WFNode node = m_nodes.get(i); + Rectangle rect = node.getBounds(); + node.setBounds(x, y, rect.width, rect.height); + // next pos + if (x == 5) + x = 230; + else + { + x = 5; + y += 100; + } + } + } + + /** + * Need Layout + * @param parent parent + * @return true if we need to layout + */ + private boolean needLayout () + { + // Go through all components + for (int i = 0; i < m_nodes.size(); i++) + { + WFNode node = m_nodes.get(i); + Rectangle rect = node.getBounds(); + if (rect.x == 0 && rect.y == 0) + { + return true; + } + } + return false; + } // needLayout + + public ArrayList getNodes() { + return m_nodes; + } + +} // WFContentPanel diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFPanel.java b/zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFPanel.java new file mode 100644 index 0000000000..bf6da96831 --- /dev/null +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/apps/wf/WFPanel.java @@ -0,0 +1,246 @@ +/****************************************************************************** + * 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.apps.wf; + +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.util.*; +import java.util.logging.*; + +import javax.imageio.ImageIO; + +import org.adempiere.webui.component.Panel; +import org.adempiere.webui.component.VerticalBox; +import org.adempiere.webui.exception.ApplicationException; +import org.adempiere.webui.session.SessionManager; +import org.compiere.apps.wf.WFLine; +import org.compiere.util.*; +import org.compiere.wf.*; +import org.zkoss.image.AImage; +import org.zkoss.zk.ui.event.Event; +import org.zkoss.zk.ui.event.EventListener; +import org.zkoss.zk.ui.event.Events; +import org.zkoss.zk.ui.event.MouseEvent; +import org.zkoss.zul.Area; +import org.zkoss.zul.Div; +import org.zkoss.zul.Html; +import org.zkoss.zul.Imagemap; +import org.zkoss.zul.Separator; + +/** + * WorkFlow Panel + * + * @author Low Heng Sin + */ +public class WFPanel extends Panel implements EventListener +{ + /** + * Create Workflow Panel + */ + public WFPanel () + { + try + { + jbInit(); + } + catch(Exception e) + { + log.log(Level.SEVERE, "WFPanel", e); + } + m_WindowNo = SessionManager.getAppDesktop().registerWindow(this); + } // WFPanel + + /** Window No */ + private int m_WindowNo = 0; + + + /** Workflow Model */ + private MWorkflow m_wf = null; + /** Context */ + private Properties m_ctx = Env.getCtx(); + + /** Logger */ + private static CLogger log = CLogger.getCLogger(WFPanel.class); + + // IO + private WFNodeContainer nodeContainer = new WFNodeContainer(); + + private Html infoTextPane = new Html(); + private Div contentPanel = new Div(); + // + + + /** + * Static Init + *
+	 * 		centerScrollPane
+	 * 			centerPanel
+	 * 		south Panel
+	 * 			infoScrollPane
+	 * 			buttonPanel
+	 * 	
+ * @throws Exception + */ + private void jbInit() throws Exception + { + VerticalBox vbox = new VerticalBox(); + appendChild(vbox); + // Center + contentPanel.setStyle("width: 100%; heigh: 100%; overflow: auto;"); + vbox.appendChild(new Separator()); + vbox.appendChild(contentPanel); + vbox.appendChild(new Separator()); + vbox.appendChild(infoTextPane); + vbox.setHeights("85%,15%"); + vbox.setStyle("padding-left: 10px"); + + } // jbInit + + /** + * Dispose + * @see org.compiere.apps.form.FormPanel#dispose() + */ + public void dispose() + { + SessionManager.getAppDesktop().closeActiveWindow(); + } // dispose + + + /** + * Load Workflow & Nodes + * @param AD_Workflow_ID ID + */ + public void load (int AD_Workflow_ID) + { + log.fine("AD_Workflow_ID=" + AD_Workflow_ID); + if (AD_Workflow_ID == 0) + return; + int AD_Client_ID = Env.getAD_Client_ID(Env.getCtx()); + // Get Workflow + m_wf = new MWorkflow (Env.getCtx(), AD_Workflow_ID, null); + nodeContainer.removeAll(); + nodeContainer.setWorkflow(m_wf); + + // Add Nodes for Paint + MWFNode[] nodes = m_wf.getNodes(true, AD_Client_ID); + for (int i = 0; i < nodes.length; i++) + { + WFNode wfn = new WFNode (nodes[i]); + nodeContainer.add (wfn); + // Add Lines + MWFNodeNext[] nexts = nodes[i].getTransitions(AD_Client_ID); + for (int j = 0; j < nexts.length; j++) + nodeContainer.add (new WFLine (nexts[j])); + } + Dimension dimension = nodeContainer.getDimension(); + BufferedImage bi = new BufferedImage (dimension.width + 2, dimension.height + 2, BufferedImage.TYPE_INT_ARGB); + nodeContainer.paint(bi.createGraphics()); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + try { + ImageIO.write(bi, "png", os); + AImage imageContent = new AImage("workflow.png", os.toByteArray()); + Imagemap image = new Imagemap(); + image.setWidth(dimension.width + "px"); + image.setHeight(dimension.height + "px"); + image.setContent(imageContent); + contentPanel.appendChild(image); + + image.addEventListener(Events.ON_CLICK, this); + for(WFNode node : nodeContainer.getNodes()) { + Area area = new Area(); + Rectangle rect = node.getBounds(); + area.setCoords(rect.x + "," + rect.y + "," + (rect.x+rect.width) + "," + + (rect.y+rect.height)); + image.appendChild(area); + area.setId("WFN_"+node.getAD_WF_Node_ID()); + StringBuffer tooltip = new StringBuffer(); + String s = node.getNode().getDescription(true); + if (s != null && s.trim().length() > 0) + tooltip.append(s); + String h = node.getNode().getHelp(true); + if (h != null && h.trim().length() > 0) { + if (tooltip.length() > 0) + tooltip.append(". "); + tooltip.append(h); + } + area.setTooltiptext(tooltip.toString()); + } + } catch (Exception e) { + log.log(Level.SEVERE, e.getLocalizedMessage(), e); + } + + // Info Text + StringBuffer msg = new StringBuffer(""); + msg.append("

").append(m_wf.getName(true)).append("

"); + String s = m_wf.getDescription(true); + if (s != null && s.length() > 0) + msg.append("").append(s).append(""); + s = m_wf.getHelp(true); + if (s != null && s.length() > 0) + msg.append("
").append(s); + infoTextPane.setContent(msg.toString()); + + } // load + + /** + * String Representation + * @return info + */ + public String toString() + { + StringBuffer sb = new StringBuffer("WorkflowPanel["); + if (m_wf != null) + sb.append(m_wf.getAD_Workflow_ID()); + sb.append("]"); + return sb.toString(); + } // toString + + public MWorkflow getWorkflow() + { + return m_wf; + } + + public void onEvent(Event event) throws Exception { + if (Events.ON_CLICK.equals(event.getName()) && event instanceof MouseEvent) { + MouseEvent me = (MouseEvent) event; + String areaId = me.getArea(); + if (areaId != null && areaId.startsWith("WFN_")) { + int id = Integer.valueOf(areaId.substring(4)); + for(WFNode node : nodeContainer.getNodes()) { + if (node.getAD_WF_Node_ID() == id) { + start(node); + break; + } + } + } + } + } + + private void start(WFNode node) { + MWFNode wfn = node.getNode(); + if (wfn.getAD_Window_ID() > 0) { + SessionManager.getAppDesktop().openWindow(wfn.getAD_Window_ID()); + } else if (wfn.getAD_Form_ID() > 0) { + SessionManager.getAppDesktop().openForm(wfn.getAD_Form_ID()); + } else if (wfn.getAD_Process_ID() > 0) { + SessionManager.getAppDesktop().openProcessDialog(wfn.getAD_Process_ID(), false); + } else if (wfn.getAD_Task_ID() > 0) { + SessionManager.getAppDesktop().openTask(wfn.getAD_Task_ID()); + } else { + throw new ApplicationException("Action not yet implemented: " + wfn.getAction()); + } + } + +} // WFPanel diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/DatetimeBox.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/DatetimeBox.java new file mode 100644 index 0000000000..ef1005b820 --- /dev/null +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/DatetimeBox.java @@ -0,0 +1,128 @@ +/****************************************************************************** + * 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.text.SimpleDateFormat; +import java.util.Date; + +import org.adempiere.webui.apps.AEnv; +import org.zkoss.zk.ui.event.EventListener; +import org.zkoss.zul.Timebox; + +/** + * + * @author Low Heng Sin + * + */ +public class DatetimeBox extends Panel { + + private Datebox dateBox; + private Timebox timeBox; + + public DatetimeBox() { + dateBox = new Datebox(); + timeBox = new Timebox(); + appendChild(dateBox); + appendChild(timeBox); + + initComponents(); + } + + private void initComponents() { + dateBox.setStyle("display: inline"); + timeBox.setStyle("display: inline"); + timeBox.setButtonVisible(false); + + String style = AEnv.isFirefox2() ? "display: inline" : "display: inline-block"; + style = style + ";white-space:nowrap"; + this.setStyle(style); + } + + /** + * @param date + */ + public void setValue(Date date) { + dateBox.setValue(date); + timeBox.setValue(date); + } + + /** + * @param text + */ + public void setText(String text) { + if (text != null && text.trim().length() > 0) + { + String[] s = text.split("\\s"); + + dateBox.setText(s[0]); + timeBox.setText(s[1]); + } + else + { + dateBox.setValue(null); + timeBox.setValue(null); + } + } + + /** + * @return String + */ + public String getText() { + return dateBox.getText() + " " + timeBox.getText(); + } + + @Override + public boolean addEventListener(String evtnm, EventListener listener) { + return dateBox.addEventListener(evtnm, listener) && timeBox.addEventListener(evtnm, listener); + } + + /** + * @return boolean + */ + public boolean isEnabled() { + return !dateBox.isReadonly(); + } + + /** + * @param readWrite + */ + public void setEnabled(boolean readWrite) { + dateBox.setDisabled(!readWrite); + timeBox.setDisabled(!readWrite); + dateBox.setButtonVisible(readWrite); + } + + /** + * @return date + */ + public Date getValue() { + Date d = dateBox.getValue(); + Date t = timeBox.getValue(); + + if (d != null && t != null) { + d.setHours(t.getHours()); + d.setMinutes(t.getMinutes()); + d.setSeconds(t.getSeconds()); + } + + return d; + } + + /** + * + * @param dateFormat + */ + public void setDateFormat(SimpleDateFormat dateFormat) { + dateBox.setFormat(dateFormat.toPattern()); + } +} diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/EditorBox.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/EditorBox.java index 05b278ea62..00b57dd19e 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/component/EditorBox.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/EditorBox.java @@ -59,6 +59,7 @@ public class EditorBox extends Panel private void initComponents() { txt = new Textbox(); + txt.setStyle("display: inline;"); btn = new Button(); this.appendChild(txt); @@ -67,6 +68,7 @@ public class EditorBox extends Panel btn.setSclass("editor-button"); String style = AEnv.isFirefox2() ? "display: inline" : "display: inline-block"; + style = style + ";white-space:nowrap"; this.setStyle(style); } diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/FilenameBox.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/FilenameBox.java index 95be1a9796..f67565b789 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/component/FilenameBox.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/FilenameBox.java @@ -17,13 +17,13 @@ package org.adempiere.webui.component; +import org.adempiere.webui.apps.AEnv; import org.zkoss.zk.ui.event.EventListener; -import org.zkoss.zul.Hbox; /** * URL Box */ -public class FilenameBox extends Hbox +public class FilenameBox extends Panel { private static final long serialVersionUID = 1L; @@ -51,11 +51,15 @@ public class FilenameBox extends Hbox private void initComponents() { textbox = new Textbox(); - textbox.setWidth("100%"); + textbox.setStyle("display: inline"); button = new Button(); - button.setHeight("98%"); + button.setSclass("editor-button"); appendChild(textbox); appendChild(button); + + String style = AEnv.isFirefox2() ? "display: inline" : "display: inline-block"; + style = style + ";white-space:nowrap"; + this.setStyle(style); } public void setText(String value) diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/Locationbox.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/Locationbox.java index 8d07402c6b..5fe564eddc 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/component/Locationbox.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/Locationbox.java @@ -53,12 +53,14 @@ public class Locationbox extends Panel private void initComponents() { txt = new Textbox(); + txt.setStyle("display: inline"); btn = new Button(); btn.setSclass("editor-button"); this.appendChild(txt); this.appendChild(btn); String style = AEnv.isFirefox2() ? "display: inline" : "display: inline-block"; + style = style + ";white-space:nowrap"; this.setStyle(style); } diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/NumberBox.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/NumberBox.java index 67492cd796..7918cf64e4 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/component/NumberBox.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/NumberBox.java @@ -25,6 +25,7 @@ import org.adempiere.webui.apps.AEnv; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.Events; import org.zkoss.zul.Decimalbox; +import org.zkoss.zul.Div; import org.zkoss.zul.Hbox; import org.zkoss.zul.Popup; import org.zkoss.zul.Vbox; @@ -37,7 +38,7 @@ import org.zkoss.zul.Vbox; * * @author Low Heng Sin */ -public class NumberBox extends Panel +public class NumberBox extends Div { private static final long serialVersionUID = 1L; @@ -66,6 +67,7 @@ public class NumberBox extends Panel decimalBox = new Decimalbox(); if (integral) decimalBox.setScale(0); + decimalBox.setStyle("display: inline;"); btn = new Button(); btn.setImage("/images/Calculator16.png"); @@ -73,12 +75,13 @@ public class NumberBox extends Panel Popup popup = getCalculatorPopup(); btn.setSclass("editor-button"); btn.setPopup(popup); - btn.setStyle("text-align: center"); + btn.setStyle("text-align: center;"); appendChild(decimalBox); appendChild(btn); appendChild(popup); String style = AEnv.isFirefox2() ? "display: inline" : "display: inline-block"; + style = style + ";white-space:nowrap"; this.setStyle(style); } diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/PAttributebox.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/PAttributebox.java index 9a8fb887a2..fde54e6079 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/component/PAttributebox.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/PAttributebox.java @@ -51,13 +51,15 @@ public class PAttributebox extends Panel private void initComponents() { textBox = new Textbox(); + textBox.setStyle("display: inline"); button = new Button(); button.setSclass("editor-button"); appendChild(textBox); appendChild(button); String style = AEnv.isFirefox2() ? "display: inline" : "display: inline-block"; - this.setStyle(style); + style = style + ";white-space:nowrap"; + this.setStyle(style + ";overflow: hidden"); } public void setText(String value) diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/Searchbox.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/Searchbox.java index 937d7ab66f..84328115df 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/component/Searchbox.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/Searchbox.java @@ -22,8 +22,9 @@ import java.beans.PropertyChangeSupport; import org.adempiere.webui.apps.AEnv; import org.zkoss.zk.ui.event.EventListener; +import org.zkoss.zul.Div; -public class Searchbox extends Panel +public class Searchbox extends Div { private static final long serialVersionUID = 1L; private PropertyChangeSupport m_propertyChangeListeners = new PropertyChangeSupport(this); @@ -49,12 +50,14 @@ public class Searchbox extends Panel private void initComponents() { txt = new Textbox(); + txt.setStyle("display: inline;"); btn = new Button(); btn.setSclass("editor-button"); appendChild(txt); appendChild(btn); String style = AEnv.isFirefox2() ? "display: inline" : "display: inline-block"; + style = style + ";white-space:nowrap"; this.setStyle(style); } diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/Searchbox2.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/Searchbox2.java deleted file mode 100644 index b7fb72e366..0000000000 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/component/Searchbox2.java +++ /dev/null @@ -1,97 +0,0 @@ -/****************************************************************************** - * Product: Posterita Ajax UI * - * Copyright (C) 2007 Posterita Ltd. 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 * - * Posterita Ltd., 3, Draper Avenue, Quatre Bornes, Mauritius * - * or via info@posterita.org or http://www.posterita.org/ * - *****************************************************************************/ - -package org.adempiere.webui.component; - -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; - -import org.zkoss.zk.ui.event.EventListener; - -public class Searchbox2 extends Bandbox -{ - private static final long serialVersionUID = 1L; - private PropertyChangeSupport m_propertyChangeListeners = new PropertyChangeSupport(this); -// private Textbox txt; -// private Button btn; - - public Searchbox2() - { - initComponents(); - } - - public Searchbox2(String text) - { - initComponents(); - setText(text); - } - - public void setButtonImage(String imageSrc) - { - this.setImage(imageSrc); - } - - private void initComponents() - { -// txt = new Textbox(); -// txt.setWidth("100%"); -// btn = new Button(); -// btn.setHeight("98%"); -// appendChild(txt); -// appendChild(btn); - } - -// public void setText(String value) -// { -// txt.setText(value); -// } - -// public String getText() -// { -// return txt.getText(); -// } - - public void setEnabled(boolean enabled) - { - setReadonly(!enabled); -// txt.setReadonly(!enabled); -// btn.setEnabled(enabled); - } - - public boolean isEnabled() - { - return !isReadonly(); -// return txt.isReadonly(); - } - - public boolean addEventListener(String evtnm, EventListener listener) - { - return super.addEventListener(evtnm, listener); -// if("onClick".equals(evtnm)) -// { -// return btn.addEventListener(evtnm, listener); -// } -// else -// { -// return txt.addEventListener(evtnm, listener); -// } - } - public synchronized void addPropertyChangeListener(PropertyChangeListener l) - { - m_propertyChangeListeners.addPropertyChangeListener(l); - } -} diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/SimpleTreeModel.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/SimpleTreeModel.java index e139b05650..7d8cd322fa 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/component/SimpleTreeModel.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/SimpleTreeModel.java @@ -219,4 +219,12 @@ public class SimpleTreeModel extends org.zkoss.zul.SimpleTreeModel implements Tr } return null; } + + public void nodeUpdated(SimpleTreeNode node) { + SimpleTreeNode parent = getParent(node); + if (parent != null) { + int i = parent.getChildren().indexOf(node); + fireEvent(parent, i, i, TreeDataEvent.CONTENTS_CHANGED); + } + } } diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/component/Urlbox.java b/zkwebui/WEB-INF/src/org/adempiere/webui/component/Urlbox.java index 4459bb4145..ebc4863603 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/component/Urlbox.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/component/Urlbox.java @@ -19,7 +19,6 @@ package org.adempiere.webui.component; import org.adempiere.webui.apps.AEnv; import org.zkoss.zk.ui.event.EventListener; -import org.zkoss.zul.Hbox; /** * URL Box @@ -52,12 +51,14 @@ public class Urlbox extends Panel private void initComponents() { txtUrl = new Textbox(); + txtUrl.setStyle("display: inline;"); btnUrl = new Button(); btnUrl.setSclass("editor-button"); appendChild(txtUrl); appendChild(btnUrl); String style = AEnv.isFirefox2() ? "display: inline" : "display: inline-block"; + style = style + ";white-space:nowrap"; this.setStyle(style); } diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WDateEditor.java b/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WDateEditor.java index 93f5be7c6a..4e7339f514 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WDateEditor.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WDateEditor.java @@ -25,6 +25,7 @@ import org.adempiere.webui.component.Datebox; import org.adempiere.webui.event.ValueChangeEvent; import org.compiere.model.GridField; import org.compiere.util.CLogger; +import org.compiere.util.DisplayType; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.Events; @@ -53,6 +54,7 @@ public class WDateEditor extends WEditor public WDateEditor(GridField gridField) { super(new Datebox(), gridField); + init(); } @@ -74,11 +76,12 @@ public class WDateEditor extends WEditor { super(new Datebox(), label, description, mandatory, readonly, updateable); setColumnName("Date"); + init(); } public WDateEditor() { - this("Date", "Date", false, false, true); + this("Date", "Date", false, false, true); } // VDate /** @@ -94,6 +97,11 @@ public class WDateEditor extends WEditor { super(new Datebox(), columnName, title, null, mandatory, readonly, updateable); } + + private void init() + { + getComponent().setFormat(DisplayType.getDateFormat().toPattern()); + } public void onEvent(Event event) { diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WDatetimeEditor.java b/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WDatetimeEditor.java new file mode 100644 index 0000000000..38ea8c59ab --- /dev/null +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WDatetimeEditor.java @@ -0,0 +1,189 @@ +/****************************************************************************** + * 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.editor; + +import java.sql.Timestamp; +import java.util.Date; + +import org.adempiere.webui.component.DatetimeBox; +import org.adempiere.webui.event.ValueChangeEvent; +import org.compiere.model.GridField; +import org.compiere.util.CLogger; +import org.compiere.util.DisplayType; +import org.zkoss.zk.ui.event.Event; +import org.zkoss.zk.ui.event.Events; + +/** + * + * @author Low Heng Sin + */ +public class WDatetimeEditor extends WEditor +{ + private static final String[] LISTENER_EVENTS = {Events.ON_CHANGE}; + private static final CLogger logger; + + static + { + logger = CLogger.getCLogger(WDatetimeEditor.class); + } + + private Timestamp oldValue = new Timestamp(0); + + /** + * + * @param gridField + */ + public WDatetimeEditor(GridField gridField) + { + super(new DatetimeBox(), gridField); + init(); + } + + + /** + * Constructor for use if a grid field is unavailable + * + * @param label + * column name (not displayed) + * @param description + * description of component + * @param mandatory + * whether a selection must be made + * @param readonly + * whether or not the editor is read only + * @param updateable + * whether the editor contents can be changed + */ + public WDatetimeEditor (String label, String description, boolean mandatory, boolean readonly, boolean updateable) + { + super(new DatetimeBox(), label, description, mandatory, readonly, updateable); + setColumnName("Datetime"); + init(); + } + + public WDatetimeEditor() + { + this("Datetime", "Datetime", false, false, true); + } // VDate + + /** + * + * @param columnName + * @param mandatory + * @param readonly + * @param updateable + * @param title + */ + public WDatetimeEditor(String columnName, boolean mandatory, boolean readonly, boolean updateable, + String title) + { + super(new DatetimeBox(), columnName, title, null, mandatory, readonly, updateable); + init(); + } + + private void init() + { + getComponent().setDateFormat(DisplayType.getDateFormat()); + } + + public void onEvent(Event event) + { + Date date = getComponent().getValue(); + Timestamp newValue = null; + + if (date != null) + { + newValue = new Timestamp(date.getTime()); + } + + ValueChangeEvent changeEvent = new ValueChangeEvent(this, this.getColumnName(), oldValue, newValue); + super.fireValueChange(changeEvent); + oldValue = newValue; + } + + @Override + public String getDisplay() + { + // Elaine 2008/07/29 + return getComponent().getText(); + // + } + + @Override + public Object getValue() + { + // Elaine 2008/07/25 + if(getComponent().getValue() == null) return null; + return new Timestamp(getComponent().getValue().getTime()); + // + } + + @Override + public boolean isMandatory() + { + return false; + } + + @Override + public void setMandatory(boolean mandatory) + { + } + + @Override + public void setValue(Object value) + { + if (value == null || value.toString().trim().length() == 0) + { + oldValue = null; + getComponent().setValue(null); + } + else if (value instanceof Timestamp) + { + getComponent().setValue((Timestamp)value); + oldValue = (Timestamp)value; + } + else + { + try + { + getComponent().setText(value.toString()); + } catch (Exception e) {} + if (getComponent().getValue() != null) + oldValue = new Timestamp(getComponent().getValue().getTime()); + else + oldValue = null; + } + } + + @Override + public DatetimeBox getComponent() { + return (DatetimeBox) component; + } + + @Override + public boolean isReadWrite() { + return getComponent().isEnabled(); + } + + + @Override + public void setReadWrite(boolean readWrite) { + getComponent().setEnabled(readWrite); + } + + public String[] getEvents() + { + return LISTENER_EVENTS; + } + +} diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WebEditorFactory.java b/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WebEditorFactory.java index fbac8b5012..bdbfee0f74 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WebEditorFactory.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/editor/WebEditorFactory.java @@ -109,6 +109,8 @@ public class WebEditorFactory { if (displayType == DisplayType.Time) editor = new WTimeEditor(gridField); + else if (displayType == DisplayType.DateTime) + editor = new WDatetimeEditor(gridField); else editor = new WDateEditor(gridField); } diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/panel/ADForm.java b/zkwebui/WEB-INF/src/org/adempiere/webui/panel/ADForm.java index e3aabc098f..cb2edfe600 100755 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/panel/ADForm.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/panel/ADForm.java @@ -192,6 +192,8 @@ public abstract class ADForm extends Window implements EventListener webClassName = "org.adempiere.webui.apps.form.WArchiveViewer"; // TEMP else if ("org.compiere.apps.wf.WFActivity".equals(richClassName)) webClassName = "org.adempiere.webui.apps.wf.WWFActivity"; // TEMP + else if ("org.compiere.apps.wf.WFPanel".equals(richClassName)) + webClassName = "org.adempiere.webui.apps.wf.WFEditor"; else webClassName = translateFormClassName(richClassName); 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 468452e38f..708ff22e6b 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/panel/ADTabpanel.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/panel/ADTabpanel.java @@ -75,6 +75,7 @@ import org.zkoss.zkex.zul.West; import org.zkoss.zul.Div; import org.zkoss.zul.Separator; import org.zkoss.zul.SimpleTreeNode; +import org.zkoss.zul.Space; import org.zkoss.zul.Toolbarbutton; import org.zkoss.zul.Tree; import org.zkoss.zul.Treeitem; @@ -360,7 +361,7 @@ DataStatusListener, ValueChangeListener, IADTabpanel //can't stretch bandbox & datebox if (!(editor.getComponent() instanceof Bandbox) && !(editor.getComponent() instanceof Datebox)) { - String width = AEnv.isFirefox2() ? "99%" : "100%"; + String width = "99%"; ((HtmlBasedComponent)editor.getComponent()).setWidth(width); } } @@ -404,11 +405,7 @@ DataStatusListener, ValueChangeListener, IADTabpanel } private Component createSpacer() { - Span span = new Span(); - Text text = new Text("     "); - text.setParent(span); - span.setStyle("width: 100%"); - return span; + return new Space(); } public void dynamicDisplay (int col) diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/panel/AbstractADWindowPanel.java b/zkwebui/WEB-INF/src/org/adempiere/webui/panel/AbstractADWindowPanel.java index acb172116f..b473c09c84 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/panel/AbstractADWindowPanel.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/panel/AbstractADWindowPanel.java @@ -118,6 +118,8 @@ public abstract class AbstractADWindowPanel extends AbstractUIPart implements To private boolean m_uiLocked; + private boolean m_findCancelled; + public AbstractADWindowPanel(Properties ctx, int windowNo) { this.ctx = ctx; @@ -201,6 +203,9 @@ public abstract class AbstractADWindowPanel extends AbstractUIPart implements To if (tab == 0) { query = initialQuery(query, gTab); + if (gTab.isHighVolume() && m_findCancelled) + return false; + if (query != null && query.getRecordCount() <= 1) { // goSingleRow = true; @@ -211,6 +216,7 @@ public abstract class AbstractADWindowPanel extends AbstractUIPart implements To m_onlyCurrentRows = false; gTab.setQuery(query); } + curTab = gTab; curTabIndex = tab; } @@ -309,6 +315,7 @@ public abstract class AbstractADWindowPanel extends AbstractUIPart implements To // Show Query if (require) { + m_findCancelled = false; GridField[] findFields = mTab.getFields(); FindWindow find = new FindWindow(curWindowNo, mTab.getName(), mTab.getAD_Table_ID(), mTab.getTableName(), @@ -317,7 +324,10 @@ public abstract class AbstractADWindowPanel extends AbstractUIPart implements To // Title is not set when the number of rows is below the minRecords parameter (10) find.setVisible(true); AEnv.showWindow(find); - query = find.getQuery(); + if (!find.isCancel()) + query = find.getQuery(); + else + m_findCancelled = true; find = null; } } diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/panel/MenuPanel.java b/zkwebui/WEB-INF/src/org/adempiere/webui/panel/MenuPanel.java index 84b9da66d7..aa5c483a5e 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/panel/MenuPanel.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/panel/MenuPanel.java @@ -166,7 +166,7 @@ public class MenuPanel extends Panel implements EventListener if (mChildNode.isReport()) treeitem.setImage("/images/mReport.png"); - else if (mChildNode.isProcess()) + else if (mChildNode.isProcess() || mChildNode.isTask()) treeitem.setImage("/images/mProcess.png"); else if (mChildNode.isWorkFlow()) treeitem.setImage("/images/mWorkFlow.png"); diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/util/OSTask.java b/zkwebui/WEB-INF/src/org/adempiere/webui/util/OSTask.java new file mode 100644 index 0000000000..757bc87e36 --- /dev/null +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/util/OSTask.java @@ -0,0 +1,206 @@ +/****************************************************************************** + * 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.util; + +import java.io.*; +import java.util.logging.*; + +import org.compiere.util.CLogger; + +/** + * Execute OS Task + * + * @author Low Heng Sin + */ +public class OSTask extends Thread +{ + /** + * Create Process with cmd + * @param cmd o/s command + */ + public OSTask (String cmd) + { + m_cmd = cmd; + } // Task + + private String m_cmd; + private Process m_child = null; + + private StringBuffer m_out = new StringBuffer(); + private StringBuffer m_err = new StringBuffer(); + + /** The Output Stream of process */ + private InputStream m_outStream; + /** The Error Output Stream of process */ + private InputStream m_errStream; + /** The Input Stream of process */ + private OutputStream m_inStream; + + /** Logger */ + private static CLogger log = CLogger.getCLogger(OSTask.class); + + /** Read Out */ + private Thread m_outReader = new Thread() + { + public void run() + { + log.fine("outReader"); + try + { + int c; + while ((c = m_outStream.read()) != -1 && !isInterrupted()) + { + m_out.append((char)c); + } + m_outStream.close(); + } + catch (IOException ioe) + { + log.log(Level.SEVERE, "outReader", ioe); + } + log.fine("outReader - done"); + } // run + }; // m_outReader + + /** Read Out */ + private Thread m_errReader = new Thread() + { + public void run() + { + log.fine("errReader"); + try + { + int c; + while ((c = m_errStream.read()) != -1 && !isInterrupted()) + { + m_err.append((char)c); + } + m_errStream.close(); + } + catch (IOException ioe) + { + log.log(Level.SEVERE, "errReader", ioe); + } + log.fine("errReader - done"); + } // run + }; // m_errReader + + + /** + * Execute it + */ + public void run() + { + log.info(m_cmd); + try + { + m_child = Runtime.getRuntime().exec(m_cmd); + // + m_outStream = m_child.getInputStream(); + m_errStream = m_child.getErrorStream(); + m_inStream = m_child.getOutputStream(); + // + if (checkInterrupted()) + return; + m_outReader.start(); + m_errReader.start(); + + Integer exitValue = null; + while(exitValue == null) + { + // + try + { + Thread.sleep(500); + if (checkInterrupted()) + return; + int i = m_child.exitValue(); + exitValue = new Integer(i); + } + catch (Exception ie) + { + log.log(Level.INFO, "(ie) - " + ie); + } + // ExitValue + log.config("done"); + } + } + catch (IOException ioe) + { + log.log(Level.SEVERE, "(ioe)", ioe); + } + } // run + + /** + * Check if interrupted + * @return true if interrupted + */ + private boolean checkInterrupted() + { + if (isInterrupted()) + { + log.config("interrupted"); + // interrupt child processes + if (m_child != null) + m_child.destroy(); + m_child = null; + if (m_outReader != null && m_outReader.isAlive()) + m_outReader.interrupt(); + m_outReader = null; + if (m_errReader != null && m_errReader.isAlive()) + m_errReader.interrupt(); + m_errReader = null; + // close Streams + if (m_inStream != null) + try { m_inStream.close(); } catch (Exception e) {} + m_inStream = null; + if (m_outStream != null) + try { m_outStream.close(); } catch (Exception e) {} + m_outStream = null; + if (m_errStream != null) + try { m_errStream.close(); } catch (Exception e) {} + m_errStream = null; + // + return true; + } + return false; + } // checkInterrupted + + /** + * Get Out Info + * @return StringBuffer + */ + public StringBuffer getOut() + { + return m_out; + } // getOut + + /** + * Get Err Info + * @return StringBuffer + */ + public StringBuffer getErr() + { + return m_err; + } // getErr + + /** + * Get The process input stream - i.e. we output to it + * @return OutputStream + */ + public OutputStream getInStream() + { + return m_inStream; + } // getInStream + +} // Task diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/window/ADWindow.java b/zkwebui/WEB-INF/src/org/adempiere/webui/window/ADWindow.java index 5ef2dbec14..bb5e691339 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/window/ADWindow.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/window/ADWindow.java @@ -77,10 +77,16 @@ public class ADWindow extends AbstractUIPart windowPanelComponent = windowPanel.createPart(parent); windowPanelComponent.setAttribute("ADWindow", this); windowPanelComponent.setAttribute("desktop.windowno", windowNo); - windowPanel.initPanel(adWindowId, query); - _title = windowPanel.getTitle(); - - return windowPanelComponent; + if (windowPanel.initPanel(adWindowId, query)) + { + _title = windowPanel.getTitle(); + return windowPanelComponent; + } + else + { + windowPanelComponent.detach(); + return null; + } } public Component getComponent() { diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/window/FindWindow.java b/zkwebui/WEB-INF/src/org/adempiere/webui/window/FindWindow.java index 66fddb1e98..8d1e641498 100644 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/window/FindWindow.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/window/FindWindow.java @@ -654,7 +654,7 @@ public class FindWindow extends Window implements EventListener,ValueChangeListe public void onEvent(Event event) throws Exception { - if ("onSelect".equals(event.getName())) + if (Events.ON_SELECT.equals(event.getName())) { if (event.getTarget() instanceof Listbox) { @@ -685,7 +685,7 @@ public class FindWindow extends Window implements EventListener,ValueChangeListe parseUserQuery(userQueries[index]); } } // - else if ("onClick".equals(event.getName())) + else if (Events.ON_CLICK.equals(event.getName())) { // Toolbar Buttons actions if(event.getTarget() instanceof ToolBarButton) @@ -726,6 +726,7 @@ public class FindWindow extends Window implements EventListener,ValueChangeListe } else if("btnCancel".equals(btn.getName())) { + m_isCancel = true; dispose(); } else if ("btnNew".equals(btn.getName())) @@ -757,7 +758,7 @@ public class FindWindow extends Window implements EventListener,ValueChangeListe } } } - else if ("onOK".equals(event.getName())) + else if (Events.ON_OK.equals(event.getName())) { if (winLookupRecord.equals(event.getTarget())) { @@ -1714,5 +1715,12 @@ public class FindWindow extends Window implements EventListener,ValueChangeListe Clients.response(new AuFocus(m_sEditors.get(0).getComponent())); } + /** + * + * @return true if dialog cancel by user, false otherwise + */ + public boolean isCancel() { + return m_isCancel; + } } // FindPanel \ No newline at end of file diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/window/WTask.java b/zkwebui/WEB-INF/src/org/adempiere/webui/window/WTask.java new file mode 100644 index 0000000000..85077e5f5a --- /dev/null +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/window/WTask.java @@ -0,0 +1,193 @@ +/****************************************************************************** + * 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.window; + +import java.util.logging.*; + +import org.adempiere.webui.LayoutUtils; +import org.adempiere.webui.component.ConfirmPanel; +import org.adempiere.webui.component.Window; +import org.adempiere.webui.session.SessionManager; +import org.adempiere.webui.util.OSTask; +import org.compiere.util.*; +import org.compiere.model.*; +import org.zkoss.zk.ui.DesktopUnavailableException; +import org.zkoss.zk.ui.Executions; +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.Div; +import org.zkoss.zul.Html; + +/** + * Application Task + * + * @author Jorg Janke + * @version $Id: ATask.java,v 1.2 2006/07/30 00:51:27 jjanke Exp $ + * + * @author Low Heng Sin + */ +public class WTask extends Window implements EventListener +{ + /** + * Start Application Task + * @param task task model + */ + public static void start (final String title, final MTask task) + { + new WTask(title, task); + } // start + + private MTask m_task; + + private Thread taskThread; + + + /************************************************************************** + * Full Constructor + * @param title title + * @param task task + */ + public WTask (String title, MTask task) + { + super (); + setTitle(title); + try + { + zkInit(); + setAttribute(Window.MODE_KEY, Window.MODE_EMBEDDED); + + // + m_task = task; + if (task.isServerProcess()) + info.setContent("Executing on Server ..."); + else + info.setContent("Executing locally ..."); + + SessionManager.getAppDesktop().showWindow(this); + + Events.echoEvent("executeTask", this, null); + } + catch(Exception e) + { + log.log(Level.SEVERE, task.toString(), e); + } + } // ATask + + + public void executeTask() { + Runnable runnable = new Runnable() { + public void run() { + //get full control of desktop + org.zkoss.zk.ui.Desktop desktop = WTask.this.getDesktop(); + String cmd = Msg.parseTranslation(Env.getCtx(), m_task.getOS_Command()).trim(); + if (cmd == null || cmd.equals("")) + info.setContent("Cannot execute '" + m_task.getOS_Command() + "'"); + OSTask osTask = new OSTask(cmd); + osTask.start(); + + while (true) { + try { + Thread.sleep(500); + Executions.activate(desktop); + try { + StringBuffer sb = new StringBuffer(); + sb.append(osTask.getOut()) + .append("
-----------
") + .append(osTask.getErr()) + .append("
-----------"); + + info.setContent(sb.toString().replace("\n", "
")); + if (!osTask.isAlive()) + { + confirmPanel.getButton(ConfirmPanel.A_CANCEL).setEnabled(false); + confirmPanel.getOKButton().setEnabled(true); + break; + } + } finally{ + //release full control of desktop + Executions.deactivate(desktop); + } + } catch (DesktopUnavailableException e) { + log.log(Level.SEVERE, e.getLocalizedMessage(), e); + } catch (InterruptedException e) { + log.log(Level.WARNING, e.getLocalizedMessage(), e); + osTask.interrupt(); + break; + } + } + } + }; + taskThread = new Thread(runnable); + taskThread.start(); + } + + /** Logger */ + private static CLogger log = CLogger.getCLogger(WTask.class); + + private ConfirmPanel confirmPanel = new ConfirmPanel(true); + private Html info = new Html(); + + /** + * Static Layout + * @throws Exception + */ + private void zkInit() throws Exception + { + Borderlayout layout = new Borderlayout(); + layout.setWidth("100%"); + layout.setHeight("100%"); + layout.setStyle("position: absolute;"); + this.setHeight("100%"); + this.setWidth("100%"); + appendChild(layout); + Center center = new Center(); + layout.appendChild(center); + Div div = new Div(); + div.setStyle("width: 100%; height:100%; overflow: auto"); + div.appendChild(info); + center.appendChild(div); + center.setFlex(true); + + South south = new South(); + layout.appendChild(south); + south.setStyle("border: none"); + south.appendChild(confirmPanel); + // + confirmPanel.addActionListener(this); + confirmPanel.getOKButton().setEnabled(false); + + LayoutUtils.sendDeferLayoutEvent(layout, 100); + } // jbInit + + + /** + * Action Listener + * @param e + */ + public void onEvent(Event e) + { + if (taskThread != null && taskThread.isAlive()) + taskThread.interrupt(); + + SessionManager.getAppDesktop().closeActiveWindow(); + } // actionPerformed + +} // ATask diff --git a/zkwebui/css/default.css.dsp b/zkwebui/css/default.css.dsp index becc9bfb54..3780d88abf 100644 --- a/zkwebui/css/default.css.dsp +++ b/zkwebui/css/default.css.dsp @@ -27,7 +27,16 @@ html,body { .disableFilter img { opacity: 0.2; filter: progid : DXImageTransform . Microsoft . Alpha(opacity = 20); - -moz-opacity: 0.2; + -moz-opacity: 0.2; +} + +.depressed { + border-style: inset; + border-width: 1px; + border-color: #CCCCCC; + background-color: #E4E3DC; + -moz-border-radius: 5px; + padding: 1px 4px 1px 4px; } .header { @@ -56,6 +65,7 @@ html,body { height: 22px; width: 26px; padding: 0px; + display: inline; } .editor-button img {