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

jaxx.runtime.swing.navigation.NavigationTreeHandler Maven / Gradle / Ivy

package jaxx.runtime.swing.navigation;

import java.awt.Component;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeSelectionModel;
import javax.swing.tree.TreePath;
import jaxx.runtime.JAXXAction;
import jaxx.runtime.JAXXContext;
import jaxx.runtime.JAXXContextEntryDef;
import jaxx.runtime.JAXXObject;
import jaxx.runtime.swing.navigation.NavigationTreeModel.NavigationTreeNode;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * The handler of a navigation tree.
 *
 * This is also the selection model to use, since we must check before moving
 * from a node we can not just listen selection model changed, we must control
 * it.
 *
 *
 * @author tony
 * @since 1.3
 */
public abstract class NavigationTreeHandler extends DefaultTreeSelectionModel {

    private static final long serialVersionUID = 1L;
    /** to use log facility, just put in your code: log.info(\"...\"); */
    static private final Log log = LogFactory.getLog(NavigationTreeHandler.class);
    static public final String NAVIGATION_SELECTED_BEAN = "navigation-selected-bean";
    static public final JAXXContextEntryDef NAVIGATION_SELECTED_PATH_ENTRY_DEF = JAXXContextEntryDef.newDef("navigation-selected-path", String.class);
    static public final JAXXContextEntryDef NAVIGATION_SELECTED_NODE_ENTRY_DEF = JAXXContextEntryDef.newDef("navigation-selected-node", NavigationTreeNode.class);

    /** defined the stategy of instanciation of ui */
    public enum Strategy {

        /** instanciate a ui for a node */
        PER_NODE,
        /** instanciate only one a ui for a type,nodes will share the instanciation */
        PER_UI_TYPE
    }
    /** la classe d'ui par defaut, associé à un noeud de l'arbe */
    protected Class defaultUIClass;
    protected Class defaultUIHandlerClass;
    /** l'ui contenant l'arbre de navigation */
    protected JAXXObject context;
    protected Strategy strategy;

    protected NavigationTreeHandler(Class defaultUIClass, Class defaultUIHandlerClass, JAXXObject context, Strategy strategy) {
        this.defaultUIClass = defaultUIClass;
        this.defaultUIHandlerClass = defaultUIHandlerClass;
        this.context = context;
        this.strategy = strategy;
        addTreeSelectionListener(new TreeSelectionListener() {

            @Override
            public void valueChanged(TreeSelectionEvent event) {
                if (event.getOldLeadSelectionPath() != null && event.getOldLeadSelectionPath().equals(event.getPath())) {
                    // do not treate this if no path changed
                    return;
                }
                NavigationTreeNode node = (NavigationTreeNode) event.getPath().getLastPathComponent();
                selectNodeUI(node);
            }
        });
    }

    protected abstract NavigationTreeModel getNavigationTreeModel();

    /**
     * @return le composent actuellement visible associé au noeud courant ou au noeud précédent
     *         lors d'un changement de noeud.
     */
    protected abstract Component getCurrentUI();

    /**
     * @param node le noeud associé à l'ui à retrouver
     * @return l'ui associé au novueau noeud sélectionné
     */
    protected abstract Component getUI(NavigationTreeNode node);

    /**
     * @param component le composent actuellement visible
     * @return true si le composent a bien été fermé, false sinon
     * @throws Exception if any
     */
    protected abstract boolean closeUI(Component component) throws Exception;

    /**
     * Instancie une nouvelle ui associé à un noeud de l'arbre de navigation
     *
     * @param node le noeud associé à l'ui à créer
     * @return la nouvelle ui associée au noeud
     * @throws Exception if any
     */
    protected abstract Component createUI(NavigationTreeNode node) throws Exception;

    protected abstract JAXXContext createUIContext(NavigationTreeNode node) throws Exception;

