# Java support

This version of SpecTcl has an experimental java code generator available.

## Turning on the Java Support

Java support can be added to SpecTcl by adding the line

    		source $Base_dir/java_setup.tk

to the file `SpecTclrc` in your home directory. Make sure that the java compiler (javac) and interpreter (java) are in your execution path.

## Using the Java support

The Java support adds two additional commands to the edit menu:

Java
  Causes a java file to be generated, compiled, and tested.
Kill java
  Kills any existing java test

In addition, the file java.project in the current directory is sourced when the java support is first loaded, and may be used to add project specific behavior to the generated java code as explained below.

## The Java code generator

The Java code generator defines a new class, whose name is the same as the SpecTcl project name. By default, the class extends java.applet.Applet, and is placed in the default package. The class contains the following items:

- New methods defined
  public static void main(String[] args)
    A default main for testing, starts the interface in a toplevel.
  public String[] getNames()
    Returns an array of the widget and radiobutton-group names.
  public Object[] getWidgets()
    Returns an array of widget and radio-button-group objects, in the same order as `getNames`.
- Methods that are overridden from a super class
  public void init()
    This instantiates the user interface. It is called directly if the application is run stand-alone, and implicitly when run an as applet. The super-class `init` routine is also called after the interface is instantiated, to permit application specific initialization to occur.
  public boolean handleEvent(Event event)
    Any actions associated with the widgets (as specified with the "action" option of the widget) are dispatched via the `handle_event` method. Actions that are not explicitly set with the action option are handled by the super class. Eventually an interface to bindings will be provided to allow events other than "action" events.
- Public instance variables All of the widgets and radiobutton-groups, as returned by the `getWidgets` method are public instance variables.

## Interfacing to application code

Application specific code is specified by using the action option for each widget. The actions are java statements to be invoked when the action occurs. Normally the statement is expected to be a Java method call. The local variable event of class Event is available to pass to the method as an argument. The event class contains both a handle to the widget and to the event that is being performed.

The file java.project in the current directory contains TCL code to tailor the code generator for a specific application. The following sample is illustrative: form:

    	set P(extends) my_app     ;# extend my_app instead of Applet
    	set P(package) my_package ;# place the code in package my_package
    	set P(export)  check      ;# add an class instance array with this property
    	set P(other_items:entry) check  ;# add option check to all entry widgets

SpecTcl allows application specific options to be added to widgets, which is then passed through to the java code. P(export) contains a list of option names, each of which causes a class instance variable of type `String[]` to be generated that contains the the value of that option for each widget. Widgets that do not have that property are given a string value of `null`. P(otheritems:widget_name) contains a list of options that are added to the option sheet for the widget widget_name. generated.

## Sample java generated code

This is a sample of the code generated for an interface with a single button, hello, that prints the word "hello" when pressed:

    // SpecTcl generated class hello, version 0.01

    import java.awt.*;
    public class hello extends java.applet.Applet {

    public Button button_1;

    //methods to support form introspection
    public static String names[] = {
    	"button_1",
    };
    public String[] getNames() {
    	return names;
    }

    //There should be an easier way to do this
    public Object[] getWidgets() {
    	Object[] list = new Object[1];
    	list[0] = button_1;
    	return list;
    }

    public void init() {

    	// main panel
    	GridBagLayout grid = new GridBagLayout();
    	int rowHeights[] = {0,30};
    	int columnWidths[] = {0,30};
    	double rowWeights[] = {0.0,0.0};
    	double columnWeights[] = {0.0,0.0};
    	grid.rowHeights = rowHeights;
    	grid.columnWidths = columnWidths;
    	grid.rowWeights = rowWeights;
    	grid.columnWeights = columnWeights;
    	button_1 = new Button();
    	button_1.setFont(new Font("Helvetica",Font.PLAIN + Font.BOLD , 16));
    	button_1.setForeground(new Color(0/256,0/256,65535/256));
    	button_1.setLabel("hello");
    	this.add(button_1);

    	// Geometry management
    	GridBagConstraints con = new GridBagConstraints();
    	reset(con);
    	con.gridx = 1;
    	con.gridy = 1;
    	con.anchor = GridBagConstraints.CENTER;
    	con.fill = GridBagConstraints.NONE;
    	grid.setConstraints(button_1, con);

    	// Resize behavior management and parent hierarchy
    	setLayout(grid);

    	// Give the application a chance to do its initialization
    	super.init();
    }

    public boolean handleEvent(Event event) {
    	if (event.target == button_1 && event.id == event.ACTION_EVENT) {
    		System.out.println("hello");
    	} else
    		return super.handleEvent(event);
    	return true;
    }

    public static void main(String[] args) {
        Frame f = new Frame("hello Test");
        hello win = new hello();
        win.init();
        f.add("Center", win);
        f.pack();
        f.show();
    }

    private void reset(GridBagConstraints con) { ... }
    }