General Modularity Example Module Projects & Files Commands & Scripting
Windows Menus Charts Tables Buttons & tools
Trees and Taxa Characters & Models Documentation General Utilities
Introduction The module's source code Employing other modules Menus
Commands & snapshots Automatic documentation generation Windows

An example module: modules employing other modules

(updated February 2001)

See how modules employ other modules.

This source code may not be the latest version. Check the newest source code in mesquite.examples.BabyTreeWindow


package mesquite.examples.BabyTreeWindow;

import java.applet.*;
import java.awt.*;
import mesquite.lib.*;
import mesquite.lib.duties.*;

/*========================================*/
/*A simple example module that displays a tree window that depends on a tree in a standard tree window*/
public class BabyTreeWindow extends TreeWindowAssistantN {
    /* In this field the module stores its reference to the module it employs
    to draw the tree in its window */
    DrawTreeCoordinator treeDrawCoordTask;
    /* In this field the module stores its reference to the module it employs
    to calculate a number for the tree in its window */
    NumberForTree numberTask;
    BTreeWindow bTreeWindow;
    
    /*--------------------------------------*/
    /*The basic substitute for a constructor for modules  (overrides method of MesquiteModule)*/
    public boolean startJob(String arguments, Object condition, CommandRecord commandRec, boolean hiredByName) {
        /* With the hireEmployee method, this module is hiring a module to coordinate
        the drawing of a tree in its window.  The method is passed DrawTreeCoordinator.class
        so as to indicate what subclass ("duty class") of module is being sought.
        Since there is likely only one such module available, it would be hired without
        the need for a choice.  Had there been several and the programmer wanted the user to
        be presented with a choice at this point, the last parameter could have been passed
        as a String with the query to be given to the user, such as "What module to use
        as coordinator for drawing trees?".  However, given that null was passed, no
        query would have been given and the first DrawTreeCoordinator found would have been
        hired.  Other versions of hireEmployee pass two strings, one to indicate the specific
        module to be hired, the other the query should the preferred module not be found. */
        treeDrawCoordTask= (DrawTreeCoordinator)hireEmployee(commandRec, DrawTreeCoordinator.class, null);
        /* If no tree draw coordinator was found, the module cannot function. Hence, startJob
        should return false.  This will cause the module to be shut down. */
        if (treeDrawCoordTask == null)
            return false;
        /* Now, the module to calculate a number for a tree is hired.  Because there likely
        will be several alternatives available, a string is passed to query the user
        in a dialog box as to which calculation should be used.*/
        numberTask= (NumberForTree)hireEmployee(commandRec, NumberForTree.class, "Number to calculate");
        makeMenu("Baby");
        /* Here a submenu is defined which shows alternative modules to calculate numbers
        for trees.  This allows the user to switch the calculating module after the window
        is shown. */
        addSubmenu(null, "Number to calculate", makeCommand("setNumberTask",  this), NumberForTree.class);
        addMenuItem( "-", null);
        bTreeWindow= new BTreeWindow( this, treeDrawCoordTask, numberTask);
        setModuleWindow(bTreeWindow);
        if (!commandRec.scripting())
             bTreeWindow.setVisible(true);
        resetAllMenuBars();
        return true;
    }
    /*--------------------------------------*/
    /*A method necessary with modules of subclass TreeWindowAssistantN; allows standard tree window
    on which this module depends to indicate tree has changed  (overrides method of TreeWindowAssistantN)*/
    public void setTree(Tree tree, CommandRecord commandRec) {
        bTreeWindow.setTree(tree, commandRec);
    }
    /*--------------------------------------*/
    /*Makes the module shut down when the go-away box of the window is touched  (overrides method of MesquiteModule)*/
     public void windowGoAway(MesquiteWindow whichWindow) {
        whichWindow.hide();
        whichWindow.dispose();
        iQuit();
    }
    /*--------------------------------------*/
    /*Returns the snapshot necessary to get this module back to the current state.  Note that it incorporates
      a snapshot from its window  (overrides method of MesquiteModule)*/
    public Snapshot getSnapshot(MesquiteFile file) {
        if (bTreeWindow ==null)
           return null;
        Snapshot fromWindow = bTreeWindow.getSnapshot(file);
        if (fromWindow == null || fromWindow.getNumLines() ==0)
            return null;
        Snapshot sn = new Snapshot();
        sn.addLine("getWindow");
        sn.addLine("tell It");
        sn.incorporate(fromWindow, true);
        sn.addLine("endTell");
        /* This command in the snapshot sets the tree draw coordinator to be the one hired.
        As noted in the page on commands and snapshots, the passing of the reference to the
        current module allows its snapshot commands to be inserted directly at this point.*/
        sn.addLine("getTreeDrawCoordinator", treeDrawCoordTask);
        /* Likewise the command sets the module calculating the number for the tree to be the
        current one */
        sn.addLine("setNumberTask", numberTask);
        sn.addLine("showWindow");
        return sn;
    }
    /*--------------------------------------*/
    /*The standard method for Commandable interface; receives commands either for snapshotting purposes
      or from menu actions  (overrides method of MesquiteModule)*/
    public Object doCommand(String commandName, String arguments, CommandRecord commandRec, CommandChecker checker) {
        /* The "getTreeDrawCoordinator" command, used primarily by scripts written by
        the snapshotting routines, returns the current tree draw coordinator */
        if (checker.compare(this.getClass(), "Returns the module serving as the window's draw tree coordinator", null, commandName, "getTreeDrawCoordinator"))
            return treeDrawCoordTask;
        /* The "setNumberTask" command causes the module to replace the current number calculating
        module to the module indicated by the arguments. */
        else if (checker.compare(this.getClass(), "Sets which module class should calculate a number for the tree", "[name of module]", commandName, "setNumberTask")) {
            /* The method replaceEmployee attempts to find the module of the indicated 
            subclass and with the name indicated by the arguments.  If it finds it, it
            fires the current module and then hires the desired one.  Otherwise, it
            returns null. */
            NumberForTree temp= (NumberForTree)replaceEmployee(commandRec, NumberForTree.class, arguments, null, numberTask);
            if (temp!=null) {
                numberTask = temp;
                bTreeWindow.setNumberTask(numberTask, commandRec);
                /* Because a new module calculating a number for the tree has been hired,
                any menu items that had belonged to the old calculator need to be removed,
                and any menu items for the new calculator need to be added.  Hence,
                resetContainingMenuBar resets the menus of this window. */
                resetContainingMenuBar();
                /* The doCommand method should return the module newly hired.  This
                means that in a script, "It" will take on the value of this module, and
                a tell It statement immediately following will know it refers to the
                hired module. Commands that hire a module should always return the module
                as the returned Object. */
                return numberTask;
            }
        }
        else 
            return super.doCommand(commandName, arguments, commandRec, checker);
        return null;
    }
    /*--------------------------------------*/
    /*Receives message from employees that their parameters have changed an recalculation may be needed  (overrides method of MesquiteModule)*/
    /* This important method is a way for employee modules to give feedback to their
    employers.  It is passed up the from employee through employer until one intercepts
    it and acts on it.  An employee initiates the sequence when it calls its 
    parametersChanged method, which it should do whenever it has changed some of its parameters
    in a way that affects the basic duty it is to perform.  For instance, a module
    calculating a number for a tree that uses stochastic models of evolution should report
    its parameters changed if it chooses an alternative model of evolution.  This is equivalent
    to "I have just changed the way that I do my job.  Please ask me to do it again.".  Thus,
    An employer can request the calculations to be done again so that they are up to date.
    The first parameter is through which immediate employee the message is being passed;
    the second parameter is the original module that initiated the message.  The CommandRecord with method
    scripting() is passed either to allow subsequent calculations to know how much they
    should bother the user with queries, or because on occasion it makes sense for a module
    to not respond to parameters being changed when being scripted, to prevent a module from
    responding to every single little command resetting parameters of its employees. */ 
    public void employeeParametersChanged(MesquiteModule employee, MesquiteModule source, CommandRecord commandRec) {
        if (employee== numberTask)
            bTreeWindow.recalculate(commandRec);
    }
    /*--------------------------------------*/
    /*Indicates to the name of this module for purposes of menu listings and documentation.  (overrides method of MesquiteModule)*/
    public String getName() {
        return "Baby Tree Window";
    }
    /*--------------------------------------*/
    /*Returns the version of this module.  (overrides method of MesquiteModule)*/
    public String getVersion() {
        return "0.9";
    }
    /*--------------------------------------*/
    /*Returns an explanation of what the module does.  (overrides method of MesquiteModule)*/
    public String getExplanation() {
        return "Displays a single tree (the same as in a tree window)." ;
    }
    /*--------------------------------------*/
    /*Returns the authors of the module.  (overrides method of MesquiteModule)*/
    public String getAuthors() {
        return "Wayne Maddison";
    }
}
    