    /**
     * Ouvre l'ui associée au noeud sélectionné dans l'arbre de navigation.
     *
     * @param newUI l'ui associé au noeud sélectionné à ouvrir
     * @param node  le node de l'ui a ouvrir
     * @throws Exception if any
     */
    protected abstract void openUI(Component newUI, NavigationTreeNode node) throws Exception;

    /**
     * Traitement des exceptions.
     *
     * @param e     l'erreur recontrée (ou null si pas d"erreur)
     */
    protected abstract void treateError(Exception e);

    /**
     * Prepare le nouveau noeud sélectionné.
     *
     * @param node le noeud a preparer
     * @return le noeud selectionné et preparé
     */
    protected NavigationTreeNode prepareNode(NavigationTreeNode node) {

        if (node.getJaxxClass() == null) {
            // no ui is associated with this node, display a empty content
            node.setJaxxClass(defaultUIClass);
        }

        if (node.getJaxxActionClass() == null) {
            node.setJaxxActionClass(defaultUIHandlerClass);
        }
        return node;
    }

    @Override
    public void setSelectionPath(TreePath path) {
        if (path.equals(getSelectionPath())) {
            // stay on same node, can skip
            if (log.isDebugEnabled()) {
                log.debug("skip stay on path " + path);
            }
            return;
        }
        Component component = getCurrentUI();

        try {
            if (!closeUI(component)) {
                if (log.isDebugEnabled()) {
                    log.debug("changing node canceled!");
                }
                // can not changed current node
                return;
            }
        } catch (Exception ex) {
            treateError(ex);
            return;
        }
        if (log.isDebugEnabled()) {
            log.debug("will select path " + path);
        }
        // ok can safely select the new path
        super.setSelectionPath(path);
    }

    public void selectNodeUI(NavigationTreeNode node) {

        try {

            node = prepareNode(node);

            String path = node.getContextPath();

            if (log.isTraceEnabled()) {
                log.trace(path);
            }

            Component newUI = getUI(node);

            // now, we are free to open the ui associated with the selected node in navigation

            // always clean cache on the node before all
            node.cachedBean = null;
            if (node.renderer != null) {
                node.renderer.setRendererCachedValue(null);
            }
            // before all, attach bean in context associated with the selected node in navigation tree
            Object data = getNavigationTreeModel().getJAXXContextValue(context, path);

            addSelectedBeanInContext(node, data);

            if (newUI == null) {
                // instanciate a new ui associated with the selected node
                newUI = createUI(node);
            }

            // save in context current node context path
            NAVIGATION_SELECTED_PATH_ENTRY_DEF.setContextValue(context, node.getContextPath());

            // save in context current node
            NAVIGATION_SELECTED_NODE_ENTRY_DEF.setContextValue(context, node);

            // really open the ui associated with the selected node
            openUI(newUI, node);

        } catch (Exception e) {
            // remove data from context

            // if any error, go back to previvous node
            treateError(e);
        }
    }

    protected void addSelectedBeanInContext(NavigationTreeNode node, Object data) {

        if (log.isDebugEnabled()) {
            log.debug("find data for contextPath <" + node.getContextPath() + "> : " + (data == null ? null : data.getClass()));
        }

        context.removeContextValue(Object.class, NAVIGATION_SELECTED_BEAN);

        if (data != null) {
            context.setContextValue(data, NAVIGATION_SELECTED_BEAN);
            //todo should we not use this to avoid conflict in context ?
            context.setContextValue(data);
        }
    }

    protected String getNodeConstraints(NavigationTreeNode node) {
        String constraints;
        switch (strategy) {
            case PER_NODE:
                constraints = node.getContextPath();
                break;
            case PER_UI_TYPE:
                constraints = node.getJaxxClass().getName();
                break;
            default:
                throw new IllegalArgumentException("could not find constraint for node : " + node);
        }
        return constraints;
    }

    protected JAXXAction getJAXXAction(Class jaxxActionClass) throws Exception {
        JAXXAction action = jaxxActionClass.newInstance();
        return action;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy