1628f58d1c911e86b752e51252897843b2c850e4
[jalview.git] / src / jalview / gui / TreeCanvas.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 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\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     //RubberbandRectangle rubberband;\r
65     Vector listeners;\r
66     Hashtable nameHash = new Hashtable();\r
67     Hashtable nodeHash = new Hashtable();\r
68 \r
69     /**\r
70      * Creates a new TreeCanvas object.\r
71      *\r
72      * @param av DOCUMENT ME!\r
73      * @param tree DOCUMENT ME!\r
74      * @param scroller DOCUMENT ME!\r
75      * @param label DOCUMENT ME!\r
76      */\r
77     public TreeCanvas(AlignViewport av, JScrollPane scroller)\r
78     {\r
79         this.av = av;\r
80         font = av.getFont();\r
81         scrollPane = scroller;\r
82         addMouseListener(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(Sequence 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         PaintRefresher.Refresh(this, av.alignment);\r
106         repaint();\r
107     }\r
108 \r
109     /**\r
110      * DOCUMENT ME!\r
111      *\r
112      * @param tree DOCUMENT ME!\r
113      */\r
114     public void setTree(NJTree tree)\r
115     {\r
116         this.tree = tree;\r
117         tree.findHeight(tree.getTopNode());\r
118 \r
119         // Now have to calculate longest name based on the leaves\r
120         Vector leaves = tree.findLeaves(tree.getTopNode(), new Vector());\r
121         boolean has_placeholders = false;\r
122         longestName = "";\r
123 \r
124         for (int i = 0; i < leaves.size(); i++)\r
125         {\r
126           SequenceNode lf = (SequenceNode) leaves.elementAt(i);\r
127 \r
128           if (lf.isPlaceholder())\r
129           {\r
130             has_placeholders = true;\r
131           }\r
132 \r
133           if (longestName.length() < ( (Sequence) lf.element()).getName()\r
134               .length())\r
135           {\r
136             longestName = TreeCanvas.PLACEHOLDER +\r
137                 ( (Sequence) lf.element()).getName();\r
138           }\r
139         }\r
140 \r
141         setMarkPlaceholders(has_placeholders);\r
142     }\r
143 \r
144     /**\r
145      * DOCUMENT ME!\r
146      *\r
147      * @param g DOCUMENT ME!\r
148      * @param node DOCUMENT ME!\r
149      * @param chunk DOCUMENT ME!\r
150      * @param scale DOCUMENT ME!\r
151      * @param width DOCUMENT ME!\r
152      * @param offx DOCUMENT ME!\r
153      * @param offy DOCUMENT ME!\r
154      */\r
155     public void drawNode(Graphics g, SequenceNode node, float chunk,\r
156         float scale, int width, int offx, int offy)\r
157     {\r
158         if (node == null)\r
159         {\r
160             return;\r
161         }\r
162 \r
163         if ((node.left() == null) && (node.right() == null))\r
164         {\r
165             // Drawing leaf node\r
166             float height = node.height;\r
167             float dist = node.dist;\r
168 \r
169             int xstart = (int) ((height - dist) * scale) + offx;\r
170             int xend = (int) (height * scale) + offx;\r
171 \r
172             int ypos = (int) (node.ycount * chunk) + offy;\r
173 \r
174             if (node.element() instanceof SequenceI)\r
175             {\r
176                 if (((SequenceI) ((SequenceNode) node).element()).getColor() == Color.white)\r
177                 {\r
178                     g.setColor(Color.black);\r
179                 }\r
180                 else\r
181                 {\r
182                     g.setColor(((SequenceI) ((SequenceNode) node).element()).getColor()\r
183                                 .darker());\r
184                 }\r
185             }\r
186             else\r
187             {\r
188                 g.setColor(Color.black);\r
189             }\r
190 \r
191             // Draw horizontal line\r
192             g.drawLine(xstart, ypos, xend, ypos);\r
193 \r
194             String nodeLabel = "";\r
195 \r
196             if (showDistances && (node.dist > 0))\r
197             {\r
198                 nodeLabel = new Format("%-.2f").form(node.dist);\r
199             }\r
200 \r
201             if (showBootstrap)\r
202             {\r
203                 if (showDistances)\r
204                 {\r
205                     nodeLabel = nodeLabel + " : ";\r
206                 }\r
207 \r
208                 nodeLabel = nodeLabel + String.valueOf(node.getBootstrap());\r
209             }\r
210 \r
211             if (!nodeLabel.equals(""))\r
212             {\r
213                 g.drawString(nodeLabel, xstart+2, ypos - 2);\r
214             }\r
215 \r
216             String name = (markPlaceholders && node.isPlaceholder())\r
217                 ? (PLACEHOLDER + node.getName()) : node.getName();\r
218 \r
219             int charWidth = fm.stringWidth(name) + 3;\r
220             int charHeight = font.getSize();\r
221 \r
222             Rectangle rect = new Rectangle(xend+10, ypos-charHeight/2,\r
223                     charWidth, charHeight);\r
224 \r
225             nameHash.put((SequenceI) node.element(), rect);\r
226 \r
227             // Colour selected leaves differently\r
228             SequenceGroup selected = av.getSelectionGroup();\r
229 \r
230             if ((selected != null) &&\r
231                     selected.getSequences(false).contains((SequenceI) node.element()))\r
232             {\r
233                 g.setColor(Color.gray);\r
234 \r
235                 g.fillRect(xend + 10, ypos-charHeight/2, charWidth,\r
236                     charHeight);\r
237                 g.setColor(Color.white);\r
238             }\r
239 \r
240             g.drawString(name, xend + 10, ypos+fm.getDescent());\r
241             g.setColor(Color.black);\r
242         }\r
243         else\r
244         {\r
245             drawNode(g, (SequenceNode) node.left(), chunk, scale, width, offx,\r
246                 offy);\r
247             drawNode(g, (SequenceNode) node.right(), chunk, scale, width, offx,\r
248                 offy);\r
249 \r
250             float height = node.height;\r
251             float dist = node.dist;\r
252 \r
253             int xstart = (int) ((height - dist) * scale) + offx;\r
254             int xend = (int) (height * scale) + offx;\r
255             int ypos = (int) (node.ycount * chunk) + offy;\r
256 \r
257             g.setColor(((SequenceNode) node).color.darker());\r
258 \r
259             // Draw horizontal line\r
260             g.drawLine(xstart, ypos, xend, ypos);\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 e)\r
661     {\r
662     }\r
663 \r
664     /**\r
665      * DOCUMENT ME!\r
666      *\r
667      * @param e DOCUMENT ME!\r
668      */\r
669     public void mousePressed(MouseEvent e)\r
670     {\r
671         av.setCurrentTree(tree);\r
672 \r
673         int x = e.getX();\r
674         int y = e.getY();\r
675 \r
676         Object ob = findElement(x, y);\r
677 \r
678         if (ob instanceof SequenceI)\r
679         {\r
680             TreeSelectionChanged((Sequence) ob);\r
681             repaint();\r
682 \r
683             return;\r
684         }\r
685         else if (ob instanceof SequenceNode)\r
686         {\r
687             SequenceNode tmpnode = (SequenceNode) ob;\r
688             tree.swapNodes(tmpnode);\r
689             tree.reCount(tree.getTopNode());\r
690             tree.findHeight(tree.getTopNode());\r
691         }\r
692         else\r
693         {\r
694             // Find threshold\r
695             if (tree.getMaxHeight() != 0)\r
696             {\r
697                 threshold = (float) (x - offx) / (float) (getWidth() -\r
698                     labelLength - (2 * offx));\r
699 \r
700                 tree.getGroups().removeAllElements();\r
701                 tree.groupNodes(tree.getTopNode(), threshold);\r
702                 setColor(tree.getTopNode(), Color.black);\r
703 \r
704                 av.setSelectionGroup(null);\r
705                 av.alignment.deleteAllGroups();\r
706 \r
707                 for (int i = 0; i < tree.getGroups().size(); i++)\r
708                 {\r
709                     Color col = new Color((int) (Math.random() * 255),\r
710                             (int) (Math.random() * 255),\r
711                             (int) (Math.random() * 255));\r
712                     setColor((SequenceNode) tree.getGroups().elementAt(i),\r
713                         col.brighter());\r
714 \r
715                     Vector l = tree.findLeaves((SequenceNode) tree.getGroups()\r
716                                                                   .elementAt(i),\r
717                             new Vector());\r
718 \r
719                     Vector sequences = new Vector();\r
720 \r
721                     for (int j = 0; j < l.size(); j++)\r
722                     {\r
723                         SequenceI s1 = (SequenceI) ((SequenceNode) l.elementAt(j)).element();\r
724 \r
725                         if (!sequences.contains(s1))\r
726                         {\r
727                             sequences.addElement(s1);\r
728                         }\r
729                     }\r
730 \r
731                     ColourSchemeI cs = null;\r
732 \r
733                     if (av.getGlobalColourScheme() != null)\r
734                     {\r
735                       if (av.getGlobalColourScheme() instanceof UserColourScheme)\r
736                       {\r
737                         cs = new UserColourScheme(\r
738                             ( (UserColourScheme) av.getGlobalColourScheme()).getColours());\r
739 \r
740                       }\r
741                       else\r
742                         cs = ColourSchemeProperty.getColour(sequences,\r
743                                                             av.alignment.getWidth(),\r
744                                                             ColourSchemeProperty.getColourName(\r
745                                                                 av.getGlobalColourScheme()));\r
746 \r
747                         cs.setThreshold(av.getGlobalColourScheme().getThreshold(),\r
748                                                              av.getIgnoreGapsConsensus());\r
749                     }\r
750 \r
751 \r
752                     SequenceGroup sg = new SequenceGroup(sequences,\r
753                             "TreeGroup", cs, true, true, false, 0,\r
754                             av.alignment.getWidth()-1);\r
755 \r
756 \r
757                     if (  av.getGlobalColourScheme()!=null\r
758                        && av.getGlobalColourScheme().conservationApplied())\r
759                     {\r
760                         Conservation c = new Conservation("Group",\r
761                                 ResidueProperties.propHash, 3,\r
762                                 sg.getSequences(false),\r
763                                 sg.getStartRes(), sg.getEndRes());\r
764 \r
765                         c.calculate();\r
766                         c.verdict(false, av.ConsPercGaps);\r
767                         sg.cs.setConservation(c);\r
768                     }\r
769 \r
770                     av.alignment.addGroup(sg);\r
771                 }\r
772             }\r
773         }\r
774 \r
775         PaintRefresher.Refresh(this, av.alignment);\r
776         repaint();\r
777     }\r
778 \r
779     /**\r
780      * DOCUMENT ME!\r
781      *\r
782      * @param state DOCUMENT ME!\r
783      */\r
784     public void setShowDistances(boolean state)\r
785     {\r
786         this.showDistances = state;\r
787         repaint();\r
788     }\r
789 \r
790     /**\r
791      * DOCUMENT ME!\r
792      *\r
793      * @param state DOCUMENT ME!\r
794      */\r
795     public void setShowBootstrap(boolean state)\r
796     {\r
797         this.showBootstrap = state;\r
798         repaint();\r
799     }\r
800 \r
801     /**\r
802      * DOCUMENT ME!\r
803      *\r
804      * @param state DOCUMENT ME!\r
805      */\r
806     public void setMarkPlaceholders(boolean state)\r
807     {\r
808         this.markPlaceholders = state;\r
809         repaint();\r
810     }\r
811 }\r