/* Mesquite source code. Copyright 1997-2004 W. Maddison and D. Maddison. Version 1.01, January 2004. Disclaimer: The Mesquite source code is lengthy and we are few. There are no doubt inefficiencies and goofs in this code. The commenting leaves much to be desired. Please approach this source code with the spirit of helping out. Perhaps with your help we can be more than a few, and make Mesquite better. Mesquite is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. Mesquite's web site is http://mesquiteproject.org This source code and its compiled class files are free and modifiable under the terms of GNU Lesser General Public License. (http://www.gnu.org/copyleft/lesser.html) */ package mesquite.lib; import java.awt.*; import java.net.*; import java.util.*; import java.io.*; import java.awt.image.*; import mesquite.lib.duties.*; import edu.stanford.ejalbert.*; //for Browserlauncher /* ============================Class MesquiteModule============================================ */ /** The Mesquite system operates around a tree of modules (subclasses of MesquiteModule), with the class containing the "main" method being the trunk module, and the other modules like branches that are attached to the trunk.
When Mesquite starts up, the trunk starts up and surveys the mesquite folder to acquire information about all of the available modules (i.e., all of the available subclasses of MesquiteModule). To be found, a module must be in a folder (directory) of the same name as itself; that is, a module whose class file is "MyModule.class" must be in a directory named "MyModule". Mesquite remembers the modules in a vector of MesquiteModuleInfo objects. Later, when modules need to be "hired" to perform certain tasks, this vector of information can be used to help choose which module to hire. To be hired, a module is instantiated and linked to its employer module. Thus, a new branch sprouts in the Mesquite bureacratic hierarchy.
Modules are chosen for hire by other modules according to their talents. What talents a module has is implicit in its superclass. For instance, a module that subclasses the NumberForTree class (itself a subclass of MesquiteModule) calculates a number for a tree. Any module that wants numbers calculated for trees can therefore hire a module that is an instance of the NumberForTree class. The basic talent-defining classes are part of the Mesquite Class LIbrary, in the subpackage duties. There is in addition a system to determine whether a module is compatible with a particular condition (e.g. operating on continuous-valued data.)
The only types of module that the trunk knows of directly are the FileCoordinator and FileInterpreter classes. Each instance of the File Coordinator is associated with one file, and it is responsible for using employee modules to read and write the file, and to hire tree windows and data windows. The trunk is a specific subclass of MesquiteModule, a MesquiteTrunk
Because menus are composed hierarchically along the employee tree, menu composition is most easily done where there is easy access to employee-employer relations. For this reason, it is most convenient to have the menu composition embedded within the module code. In order not to burden the MesquiteModule class with numerous methods to handle employee-employer relations, the MesquiteModule class was split into three: its superclass, EmployeeEmployer (which handles employee-employer relations), MenuOwner (which handles all menu issues) and MesquiteModule itself, which handles its basic functions. EmployeeEmployer and MenuOwner are intended to be used ONLY as superclasses to MesquiteModule
The MesquiteModule class is more or less equivalent to the MacClade proto4 ModuleRecord, while its instantiated objects are more or less equivalent to the MacClade proto4 Tasks. Hence, "task" is sometimes used in names for MesquiteModule objects.
*/ public abstract class MesquiteModule extends EmployerEmployee implements Commandable, Showable, Logger, Explainable, Identifiable, FileDirtier, MesquiteListener { LeakFinder leakFinder = MesquiteTrunk.leakFinderObject; /** Static storage so that everyone can find the trunk MesquiteModule object*/ public static MesquiteTrunk mesquiteTrunk; /** The root of the mesquite classpath.*/ public static File mesquiteDirectory=null; /** The root of the mesquite classpath.*/ public static String mesquiteDirectoryPath=null; /** The directory that includes all the preference files.*/ public static File prefsDirectory=null; /** The user's directory.*/ public static File userDirectory=null; /** The window, created by mesquiteTrunk, that displays the log.*/ public static LogWindow logWindow; /** true if name of MesquiteModule is to be shown in alerts*/ private static final boolean showModuleInAlert = true; /** true if name of MesquiteModule is to be shown in log entries*/ private static final boolean showModuleInLog = false; /** true if alerts should show a dialog, or merely write to log.*/ private static final boolean alertUseDialog = true; /** the file path to the web browser for showing web pages*/ protected static String browserString = null; /** true if does extra check for module compatibility at startup.*/ public static boolean checkMethodsAtStartup = false; /** This module was hired as a default choice in scripting*/ public boolean hiredAsDefaultInScripting = false; // /** Has module requested enabling of macro auto-save?*/ private boolean autoSaveMacros = false; private boolean lastEmployee = false; public static int totalFinalized = 0; /** the MesquiteModuleInfo that refers to the module*/ protected MesquiteModuleInfo moduleInfo = null; /** The project that the module was hired under. Almost all modules are descendant from a file coordinating module that belongs to a specific project*/ protected MesquiteProject proj=null; /** for the paging system (may be defunct)*/ Vector pagingsEphemeral = new Vector(); /** for the paging system (may be defunct)*/ Vector pagingsPersistent = new Vector(); public static int textEdgeCompensationHeight = 0; public static int textEdgeCompensationWidth = 10; private static int instantiations = 0; private int idNumber; private String permanentIDString = null; private String assignedIDString = null; private static Random randomNumberGenerator; static { randomNumberGenerator = new Random(System.currentTimeMillis()); } /** The constructor in general is to be avoided, because modules are instantiated momentarily on startup to gather information. The usual functions of a constructor are performed by startJob*/ public MesquiteModule () { super(); setModule(this); instantiations++; idNumber = instantiations; permanentIDString = Integer.toString(idNumber) + "." + System.currentTimeMillis() + "." + Math.abs(randomNumberGenerator.nextLong()); assignedIDString = null;//new String(permanentIDString); } /*.................................................................................................................*/ /** instantiations of modules are numbered sequentially so they can be referred to by number*/ public long getID(){ return idNumber; } /*.................................................................................................................*/ /** A string that uniquely refers to this module (unique even across runs of Mesquite)*/ public String getPermanentIDString(){ if (assignedIDString == null) return permanentIDString; else return assignedIDString; } /*.................................................................................................................*/ /** A string that should uniquely refer to this module during this run time public String getAssignedIDString(){ return assignedIDString; } /*.................................................................................................................*/ /** Broadcasts that an id has been assigned to a module. This is used for scripting, in which a module assigns itself an id string in a snapshot (e.g., a TreeContext) that an interested module can clue in to (e.g., TreeOfContext). This allows the interested module to hook up to the assigning module even if the former was script-created before the latter (see interaction between BasicTreeWindow and TreeOfContext)*/ public void broadCastAssignedID(MesquiteModule module, String assignedID, CommandRecord commandRec){ if (assignedID == null) return; if (employees ==null) return; Enumeration enum=employees.elements(); while (enum.hasMoreElements()){ MesquiteModule mb = (MesquiteModule)enum.nextElement(); mb.broadCastAssignedID(module, assignedID, commandRec); } } /*.................................................................................................................*/ /** superStartJob is called automatically when an employee is hired. This is intended for use by superclasses of modules that need their own constructor-like call, without relying on the subclass to be polite enough to call super.startJob().*/ public boolean superStartJob(String arguments, Object condition, CommandRecord commandRec, boolean hiredByName){ return true; } /*.................................................................................................................*/ /** startJob is called automatically when an employee is hired. The parameter scripting indicates if the hiring occurs in the context of automated scripting (e.g., on reading a Mesquite block of a NEXUS file). The module can limit user interface calls (e.g. dialog boxes) when scripting occurs.
The MesquiteModule should override this method, to add code to initialize things it needs, and to hire relevant necessary employees. startJob must return true if the module was successfully started; false otherwise. Thus, if the module needs a data matrix but the file has none, it returns false and the hiring process is undone.
Most modules will ignore the arguments and condition.*/
public abstract boolean startJob(String arguments, Object condition, CommandRecord commandRec, boolean hiredByName);
/*.................................................................................................................*/
/** endJob is called as a module is quitting; modules should put their clean up code here.*/
public void endJob() {
}
/*.................................................................................................................*/
public void finalize() throws Throwable {
totalFinalized++;
super.finalize();
}
/*.................................................................................................................*/
/** dispose is called automatically when an employee is fired. It fires all employees and their subemployees etc.
The MesquiteModule should call endJob to
finalize things it needs.. NOTE: if a module wants to quit on its own accord, it should call "iQuit" so that
the replacement hiring system can take effect.*/
protected void dispose() {
if (assignedMenuSpec !=null)
assignedMenuSpec.removeGuestModule(this);
if (moduleMenuSpec !=null)
moduleMenuSpec.removeGuestModule(this);
doomed = true;
MesquiteWindow w = getModuleWindow();
if (w !=null) {
w.hide();
}
boolean employerDoomed = (employer!=null && employer.doomed);
if (!employerDoomed)
incrementMenuResetSuppression();
storePreferences();
if (pagingsEphemeral!=null)
pagingsEphemeral.removeAllElements();
if (pagingsPersistent!=null)
pagingsPersistent.removeAllElements();
disposeMenuSpecifications();
if (w !=null) {
if (!w.disposed()) {
w.dispose();
}
resetAllMenuBars();
}
// if (employer!=null && quit) //TODO: only call this if the employer quit on its own
// employer.employeeQuit(this);
if (MesquiteTrunk.trackActivity) MesquiteMessage.notifyProgrammer ("MesquiteModule " + getName() + " closing down ");
closeDownAllEmployees (this);
if (employer!=null && !employer.doomed && employer.employees!=null) {
employer.employees.removeElement(this, false);
}
if (!employerDoomed)
resetContainingMenuBar();
employer = null; //MEMORY: cut this out to promote memory leaks (tying modules together WHILE debugging NEW aug 99
if (employees!=null)
employees.dispose();
employees = null;
if (!employerDoomed)
decrementMenuResetSuppression();
proj = null;
totalDisposed++;
}
/*.................................................................................................................*/
/** To be called by a module to close down on its own (as opposed to being fired). This might happen, for
example, if conditions change so that the module can no longer function (e.g. all stored matrices are deleted
from a file, and so StoredMatrices can no longer supply matrices). A module could
also call its own endJob() method, but iQuit is to be preferred because it evokes the automatic replacement
hiring system if available. (See setHiringCommand of EmployerEmployee) */
public final void iQuit(){
incrementMenuResetSuppression();
doomAll();
MesquiteModule employerMod = employer;
MesquiteModule localRefEmployer = employer;
boolean employerDoomed = (employer==null || employer.doomed || employerMod.quittingConditions());
if (!employerDoomed) {
localRefEmployer.incrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
localRefEmployer.refreshBrowser(MesquiteModule.class);
}
endJob();
dispose();
MesquiteCommand command = getHiringCommand();
resetAllWindowsMenus();
/* if hiringCommand isn't null, then look among the module info's for possible replacements
and use the hiringCommand to attempt to hire them.
In looking for possible replacements:
-- use the hiringCondition to find compatible modules
-- don't choose again the current module
With each candidate replacement, call the command's doIt method, passing the name of
the candidate as an argument. If the Object returned by doIt is non-null and is an instance of the
candidate module, then it is assume the replacement was successful and the search for replacements is ended.
(It may make sense to notify the user of the replacement.)
*/
if (employerDoomed || employerMod.quittingConditions()) {
}
else if (command!=null){
resetContainingMenuBar();
alert("Module \"" + getName() + "\" has quit; a replacement module will be sought."); //TODO: ask user
MesquiteModuleInfo c=null;
boolean found = false;
if (getHiringCondition()==null){
String name =ListDialog.queryList(module.containerOfModule(), "Select replacement", "Select module to replace " + getName(), MesquiteString.helpString, getHiredAs(), null, employerMod);
if (StringUtil.blank(name)) {
hiredAs = null;
hiringCondition = null;
employerMod.employeeQuit(this);
decrementMenuResetSuppression();
if (!employerDoomed) localRefEmployer.decrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
return;
}
CommandRecord cr = new CommandRecord(false);
cr.setEmergencyRehire(true);
Object mb = command.doIt(StringUtil.tokenize(name), cr);
if (mb!=null && mb instanceof MesquiteModule && ((MesquiteModule)mb).getModuleInfo()!= getModuleInfo() && getHiredAs()!=null && getHiredAs().isAssignableFrom(mb.getClass())) {
alert("Module \"" + ((Listable)mb).getName() + "\" hired to replace \"" + getName() + "\", which has quit");
decrementMenuResetSuppression();
if (!employerDoomed) localRefEmployer.decrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
return;
}
MesquiteModuleInfo prevC = null;
while ((c = MesquiteTrunk.mesquiteModulesInfoVector.findNextModule(getHiredAs(), c)) != null) { // if wasn't successful, find first that works.
if (c!=prevC){
cr = new CommandRecord(false);
cr.setEmergencyRehire(true);
mb = command.doIt(StringUtil.tokenize(c.getName()), cr);
if (mb!=null && mb instanceof MesquiteModule && ((MesquiteModule)mb).getModuleInfo()!= getModuleInfo() && getHiredAs()!=null && getHiredAs().isAssignableFrom(mb.getClass())) {
alert("Module \"" + ((Listable)mb).getName() + "\" hired to replace \"" + getName() + "\", which has quit");
decrementMenuResetSuppression();
if (!employerDoomed) localRefEmployer.decrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
return;
}
prevC = c;
}
}
}
else {
String name =ListDialog.queryList(module.containerOfModule(), "Select replacement", "Select module to replace " + getName(), MesquiteString.helpString, getHiredAs(), getHiringCondition(), employerMod);
if (StringUtil.blank(name)) {
hiredAs = null;
hiringCondition = null;
employerMod.employeeQuit(this);
decrementMenuResetSuppression();
if (!employerDoomed) localRefEmployer.decrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
return;
}
Object mb = command.doIt(StringUtil.tokenize(name));
if (mb!=null && mb instanceof MesquiteModule && ((MesquiteModule)mb).getModuleInfo()!= getModuleInfo() && getHiredAs()!=null && getHiredAs().isAssignableFrom(mb.getClass())) {
alert("Module \"" + ((Listable)mb).getName() + "\" hired to replace \"" + getName() + "\", which has quit");
decrementMenuResetSuppression();
if (!employerDoomed) localRefEmployer.decrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
return;
}
MesquiteModuleInfo prevC = null;
while ((c = MesquiteTrunk.mesquiteModulesInfoVector.findNextModule(getHiredAs(), c, getHiringCondition(), getProject(), employerMod)) != null) { // if wasn't successful, find first that works.
if (c!=prevC){
mb = command.doIt(StringUtil.tokenize(c.getName()));
if (mb!=null && mb instanceof MesquiteModule && ((MesquiteModule)mb).getModuleInfo()!= getModuleInfo() && getHiredAs()!=null && getHiredAs().isAssignableFrom(mb.getClass())) {
alert("Module \"" + ((Listable)mb).getName() + "\" hired to replace \"" + getName() + "\", which has quit");
decrementMenuResetSuppression();
if (!employerDoomed) localRefEmployer.decrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
return;
}
}
prevC = c;
}
}
alert("Employee quit but no replacement hire was found");
employerMod.employeeQuit(this);
}
else {
//alert("Module \"" + getName() + "\" has quit.");
employerMod.employeeQuit(this);
}
decrementMenuResetSuppression();
if (!employerDoomed) localRefEmployer.decrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
}
/*.................................................................................................................*/
/** Query module as to whether conditions are such that it will have to quit soon -- e.g. if its taxa block has been doomed. The tree window, data window,
etc. override this to return true if their object is doomed. This is useful in case MesquiteListener disposing method is not called for an employer before one of its
employees discovers that it needs to quit. If the employer is going to quit anyway,there is no use to use auto rehire for the quit employee.*/
public boolean quittingConditions(){
if (employer!=null) {
return employer.quittingConditions();
}
return false;
}
/*.................................................................................................................*/
/** A method called immediately after the file has been established but not yet read in.*/
public void projectEstablished() {
}
/*.................................................................................................................*/
/** A method called immediately after the file has been read in or completely set up (if a new file).*/
public void fileReadIn(MesquiteFile f) {
}
/*.................................................................................................................*/
/** A method called immediately before a file is to be saved.*/
public void fileAboutToBeWritten(MesquiteFile f) {
}
/*.................................................................................................................*/
/** A method called when a FileElement added to the project; module can respond as needed (e.g.,
InitializeParsimony can add default model set to a CharacterData. (currently only called for Taxa and CharacterData additions).*/
public void fileElementAdded(FileElement element) {
}
/*.................................................................................................................*/
/** Returns duty Class the module belongs to; should be defined not by module itself but by abstract class representing duty */
public abstract Class getDutyClass();
/*.................................................................................................................*/
/** Returns module info for module*/
public MesquiteModuleInfo getModuleInfo(){
return moduleInfo;
}
/** Notifies all employees that a class field has changed.*/
public void classFieldChanged (Class c, String fieldName, CommandRecord commandRec) {
if (employees==null || doomed)
return;
Enumeration e = employees.elements();
while (e.hasMoreElements()) {
Object obj = e.nextElement();
MesquiteModule mbe = (MesquiteModule)obj;
if (mbe!=null) {
mbe.classFieldChanged(c, fieldName, commandRec);
}
}
}
/*.................................................................................................................*/
/** A generic call to tell employer that the module's parameters have changed
sufficiently that its basic calculations are no longer valid, and a recalculation should
be requested. The employer receives the message as a call to its employeeParametersChanged.
(Typically, this might follow an outputInvalid call, which */
public final void parametersChanged(Notification notification, CommandRecord commandRec) {
if (commandRec !=null) commandRec.tick("Parameters of module changed");
if (employer!=null && !doomed) {
if (!hasOldStyleEPC(employer))
employer.employeeParametersChanged(this, this, notification, commandRec);
}
}
public final void parametersChanged(CommandRecord commandRec) {
parametersChanged(null, commandRec);
}
private boolean hasOldStyleEPC(MesquiteModule mb){
try {
mb.getClass().getMethod("employeeParametersChanged", new Class[] {MesquiteModule.class, MesquiteModule.class, CommandRecord.class});
}
catch(NoSuchMethodException e){
return false;
}
catch(SecurityException e){
return false; //hope for best
}
alert("The module " + employer.getName() +" appears to be old and incompatible with the current version of Mesquite.");
return true;
}
/*.................................................................................................................*/
/** Generated by an employee calling its parametersChanged method. The MesquiteModule should act accordingly, for instance, asking
the employee to do a recalculation. */
public void employeeParametersChanged(MesquiteModule employee, MesquiteModule source, Notification notification, CommandRecord commandRec) {
if (commandRec !=null) commandRec.tick("Parameters of employee module changed");
if (employer!=null && !doomed) {
if (!hasOldStyleEPC(employer))
employer.employeeParametersChanged(this, source, notification, commandRec);
}
}
/*.................................................................................................................*/
/** This passes an employeeOutputInvalid call to the employer, and so on, until some employer overrides it to do something about it.
The purpose of this is not to call for recalculations, but primarily to allow the output to be turned blank while
long recalculations are done. To force recalculation, parametersChanged should be called after outputInvalid is called*/
public final void outputInvalid(CommandRecord commandRec) {
if (employer!=null && !doomed)
employer.employeeOutputInvalid(this, this, commandRec);
}
/*.................................................................................................................*/
/** Generated by an employee calling its outputInvalide method. The MesquiteModule should blank any output. */
public void employeeOutputInvalid(MesquiteModule employee, MesquiteModule source, CommandRecord commandRec) {
if (employer!=null && !doomed)
employer.employeeOutputInvalid(this, source, commandRec);
}
/*.................................................................................................................*/
/** Generated by an employee who quit. The MesquiteModule should act accordingly. */
public void employeeQuit(MesquiteModule employee) {
}
/*.................................................................................................................*/
/** Sets this module to remain one of the last employees of its employers. */
public void setToLastEmployee(boolean last){
lastEmployee = last;
}
/*.................................................................................................................*/
/** Returns whether this module is to remain one of the last employees of its employers. */
public boolean getIfLastEmployee(){
return lastEmployee;
}
/*.................................................................................................................*/
/** Sets whether module has requested to enable auto-save of macros. */
public void setAutoSaveMacros(boolean aut){
autoSaveMacros = aut;
}
/*.................................................................................................................*/
/** Returns whether module has requested to enable auto-save of macros. */
public boolean getAutoSaveMacros(){
return autoSaveMacros;
}
/*.................................................................................................................*/
/** Called typically by employer to indicate that will be called soon, therefore don't update graphics. */
public void onHold() {
}
/*.................................................................................................................*/
/** Called typically by employer to turn off hold, therefore don't update graphics. */
public void offHold() {
}
/*.................................................................................................................*/
private String prefsPath (){
return prefsDirectory + MesquiteFile.fileSeparator + getShortClassName(this.getClass()) +".pref";
}
/*.................................................................................................................*/
/** This causes the file "prefs" in the module's directory to be read, and the contents
are then sent to "processPreferencesFromFile".*/
public final void loadPreferences () {
if (MesquiteFile.fileExists(prefsPath())){
String[] prefsString = MesquiteFile.getFileContentsAsStrings(prefsPath());
if (prefsString!=null)
processPreferencesFromFile(prefsString);
}
}
/*.................................................................................................................*/
/** This is called following a "loadPreferences" call by a module. A module can override it
to process the preferences string*/
public void processPreferencesFromFile (String[] prefs) {
}
/*.................................................................................................................*/
/** This causes the file "prefs" in the module's directory to be written, using contents
returned by the module via "preparePreferencesForFile"*/
public final void storePreferences () {
String[] prefsString = preparePreferencesForFile();
if (prefsString!=null)
MesquiteFile.putFileContents(prefsPath(), prefsString, false);
}
/*.................................................................................................................*/
/** This is called following a "storePreferences" call by a module. A module should override it
to indicate the strings to save to its preferences file. */
public String[] preparePreferencesForFile () {
return null;
}
/*.................................................................................................................*/
/** returns path to this module's directory*/
public String getPath() {
if (this == MesquiteTrunk.mesquiteTrunk)
return getRootPath() + "mesquite" + MesquiteFile.fileSeparator;
return moduleInfo.getDirectoryPath();
}
/*.................................................................................................................*/
/** returns path to the root directory of Mesquite (i.e., above mesquite, images, etc.)*/
public static String getRootPath() {
String s= StringUtil.getAllButLastItem(mesquiteDirectoryPath, MesquiteFile.fileSeparator);
if (s==null)
return null;
else
return s + MesquiteFile.fileSeparator;
}
/*.................................................................................................................*/
/** returns path to the root directory of Mesquite images*/
public static String getRootImageDirectoryPath() {
String s = getRootPath();
if (s==null)
return null;
else
return s + "images/";
}
/*.................................................................................................................*/
public static String getSizedRootImageFilePath(int s, String imageFileName){
return getRootImageDirectoryPath() + s + imageFileName;
}
/*.................................................................................................................*/
/** returns path to the root directory of the documentation of Mesquite*/
public static String getDocsPath() {
String s= StringUtil.getAllButLastItem(mesquiteDirectoryPath, MesquiteFile.fileSeparator);
if (s==null)
return null;
else
return s + MesquiteFile.fileSeparator + "docs/mesquite/";
}
/*.................................................................................................................*/
/** returns a local file path expected by the module. This allows the module to say "I am going to need this". Mesquite
check on startup and issues warning if not found . */
public String getExpectedPath(){
return null;
}
/*.................................................................................................................*/
/** Displays an alert in log; also in dialog if flag is set.*/
public void alert(String s, String windowTitle, String logTitle) {
if (startupBailOut)
return;
if (showModuleInAlert)
logln(logTitle+": (" + getName() + "): " + s);
else
logln(logTitle+": " + s);
if (alertUseDialog) {
AlertDialog.notice(containerOfModule(),windowTitle, s);
}
}
/*.................................................................................................................*/
/** Displays an alert in log; also in dialog if flag is set.*/
public void alert(String s) {
alert(s,"Alert", "ALERT");
}
/*.................................................................................................................*/
/** If scripting, puts alert in log; otherwise puts up alert dialog.*/
public void discreetAlert(CommandRecord commandRec, String s) {
discreetAlert(commandRec != null && commandRec.scripting(), s);
}
/*.................................................................................................................*/
/** If scripting, puts alert in log; otherwise puts up alert dialog.*/
public void discreetAlert(boolean beDiscreet, String s) {
if (beDiscreet)
logln("Note: " + s);
else
alert(s,"Note", "Note");
}
/*.................................................................................................................*/
/** Displays a message and returns false. For use when a method fails and is returning false to indicate this, and needs to present a notice to the user.
(This method was made so as to change easily statements of "return false" so that they also gave a message, without having to split into two lines.) */
public boolean sorry(CommandRecord commandRec, String s) {
if (commandRec !=null) commandRec.tick("Sorry, module couldn't be started");
if (!startupBailOut){
if (!commandRec.scripting())
alert(s);
else
logln("Message from " + getNameForMenuItem() + ": " + s);
}
return false;
}
/*.................................................................................................................*/
/** Places string in log AND in System.out.println.*/
public void log(String s) {
logNoEcho(s);
if (!MesquiteTrunk.isMacOS() || (MesquiteTrunk.isMacOSX() && MesquiteTrunk.getJavaVersionAsDouble()>1.39))
System.out.print(s);
}
/*.................................................................................................................*/
/** Places string and newline character in log AND in System.out.println.*/
public void logln(String s) {
loglnNoEcho(s);
if (!MesquiteTrunk.isMacOS() || (MesquiteTrunk.isMacOSX() && MesquiteTrunk.getJavaVersionAsDouble()>1.39))
System.out.println(s);
}
/*.................................................................................................................*/
/** Places string in log.*/
public void logNoEcho(String s) {
if (logWindow!=null) {
if (showModuleInLog)
logWindow.append(getName() + "-- " + s);
else
logWindow.append(s);
}
MesquiteFile.writeToLog(s); //TODO: have a flag that turns this on
Object cOM = containerOfModule();
if (cOM instanceof MesquiteWindow)
((MesquiteWindow)cOM).log(s);
}
/*.................................................................................................................*/
/** Places string and newline character in log.*/
public void loglnNoEcho(String s) {
if (logWindow!=null) {
if (showModuleInLog)
logWindow.append(getName() + "-- " + s + "\n");
else
logWindow.append(s + "\n");
}
MesquiteFile.writeToLog(s+ StringUtil.lineEnding());
Object cOM = containerOfModule();
if (cOM != null && cOM instanceof MesquiteWindow)
((MesquiteWindow)cOM).logln(s);
}
/*.................................................................................................................*/
/** Shows the log window.*/
public static void showLogWindow() {
showLogWindow(true);
}
/*.................................................................................................................*/
/** Shows the log window.*/
public static void showLogWindow(boolean bringToFront) {
if (logWindow!=null) {
if (bringToFront || !logWindow.isVisible())
logWindow.setVisible(true);
}
}
/*.................................................................................................................*/
/** passes which object is being disposed (from MesquiteListener interface)*/
public void disposing(Object obj){
}
/*.................................................................................................................*/
/** passes which object is being disposed (from MesquiteListener interface)*/
public boolean okToDispose(Object obj, int queryUser){
return true; //TODO: respond
}
/*.................................................................................................................*/
/** passes which object changed, along with optional integer (e.g. for character) (from MesquiteListener interface)*/
public void changed(Object caller, Object obj, Notification notification, CommandRecord commandRec){
}
/*.................................................................................................................*/
/** Requests modules to start profiling.*/
public void startProfiling(){
Enumeration e = employees.elements();
while (e.hasMoreElements()) {
Object obj = e.nextElement();
MesquiteModule mbe = (MesquiteModule)obj;
mbe.startProfiling();
}
}
/*.................................................................................................................*/
/** Requests modules to report profiling.*/
public void reportProfiling(){
Enumeration e = employees.elements();
while (e.hasMoreElements()) {
Object obj = e.nextElement();
MesquiteModule mbe = (MesquiteModule)obj;
mbe.reportProfiling();
}
}
public boolean permanentIDExists(String id) {
if (id == null || employees ==null)
return false;
if (id.equalsIgnoreCase(getPermanentIDString())) //had been getAssignedIDString
return true;
Enumeration enum=employees.elements();
while (enum.hasMoreElements()){
MesquiteModule mb = (MesquiteModule)enum.nextElement();
if (mb.permanentIDExists(id))
return true;
}
return false;
}
/*.................................................................................................................*/
/** A request for the MesquiteModule to perform a command. It is passed two strings, the name of the command and the arguments.
This should be overridden by any module that wants to respond to a command.*/
public Object doCommand(String commandName, String arguments, CommandRecord commandRec, CommandChecker checker) {
if (checker.compare(MesquiteModule.class, null, null, commandName, "showEmployeeTree")) {
EmployeeTree etM = (EmployeeTree)findImmediateEmployeeWithDuty(EmployeeTree.class);
if (etM == null)
etM = (EmployeeTree)hireEmployee(commandRec, EmployeeTree.class, null);
if (etM!=null)
etM.showEmployeeTreeWindow(this);
return etM;
}
else if (checker.compare(MesquiteModule.class, "Show employers of this module", null, commandName, "employers")) {
logln(getEmployerPath());
}
else if (checker.compare(MesquiteModule.class, null, null, commandName, "dumpParameterTree")) {
System.out.println("=============\nParameters of modules of window of " + getName() + "\n" + listEmployeeParameters("") + "\n=============");
}
else if (checker.compare(MesquiteModule.class, "Shows manual in browser", null, commandName, "showManual")) {
showManual();
}
else if (checker.compare(MesquiteModule.class, null, null, commandName, "showCommandPage")) {
showWebPage(getCommandPagePath(), true);
}
else if (checker.compare(MesquiteModule.class, null, null, commandName, "showMiniInfoWindow")) {
return new ModuleInfoWindow(module);
}
else if (checker.compare(MesquiteModule.class, null, null, commandName, "setAssignedID")) {
if (getFileCoordinator()!=null && getFileCoordinator().permanentIDExists(arguments))
assignedIDString = getPermanentIDString(); // make new one if old exists
else
assignedIDString = arguments;
if (getFileCoordinator()!=null)
getFileCoordinator().broadCastAssignedID(this, arguments, commandRec);
else
mesquiteTrunk.broadCastAssignedID(this, arguments, commandRec);
return assignedIDString;
}
else if (checker.compare(MesquiteModule.class, null, null, commandName, "getWindow")) {
return getModuleWindow();
}
else if (checker.compare(MesquiteModule.class, null, null, commandName, "saveMacro")) {
String recipe = Snapshot.getSnapshotCommands(this, null, "");
MesquiteMacro.saveMacro(this, "Untitled Macro for " + getNameForMenuItem(), 0, recipe);
}
else if (checker.compare(MesquiteModule.class, null, null, commandName, "applyMacro")) {
MesquiteModuleInfo mmi = getModuleInfo();
if (mmi==null)
return null;
Vector macros = mmi.getMacros();
if (macros ==null || macros.size()<=0)
return null;
MesquiteInteger io = new MesquiteInteger(0);
int macroNumber = MesquiteInteger.fromString(arguments, io);
if (macroNumber>=0 && macroNumber