package Current.manage; import java.applet.Applet; import java.awt.event.*; import java.awt.*; import java.awt.geom.*; import java.util.*; import java.lang.ref.WeakReference; import java.lang.reflect.Method; import java.net.URL; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.Serializable; import org.pat.util.ClassComparator; import Current.popups.Settings.Items.StringSelector; import Current.basic.*; // messages import Current.*; // popups import Current.popups.Grids.GridManager; import Current.popups.Settings.*; import Current.popups.ImageSave.ImageSaveManager; import Current.popups.Deg100.Deg100Interface; // sub managers import Current.manage.Popup.*; import Current.manage.Tiles.*; import Current.manage.ParameterSpace.*; /** * This class offers a communications channel for different components of * McBilliards to talk to each other. * * There is description of "Howto communicate using the manager" * on Pat's website at * @link http://math.sunysb.edu/~pat/visual/web_mcb/Current/Howto/manager.html */ public class Manager implements ParameterSpaceRenderer { //added by Rich //Deg100ManagerInterface DMI=new Deg100ManagerInterface(); /////////////// Handles configuring various features in McBilliards /////////////// for instance: colors for some popups public Settings settings; ///////////////// The MOUSE /** if mouse=1 we are in 3 button mode, if mouse=0 we are in one button mode */ public int mouse; /** if mouse=0, then emulate button=mode presses for mode equal 1,2,3*/ public int mode; ///////////////// SUBMANAGERS public GridManager GM; public SpaceTileManager STM; //private ParameterManager PM; public ParameterSpaceManager PSM; public ImageSaveManager ISM; public SettingsManager settingsManager; public PopupManager PopupM; // global settings public GlobalSettings global; // debugging settings public DebugManagerSettings debug; private Debugger debugger; public Manager() { init(); } public Manager(Applet A) { setCodeBase(A); init(); } private void init() { // set up debugging debug=new DebugManagerSettings(); // set up global settings global=new GlobalSettings(); send_thread=new SendThread(); send_thread.start(); // moving to the new form of manager listeners=new TreeMap(new ClassComparator()); debugger=new Debugger(this); // turn on some caching by default (e.g. colors, parameter space) defaultCaching(); //default to 3 button mouse mouse=1; // if 1 button mouse default to middle button mode=2; // settings settings=new Settings(this); debug=(DebugManagerSettings)settings.getDefault(DebugManagerSettings.class); global=(GlobalSettings)settings.getDefault(GlobalSettings.class); /// submanagers (order is important) //PM=new ParameterManager(); settingsManager=new SettingsManager(this); PSM=new ParameterSpaceManager(this); STM=new SpaceTileManager(this); GM=new GridManager(this); ISM=new ImageSaveManager(); PopupM=new PopupManager(this); } private void defaultCaching() { // cache color and fill start with white mcbCache(Color.class); mcbSend(new Color(255,255,255),true); // cache tiles and default to Fagnano word mcbCache(Tile.class); mcbSend(new SearchTile("123123"),true); // cache and save a default viewing rectangle mcbCache(ViewingRectangleChange.class); mcbSend(new ViewingRectangleChange(new Rectangle2D.Double(0.0,0.0,1.0,1.0)),true); // cache and save a default point in the parameter space mcbCache(Parameter.class); mcbSend(new Parameter(2.0/3,2.0/3),true); // cache rational triangles mcbCache(RationalTriangle.class); mcbSend(new RationalTriangle(1,1,1),true); // cache rational line mcbCache(RationalLine.class); mcbSend(new RationalLine(1,-1,0),true); // cache Deg100Interface mcbCache(Deg100Interface.class); // the rest of this ensures that the messages are dealt with before // continuing } /** wait until no messages are on the stack */ public void mcbWait() { boolean b=false; synchronized (send_queue) { b=(send_queue.size()==0); } while (!b) { try { Thread.currentThread().sleep(10); } catch (Throwable T) { } synchronized (send_queue) { b=(send_queue.size()==0); } } } public static class GlobalSettings implements Serializable { public String getTitle() { return "global settings"; } public StringSelector affine_coordinate_scheme; public static final String affine_coordinate_scheme_name="Affine Coordinate Scheme"; public GlobalSettings() { String[] obtuse_acute={"obtuse", "acute"}; affine_coordinate_scheme=new StringSelector(obtuse_acute); } } public static class DebugManagerSettings implements Serializable { public String getTitle() { return "debug manager"; } /** If true print every new word */ public boolean print_new_words=false; public static final String print_new_words_name="print new words"; public boolean send_debugging=false; public static final String send_debugging_name="debug mcbSend()"; public boolean verbose_debugging=false; public static final String verbose_debugging_name="verbose debugging"; } public class Debugger { public Debugger(Manager M) { M.addListener(this); } public void mcbReceive(Tile t) { if (debug.print_new_words) { System.out.println("Current word:\""+t.getStringWord()+"\""); } } } public void render(Graphics2D g, java.awt.geom.AffineTransform T) { PSM.render(g,T); } /** Add me to the list of components that render to the canvas * I want to draw first! (meaning everything else will draw on top of me */ public void addRendererBottom(ParameterSpaceRenderer me) { PSM.addRendererBottom(me); } /** Add me to the list of components that render to the canvas * I want to draw last! (meaning I draw on top of everything else) */ public void addRendererTop(ParameterSpaceRenderer me) { PSM.addRendererTop(me); } /** return true if the program can write to files. This is impossible * if the program is running as an applet. */ public static boolean canWrite(){ SecurityManager SM=System.getSecurityManager(); if (SM==null) { //System.out.println("No SecurityManager Present!"); return true; } return false; } /*************** REMOVAL *******************/ /** This is a function that removes all references of the given object */ public void remove(Object obj){ //System.out.println("Manager removing a "+obj.getClass().getName()); // also remove from any sub-managers //PSM.remove(obj); ISM.remove(obj); Object o; this.removeListener(obj); o=null; } ///////////////// determines how you should read files // I'm sure there is a better way to do this. private boolean is_applet=false; private URL codeBase; public void setCodeBase(Applet A){ try { codeBase=A.getCodeBase(); is_applet=true; } catch (Throwable T) { is_applet=false; } } public boolean isApplet() { return is_applet; } /** throws exceptions if fails */ public InputStream getInputStream(String file) throws java.io.FileNotFoundException, java.net.MalformedURLException, java.io.IOException { if (is_applet) { return (new URL(codeBase,file)).openStream(); } else { return new FileInputStream(file); } } public URL toURL(String file) { if (is_applet) { try { return new URL(codeBase,file); } catch (Throwable T) { T.printStackTrace(); } } try { URL url=(new File(file)).toURL(); //System.out.println("URL="+url); return url; } catch (Throwable T) { T.printStackTrace(); } System.err.println("Warning returning null in getCodeBase()"); return null; } /// NEW STUFF.... /// From here on, we implement the new version of the /// Manager class. Eventually, the earlier version will be faded out. private class ManagerListener { public WeakReference wr; public Method m; public ManagerListener(WeakReference wr, Method m) { this.wr=wr; this.m=m; } public boolean isValid() { return (wr.get()!=null); } public Class getType() { return m.getParameterTypes()[0]; } public void call(Object obj) { Object arg[]={obj}; Object x=wr.get(); if (x==null) { System.err.println("Attempted to invoke method on vanished weak reference!"); System.err.println("Object type: "+getType()); } else { try { m.invoke(x,arg); } catch (Throwable T) { System.err.println("Trouble with calling method "+m); System.err.println("Using object of type "+x.getClass()); System.err.println("Applying to object of type "+obj.getClass()); T.printStackTrace(); } } } } private class SafeManagerListener { public Object obj; public Method m; public SafeManagerListener(ManagerListener ml) { obj=ml.wr.get(); m=ml.m; } public boolean isValid() { return (obj!=null); } public Class getType() { return m.getParameterTypes()[0]; } public void call(Object parameter) { Object arg[]={parameter}; if (obj==null) { System.err.println("Attempted to invoke method on vanished weak reference!"); System.err.println("Object type: "+getType()); } else { try { m.invoke(obj,arg); } catch (Throwable T) { System.err.println("Trouble with calling method "+m); System.err.println("Using object of type "+obj.getClass()); System.err.println("Applying to object of type "+obj.getClass()); T.printStackTrace(); } } } } private class ListenerClasses { // Linked list of ManagerListeners private LinkedList ll=new LinkedList(); // do you want to cache the object? private boolean cache=false; // cached object private Object cached=null; public ListenerClasses() { } public void add(ManagerListener ml) { synchronized (ll) { ll.add(ml); } } public void remove(Object obj) { synchronized (ll) { ManagerListener ml; for (Iterator it=ll.iterator(); it.hasNext(); ) { ml=(ManagerListener)(it.next()); if (ml.isValid()) { if (ml.wr.get()==obj) { it.remove(); } } else { System.err.println("Warning: non-manual removal of a ManagerListener"+ " of type "+ml.getType()); it.remove(); } } } } private void notifyList(Object msg) { LinkedList ll2=new LinkedList(); SafeManagerListener sml; synchronized (ll) { for (ListIterator it=ll.listIterator(); it.hasNext();) { sml=new SafeManagerListener((ManagerListener)(it.next())); if (sml.isValid()) ll2.add(sml); else { it.remove(); System.out.println("warning: removing a listener of type "+sml.getType()); } } } for (ListIterator it=ll2.listIterator(); it.hasNext();) { sml=(SafeManagerListener)(it.next()); sml.call(msg); } // caching ... if (cache=true) { cached=msg; } } } /** This listeners is arraged by key's of type Class/Interface * and values consisting of a linked list of ManagerListeners */ TreeMap listeners; /** add this object to the list of those objects ** which listen to sent messages */ public void addListener(Object obj) { WeakReference wr=new WeakReference(obj); Class c=obj.getClass(); Method[] meth=c.getMethods(); for (int i=0; i