/*******************************************************************************
* Copyright (c) 2007, 2008 Gregory Jordan
*
* This file is part of PhyloWidget.
*
* PhyloWidget is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 2 of the License, or (at your option) any later
* version.
*
* PhyloWidget is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* PhyloWidget. If not, see <http://www.gnu.org/licenses/>.
*/
package org.phylowidget;
import java.awt.event.KeyEvent;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.SwingUtilities;
import org.andrewberman.ui.UIUtils;
import org.andrewberman.ui.unsorted.JSCaller;
import org.andrewberman.ui.unsorted.JavaUtils;
import org.andrewberman.ui.unsorted.MethodAndFieldSetter;
import org.andrewberman.ui.unsorted.StringPair;
import org.phylowidget.net.PhyloTransformServices;
import org.phylowidget.render.DoubleBuffer;
import org.phylowidget.tree.PhyloNode;
import org.phylowidget.tree.RootedTree;
import org.phylowidget.tree.TreeIO;
import org.phylowidget.ui.PhyloConfig;
import org.phylowidget.ui.PhyloUI;
import processing.core.PApplet;
public class PhyloWidget extends PWPublicMethods
{
private static final long serialVersionUID = -7096870051293017660L;
public PWContext pwc;
public static float FRAMERATE = 40;
private static String messageString = new String();
long time = 0;
public PhyloWidget()
{
super();
time = System.currentTimeMillis();
}
@Override
public void start()
{
pwc = (PWContext) PWPlatform.getInstance().registerApp(this);
super.start();
// When running inside a browser, start() will be called when someone
// returns to a page containing this applet.
// http://dev.processing.org/bugs/show_bug.cgi?id=581
finished = false;
}
public void setup()
{
if (frame != null)
{
/*
* We're in standalone / application mode. FREEDOM!!!
*/
frame.setResizable(true);
frame.setTitle("PhyloWidget Standalone");
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
size(500, 500);
}
});
} else
{
/*
* We're locked into an applet. Don't fight it.
*/
size(getWidth(), getHeight(), JAVA2D);
final PhyloWidget pw = this;
Runnable callHome = new Runnable()
{
public void run()
{
JSCaller call = new JSCaller(pw);
try
{
// Make this Javascript call to satisfy the PulpCore javascript loader that we're using.
call.call("pulpcore_appletLoaded", null);
} catch (Exception e)
{
// If we're not in a browser, we'll get an exception here.
}
}
};
pwc.createThread(callHome).start();
}
frameRate(FRAMERATE);
unregisterDraw(pwc.event());
final PhyloWidget pw = this;
Runnable setup = new Runnable()
{
public void run()
{
pwc.ui().setup();
pwc.trees().setup();
clearQueues();
}
};
// setup.run();
pwc.createThread(setup).start();
}
DoubleBuffer dbr;
@Override
public void resize(int width, int height)
{
super.resize(width, height);
UIUtils.setRenderingHints(g);
}
boolean drawnOnce = false;
public void drawLongWaitingMessage()
{
;
fill(100f, 200f);
rect(0, 0, width, height);
fill(255);
textSize(14);
textAlign(PApplet.CENTER, PApplet.CENTER);
text("Doing something that \nmight take a while...", width / 2, height / 2);
}
public synchronized void draw()
{
background(pwc.config().getBackgroundColor().getRGB(), 1.0f);
// If we have setting changes or method calls on the queue, run them now.
if (drawnOnce)
clearQueues();
pwc.event().draw();
if (doingSomethingLong)
{
drawLongWaitingMessage();
}
if (!pwc.config().suppressMessages)
{
if (frameCount - messageFrame > (frameRateTarget * messageDecay))
messageString = "";
if (messageString.length() != 0)
{
drawMessage();
}
if (pwc.config().debug)
{
drawNumLeaves();
drawFrameRate();
}
}
drawnOnce = true;
}
Pattern parens = Pattern.compile("(.*?)\\((.*)\\)");
ArrayList<StringPair> settingsAndMethods = new ArrayList<StringPair>();
static final String METHOD_FLAG = "!!method!!";
protected void clearQueues()
{
internalTransformTree();
while (!settingsAndMethods.isEmpty())
{
StringPair sp = settingsAndMethods.remove(0); // Remove first.
System.out.println(sp);
if (sp.a == METHOD_FLAG)
{
try
{
String s = sp.b;
Method m = null;
Object[] args = new Object[] {};
Matcher match = parens.matcher(s);
boolean matched = false;
while (match.find())
{
matched = true;
s = match.group(1);
args = new Object[] { match.group(2) };
System.out.println(s + " " + args);
m = PhyloUI.class.getMethod(s, String.class);
m.invoke(pwc.ui(), args);
}
if (!matched)
{
m = PhyloUI.class.getMethod(s);
m.invoke(pwc.ui());
}
} catch (Exception e)
{
e.printStackTrace();
}
} else
{
HashMap<String, String> map = new HashMap<String, String>();
map.put(sp.a, sp.b);
MethodAndFieldSetter.setMethodsAndFields(pwc.config(), map);
}
}
}
public void stop()
{
super.stop();
}
public synchronized void destroy()
{
noLoop();
super.destroy();
pwc.destroy();
}
protected void drawFrameRate()
{
textAlign(PApplet.LEFT);
textFont(pwc.getPFont());
textSize(10);
fill(255, 0, 0);
text(String.valueOf(round(frameRate * 10) / 10.0), width - 40, height - 10);
// Uncomment to print out the number of leaves.
// RootedTree t = trees.getTree();
// int numLeaves = t.getNumEnclosedLeaves(t.getRoot());
// text(numLeaves,5,height-10);
}
protected void drawNumLeaves()
{
RootedTree tree = pwc.trees().getTree();
if (tree == null)
return;
int leaves = tree.getNumEnclosedLeaves(tree.getRoot());
String nleaves = String.valueOf(leaves);
textAlign(PApplet.LEFT);
textFont(pwc.getPFont());
textSize(10);
fill(255, 0, 0);
text(nleaves, width - 100, height - 10);
}
protected void drawMessage()
{
textAlign(PApplet.LEFT);
textFont(pwc.getPFont());
textSize(10);
float w = textWidth(messageString);
fill(255, 255, 255);
stroke(255, 255, 255);
strokeWeight(3);
rect(5, height - 20, w, 12);
fill(255, 0, 0);
text(messageString, 5, height - 10);
}
static int messageFrame;
static float messageDecay = 15;
public void setMessage(String s)
{
messageString = s;
// if (p != null)
messageFrame = frameCount;
}
public boolean jsTest()
{
return true;
}
public void close()
{
if (frame != null) // We're in standalone mode
{
frame.setVisible(false);
destroy();
}
}
public void setTree(String s)
{
changeSetting("tree", s);
setMessage("Tree updated.");
}
public void setClipboard(String s)
{
changeSetting("clipboard", s);
setMessage("Clipboard updated.");
}
public synchronized void changeSetting(String setting, String newValue)
{
if (pwc.config().debug)
{
System.out.println(setting + "\t" + newValue);
}
synchronized (settingsAndMethods)
{
settingsAndMethods.add(new StringPair(setting, newValue));
}
}
public synchronized void callMethod(String method)
{
settingsAndMethods.add(new StringPair(METHOD_FLAG, method));
}
@Override
public void keyPressed()
{
super.keyPressed();
if (key == KeyEvent.VK_ESCAPE)
key = 0;
}
@Override
public String getAppletInfo()
{
return "PhyloWidget";
}
static public void main(String args[])
{
PApplet.main(new String[] { "org.phylowidget.PhyloWidget" });
}
@Override
public String getClipboardString()
{
return pwc.ui().clipboard.getClipboardText();
}
@Override
public String getUrlParameters()
{
Map<String, String> changedFields = PhyloConfig.getConfigSnapshot(pwc.config());
PhyloTree tree = (PhyloTree) pwc.trees().getTree();
// Replace the &'s with *'s. TreeIO was modified to accept this alternative NHX signifier.
String nhx = tree.getNHX();
nhx = nhx.replaceAll("&", "*");
nhx = nhx.replaceAll("'", "`");
changedFields.put("tree", nhx);
ArrayList<String> keyvals = new ArrayList<String>();
for (String key : changedFields.keySet())
{
String s = "";
s += key + "=" + "'" + changedFields.get(key) + "'";
keyvals.add(s);
}
return JavaUtils.join("&", keyvals);
}
@Override
public void setAnnotations(String nodeLabel, String annotationJson)
{
System.out.println("SETTING ANNOTATION\n");
PhyloTree tree = (PhyloTree) pwc.trees().getTree();
if (tree == null)
return;
List<PhyloNode> nodes = tree.search(nodeLabel);
PhyloNode n = nodes.get(0);
if (n == null)
return;
System.out.println("JSON: " + annotationJson);
n.setAnnotationsFromJson(annotationJson);
}
public void setAnnotation(String nodeLabel, String key, String value)
{
PhyloTree tree = (PhyloTree) pwc.trees().getTree();
if (tree == null)
return;
List<PhyloNode> nodes = tree.search(nodeLabel);
PhyloNode n = nodes.get(0);
if (n == null)
return;
n.setAnnotation(key, value);
}
private boolean doingSomethingLong = false;
@Override
public void transformTree(final String url)
{
treeTransform = url;
}
String treeTransform = null;
private void internalTransformTree()
{
// For the record: Java security sucks. GJ 2009-03-13.
if (treeTransform == null)
{
return;
} else
{
doingSomethingLong = true;
pwc.event().setDisabled(true);
final String url = treeTransform;
this.treeTransform = null;
final PhyloTree tree = (PhyloTree) pwc.trees().getTree();
new Thread()
{
public void run()
{
String nexml = tree.getNeXML();
try
{
// String url = "http://www.phylowidget.org/cgi-bin/random_mess.pl";
// String url = "http://www.phylowidget.org/cgi-bin/images_from_morphbank.pl";
// String url = "http://www.phylowidget.org/cgi-bin/images_from_tolweb.pl";
String returned = PhyloTransformServices.transformTree(url, nexml);
PhyloTree newTree = (PhyloTree) TreeIO.parseNewickString(new PhyloTree(), returned);
pwc.trees().setTree(newTree);
} catch (Exception e)
{
e.printStackTrace();
}
pwc.event().setDisabled(false);
doingSomethingLong = false;
}
}.start();
}
}
}