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
This commit is contained in:
hengsin 2022-03-04 18:03:00 +08:00 committed by GitHub
parent 715dfe8192
commit 89a1d0cd23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 194 additions and 48 deletions

View File

@ -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
;

View File

@ -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
;

View File

@ -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";

View File

@ -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<Event>{
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) {

View File

@ -63,6 +63,10 @@ import org.zkoss.zul.Treerow;
*/
public abstract class AbstractMenuPanel extends Panel implements EventListener<Event> {
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<E
link.setIconSclass("z-icon-Report");
else
link.setImage(ThemeManager.getThemeResource("images/mReport.png"));
treeitem.setAttribute("menu.type", "report");
treeitem.setAttribute(MENU_TYPE_ATTRIBUTE, "report");
}
else if (mChildNode.isProcess() || mChildNode.isTask())
{
@ -182,7 +186,7 @@ public abstract class AbstractMenuPanel extends Panel implements EventListener<E
link.setIconSclass("z-icon-Process");
else
link.setImage(ThemeManager.getThemeResource("images/mProcess.png"));
treeitem.setAttribute("menu.type", "process");
treeitem.setAttribute(MENU_TYPE_ATTRIBUTE, "process");
}
else if (mChildNode.isWorkFlow())
{
@ -190,7 +194,7 @@ public abstract class AbstractMenuPanel extends Panel implements EventListener<E
link.setIconSclass("z-icon-Workflow");
else
link.setImage(ThemeManager.getThemeResource("images/mWorkFlow.png"));
treeitem.setAttribute("menu.type", "workflow");
treeitem.setAttribute(MENU_TYPE_ATTRIBUTE, "workflow");
}
else if (mChildNode.isForm())
{
@ -198,7 +202,7 @@ public abstract class AbstractMenuPanel extends Panel implements EventListener<E
link.setIconSclass("z-icon-Form");
else
link.setImage(ThemeManager.getThemeResource("images/mForm.png"));
treeitem.setAttribute("menu.type", "form");
treeitem.setAttribute(MENU_TYPE_ATTRIBUTE, "form");
}
else if (mChildNode.isInfo())
{
@ -206,7 +210,7 @@ public abstract class AbstractMenuPanel extends Panel implements EventListener<E
link.setIconSclass("z-icon-Info");
else
link.setImage(ThemeManager.getThemeResource("images/mInfo.png"));
treeitem.setAttribute("menu.type", "info");
treeitem.setAttribute(MENU_TYPE_ATTRIBUTE, "info");
}
else // Window
{
@ -214,7 +218,7 @@ public abstract class AbstractMenuPanel extends Panel implements EventListener<E
link.setIconSclass("z-icon-Window");
else
link.setImage(ThemeManager.getThemeResource("images/mWindow.png"));
treeitem.setAttribute("menu.type", "window");
treeitem.setAttribute(MENU_TYPE_ATTRIBUTE, "window");
Toolbarbutton newBtn = createNewButton();
treeCell.appendChild(newBtn);
@ -222,6 +226,7 @@ public abstract class AbstractMenuPanel extends Panel implements EventListener<E
}
treeitem.addEventListener(Events.ON_OK, this);
link.setLabel(mChildNode.getName());
treeitem.setAttribute(MENU_LABEL_ATTRIBUTE, link.getLabel());
link.addEventListener(Events.ON_CLICK, this);
link.setSclass("menu-href");

View File

@ -1,10 +1,14 @@
package org.adempiere.webui.panel;
import java.util.List;
import org.adempiere.webui.theme.ThemeManager;
import org.adempiere.webui.util.TreeItemAction;
import org.adempiere.webui.util.TreeUtils;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.compiere.util.Util;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.IdSpace;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
@ -13,20 +17,26 @@ import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Popup;
import org.zkoss.zul.Tree;
import org.zkoss.zul.Treechildren;
import org.zkoss.zul.Treeitem;
import org.zkoss.zul.Vbox;
public class MenuTreeFilterPanel extends Popup implements EventListener<Event>, 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<Event>,
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<Event>,
{
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<Event>,
{
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<Component> 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))

View File

@ -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<Event> 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);

View File

@ -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)
{

View File

@ -276,7 +276,7 @@ public class TreeSearchPanel extends Panel implements EventListener<Event>, 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<Event>, 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))