Sequence colour in viewport
[jalview.git] / src / jalview / gui / TreeCanvas.java
index e923792..57e652c 100755 (executable)
@@ -1,6 +1,6 @@
 /*\r
  * Jalview - A Sequence Alignment Editor and Viewer\r
- * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
+ * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
  *\r
  * This program is free software; you can redistribute it and/or\r
  * modify it under the terms of the GNU General Public License\r
@@ -42,29 +42,29 @@ import javax.swing.*;
  * @version $Revision$\r
  */\r
 public class TreeCanvas extends JPanel implements MouseListener, Runnable,\r
-    Printable\r
+    Printable, MouseMotionListener\r
 {\r
     /** DOCUMENT ME!! */\r
     public static final String PLACEHOLDER = " * ";\r
     NJTree tree;\r
     JScrollPane scrollPane;\r
     AlignViewport av;\r
+    AlignmentPanel ap;\r
     Font font;\r
-    int fontSize = 12;\r
+    FontMetrics fm;\r
     boolean fitToWindow = true;\r
     boolean showDistances = false;\r
     boolean showBootstrap = false;\r
     boolean markPlaceholders = false;\r
     int offx = 20;\r
-    int offy = 20;\r
+    int offy;\r
     float threshold;\r
     String longestName;\r
     int labelLength = -1;\r
 \r
-    //RubberbandRectangle rubberband;\r
-    Vector listeners;\r
     Hashtable nameHash = new Hashtable();\r
     Hashtable nodeHash = new Hashtable();\r
+    SequenceNode highlightNode;\r
 \r
     /**\r
      * Creates a new TreeCanvas object.\r
@@ -74,25 +74,25 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
      * @param scroller DOCUMENT ME!\r
      * @param label DOCUMENT ME!\r
      */\r
-    public TreeCanvas(AlignViewport av, NJTree tree, JScrollPane scroller,\r
-        String label)\r
+    public TreeCanvas(AlignmentPanel ap, JScrollPane scroller)\r
     {\r
-        this.av = av;\r
-        this.tree = tree;\r
+        this.av = ap.av;\r
+        this.ap = ap;\r
+        font = av.getFont();\r
         scrollPane = scroller;\r
         addMouseListener(this);\r
-        tree.findHeight(tree.getTopNode());\r
-        longestName = label;\r
-\r
-        PaintRefresher.Register(this, av.alignment);\r
+        addMouseMotionListener(this);\r
+        PaintRefresher.Register(this, ap.av.getSequenceSetId());\r
+        ToolTipManager.sharedInstance().registerComponent(this);\r
     }\r
 \r
+\r
     /**\r
      * DOCUMENT ME!\r
      *\r
      * @param sequence DOCUMENT ME!\r
      */\r
-    public void TreeSelectionChanged(Sequence sequence)\r
+    public void treeSelectionChanged(SequenceI sequence)\r
     {\r
         SequenceGroup selected = av.getSelectionGroup();\r
 \r
@@ -102,11 +102,8 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
             av.setSelectionGroup(selected);\r
         }\r
 \r
-        selected.setEndRes(av.alignment.getWidth());\r
+        selected.setEndRes(av.alignment.getWidth()-1);\r
         selected.addOrRemove(sequence, true);\r
-\r
-        PaintRefresher.Refresh(this, av.alignment);\r
-        repaint();\r
     }\r
 \r
     /**\r
@@ -118,6 +115,30 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     {\r
         this.tree = tree;\r
         tree.findHeight(tree.getTopNode());\r
+\r
+        // Now have to calculate longest name based on the leaves\r
+        Vector leaves = tree.findLeaves(tree.getTopNode(), new Vector());\r
+        boolean has_placeholders = false;\r
+        longestName = "";\r
+\r
+        for (int i = 0; i < leaves.size(); i++)\r
+        {\r
+          SequenceNode lf = (SequenceNode) leaves.elementAt(i);\r
+\r
+          if (lf.isPlaceholder())\r
+          {\r
+            has_placeholders = true;\r
+          }\r
+\r
+          if (longestName.length() < ( (Sequence) lf.element()).getName()\r
+              .length())\r
+          {\r
+            longestName = TreeCanvas.PLACEHOLDER +\r
+                ( (Sequence) lf.element()).getName();\r
+          }\r
+        }\r
+\r
+        setMarkPlaceholders(has_placeholders);\r
     }\r
 \r
     /**\r
@@ -152,14 +173,15 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 \r
             if (node.element() instanceof SequenceI)\r
             {\r
-                if (((SequenceI) ((SequenceNode) node).element()).getColor() == Color.white)\r
+              SequenceI seq = (SequenceI)((SequenceNode) node).element();\r
+\r
+                if (av.getSequenceColour(seq) == Color.white)\r
                 {\r
                     g.setColor(Color.black);\r
                 }\r
                 else\r
                 {\r
-                    g.setColor(((SequenceI) ((SequenceNode) node).element()).getColor()\r
-                                .darker());\r
+                    g.setColor(av.getSequenceColour(seq).darker());\r
                 }\r
             }\r
             else\r
@@ -174,7 +196,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 \r
             if (showDistances && (node.dist > 0))\r
             {\r
-                nodeLabel = new Format("%5.2f").form(node.dist);\r
+                nodeLabel = new Format("%-.2f").form(node.dist);\r
             }\r
 \r
             if (showBootstrap)\r
@@ -189,16 +211,16 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 \r
             if (!nodeLabel.equals(""))\r
             {\r
-                g.drawString(nodeLabel, xstart, ypos - 10);\r
+                g.drawString(nodeLabel, xstart+2, ypos - 2);\r
             }\r
 \r
             String name = (markPlaceholders && node.isPlaceholder())\r
                 ? (PLACEHOLDER + node.getName()) : node.getName();\r
-            FontMetrics fm = g.getFontMetrics(font);\r
+\r
             int charWidth = fm.stringWidth(name) + 3;\r
-            int charHeight = fm.getHeight();\r
+            int charHeight = font.getSize();\r
 \r
-            Rectangle rect = new Rectangle(xend + 20, ypos - charHeight,\r
+            Rectangle rect = new Rectangle(xend+10, ypos-charHeight/2,\r
                     charWidth, charHeight);\r
 \r
             nameHash.put((SequenceI) node.element(), rect);\r
@@ -207,16 +229,16 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
             SequenceGroup selected = av.getSelectionGroup();\r
 \r
             if ((selected != null) &&\r
-                    selected.sequences.contains((SequenceI) node.element()))\r
+                    selected.getSequences(false).contains((SequenceI) node.element()))\r
             {\r
                 g.setColor(Color.gray);\r
 \r
-                g.fillRect(xend + 10, ypos - charHeight + 3, charWidth,\r
+                g.fillRect(xend + 10, ypos-charHeight/2, charWidth,\r
                     charHeight);\r
                 g.setColor(Color.white);\r
             }\r
 \r
-            g.drawString(name, xend + 10, ypos);\r
+            g.drawString(name, xend + 10, ypos+fm.getDescent());\r
             g.setColor(Color.black);\r
         }\r
         else\r
@@ -237,7 +259,10 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 \r
             // Draw horizontal line\r
             g.drawLine(xstart, ypos, xend, ypos);\r
-            g.fillRect(xend - 2, ypos - 2, 4, 4);\r
+            if (node == highlightNode)\r
+              g.fillRect(xend - 3, ypos - 3, 6, 6);\r
+            else\r
+              g.fillRect(xend - 2, ypos - 2, 4, 4);\r
 \r
             int ystart = (int) (((SequenceNode) node.left()).ycount * chunk) +\r
                 offy;\r
@@ -252,8 +277,8 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 \r
             if (showDistances && (node.dist > 0))\r
             {\r
-                g.drawString(new Format("%5.2f").form(node.dist), xstart,\r
-                    ypos - 5);\r
+                g.drawString(new Format("%-.2f").form(node.dist).trim(), xstart+2,\r
+                    ypos - 2);\r
             }\r
         }\r
     }\r
@@ -319,7 +344,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
                 ((SequenceNode) top.right()).count;\r
         }\r
 \r
-        float chunk = (float) (height - (offy * 2)) / top.count;\r
+        float chunk = (float) (height - (offy)) / top.count;\r
 \r
         pickNode(pickBox, top, chunk, wscale, width, offx, offy);\r
     }\r
@@ -395,7 +420,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 \r
             if (node.element() instanceof SequenceI)\r
             {\r
-                ((SequenceI) node.element()).setColor(c);\r
+              av.setSequenceColour((SequenceI) node.element(), c);\r
             }\r
         }\r
         else\r
@@ -503,52 +528,49 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     public void paintComponent(Graphics g)\r
     {\r
         super.paintComponent(g);\r
-        font = new Font("Verdana", Font.PLAIN, fontSize);\r
         g.setFont(font);\r
 \r
-        FontMetrics fm = g.getFontMetrics(font);\r
-\r
-        if (nameHash.size() == 0)\r
+        if(tree==null)\r
         {\r
-            repaint();\r
+          g.drawString("Calculating tree....", 20, getHeight()/2);\r
         }\r
-\r
-        if (fitToWindow ||\r
-                (!fitToWindow &&\r
-                (scrollPane.getHeight() > ((fm.getHeight() * nameHash.size()) +\r
-                offy))))\r
+        else\r
         {\r
+          fm = g.getFontMetrics(font);\r
+\r
+          if (nameHash.size() == 0)\r
+          {\r
+            repaint();\r
+          }\r
+\r
+          if (fitToWindow ||\r
+              (!fitToWindow &&\r
+               (scrollPane.getHeight() > ( (fm.getHeight() * nameHash.size()) +\r
+                                          offy))))\r
+          {\r
             draw(g, scrollPane.getWidth(), scrollPane.getHeight());\r
             setPreferredSize(null);\r
-        }\r
-        else\r
-        {\r
+          }\r
+          else\r
+          {\r
             setPreferredSize(new Dimension(scrollPane.getWidth(),\r
-                    fm.getHeight() * nameHash.size()));\r
+                                           fm.getHeight() * nameHash.size()));\r
             draw(g, scrollPane.getWidth(), fm.getHeight() * nameHash.size());\r
-        }\r
+          }\r
 \r
-        scrollPane.revalidate();\r
+          scrollPane.revalidate();\r
+        }\r
     }\r
 \r
-    /**\r
-     * DOCUMENT ME!\r
-     *\r
-     * @return DOCUMENT ME!\r
-     */\r
-    public int getFontSize()\r
-    {\r
-        return fontSize;\r
-    }\r
 \r
     /**\r
      * DOCUMENT ME!\r
      *\r
      * @param fontSize DOCUMENT ME!\r
      */\r
