*) Design document. *) can now write BuildEvents to console. Submitted by: Simeon Fitch <metasim@yahoo.com> git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@268152 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -4,6 +4,8 @@ Changes from Ant 1.2 to the current sources | |||
| Other changes: | |||
| -------------- | |||
| * A GUI Frontend: Antidote | |||
| * New tasks: propertyfile, depend, antlr | |||
| * Added output attribute to <java>. | |||
| @@ -1,3 +1,43 @@ | |||
| 2000-11-05 Simeon H.K. Fitch <simeon@fitch.net> | |||
| * org/apache/tools/ant/gui/LogLevelEnum.java: Added log level | |||
| enumeration for use with combo boxes (drops nicely into default model). | |||
| * org/apache/tools/ant/gui/event/BuildEventType.java: Added | |||
| delivering of event to a BuildListener based on enumeration value. | |||
| * org/apache/tools/ant/gui/ProjectProxy.java: Added generation of | |||
| BuildEvent on project start and finish, as the project itself | |||
| doesn't generate theses events (unfortunately). | |||
| * org/apache/tools/ant/gui/Console.java: Added filtering level, | |||
| and clearing of buffer when a new build starts. | |||
| * org/apache/tools/ant/gui/AntEditor.java: Added automatic border | |||
| for all subclasses. | |||
| 2000-11-04 Simeon H.K. Fitch <simeon@fitch.net> | |||
| * org/apache/tools/ant/gui/ProjectProxy.java: Added inner class to | |||
| execute the build in a separate thread. | |||
| * org/apache/tools/ant/gui/event/EventBus.java: Added check to see | |||
| if postEvent() is being called on the AWTEvent thread, and if not, | |||
| post the dispatching of the event to that thread. This is needed | |||
| as most of the listeners will be bound to GUI components and will | |||
| be updating their state (which must occur on the event thread). | |||
| * org/apache/tools/ant/gui/ProjectProxy.java: Added a | |||
| BuildListener to forward events to the EventBus. | |||
| 2000-11-03 Simeon H.K. Fitch <simeon@fitch.net> | |||
| * org/apache/tools/ant/gui/Antidote.java: Removed hard-coded | |||
| Console class. | |||
| * org/apache/tools/ant/gui/Console.java: Changed to a real | |||
| AntEditor class, initialized by the config file. | |||
| 2000-11-02 Simeon H.K. Fitch <simeon@fitch.net> | |||
| * org/apache/tools/ant/gui/event/EventBus.java: Added interrupt | |||
| @@ -50,8 +50,8 @@ | |||
| <javac srcdir="${src.dir}" | |||
| destdir="${build.classes}" | |||
| debug="on" | |||
| deprecation="off" | |||
| optimize="on" > | |||
| deprecation="on" | |||
| optimize="off" > | |||
| <classpath refid="classpath" /> | |||
| </javac> | |||
| @@ -0,0 +1,258 @@ | |||
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "strict.dtd"> | |||
| <HTML> | |||
| <HEAD> | |||
| <TITLE>Antidote Design Overview</TITLE> | |||
| </HEAD> | |||
| <BODY> | |||
| <H1>Antidote Design Overview</H1> | |||
| <P>Version 0.1 (2000/11/02)</P> | |||
| <P>Authors: | |||
| <A HREF="mailto:simeon@fitch.net">Simeon H.K. Fitch</A> | |||
| </P> | |||
| <H2>Introduction</H2> | |||
| <P>The purpose of this document is to communicate the overall | |||
| structure and design patters used in Antidote, the GUI for | |||
| Ant. This document is a work in progress, as well as a living | |||
| document, and it is most likely not be in full synchronization with | |||
| the source code. Therefore, if there is any doubt, view the source | |||
| ;-)</P> | |||
| <H2>Overview</H2> | |||
| <P>The Antidote architecture design aims to provide a high level | |||
| of modularity and extensibility. Ideally the components of | |||
| Antidote will be able to be assembled in different configurations | |||
| to provide the type of application or plug-in desired.</P> | |||
| <P>To acheive this modularity, a high level of decoupling is | |||
| necessary. The standard UI design approach of providing separation | |||
| of view (presentation) from model (data) is applied, leveraging | |||
| the built-in Ant data model where possible, as well as the | |||
| predifined Swing model interfaces. Furthermore, the architecture | |||
| is highly event driven, whereby modules communicate via a shared | |||
| communications channel.</P> | |||
| <P>To a large extent, the configuration of application modules is | |||
| driven by localized configuration files, allowing new editors or | |||
| data views to be added, as well as providing multi-language | |||
| support.</P> | |||
| <P>The diagram below conveys a high altitude view of the | |||
| application's structure. As the application grows, new components | |||
| will be plugged in to what will be described as the <TT>EventBus</TT>. | |||
| <TT><PRE> | |||
| Antidote Component Architecture | |||
| +---------------+ +----------------+ +-------------+ +-------------+ | |||
| | | | | | | | | | |||
| | ActionManager | | EventResponder | | AntEditor | | AntEditor | | |||
| | | | | |(ProjectNav) | |(SourceEdit) | | |||
| +---------------+ +----------------+ +-------------+ +-------------+ | |||
| | ^ ^ ^ | |||
| | | | | | |||
| ActionEvent EventObject AntEvent AntEvent | |||
| | | | | | |||
| v v v v | |||
| /---------------------------------------------------------------------\ | |||
| / \ | |||
| < EventBus > | |||
| \ / | |||
| \---------------------------------------------------------------------/ | |||
| | ^ ^ ^ | |||
| | | | | | |||
| EventObject ChangeEvent BuildEvent EventObject | |||
| | | | | | |||
| v | | v | |||
| +---------------+ +----------------+ +-------------+ +--------------+ | |||
| | | | | | | | | | |||
| | Console | | ProjectProxy | | Ant | | (Your Module)| | |||
| | | | | | | | | | |||
| +---------------+ +----------------+ +-------------+ +--------------+ | |||
| </TT></PRE> | |||
| <H2>Event Bus</H2> | |||
| <P>The backbone of the application is the <TT>EventBus</TT>. Any | |||
| component of the application can post events to the | |||
| <TT>EventBus</TT>. Components that wish to receive events are | |||
| called <TT>BusMember</TT>s.</P> | |||
| <P>The <TT>EventBus</TT> will dispatch any object of type | |||
| <TT>java.util.EventBus</TT>, which means that Ant <TT>BuildEvent</TT> | |||
| objects, as well as <TT>AWTEvent</TT> objects can be posted (if desired). A | |||
| new class of events called <TT>AntEvent</TT> is defined for Antidote | |||
| specific events, which have the additional capability of being | |||
| cancelled mid-dispatch.</P> | |||
| <P>Each <TT>BusMember</TT> must provide a <TT>BusFilter</TT> instance, | |||
| which is the members' means of telling the bus which | |||
| events it is interested in. This allows a <TT>BusMember</TT> to, | |||
| say, only receive <TT>AntEvent</TT> objects.</P> | |||
| <P>When a <TT>BusMember</TT> registers itself with the | |||
| <TT>EventBus</TT>, it must provide a (so called) <I>interrupt | |||
| level</I> which is a integer value defining a relative ordering | |||
| for dispatching <TT>EventObject</TT>s to <TT>BusMember</TT>s. The | |||
| purpose of this is to allow certain <TT>BusMember</TT> instances | |||
| to see an event before others, and in the case of <TT>AntEvent</TT | |||
| objects, keep the event from propogating onward. The | |||
| <TT>EventBus</TT> class defines the interrupt level constants | |||
| <TT>MONITORING=1</TT>, <TT>VETOING=5</TT>, and <TT>RESPONDING=10</TT> to | |||
| help define categories of members. The implied purpose being that: | |||
| <UL> | |||
| <LI><TT>MONITORING</TT>: Just listens for events, like a logger | |||
| or status monitor.</LI> | |||
| <LI><TT>VETOING</TT>: Listens for certain types of events, and | |||
| may process them in a non-default manner to determine if the | |||
| event should be cancelled before being dispatched to the | |||
| <TT>RESPONDING</TT> group. An example of this might be to handle | |||
| a <I>SaveAs</I> event, whereby a <TT>VETOING</TT> member will | |||
| check to see if the file exists, and ask the user if they are | |||
| sure they want to overwrite the existing file. The <I>SaveAs</I> | |||
| event could then be cancelled before the operation is executed.</LI> | |||
| <LI><TT>RESPONDING</TT>: Process events in a default manner, | |||
| knowing that the event has passed any <TT>VETOING</TT> members.</LI> | |||
| </UL> | |||
| Within a specific interrupt level, the order in which members will | |||
| receive events is undefied. A <TT>BusMember</TT> may be registered | |||
| at a level that is +/- of one of the defined levels, as long as it | |||
| follows the constraint <TT>MONITORING <= interruptLevel <= | |||
| MAX_INTERRUPT</TT>.</P> | |||
| <H2>Actions and ActionManager</H2> | |||
| <P>Extensive use of the <TT>javax.swing.Action</TT> interface is | |||
| made for defining the set of menu and tool bar options that are | |||
| available. The configuration file <TT>action.properties</TT> | |||
| exists to define what should appear in the menu and toolbar, how | |||
| it is displayed, and the <TT>Action</TT> command name that is | |||
| dispatched when the user invokes that action. A class called | |||
| <TT>ActionManager</TT> exists for not only processing the | |||
| configuration file, but also for dispatching invoked action events | |||
| to the <TT>EventBus</TT>, and for controlling the enabled state of | |||
| an <TT>Action</TT>. When a new menu item or toolbar button is | |||
| desired, first it is added to the <TT>action.properties</TT> file, | |||
| and then the code to respond to it is added to the | |||
| <TT>EventResponder</TT> (see below). | |||
| <H2>Commands and EventResponder</H2> | |||
| <P>At some point in the stages of event processing, an event may | |||
| require the data model to be modified, or some other task be | |||
| performed. The <TT>Command</TT> interface is defined to classify | |||
| code which performs some task or operation. This is distinct from | |||
| an <TT>Action</TT>, which is a user request for an operation. A | |||
| <TT>Command</TT> class is the encapsulation of the operation | |||
| itself.</P> | |||
| <P>When an <TT>Action</TT> generates an <TT>ActionEvent</TT>, the | |||
| event is posted to the <TT>EventBus</TT> which delivers the event | |||
| to all interested <TT>BusMember</TT>s. It eventually makes it to | |||
| the <TT>EventResponder</TT> instance (registered at the | |||
| <TT>RESPONDING</TT> interrupt level), which is responsible for | |||
| translating specific events into <TT>Command</TT> objects, and | |||
| then executing the <TT>Command</TT> object. For example, when the | |||
| user selects the "Open..." menu option, an <TT>ActionEvent</TT> is | |||
| generated by the Swing <TT>MenuItem</TT> class, which is then | |||
| posted to the <TT>EventBus</TT> by the <TT>ActionManager</TT>. The | |||
| <TT>ActionEvent</TT> is delivered to the <TT>EventResponder</TT>, | |||
| which converts the <TT>ActionEvent</TT> into a <TT>Command</TT> | |||
| instance. The <TT>EventResponder</TT> then calls the method | |||
| <TT>Command.execute()</TT> to invoke the command (which displays a | |||
| dialog for selecting a file to open).</P> | |||
| <P>When adding new <TT>Action</TT>s or general tasks to the | |||
| application, a <TT>Command</TT> object should be created to | |||
| encapsulate the behavior. This includes most operations which | |||
| modify the state of the data model.</P> | |||
| <P>The purpose of this encapsulation is to allow the clean | |||
| separation of making a request, and servicing a request. Due to | |||
| various conditions in the application state, the actualy response | |||
| to a request may change, as well as who services it. This | |||
| design approach facilitates that.</P> | |||
| <H2>Data Model and Views</H2> | |||
| <P>The data model is mainly defined by the Ant application, | |||
| primarily through the <TT>Project</TT>, <TT>Target</TT>, and | |||
| <TT>Task</TT> classes.<P> However, Antidote defines the class | |||
| <TT>ProjectProxy</TT> to act not only as a proxy to the real | |||
| <TT>Project</TT> class, but also as creator of GUI <I>views</I> of | |||
| the <TT>Project</TT>. A <I>view</I> is essentially a flyweight or | |||
| data proxy; it provides an orgainizational perspective on the actual | |||
| <TT>Project</TT> structure. For example, to render a | |||
| <TT>JTree</TT> version of the <TT>Project</TT>, one would call the | |||
| method <TT>ProjectProxy.getTreeModel()</TT>. Similarly, to get a | |||
| <TT>Document</TT> version of the <TT>Project</TT>, the | |||
| <TT>ProjectProxy,getDocument()</TT> method is used.</P> | |||
| <P><I>NB: This part of the architecture is not fleshed out very | |||
| well. There needs to be a discussion of the degree to which the | |||
| Antidote development should be able to impose changes on the Ant | |||
| data model, and to what level that model should be mirrored in the | |||
| Antidote code base. The coupling between them should be kept low, | |||
| and at the same time changes to one should affect the other | |||
| minimally. Still, features like property change events and bean | |||
| introspection (or BeanInfo) may be needed to be added to the Ant | |||
| data model. Having each view into the data go to the ProjectProxy | |||
| for its data model may not be the best approach. In other words, | |||
| lots of thought needs to occur here.</I></P> | |||
| <H2>Application Context</H2> | |||
| <P>In order to keep the coupling amoung application modules to a | |||
| minimum, a single point of reference is needed for coordination | |||
| and data sharing. The class <TT>AppContext</TT> is the catch-all | |||
| class for containing the application state. Most modules and | |||
| <TT>Command</TT> classes require an instance of the | |||
| <TT>AppContext</TT> class. Because all state information in | |||
| contained in an <TT>AppContext</TT> instance, multiple instances | |||
| of Antidote can run inside the same JVM as long as each has it's | |||
| own <TT>AppContext</TT>. (Interestingly, two instances of the | |||
| Antidote could conceivably share an <TT>AppContext</TT> instance | |||
| through RMI, allowing remote interaction/collaboration.)</P> | |||
| <H2>Configuration and ResourceManager</H2> | |||
| <P>Full "i18n" support should be assumed in modern applications, | |||
| and all user viewable strings should be defined in a configuration | |||
| file. For Antidote this configuraiton file is | |||
| <TT>antidote.properties</TT>, which is located (with other UI | |||
| resources) in the subpackage "resources".</P> | |||
| <P>To aid in the lookup of text properties, as well as other | |||
| resources like icons, a class called <TT>ResourceManager</TT> is | |||
| defined. There are various convenience methods attached to this | |||
| class, which will likely grow to make looking up configuration | |||
| values as easy as possible.</P> | |||
| <P>The organization of configuration properties is based on the | |||
| fully qualifed path of the class that requires the property. For | |||
| example, the "about" box contains a messages, so it looks for the | |||
| property "<TT>org.apache.tools.ant.gui.About.message</TT>" for the text | |||
| message it should display. Therefore, the <TT>ResourceManager</TT> | |||
| method <TT>getString()</TT> takes a <TT>Class</TT> instance as | |||
| well as a <TT>String</TT> key. Please see the | |||
| <TT>ResourceManager</TT> documentation for more information. Given | |||
| this support, no user visible strings should appear in the source | |||
| code itself.</P> | |||
| </BODY> | |||
| </HTML> | |||
| @@ -113,7 +113,24 @@ public class ActionManager { | |||
| while(tok.hasMoreTokens()) { | |||
| String name = tok.nextToken(); | |||
| JMenu menu = new JMenu(name); | |||
| retval.add(menu); | |||
| // XXX should be in config file | |||
| menu.setMnemonic(name.charAt(0)); | |||
| // XXX need to i18n here... | |||
| if(name.equalsIgnoreCase("help")) { | |||
| try { | |||
| retval.setHelpMenu(menu); | |||
| } | |||
| catch(Error err) { | |||
| // Catch the "not implemented" error in | |||
| // some (all?) Swing implementations | |||
| retval.add(menu); | |||
| } | |||
| } | |||
| else { | |||
| retval.add(menu); | |||
| } | |||
| menus.put(name, menu); | |||
| } | |||
| @@ -130,10 +147,13 @@ public class ActionManager { | |||
| menus.put(parent, menu); | |||
| } | |||
| if(action.isPreceededBySeparator()) { | |||
| // See if we should add a separator. | |||
| if(action.isPreceededBySeparator() && | |||
| menu.getMenuComponentCount() > 0) { | |||
| menu.addSeparator(); | |||
| } | |||
| JMenuItem item = menu.add(action); | |||
| item.setAccelerator(action.getAccelerator()); | |||
| addNiceStuff(item, action); | |||
| } | |||
| } | |||
| @@ -171,6 +191,13 @@ public class ActionManager { | |||
| // Set the action command so that it is consitent | |||
| // no matter what language the display is in. | |||
| button.setActionCommand(action.getID()); | |||
| // XXX this should be moved to the config file. | |||
| String label = button.getText(); | |||
| if(label != null) { | |||
| button.setMnemonic(label.charAt(0)); | |||
| } | |||
| String tip = action.getShortDescription(); | |||
| if(tip != null) { | |||
| button.setToolTipText(tip); | |||
| @@ -202,6 +229,7 @@ public class ActionManager { | |||
| /** 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 ACCELERATOR = "accelerator"; | |||
| /** Unique id. */ | |||
| private String _id = null; | |||
| @@ -215,8 +243,14 @@ public class ActionManager { | |||
| _id = id; | |||
| putValue(NAME, getString(id, "name")); | |||
| putValue(SHORT_DESCRIPTION, getString(id, "shortDescription")); | |||
| putValue(PARENT_MENU_NAME, getString(id, "parentMenuName")); | |||
| putValue(SEPARATOR, getString(id, "separator")); | |||
| putValue(PARENT_MENU_NAME, getString(id, PARENT_MENU_NAME)); | |||
| putValue(SEPARATOR, getString(id, SEPARATOR)); | |||
| String accelerator = getString(id, ACCELERATOR); | |||
| if(accelerator != null) { | |||
| putValue(ACCELERATOR, KeyStroke.getKeyStroke(accelerator)); | |||
| } | |||
| String iconName = getString(id, "icon"); | |||
| if(iconName != null) { | |||
| @@ -232,7 +266,6 @@ public class ActionManager { | |||
| ex.printStackTrace(); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| @@ -291,6 +324,10 @@ public class ActionManager { | |||
| return (Icon) getValue(SMALL_ICON); | |||
| } | |||
| public KeyStroke getAccelerator() { | |||
| return (KeyStroke) getValue(ACCELERATOR); | |||
| } | |||
| /** | |||
| * Pass the action on to the EventBus. | |||
| * | |||
| @@ -54,6 +54,7 @@ | |||
| package org.apache.tools.ant.gui; | |||
| import javax.swing.JPanel; | |||
| import javax.swing.BorderFactory; | |||
| /** | |||
| * Abstract base class for an "editor", which is really anything that | |||
| @@ -78,6 +79,7 @@ public abstract class AntEditor extends JPanel { | |||
| */ | |||
| protected AntEditor(AppContext context) { | |||
| _context = context; | |||
| setBorder(BorderFactory.createTitledBorder(getName())); | |||
| } | |||
| /** | |||
| @@ -66,11 +66,6 @@ import java.lang.reflect.Constructor; | |||
| * @author Simeon Fitch | |||
| */ | |||
| public class Antidote extends JPanel { | |||
| /** Logging console. */ | |||
| private Console _console = null; | |||
| /** Source of application state data. */ | |||
| private AppContext _context = null; | |||
| @@ -83,18 +78,25 @@ public class Antidote extends JPanel { | |||
| _context = context; | |||
| _console = new Console(_context); | |||
| // Add the various editors/views to the editing area. | |||
| JSplitPane splitter = new JSplitPane(); | |||
| splitter.add(JSplitPane.LEFT, populateEditors("left")); | |||
| splitter.add(JSplitPane.RIGHT, populateEditors("right")); | |||
| // This is necessary because, frankly, the JSplitPane widget | |||
| // sucks, and doesn't provide enought (working) control over the | |||
| // initial size of it's subcomponents. setDividerLocation(double) | |||
| // doesn't seem to work until after the widget is visible. | |||
| splitter.setPreferredSize(new Dimension(500, 300)); | |||
| add(BorderLayout.CENTER, splitter); | |||
| // Top bottom splitter. | |||
| JSplitPane splitter2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT); | |||
| splitter2.setOneTouchExpandable(true); | |||
| add(BorderLayout.SOUTH, _console); | |||
| splitter2.add(JSplitPane.TOP, splitter); | |||
| splitter2.add(JSplitPane.BOTTOM, populateEditors("bottom")); | |||
| add(BorderLayout.CENTER, splitter2); | |||
| splitter2.resetToPreferredSizes(); | |||
| setPreferredSize(new Dimension(640, 480)); | |||
| } | |||
| @@ -0,0 +1,151 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 1999, 2000 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * 1. Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * 2. Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in | |||
| * the documentation and/or other materials provided with the | |||
| * distribution. | |||
| * | |||
| * 3. The end-user documentation included with the redistribution, if | |||
| * any, must include the following acknowlegement: | |||
| * "This product includes software developed by the | |||
| * Apache Software Foundation (http://www.apache.org/)." | |||
| * Alternately, this acknowlegement may appear in the software itself, | |||
| * if and wherever such third-party acknowlegements normally appear. | |||
| * | |||
| * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software | |||
| * Foundation" must not be used to endorse or promote products derived | |||
| * from this software without prior written permission. For written | |||
| * permission, please contact apache@apache.org. | |||
| * | |||
| * 5. Products derived from this software may not be called "Apache" | |||
| * nor may "Apache" appear in their names without prior written | |||
| * permission of the Apache Group. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| * SUCH DAMAGE. | |||
| * ==================================================================== | |||
| * | |||
| * This software consists of voluntary contributions made by many | |||
| * individuals on behalf of the Apache Software Foundation. For more | |||
| * information on the Apache Software Foundation, please see | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.gui; | |||
| import org.apache.tools.ant.gui.event.*; | |||
| import org.apache.tools.ant.BuildListener; | |||
| import org.apache.tools.ant.BuildEvent; | |||
| /** | |||
| * BuildListener for forwarding events to the EventBus. | |||
| * | |||
| * @version $Revision$ | |||
| * @author Simeon Fitch | |||
| */ | |||
| public class BuildEventForwarder implements BuildListener { | |||
| /** Application context. */ | |||
| private AppContext _context = null; | |||
| public BuildEventForwarder(AppContext context) { | |||
| _context = context; | |||
| } | |||
| /** | |||
| * Fired before any targets are started. | |||
| */ | |||
| public void buildStarted(BuildEvent event){ | |||
| postEvent(event, BuildEventType.BUILD_STARTED); | |||
| } | |||
| /** | |||
| * Fired after the last target has finished. This event | |||
| * will still be thrown if an error occured during the build. | |||
| * | |||
| * @see BuildEvent#getException() | |||
| */ | |||
| public void buildFinished(BuildEvent event) { | |||
| postEvent(event, BuildEventType.BUILD_FINISHED); | |||
| } | |||
| /** | |||
| * Fired when a target is started. | |||
| * | |||
| * @see BuildEvent#getTarget() | |||
| */ | |||
| public void targetStarted(BuildEvent event) { | |||
| postEvent(event, BuildEventType.TARGET_STARTED); | |||
| } | |||
| /** | |||
| * Fired when a target has finished. This event will | |||
| * still be thrown if an error occured during the build. | |||
| * | |||
| * @see BuildEvent#getException() | |||
| */ | |||
| public void targetFinished(BuildEvent event) { | |||
| postEvent(event, BuildEventType.TARGET_FINISHED); | |||
| } | |||
| /** | |||
| * Fired when a task is started. | |||
| * | |||
| * @see BuildEvent#getTask() | |||
| */ | |||
| public void taskStarted(BuildEvent event) { | |||
| postEvent(event, BuildEventType.TASK_STARTED); | |||
| } | |||
| /** | |||
| * Fired when a task has finished. This event will still | |||
| * be throw if an error occured during the build. | |||
| * | |||
| * @see BuildEvent#getException() | |||
| */ | |||
| public void taskFinished(BuildEvent event) { | |||
| postEvent(event, BuildEventType.TASK_FINISHED); | |||
| } | |||
| /** | |||
| * Fired whenever a message is logged. | |||
| * | |||
| * @see BuildEvent#getMessage() | |||
| * @see BuildEvent#getPriority() | |||
| */ | |||
| public void messageLogged(BuildEvent event) { | |||
| postEvent(event, BuildEventType.MESSAGE_LOGGED); | |||
| } | |||
| /** | |||
| * Forward the event. | |||
| * | |||
| * @param event Event to forward. | |||
| * @param type Description of how the event came in. | |||
| */ | |||
| private void postEvent(BuildEvent event, BuildEventType type) { | |||
| _context.getEventBus().postEvent( | |||
| new AntBuildEvent(_context, event, type)); | |||
| } | |||
| } | |||
| @@ -52,10 +52,13 @@ | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.gui; | |||
| import org.apache.tools.ant.gui.event.*; | |||
| import javax.swing.*; | |||
| import java.awt.GridLayout; | |||
| import javax.swing.text.Document; | |||
| import java.awt.BorderLayout; | |||
| import java.awt.FlowLayout; | |||
| import java.awt.Dimension; | |||
| import java.util.EventObject; | |||
| /** | |||
| * Logging console display. | |||
| @@ -63,22 +66,114 @@ import java.awt.Dimension; | |||
| * @version $Revision$ | |||
| * @author Simeon Fitch | |||
| */ | |||
| public class Console extends JPanel { | |||
| private AppContext _context = null; | |||
| public class Console extends AntEditor { | |||
| /** Area where messages are printed. */ | |||
| private JTextPane _text = null; | |||
| /** Selection of logging levels. */ | |||
| private JComboBox _logLevel = null; | |||
| /** | |||
| * Standard ctor. | |||
| * | |||
| * @param context Application context; | |||
| */ | |||
| public Console(AppContext context) { | |||
| setLayout(new GridLayout(1,1)); | |||
| _context = context; | |||
| super(context); | |||
| context.getEventBus().addMember(EventBus.MONITORING, new Handler()); | |||
| setLayout(new BorderLayout()); | |||
| _text = new JTextPane(); | |||
| _text.setEditable(false); | |||
| JScrollPane scroller = new JScrollPane(_text); | |||
| scroller.setVerticalScrollBarPolicy( | |||
| JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); | |||
| add(BorderLayout.CENTER, scroller); | |||
| JPanel controls = new JPanel(new FlowLayout(FlowLayout.LEFT)); | |||
| JLabel label = new JLabel( | |||
| context.getResources().getString(getClass(), "logLevel")); | |||
| controls.add(label); | |||
| _logLevel = new JComboBox(LogLevelEnum.getValues()); | |||
| controls.add(_logLevel); | |||
| add(scroller); | |||
| add(BorderLayout.NORTH, controls); | |||
| _text.setText( | |||
| "This is the console area. \nLots of stuff to see here..."); | |||
| setPreferredSize(new Dimension(200, 40)); | |||
| } | |||
| /** Class for handling project events. */ | |||
| private class Handler implements BusMember { | |||
| private final Filter _filter = new Filter(); | |||
| /** | |||
| * Get the filter to that is used to determine if an event should | |||
| * to to the member. | |||
| * | |||
| * @return Filter to use. | |||
| */ | |||
| public BusFilter getBusFilter() { | |||
| return _filter; | |||
| } | |||
| /** | |||
| * Called when an event is to be posed to the member. | |||
| * | |||
| * @param event Event to post. | |||
| */ | |||
| public void eventPosted(EventObject event) { | |||
| AntBuildEvent buildEvent = (AntBuildEvent) event; | |||
| String text = null; | |||
| Document doc = _text.getDocument(); | |||
| switch(buildEvent.getType().getValue()) { | |||
| case BuildEventType.BUILD_STARTED_VAL: | |||
| try { | |||
| doc.remove(0, doc.getLength()); | |||
| } | |||
| catch(Exception ex) { | |||
| // Intentionally ignored. | |||
| } | |||
| break; | |||
| case BuildEventType.TARGET_STARTED_VAL: | |||
| text = buildEvent.getEvent().getTarget().getName() + ":"; | |||
| break; | |||
| case BuildEventType.TARGET_FINISHED_VAL: | |||
| case BuildEventType.TASK_STARTED_VAL: | |||
| case BuildEventType.TASK_FINISHED_VAL: | |||
| break; | |||
| case BuildEventType.MESSAGE_LOGGED_VAL: | |||
| text = buildEvent.toString(); | |||
| break; | |||
| } | |||
| // Filter out events that are below our selected filterint level. | |||
| LogLevelEnum level = (LogLevelEnum) _logLevel.getSelectedItem(); | |||
| if(buildEvent.getEvent().getPriority() > level.getValue()) return; | |||
| if(text != null) { | |||
| try { | |||
| doc.insertString(doc.getLength(), text, null); | |||
| doc.insertString(doc.getLength(), "\n", null); | |||
| } | |||
| catch(Exception ex) { | |||
| // XXX log me. | |||
| ex.printStackTrace(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** Class providing filtering for project events. */ | |||
| private static class Filter implements BusFilter { | |||
| /** | |||
| * Determines if the given event should be accepted. | |||
| * | |||
| * @param event Event to test. | |||
| * @return True if event should be given to BusMember, false otherwise. | |||
| */ | |||
| public boolean accept(EventObject event) { | |||
| return event instanceof AntBuildEvent; | |||
| } | |||
| } | |||
| } | |||
| @@ -117,6 +117,9 @@ class EventResponder { | |||
| if(command.equals(OpenCmd.ACTION_NAME)) { | |||
| new OpenCmd(_context).execute(); | |||
| } | |||
| else if(command.equals(BuildCmd.ACTION_NAME)) { | |||
| new BuildCmd(_context).execute(); | |||
| } | |||
| else if(command.equals(CloseCmd.ACTION_NAME)) { | |||
| new CloseCmd(_context).execute(); | |||
| } | |||
| @@ -0,0 +1,163 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 1999, 2000 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * 1. Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * 2. Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in | |||
| * the documentation and/or other materials provided with the | |||
| * distribution. | |||
| * | |||
| * 3. The end-user documentation included with the redistribution, if | |||
| * any, must include the following acknowlegement: | |||
| * "This product includes software developed by the | |||
| * Apache Software Foundation (http://www.apache.org/)." | |||
| * Alternately, this acknowlegement may appear in the software itself, | |||
| * if and wherever such third-party acknowlegements normally appear. | |||
| * | |||
| * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software | |||
| * Foundation" must not be used to endorse or promote products derived | |||
| * from this software without prior written permission. For written | |||
| * permission, please contact apache@apache.org. | |||
| * | |||
| * 5. Products derived from this software may not be called "Apache" | |||
| * nor may "Apache" appear in their names without prior written | |||
| * permission of the Apache Group. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| * SUCH DAMAGE. | |||
| * ==================================================================== | |||
| * | |||
| * This software consists of voluntary contributions made by many | |||
| * individuals on behalf of the Apache Software Foundation. For more | |||
| * information on the Apache Software Foundation, please see | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.gui; | |||
| /** | |||
| * Enumeration class of the different log levels. | |||
| * | |||
| * @version $Revision$ | |||
| * @author Simeon Fitch | |||
| */ | |||
| public class LogLevelEnum { | |||
| /** Enum value. */ | |||
| private int _value = 0; | |||
| /** | |||
| * Standard ctor. | |||
| * | |||
| * @param value Index value. | |||
| */ | |||
| private LogLevelEnum(int value) { | |||
| _value = value; | |||
| } | |||
| /** | |||
| * Get the enumeration value. | |||
| * | |||
| * @return | |||
| */ | |||
| public int getValue() { | |||
| return _value; | |||
| } | |||
| /** | |||
| * Get the enumeration value with the given index value. | |||
| * | |||
| * @param value Index value. | |||
| * @return Enumeration value. | |||
| */ | |||
| public static LogLevelEnum fromInt(int value) { | |||
| return _objectMap[value]; | |||
| } | |||
| /** | |||
| * Get the set of enumeration values. | |||
| * | |||
| * @return Value set. | |||
| */ | |||
| public static LogLevelEnum[] getValues() { | |||
| return _objectMap; | |||
| } | |||
| /** | |||
| * Determine if the given object is logically equal to this one. | |||
| * | |||
| * @param o Object to compare to | |||
| * @return True if equal, false otherwise. | |||
| */ | |||
| public boolean equals(Object o) { | |||
| if(o instanceof LogLevelEnum) { | |||
| return ((LogLevelEnum)o)._value == _value; | |||
| } | |||
| return false; | |||
| } | |||
| /** | |||
| * Generate a hash value. | |||
| * | |||
| * @return Hash value. | |||
| */ | |||
| public int hashValue() { | |||
| return _value; | |||
| } | |||
| /** | |||
| * Provide a string representation of this. | |||
| * | |||
| * @return String representation. | |||
| */ | |||
| public String toString() { | |||
| return _stringMap[_value]; | |||
| } | |||
| /* Index values. */ | |||
| public static final int ERROR_VAL = 0; | |||
| public static final int WARNING_VAL = 1; | |||
| public static final int INFO_VAL = 2; | |||
| public static final int VERBOSE_VAL = 3; | |||
| public static final int DEBUG_VAL = 4; | |||
| /* Enumeration values. */ | |||
| public static final LogLevelEnum ERROR = | |||
| new LogLevelEnum(ERROR_VAL); | |||
| public static final LogLevelEnum WARNING = | |||
| new LogLevelEnum(WARNING_VAL); | |||
| public static final LogLevelEnum INFO = | |||
| new LogLevelEnum(INFO_VAL); | |||
| public static final LogLevelEnum VERBOSE = | |||
| new LogLevelEnum(VERBOSE_VAL); | |||
| public static final LogLevelEnum DEBUG = | |||
| new LogLevelEnum(DEBUG_VAL); | |||
| /** Index to object mapping. */ | |||
| private static final LogLevelEnum[] _objectMap = { | |||
| ERROR, WARNING, INFO, VERBOSE, DEBUG | |||
| }; | |||
| /** String map. XXX needs to be localized. */ | |||
| private static final String[] _stringMap = { | |||
| "Error", "Warning", "Info", "Verbose", "Debug" | |||
| }; | |||
| } | |||
| @@ -52,7 +52,7 @@ | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.gui; | |||
| import org.apache.tools.ant.gui.util.WindowUtils; | |||
| import javax.swing.*; | |||
| import java.awt.BorderLayout; | |||
| @@ -82,10 +82,19 @@ public class Main { | |||
| f.getContentPane().add(BorderLayout.NORTH, | |||
| context.getActions().createToolBar()); | |||
| ImageIcon icon = | |||
| context.getResources().getImageIcon("icon-small.gif"); | |||
| if(icon != null) { | |||
| f.setIconImage(icon.getImage()); | |||
| } | |||
| else { | |||
| System.out.println("Application icon not found."); | |||
| } | |||
| f.pack(); | |||
| f.setVisible(true); | |||
| // Hack around linux window placement annoyance. | |||
| f.setLocation(100, 100); | |||
| WindowUtils.centerWindow(f); | |||
| } | |||
| catch(Exception ex) { | |||
| @@ -85,7 +85,7 @@ class ProjectNavigator extends AntEditor { | |||
| JScrollPane scroller = new JScrollPane(_tree); | |||
| add(scroller); | |||
| setPreferredSize(new Dimension(100, 100)); | |||
| setPreferredSize(new Dimension(150, 100)); | |||
| } | |||
| @@ -54,10 +54,15 @@ | |||
| package org.apache.tools.ant.gui; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.ProjectHelper; | |||
| import org.apache.tools.ant.BuildEvent; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.BuildListener; | |||
| import org.apache.tools.ant.gui.event.*; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import javax.swing.tree.TreeModel; | |||
| import javax.swing.text.Document; | |||
| import java.util.Enumeration; | |||
| /** | |||
| * This class provides the gateway interface to the data model for | |||
| @@ -70,44 +75,59 @@ import javax.swing.text.Document; | |||
| */ | |||
| public class ProjectProxy { | |||
| /** Application context */ | |||
| private AppContext _context = null; | |||
| /** The file where the project was last saved. */ | |||
| private File _file = null; | |||
| /** The real Ant Project instance. */ | |||
| private Project _project = null; | |||
| /** | |||
| * Default constructor. NB: right now it is private, but | |||
| * will be opened up once the gui supports creating new projects. | |||
| * | |||
| */ | |||
| private ProjectProxy() { | |||
| } | |||
| /** Private the current thread executing a build. */ | |||
| private Thread _buildThread = null; | |||
| /** | |||
| * File loading ctor. | |||
| * | |||
| * @param file File containing build file to load. | |||
| */ | |||
| public ProjectProxy(File file) throws IOException { | |||
| this(); | |||
| public ProjectProxy(AppContext context, File file) throws IOException { | |||
| _file = file; | |||
| _context = context; | |||
| loadProject(); | |||
| } | |||
| /** | |||
| * Load the project from the build file. | |||
| * | |||
| */ | |||
| private void loadProject() throws IOException { | |||
| _project = new Project(); | |||
| _project.init(); | |||
| synchronized(_project) { | |||
| _project.init(); | |||
| // XXX there is a bunch of stuff in the class org.apache.tools.ant.Main | |||
| // that needs to be abstracted out so that it doesn't | |||
| // have to be replicated here. | |||
| // XXX there is a bunch of stuff in the class | |||
| // org.apache.tools.ant.Main that needs to be | |||
| // abstracted out so that it doesn't have to be | |||
| // replicated here. | |||
| // XXX need to provide a way to pass in externally defined properties. | |||
| // Perhaps define an external Antidote properties file. | |||
| _project.setUserProperty("ant.file" , _file.getAbsolutePath()); | |||
| ProjectHelper.configureProject(_project, _file); | |||
| // XXX need to provide a way to pass in externally | |||
| // defined properties. Perhaps define an external | |||
| // Antidote properties file. | |||
| _project.setUserProperty("ant.file" , _file.getAbsolutePath()); | |||
| ProjectHelper.configureProject(_project, _file); | |||
| } | |||
| } | |||
| /** | |||
| * Build the project with the current target (or the default target | |||
| * if none is selected. Build occurs on a separate thread, so method | |||
| * returns immediately. | |||
| * | |||
| */ | |||
| public void build() throws BuildException { | |||
| if(_project == null) return; | |||
| _buildThread = new Thread(new BuildRunner()); | |||
| _buildThread.start(); | |||
| } | |||
| /** | |||
| @@ -146,4 +166,56 @@ public class ProjectProxy { | |||
| } | |||
| return null; | |||
| } | |||
| /** | |||
| * Convenience method for causeing the project to fire a build event. | |||
| * Implemented because the corresponding method in the Project class | |||
| * is not publically accessible. | |||
| * | |||
| * @param event Event to fire. | |||
| */ | |||
| private void fireBuildEvent(BuildEvent event, BuildEventType type) { | |||
| synchronized(_project) { | |||
| Enumeration enum = _project.getBuildListeners().elements(); | |||
| while(enum.hasMoreElements()) { | |||
| BuildListener l = (BuildListener) enum.nextElement(); | |||
| type.fireEvent(event, l); | |||
| } | |||
| } | |||
| } | |||
| /** Class for executing the build in a separate thread. */ | |||
| private class BuildRunner implements Runnable { | |||
| public void run() { | |||
| synchronized(_project) { | |||
| // Add the build listener for | |||
| // dispatching BuildEvent objects to the | |||
| // EventBus. | |||
| BuildEventForwarder handler = | |||
| new BuildEventForwarder(_context); | |||
| _project.addBuildListener(handler); | |||
| try { | |||
| fireBuildEvent(new BuildEvent( | |||
| _project), BuildEventType.BUILD_STARTED); | |||
| // XXX add code to indicate target execution | |||
| // on the targets that are selected. | |||
| _project.executeTarget( | |||
| _project.getDefaultTarget()); | |||
| } | |||
| catch(BuildException ex) { | |||
| BuildEvent errorEvent = new BuildEvent(_project); | |||
| errorEvent.setException(ex); | |||
| errorEvent.setMessage(ex.getMessage(), Project.MSG_ERR); | |||
| fireBuildEvent(errorEvent, BuildEventType.MESSAGE_LOGGED); | |||
| } | |||
| finally { | |||
| fireBuildEvent(new BuildEvent( | |||
| _project), BuildEventType.BUILD_FINISHED); | |||
| _project.removeBuildListener(handler); | |||
| _buildThread = null; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -55,6 +55,9 @@ package org.apache.tools.ant.gui; | |||
| import java.util.*; | |||
| import java.text.MessageFormat; | |||
| import javax.swing.ImageIcon; | |||
| import java.net.URL; | |||
| import java.io.File; | |||
| /** | |||
| * Singleton class for accessing various resources by the application. | |||
| @@ -143,4 +146,22 @@ public class ResourceManager { | |||
| return MessageFormat.format(format, arguments); | |||
| } | |||
| /** | |||
| * Get the image as an ImageIcon with the given file name. | |||
| * For example "open.gif". The image is loaded from the resources package. | |||
| * | |||
| * @param fileName Image file to load. | |||
| * @return Image as an ImageIcon, or null if not found. | |||
| */ | |||
| public ImageIcon getImageIcon(String fileName) { | |||
| ImageIcon icon = null; | |||
| URL location = getClass().getResource("resources/" + fileName); | |||
| if(location != null) { | |||
| icon = new ImageIcon(location); | |||
| } | |||
| return icon; | |||
| } | |||
| } | |||
| @@ -0,0 +1,90 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 1999, 2000 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * 1. Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * 2. Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in | |||
| * the documentation and/or other materials provided with the | |||
| * distribution. | |||
| q * | |||
| * 3. The end-user documentation included with the redistribution, if | |||
| * any, must include the following acknowlegement: | |||
| * "This product includes software developed by the | |||
| * Apache Software Foundation (http://www.apache.org/)." | |||
| * Alternately, this acknowlegement may appear in the software itself, | |||
| * if and wherever such third-party acknowlegements normally appear. | |||
| * | |||
| * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software | |||
| * Foundation" must not be used to endorse or promote products derived | |||
| * from this software without prior written permission. For written | |||
| * permission, please contact apache@apache.org. | |||
| * | |||
| * 5. Products derived from this software may not be called "Apache" | |||
| * nor may "Apache" appear in their names without prior written | |||
| * permission of the Apache Group. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| * SUCH DAMAGE. | |||
| * ==================================================================== | |||
| * | |||
| * This software consists of voluntary contributions made by many | |||
| * individuals on behalf of the Apache Software Foundation. For more | |||
| * information on the Apache Software Foundation, please see | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.gui.command; | |||
| import org.apache.tools.ant.gui.AppContext; | |||
| import org.apache.tools.ant.gui.ProjectProxy; | |||
| /** | |||
| * Starts an Ant build. | |||
| * | |||
| * @version $Revision$ | |||
| * @author Simeon Fitch | |||
| */ | |||
| public class BuildCmd implements Command { | |||
| /** Name of the action the command maps to. */ | |||
| public static final String ACTION_NAME = "startBuild"; | |||
| /** The application context */ | |||
| private AppContext _context = null; | |||
| /** | |||
| * Standard ctor. | |||
| * | |||
| * @param context Application context. | |||
| */ | |||
| public BuildCmd(AppContext context) { | |||
| _context = context; | |||
| } | |||
| /** | |||
| * Start the Ant build. | |||
| * | |||
| */ | |||
| public void execute() { | |||
| ProjectProxy project = _context.getProject(); | |||
| if(project != null) { | |||
| project.build(); | |||
| } | |||
| } | |||
| } | |||
| @@ -95,7 +95,7 @@ public class LoadFileCmd implements Command { | |||
| } | |||
| else { | |||
| try { | |||
| ProjectProxy project = new ProjectProxy(_file); | |||
| ProjectProxy project = new ProjectProxy(_context, _file); | |||
| _context.setProject(project); | |||
| } | |||
| catch(IOException ex) { | |||
| @@ -0,0 +1,138 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 1999, 2000 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * 1. Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * 2. Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in | |||
| * the documentation and/or other materials provided with the | |||
| * distribution. | |||
| * | |||
| * 3. The end-user documentation included with the redistribution, if | |||
| * any, must include the following acknowlegement: | |||
| * "This product includes software developed by the | |||
| * Apache Software Foundation (http://www.apache.org/)." | |||
| * Alternately, this acknowlegement may appear in the software itself, | |||
| * if and wherever such third-party acknowlegements normally appear. | |||
| * | |||
| * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software | |||
| * Foundation" must not be used to endorse or promote products derived | |||
| * from this software without prior written permission. For written | |||
| * permission, please contact apache@apache.org. | |||
| * | |||
| * 5. Products derived from this software may not be called "Apache" | |||
| * nor may "Apache" appear in their names without prior written | |||
| * permission of the Apache Group. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| * SUCH DAMAGE. | |||
| * ==================================================================== | |||
| * | |||
| * This software consists of voluntary contributions made by many | |||
| * individuals on behalf of the Apache Software Foundation. For more | |||
| * information on the Apache Software Foundation, please see | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.gui.event; | |||
| import org.apache.tools.ant.BuildEvent; | |||
| import org.apache.tools.ant.gui.util.StackFrame; | |||
| import org.apache.tools.ant.gui.command.Command; | |||
| import org.apache.tools.ant.gui.command.NoOpCmd; | |||
| import org.apache.tools.ant.gui.AppContext; | |||
| import java.util.EventObject; | |||
| /** | |||
| * Wrapper event for the events generated during an Ant build. | |||
| * | |||
| * @version $Revision$ | |||
| * @author Simeon Fitch | |||
| */ | |||
| public class AntBuildEvent extends AntEvent { | |||
| /** The original event we are wrapping. */ | |||
| private BuildEvent _buildEvent = null; | |||
| /** The type of event we are wrapping. */ | |||
| private BuildEventType _type = null; | |||
| /** | |||
| * Standard ctor. | |||
| * | |||
| * @param context application context. | |||
| */ | |||
| public AntBuildEvent(AppContext context, | |||
| BuildEvent buildEvent, BuildEventType type) { | |||
| super(context); | |||
| _buildEvent = buildEvent; | |||
| _type = type; | |||
| if(_buildEvent == null || _type == null) { | |||
| throw new IllegalArgumentException("Null parameter passed"); | |||
| } | |||
| } | |||
| /** | |||
| * Get the wrapped build event. | |||
| * | |||
| * @return Build event. | |||
| */ | |||
| public BuildEvent getEvent() { | |||
| return _buildEvent; | |||
| } | |||
| /** | |||
| * Get the build event type. | |||
| * | |||
| * @return Event type. | |||
| */ | |||
| public BuildEventType getType() { | |||
| return _type; | |||
| } | |||
| /** | |||
| * Create the appropriate default response command to this event. | |||
| * | |||
| * @return Command representing an appropriate response to this event. | |||
| */ | |||
| public Command createDefaultCmd() { | |||
| return new NoOpCmd(); | |||
| } | |||
| /** | |||
| * Create a string representation of this. | |||
| * | |||
| * @return String representation. | |||
| */ | |||
| public String toString() { | |||
| StringBuffer buf = new StringBuffer(); | |||
| if(_buildEvent.getMessage() != null) { | |||
| buf.append(_buildEvent.getMessage()); | |||
| buf.append('\n'); | |||
| } | |||
| if(_buildEvent.getException() != null) { | |||
| buf.append(StackFrame.toString(_buildEvent.getException())); | |||
| } | |||
| return buf.toString(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,208 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 1999, 2000 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * 1. Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * 2. Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in | |||
| * the documentation and/or other materials provided with the | |||
| * distribution. | |||
| * | |||
| * 3. The end-user documentation included with the redistribution, if | |||
| * any, must include the following acknowlegement: | |||
| * "This product includes software developed by the | |||
| * Apache Software Foundation (http://www.apache.org/)." | |||
| * Alternately, this acknowlegement may appear in the software itself, | |||
| * if and wherever such third-party acknowlegements normally appear. | |||
| * | |||
| * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software | |||
| * Foundation" must not be used to endorse or promote products derived | |||
| * from this software without prior written permission. For written | |||
| * permission, please contact apache@apache.org. | |||
| * | |||
| * 5. Products derived from this software may not be called "Apache" | |||
| * nor may "Apache" appear in their names without prior written | |||
| * permission of the Apache Group. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| * SUCH DAMAGE. | |||
| * ==================================================================== | |||
| * | |||
| * This software consists of voluntary contributions made by many | |||
| * individuals on behalf of the Apache Software Foundation. For more | |||
| * information on the Apache Software Foundation, please see | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.gui.event; | |||
| import org.apache.tools.ant.BuildListener; | |||
| import org.apache.tools.ant.BuildEvent; | |||
| import java.lang.reflect.Method; | |||
| /** | |||
| * Enumeration class of the different contexts in which Ant will generate | |||
| * a BuildEvent. | |||
| * | |||
| * @version $Revision$ | |||
| * @author Simeon Fitch | |||
| */ | |||
| public class BuildEventType { | |||
| /** Enum value. */ | |||
| private int _value = 0; | |||
| /** | |||
| * Standard ctor. | |||
| * | |||
| * @param value Index value. | |||
| */ | |||
| private BuildEventType(int value) { | |||
| _value = value; | |||
| } | |||
| /** | |||
| * Get the enumeration value. | |||
| * | |||
| * @return | |||
| */ | |||
| public int getValue() { | |||
| return _value; | |||
| } | |||
| /** | |||
| * Pseudo abstract method for firing an event to a build listener | |||
| * based on our enumation value. I overridded by the individual instances. | |||
| * | |||
| * @param e Event to fire. | |||
| * @param l Listener to send event to. | |||
| */ | |||
| public void fireEvent(BuildEvent e, BuildListener l) { | |||
| try { | |||
| Method method = | |||
| BuildListener.class.getMethod(_methodNameMap[_value], | |||
| _listenerMethodParam); | |||
| method.invoke(l, new Object[] { e }); | |||
| } | |||
| catch(Exception ex) { | |||
| // XXX log me. | |||
| ex.printStackTrace(); | |||
| } | |||
| } | |||
| /** | |||
| * Get the enumeration value with the given index value. | |||
| * | |||
| * @param value Index value. | |||
| * @return Enumeration value. | |||
| */ | |||
| public static BuildEventType fromInt(int value) { | |||
| return _objectMap[value]; | |||
| } | |||
| /** | |||
| * Determine if the given object is logically equal to this one. | |||
| * | |||
| * @param o Object to compare to | |||
| * @return True if equal, false otherwise. | |||
| */ | |||
| public boolean equals(Object o) { | |||
| if(o instanceof BuildEventType) { | |||
| return ((BuildEventType)o)._value == _value; | |||
| } | |||
| return false; | |||
| } | |||
| /** | |||
| * Generate a hash value. | |||
| * | |||
| * @return Hash value. | |||
| */ | |||
| public int hashValue() { | |||
| return _value; | |||
| } | |||
| /** | |||
| * Provide a string representation of this. | |||
| * | |||
| * @return String representation. | |||
| */ | |||
| public String toString() { | |||
| return _stringMap[_value]; | |||
| } | |||
| /* Index values. */ | |||
| public static final int BUILD_STARTED_VAL = 0; | |||
| public static final int BUILD_FINISHED_VAL = 1; | |||
| public static final int TARGET_STARTED_VAL = 2; | |||
| public static final int TARGET_FINISHED_VAL = 3; | |||
| public static final int TASK_STARTED_VAL = 4; | |||
| public static final int TASK_FINISHED_VAL = 5; | |||
| public static final int MESSAGE_LOGGED_VAL = 6; | |||
| /* Enumeration values. */ | |||
| public static final BuildEventType BUILD_STARTED = | |||
| new BuildEventType(BUILD_STARTED_VAL); | |||
| public static final BuildEventType BUILD_FINISHED = | |||
| new BuildEventType(BUILD_FINISHED_VAL); | |||
| public static final BuildEventType TARGET_STARTED = | |||
| new BuildEventType(TARGET_STARTED_VAL); | |||
| public static final BuildEventType TARGET_FINISHED = | |||
| new BuildEventType(TARGET_FINISHED_VAL); | |||
| public static final BuildEventType TASK_STARTED = | |||
| new BuildEventType(TASK_STARTED_VAL); | |||
| public static final BuildEventType TASK_FINISHED = | |||
| new BuildEventType(TASK_FINISHED_VAL); | |||
| public static final BuildEventType MESSAGE_LOGGED = | |||
| new BuildEventType(MESSAGE_LOGGED_VAL); | |||
| /** Index to object mapping. */ | |||
| private static final BuildEventType[] _objectMap = { | |||
| BUILD_STARTED, | |||
| BUILD_FINISHED, | |||
| TARGET_STARTED, | |||
| TARGET_FINISHED, | |||
| TASK_STARTED, | |||
| TASK_FINISHED, | |||
| MESSAGE_LOGGED | |||
| }; | |||
| /** String map. XXX needs to be localized. */ | |||
| private static final String[] _stringMap = { | |||
| "Build Started", | |||
| "Build Finished", | |||
| "Target Started", | |||
| "Target Finished", | |||
| "Task Started", | |||
| "Task Finished", | |||
| "Message Logged" | |||
| }; | |||
| /** Map of corresponding method names in the BuildListener intereface. */ | |||
| private static final String[] _methodNameMap = { | |||
| "buildStarted", | |||
| "buildFinished", | |||
| "targetStarted", | |||
| "targetFinished", | |||
| "taskStarted", | |||
| "taskFinished", | |||
| "messageLogged" | |||
| }; | |||
| private static final Class[] _listenerMethodParam = { BuildEvent.class }; | |||
| } | |||
| @@ -54,7 +54,7 @@ | |||
| package org.apache.tools.ant.gui.event; | |||
| import java.util.*; | |||
| import javax.swing.SwingUtilities; | |||
| /** | |||
| * An event "bus" providing a centralized place for posting | |||
| * and recieving generic application events. To receive events a class must | |||
| @@ -142,29 +142,55 @@ public class EventBus { | |||
| * @param event Event to post. | |||
| */ | |||
| public void postEvent(EventObject event) { | |||
| synchronized(_memberSet) { | |||
| // XXX need to insert code here to test whether we are being | |||
| // executed by the AWTEventQueue, or some other thread. If | |||
| // the latter, then we need to insert our execution on the | |||
| // AWTEventQueue thread as all code executing commands assumes | |||
| // that context. | |||
| EventDispatcher disp = new EventDispatcher(event); | |||
| for(int i = 0; i < _memberSet.length; i++) { | |||
| if(_memberSet[i] == null) continue; | |||
| // Events need to be dispatched on the AWTEvent thread, as the UI | |||
| // components assume that. | |||
| if(SwingUtilities.isEventDispatchThread()) { | |||
| disp.run(); | |||
| } | |||
| else { | |||
| SwingUtilities.invokeLater(disp); | |||
| } | |||
| } | |||
| Iterator it = _memberSet[i].iterator(); | |||
| while(it.hasNext()) { | |||
| BusMember next = (BusMember) it.next(); | |||
| BusFilter filter = next.getBusFilter(); | |||
| if(filter == null || filter.accept(event)) { | |||
| next.eventPosted(event); | |||
| } | |||
| // Check to see if the member cancelled the event. If so | |||
| // then don't send it on to the other members. | |||
| if(event instanceof AntEvent && | |||
| ((AntEvent)event).isCancelled()) break; | |||
| } | |||
| } | |||
| /** Class that performs the duty of dispatching events to the members. */ | |||
| private class EventDispatcher implements Runnable { | |||
| /** Event to dispatch. */ | |||
| private EventObject _event = null; | |||
| /** | |||
| * Standard ctor. | |||
| * | |||
| * @param event Event to dispatch. | |||
| */ | |||
| public EventDispatcher(EventObject event) { | |||
| _event = event; | |||
| } | |||
| /** | |||
| * Perform dispatching. | |||
| * | |||
| */ | |||
| public void run() { | |||
| synchronized(_memberSet) { | |||
| for(int i = 0; i < _memberSet.length; i++) { | |||
| if(_memberSet[i] == null) continue; | |||
| Iterator it = _memberSet[i].iterator(); | |||
| while(it.hasNext()) { | |||
| BusMember next = (BusMember) it.next(); | |||
| BusFilter filter = next.getBusFilter(); | |||
| if(filter == null || filter.accept(_event)) { | |||
| next.eventPosted(_event); | |||
| } | |||
| // Check to see if the member cancelled the event. If so | |||
| // then don't send it on to the other members. | |||
| if(_event instanceof AntEvent && | |||
| ((AntEvent)_event).isCancelled()) break; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,21 +1,24 @@ | |||
| menus=File, Help | |||
| menus=File, Build, Help | |||
| actions=open, close, exit, about | |||
| actions=open, close, exit, about, startBuild, stopBuild | |||
| new.name=New | |||
| new.shortDescription=Create a new project | |||
| new.parentMenuName=File | |||
| new.icon=new.gif | |||
| new.accelerator=control N | |||
| open.name=Open | |||
| open.shortDescription=Open an existing project | |||
| open.parentMenuName=File | |||
| open.icon=open.gif | |||
| open.accelerator=control O | |||
| save.name=Save | |||
| save.shortDescription=Save the current project | |||
| save.parentMenuName=File | |||
| save.icon=save.gif | |||
| save.accelerator=control S | |||
| close.name=Close | |||
| close.shortDescription=Close the current project | |||
| @@ -30,3 +33,17 @@ about.name=About | |||
| about.shortDescription=About this application | |||
| about.parentMenuName=Help | |||
| about.separator=true; | |||
| startBuild.name=Start | |||
| startBuild.shortDescription=Start build of selected target | |||
| startBuild.parentMenuName=Build | |||
| startBuild.icon=start.gif | |||
| startBuild.separator=true | |||
| startBuild.accelerator=control B | |||
| stopBuild.name=Stop | |||
| stopBuild.shortDescription=Stop the current build | |||
| stopBuild.parentMenuName=Build | |||
| stopBuild.icon=stop.gif | |||
| stopBuild.accelerator=control K | |||
| @@ -9,10 +9,16 @@ org.apache.tools.ant.gui.Antidote.right.editors=\ | |||
| org.apache.tools.ant.gui.Antidote.left.editors=\ | |||
| org.apache.tools.ant.gui.ProjectNavigator | |||
| # Configure the editors that appear on the bottom of the UI. | |||
| org.apache.tools.ant.gui.Antidote.bottom.editors=\ | |||
| org.apache.tools.ant.gui.Console | |||
| # Set specific class properties. | |||
| org.apache.tools.ant.gui.SourceEditor.name=Source | |||
| org.apache.tools.ant.gui.PropertyEditor.name=Properties | |||
| org.apache.tools.ant.gui.ProjectNavigator.name=Task Navigator | |||
| org.apache.tools.ant.gui.ProjectNavigator.name=Project | |||
| org.apache.tools.ant.gui.Console.name=Console | |||
| org.apache.tools.ant.gui.Console.logLevel=Log message level: | |||
| org.apache.tools.ant.gui.XMLFileFilter.description=XML Files | |||
| @@ -82,7 +82,7 @@ public class WindowUtils { | |||
| } | |||
| /** | |||
| * Center the given child window with repsect to the child window. | |||
| * Center the given child window with repsect to the parent window. | |||
| * | |||
| * @param parent Window to base centering on. | |||
| * @param child Window to center. | |||
| @@ -94,4 +94,15 @@ public class WindowUtils { | |||
| bounds.y + (bounds.height - size.height)/2); | |||
| } | |||
| /** | |||
| * Center the given child window with repsect to the root. | |||
| * | |||
| * @param child Window to center. | |||
| */ | |||
| public static void centerWindow(Window child) { | |||
| Dimension rsize = child.getToolkit().getScreenSize(); | |||
| Dimension size = child.getSize(); | |||
| child.setLocation((rsize.width - size.width)/2, | |||
| (rsize.height - size.height)/2); | |||
| } | |||
| } | |||