2 * Jalview - A Sequence Alignment Editor and Viewer
\r
3 * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
\r
5 * This program is free software; you can redistribute it and/or
\r
6 * modify it under the terms of the GNU General Public License
\r
7 * as published by the Free Software Foundation; either version 2
\r
8 * of the License, or (at your option) any later version.
\r
10 * This program is distributed in the hope that it will be useful,
\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 * GNU General Public License for more details.
\r
15 * You should have received a copy of the GNU General Public License
\r
16 * along with this program; if not, write to the Free Software
\r
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
\r
20 package jalview.appletgui;
\r
25 import java.awt.event.*;
\r
27 import jalview.analysis.*;
\r
28 import jalview.datamodel.*;
\r
29 import jalview.schemes.*;
\r
30 import jalview.util.*;
\r
32 public class TreeCanvas
\r
33 extends Panel implements MouseListener
\r
36 ScrollPane scrollPane;
\r
38 public static final String PLACEHOLDER = " * ";
\r
42 boolean fitToWindow = true;
\r
43 boolean showDistances = false;
\r
44 boolean showBootstrap = false;
\r
45 boolean markPlaceholders = false;
\r
53 int labelLength = -1;
\r
55 //RubberbandRectangle rubberband;
\r
59 Hashtable nameHash = new Hashtable();
\r
60 Hashtable nodeHash = new Hashtable();
\r
62 public TreeCanvas(AlignViewport av, NJTree tree, ScrollPane scroller,
\r
67 scrollPane = scroller;
\r
68 addMouseListener(this);
\r
69 tree.findHeight(tree.getTopNode());
\r
70 longestName = label;
\r
73 PaintRefresher.Register(this, av.alignment);
\r
76 public void TreeSelectionChanged(Sequence sequence)
\r
78 SequenceGroup selected = av.getSelectionGroup();
\r
79 if (selected == null)
\r
81 selected = new SequenceGroup();
\r
82 av.setSelectionGroup(selected);
\r
85 selected.setEndRes(av.alignment.getWidth());
\r
86 selected.addOrRemove(sequence, true);
\r
88 System.out.println("called here");
\r
89 PaintRefresher.Refresh(this, av.alignment);
\r
93 public void setTree(NJTree tree)
\r
96 tree.findHeight(tree.getTopNode());
\r
99 public void drawNode(Graphics g, SequenceNode node, float chunk, float scale,
\r
100 int width, int offx, int offy)
\r
107 if (node.left() == null && node.right() == null)
\r
109 // Drawing leaf node
\r
111 float height = node.height;
\r
112 float dist = node.dist;
\r
114 int xstart = (int) ( (height - dist) * scale) + offx;
\r
115 int xend = (int) (height * scale) + offx;
\r
117 int ypos = (int) (node.ycount * chunk) + offy;
\r
119 if (node.element() instanceof SequenceI)
\r
121 if ( ( (SequenceI) ( (SequenceNode) node).element()).getColor() ==
\r
124 g.setColor(Color.black);
\r
128 g.setColor( ( (SequenceI) ( (SequenceNode) node).element()).getColor().
\r
135 g.setColor(Color.black);
\r
138 // Draw horizontal line
\r
139 g.drawLine(xstart, ypos, xend, ypos);
\r
141 String nodeLabel = "";
\r
142 if (showDistances && node.dist > 0)
\r
144 nodeLabel = new Format("%5.2f").form(node.dist);
\r
150 nodeLabel = nodeLabel + " : ";
\r
152 nodeLabel = nodeLabel + String.valueOf(node.getBootstrap());
\r
154 if (!nodeLabel.equals(""))
\r
156 g.drawString(nodeLabel, xstart, ypos - 10);
\r
159 String name = (markPlaceholders && node.isPlaceholder()) ?
\r
160 (PLACEHOLDER + node.getName()) : node.getName();
\r
161 FontMetrics fm = g.getFontMetrics(font);
\r
162 int charWidth = fm.stringWidth(name) + 3;
\r
163 int charHeight = fm.getHeight();
\r
165 Rectangle rect = new Rectangle(xend + 20, ypos - charHeight,
\r
166 charWidth, charHeight);
\r
168 nameHash.put( (SequenceI) node.element(), rect);
\r
170 // Colour selected leaves differently
\r
171 SequenceGroup selected = av.getSelectionGroup();
\r
172 if (selected != null &&
\r
173 selected.sequences.contains( (SequenceI) node.element()))
\r
175 g.setColor(Color.gray);
\r
177 g.fillRect(xend + 10, ypos - charHeight + 3, charWidth, charHeight);
\r
178 g.setColor(Color.white);
\r
180 g.drawString(name, xend + 10, ypos);
\r
181 g.setColor(Color.black);
\r
185 drawNode(g, (SequenceNode) node.left(), chunk, scale, width, offx, offy);
\r
186 drawNode(g, (SequenceNode) node.right(), chunk, scale, width, offx, offy);
\r
188 float height = node.height;
\r
189 float dist = node.dist;
\r
191 int xstart = (int) ( (height - dist) * scale) + offx;
\r
192 int xend = (int) (height * scale) + offx;
\r
193 int ypos = (int) (node.ycount * chunk) + offy;
\r
195 g.setColor( ( (SequenceNode) node).color.darker());
\r
197 // Draw horizontal line
\r
198 g.drawLine(xstart, ypos, xend, ypos);
\r
199 g.fillRect(xend - 2, ypos - 2, 4, 4);
\r
201 int ystart = (int) ( ( (SequenceNode) node.left()).ycount * chunk) + offy;
\r
202 int yend = (int) ( ( (SequenceNode) node.right()).ycount * chunk) + offy;
\r
204 Rectangle pos = new Rectangle(xend - 2, ypos - 2, 5, 5);
\r
205 nodeHash.put(node, pos);
\r
207 g.drawLine( (int) (height * scale) + offx, ystart,
\r
208 (int) (height * scale) + offx, yend);
\r
210 if (showDistances && node.dist > 0)
\r
212 g.drawString(new Format("%5.2f").form(node.dist), xstart, ypos - 5);
\r
218 public Object findElement(int x, int y)
\r
220 Enumeration keys = nameHash.keys();
\r
222 while (keys.hasMoreElements())
\r
224 Object ob = keys.nextElement();
\r
225 Rectangle rect = (Rectangle) nameHash.get(ob);
\r
227 if (x >= rect.x && x <= (rect.x + rect.width) &&
\r
228 y >= rect.y && y <= (rect.y + rect.height))
\r
233 keys = nodeHash.keys();
\r
235 while (keys.hasMoreElements())
\r
237 Object ob = keys.nextElement();
\r
238 Rectangle rect = (Rectangle) nodeHash.get(ob);
\r
240 if (x >= rect.x && x <= (rect.x + rect.width) &&
\r
241 y >= rect.y && y <= (rect.y + rect.height))
\r
250 public void pickNodes(Rectangle pickBox)
\r
252 int width = getSize().width;
\r
253 int height = getSize().height;
\r
255 SequenceNode top = tree.getTopNode();
\r
257 float wscale = (float) (width * .8 - offx * 2) / tree.getMaxHeight()
\r
259 if (top.count == 0)
\r
261 top.count = ( (SequenceNode) top.left()).count +
\r
262 ( (SequenceNode) top.right()).count;
\r
264 float chunk = (float) (height - offy * 2) / top.count;
\r
266 pickNode(pickBox, top, chunk, wscale, width, offx, offy);
\r
269 public void pickNode(Rectangle pickBox, SequenceNode node, float chunk,
\r
270 float scale, int width, int offx, int offy)
\r
277 if (node.left() == null && node.right() == null)
\r
279 float height = node.height;
\r
280 float dist = node.dist;
\r
282 int xstart = (int) ( (height - dist) * scale) + offx;
\r
283 int xend = (int) (height * scale) + offx;
\r
285 int ypos = (int) (node.ycount * chunk) + offy;
\r
287 if (pickBox.contains(new Point(xend, ypos)))
\r
289 if (node.element() instanceof SequenceI)
\r
291 SequenceI seq = (SequenceI) node.element();
\r
292 SequenceGroup sg = av.getSelectionGroup();
\r
295 sg.addOrRemove(seq, true);
\r
302 pickNode(pickBox, (SequenceNode) node.left(), chunk, scale, width, offx,
\r
304 pickNode(pickBox, (SequenceNode) node.right(), chunk, scale, width, offx,
\r
309 public void setColor(SequenceNode node, Color c)
\r
316 if (node.left() == null && node.right() == null)
\r
320 if (node.element() instanceof SequenceI)
\r
322 ( (SequenceI) node.element()).setColor(c);
\r
328 setColor( (SequenceNode) node.left(), c);
\r
329 setColor( (SequenceNode) node.right(), c);
\r
333 public void paint(Graphics g)
\r
336 font = new Font("Verdana", Font.PLAIN, fontSize);
\r
339 FontMetrics fm = g.getFontMetrics(font);
\r
341 if (nameHash.size() == 0)
\r
348 scrollPane.getSize().height > fm.getHeight() * nameHash.size() + offy))
\r
350 draw(g, scrollPane.getSize().width, scrollPane.getSize().height);
\r
354 setSize(new Dimension(scrollPane.getSize().width,
\r
355 fm.getHeight() * nameHash.size()));
\r
356 draw(g, scrollPane.getSize().width, fm.getHeight() * nameHash.size());
\r
359 scrollPane.validate();
\r
362 public int getFontSize()
\r
367 public void setFontSize(int fontSize)
\r
369 this.fontSize = fontSize;
\r
373 public void draw(Graphics g, int width, int height)
\r
376 g.setColor(Color.white);
\r
377 g.fillRect(0, 0, width, height);
\r
379 labelLength = g.getFontMetrics(font).stringWidth(longestName) + 20; //20 allows for scrollbar
\r
381 float wscale = (float) (width - labelLength - offx * 2) / tree.getMaxHeight();
\r
383 SequenceNode top = tree.getTopNode();
\r
385 if (top.count == 0)
\r
387 top.count = ( (SequenceNode) top.left()).count +
\r
388 ( (SequenceNode) top.right()).count;
\r
390 float chunk = (float) (height - offy * 2) / top.count;
\r
392 drawNode(g, tree.getTopNode(), chunk, wscale, width, offx, offy);
\r
394 if (threshold != 0)
\r
396 if (av.getCurrentTree() == tree)
\r
398 g.setColor(Color.red);
\r
402 g.setColor(Color.gray);
\r
405 int x = (int) (threshold *
\r
406 (float) (getSize().width - labelLength - 2 * offx) + offx);
\r
408 g.drawLine(x, 0, x, getSize().height);
\r
413 public void mouseReleased(MouseEvent e)
\r
416 public void mouseEntered(MouseEvent e)
\r
419 public void mouseExited(MouseEvent e)
\r
422 public void mouseClicked(MouseEvent e)
\r
426 public void mousePressed(MouseEvent e)
\r
428 av.setCurrentTree(tree);
\r
433 Object ob = findElement(x, y);
\r
435 if (ob instanceof SequenceI)
\r
437 TreeSelectionChanged( (Sequence) ob);
\r
442 else if (ob instanceof SequenceNode)
\r
444 SequenceNode tmpnode = (SequenceNode) ob;
\r
445 tree.swapNodes(tmpnode);
\r
446 tree.reCount(tree.getTopNode());
\r
447 tree.findHeight(tree.getTopNode());
\r
453 if (tree.getMaxHeight() != 0)
\r
455 threshold = (float) (x - offx) /
\r
456 (float) (getSize().width - labelLength - 2 * offx);
\r
458 tree.getGroups().removeAllElements();
\r
459 tree.groupNodes(tree.getTopNode(), threshold);
\r
460 setColor(tree.getTopNode(), Color.black);
\r
462 av.setSelectionGroup(null);
\r
463 av.alignment.deleteAllGroups();
\r
465 for (int i = 0; i < tree.getGroups().size(); i++)
\r
468 Color col = new Color( (int) (Math.random() * 255),
\r
469 (int) (Math.random() * 255),
\r
470 (int) (Math.random() * 255));
\r
471 setColor( (SequenceNode) tree.getGroups().elementAt(i), col.brighter());
\r
473 Vector l = tree.findLeaves( (SequenceNode) tree.getGroups().elementAt(
\r
476 Vector sequences = new Vector();
\r
477 for (int j = 0; j < l.size(); j++)
\r
479 SequenceI s1 = (SequenceI) ( (SequenceNode) l.elementAt(j)).element();
\r
480 if(!sequences.contains(s1))
\r
481 sequences.addElement(s1);
\r
484 ColourSchemeI cs = ColourSchemeProperty.getColour(sequences, av.alignment.getWidth(),
\r
485 ColourSchemeProperty.getColourName(av.getGlobalColourScheme()));
\r
488 SequenceGroup sg = new SequenceGroup(sequences, "TreeGroup",
\r
490 false, 0, av.alignment.getWidth());
\r
493 if (av.getGlobalColourScheme() instanceof ConservationColourScheme)
\r
495 ConservationColourScheme ccs = (ConservationColourScheme) av.
\r
496 getGlobalColourScheme();
\r
497 Conservation c = new Conservation("Group",
\r
498 ResidueProperties.propHash, 3,
\r
499 sg.sequences, sg.getStartRes(),
\r
503 c.verdict(false, av.ConsPercGaps);
\r
504 ccs = new ConservationColourScheme(c, ccs.cs);
\r
510 av.alignment.addGroup(sg);
\r
516 PaintRefresher.Refresh(this, av.alignment);
\r
521 public void setShowDistances(boolean state)
\r
523 this.showDistances = state;
\r
527 public void setShowBootstrap(boolean state)
\r
529 this.showBootstrap = state;
\r
533 public void setMarkPlaceholders(boolean state)
\r
535 this.markPlaceholders = state;
\r