click node to select sequences
[jalview.git] / src / jalview / gui / TreeCanvas.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\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
9  *\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
14  *\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
18  */\r
19 package jalview.gui;\r
20 \r
21 import jalview.analysis.*;\r
22 \r
23 import jalview.datamodel.*;\r
24 \r
25 import jalview.schemes.*;\r
26 \r
27 import jalview.util.*;\r
28 \r
29 import java.awt.*;\r
30 import java.awt.event.*;\r
31 import java.awt.print.*;\r
32 \r
33 import java.util.*;\r
34 \r
35 import javax.swing.*;\r
36 \r
37 \r
38 /**\r
39  * DOCUMENT ME!\r
40  *\r
41  * @author $author$\r
42  * @version $Revision$\r
43  */\r
44 public class TreeCanvas extends JPanel implements MouseListener, Runnable,\r
45     Printable, MouseMotionListener\r
46 {\r
47     /** DOCUMENT ME!! */\r
48     public static final String PLACEHOLDER = " * ";\r
49     NJTree tree;\r
50     JScrollPane scrollPane;\r
51     AlignViewport av;\r
52     Font font;\r
53     FontMetrics fm;\r
54     boolean fitToWindow = true;\r
55     boolean showDistances = false;\r
56     boolean showBootstrap = false;\r
57     boolean markPlaceholders = false;\r
58     int offx = 20;\r
59     int offy;\r
60     float threshold;\r
61     String longestName;\r
62     int labelLength = -1;\r
63 \r
64     Hashtable nameHash = new Hashtable();\r
65     Hashtable nodeHash = new Hashtable();\r
66     SequenceNode highlightNode;\r
67 \r
68     /**\r
69      * Creates a new TreeCanvas object.\r
70      *\r
71      * @param av DOCUMENT ME!\r
72      * @param tree DOCUMENT ME!\r
73      * @param scroller DOCUMENT ME!\r
74      * @param label DOCUMENT ME!\r
75      */\r
76     public TreeCanvas(AlignViewport av, JScrollPane scroller)\r
77     {\r
78         this.av = av;\r
79         font = av.getFont();\r
80         scrollPane = scroller;\r
81         addMouseListener(this);\r
82         addMouseMotionListener(this);\r
83         PaintRefresher.Register(this, av.alignment);\r
84     }\r
85 \r
86 \r
87     /**\r
88      * DOCUMENT ME!\r
89      *\r
90      * @param sequence DOCUMENT ME!\r
91      */\r
92     public void treeSelectionChanged(SequenceI sequence)\r
93     {\r
94         SequenceGroup selected = av.getSelectionGroup();\r
95 \r
96         if (selected == null)\r
97         {\r
98             selected = new SequenceGroup();\r
99             av.setSelectionGroup(selected);\r
100         }\r
101 \r
102         selected.setEndRes(av.alignment.getWidth()-1);\r
103         selected.addOrRemove(sequence, true);\r
104     }\r
105 \r
106     /**\r
107      * DOCUMENT ME!\r
108      *\r
109      * @param tree DOCUMENT ME!\r
110      */\r
111     public void setTree(NJTree tree)\r
112     {\r
113         this.tree = tree;\r
114         tree.findHeight(tree.getTopNode());\r
115 \r
116         // Now have to calculate longest name based on the leaves\r
117         Vector leaves = tree.findLeaves(tree.getTopNode(), new Vector());\r
118         boolean has_placeholders = false;\r
119         longestName = "";\r
120 \r
121         for (int i = 0; i < leaves.size(); i++)\r
122         {\r
123           SequenceNode lf = (SequenceNode) leaves.elementAt(i);\r
124 \r
125           if (lf.isPlaceholder())\r
126           {\r
127             has_placeholders = true;\r
128           }\r
129 \r
130           if (longestName.length() < ( (Sequence) lf.element()).getName()\r
131               .length())\r
132           {\r
133             longestName = TreeCanvas.PLACEHOLDER +\r
134                 ( (Sequence) lf.element()).getName();\r
135           }\r
136         }\r
137 \r
138         setMarkPlaceholders(has_placeholders);\r
139     }\r
140 \r
141     /**\r
142      * DOCUMENT ME!\r
143      *\r
144      * @param g DOCUMENT ME!\r
145      * @param node DOCUMENT ME!\r
146      * @param chunk DOCUMENT ME!\r
147      * @param scale DOCUMENT ME!\r
148      * @param width DOCUMENT ME!\r
149      * @param offx DOCUMENT ME!\r
150      * @param offy DOCUMENT ME!\r
151      */\r
152     public void drawNode(Graphics g, SequenceNode node, float chunk,\r
153         float scale, int width, int offx, int offy)\r
154     {\r
155         if (node == null)\r
156         {\r
157             return;\r
158         }\r
159 \r
160         if ((node.left() == null) && (node.right() == null))\r
161         {\r
162             // Drawing leaf node\r
163             float height = node.height;\r
164             float dist = node.dist;\r
165 \r
166             int xstart = (int) ((height - dist) * scale) + offx;\r
167             int xend = (int) (height * scale) + offx;\r
168 \r
169             int ypos = (int) (node.ycount * chunk) + offy;\r
170 \r
171             if (node.element() instanceof SequenceI)\r
172             {\r
173                 if (((SequenceI) ((SequenceNode) node).element()).getColor() == Color.white)\r
174                 {\r
175                     g.setColor(Color.black);\r
176                 }\r
177                 else\r
178                 {\r
179                     g.setColor(((SequenceI) ((SequenceNode) node).element()).getColor()\r
180                                 .darker());\r
181                 }\r
182             }\r
183             else\r
184             {\r
185                 g.setColor(Color.black);\r
186             }\r
187 \r
188             // Draw horizontal line\r
189             g.drawLine(xstart, ypos, xend, ypos);\r
190 \r
191             String nodeLabel = "";\r
192 \r
193             if (showDistances && (node.dist > 0))\r
194             {\r
195                 nodeLabel = new Format("%-.2f").form(node.dist);\r
196             }\r
197 \r
198             if (showBootstrap)\r
199             {\r
200                 if (showDistances)\r
201                 {\r
202                     nodeLabel = nodeLabel + " : ";\r
203                 }\r
204 \r
205                 nodeLabel = nodeLabel + String.valueOf(node.getBootstrap());\r
206             }\r
207 \r
208             if (!nodeLabel.equals(""))\r
209             {\r
210                 g.drawString(nodeLabel, xstart+2, ypos - 2);\r
211             }\r
212 \r
213             String name = (markPlaceholders && node.isPlaceholder())\r
214                 ? (PLACEHOLDER + node.getName()) : node.getName();\r
215 \r
216             int charWidth = fm.stringWidth(name) + 3;\r
217             int charHeight = font.getSize();\r
218 \r
219             Rectangle rect = new Rectangle(xend+10, ypos-charHeight/2,\r
220                     charWidth, charHeight);\r
221 \r
222             nameHash.put((SequenceI) node.element(), rect);\r
223 \r
224             // Colour selected leaves differently\r
225             SequenceGroup selected = av.getSelectionGroup();\r
226 \r
227             if ((selected != null) &&\r
228                     selected.getSequences(false).contains((SequenceI) node.element()))\r
229             {\r
230                 g.setColor(Color.gray);\r
231 \r
232                 g.fillRect(xend + 10, ypos-charHeight/2, charWidth,\r
233                     charHeight);\r
234                 g.setColor(Color.white);\r
235             }\r
236 \r
237             g.drawString(name, xend + 10, ypos+fm.getDescent());\r
238             g.setColor(Color.black);\r
239         }\r
240         else\r
241         {\r
242             drawNode(g, (SequenceNode) node.left(), chunk, scale, width, offx,\r
243                 offy);\r
244             drawNode(g, (SequenceNode) node.right(), chunk, scale, width, offx,\r
245                 offy);\r
246 \r
247             float height = node.height;\r
248             float dist = node.dist;\r
249 \r
250             int xstart = (int) ((height - dist) * scale) + offx;\r
251             int xend = (int) (height * scale) + offx;\r
252             int ypos = (int) (node.ycount * chunk) + offy;\r
253 \r
254             g.setColor(((SequenceNode) node).color.darker());\r
255 \r
256             // Draw horizontal line\r
257             g.drawLine(xstart, ypos, xend, ypos);\r
258             if (node == highlightNode)\r
259               g.fillRect(xend - 3, ypos - 3, 6, 6);\r
260             else\r
261               g.fillRect(xend - 2, ypos - 2, 4, 4);\r
262 \r
263             int ystart = (int) (((SequenceNode) node.left()).ycount * chunk) +\r
264                 offy;\r
265             int yend = (int) (((SequenceNode) node.right()).ycount * chunk) +\r
266                 offy;\r
267 \r
268             Rectangle pos = new Rectangle(xend - 2, ypos - 2, 5, 5);\r
269             nodeHash.put(node, pos);\r
270 \r
271             g.drawLine((int) (height * scale) + offx, ystart,\r
272                 (int) (height * scale) + offx, yend);\r
273 \r
274             if (showDistances && (node.dist > 0))\r
275             {\r
276                 g.drawString(new Format("%-.2f").form(node.dist).trim(), xstart+2,\r
277                     ypos - 2);\r
278             }\r
279         }\r
280     }\r
281 \r
282     /**\r
283      * DOCUMENT ME!\r
284      *\r
285      * @param x DOCUMENT ME!\r
286      * @param y DOCUMENT ME!\r
287      *\r
288      * @return DOCUMENT ME!\r
289      */\r
290     public Object findElement(int x, int y)\r
291     {\r
292         Enumeration keys = nameHash.keys();\r
293 \r
294         while (keys.hasMoreElements())\r
295         {\r
296             Object ob = keys.nextElement();\r
297             Rectangle rect = (Rectangle) nameHash.get(ob);\r
298 \r
299             if ((x >= rect.x) && (x <= (rect.x + rect.width)) && (y >= rect.y) &&\r
300                     (y <= (rect.y + rect.height)))\r
301             {\r
302                 return ob;\r
303             }\r
304         }\r
305 \r
306         keys = nodeHash.keys();\r
307 \r
308         while (keys.hasMoreElements())\r
309         {\r
310             Object ob = keys.nextElement();\r
311             Rectangle rect = (Rectangle) nodeHash.get(ob);\r
312 \r
313             if ((x >= rect.x) && (x <= (rect.x + rect.width)) && (y >= rect.y) &&\r
314                     (y <= (rect.y + rect.height)))\r
315             {\r
316                 return ob;\r
317             }\r
318         }\r
319 \r
320         return null;\r
321     }\r
322 \r
323     /**\r
324      * DOCUMENT ME!\r
325      *\r
326      * @param pickBox DOCUMENT ME!\r
327      */\r
328     public void pickNodes(Rectangle pickBox)\r
329     {\r
330         int width = getWidth();\r
331         int height = getHeight();\r
332 \r
333         SequenceNode top = tree.getTopNode();\r
334 \r
335         float wscale = (float) ((width * .8) - (offx * 2)) / tree.getMaxHeight();\r
336 \r
337         if (top.count == 0)\r
338         {\r
339             top.count = ((SequenceNode) top.left()).count +\r
340                 ((SequenceNode) top.right()).count;\r
341         }\r
342 \r
343         float chunk = (float) (height - (offy)) / top.count;\r
344 \r
345         pickNode(pickBox, top, chunk, wscale, width, offx, offy);\r
346     }\r
347 \r
348     /**\r
349      * DOCUMENT ME!\r
350      *\r
351      * @param pickBox DOCUMENT ME!\r
352      * @param node DOCUMENT ME!\r
353      * @param chunk DOCUMENT ME!\r
354      * @param scale DOCUMENT ME!\r
355      * @param width DOCUMENT ME!\r
356      * @param offx DOCUMENT ME!\r
357      * @param offy DOCUMENT ME!\r
358      */\r
359     public void pickNode(Rectangle pickBox, SequenceNode node, float chunk,\r
360         float scale, int width, int offx, int offy)\r
361     {\r
362         if (node == null)\r
363         {\r
364             return;\r
365         }\r
366 \r
367         if ((node.left() == null) && (node.right() == null))\r
368         {\r
369             float height = node.height;\r
370             float dist = node.dist;\r
371 \r
372             int xstart = (int) ((height - dist) * scale) + offx;\r
373             int xend = (int) (height * scale) + offx;\r
374 \r
375             int ypos = (int) (node.ycount * chunk) + offy;\r
376 \r
377             if (pickBox.contains(new Point(xend, ypos)))\r
378             {\r
379                 if (node.element() instanceof SequenceI)\r
380                 {\r
381                     SequenceI seq = (SequenceI) node.element();\r
382                     SequenceGroup sg = av.getSelectionGroup();\r
383 \r
384                     if (sg != null)\r
385                     {\r
386                         sg.addOrRemove(seq, true);\r
387                     }\r
388                 }\r
389             }\r
390         }\r
391         else\r
392         {\r
393             pickNode(pickBox, (SequenceNode) node.left(), chunk, scale, width,\r
394                 offx, offy);\r
395             pickNode(pickBox, (SequenceNode) node.right(), chunk, scale, width,\r
396                 offx, offy);\r
397         }\r
398     }\r
399 \r
400     /**\r
401      * DOCUMENT ME!\r
402      *\r
403      * @param node DOCUMENT ME!\r
404      * @param c DOCUMENT ME!\r
405      */\r
406     public void setColor(SequenceNode node, Color c)\r
407     {\r
408         if (node == null)\r
409         {\r
410             return;\r
411         }\r
412 \r
413         if ((node.left() == null) && (node.right() == null))\r
414         {\r
415             node.color = c;\r
416 \r
417             if (node.element() instanceof SequenceI)\r
418             {\r
419                 ((SequenceI) node.element()).setColor(c);\r
420             }\r
421         }\r
422         else\r
423         {\r
424             node.color = c;\r
425             setColor((SequenceNode) node.left(), c);\r
426             setColor((SequenceNode) node.right(), c);\r
427         }\r
428     }\r
429 \r
430     /**\r
431      * DOCUMENT ME!\r
432      */\r
433     void startPrinting()\r
434     {\r
435         Thread thread = new Thread(this);\r
436         thread.start();\r
437     }\r
438 \r
439     // put printing in a thread to avoid painting problems\r
440     public void run()\r
441     {\r
442         PrinterJob printJob = PrinterJob.getPrinterJob();\r
443         PageFormat pf = printJob.pageDialog(printJob.defaultPage());\r
444 \r
445         printJob.setPrintable(this, pf);\r
446 \r
447         if (printJob.printDialog())\r
448         {\r
449             try\r
450             {\r
451                 printJob.print();\r
452             }\r
453             catch (Exception PrintException)\r
454             {\r
455                 PrintException.printStackTrace();\r
456             }\r
457         }\r
458     }\r
459 \r
460     /**\r
461      * DOCUMENT ME!\r
462      *\r
463      * @param pg DOCUMENT ME!\r
464      * @param pf DOCUMENT ME!\r
465      * @param pi DOCUMENT ME!\r
466      *\r
467      * @return DOCUMENT ME!\r
468      *\r
469      * @throws PrinterException DOCUMENT ME!\r
470      */\r
471     public int print(Graphics pg, PageFormat pf, int pi)\r
472         throws PrinterException\r
473     {\r
474         pg.setFont(font);\r
475         pg.translate((int) pf.getImageableX(), (int) pf.getImageableY());\r
476 \r
477         int pwidth = (int) pf.getImageableWidth();\r
478         int pheight = (int) pf.getImageableHeight();\r
479 \r
480         int noPages = getHeight() / pheight;\r
481 \r
482         if (pi > noPages)\r
483         {\r
484             return Printable.NO_SUCH_PAGE;\r
485         }\r
486 \r
487         if (pwidth > getWidth())\r
488         {\r
489             pwidth = getWidth();\r
490         }\r
491 \r
492         if (fitToWindow)\r
493         {\r
494             if (pheight > getHeight())\r
495             {\r
496                 pheight = getHeight();\r
497             }\r
498 \r
499             noPages = 0;\r
500         }\r
501         else\r
502         {\r
503             FontMetrics fm = pg.getFontMetrics(font);\r
504             int height = fm.getHeight() * nameHash.size();\r
505             pg.translate(0, -pi * pheight);\r
506             pg.setClip(0, pi * pheight, pwidth, (pi * pheight) + pheight);\r
507 \r
508             // translate number of pages,\r
509             // height is screen size as this is the\r
510             // non overlapping text size\r
511             pheight = height;\r
512         }\r
513 \r
514         draw(pg, pwidth, pheight);\r
515 \r
516         return Printable.PAGE_EXISTS;\r
517     }\r
518 \r
519     /**\r
520      * DOCUMENT ME!\r
521      *\r
522      * @param g DOCUMENT ME!\r
523      */\r
524     public void paintComponent(Graphics g)\r
525     {\r
526         super.paintComponent(g);\r
527         g.setFont(font);\r
528 \r
529         if(tree==null)\r
530         {\r
531           g.drawString("Calculating tree....", 20, getHeight()/2);\r
532         }\r
533         else\r
534         {\r
535           fm = g.getFontMetrics(font);\r
536 \r
537           if (nameHash.size() == 0)\r
538           {\r
539             repaint();\r
540           }\r
541 \r
542           if (fitToWindow ||\r
543               (!fitToWindow &&\r
544                (scrollPane.getHeight() > ( (fm.getHeight() * nameHash.size()) +\r
545                                           offy))))\r
546           {\r
547             draw(g, scrollPane.getWidth(), scrollPane.getHeight());\r
548             setPreferredSize(null);\r
549           }\r
550           else\r
551           {\r
552             setPreferredSize(new Dimension(scrollPane.getWidth(),\r
553                                            fm.getHeight() * nameHash.size()));\r
554             draw(g, scrollPane.getWidth(), fm.getHeight() * nameHash.size());\r
555           }\r
556 \r
557           scrollPane.revalidate();\r
558         }\r
559     }\r
560 \r
561 \r
562     /**\r
563      * DOCUMENT ME!\r
564      *\r
565      * @param fontSize DOCUMENT ME!\r
566      */\r
567     public void setFont(Font font)\r
568     {\r
569         this.font = font;\r
570         repaint();\r
571     }\r
572 \r
573     /**\r
574      * DOCUMENT ME!\r
575      *\r
576      * @param g1 DOCUMENT ME!\r
577      * @param width DOCUMENT ME!\r
578      * @param height DOCUMENT ME!\r
579      */\r
580     public void draw(Graphics g1, int width, int height)\r
581     {\r
582         Graphics2D g2 = (Graphics2D) g1;\r
583         g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
584             RenderingHints.VALUE_ANTIALIAS_ON);\r
585         g2.setColor(Color.white);\r
586         g2.fillRect(0, 0, width, height);\r
587 \r
588         g2.setFont(font);\r
589 \r
590         offy = font.getSize()+10;\r
591 \r
592         fm = g2.getFontMetrics(font);\r
593 \r
594         labelLength = fm.stringWidth(longestName) + 20; //20 allows for scrollbar\r
595 \r
596         float wscale = (float) (width - labelLength - (offx * 2)) / tree.getMaxHeight();\r
597 \r
598         SequenceNode top = tree.getTopNode();\r
599 \r
600         if (top.count == 0)\r
601         {\r
602             top.count = ((SequenceNode) top.left()).count +\r
603                 ((SequenceNode) top.right()).count;\r
604         }\r
605 \r
606         float chunk = (float) (height - (offy)) / top.count;\r
607 \r
608         drawNode(g2, tree.getTopNode(), chunk, wscale, width, offx, offy);\r
609 \r
610         if (threshold != 0)\r
611         {\r
612             if (av.getCurrentTree() == tree)\r
613             {\r
614                 g2.setColor(Color.red);\r
615             }\r
616             else\r
617             {\r
618                 g2.setColor(Color.gray);\r
619             }\r
620 \r
621             int x = (int) ((threshold * (float) (getWidth() - labelLength -\r
622                 (2 * offx))) + offx);\r
623 \r
624             g2.drawLine(x, 0, x, getHeight());\r
625         }\r
626     }\r
627 \r
628     /**\r
629      * DOCUMENT ME!\r
630      *\r
631      * @param e DOCUMENT ME!\r
632      */\r
633     public void mouseReleased(MouseEvent e)\r
634     {\r
635     }\r
636 \r
637     /**\r
638      * DOCUMENT ME!\r
639      *\r
640      * @param e DOCUMENT ME!\r
641      */\r
642     public void mouseEntered(MouseEvent e)\r
643     {\r
644     }\r
645 \r
646     /**\r
647      * DOCUMENT ME!\r
648      *\r
649      * @param e DOCUMENT ME!\r
650      */\r
651     public void mouseExited(MouseEvent e)\r
652     {\r
653     }\r
654 \r
655     /**\r
656      * DOCUMENT ME!\r
657      *\r
658      * @param e DOCUMENT ME!\r
659      */\r
660     public void mouseClicked(MouseEvent evt)\r
661     {\r
662       if(highlightNode!=null)\r
663       {\r
664         if(evt.getClickCount()>1)\r
665         {\r
666           tree.swapNodes(highlightNode);\r
667           tree.reCount(tree.getTopNode());\r
668           tree.findHeight(tree.getTopNode());\r
669         }\r
670         else\r
671         {\r
672           Vector leaves = new Vector();\r
673           tree.findLeaves(highlightNode, leaves);\r
674 \r
675           for (int i = 0; i < leaves.size(); i++)\r
676           {\r
677             SequenceI seq =\r
678                 (SequenceI) ( (SequenceNode) leaves.elementAt(i)).element();\r
679             treeSelectionChanged(seq);\r
680           }\r
681         }\r
682 \r
683         PaintRefresher.Refresh(this, av.alignment);\r
684         repaint();\r
685       }\r
686     }\r
687 \r
688 \r
689 \r
690     public void mouseMoved(MouseEvent evt)\r
691     {\r
692       av.setCurrentTree(tree);\r
693 \r
694       Object ob = findElement(evt.getX(), evt.getY());\r
695 \r
696       if (ob instanceof SequenceNode)\r
697       {\r
698         highlightNode = (SequenceNode) ob;\r
699         repaint();\r
700       }\r
701       else\r
702       {\r
703         if (highlightNode != null)\r
704         {\r
705           highlightNode = null;\r
706           repaint();\r
707         }\r
708       }\r
709   }\r
710 \r
711     public void mouseDragged(MouseEvent ect)\r
712     {}\r
713 \r
714     /**\r
715      * DOCUMENT ME!\r
716      *\r
717      * @param e DOCUMENT ME!\r
718      */\r
719     public void mousePressed(MouseEvent e)\r
720     {\r
721         av.setCurrentTree(tree);\r
722 \r
723         int x = e.getX();\r
724         int y = e.getY();\r
725 \r
726         Object ob = findElement(x, y);\r
727 \r
728         if (ob instanceof SequenceI)\r
729         {\r
730           treeSelectionChanged( (Sequence) ob);\r
731           PaintRefresher.Refresh(this, av.alignment);\r
732           repaint();\r
733           return;\r
734         }\r
735         else if( !(ob instanceof SequenceNode) )\r
736         {\r
737             // Find threshold\r
738             if (tree.getMaxHeight() != 0)\r
739             {\r
740                 threshold = (float) (x - offx) / (float) (getWidth() -\r
741                     labelLength - (2 * offx));\r
742 \r
743                 tree.getGroups().removeAllElements();\r
744                 tree.groupNodes(tree.getTopNode(), threshold);\r
745                 setColor(tree.getTopNode(), Color.black);\r
746 \r
747                 av.setSelectionGroup(null);\r
748                 av.alignment.deleteAllGroups();\r
749 \r
750                 colourGroups();\r
751               }\r
752 \r
753               PaintRefresher.Refresh(this, av.alignment);\r
754               repaint();\r
755         }\r
756 \r
757 \r
758     }\r
759 \r
760     void colourGroups()\r
761     {\r
762       for (int i = 0; i < tree.getGroups().size(); i++)\r
763       {\r
764         Color col = new Color( (int) (Math.random() * 255),\r
765                               (int) (Math.random() * 255),\r
766                               (int) (Math.random() * 255));\r
767         setColor( (SequenceNode) tree.getGroups().elementAt(i),\r
768                  col.brighter());\r
769 \r
770         Vector l = tree.findLeaves( (SequenceNode) tree.getGroups()\r
771                                    .elementAt(i),\r
772                                    new Vector());\r
773 \r
774         Vector sequences = new Vector();\r
775 \r
776         for (int j = 0; j < l.size(); j++)\r
777         {\r
778           SequenceI s1 = (SequenceI) ( (SequenceNode) l.elementAt(j)).element();\r
779 \r
780           if (!sequences.contains(s1))\r
781           {\r
782             sequences.addElement(s1);\r
783           }\r
784         }\r
785 \r
786         ColourSchemeI cs = null;\r
787 \r
788         if (av.getGlobalColourScheme() != null)\r
789         {\r
790           if (av.getGlobalColourScheme() instanceof UserColourScheme)\r
791           {\r
792             cs = new UserColourScheme(\r
793                 ( (UserColourScheme) av.getGlobalColourScheme()).getColours());\r
794 \r
795           }\r
796           else\r
797             cs = ColourSchemeProperty.getColour(sequences,\r
798                                                 av.alignment.getWidth(),\r
799                                                 ColourSchemeProperty.\r
800                                                 getColourName(\r
801                                                     av.getGlobalColourScheme()));\r
802 \r
803           cs.setThreshold(av.getGlobalColourScheme().getThreshold(),\r
804                           av.getIgnoreGapsConsensus());\r
805         }\r
806 \r
807         SequenceGroup sg = new SequenceGroup(sequences,\r
808                                              "TreeGroup", cs, true, true, false,\r
809                                              0,\r
810                                              av.alignment.getWidth() - 1);\r
811 \r
812         if (av.getGlobalColourScheme() != null\r
813             && av.getGlobalColourScheme().conservationApplied())\r
814         {\r
815           Conservation c = new Conservation("Group",\r
816                                             ResidueProperties.propHash, 3,\r
817                                             sg.getSequences(false),\r
818                                             sg.getStartRes(), sg.getEndRes());\r
819 \r
820           c.calculate();\r
821           c.verdict(false, av.ConsPercGaps);\r
822           sg.cs.setConservation(c);\r
823         }\r
824 \r
825         av.alignment.addGroup(sg);\r
826       }\r
827 \r
828     }\r
829 \r
830     /**\r
831      * DOCUMENT ME!\r
832      *\r
833      * @param state DOCUMENT ME!\r
834      */\r
835     public void setShowDistances(boolean state)\r
836     {\r
837         this.showDistances = state;\r
838         repaint();\r
839     }\r
840 \r
841     /**\r
842      * DOCUMENT ME!\r
843      *\r
844      * @param state DOCUMENT ME!\r
845      */\r
846     public void setShowBootstrap(boolean state)\r
847     {\r
848         this.showBootstrap = state;\r
849         repaint();\r
850     }\r
851 \r
852     /**\r
853      * DOCUMENT ME!\r
854      *\r
855      * @param state DOCUMENT ME!\r
856      */\r
857     public void setMarkPlaceholders(boolean state)\r
858     {\r
859         this.markPlaceholders = state;\r
860         repaint();\r
861     }\r
862 }\r