4 import jalview.analysis.*;
\r
5 import jalview.datamodel.*;
\r
6 import jalview.util.*;
\r
7 import javax.swing.*;
\r
9 import java.awt.event.*;
\r
13 public class TreeCanvas extends JPanel implements MouseListener
\r
16 JScrollPane scrollPane;
\r
22 boolean showDistances = false;
\r
23 boolean showBootstrap = false;
\r
33 //RubberbandRectangle rubberband;
\r
38 Hashtable nameHash = new Hashtable();
\r
39 Hashtable nodeHash = new Hashtable();
\r
41 public TreeCanvas(AlignViewport av, NJTree tree, JScrollPane scroller, String label)
\r
45 selected = av.getSelection();
\r
46 scrollPane = scroller;
\r
47 addMouseListener(this);
\r
48 tree.findHeight(tree.getTopNode());
\r
49 longestName = label;
\r
51 PaintRefresher.Register(this);
\r
53 public void TreeSelectionChanged(Sequence sequence)
\r
55 selected = av.getSelection();
\r
57 if (selected.contains(sequence))
\r
58 selected.removeElement(sequence);
\r
60 selected.addElement(sequence);
\r
62 setSelected(selected);
\r
63 PaintRefresher.Refresh(this);
\r
68 public void setSelected(Selection selected)
\r
70 this.selected = selected;
\r
73 public void setTree(NJTree tree) {
\r
75 tree.findHeight(tree.getTopNode());
\r
78 public void drawNode(Graphics g,SequenceNode node, float chunk, float scale, int width,int offx, int offy) {
\r
83 if (node.left() == null && node.right() == null) {
\r
84 // Drawing leaf node
\r
86 float height = node.height;
\r
87 float dist = node.dist;
\r
89 int xstart = (int)((height-dist)*scale) + offx;
\r
90 int xend = (int)(height*scale) + offx;
\r
92 int ypos = (int)(node.ycount * chunk) + offy;
\r
94 if (node.element() instanceof SequenceI)
\r
95 g.setColor(((SequenceI)((SequenceNode)node).element()).getColor().darker());
\r
97 g.setColor(Color.black);
\r
100 // Draw horizontal line
\r
101 g.drawLine(xstart,ypos,xend,ypos);
\r
103 String nodeLabel = "";
\r
104 if (showDistances && node.dist > 0) {
\r
105 nodeLabel = new Format("%5.2f").form(node.dist);
\r
107 if (showBootstrap) {
\r
108 if (showDistances) {
\r
109 nodeLabel = nodeLabel + " : ";
\r
111 nodeLabel = nodeLabel + String.valueOf(node.getBootstrap());
\r
113 if (! nodeLabel.equals("")) {
\r
114 g.drawString(nodeLabel,xstart,ypos - 10);
\r
117 // Colour selected leaves differently
\r
118 String name = node.getName();
\r
119 FontMetrics fm = g.getFontMetrics(font);
\r
120 int charWidth = fm.stringWidth(node.getName()) + 3;
\r
121 int charHeight = fm.getHeight();
\r
123 Rectangle rect = new Rectangle(xend+20,ypos-charHeight,
\r
124 charWidth,charHeight);
\r
126 nameHash.put((SequenceI)node.element(),rect);
\r
128 if (selected.contains((SequenceI)node.element())) {
\r
129 g.setColor(Color.gray);
\r
131 g.fillRect(xend + 10, ypos - charHeight + 3,charWidth,charHeight);
\r
132 g.setColor(Color.white);
\r
134 g.drawString(node.getName(),xend+10,ypos);
\r
135 g.setColor(Color.black);
\r
137 drawNode(g,(SequenceNode)node.left(), chunk,scale,width,offx,offy);
\r
138 drawNode(g,(SequenceNode)node.right(),chunk,scale,width,offx,offy);
\r
140 float height = node.height;
\r
141 float dist = node.dist;
\r
143 int xstart = (int)((height-dist)*scale) + offx;
\r
144 int xend = (int)(height *scale) + offx;
\r
145 int ypos = (int)(node.ycount *chunk) + offy;
\r
147 g.setColor(((SequenceNode)node).color.darker());
\r
149 // Draw horizontal line
\r
150 g.drawLine(xstart,ypos,xend,ypos);
\r
151 g.fillRect(xend-2, ypos-2, 4,4);
\r
153 int ystart = (int)(((SequenceNode)node.left()) .ycount * chunk) + offy;
\r
154 int yend = (int)(((SequenceNode)node.right()).ycount * chunk) + offy;
\r
156 Rectangle pos = new Rectangle(xend-2,ypos-2,5,5);
\r
157 nodeHash.put(node,pos);
\r
159 g.drawLine((int)(height*scale) + offx, ystart,
\r
160 (int)(height*scale) + offx, yend);
\r
162 if (showDistances && node.dist > 0) {
\r
163 g.drawString(new Format("%5.2f").form(node.dist),xstart,ypos - 5);
\r
168 public Object findElement(int x, int y) {
\r
169 Enumeration keys = nameHash.keys();
\r
171 while (keys.hasMoreElements()) {
\r
172 Object ob = keys.nextElement();
\r
173 Rectangle rect = (Rectangle)nameHash.get(ob);
\r
175 if (x >= rect.x && x <= (rect.x + rect.width) &&
\r
176 y >= rect.y && y <= (rect.y + rect.height)) {
\r
180 keys = nodeHash.keys();
\r
182 while (keys.hasMoreElements()) {
\r
183 Object ob = keys.nextElement();
\r
184 Rectangle rect = (Rectangle)nodeHash.get(ob);
\r
186 if (x >= rect.x && x <= (rect.x + rect.width) &&
\r
187 y >= rect.y && y <= (rect.y + rect.height)) {
\r
195 public void pickNodes(Rectangle pickBox, Selection sel) {
\r
196 int width = getWidth();
\r
197 int height = getHeight();
\r
199 SequenceNode top = tree.getTopNode();
\r
201 float wscale = (float)(width*.8-offx*2)/tree.getMaxHeight()
\r
203 if (top.count == 0) {
\r
204 top.count = ((SequenceNode)top.left()).count + ((SequenceNode)top.right()).count ;
\r
206 float chunk = (float)(height-offy*2)/top.count;
\r
208 pickNode(pickBox,sel,top,chunk,wscale,width,offx,offy);
\r
211 public void pickNode(Rectangle pickBox, Selection sel, SequenceNode node, float chunk, float scale, int width,int offx, int offy) {
\r
212 if (node == null) {
\r
216 if (node.left() == null && node.right() == null) {
\r
217 float height = node.height;
\r
218 float dist = node.dist;
\r
220 int xstart = (int)((height-dist)*scale) + offx;
\r
221 int xend = (int)(height*scale) + offx;
\r
223 int ypos = (int)(node.ycount * chunk) + offy;
\r
225 if (pickBox.contains(new Point(xend,ypos))) {
\r
226 if (node.element() instanceof SequenceI) {
\r
227 SequenceI seq = (SequenceI)node.element();
\r
228 if (sel.contains(seq)) {
\r
229 sel.removeElement(seq);
\r
231 sel.addElement(seq);
\r
236 pickNode(pickBox,sel,(SequenceNode)node.left(), chunk,scale,width,offx,offy);
\r
237 pickNode(pickBox,sel,(SequenceNode)node.right(),chunk,scale,width,offx,offy);
\r
241 public void setColor(SequenceNode node, Color c) {
\r
242 if (node == null) {
\r
246 if (node.left() == null && node.right() == null) {
\r
249 if (node.element() instanceof SequenceI) {
\r
250 ((SequenceI)node.element()).setColor(c);
\r
254 setColor((SequenceNode)node.left(),c);
\r
255 setColor((SequenceNode)node.right(),c);
\r
260 public void paintComponent(Graphics g) {
\r
263 font = new Font("Verdana",Font.PLAIN,fontSize);
\r
266 FontMetrics fm = g.getFontMetrics(font);
\r
268 if(nameHash.size()==0)
\r
272 if( scrollPane.getHeight() > fm.getHeight() * nameHash.size()+offy)
\r
274 draw(g,scrollPane.getWidth(),scrollPane.getHeight());
\r
275 setPreferredSize(new Dimension(scrollPane.getWidth(), scrollPane.getHeight()));
\r
279 setPreferredSize(new Dimension(getWidth(), fm.getHeight() * nameHash.size()));
\r
280 draw( g,getWidth(), fm.getHeight() * nameHash.size());
\r
284 if (threshold != 0)
\r
286 g.setColor(Color.red);
\r
287 g.drawLine(threshold,0,threshold,getHeight());
\r
290 scrollPane.revalidate();
\r
292 public int getFontSize() {
\r
295 public void setFontSize(int fontSize) {
\r
296 this.fontSize = fontSize;
\r
299 public void draw(Graphics g, int width, int height) {
\r
300 g.setColor(Color.white);
\r
301 g.fillRect(0,0,width,height);
\r
304 labelLength = g.getFontMetrics(font).stringWidth(longestName)+ 20;//20 allows for scrollbar
\r
306 float wscale =(float)(width - labelLength -offx*2)/tree.getMaxHeight();
\r
308 SequenceNode top = tree.getTopNode();
\r
310 if (top.count == 0) {
\r
311 top.count = ((SequenceNode)top.left()).count + ((SequenceNode)top.right()).count ;
\r
313 float chunk = (float)(height-offy*2)/top.count ;
\r
315 drawNode(g,tree.getTopNode(),chunk,wscale,width,offx,offy);
\r
318 public void mouseReleased(MouseEvent e) { }
\r
319 public void mouseEntered(MouseEvent e) { }
\r
320 public void mouseExited(MouseEvent e) { }
\r
321 public void mouseClicked(MouseEvent e) {
\r
324 public void mousePressed(MouseEvent e) {
\r
328 Object ob = findElement(x,y);
\r
330 if (ob instanceof SequenceI)
\r
332 TreeSelectionChanged((Sequence)ob);
\r
336 } else if (ob instanceof SequenceNode) {
\r
337 SequenceNode tmpnode = (SequenceNode)ob;
\r
338 tree.swapNodes(tmpnode);
\r
339 tree.reCount(tree.getTopNode());
\r
340 tree.findHeight(tree.getTopNode());
\r
344 if (tree.getMaxHeight() != 0) {
\r
345 float fthreshold = (float)(x - offx)/(float)(getWidth()-labelLength - 2*offx);
\r
346 this.threshold = x;
\r
347 tree.getGroups().removeAllElements();
\r
348 tree.groupNodes(tree.getTopNode(),fthreshold);
\r
349 setColor(tree.getTopNode(),Color.black);
\r
351 for (int i=0; i < tree.getGroups().size(); i++) {
\r
353 Color col = new Color((int)(Math.random()*255),
\r
354 (int)(Math.random()*255),
\r
355 (int)(Math.random()*255));
\r
356 setColor((SequenceNode)tree.getGroups().elementAt(i),col.brighter());
\r
358 // l is vector of Objects
\r
359 // Vector l = tree.findLeaves((SequenceNode)tree.getGroups().elementAt(i),new Vector());
\r
365 PaintRefresher.Refresh(this);
\r
370 public void setShowDistances(boolean state) {
\r
371 this.showDistances = state;
\r
375 public void setShowBootstrap(boolean state) {
\r
376 this.showBootstrap = state;
\r