<commit_before>/**
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 * 
 * This Source Code Form is also subject to the terms of the Health-Related Additional
 * Disclaimer of Warranty and Limitation of Liability available at
 * http://www.carewebframework.org/licensing/disclaimer.
 */
package org.carewebframework.ui.zk;

import java.util.List;

import org.carewebframework.common.MiscUtil;
import org.carewebframework.ui.zk.ZKUtil.MatchMode;

import org.zkoss.zk.ui.Component;
import org.zkoss.zul.Menu;
import org.zkoss.zul.Menubar;
import org.zkoss.zul.Menuitem;
import org.zkoss.zul.Menupopup;
import org.zkoss.zul.impl.LabelImageElement;

/**
 * Useful ZK menu functions.
 */
public class MenuUtil {
    
    private static final String[] NULL_PATH = { "null" };
    
    /**
     * Adds a ZK menu item to the main menu.
     * 
     * @param path Determines the position of the menu item in the menu tree.
     * @param menuItem The menu item to be added. If null, a new menu item is created.
     * @param menubar The menubar to receive the new menu item.
     * @param insertBefore The sibling before which the new menu item is to be inserted. If null, or
     *            the specified component is not at the same level as the item to be added, the new
     *            menu item will be added after any existing siblings.
     * @return The menu item added. If the menuItem parameter was not null, this is the value
     *         returned. Otherwise, it is a reference to the newly created menu item.
     */
    public static Menuitem addMenuItem(String path, Menuitem menuItem, Menubar menubar, Component insertBefore) {
        return addMenuOrMenuItem(path, menuItem, menubar, insertBefore, Menuitem.class);
    }
    
    /**
     * Adds a ZK menu to the main menu.
     * 
     * @param path Determines the position of the menu in the menu tree.
     * @param menu The menu to be added. If null, a new menu is created.
     * @param menubar The menubar to receive the new menu.
     * @param insertBefore The sibling before which the new menu is to be inserted. If null, or the
     *            specified component is not at the same level as the menu to be added, the new menu
     *            will be added after any existing siblings.
     * @return The menu added. If the menu parameter was not null, this is the value returned.
     *         Otherwise, it is a reference to the newly created menu.
     */
    public static Menu addMenu(String path, Menu menu, Menubar menubar, Component insertBefore) {
        return addMenuOrMenuItem(path, menu, menubar, insertBefore, Menu.class);
    }
    
    /**
     * Adds an element (menu or menu item) to the main menu.
     * 
     * @param path Determines the position of the element in the menu tree.
     * @param ele The element to be added. If null, a new element of the specified type is created.
     * @param menubar The menubar to receive the new element.
     * @param insertBefore The sibling before which the new element is to be inserted. If null, or
     *            the specified component is not at the same level as the element to be added, the
     *            new element will be added after any existing siblings.
     * @param clazz Class of the element to be added.
     * @return The element that was added.
     */
    public static <T extends LabelImageElement> T addMenuOrMenuItem(String path, T ele, Menubar menubar,
                                                                    Component insertBefore, Class<T> clazz) {
        String pcs[] = path == null ? NULL_PATH : path.split(Constants.PATH_DELIMITER_REGEX);
        int last = pcs.length - 1;
        Component parent = menubar;
        
        if (ele == null) {
            try {
                ele = clazz.newInstance();
            } catch (Exception e) {
                throw MiscUtil.toUnchecked(e);
            }
        }
        
        for (int i = 0; i < last; i++) {
            parent = findMenu(parent, pcs[i], insertBefore);
        }
        
        ele.setLabel(pcs[last]);
        parent = getRealParent(parent);
        
        if (insertBefore != null && parent == insertBefore.getParent()) {
            parent.insertBefore(ele, insertBefore);
        } else {
            parent.appendChild(ele);
        }
        
        return ele;
    }
    
    /**
     * Returns a parent that can receive a menu item.
     * 
     * @param parent The parent component.
     * @return The true parent.
     */
    private static Component getRealParent(Component parent) {
        if (!(parent instanceof Menu)) {
            return parent;
        }
        
        Menupopup menuPopup = ZKUtil.findChild(parent, Menupopup.class);
        
        if (menuPopup == null) {
            menuPopup = new Menupopup();
            menuPopup.setParent(parent);
        }
        
        return menuPopup;
    }
    
    /**
     * Recursively remove empty menu container elements. This is done after removing menu items to
     * keep the menu structure lean.
     * 
     * @param parent The starting menu container.
     */
    public static void pruneMenus(Component parent) {
        while (parent != null && !(parent instanceof Menubar)) {
            if (parent.getChildren().isEmpty()) {
                Component newParent = parent.getParent();
                parent.detach();
                parent = newParent;
            } else {
                break;
            }
        }
    }
    