/*========================================*/
/*The window (Frame) itself shown on the screen, containing a tree that is the same as the one in the standard tree window*/
public class BTreeWindow extends MesquiteWindow  {
    TreeDisplay treeDisplay;
    /* It is useful for the window to save its own local reference to the tree draw coordinator module*/
    DrawTreeCoordinator treeDrawCoordTask;
    TextField p;
    MesquiteNumber num = new MesquiteNumber();
    /* It is useful for the window to save its own local reference to module that
    calculates the number for the tree.*/
    NumberForTree numberTask;
    Tree tree;
    
    public BTreeWindow (BabyTreeWindow ownerModule, DrawTreeCoordinator treeDrawCoordTask, NumberForTree numberTask){
        super(ownerModule, true); 
        this.treeDrawCoordTask = treeDrawCoordTask;
        this.numberTask = numberTask;
        setWindowSize(500,400);
        setBackground(Color.white);
        p = new TextField();
        p.setBackground(Color.yellow);
        addToWindow(p);
        resetTitle();
    }
    /*--------------------------------------*/
    /* Used to get the title for window (overrides abstract method of MesquiteWindow)*/
    public void resetTitle(){
        setTitle("Baby Tree Window"); 
    }
    /*--------------------------------------*/
    /* Resize the tree display and other components.*/
    public void sizeDisplays(){
        if (treeDisplay==null) return;
        int totalWidth = getWidth();
        int totalHeight = getHeight() - 30;
        treeDisplay.setSize(totalWidth,totalHeight);
        treeDisplay.setFieldSize(totalWidth,totalHeight);
        if (p!=null)
            p.setBounds(0,totalHeight, totalWidth, 30);
    }
    /*--------------------------------------*/
    /*Sets the tree to be shown in the window.*/
    public void setTree(Tree newTree, CommandRecord commandRec){
        if (treeDisplay == null) {
            Taxa taxa = newTree.getTaxa();
            /* Here the tree draw coordinating module is being used.  Its job is to supply
            a special "TreeDisplay" Component for incorporating into the window.
            The tree draw coordinating module will be responsible for supervising what
            modules are employed for all of the details of the tree drawing, and it will
            act to update the TreeDisplay as needed */
            treeDisplay =treeDrawCoordTask.createOneTreeDisplay(taxa, this); 
            addToWindow(treeDisplay);
            treeDisplay.setLocation(0,0);
            sizeDisplays();
        }
        
        if (treeDisplay.getTree()!=null)
            treeDisplay.getTree().dispose();
        if (newTree!=null) {
            tree = newTree.cloneTree();
            /* Here the tree draw coordinating module is being asked to attach a  
            particular tree to its TreeDisplay. */
            treeDrawCoordTask.setTreeOfOneDisplay(tree);
            recalculate(commandRec);
            treeDisplay.suppressDrawing(false);
            treeDisplay.setVisible(true);
            treeDisplay.repaint();
        }
    }
    /*--------------------------------------*/
    /*Sets what module is to be used for calculating the number for the tree*/
    public void setNumberTask(NumberForTree numTask, CommandRecord commandRec){
        /* This method is called when the module owning this window hires a new
        module to calculate a number for the tree. The window responds by asking
        for its number for the tree be recalculated and the display updated */
        numberTask = numTask;
        recalculate(commandRec);
    }
    /*--------------------------------------*/
    /*Recalculates the number for the tree*/
    public void recalculate(CommandRecord commandRec){
        if (numberTask!=null && tree !=null){
            /* This is the only point at which the module calculating a number for the
            tree is actually used.  The module is passed the tree, and a MesquiteNumber
            to receive the resulting number.  The TextField is filled with the result.*/
            numberTask.calculateNumber(tree, num, commandRec);
            p.setText(numberTask.getName() + " " + num);
        }
        else
            p.setText("");
    }
    /*--------------------------------------*/
    /*Sets the size of the window (setSize and setBounds should not be used!!!>  (overrides method of MesquiteWindow)*/
    public void setWindowSize(int w, int h){
        super.setWindowSize(w,h);
        sizeDisplays();
    }
    /*--------------------------------------*/
    /* Called when the window has been resized, e.g. by user. (overrides method of MesquiteWindow)*/
    public void windowResized(){
        sizeDisplays();
    }
    /*--------------------------------------*/
    /*Disposes of the window*/
    public void dispose(){
        if (treeDisplay!=null){
            if (treeDisplay.getTree()!=null)
                treeDisplay.getTree().dispose();
            treeDisplay.dispose();
        }
        super.dispose();
    }
}


© W. Maddison & D. Maddison 2000-2001