Hi All, I would like to submit a patch to the ANTIDOTE project which provides a generic ACS element. The elements children are determined by the supplied DTD. The patch does contain two minor fixes: 1) Allow the root element of the tree to be selected. 2) Select the correct tree element before displaying the popup menu. The project.dtd and project-ext.dtd should be placed in org/apache/tools/ant/gui/acs. Cheers, Nick p.s. there were quite a few new files so I jarred them to allow posting to the mailing list. please let me know if I should break the fix into small units. Index: ACSFactory.java =================================================================== RCS file: /home/cvspublic/jakarta-ant/src/antidote/org/apache/tools/ant/gui/acs/ACSFac tory.java,v retrieving revision 1.8 diff -u -r1.8 ACSFactory.java --- ACSFactory.java 2001/01/12 20:42:22 1.8 +++ ACSFactory.java 2001/03/27 14:20:11 @@ -60,9 +60,7 @@ import org.w3c.dom.*; import org.xml.sax.SAXException; import com.sun.xml.parser.Parser; -import com.sun.xml.tree.SimpleElementFactory; -import com.sun.xml.tree.XmlDocument; -import com.sun.xml.tree.XmlDocumentBuilder; +import com.sun.xml.tree.*; import java.util.Properties; import java.util.Enumeration; import com.sun.xml.parser.Resolver; @@ -92,7 +90,7 @@ String name = (String) enum.nextElement(); // XXX the name of the class needs to be stored externally. _elementMap.setProperty( - name, "org.apache.tools.ant.gui.acs.ACSTaskElement"); + name, "org.apache.tools.ant.gui.acs.ACSDtdDefinedElement"); } // Then we add/override the local definitions. @@ -164,7 +162,6 @@ sax.parse(location.openStream(), null); doc = builder.getDocument(); - } catch(ParserConfigurationException ex) { ex.printStackTrace(); @@ -235,6 +232,22 @@ return retval; } + /** + * Create a new element. + * + * @param node the Node to assign the property to. + * @param name the new elements type. + * @return New, unnamed property. + */ + public ACSElement createElement(ACSElement node, String name) { + ACSElement retval = (ACSElement) node. + getOwnerDocument().createElement(name); + // XXX fixme. + indent(node, 1); + node.appendChild(retval); + return retval; + } + /** * Insert a new line and indentation at the end of the given * node in preparation for a new element being added. Index: ACSNamedElement.java =================================================================== RCS file: /home/cvspublic/jakarta-ant/src/antidote/org/apache/tools/ant/gui/acs/ACSNam edElement.java,v retrieving revision 1.3 diff -u -r1.3 ACSNamedElement.java --- ACSNamedElement.java 2001/01/03 14:18:17 1.3 +++ ACSNamedElement.java 2001/03/27 14:20:39 @@ -62,7 +62,7 @@ * @version $Revision: 1.3 $ * @author Simeon Fitch */ -public class ACSNamedElement extends ACSTreeNodeElement { +public class ACSNamedElement extends ACSDtdDefinedElement { /** The 'name' property name. */ public static final String NAME = "name"; /** The discription property name. */ @@ -73,7 +73,6 @@ * */ public ACSNamedElement() { - } /** Index: ACSPropertyElement.java =================================================================== RCS file: /home/cvspublic/jakarta-ant/src/antidote/org/apache/tools/ant/gui/acs/ACSPro pertyElement.java,v retrieving revision 1.4 diff -u -r1.4 ACSPropertyElement.java --- ACSPropertyElement.java 2001/01/03 14:18:17 1.4 +++ ACSPropertyElement.java 2001/03/27 14:21:24 @@ -61,7 +61,7 @@ * @version $Revision: 1.4 $ * @author Simeon Fitch */ -public class ACSPropertyElement extends ACSTreeNodeElement { +public class ACSPropertyElement extends ACSDtdDefinedElement { /** The 'name' property name. */ public static final String NAME = "name"; /** The 'value' property name. */ Index: ActionManager.java =================================================================== RCS file: /home/cvspublic/jakarta-ant/src/antidote/org/apache/tools/ant/gui/core/Actio nManager.java,v retrieving revision 1.5 diff -u -r1.5 ActionManager.java --- ActionManager.java 2001/03/12 19:51:33 1.5 +++ ActionManager.java 2001/03/27 14:23:29 @@ -72,6 +72,8 @@ public class ActionManager { /** Parameters for the Command constructor. */ private static final Class[] COMMAND_CTOR_PARAMS = { AppContext.class }; + private static final Class[] COMMAND_CTOR_PARAMS_WITH_EVENT = + { AppContext.class, EventObject.class }; /** Externalized resources. */ private ResourceManager _resources = null; @@ -207,6 +209,12 @@ for(int i = 0; i < _actionIDs.length; i++) { AntAction action = (AntAction) _actions.get(_actionIDs[i]); + + // If the action is hidden do not display it. + if(action.isHidden()) { + continue; + } + // If it has an icon, then we add it to the toolbar. if(action.getIcon() != null) { if(action.isPreceededBySeparator()) { @@ -232,51 +240,78 @@ return retval; } - /** + /** * Create a popup menu with the given actionIDs. - * XXX check this for object leak. Does the button - * get added to the action as a listener? There are also some - * changes to this behavior in 1.3. - * + * XXX check this for object leak. Does the button + * get added to the action as a listener? There are also some + * changes to this behavior in 1.3. + * * @param actionIDs List of action IDs for actions - * to appear in popup menu. + * to appear in popup menu. + * @param defaultID Use this action ID if the item + * from the list is not found. * @return Popup menu to display. */ - public JPopupMenu createPopup(String[] actionIDs) { + public JPopupMenu createPopup(String[] actionIDs, String defaultID) { + JPopupMenu retval = new JPopupMenu(); for(int i = 0; i < actionIDs.length; i++) { AntAction action = (AntAction) _actions.get(actionIDs[i]); - if(action != null) { + + // If the ID is not found, use the default. + if (action == null && defaultID != null) { + action = (AntAction) _actions.get(defaultID); AbstractButton button = retval.add(action); + + // Set the button text to the action ID. + button.setText(actionIDs[i]); addNiceStuff(button, action); + } else { + if(action.isPopupPreceededBySeparator() && + retval.getComponentCount() > 0) { + retval.addSeparator(); + } + + AbstractButton button = retval.add(action); + addNiceStuff(button, action); } } return retval; } - /** + /** * Get the command assocaited with the Action with the given id. - * + * * @param actionID Id of action to get command for. * @return Command associated with action, or null if none available. */ - public Command getActionCommand(String actionID, AppContext context) { + public Command getActionCommand(String actionID, + AppContext context, + EventObject event) { Command retval = null; AntAction action = (AntAction) _actions.get(actionID); if(action != null) { Class clazz = action.getCommandClass(); if(clazz != null) { try { - Constructor ctor = + Constructor ctor = clazz.getConstructor(COMMAND_CTOR_PARAMS); retval = (Command) ctor.newInstance( new Object[] { context }); } catch(Exception ex) { - // XXX log me. - ex.printStackTrace(); + try { + Constructor ctor = clazz.getConstructor( + COMMAND_CTOR_PARAMS_WITH_EVENT); + retval = (Command) ctor.newInstance( + new Object[] { context, event }); + } + catch (Exception ex2) { + // XXX log me. + ex.printStackTrace(); + } } } } Index: AntAction.java =================================================================== RCS file: /home/cvspublic/jakarta-ant/src/antidote/org/apache/tools/ant/gui/core/AntAc tion.java,v retrieving revision 1.4 diff -u -r1.4 AntAction.java --- AntAction.java 2001/03/12 19:51:34 1.4 +++ AntAction.java 2001/03/27 14:24:02 @@ -73,6 +73,7 @@ /** Property name for the parent menu item. */ public static final String PARENT_MENU_NAME = "parentMenuName"; public static final String SEPARATOR = "separator"; + public static final String POPUP_SEPARATOR = "popupSeparator"; public static final String ACCELERATOR = "accelerator"; public static final String ENABLED = "enabled"; public static final String ENABLE_ON = "enableOn"; @@ -81,6 +82,7 @@ public static final String CHECKED_TRUE_ON = "checkedTrueOn"; public static final String CHECKED_FALSE_ON = "checkedFalseOn"; public static final String COMMAND = "command"; + public static final String HIDDEN = "hidden"; /** Property resources. */ private ResourceManager _resources = null; @@ -118,6 +120,8 @@ putValue(SHORT_DESCRIPTION, getString("shortDescription")); putValue(PARENT_MENU_NAME, getString(PARENT_MENU_NAME)); putValue(SEPARATOR, getString(SEPARATOR)); + putValue(POPUP_SEPARATOR, getString(POPUP_SEPARATOR)); + putValue(HIDDEN, getString(HIDDEN)); // Set the default enabled state. @@ -268,6 +272,28 @@ return (Icon) getValue(SMALL_ICON); } + /** + * Determine if a separator should appear before the action + * when the popup menu is created. + * + * @return True if add separator, false otherwise. + */ + public boolean isPopupPreceededBySeparator() { + return Boolean.valueOf( + String.valueOf(getValue(POPUP_SEPARATOR))).booleanValue(); + } + + /** + * Determine if the action is hidden and should not + * be displayed from a button. + * + * @return True the action is hidden. + */ + public boolean isHidden() { + return Boolean.valueOf( + String.valueOf(getValue(HIDDEN))).booleanValue(); + } + /** * Get the accelerator keystroke. * Index: EventResponder.java =================================================================== RCS file: /home/cvspublic/jakarta-ant/src/antidote/org/apache/tools/ant/gui/core/Event Responder.java,v retrieving revision 1.2 diff -u -r1.2 EventResponder.java --- EventResponder.java 2001/01/03 14:18:20 1.2 +++ EventResponder.java 2001/03/27 14:25:08 @@ -113,9 +113,8 @@ */ public boolean eventPosted(EventObject event) { String command = ((ActionEvent)event).getActionCommand(); - Command cmd = - _context.getActions().getActionCommand(command, _context); + _context.getActions().getActionCommand(command, _context, event); if(cmd != null) { cmd.run(); return false; Index: ElementNavigator.java =================================================================== RCS file: /home/cvspublic/jakarta-ant/src/antidote/org/apache/tools/ant/gui/modules/ed it/ElementNavigator.java,v retrieving revision 1.5 diff -u -r1.5 ElementNavigator.java --- ElementNavigator.java 2001/01/12 19:02:46 1.5 +++ ElementNavigator.java 2001/03/27 14:18:47 @@ -138,6 +138,9 @@ // The project node has changed. model.fireNodeChanged((ACSElement)event.getSource()); } + else if(event instanceof RefreshDisplayEvent && model != null) { + _tree.updateUI(); + } else if(event instanceof NewElementEvent && model != null) { ACSElement element = ((NewElementEvent)event).getNewElement(); model.fireNodeAdded(element); @@ -145,6 +148,9 @@ _selections.setSelectionPath(path); _tree.scrollPathToVisible(path); } + else if(event instanceof DeleteElementEvent && model != null) { + _tree.updateUI(); + } else { ACSProjectElement project = null; if(event instanceof ProjectSelectedEvent) { @@ -163,11 +169,31 @@ ElementSelectionEvent.createEvent(getContext(), null); } else { - _tree.setModel(new ElementTreeModel(project)); - _selections = new ElementTreeSelectionModel(); - _selections.addTreeSelectionListener( - new SelectionForwarder()); - _tree.setSelectionModel(_selections); + boolean updateModel = false; + TreeModel testModel = _tree.getModel(); + + // Set the model if's not an ElementTreeModel + if (testModel instanceof ElementTreeModel) { + ElementTreeModel etm = (ElementTreeModel) testModel; + ACSProjectElement currentProject = + (ACSProjectElement) etm.getRoot(); + + // Set the model if the project is wrong + if (currentProject != project) { + updateModel = true; + } + } else { + updateModel = true; + } + + // Should we update the tree model + if (updateModel) { + _tree.setModel(new ElementTreeModel(project)); + _selections = new ElementTreeSelectionModel(); + _selections.addTreeSelectionListener( + new SelectionForwarder()); + _tree.setSelectionModel(_selections); + } } } return true; @@ -195,7 +221,9 @@ return event instanceof ProjectSelectedEvent || event instanceof ProjectClosedEvent || event instanceof NewElementEvent || - event instanceof PropertyChangeEvent; + event instanceof PropertyChangeEvent || + event instanceof DeleteElementEvent || + event instanceof RefreshDisplayEvent; } } @@ -203,11 +231,42 @@ private class PopupHandler extends MouseAdapter { private void handle(MouseEvent e) { if(e.isPopupTrigger()) { - ActionManager mgr = getContext().getActions(); - JPopupMenu menu = mgr.createPopup( - getContext().getResources().getStringArray( - ElementNavigator.class, "popupActions")); - menu.show((JComponent)e.getSource(), e.getX(), e.getY()); + Object source = e.getSource(); + String[] menuStr = null; + JTree tree = (JTree) source; + + // Find the selected path. + TreePath selPath = tree.getPathForLocation( + e.getX(), e.getY()); + if (selPath == null) { + return; + } + + // Update the selection. + tree.setSelectionPath(selPath); + + // Find the selected object. + Object selObj = selPath.getLastPathComponent(); + + String defaultID = null; + + // Does the item provide its own menu? + if (selObj instanceof ACSInfoProvider) { + ACSInfoProvider ip = (ACSInfoProvider) selObj; + menuStr = ip.getMenuString(); + defaultID = ip.getDefaultActionID(); + } else { + // Get the menu from the prop file. + menuStr = getContext().getResources().getStringArray( + ElementNavigator.class, defaultID); + } + + // Should we create a menu? + if (menuStr != null && menuStr.length != 0) { + ActionManager mgr = getContext().getActions(); + JPopupMenu menu = mgr.createPopup(menuStr, defaultID); + menu.show((JComponent)e.getSource(), e.getX(), e.getY()); + } } } Index: action.properties =================================================================== RCS file: /home/cvspublic/jakarta-ant/src/antidote/org/apache/tools/ant/gui/resources/ action.properties,v retrieving revision 1.16 diff -u -r1.16 action.properties --- action.properties 2001/03/12 19:51:42 1.16 +++ action.properties 2001/03/27 14:26:49 @@ -4,7 +4,7 @@ # Declare the list of known actions. actions=\ new, open, save, saveas, close, exit, about, \ - newTarget, newTask, newProperty \ + newTarget, newElement, newProperty, deleteElement, \ startBuild, stopBuild, viewConsole # Configure the decalred actions. @@ -120,7 +120,8 @@ org.apache.tools.ant.gui.event.TaskSelectionEvent, \ org.apache.tools.ant.gui.event.PropertySelectionEvent, \ org.apache.tools.ant.gui.event.ProjectClosedEvent, \ - org.apache.tools.ant.gui.event.NullSelectionEvent + org.apache.tools.ant.gui.event.NullSelectionEvent, \ + org.apache.tools.ant.gui.event.DtdDefinedElementSelectionEvent newTask.name=New Task newTask.shortDescription=Create a new task under the selected target @@ -133,7 +134,8 @@ org.apache.tools.ant.gui.event.ProjectClosedEvent, \ org.apache.tools.ant.gui.event.TaskSelectionEvent, \ org.apache.tools.ant.gui.event.PropertySelectionEvent, \ - org.apache.tools.ant.gui.event.NullSelectionEvent + org.apache.tools.ant.gui.event.NullSelectionEvent, \ + org.apache.tools.ant.gui.event.DtdDefinedElementSelectionEvent newProperty.name=New Property newProperty.shortDescription=Create a new property under the selected element @@ -148,7 +150,24 @@ newProperty.disableOn=\ org.apache.tools.ant.gui.event.PropertySelectionEvent, \ org.apache.tools.ant.gui.event.ProjectClosedEvent, \ - org.apache.tools.ant.gui.event.NullSelectionEvent + org.apache.tools.ant.gui.event.NullSelectionEvent, \ + org.apache.tools.ant.gui.event.DtdDefinedElementSelectionEvent + +newElement.name=New Element +newElement.shortDescription=Create a new element under the selected element +newElement.icon=default.gif +newElement.command=org.apache.tools.ant.gui.command.NewElementCmd +newElement.enabled=true +newElement.hidden=true +newElement.popupSeparator=true + +deleteElement.name=Delete Element +deleteElement.shortDescription=Delete the selected element +deleteElement.icon=default.gif +deleteElement.command=org.apache.tools.ant.gui.command.DeleteElementCmd +deleteElement.enabled=true +deleteElement.hidden=true +deleteElement.popupSeparator=true viewConsole.name=console viewConsole.shortDescription=Displays or hides the console pane Index: antidote.properties =================================================================== RCS file: /home/cvspublic/jakarta-ant/src/antidote/org/apache/tools/ant/gui/resources/ antidote.properties,v retrieving revision 1.23 diff -u -r1.23 antidote.properties --- antidote.properties 2001/03/08 15:37:50 1.23 +++ antidote.properties 2001/03/27 14:27:20 @@ -108,6 +108,14 @@ org.apache.tools.ant.gui.acs.ACSTaskElementBeanInfo.xmlString=XML Code org.apache.tools.ant.gui.acs.ACSTaskElementBeanInfo.icon=task.gif +org.apache.tools.ant.gui.acs.ACSDtdDefinedElementBeanInfo.beanName= +org.apache.tools.ant.gui.acs.ACSDtdDefinedElementBeanInfo.beanDescription=\ + A scoped property +org.apache.tools.ant.gui.acs.ACSDtdDefinedElementBeanInfo.taskType=Type +org.apache.tools.ant.gui.acs.ACSDtdDefinedElementBeanInfo.namedValues=\ + Attributes +org.apache.tools.ant.gui.acs.ACSDtdDefinedElementBeanInfo.xmlString=XML Code +org.apache.tools.ant.gui.acs.ACSDtdDefinedElementBeanInfo.icon=default.gif org.apache.tools.ant.gui.command.NewProjectCmd.defName=New Project org.apache.tools.ant.gui.command.NewTargetCmd.defName=New Target Index: acs-element.properties =================================================================== RCS file: /home/cvspublic/jakarta-ant/src/antidote/org/apache/tools/ant/gui/acs/acs-el ement.properties,v retrieving revision 1.3 diff -u -r1.3 acs-element.properties --- acs-element.properties 2000/12/14 23:03:25 1.3 +++ acs-element.properties 2001/03/27 14:30:12 @@ -3,10 +3,12 @@ # # The default element -*Element=org.apache.tools.ant.gui.acs.ACSDefaultElement +*Element=org.apache.tools.ant.gui.acs.ACSDtdDefinedElement # Specific elements. project=org.apache.tools.ant.gui.acs.ACSProjectElement property=org.apache.tools.ant.gui.acs.ACSPropertyElement target=org.apache.tools.ant.gui.acs.ACSTargetElement task=org.apache.tools.ant.gui.acs.ACSTaskElement + +