From 89a1d0cd23a45c1d29a736ff5cd5f3954a230983 Mon Sep 17 00:00:00 2001 From: hengsin Date: Fri, 4 Mar 2022 18:03:00 +0800 Subject: [PATCH] IDEMPIERE-5213 Flat view improvement for menu tree (#1212) * IDEMPIERE-5213 Flat view improvement for menu tree * IDEMPIERE-5213 Flat view improvement for menu tree - fix annotation warning --- .../oracle/202203022014_IDEMPIERE-5213.sql | 22 +++ .../202203022014_IDEMPIERE-5213.sql | 19 +++ .../src/org/compiere/model/MSysConfig.java | 1 + .../webui/apps/MenuSearchController.java | 3 +- .../webui/panel/AbstractMenuPanel.java | 17 +- .../webui/panel/MenuTreeFilterPanel.java | 161 ++++++++++++++---- .../adempiere/webui/panel/MenuTreePanel.java | 11 ++ .../webui/panel/MenuTreeSearchPanel.java | 4 +- .../webui/panel/TreeSearchPanel.java | 4 +- 9 files changed, 194 insertions(+), 48 deletions(-) create mode 100644 migration/iD10/oracle/202203022014_IDEMPIERE-5213.sql create mode 100644 migration/iD10/postgresql/202203022014_IDEMPIERE-5213.sql diff --git a/migration/iD10/oracle/202203022014_IDEMPIERE-5213.sql b/migration/iD10/oracle/202203022014_IDEMPIERE-5213.sql new file mode 100644 index 0000000000..3e9731483a --- /dev/null +++ b/migration/iD10/oracle/202203022014_IDEMPIERE-5213.sql @@ -0,0 +1,22 @@ +-- IDEMPIERE-5213 Flat view improvement for menu tree +SELECT register_migration_script('202203022014_IDEMPIERE-5213.sql') FROM dual; + +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- Mar 2, 2022, 8:14:17 PM MYT +INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200195,0,0,TO_TIMESTAMP('2022-03-02 20:14:17','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2022-03-02 20:14:17','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','ZK_FLAT_VIEW_MENU_TREE','50000','D','S','359e0313-663a-4b3a-9a80-d20eea8c3b54') +; + +-- Mar 2, 2022, 8:15:58 PM MYT +UPDATE AD_SysConfig SET Description='Y/N - Define if the application menu tree default to a single level only, flat structure',Updated=TO_TIMESTAMP('2022-03-02 20:15:58','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_SysConfig_ID=200195 +; + +-- Mar 2, 2022, 8:16:04 PM MYT +UPDATE AD_SysConfig SET Value='N',Updated=TO_TIMESTAMP('2022-03-02 20:16:04','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_SysConfig_ID=200195 +; + +-- Mar 2, 2022, 8:16:08 PM MYT +UPDATE AD_SysConfig SET ConfigurationLevel='C',Updated=TO_TIMESTAMP('2022-03-02 20:16:08','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_SysConfig_ID=200195 +; + diff --git a/migration/iD10/postgresql/202203022014_IDEMPIERE-5213.sql b/migration/iD10/postgresql/202203022014_IDEMPIERE-5213.sql new file mode 100644 index 0000000000..e7ca3a2444 --- /dev/null +++ b/migration/iD10/postgresql/202203022014_IDEMPIERE-5213.sql @@ -0,0 +1,19 @@ +-- IDEMPIERE-5213 Flat view improvement for menu tree +SELECT register_migration_script('202203022014_IDEMPIERE-5213.sql') FROM dual; + +-- Mar 2, 2022, 8:14:17 PM MYT +INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200195,0,0,TO_TIMESTAMP('2022-03-02 20:14:17','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2022-03-02 20:14:17','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','ZK_FLAT_VIEW_MENU_TREE','50000','D','S','359e0313-663a-4b3a-9a80-d20eea8c3b54') +; + +-- Mar 2, 2022, 8:15:58 PM MYT +UPDATE AD_SysConfig SET Description='Y/N - Define if the application menu tree default to a single level only, flat structure',Updated=TO_TIMESTAMP('2022-03-02 20:15:58','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_SysConfig_ID=200195 +; + +-- Mar 2, 2022, 8:16:04 PM MYT +UPDATE AD_SysConfig SET Value='N',Updated=TO_TIMESTAMP('2022-03-02 20:16:04','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_SysConfig_ID=200195 +; + +-- Mar 2, 2022, 8:16:08 PM MYT +UPDATE AD_SysConfig SET ConfigurationLevel='C',Updated=TO_TIMESTAMP('2022-03-02 20:16:08','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_SysConfig_ID=200195 +; + diff --git a/org.adempiere.base/src/org/compiere/model/MSysConfig.java b/org.adempiere.base/src/org/compiere/model/MSysConfig.java index e466c102a1..221d342a7f 100644 --- a/org.adempiere.base/src/org/compiere/model/MSysConfig.java +++ b/org.adempiere.base/src/org/compiere/model/MSysConfig.java @@ -189,6 +189,7 @@ public class MSysConfig extends X_AD_SysConfig public static final String ZK_DESKTOP_SHOW_TAB_LIST_BUTTON = "ZK_DESKTOP_SHOW_TAB_LIST_BUTTON"; public static final String ZK_DESKTOP_TAB_AUTO_SHRINK_TO_FIT = "ZK_DESKTOP_TAB_AUTO_SHRINK_TO_FIT"; public static final String ZK_DESKTOP_TAB_MAX_TITLE_LENGTH = "ZK_DESKTOP_TAB_MAX_TITLE_LENGTH"; + public static final String ZK_FLAT_VIEW_MENU_TREE = "ZK_FLAT_VIEW_MENU_TREE"; public static final String ZK_FOOTER_SERVER_DATETIME_FORMAT = "ZK_FOOTER_SERVER_DATETIME_FORMAT"; public static final String ZK_FOOTER_SERVER_MSG = "ZK_FOOTER_SERVER_MSG"; public static final String ZK_GRID_AFTER_FIND = "ZK_GRID_AFTER_FIND"; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/MenuSearchController.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/MenuSearchController.java index 0f049fdd64..70e281be20 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/MenuSearchController.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/MenuSearchController.java @@ -22,6 +22,7 @@ import org.adempiere.webui.component.ListItem; import org.adempiere.webui.component.Listbox; import org.adempiere.webui.component.ToolBarButton; import org.adempiere.webui.desktop.FavouriteController; +import org.adempiere.webui.panel.AbstractMenuPanel; import org.adempiere.webui.theme.ThemeManager; import org.adempiere.webui.util.TreeItemAction; import org.adempiere.webui.util.TreeNodeAction; @@ -154,7 +155,7 @@ public class MenuSearchController implements EventListener{ item.setImage(image); item.setData(treeItem); list.add(item); - item.setType((String) treeItem.getAttribute("menu.type")); + item.setType((String) treeItem.getAttribute(AbstractMenuPanel.MENU_TYPE_ATTRIBUTE)); } private String getLabel(Treeitem treeItem) { diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/AbstractMenuPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/AbstractMenuPanel.java index d35a850108..8a0d983b9b 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/AbstractMenuPanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/AbstractMenuPanel.java @@ -63,6 +63,10 @@ import org.zkoss.zul.Treerow; */ public abstract class AbstractMenuPanel extends Panel implements EventListener { + public static final String MENU_TYPE_ATTRIBUTE = "menu.type"; + + public static final String MENU_LABEL_ATTRIBUTE = "menu.label"; + /** * */ @@ -174,7 +178,7 @@ public abstract class AbstractMenuPanel extends Panel implements EventListener, IdSpace { + private static final String ORIGINAL_SIBLING = "original.sibling"; + + private static final String FLAT_VIEW_PARENT = "flatView.parent"; + private static final long serialVersionUID = 5884898489357885711L; public static final String MENU_TREE_FILTER_CHECKED_QUEUE = "MENU_TREE_FILTER_CHECKED_QUEUE"; - @SuppressWarnings("unused") private Tree tree; @SuppressWarnings("unused") private TreeSearchPanel searchPanel; + private Checkbox flatView; + public MenuTreeFilterPanel(Tree tree, TreeSearchPanel panel) { super(); this.tree = tree; @@ -94,33 +104,43 @@ public class MenuTreeFilterPanel extends Popup implements EventListener, info.addEventListener(Events.ON_CHECK, this); box.appendChild(info); - Checkbox single = new Checkbox(); - single.setLabel(Msg.getMsg(Env.getCtx(), "FlatView")); - single.setId("flatView"); - single.setChecked(false); - single.addEventListener(Events.ON_CHECK, this); - box.appendChild(single); + flatView = new Checkbox(); + flatView.setLabel(Msg.getMsg(Env.getCtx(), "FlatView")); + flatView.setId("flatView"); + flatView.setChecked(false); + flatView.addEventListener(Events.ON_CHECK, this); + box.appendChild(flatView); appendChild(box); } public void onEvent(Event event) throws Exception { final Checkbox chk = (Checkbox) event.getTarget(); -/* if ("flatView".equals(chk.getId())) - toggleFlatView(tree, chk); - else - toggle(tree, chk); - if (searchPanel != null) - searchPanel.refreshSearchList(); - tree.invalidate(); -*/ EventQueues.lookup(MENU_TREE_FILTER_CHECKED_QUEUE, EventQueues.DESKTOP, true).publish(new Event(Events.ON_CHECK, null, chk)); } + /** + * switch menu tree to flat view + */ + public void switchToFlatView() { + if (!flatView.isChecked()) { + flatView.setChecked(true); + toggleFlatView(tree, flatView); + } + } + + /** + * + * @param tree + * @param chk checkbox for flat view toggle + */ public static void toggleFlatView(Tree tree, final Checkbox chk) { + final Treeitem[] lastVisitedItem = new Treeitem[1]; + final Treeitem[] lastVisitedParent = new Treeitem[1]; TreeUtils.traverse(tree, new TreeItemAction() { public void run(Treeitem treeItem) { - if (treeItem.getAttribute("menu.type") == null) + Treeitem currentParent = treeItem.getParentItem(); + if (treeItem.getAttribute(AbstractMenuPanel.MENU_TYPE_ATTRIBUTE) == null) { if (chk.isChecked()) { @@ -133,6 +153,13 @@ public class MenuTreeFilterPanel extends Popup implements EventListener, { treeItem.setVisible(true); } + if (lastVisitedParent[0] == treeItem.getParentItem()) + { + if (lastVisitedItem[0] != null && lastVisitedItem[0].getAttribute(ORIGINAL_SIBLING) == null) + { + lastVisitedItem[0].setAttribute(ORIGINAL_SIBLING, treeItem); + } + } } else { @@ -140,59 +167,119 @@ public class MenuTreeFilterPanel extends Popup implements EventListener, { if (treeItem.getParentItem() != null && !treeItem.getParentItem().isVisible()) { - StringBuilder label = new StringBuilder(treeItem.getLabel()); - treeItem.setAttribute("flatView.label", treeItem.getLabel()); Treeitem parent = treeItem.getParentItem(); - treeItem.setAttribute("flatView.parent", parent); + treeItem.setAttribute(FLAT_VIEW_PARENT, parent); while(parent != null) { if (parent.isVisible()) { + if (lastVisitedParent[0] == treeItem.getParentItem()) + { + if (lastVisitedItem[0] != null && lastVisitedItem[0].getAttribute(ORIGINAL_SIBLING) == null) + { + lastVisitedItem[0].setAttribute(ORIGINAL_SIBLING, treeItem); + } + } treeItem.detach(); - parent.getTreechildren().appendChild(treeItem); + parent.getTreechildren().insertBefore(treeItem, findFlatViewSibling(parent.getTreechildren(), treeItem)); break; } - //not working with search - /* - String t = parent.getLabel(); - label.insert(0, " > "); - label.insert(0, t); - */ parent = parent.getParentItem(); } - treeItem.setLabel(label.toString()); } else { Treeitem parent = treeItem.getParentItem(); if (parent != null) - parent.getTreechildren().appendChild(treeItem); + { + if (lastVisitedParent[0] == treeItem.getParentItem()) + { + if (lastVisitedItem[0] != null && lastVisitedItem[0].getAttribute(ORIGINAL_SIBLING) == null) + { + lastVisitedItem[0].setAttribute(ORIGINAL_SIBLING, treeItem); + } + } + treeItem.detach(); + parent.getTreechildren().insertBefore(treeItem, findFlatViewSibling(parent.getTreechildren(), treeItem)); + } } } else { - if (treeItem.getAttribute("flatView.parent") != null) + if (treeItem.getAttribute(FLAT_VIEW_PARENT) != null) { - Treeitem parent = (Treeitem) treeItem.getAttribute("flatView.parent"); - String label = (String) treeItem.getAttribute("flatView.label"); - treeItem.setLabel(label); + Treeitem parent = (Treeitem) treeItem.getAttribute(FLAT_VIEW_PARENT); treeItem.detach(); - parent.getTreechildren().appendChild(treeItem); - treeItem.removeAttribute("flatView.parent"); - treeItem.removeAttribute("flatView.label"); + Treeitem sibling = (Treeitem) treeItem.getAttribute(ORIGINAL_SIBLING); + if (sibling != null) + { + reattachSibling(parent.getTreechildren(), sibling); + } + parent.getTreechildren().insertBefore(treeItem, sibling); + treeItem.removeAttribute(FLAT_VIEW_PARENT); + } + else + { + Treeitem parent = treeItem.getParentItem(); + Treeitem sibling = (Treeitem) treeItem.getAttribute(ORIGINAL_SIBLING); + if (sibling != null) + { + reattachSibling(parent.getTreechildren(), sibling); + } + parent.getTreechildren().insertBefore(treeItem, sibling); } } } + lastVisitedItem[0] = treeItem; + lastVisitedParent[0] = currentParent; } }); } + private static void reattachSibling(Treechildren treechildren, Treeitem treeItem) { + Treeitem sibling = (Treeitem) treeItem.getAttribute(ORIGINAL_SIBLING); + if (sibling != null) + { + reattachSibling(treechildren, sibling); + } + treechildren.insertBefore(treeItem, sibling); + } + + private static Component findFlatViewSibling(Treechildren treechildren, Treeitem treeItem) { + List childrens = treechildren.getChildren(); + if (childrens.isEmpty()) { + return null; + } + String menuType = (String) treeItem.getAttribute(AbstractMenuPanel.MENU_TYPE_ATTRIBUTE); + String label = (String) treeItem.getAttribute(AbstractMenuPanel.MENU_LABEL_ATTRIBUTE); + for(int i = 0; i < childrens.size(); i++) { + Component child = childrens.get(i); + if (child instanceof Treeitem) { + Treeitem ti = (Treeitem) child; + String tiType = (String) ti.getAttribute(AbstractMenuPanel.MENU_TYPE_ATTRIBUTE); + if (tiType == null) + continue; + if (menuType.equals(tiType)) { + String tiLabel = (String) ti.getAttribute(AbstractMenuPanel.MENU_LABEL_ATTRIBUTE); + if (Util.isEmpty(tiLabel)) + continue; + if (label.compareTo(tiLabel) < 0) { + return child; + } + } else if (menuType.compareTo(tiType) < 0) { + return child; + } + } + } + return null; + } + public static void toggle(Tree tree, final Checkbox chk) { TreeUtils.traverse(tree, new TreeItemAction() { public void run(Treeitem treeItem) { - if (treeItem.getAttribute("menu.type") != null) + if (treeItem.getAttribute(AbstractMenuPanel.MENU_TYPE_ATTRIBUTE) != null) { - String menuType = (String) treeItem.getAttribute("menu.type"); + String menuType = (String) treeItem.getAttribute(AbstractMenuPanel.MENU_TYPE_ATTRIBUTE); if (chk.isChecked()) { if (chk.getId().equals(menuType)) diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/MenuTreePanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/MenuTreePanel.java index 632189ce3b..bfd59f87bb 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/MenuTreePanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/MenuTreePanel.java @@ -17,6 +17,7 @@ package org.adempiere.webui.panel; import org.adempiere.webui.component.ToolBarButton; import org.adempiere.webui.theme.ThemeManager; import org.adempiere.webui.util.TreeUtils; +import org.compiere.model.MSysConfig; import org.compiere.model.MUser; import org.compiere.util.Env; import org.compiere.util.Msg; @@ -51,11 +52,16 @@ public class MenuTreePanel extends AbstractMenuPanel private Toolbarbutton filterBtn; private EventListener listener; + /** + * + * @param parent + */ public MenuTreePanel(Component parent) { super(parent); } + @Override protected void init() { super.init(); @@ -84,8 +90,12 @@ public class MenuTreePanel extends AbstractMenuPanel } }; EventQueues.lookup(MenuTreeFilterPanel.MENU_TREE_FILTER_CHECKED_QUEUE, EventQueues.DESKTOP, true).subscribe(listener); + + if (MSysConfig.getBooleanValue(MSysConfig.ZK_FLAT_VIEW_MENU_TREE, false, Env.getAD_Client_ID(Env.getCtx()))) + filterPanel.switchToFlatView(); } + @Override protected void initComponents() { super.initComponents(); @@ -119,6 +129,7 @@ public class MenuTreePanel extends AbstractMenuPanel toolbar.appendChild(filterBtn); } + @Override public void onEvent(Event event) { super.onEvent(event); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/MenuTreeSearchPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/MenuTreeSearchPanel.java index 5a49982afb..403598f400 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/MenuTreeSearchPanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/MenuTreeSearchPanel.java @@ -160,14 +160,14 @@ public class MenuTreeSearchPanel extends TreeSearchPanel { continue; if (isNew) { - if (!"window".equals(treeItem.getAttribute("menu.type"))) { + if (!"window".equals(treeItem.getAttribute(AbstractMenuPanel.MENU_TYPE_ATTRIBUTE))) { continue; } } valueList.add(getLabel(treeItem)); descriptionList.add(treeItem.getTooltiptext()); - typeList.add(String.valueOf(treeItem.getAttribute("menu.type"))); + typeList.add(String.valueOf(treeItem.getAttribute(AbstractMenuPanel.MENU_TYPE_ATTRIBUTE))); String image = getImage(treeItem); if (image == null || image.length() == 0) { diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/TreeSearchPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/TreeSearchPanel.java index 32de9bddcd..1f1f384468 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/TreeSearchPanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/TreeSearchPanel.java @@ -276,7 +276,7 @@ public class TreeSearchPanel extends Panel implements EventListener, Tree protected void addTreeItem(Treeitem treeItem) { - StringBuilder key = new StringBuilder(getLabel(treeItem)).append(".").append(treeItem.getAttribute("menu.type")); + StringBuilder key = new StringBuilder(getLabel(treeItem)).append(".").append(treeItem.getAttribute(AbstractMenuPanel.MENU_TYPE_ATTRIBUTE)); treeNodeItemMap.put(key.toString(), treeItem); } @@ -331,7 +331,7 @@ public class TreeSearchPanel extends Panel implements EventListener, Tree { Treeitem treeItem = (Treeitem) value; treeValues[i] = getLabel(treeItem); - treeTypes[i]= String.valueOf(treeItem.getAttribute("menu.type")); + treeTypes[i]= String.valueOf(treeItem.getAttribute(AbstractMenuPanel.MENU_TYPE_ATTRIBUTE)); treeDescription[i] = treeItem.getTooltiptext(); treeImages[i] = getImage(treeItem); if ((treeImages[i] == null || treeImages[i].trim().length() == 0) && isFolder(treeItem))