package com.c2kernel.gui.data; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.tree.DefaultMutableTreeNode; import com.c2kernel.common.ObjectNotFoundException; import com.c2kernel.gui.DynamicTreeBuilder; import com.c2kernel.gui.EntityTabManager; import com.c2kernel.lookup.AgentPath; import com.c2kernel.lookup.Path; import com.c2kernel.process.Gateway; import com.c2kernel.utils.Language; import com.c2kernel.utils.Logger; import com.c2kernel.utils.Resource; public abstract class Node implements Runnable { protected Path binding; protected DefaultMutableTreeNode treeNode; protected String name; // domain key protected int sysKey; // target item // attributes protected String type = ""; protected Icon icon; protected boolean isExpandable = false; protected HashMap childNodes = new HashMap(); protected ArrayList subscribers = new ArrayList(); protected DynamicTreeBuilder loader = null; private boolean loaded = false; private String iconName; protected EntityTabManager desktop; static ImageIcon folder = Resource.getImageResource("folder.png"); static ImageIcon emptyLeaf = Resource.getImageResource("leaf.png"); public Node() { } protected void createTreeNode() { this.treeNode = new DefaultMutableTreeNode(this); } public Node(Path path, EntityTabManager desktop) { this.binding = path; this.desktop = desktop; this.sysKey = path.getSysKey(); // get the name of this node (last path element) String[] pathComponents = path.getPath(); if (pathComponents.length > 0) this.name = pathComponents[pathComponents.length-1]; else this.name = Gateway.getProperty("Name"); } public EntityTabManager getDesktop() { return desktop; } public Node newNode(Path path) { try { if (path.getEntity() instanceof AgentPath) return new NodeAgent(path, desktop); else return new NodeItem(path, desktop); } catch (ObjectNotFoundException ex) { return new NodeContext(path, desktop); } } /** Inserts a tree builder as the first child of the node, so it can be opened in the tree */ public void makeExpandable() { if (isExpandable) return; loader = new DynamicTreeBuilder(this.treeNode); this.treeNode.insert(loader.getTreeNode(),0); isExpandable = true; } public DefaultMutableTreeNode getTreeNode() { return treeNode; } public void setTreeNode(DefaultMutableTreeNode treeNode) { this.treeNode = treeNode; treeNode.setUserObject(this); } /** Subscription for loading node children. * Note this is separate from the itemproxy subscription as it included query of the naming service * and eventually should not require access to the item at all for higher performance */ public void subscribeNode(NodeSubscriber target) { subscribers.add(target); if (loaded == false) { loaded = true; loadMore(); } else { synchronized (childNodes) { Node newNode; for (Iterator nodes = childNodes.values().iterator(); nodes.hasNext();) { newNode = (Node)nodes.next(); Logger.msg("subscribeNode target.add("+newNode.name+")"); target.add(newNode); } } } } public void loadMore() { Thread loading = new Thread(this); loading.start(); } public void unsubscribeNode(NodeSubscriber target) { subscribers.remove(target); } public void add(Node newNode) { synchronized(childNodes) { childNodes.put(newNode.getPath(), newNode); for (Iterator e = subscribers.iterator(); e.hasNext();) { NodeSubscriber thisSub = (NodeSubscriber)e.next(); thisSub.add(newNode); } } } public void remove(Path oldPath) { synchronized(childNodes) { childNodes.remove(oldPath); for (Iterator e = subscribers.iterator(); e.hasNext();) { NodeSubscriber thisSub = (NodeSubscriber)e.next(); thisSub.remove(oldPath); } } } public void removeAllChildren() { synchronized(childNodes) { Path thisPath; while (childNodes.keySet().iterator().hasNext()) { remove((Path)childNodes.keySet().iterator().next()); } } } public Node getChildNode(Path itsPath) { for (Iterator i = childNodes.keySet().iterator(); i.hasNext();) { Object next = i.next(); if ( next.equals(itsPath) ) return (Node)childNodes.get(next); } return null; } // end of current batch public void end(boolean more) { for (Iterator e = subscribers.iterator(); e.hasNext();) { NodeSubscriber thisSub = (NodeSubscriber)e.next(); thisSub.end(more); } } public void run() { Thread.currentThread().setName("Node Loader: "+name); loadChildren(); } public abstract void loadChildren(); public void refresh() { removeAllChildren(); loadChildren(); } // Getters and Setters public int getSysKey() { return sysKey; } // public void setSysKey( int sysKey ) { this.sysKey = sysKey; } public String getName() { return name; } // public void setName( String name ) { this.name = name; } public String getType() { return type; } // public void setType( String type ) { this.type = type; } public Path getPath() { return binding; } public DynamicTreeBuilder getTreeBuilder() { return loader; } public String toString() { if (this.name.length() > 0) { return this.name; } else { return "Cristal"; } } public Icon getIcon() { if (icon != null) return icon; return(isExpandable?folder:emptyLeaf); } public String getIconName() { return iconName; } public void setIcon(String icon) { iconName = icon; this.icon = Resource.getImageResource("typeicons/"+icon+"_16.png"); } public JPopupMenu getPopupMenu() { JPopupMenu popup = new JPopupMenu(); JMenuItem menuItem = new JMenuItem(Language.translate("Refresh")); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (isExpandable) refresh(); } }); popup.add(menuItem); return popup; } }