org.carewebframework.shell.designer.AddComponent.java Source code

Java tutorial

Introduction

Here is the source code for org.carewebframework.shell.designer.AddComponent.java

Source

/**
 * 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.shell.designer;

import java.util.List;

import org.apache.commons.lang.StringUtils;

import org.carewebframework.api.property.PropertyUtil;
import org.carewebframework.common.StrUtil;
import org.carewebframework.shell.layout.LayoutUtil;
import org.carewebframework.shell.layout.UIElementBase;
import org.carewebframework.shell.layout.UIElementLayout;
import org.carewebframework.shell.layout.UIElementPlugin;
import org.carewebframework.shell.plugins.PluginDefinition;
import org.carewebframework.shell.plugins.PluginRegistry;
import org.carewebframework.ui.zk.PopupDialog;
import org.carewebframework.ui.zk.TreeUtil;
import org.carewebframework.ui.zk.ZKUtil;

import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.HtmlBasedComponent;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Button;
import org.zkoss.zul.Span;
import org.zkoss.zul.Tree;
import org.zkoss.zul.Treeitem;
import org.zkoss.zul.Window;

/**
 * Dialog for adding new component to UI.
 */
public class AddComponent extends Window {

    private static final long serialVersionUID = 1L;

    private static final String ON_FAVORITE = "onFavorite";

    private UIElementBase parentElement;

    private UIElementBase childElement;

    private PluginDefinition definition;

    private Tree tree;

    private Button btnOK;

    private boolean createChild;

    private Treeitem itmFavorites;

    private List<String> favorites;

    private boolean favoritesChanged;

    private final String favoritesCategory = Labels.getLabel("cwf.shell.plugin.category.favorite");

    private final String favoritesAddHint = Labels.getLabel("cwf.shell.designer.add.component.favorite.add.hint");

    private final String favoritesRemoveHint = Labels
            .getLabel("cwf.shell.designer.add.component.favorite.remove.hint");

    private final String noDescriptionHint = Labels
            .getLabel("cwf.shell.designer.add.component.description.missing.hint");

    /**
     * Handles click on item not under favorites category.
     */
    private final EventListener<Event> favoriteListener1 = new EventListener<Event>() {

        @Override
        public void onEvent(Event event) throws Exception {
            Treeitem item = (Treeitem) event.getTarget();
            String path = (String) item.getAttribute("path");
            boolean isFavorite = !(Boolean) item.getAttribute("favorite");
            Treeitem other = (Treeitem) item.getAttribute("other");
            favoritesChanged = true;

            if (isFavorite) {
                favorites.add(path);
                other = addTreeitem((PluginDefinition) item.getValue(), item);
                item.setAttribute("other", other);
            } else {
                favorites.remove(path);
                other.detach();
            }

            setFavoriteStatus(item, isFavorite);
        }
    };

    /**
     * Handles click on item under favorites category.
     */
    private final EventListener<Event> favoriteListener2 = new EventListener<Event>() {

        @Override
        public void onEvent(Event event) throws Exception {
            Treeitem item = (Treeitem) event.getTarget();
            Treeitem other = (Treeitem) item.getAttribute("other");
            Events.sendEvent(ON_FAVORITE, other, null);
        }

    };

    /**
     * Display the add component dialog, presenting a list of candidate plugins that may serve as
     * children to the specified parent element.
     * 
     * @param parentElement Element to serve as parent to the newly created child element.
     * @return The newly created child element, or null if the dialog was cancelled.
     */
    public static UIElementBase newChild(UIElementBase parentElement) {
        return execute(parentElement, true).childElement;
    }

    /**
     * Display the add component dialog, presenting a list of candidate plugins that may serve as
     * children to the specified parent element.
     * 
     * @param parentElement Element to serve as parent to the newly created child element.
     * @return The selected plugin definition, or null if the dialog was cancelled.
     */
    public static PluginDefinition getDefinition(UIElementBase parentElement) {
        return execute(parentElement, false).definition;
    }

    /**
     * Display the add component dialog, presenting a list of candidate plugins that may serve as
     * children to the specified parent element.
     * 
     * @param parentElement Element to serve as parent to the newly created child element.
     * @param createChild If true, the selected element will be created.
     * @return The dialog instance that was created.
     */
    private static AddComponent execute(UIElementBase parentElement, boolean createChild) {
        AddComponent dlg = null;

        try {
            dlg = (AddComponent) PopupDialog.popup(
                    ZKUtil.loadCachedPageDefinition(DesignConstants.RESOURCE_PREFIX + "AddComponent.zul"), null,
                    true, true, false);
            dlg.init(parentElement, createChild);
            dlg.doModal();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return dlg;
    }

    /**
     * Initialize the tree view based with list of plugins that may serve as children to the parent
     * element.
     * 
     * @param parentElement Element to serve as parent to the newly created child element.
     * @param createChild If true, the selected element will be created.
     */
    private void init(UIElementBase parentElement, boolean createChild) {
        this.parentElement = parentElement;
        this.createChild = createChild;
        ZKUtil.wireController(this);
        Treeitem defaultItem = null;
        boolean useDefault = true;
        loadFavorites();

        for (PluginDefinition def : PluginRegistry.getInstance()) {
            if (def.isInternal()) {
                continue;
            }

            Class<? extends UIElementBase> clazz = def.getClazz();

            if (!parentElement.canAcceptChild(clazz)
                    || !UIElementBase.canAcceptParent(clazz, parentElement.getClass())) {
                continue;
            }

            Treeitem item = addTreeitem(def, null);

            if (item == null) {
                continue;
            }

            if (!item.isDisabled()) {
                if (defaultItem == null) {
                    defaultItem = item;
                } else {
                    useDefault = false;
                }
            }
        }

        if (parentElement.canAcceptChild(UIElementLayout.class)) {
            addLayouts(true);
            addLayouts(false);
        }

        TreeUtil.sort(tree);
        ZKUtil.moveChild(itmFavorites, 0);

        if (useDefault && defaultItem != null) {
            defaultItem.setSelected(true);
            onSelect$tree();
        }

        setTitle(StrUtil.formatMessage("@cwf.shell.designer.add.component.title",
                parentElement.getDefinition().getName()));
    }

    private void loadFavorites() {
        try {
            favorites = PropertyUtil.getValues(DesignConstants.DESIGN_FAVORITES_PROPERTY);
        } catch (Exception e) {
            favorites = null;
        }
    }

    private void addLayouts(boolean shared) {
        for (String layout : LayoutUtil.getLayouts(shared)) {
            UIElementLayout ele = new UIElementLayout(layout, shared);
            addTreeitem(ele.getDefinition(), null);
        }
    }

    private Treeitem addTreeitem(PluginDefinition def, Treeitem other) {
        String category = other != null ? favoritesCategory : def.getCategory();

        if (StringUtils.isEmpty(category)) {
            if (UIElementPlugin.class.isAssignableFrom(def.getClazz())) {
                category = Labels.getLabel("cwf.shell.plugin.category._default");
            } else {
                return null;
            }
        }

        String path = category + (category.endsWith("\\") ? "" : "\\") + def.getName();
        boolean isFavorite = other != null || (favorites != null && favorites.contains(path));
        boolean disabled = def.isDisabled() || def.isForbidden();
        Treeitem item = TreeUtil.findNode(tree, path, true);
        item.setValue(def);
        item.setTooltiptext(StringUtils.defaultString(def.getDescription(), noDescriptionHint));

        if (disabled) {
            item.setDisabled(true);
        } else {
            item.getTreerow().addForward(Events.ON_DOUBLE_CLICK, btnOK, Events.ON_CLICK);
        }

        if (favorites != null) {
            Span image = new Span();
            image.setZclass("glyphicon");
            image.setStyle("float:left");
            Component cell = item.getTreerow().getFirstChild();
            cell.insertBefore(image, cell.getFirstChild());
            image.addForward(Events.ON_CLICK, item, ON_FAVORITE);
            item.addEventListener(ON_FAVORITE, other == null ? favoriteListener1 : favoriteListener2);

            if (isFavorite && other == null) {
                other = addTreeitem(def, item);
            }

            item.setAttribute("other", other);
            item.setAttribute("path", path);
            item.setAttribute("image", image);
            setFavoriteStatus(item, isFavorite);
        }
        return item;
    }

    /**
     * Updates the tree item according to the favorite status.
     * 
     * @param item Tree item to update.
     * @param isFavorite If true, the item is a favorite.
     * @return The original image.
     */
    private HtmlBasedComponent setFavoriteStatus(Treeitem item, boolean isFavorite) {
        HtmlBasedComponent image = (HtmlBasedComponent) item.getAttribute("image");
        image.setSclass(isFavorite ? "glyphicon-star text-primary" : "glyphicon-star-empty text-muted");
        image.setTooltiptext(isFavorite ? favoritesRemoveHint : favoritesAddHint);
        item.setAttribute("favorite", isFavorite);
        itmFavorites.setVisible(isFavorite || itmFavorites.getTreechildren().getFirstChild() != null);
        return image;
    }

    /**
     * Returns currently selected plugin definition, or null if none selected.
     * 
     * @return Definition of the currently selected plugin.
     */
    private PluginDefinition selectedPluginDefinition() {
        return (PluginDefinition) (tree.getSelectedItem() == null ? null : tree.getSelectedItem().getValue());
    }

    /**
     * Close dialog without further action.
     */
    public void onClick$btnCancel() {
        onClose();
    }

    /**
     * Create new element based on selected plugin definition, add it to the parent element and
     * close the dialog.
     * 
     * @throws Exception Unspecified exception.
     */
    public void onClick$btnOK() throws Exception {
        definition = selectedPluginDefinition();

        if (definition != null) {
            childElement = createChild ? definition.createElement(parentElement, null) : null;

            if (childElement != null) {
                childElement.bringToFront();
            }

            onClose();
        }
    }

    /**
     * Close the dialog, saving any changes to favorites.
     */
    @Override
    public void onClose() {
        super.onClose();

        if (favoritesChanged) {
            PropertyUtil.saveValues(DesignConstants.DESIGN_FAVORITES_PROPERTY, null, false, favorites);
        }
    }

    /**
     * Update buttons based on current selection.
     */
    public void onSelect$tree() {
        btnOK.setDisabled(selectedPluginDefinition() == null);
    }
}