/*
* ExtendedTreeViewer.java
*
* Copyright (C) 2006-2014 Andrew Rambaut
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package figtree.treeviewer;
import jebl.evolution.alignments.Alignment;
import jebl.evolution.alignments.Pattern;
import jebl.evolution.graphs.Node;
import jebl.evolution.taxa.Taxon;
import jebl.evolution.trees.Tree;
import jebl.util.Attributable;
import jam.panels.StatusListener;
import jam.panels.StatusProvider;
import figtree.treeviewer.annotations.AnnotationDefinition;
import figtree.treeviewer.painters.CharactersPainter;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
/**
* @author Andrew Rambaut
* @version $Id$
*
* $HeadURL$
*
* $LastChangedBy$
* $LastChangedDate$
* $LastChangedRevision$
*/
public class ExtendedTreeViewer extends DefaultTreeViewer implements StatusProvider {
public ExtendedTreeViewer() {
this(null);
}
public ExtendedTreeViewer(JFrame frame) {
super(frame);
// setTreesPerPage(1);
setBackground(Color.white);
}
public void setPattern(Pattern pattern) {
if (pattern != null) {
// setBranchDecorator(new ParsimonyBranchDecorator(pattern));
} else {
setBranchDecorator(null, false);
}
}
public void addTree(Tree tree) {
Set<String> names = new TreeSet<String>();
for (Node node : tree.getNodes()) {
names.addAll(node.getAttributeNames());
}
for (Taxon taxon : tree.getTaxa()) {
names.addAll(taxon.getAttributeNames());
}
for (String name : names) {
if (!name.startsWith("!")) {
AnnotationDefinition annotation = getAnnotationDefinitions().get(name);
Set<Attributable> items = new HashSet<Attributable>(tree.getNodes());
items.addAll(tree.getTaxa());
AnnotationDefinition.Type type = AnnotationDefinition.guessType(name, items);
if (annotation == null) {
annotation = new AnnotationDefinition(name, type);
getAnnotationDefinitions().put(name, annotation);
} else if (type != annotation.getType()){
AnnotationDefinition.Type newType = AnnotationDefinition.Type.STRING;
if (type == AnnotationDefinition.Type.INTEGER &&
annotation.getType() == AnnotationDefinition.Type.REAL) {
newType = AnnotationDefinition.Type.REAL;
}
if (newType != type) {
annotation = new AnnotationDefinition(name, newType);
getAnnotationDefinitions().put(name, annotation);
}
}
}
}
super.addTree(tree);
showStatus();
}
public void showTree(int index) {
super.showTree(index);
showStatus();
}
public void setCharacters(Alignment characters) {
CharactersPainter painter = new CharactersPainter(characters);
setTipLabelPainter(painter);
}
public void setTaxonAnnotations(Map<AnnotationDefinition, Map<Taxon, Object>> annotations) {
for (AnnotationDefinition definition: annotations.keySet()) {
getAnnotationDefinitions().put(definition.getName(), definition);
Map<Taxon, Object> annotation = annotations.get(definition);
for (Taxon taxon : annotation.keySet()) {
taxon.setAttribute(definition.getName(), annotation.get(taxon));
}
}
fireAnnotationsChanged();
}
public void showStatus() {
fireStatusChanged(0, "Showing tree " + Integer.toString(getCurrentTreeIndex() + 1) + " / " + getTreeCount());
}
public void showInfomation() {
}
public void showStatistics() {
}
public void annotateSelected(String name, Object value) {
annotateSelectedNodes(name, value);
annotateSelectedTips(name, value);
fireAnnotationsChanged();
}
public Map<String, AnnotationDefinition> getAnnotationDefinitions() {
if (annotations == null) {
annotations = new HashMap<String, AnnotationDefinition>();
}
return annotations;
}
public void setAnnotationDefinitions(List<AnnotationDefinition> annotations) {
if (this.annotations == null) {
this.annotations = new HashMap<String, AnnotationDefinition>();
}
this.annotations.clear();
for (AnnotationDefinition definition : annotations) {
this.annotations.put(definition.getName(), definition);
}
}
public void annotateNodesFromTips(String annotationName) {
List<Object> stateCodes = new ArrayList<Object>();
Map<Taxon, Integer> stateMap = new HashMap<Taxon, Integer>();
Tree tree = treePane.getTree();
for (Node node : tree.getExternalNodes()) {
Taxon taxon = tree.getTaxon(node);
Object state = taxon.getAttribute(annotationName);
int index = stateCodes.indexOf(state);
if (index == -1) {
index = stateCodes.size();
stateCodes.add(state);
}
stateMap.put(taxon, index);
node.setAttribute(annotationName, state);
}
Parsimony parsimony = new Parsimony(stateCodes.size(), stateMap);
for (Node node : tree.getInternalNodes()) {
Integer stateIndex = parsimony.getState(tree, node);
Object state = null;
if (stateIndex != null) {
state = stateCodes.get(stateIndex);
}
node.setAttribute(annotationName, state);
}
fireAnnotationsChanged();
}
public void annotateTipsFromNodes(String annotationName) {
Tree tree = treePane.getTree();
for (Node node : tree.getExternalNodes()) {
Object state = node.getAttribute(annotationName);
if (state != null) {
Taxon taxon = tree.getTaxon(node);
taxon.setAttribute(annotationName, state);
}
}
fireAnnotationsChanged();
}
private List<AnnotationsListener> listeners = new ArrayList<AnnotationsListener>();
public void addAnnotationsListener(AnnotationsListener listener) {
listeners.add(listener);
}
public void fireAnnotationsChanged() {
for (AnnotationsListener listener : listeners) {
listener.annotationsChanged();
}
fireTreeChanged();
}
private static Map<String, AnnotationDefinition> annotations = null;
private final StatusProvider.Helper statusHelper = new StatusProvider.Helper();
public void addStatusListener(StatusListener statusListener) {
statusHelper.addStatusListener(statusListener);
}
public void removeStatusListener(StatusListener statusListener) {
statusHelper.removeStatusListener(statusListener);
}
public void fireStatusChanged(int status, String statusText) {
statusHelper.fireStatusChanged(status, statusText);
}
public void addOverrideProvider(StatusProvider provider) {
statusHelper.addOverrideProvider(provider);
}
public void removeOverrideProvider(StatusProvider provider) {
statusHelper.removeOverrideProvider(provider);
}
public void fireStatusButtonPressed() {
statusHelper.fireStatusButtonPressed();
}
public void statusButtonPressed() {
statusHelper.statusButtonPressed();
}
public int getStatus() {
return statusHelper.getStatus();
}
public String getStatusText() {
return statusHelper.getStatusText();
}
public void setStatusText(String statusText) {
statusHelper.fireStatusChanged(0, statusText);
}
}