Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / jigsaw / src / org / w3c / jigadmin / editors / ResourceTreeBrowser.java
diff --git a/JMCR-Stable/real-world application/jigsaw/src/org/w3c/jigadmin/editors/ResourceTreeBrowser.java b/JMCR-Stable/real-world application/jigsaw/src/org/w3c/jigadmin/editors/ResourceTreeBrowser.java
new file mode 100644 (file)
index 0000000..29f82dd
--- /dev/null
@@ -0,0 +1,822 @@
+// ResourceTreeBrowser.java\r
+// $Id: ResourceTreeBrowser.java,v 1.1 2010/06/15 12:25:55 smhuang Exp $\r
+// (c) COPYRIGHT MIT and INRIA, 1998.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.jigadmin.editors;\r
+\r
+import javax.swing.JTree;\r
+import javax.swing.JOptionPane;\r
+import javax.swing.KeyStroke;\r
+import javax.swing.JDialog;\r
+import javax.swing.JFrame;\r
+import javax.swing.JPopupMenu;\r
+import javax.swing.JMenuItem;\r
+import javax.swing.tree.TreePath;\r
+import javax.swing.tree.DefaultTreeCellRenderer;\r
+import javax.swing.tree.DefaultTreeModel;\r
+import javax.swing.tree.MutableTreeNode;\r
+import javax.swing.event.TreeWillExpandListener;\r
+import javax.swing.event.TreeExpansionEvent;\r
+import javax.swing.tree.ExpandVetoException;\r
+import javax.swing.tree.TreeNode;\r
+\r
+import java.awt.Cursor;\r
+import java.awt.Point;\r
+import java.awt.Component;\r
+import java.awt.GridLayout;\r
+import java.awt.Dimension;\r
+import java.awt.Container;\r
+import java.awt.event.ActionListener;\r
+import java.awt.event.ActionEvent;\r
+import java.awt.event.MouseListener;\r
+import java.awt.event.MouseAdapter;\r
+import java.awt.event.MouseEvent;\r
+import java.awt.event.KeyEvent;\r
+import java.awt.dnd.DropTarget;\r
+import java.awt.dnd.DropTargetListener;\r
+import java.awt.dnd.DropTargetDragEvent;\r
+import java.awt.dnd.DropTargetDropEvent;\r
+import java.awt.dnd.DropTargetEvent;\r
+import java.awt.dnd.DnDConstants;\r
+import java.awt.datatransfer.Transferable;\r
+import java.awt.datatransfer.DataFlavor;\r
+import java.awt.datatransfer.UnsupportedFlavorException;\r
+\r
+import java.io.IOException;\r
+\r
+import java.util.Vector;\r
+\r
+import org.w3c.jigadmin.RemoteResourceWrapper;\r
+import org.w3c.jigadmin.PropertyManager;\r
+import org.w3c.jigadmin.gui.Message;\r
+import org.w3c.jigadmin.events.ResourceActionListener;\r
+import org.w3c.jigadmin.events.ResourceActionEvent;\r
+import org.w3c.jigadmin.widgets.Icons;\r
+\r
+import org.w3c.jigsaw.admin.RemoteAccessException;\r
+import org.w3c.jigsaw.admin.RemoteResource;\r
+\r
+/**\r
+ * A JTree used to manage RemoteResource.\r
+ * @version $Revision: 1.1 $\r
+ * @author  Benoît Mahé (bmahe@w3.org)\r
+ */\r
+public class ResourceTreeBrowser extends JTree \r
+    implements DropTargetListener, ResourceActionListener\r
+{\r
+\r
+    public static final String DELETE_RESOURCE_AC = "delres";\r
+\r
+    protected RemoteResourceWrapperNode rootNode      = null;\r
+    protected String                    resIdentifier = null;\r
+    protected String                    resClassname  = null;\r
+    protected JDialog                   popup         = null;\r
+\r
+    private boolean isDragging = false;\r
+\r
+    /**\r
+     * Our TreeWillExpandListener\r
+     */\r
+    TreeWillExpandListener twel = new TreeWillExpandListener() {\r
+       public void treeWillExpand(TreeExpansionEvent event)\r
+       throws ExpandVetoException\r
+       {\r
+           TreeNode node = \r
+           (TreeNode)event.getPath().getLastPathComponent();\r
+           ((RemoteNode)node).nodeWillExpand();\r
+           ((DefaultTreeModel)getModel()).reload(node);\r
+       }\r
+\r
+       public synchronized void treeWillCollapse(TreeExpansionEvent event)\r
+       throws ExpandVetoException\r
+       {\r
+           TreeNode node = \r
+           (TreeNode)event.getPath().getLastPathComponent();\r
+           ((RemoteNode)node).nodeWillCollapse();\r
+           ((DefaultTreeModel)getModel()).reload(node);\r
+       }\r
+    };\r
+\r
+    /**\r
+     * Our ActionListener\r
+     */\r
+    ActionListener al = new ActionListener() {\r
+       public void actionPerformed(ActionEvent evt) {\r
+           String command = evt.getActionCommand();\r
+           if (command.equals(DELETE_RESOURCE_AC)) {\r
+               //delete the selected resource\r
+               deleteSelectedResources();\r
+           }\r
+       }\r
+    };\r
+    /**\r
+     * Our MouseListener\r
+     */\r
+    MouseAdapter mouseAdapter = new MouseAdapter() {\r
+       public void mouseClicked(MouseEvent e) {\r
+           int selRow = getRowForLocation(e.getX(), e.getY());\r
+           TreePath selPath = getPathForLocation(e.getX(), e.getY());\r
+           if(selRow != -1) {\r
+               if(e.getClickCount() == 1) {\r
+                   simpleClick(selPath);\r
+               }\r
+               else if(e.getClickCount() == 2) {\r
+                   doubleClick(selPath);\r
+               }\r
+           }\r
+       }\r
+\r
+       public void mousePressed(MouseEvent e) {\r
+           maybeShowPopup(e);\r
+       }\r
+           \r
+       public void mouseReleased(MouseEvent e) {\r
+           maybeShowPopup(e);\r
+       }\r
+           \r
+       private void maybeShowPopup(MouseEvent e) {\r
+           if (e.isPopupTrigger()) {\r
+               RemoteResourceWrapper rrw = getSelectedResourceWrapper();\r
+               if (rrw != null)\r
+               getPopupMenu(rrw).show(e.getComponent(), \r
+                                      e.getX(), e.getY());\r
+           }\r
+       }\r
+    };\r
+\r
+    //DropTargetListener\r
+\r
+    DropTarget dropTarget;\r
+\r
+    /**\r
+     * Is the mouse dragging something on the resource tree?\r
+     * @return a boolean\r
+     */\r
+    public boolean isDragging() {\r
+       return isDragging;\r
+    }\r
+\r
+    /**\r
+     * a Drag operation has encountered the DropTarget\r
+     */\r
+    public void dragEnter (DropTargetDragEvent dropTargetDragEvent) {\r
+       dropTargetDragEvent.acceptDrag(DnDConstants.ACTION_COPY);\r
+       isDragging = true;\r
+    }\r
+\r
+    /**\r
+     * The Drag operation has departed the DropTarget without dropping.\r
+     */\r
+    public void dragExit (DropTargetEvent dropTargetEvent) {\r
+       isDragging = false;\r
+    }\r
+\r
+    /**\r
+     * a Drag operation is ongoing on the DropTarget\r
+     */\r
+    public void dragOver (DropTargetDragEvent dropTargetDragEvent) {\r
+       Point location = dropTargetDragEvent.getLocation();\r
+       TreePath path = getClosestPathForLocation(location.x,\r
+                                                 location.y);\r
+       setSelectionPath(path);\r
+    }\r
+\r
+    /**\r
+     * The user as modified the current drop gesture\r
+     */\r
+    public void dropActionChanged (DropTargetDragEvent dropTargetDragEvent) {\r
+    }\r
+\r
+    /**\r
+     * The Drag operation has terminated with a Drop on this DropTarget\r
+     */\r
+    public synchronized void drop (DropTargetDropEvent dropTargetDropEvent) {\r
+       isDragging = false;\r
+       Transferable tr  = dropTargetDropEvent.getTransferable();\r
+       DataFlavor required = TransferableResourceCell.RESOURCE_CELL_FLAVOR;\r
+       try {\r
+           if (tr.isDataFlavorSupported(required)) {\r
+               dropTargetDropEvent.acceptDrop(DnDConstants.ACTION_COPY);\r
+               ResourceCell cell = (ResourceCell)tr.getTransferData(required);\r
+               dropTargetDropEvent.dropComplete(dropResource(cell));\r
+           } else {\r
+               dropTargetDropEvent.rejectDrop();\r
+           }\r
+       } catch (IOException ex) {\r
+           ex.printStackTrace();\r
+           dropTargetDropEvent.rejectDrop();\r
+       } catch (UnsupportedFlavorException ufe) {\r
+           ufe.printStackTrace();\r
+           dropTargetDropEvent.rejectDrop();\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Drop a resource.\r
+     * @param cell The resource cell\r
+     * @see org.w3c.jigadmin.editors.ResourceCell\r
+     */\r
+    protected boolean dropResource(ResourceCell cell) {\r
+       RemoteResourceWrapper rrw = getSelectedResourceWrapper();\r
+       PropertyManager pm = PropertyManager.getPropertyManager();\r
+       try {\r
+           if (! pm.isExtensible(rrw)) {\r
+               return false;\r
+           } else if ((cell.isFrame() || cell.isFilter()) && \r
+                      (pm.isEditable(rrw))) {\r
+               //popupresource\r
+               popupResource(rrw);\r
+               return true;\r
+           } else if (((cell.isContainer() || cell.isResource()) && \r
+                       (! rrw.getResource().isIndexersCatalog())) \r
+                      ||\r
+                      (rrw.getResource().isIndexersCatalog() && \r
+                       cell.isIndexer())) {\r
+               //must be droppped on a Container\r
+               if (rrw.getResource().isContainer()) {\r
+                   //add the resource\r
+                   String identifier = getIdentifier(cell, rrw);\r
+                   if (identifier != null) {\r
+                       TreePath path = getSelectionPath();\r
+                       addResource(identifier, cell.toString(), \r
+                                   rrw, path);\r
+                       return true;\r
+                   } \r
+               }\r
+           }\r
+           return false;\r
+       } catch (RemoteAccessException ex) {\r
+           Message.showErrorMessage(this, ex);\r
+           return false;\r
+       }\r
+    }\r
+\r
+    //End of DropTargetListener\r
+\r
+    /**\r
+     * A resource action occured.\r
+     * @param e the ResourceActionEvent\r
+     */\r
+    public void resourceActionPerformed(ResourceActionEvent e) {\r
+       int cmd = e.getResourceActionCommand();\r
+       if (isShowing()) {\r
+           if (cmd == ResourceActionEvent.DELETE_EVENT) {\r
+               deleteSelectedResources();\r
+           } else if (cmd == ResourceActionEvent.REINDEX_EVENT) {\r
+               reindexSelectedResources(false); //FIXME\r
+           } else if (cmd == ResourceActionEvent.REFERENCE_EVENT) {\r
+               showReferenceDocumentation();\r
+           } else if (cmd == ResourceActionEvent.ADD_EVENT) {\r
+               addResourceToSelectedContainer();\r
+           } else if (cmd == ResourceActionEvent.EDIT_EVENT) {\r
+               doubleClick(getSelectionPath());\r
+           }\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Add a resource to the resource wrapped.\r
+     * @param identifier The new resource identifier\r
+     * @param classname The new resource class name\r
+     * @param rrwf the Wrapper of the father resource\r
+     * @param fpath The path of the father node\r
+     */\r
+    protected void addResource(String identifier, String classname,\r
+                              RemoteResourceWrapper rrwf, TreePath fpath) \r
+       throws RemoteAccessException\r
+    {\r
+       RemoteResource rc = \r
+           rrwf.getResource().registerResource(identifier, classname);\r
+       RemoteResourceWrapper nrrw = \r
+           new RemoteResourceWrapper(rrwf, rc);\r
+       RemoteResourceWrapperNode parent = \r
+           (RemoteResourceWrapperNode)fpath.getLastPathComponent();\r
+       RemoteResourceWrapperNode child = \r
+           new RemoteResourceWrapperNode(parent, nrrw, identifier);\r
+       ((DefaultTreeModel)getModel()).insertNodeInto(child, parent, 0);\r
+       expandPath(fpath);\r
+    }\r
+\r
+    /**\r
+     * Add a resource to the selected container.\r
+     * @param classname the resource class name\r
+     * @param identifier the resource identifier\r
+     */\r
+    protected void addResourceToSelectedContainer(String classname,\r
+                                                 String identifier)\r
+       throws RemoteAccessException                              \r
+    {\r
+       RemoteResourceWrapper rrw = getSelectedResourceWrapper();\r
+       if (rrw == null)\r
+           return;\r
+       addResource(identifier, classname, rrw, getSelectionPath());\r
+    }\r
+\r
+    /**\r
+     * Get (compute) the resource identifier of the dropped resource.\r
+     * @param cell the ResourceCell dropped\r
+     * @param rrw the RemoteResourceWrapper of the father\r
+     * @return a String instance\r
+     * @see org.w3c.jigadmin.editors.ResourceCell\r
+     */\r
+    protected String getIdentifier(ResourceCell cell, \r
+                                  RemoteResourceWrapper rrw) \r
+       throws RemoteAccessException\r
+    {\r
+       String id = cell.toString();\r
+       id = id.substring(id.lastIndexOf('.')+1);\r
+       String names[] = rrw.getResource().enumerateResourceIdentifiers();\r
+       String identifier = id;\r
+       int cpt = 0; \r
+       int i   = 0;\r
+    loop:\r
+       while (i < names.length) {\r
+           if (names[i].equals(identifier)) {\r
+               identifier = id+String.valueOf(++cpt);\r
+               i = 0;\r
+               continue loop;\r
+           }\r
+           i++;\r
+       }\r
+       return identifier;\r
+    }\r
+\r
+    /**\r
+     * Get the RemoteResourceWrapper associated to the selected node.\r
+     * @return a RemoteResourceWrapper\r
+     */\r
+    protected RemoteResourceWrapper getSelectedResourceWrapper() {\r
+       RemoteResourceWrapperNode node = \r
+           (RemoteResourceWrapperNode)getLastSelectedPathComponent();\r
+       if (node == null)\r
+           return null;\r
+       return node.getResourceWrapper();\r
+    }\r
+\r
+    /**\r
+     * Get the RemoteResourceWrapper associated to the selected node.\r
+     * @param path the selected path\r
+     * @return a RemoteResourceWrapper\r
+     */\r
+    protected RemoteResourceWrapper getSelectedResourceWrapper(TreePath path) {\r
+       if (path == null)\r
+           return null;\r
+       RemoteResourceWrapperNode node = \r
+           (RemoteResourceWrapperNode) path.getLastPathComponent();\r
+       return node.getResourceWrapper();\r
+    }\r
+\r
+    /**\r
+     * Get the Panel used to add a new resource\r
+     * @param title The title\r
+     * @param rrw The wrapper of the father RemoteResource\r
+     * @return a AddResourcePanel instance\r
+     * @see org.w3c.jigadmin.editors.AddResourcePanel\r
+     */\r
+    protected AddResourcePanel getAddResourcePanel(String title, \r
+                                                  RemoteResourceWrapper rrw)\r
+       throws RemoteAccessException\r
+    {\r
+       return new AddResourcePanel(title, rrw, this);\r
+    }\r
+\r
+    /**\r
+     * Popup a "add resource" Dialog\r
+     * @param title the popup title\r
+     * @param rrw The wrapper of the father RemoteResource\r
+     */\r
+    protected void popupAddResourceDialog(String title, \r
+                                         RemoteResourceWrapper rrw) \r
+    {\r
+       try {\r
+           AddResourcePanel arp = getAddResourcePanel(title, rrw);\r
+           JFrame frame = \r
+               rootNode.\r
+               getResourceWrapper().getServerBrowser().getFrame();\r
+           popup = new JDialog(frame, title, false);\r
+           Container cont = popup.getContentPane();\r
+           cont.setLayout(new GridLayout(1,1));\r
+           cont.add(arp);\r
+           popup.setSize(new Dimension(600, 220));\r
+           popup.show();\r
+           arp.getFocus();\r
+           while(! arp.waitForCompletion());\r
+       } catch (RemoteAccessException ex) {\r
+           Message.showErrorMessage(this, ex);\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Dispose the "add resource" popup\r
+     */\r
+    protected void disposeAddResourcePopup() {\r
+       if (popup != null) {\r
+           popup.dispose();\r
+           popup = null;\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Specify some properties of the resource to add\r
+     * @param classnema the new resource class name\r
+     * @param identifier the new resource identifier\r
+     */\r
+    protected void setResourceToAdd(String classname, String identifier) {\r
+       this.resClassname  = classname;\r
+       this.resIdentifier = identifier;\r
+    }\r
+\r
+    private void performAddResourceToSelectedContainer() {\r
+       popupAddResourceDialog("Add Resource", getSelectedResourceWrapper());\r
+       if ((resIdentifier != null) && (resClassname != null)) {\r
+           try {\r
+               addResourceToSelectedContainer(resClassname, \r
+                                              resIdentifier);\r
+           } catch (RemoteAccessException ex) {\r
+               Message.showErrorMessage(this, ex);\r
+           }\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Add a (new) resource to the container associated to the\r
+     * selected node.\r
+     */\r
+    protected void addResourceToSelectedContainer() {\r
+       RemoteResourceWrapper selected = getSelectedResourceWrapper();\r
+       PropertyManager pm = PropertyManager.getPropertyManager();\r
+       try {\r
+           if (selected == null) {\r
+               JOptionPane.showMessageDialog(this, \r
+                                             "No Container selected",\r
+                                             "Error",\r
+                                             JOptionPane.ERROR_MESSAGE);\r
+               return;\r
+           } else if (! pm.isExtensible(selected)) {\r
+               JOptionPane.showMessageDialog(this, \r
+                                             "The resource selected is not "+\r
+                                             "extensible.",\r
+                                             "Error",\r
+                                             JOptionPane.ERROR_MESSAGE);\r
+           }else if (selected.getResource().isContainer()) {\r
+               Thread thread = new Thread() {\r
+                   public void run() {\r
+                       performAddResourceToSelectedContainer();\r
+                   }\r
+               };\r
+               thread.start();\r
+           } else {\r
+               JOptionPane.showMessageDialog(this, \r
+                                             "The resource selected is not "+\r
+                                             "container.",\r
+                                             "Error",\r
+                                             JOptionPane.ERROR_MESSAGE);\r
+           }\r
+       } catch (RemoteAccessException ex) {\r
+           Message.showErrorMessage(this, ex);\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Filter the TreePath array. Remove all nodes that have one of their\r
+     * parent in this array.\r
+     * @param paths the TreePath array\r
+     * @return the filtered array\r
+     */\r
+    protected TreePath[] removeDescendants(TreePath[] paths) {\r
+       if (paths == null)\r
+           return null;\r
+       Vector newpaths = new Vector();\r
+       for (int i = 0 ; i < paths.length ; i++) {\r
+           TreePath currentp = paths[i];\r
+           boolean hasParent = false;\r
+           for (int j = 0 ; j < paths.length ; j++) {\r
+               if ((!(j == i)) && (paths[j].isDescendant(currentp)))\r
+                   hasParent = true;\r
+           }\r
+           if (! hasParent)\r
+               newpaths.addElement(currentp);\r
+       }\r
+       TreePath[] filteredPath = new TreePath[newpaths.size()];\r
+       newpaths.copyInto(filteredPath);\r
+       return filteredPath;\r
+    }\r
+\r
+    /**\r
+     * Reindex the containers associated to the selected nodes.\r
+     * Display an error message (dialog) if there is no node selected or\r
+     * if one of the selected resource is not a ResourceContainer.\r
+     * @param rec recursivly?\r
+     */\r
+    protected void reindexSelectedResources(boolean rec) {\r
+       TreePath path[] = removeDescendants(getSelectionPaths());\r
+       if (path == null) {\r
+           JOptionPane.showMessageDialog(this, \r
+                                         "No Container selected",\r
+                                         "Error",\r
+                                         JOptionPane.ERROR_MESSAGE);\r
+           return;\r
+       }\r
+       if (path.length > 0) {\r
+           int result = \r
+               JOptionPane.showConfirmDialog(this, \r
+                                             "Reindex selected resource(s)?", \r
+                                             "Reindex Resource(s)", \r
+                                             JOptionPane.YES_NO_OPTION);\r
+           if (result == JOptionPane.YES_OPTION) {\r
+               for (int i = 0 ; i < path.length ; i++) {\r
+                   RemoteResourceWrapper rrw = \r
+                       getSelectedResourceWrapper(path[i]);\r
+                   if (rrw == null)\r
+                       continue;\r
+                   try {\r
+                       reindexResource(rrw, rec);\r
+                   } catch (RemoteAccessException ex) {\r
+                       Message.showErrorMessage(this, ex);\r
+                       continue;\r
+                   }\r
+               }\r
+           }\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Reindex the container wrapped by the given wrapper.\r
+     * Display an error message (dialog) if the resource\r
+     * is not a ResourceContainer.\r
+     * @param rrw the RemoteResourceWrapper\r
+     * @param rec recursivly?\r
+     * @exception RemoteAccessException if a Remote Error occurs\r
+     */\r
+    protected void reindexResource(RemoteResourceWrapper rrw, boolean rec) \r
+       throws RemoteAccessException\r
+    {\r
+       RemoteResource rr = rrw.getResource();\r
+       if (rr.isContainer()) {\r
+           rr.reindex(rec);\r
+       } else {\r
+           JOptionPane.\r
+               showMessageDialog(this, \r
+                                 rr.getValue("identifier")+\r
+                                 " is not a container.",\r
+                                 "Error",\r
+                                 JOptionPane.ERROR_MESSAGE);\r
+       }\r
+    }\r
+       \r
+\r
+    /**\r
+     * Delete the resources associated to the selected nodes.\r
+     * Display an error message if there is no node selected or if\r
+     * the resource is not editable.\r
+     */\r
+    protected void deleteSelectedResources() {\r
+       PropertyManager pm = PropertyManager.getPropertyManager();\r
+       TreePath path[] = removeDescendants(getSelectionPaths());\r
+       if (path == null) {\r
+           JOptionPane.showMessageDialog(this, \r
+                                         "No Resource selected",\r
+                                         "Error",\r
+                                         JOptionPane.ERROR_MESSAGE);\r
+           return;\r
+       }\r
+       if (path.length > 0) {\r
+           int result = \r
+               JOptionPane.showConfirmDialog(this, \r
+                                             "Delete selected resource(s)?", \r
+                                             "Delete Resource(s)", \r
+                                             JOptionPane.YES_NO_OPTION);\r
+           if (result == JOptionPane.YES_OPTION) {\r
+               DefaultTreeModel model = (DefaultTreeModel) getModel();\r
+               for (int i = 0 ; i < path.length ; i++) {\r
+                   RemoteResourceWrapper rrw = \r
+                       getSelectedResourceWrapper(path[i]);\r
+                   if (rrw == null)\r
+                       continue;\r
+                   try {\r
+                       if (pm.isEditable(rrw)) {\r
+                           deleteResource(rrw);\r
+                           MutableTreeNode node = (MutableTreeNode) \r
+                               path[i].getLastPathComponent();\r
+                           model.removeNodeFromParent(node);\r
+                       } else {\r
+                           String name = (String)\r
+                               rrw.getResource().getValue("identifier");\r
+                           Message.showInformationMessage(this, name+\r
+                                                          " is not editable");\r
+                       }\r
+                   } catch (RemoteAccessException ex) {\r
+                       Message.showErrorMessage(this, ex);\r
+                       continue;\r
+                   }\r
+               }\r
+           }\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Delete the resource wrapped by the given wrapper\r
+     * @param rrw The RemoteResourceWrapper\r
+     */\r
+    protected void deleteResource(RemoteResourceWrapper rrw) \r
+       throws RemoteAccessException\r
+    {\r
+       rrw.getResource().delete();\r
+    }\r
+\r
+    /**\r
+     * Display (in another frame) the reference documentation relative\r
+     * to the resource associated to the selected node.\r
+     * Display en error message (dialog) if no node is selected.\r
+     */\r
+    protected void showReferenceDocumentation() {\r
+       try {\r
+           RemoteResourceWrapper selected = \r
+               getSelectedResourceWrapper();\r
+           if (selected == null) {\r
+               JOptionPane.showMessageDialog(this, \r
+                                             "No Resource selected",\r
+                                             "Error",\r
+                                             JOptionPane.ERROR_MESSAGE);\r
+               return;\r
+           } else {\r
+               String url = (String)\r
+                   selected.getResource().getValue("help-url");\r
+               MiniBrowser.showDocumentationURL(url, \r
+                                                "Reference documentation");\r
+           }\r
+       } catch (RemoteAccessException rae) {\r
+           Message.showErrorMessage(this, rae);\r
+       } catch (Exception ex) {\r
+\r
+       }\r
+    }\r
+\r
+    /**\r
+     * A simle click occured on the node with the given path.\r
+     * @param path The path where the click occured.\r
+     */\r
+    protected void simpleClick(TreePath path) {\r
+    }\r
+\r
+    /**\r
+     * A double click occured on the node with the given path.\r
+     * @param path The path where the double click occured.\r
+     */\r
+    protected void doubleClick(TreePath path) {\r
+       if (path == null)\r
+           return;\r
+       RemoteResourceWrapperNode node = \r
+           (RemoteResourceWrapperNode) path.getLastPathComponent();\r
+       RemoteResourceWrapper rrw = node.getResourceWrapper();\r
+       PropertyManager pm = PropertyManager.getPropertyManager();\r
+       if (pm.isEditable(rrw))\r
+           popupResource(node.getResourceWrapper());\r
+       else {\r
+           try {\r
+               String name = (String)\r
+                   rrw.getResource().getValue("identifier");\r
+               Message.showInformationMessage(this, name+" is not editable");\r
+           } catch (RemoteAccessException ex) {\r
+               Message.showErrorMessage(this, ex);\r
+           }\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Popup a dialog where the user can edit the resource properties.\r
+     * @param rrw the wrapper if the resource to edit.\r
+     */\r
+    protected void popupResource(RemoteResourceWrapper rrw) {\r
+       rrw.getServerBrowser().popupResource(rrw);\r
+    }\r
+\r
+    /**\r
+     * Set the cursor.\r
+     * @param a cursor type\r
+     */ \r
+    protected void setCursor(int cursor) {\r
+       rootNode.getResourceWrapper().getServerBrowser().setCursor(cursor);\r
+    }\r
+\r
+   \r
+    /**\r
+     * The popup menu action listener.\r
+     */\r
+    ActionListener pmal = new ActionListener() {\r
+       public void actionPerformed(ActionEvent evt) {\r
+           setCursor(Cursor.WAIT_CURSOR);\r
+           String command = evt.getActionCommand();\r
+           if (command.equals("del")) {\r
+               deleteSelectedResources();\r
+           } else if (command.equals("add")) {\r
+               addResourceToSelectedContainer();\r
+           } else if (command.equals("reindex")) {\r
+               reindexSelectedResources(true);\r
+           } else if (command.equals("reindex-locally")) {\r
+               reindexSelectedResources(false);\r
+           } else if (command.equals("info")) {\r
+               showReferenceDocumentation();\r
+           } else if (command.equals("edit")) {\r
+               doubleClick(getSelectionPath());\r
+           }\r
+           setCursor(Cursor.DEFAULT_CURSOR);\r
+       }\r
+    };\r
+\r
+    /**\r
+     * Get the popup menu relative to the selected resource.\r
+     * @param rrw the wrapper of the resource\r
+     * @return a JPopupMenu instance\r
+     */\r
+    protected JPopupMenu getPopupMenu(RemoteResourceWrapper rrw) {\r
+\r
+       JPopupMenu popupMenu = new JPopupMenu();\r
+\r
+       boolean container  = false;\r
+       boolean editable   = false;\r
+\r
+       try {\r
+           PropertyManager pm = PropertyManager.getPropertyManager();\r
+           container = rrw.getResource().isContainer();\r
+           editable = pm.isEditable(rrw);\r
+       } catch (RemoteAccessException ex) {\r
+           container = false;\r
+       }\r
+\r
+       JMenuItem menuItem = null;\r
+\r
+       if (container) {\r
+           menuItem = new JMenuItem("Reindex", Icons.reindexIcon);\r
+           menuItem.addActionListener(pmal);\r
+           menuItem.setActionCommand("reindex");\r
+           popupMenu.add(menuItem);\r
+\r
+           menuItem = new JMenuItem("Reindex Locally", Icons.reindexIcon);\r
+           menuItem.addActionListener(pmal);\r
+           menuItem.setActionCommand("reindex-locally");\r
+           popupMenu.add(menuItem);\r
+           \r
+           menuItem = new JMenuItem("Add resource", Icons.addIcon);\r
+           menuItem.addActionListener(pmal);\r
+           menuItem.setActionCommand("add");\r
+           popupMenu.add(menuItem);\r
+       }\r
+\r
+       if (editable) {\r
+           menuItem = new JMenuItem("Delete resource", Icons.deleteIcon);\r
+           menuItem.addActionListener(pmal);\r
+           menuItem.setActionCommand("del");\r
+           popupMenu.add(menuItem);\r
+\r
+           menuItem = new JMenuItem("Edit resource", Icons.editIcon);\r
+           menuItem.addActionListener(pmal);\r
+           menuItem.setActionCommand("edit");\r
+           popupMenu.add(menuItem);\r
+\r
+           popupMenu.addSeparator();\r
+       }\r
+\r
+       menuItem = new JMenuItem("Info", Icons.infoIcon);\r
+       menuItem.addActionListener(pmal);\r
+       menuItem.setActionCommand("info");\r
+       popupMenu.add(menuItem);\r
+\r
+       return popupMenu;\r
+    }\r
+\r
+    /**\r
+     * Constructor\r
+     * @param root The root node\r
+     */\r
+    protected ResourceTreeBrowser(RemoteResourceWrapperNode root) {\r
+       super(root);\r
+       this.rootNode = root;\r
+       dropTarget = new DropTarget (this, this);\r
+       setEditable(true);\r
+       setLargeModel(true);\r
+       setScrollsOnExpand(true);\r
+       setUI(new ResourceTreeUI());\r
+       addTreeWillExpandListener(twel);\r
+       KeyStroke delK = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0);\r
+       registerKeyboardAction(al, DELETE_RESOURCE_AC, delK, WHEN_FOCUSED);\r
+       addMouseListener(mouseAdapter);\r
+    }\r
+\r
+    /**\r
+     * Get a ResourceTreeBrowser.\r
+     * @param rrw The root resource\r
+     * @param rootName The root identifier.\r
+     * @return a ResourceTreeBrowser instance\r
+     */\r
+    public static \r
+       ResourceTreeBrowser getResourceTreeBrowser(RemoteResourceWrapper rrw,\r
+                                                  String rootName)\r
+    {\r
+       RemoteResourceWrapperNode rnode = \r
+           new RemoteResourceWrapperNode(rrw, rootName);\r
+       ResourceTreeBrowser treebrowser = new ResourceTreeBrowser(rnode);\r
+       return treebrowser;\r
+    }\r
+}\r