-    public void setFontSize(int fontSize)\r
+    public void setFont(Font font)\r
     {\r
-        this.fontSize = fontSize;\r
+        this.font = font;\r
         repaint();\r
     }\r
 \r
@@ -567,7 +589,13 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
         g2.setColor(Color.white);\r
         g2.fillRect(0, 0, width, height);\r
 \r
-        labelLength = g2.getFontMetrics(font).stringWidth(longestName) + 20; //20 allows for scrollbar\r
+        g2.setFont(font);\r
+\r
+        offy = font.getSize()+10;\r
+\r
+        fm = g2.getFontMetrics(font);\r
+\r
+        labelLength = fm.stringWidth(longestName) + 20; //20 allows for scrollbar\r
 \r
         float wscale = (float) (width - labelLength - (offx * 2)) / tree.getMaxHeight();\r
 \r
@@ -579,7 +607,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
                 ((SequenceNode) top.right()).count;\r
         }\r
 \r
-        float chunk = (float) (height - (offy * 2)) / top.count;\r
+        float chunk = (float) (height - (offy)) / top.count;\r
 \r
         drawNode(g2, tree.getTopNode(), chunk, wscale, width, offx, offy);\r
 \r
@@ -633,10 +661,74 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
      *\r
      * @param e DOCUMENT ME!\r
      */\r
-    public void mouseClicked(MouseEvent e)\r
+    public void mouseClicked(MouseEvent evt)\r
     {\r
+      if(highlightNode!=null)\r
+      {\r
+        if (SwingUtilities.isRightMouseButton(evt))\r
+        {\r
+          Color col = JColorChooser.showDialog(this, "Select Background Colour",\r
+                                               highlightNode.color);\r
+\r
+          setColor(highlightNode, col);\r
+        }\r
+        else\r
+        if(evt.getClickCount()>1)\r
+        {\r
+          tree.swapNodes(highlightNode);\r
+          tree.reCount(tree.getTopNode());\r
+          tree.findHeight(tree.getTopNode());\r
+        }\r
+        else\r
+        {\r
+          Vector leaves = new Vector();\r
+          tree.findLeaves(highlightNode, leaves);\r
+\r
+          for (int i = 0; i < leaves.size(); i++)\r
+          {\r
+            SequenceI seq =\r
+                (SequenceI) ( (SequenceNode) leaves.elementAt(i)).element();\r
+            treeSelectionChanged(seq);\r
+          }\r
+        }\r
+\r
+        PaintRefresher.Refresh(this, av.getSequenceSetId());\r
+        repaint();\r
+      }\r
     }\r
 \r
+\r
+\r
+    public void mouseMoved(MouseEvent evt)\r
+    {\r
+      av.setCurrentTree(tree);\r
+\r
+      Object ob = findElement(evt.getX(), evt.getY());\r
+\r
+      if (ob instanceof SequenceNode)\r
+      {\r
+        highlightNode = (SequenceNode) ob;\r
+        this.setToolTipText(\r
+            "<html>Left click to select leaves"\r
+            + "<br>Double-click to invert leaves"\r
+            + "<br>Right click to change colour");\r
+        repaint();\r
+\r
+      }\r
+      else\r
+      {\r
+        if (highlightNode != null)\r
+        {\r
+          highlightNode = null;\r
+          setToolTipText(null);\r
+          repaint();\r
+        }\r
+      }\r
+  }\r
+\r
+    public void mouseDragged(MouseEvent ect)\r
+    {}\r
+\r
     /**\r
      * DOCUMENT ME!\r
      *\r
@@ -653,19 +745,12 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 \r
         if (ob instanceof SequenceI)\r
         {\r
-            TreeSelectionChanged((Sequence) ob);\r
-            repaint();\r
-\r
-            return;\r
-        }\r
-        else if (ob instanceof SequenceNode)\r
-        {\r
-            SequenceNode tmpnode = (SequenceNode) ob;\r
-            tree.swapNodes(tmpnode);\r
-            tree.reCount(tree.getTopNode());\r
-            tree.findHeight(tree.getTopNode());\r
+          treeSelectionChanged( (Sequence) ob);\r
+          PaintRefresher.Refresh(this, ap.av.getSequenceSetId());\r
+          repaint();\r
+          return;\r
         }\r
-        else\r
+        else if( !(ob instanceof SequenceNode) )\r
         {\r
             // Find threshold\r
             if (tree.getMaxHeight() != 0)\r
@@ -679,63 +764,86 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 \r
                 av.setSelectionGroup(null);\r
                 av.alignment.deleteAllGroups();\r
+                av.sequenceColours.clear();\r
 \r
-                for (int i = 0; i < tree.getGroups().size(); i++)\r
-                {\r
-                    Color col = new Color((int) (Math.random() * 255),\r
-                            (int) (Math.random() * 255),\r
-                            (int) (Math.random() * 255));\r
-                    setColor((SequenceNode) tree.getGroups().elementAt(i),\r
-                        col.brighter());\r
+                colourGroups();\r
+              }\r
 \r
-                    Vector l = tree.findLeaves((SequenceNode) tree.getGroups()\r
-                                                                  .elementAt(i),\r
-                            new Vector());\r
+              PaintRefresher.Refresh(this, ap.av.getSequenceSetId());\r
+              repaint();\r
+        }\r
 \r
-                    Vector sequences = new Vector();\r
 \r
-                    for (int j = 0; j < l.size(); j++)\r
-                    {\r
-                        SequenceI s1 = (SequenceI) ((SequenceNode) l.elementAt(j)).element();\r
+    }\r
 \r
-                        if (!sequences.contains(s1))\r
-                        {\r
-                            sequences.addElement(s1);\r
-                        }\r
-                    }\r
+    void colourGroups()\r
+    {\r
+      for (int i = 0; i < tree.getGroups().size(); i++)\r
+      {\r
+        Color col = new Color( (int) (Math.random() * 255),\r
+                              (int) (Math.random() * 255),\r
+                              (int) (Math.random() * 255));\r
+        setColor( (SequenceNode) tree.getGroups().elementAt(i),\r
+                 col.brighter());\r
 \r
-                    ColourSchemeI cs = ColourSchemeProperty.getColour(sequences,\r
-                            av.alignment.getWidth(),\r
-                            ColourSchemeProperty.getColourName(\r
-                                av.getGlobalColourScheme()));\r
+        Vector l = tree.findLeaves( (SequenceNode) tree.getGroups()\r
+                                   .elementAt(i),\r
+                                   new Vector());\r
 \r
-                    SequenceGroup sg = new SequenceGroup(sequences,\r
-                            "TreeGroup", cs, true, true, false, 0,\r
-                            av.alignment.getWidth());\r
+        Vector sequences = new Vector();\r
 \r
-                    if (sg.cs != null)\r
-                    {\r
-                        sg.cs.setThreshold(25, av.getIgnoreGapsConsensus());\r
-                    }\r
+        for (int j = 0; j < l.size(); j++)\r
+        {\r
+          SequenceI s1 = (SequenceI) ( (SequenceNode) l.elementAt(j)).element();\r
 \r
-                    if (av.getGlobalColourScheme().conservationApplied())\r
-                    {\r
-                        Conservation c = new Conservation("Group",\r
-                                ResidueProperties.propHash, 3, sg.sequences,\r
-                                sg.getStartRes(), sg.getEndRes());\r
+          if (!sequences.contains(s1))\r
+          {\r
+            sequences.addElement(s1);\r
+          }\r
+        }\r
 \r
-                        c.calculate();\r
-                        c.verdict(false, av.ConsPercGaps);\r
-                        sg.cs.setConservation(c);\r
-                    }\r
+        ColourSchemeI cs = null;\r
 \r
-                    av.alignment.addGroup(sg);\r
-                }\r
-            }\r
+        if (av.getGlobalColourScheme() != null)\r
+        {\r
+          if (av.getGlobalColourScheme() instanceof UserColourScheme)\r
+          {\r
+            cs = new UserColourScheme(\r
+                ( (UserColourScheme) av.getGlobalColourScheme()).getColours());\r
+\r
+          }\r
+          else\r
+            cs = ColourSchemeProperty.getColour(sequences,\r
+                                                av.alignment.getWidth(),\r
+                                                ColourSchemeProperty.\r
+                                                getColourName(\r
+                                                    av.getGlobalColourScheme()));\r
+\r
+          cs.setThreshold(av.getGlobalColourScheme().getThreshold(),\r
+                          av.getIgnoreGapsConsensus());\r
         }\r
 \r
-        PaintRefresher.Refresh(this, av.alignment);\r
-        repaint();\r
+        SequenceGroup sg = new SequenceGroup(sequences,\r
+                                             "TreeGroup", cs, true, true, false,\r
+                                             0,\r
+                                             av.alignment.getWidth() - 1);\r
+\r
+        if (av.getGlobalColourScheme() != null\r
+            && av.getGlobalColourScheme().conservationApplied())\r
+        {\r
+          Conservation c = new Conservation("Group",\r
+                                            ResidueProperties.propHash, 3,\r
+                                            sg.getSequences(false),\r
+                                            sg.getStartRes(), sg.getEndRes());\r
+\r
+          c.calculate();\r
+          c.verdict(false, av.ConsPercGaps);\r
+          sg.cs.setConservation(c);\r
+        }\r
+\r
+        av.alignment.addGroup(sg);\r
+      }\r
+\r
     }\r
 \r
     /**\r