    /**
     * Creates a menu based on the given path.
     * 
     * @param menubar The menu bar that will contain the menu.
     * @param path The menu path.
     * @param insertBefore If not null, the new menu is inserted before this one. If null, the menu
     *            is appended.
     * @return The menu corresponding to the specified path. All missing menu nodes are created
     *         automatically.
     */
    public static Menu createMenu(Menubar menubar, String path, Component insertBefore) {
        String[] pcs = path.split(Constants.PATH_DELIMITER_REGEX);
        Menu menu = null;
        
        for (int i = 0; i < pcs.length; i++) {
            menu = findMenu(menu == null ? menubar : menu, pcs[i], insertBefore);
        }
        <commit_msg>Mark createMenu as deprecated.<commit_after>/**
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 * 
 * This Source Code Form is also subject to the terms of the Health-Related Additional
 * Disclaimer of Warranty and Limitation of Liability available at
 * http://www.carewebframework.org/licensing/disclaimer.
 */
package org.carewebframework.ui.zk;

import java.util.List;

import org.carewebframework.common.MiscUtil;
import org.carewebframework.ui.zk.ZKUtil.MatchMode;

import org.zkoss.zk.ui.Component;
import org.zkoss.zul.Menu;
import org.zkoss.zul.Menubar;
import org.zkoss.zul.Menuitem;
import org.zkoss.zul.Menupopup;
import org.zkoss.zul.impl.LabelImageElement;

/**
 * Useful ZK menu functions.
 */
public class MenuUtil {
    
    private static final String[] NULL_PATH = { "null" };
    
    /**
     * Adds a ZK menu item to the main menu.
     * 
     * @param path Determines the position of the menu item in the menu tree.
     * @param menuItem The menu item to be added. If null, a new menu item is created.
     * @param menubar The menubar to receive the new menu item.
     * @param insertBefore The sibling before which the new menu item is to be inserted. If null, or
     *            the specified component is not at the same level as the item to be added, the new
     *            menu item will be added after any existing siblings.
     * @return The menu item added. If the menuItem parameter was not null, this is the value
     *         returned. Otherwise, it is a reference to the newly created menu item.
     */
    public static Menuitem addMenuItem(String path, Menuitem menuItem, Menubar menubar, Component insertBefore) {
        return addMenuOrMenuItem(path, menuItem, menubar, insertBefore, Menuitem.class);
    }
    
    /**
     * Adds a ZK menu to the main menu.
     * 
     * @param path Determines the position of the menu in the menu tree.
     * @param menu The menu to be added. If null, a new menu is created.
     * @param menubar The menubar to receive the new menu.
     * @param insertBefore The sibling before which the new menu is to be inserted. If null, or the
     *            specified component is not at the same level as the menu to be added, the new menu
     *            will be added after any existing siblings.
     * @return The menu added. If the menu parameter was not null, this is the value returned.
     *         Otherwise, it is a reference to the newly created menu.
     */
    public static Menu addMenu(String path, Menu menu, Menubar menubar, Component insertBefore) {
        return addMenuOrMenuItem(path, menu, menubar, insertBefore, Menu.class);
    }
    
    /**
     * Adds an element (menu or menu item) to the main menu.
     * 
     * @param path Determines the position of the element in the menu tree.
     * @param ele The element to be added. If null, a new element of the specified type is created.
     * @param menubar The menubar to receive the new element.
     * @param insertBefore The sibling before which the new element is to be inserted. If null, or
     *            the specified component is not at the same level as the element to be added, the
     *            new element will be added after any existing siblings.
     * @param clazz Class of the element to be added.
     * @return The element that was added.
     */
    public static <T extends LabelImageElement> T addMenuOrMenuItem(String path, T ele, Menubar menubar,
                                                                    Component insertBefore, Class<T> clazz) {
        String pcs[] = path == null ? NULL_PATH : path.split(Constants.PATH_DELIMITER_REGEX);
        int last = pcs.length - 1;
        Component parent = menubar;
        
        if (ele == null) {
            try {
                ele = clazz.newInstance();
            } catch (Exception e) {
                throw MiscUtil.toUnchecked(e);
            }
        }
        
        for (int i = 0; i < last; i++) {
            parent = findMenu(parent, pcs[i], insertBefore);
        }
        
        ele.setLabel(pcs[last]);
        parent = getRealParent(parent);
        
        if (insertBefore != null && parent == insertBefore.getParent()) {
            parent.insertBefore(ele, insertBefore);
        } else {
            parent.appendChild(ele);
        }
        
        return ele;
    }
    
    /**
     * Returns a parent that can receive a menu item.
     * 
     * @param parent The parent component.
     * @return The true parent.
     */
    private static Component getRealParent(Component parent) {
        if (!(parent instanceof Menu)) {
            return parent;
        }
        
        Menupopup menuPopup = ZKUtil.findChild(parent, Menupopup.class);
        
        if (menuPopup == null) {
            menuPopup = new Menupopup();
            menuPopup.setParent(parent);
        }
        
        return menuPopup;
    }
    
    /**
     * Recursively remove empty menu container elements. This is done after removing menu items to
     * keep the menu structure lean.
     * 
     * @param parent The starting menu container.
     */
    public static void pruneMenus(Component parent) {
        while (parent != null && !(parent instanceof Menubar)) {
            if (parent.getChildren().isEmpty()) {
                Component newParent = parent.getParent();
                parent.detach();
                parent = newParent;
            } else {
                break;
            }
        }
    }
    
    /**
     * Creates a menu based on the given path.
     * 
     * @param menubar The menu bar that will contain the menu.
     * @param path The menu path.
     * @param insertBefore If not null, the new menu is inserted before this one. If null, the menu
     *            is appended.
     * @return The menu corresponding to the specified path. All missing menu nodes are created
     *         automatically.
     * @deprecated Use FindMenu instead
     */
    @Deprecated
    public static Menu createMenu(Menubar menubar, String path, Component insertBefore) {
        String[] pcs = path.split(Constants.PATH_DELIMITER_REGEX);
        Menu menu = null;
        
        for (int i = 0; i < pcs.length; i++) {
            menu = findMenu(menu == null ? menubar : menu, pcs[i], insertBefore);
        }
        
{'fraction_non_alphanumeric': 0.0778354911233429, 'fraction_numerical': 0.001085355453911156, 'mean_word_length': 2.0772900763358777, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '265718', 'n_tokens_mistral': 3502, 'n_tokens_neox': 3466, 'n_words': 1408}