*) 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); | |||
} | |||
} |