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 extends JAXXObject> defaultUIClass;
protected Class extends JAXXAction> defaultUIHandlerClass;
/** l'ui contenant l'arbre de navigation */
protected JAXXObject context;
protected Strategy strategy;
protected NavigationTreeHandler(Class extends JAXXObject> defaultUIClass, Class extends JAXXAction> 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 extends JAXXAction> jaxxActionClass) throws Exception {
JAXXAction action = jaxxActionClass.newInstance();
return action;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy