All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nextapp.echo2.extras.webcontainer.AbstractMenuPeer Maven / Gradle / Ivy

Go to download

Echo2 bundled with Echo2_Extras, Echo2_FileTransfer and echopointing and various improvements/bugfixes

There is a newer version: 2.0.4
Show newest version
package nextapp.echo2.extras.webcontainer;

import java.util.StringTokenizer;

import nextapp.echo2.app.Component;
import nextapp.echo2.app.ImageReference;
import nextapp.echo2.app.ResourceImageReference;
import nextapp.echo2.app.update.ServerComponentUpdate;
import nextapp.echo2.extras.app.menu.AbstractMenuComponent;
import nextapp.echo2.extras.app.menu.ItemModel;
import nextapp.echo2.extras.app.menu.MenuModel;
import nextapp.echo2.extras.app.menu.MenuStateModel;
import nextapp.echo2.extras.app.menu.OptionModel;
import nextapp.echo2.extras.app.menu.RadioOptionModel;
import nextapp.echo2.extras.app.menu.SeparatorModel;
import nextapp.echo2.extras.app.menu.ToggleOptionModel;
import nextapp.echo2.webcontainer.ActionProcessor;
import nextapp.echo2.webcontainer.ComponentSynchronizePeer;
import nextapp.echo2.webcontainer.ContainerInstance;
import nextapp.echo2.webcontainer.PartialUpdateManager;
import nextapp.echo2.webcontainer.RenderContext;
import nextapp.echo2.webcontainer.image.ImageRenderSupport;
import nextapp.echo2.webcontainer.image.ImageTools;
import nextapp.echo2.webrender.ServerMessage;
import nextapp.echo2.webrender.Service;
import nextapp.echo2.webrender.WebRenderServlet;
import nextapp.echo2.webrender.servermessage.DomUpdate;
import nextapp.echo2.webrender.service.JavaScriptService;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

abstract class AbstractMenuPeer 
implements ActionProcessor, ComponentSynchronizePeer, ImageRenderSupport {
    
    static final String IMAGE_PREFIX = "/nextapp/echo2/extras/webcontainer/resource/image/";
    static final ImageReference DEFAULT_ICON_SUBMENU_LEFT = new ResourceImageReference(IMAGE_PREFIX + "ArrowLeft.gif");
    static final ImageReference DEFAULT_ICON_SUBMENU_RIGHT = new ResourceImageReference(IMAGE_PREFIX + "ArrowRight.gif");
    static final ImageReference DEFAULT_ICON_TOGGLE_OFF = new ResourceImageReference(IMAGE_PREFIX + "ToggleOff.gif");
    static final ImageReference DEFAULT_ICON_TOGGLE_ON = new ResourceImageReference(IMAGE_PREFIX + "ToggleOn.gif");
    static final ImageReference DEFAULT_ICON_RADIO_OFF = new ResourceImageReference(IMAGE_PREFIX + "RadioOff.gif");
    static final ImageReference DEFAULT_ICON_RADIO_ON = new ResourceImageReference(IMAGE_PREFIX + "RadioOn.gif");
    
    static final String IMAGE_ID_BACKGROUND = "background";
    static final String IMAGE_ID_DISABLED_BACKGROUND = "disabledBackground";
    static final String IMAGE_ID_MENU_BACKGROUND = "menuBackground";
    static final String IMAGE_ID_MENU_ITEM_PREFIX = "menuItem.";
    static final String IMAGE_ID_SELECTION_BACKGROUND = "selectionBackground";
    
    static final String IMAGE_ID_SUBMENU_LEFT = "submenuLeft";
    static final String IMAGE_ID_SUBMENU_RIGHT = "submenuRight";
    
    static final String IMAGE_ID_TOGGLE_OFF = "toggleOff";
    static final String IMAGE_ID_TOGGLE_ON = "toggleOn";
    static final String IMAGE_ID_RADIO_OFF = "radioOff";
    static final String IMAGE_ID_RADIO_ON = "radioOn";

    /**
     * Service to provide supporting JavaScript library.
     */
    public static final Service MENU_SERVICE = JavaScriptService.forResource("Echo2Extras.Menu",
            "/nextapp/echo2/extras/webcontainer/resource/js/Menu.js");

    static {
        WebRenderServlet.getServiceRegistry().add(MENU_SERVICE);
    }
    
    /**
     * The PartialUpdateManager for this synchronization peer.
     */
    PartialUpdateManager partialUpdateManager;
    
    /**
     * Default constructor.
     */
    public AbstractMenuPeer() {
        partialUpdateManager = new PartialUpdateManager();
    }
    
    /**
     * @see nextapp.echo2.webcontainer.ComponentSynchronizePeer#getContainerId(nextapp.echo2.app.Component)
     */
    public String getContainerId(Component component) {
        throw new UnsupportedOperationException("Component does not support children.");
    }
    
    /**
     * @see nextapp.echo2.webcontainer.image.ImageRenderSupport#getImage(nextapp.echo2.app.Component, java.lang.String)
     */
    public ImageReference getImage(Component component, String imageId) {
        if (IMAGE_ID_SUBMENU_RIGHT.equals(imageId)) {
            return DEFAULT_ICON_SUBMENU_RIGHT;
        } else if (IMAGE_ID_SUBMENU_LEFT.equals(imageId)) {
            return DEFAULT_ICON_SUBMENU_LEFT;
        } else if (IMAGE_ID_TOGGLE_OFF.equals(imageId)) {
            return DEFAULT_ICON_TOGGLE_OFF;
        } else if (IMAGE_ID_TOGGLE_ON.equals(imageId)) {
            return DEFAULT_ICON_TOGGLE_ON;
        } else if (IMAGE_ID_RADIO_OFF.equals(imageId)) {
            return DEFAULT_ICON_RADIO_OFF;
        } else if (IMAGE_ID_RADIO_ON.equals(imageId)) {
            return DEFAULT_ICON_RADIO_ON;
        } else if (imageId.startsWith(IMAGE_ID_MENU_ITEM_PREFIX)) {
            String itemPath = imageId.substring(IMAGE_ID_MENU_ITEM_PREFIX.length());
            ItemModel itemModel = getItemModel((AbstractMenuComponent) component, itemPath);
            if (itemModel instanceof MenuModel) {
                return ((MenuModel) itemModel).getIcon();
            } else if (itemModel instanceof OptionModel) {
                return ((OptionModel) itemModel).getIcon();
            } else {
                return null;
            }
        } else {
            return null;
        }
    }
    
    ItemModel getItemModelById(AbstractMenuComponent menu, String id) {
        return getItemModelById(menu.getModel(), id);
    }
    
    private ItemModel getItemModelById(MenuModel menuModel, String id) {
        int size = menuModel.getItemCount();
        for (int i = 0; i < size; ++i) {
            ItemModel itemModel = menuModel.getItem(i);
            if (id.equals(itemModel.getId())) {
                return itemModel;
            }
            if (itemModel instanceof MenuModel) {
                itemModel = getItemModelById((MenuModel) itemModel, id);
                if (itemModel != null) {
                    return itemModel;
                }
            }
        }
        return null;
    }
    
    ItemModel getItemModel(AbstractMenuComponent menu, String itemPath) {
        ItemModel itemModel = menu.getModel();
        StringTokenizer st = new StringTokenizer(itemPath, ".");
        while (st.hasMoreTokens()) {
            int index = Integer.parseInt(st.nextToken());
            itemModel = ((MenuModel) itemModel).getItem(index);
        }
        return itemModel;
    }

    String getItemPath(MenuModel menuModel, ItemModel targetItemModel) {
        StringBuffer out = new StringBuffer();
        getItemPath(menuModel, targetItemModel, out);
        return out.length() == 0 ? null : out.toString();
    }
    
    void getItemPath(MenuModel menuModel, ItemModel targetItemModel, StringBuffer out) {
        int itemCount = menuModel.getItemCount();
        for (int i = 0; i < itemCount; ++i) {
            ItemModel currentItemModel = menuModel.getItem(i);
            if (targetItemModel.equals(currentItemModel)) {
                out.append(i);
                return;
            }
            if (currentItemModel instanceof MenuModel) {
                getItemPath((MenuModel) currentItemModel, targetItemModel, out); 
            }
            if (out.length() != 0) {
                out.insert(0, i + ".");
                return;
            }
        }
    }
    
    /**
     * @see nextapp.echo2.webcontainer.ActionProcessor#processAction(nextapp.echo2.webcontainer.ContainerInstance, 
     *      nextapp.echo2.app.Component, org.w3c.dom.Element)
     */
    public void processAction(ContainerInstance ci, Component component, Element element) {
        AbstractMenuComponent menu = (AbstractMenuComponent) component;
        String actionName = element.getAttribute(ActionProcessor.ACTION_NAME);
        String actionValue = element.getAttribute(ActionProcessor.ACTION_VALUE);
        if ("select".equals(actionName)) {
            ItemModel itemModel = getItemModel((AbstractMenuComponent) component, actionValue);
            if (!(itemModel instanceof MenuModel || itemModel instanceof OptionModel)) {
                // Should not occur unless client input tampered with.
                return;
            }
            ci.getUpdateManager().getClientUpdateManager().setComponentAction(menu, AbstractMenuComponent.INPUT_SELECT, itemModel);
        }
    }
    
    /**
     * @see nextapp.echo2.webcontainer.ComponentSynchronizePeer#renderAdd(nextapp.echo2.webcontainer.RenderContext, 
     *      nextapp.echo2.app.update.ServerComponentUpdate, java.lang.String, nextapp.echo2.app.Component)
     */
    public void renderAdd(RenderContext rc, ServerComponentUpdate update, String targetId, Component component) {
        ServerMessage serverMessage = rc.getServerMessage();
        serverMessage.addLibrary(ExtrasUtil.JS_EXTRAS_UTIL_SERVICE.getId());
        serverMessage.addLibrary(MENU_SERVICE.getId());
        AbstractMenuComponent menu = (AbstractMenuComponent) component;
        renderInitDirective(rc, menu, targetId);
    }
    
    /**
     * @see nextapp.echo2.webcontainer.ComponentSynchronizePeer#renderDispose(
     *      nextapp.echo2.webcontainer.RenderContext, nextapp.echo2.app.update.ServerComponentUpdate, nextapp.echo2.app.Component)
     */
    public void renderDispose(RenderContext rc, ServerComponentUpdate update, Component component) {
        ServerMessage serverMessage = rc.getServerMessage();
        serverMessage.addLibrary(ExtrasUtil.JS_EXTRAS_UTIL_SERVICE.getId());
        serverMessage.addLibrary(MENU_SERVICE.getId());
        renderDisposeDirective(rc, (AbstractMenuComponent) component);
    }

    abstract void renderInitDirective(RenderContext rc, Component component, String targetId);
    
    abstract void renderDisposeDirective(RenderContext rc, Component component);
    
    /**
     * Renders an XML representation of a MenuModel to the 
     * ServerMessage.  This method is invoked recursively to render
     * hierarchies of menus.
     * 
     * @param rc the relevant RenderContext
     * @param menuModel the MenuModel to render
     * @param parentElement the parent Element, either the 'init'
     *        element or the containing 'menu' element
     */
    void renderModel(RenderContext rc, AbstractMenuComponent menu, MenuModel menuModel, Element parentElement) {
        Document document = rc.getServerMessage().getDocument();
        Element menuModelElement = document.createElement("menu");

        MenuStateModel stateModel = menu.getStateModel();
        
        if (menuModel.getText() != null) {
            menuModelElement.setAttribute("text", menuModel.getText());
        }
        if (menuModel.getIcon() != null) {
            String itemPath = getItemPath(menu.getModel(), menuModel);
            menuModelElement.setAttribute("icon", ImageTools.getUri(rc, this, menu, IMAGE_ID_MENU_ITEM_PREFIX + itemPath));
        }
        if (menuModel.getId() != null && !stateModel.isEnabled(menuModel.getId())) {
            menuModelElement.setAttribute("enabled", "false");
        }

        int length = menuModel.getItemCount();
        for (int i = 0; i < length; ++i) {
            ItemModel itemModel = menuModel.getItem(i);
            if (itemModel instanceof MenuModel) {
                renderModel(rc, menu, (MenuModel) itemModel, menuModelElement); 
            } else if (itemModel instanceof OptionModel) {
                Element optionModelElement = document.createElement("option");
                OptionModel optionModel = (OptionModel) itemModel;
                if (optionModel.getId() != null && !stateModel.isEnabled(optionModel.getId())) {
                    optionModelElement.setAttribute("enabled", "false");
                }
                if (optionModel instanceof ToggleOptionModel) {
                    if (optionModel instanceof RadioOptionModel) {
                        optionModelElement.setAttribute("type", "radio");
                    } else {
                        optionModelElement.setAttribute("type", "toggle");
                    }
                    if (stateModel != null && stateModel.isSelected(((ToggleOptionModel) optionModel).getId())) {
                        optionModelElement.setAttribute("selected", "true");
                    }
                } else {
                    optionModelElement.setAttribute("type", "default");
                }
                if (optionModel.getText() != null) {
                    optionModelElement.setAttribute("text", optionModel.getText());
                }
                if (optionModel.getIcon() != null) {
                    String itemPath = getItemPath(menu.getModel(), optionModel);
                    optionModelElement.setAttribute("icon", ImageTools.getUri(rc, this, menu, 
                            IMAGE_ID_MENU_ITEM_PREFIX + itemPath));
                }
                menuModelElement.appendChild(optionModelElement);
            } else if (itemModel instanceof SeparatorModel) {
                menuModelElement.appendChild(document.createElement("separator"));
            }
        }
        parentElement.appendChild(menuModelElement);
    }

    
    /**
    * @see nextapp.echo2.webcontainer.ComponentSynchronizePeer#renderUpdate(nextapp.echo2.webcontainer.RenderContext,
    *      nextapp.echo2.app.update.ServerComponentUpdate, java.lang.String)
    */
   public boolean renderUpdate(RenderContext rc, ServerComponentUpdate update, String targetId) {
       // Determine if fully replacing the component is required.
       if (partialUpdateManager.canProcess(rc, update)) {
           partialUpdateManager.process(rc, update);
       } else {
           // Perform full update.
           DomUpdate.renderElementRemove(rc.getServerMessage(), ContainerInstance.getElementId(update.getParent()));
           renderAdd(rc, update, targetId, update.getParent());
       }
       return true;
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy