JAL-2422 general pull-up/removal of common or unused fields and methods
[jalview.git] / src / MCview / PDBCanvas.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package MCview;
22
23 import jalview.analysis.AlignSeq;
24 import jalview.datamodel.PDBEntry;
25 import jalview.datamodel.SequenceI;
26 import jalview.gui.AlignmentPanel;
27 import jalview.gui.FeatureRenderer;
28 import jalview.gui.SequenceRenderer;
29 import jalview.io.DataSourceType;
30 import jalview.io.StructureFile;
31 import jalview.renderer.seqfeatures.FeatureColourFinder;
32 import jalview.structure.AtomSpec;
33 import jalview.structure.StructureListener;
34 import jalview.structure.StructureMapping;
35 import jalview.structure.StructureSelectionManager;
36
37 import java.awt.Color;
38 import java.awt.Dimension;
39 import java.awt.event.InputEvent;import java.awt.Font;
40 import java.awt.Graphics;
41 import java.awt.Graphics2D;
42 // JBPNote TODO: This class is quite noisy - needs proper log.info/log.debug
43 import java.awt.Image;
44 import java.awt.RenderingHints;
45 import java.awt.event.KeyAdapter;
46 import java.awt.event.KeyEvent;
47 import java.awt.event.MouseEvent;
48 import java.awt.event.MouseListener;
49 import java.awt.event.MouseMotionListener;
50 import java.io.PrintStream;
51 import java.util.List;
52 import java.util.Vector;
53
54 import javax.swing.JPanel;
55 import javax.swing.ToolTipManager;
56
57 public class PDBCanvas extends JPanel
58         implements MouseListener, MouseMotionListener, StructureListener
59 {
60   boolean redrawneeded = true;
61
62   int omx = 0;
63
64   int mx = 0;
65
66   int omy = 0;
67
68   int my = 0;
69
70   public StructureFile pdb;
71
72   PDBEntry pdbentry;
73
74   int bsize;
75
76   Image img;
77
78   Graphics ig;
79
80   Dimension prefsize;
81
82   float[] centre = new float[3];
83
84   float[] width = new float[3];
85
86   float maxwidth;
87
88   float scale;
89
90   String inStr;
91
92   String inType;
93
94   boolean bysequence = true;
95
96   boolean depthcue = true;
97
98   boolean wire = false;
99
100   boolean bymolecule = false;
101
102   boolean zbuffer = true;
103
104   boolean dragging;
105
106   int xstart;
107
108   int xend;
109
110   int ystart;
111
112   int yend;
113
114   int xmid;
115
116   int ymid;
117
118   Font font = new Font("Helvetica", Font.PLAIN, 10);
119
120   jalview.gui.SeqCanvas seqcanvas;
121
122   public SequenceI[] sequence;
123
124   final StringBuffer mappingDetails = new StringBuffer();
125
126   PDBChain mainchain;
127
128   Vector<String> highlightRes;
129
130   boolean pdbAction = false;
131
132   boolean seqColoursReady = false;
133
134   jalview.renderer.seqfeatures.FeatureRenderer fr;
135
136   Color backgroundColour = Color.black;
137
138   AlignmentPanel ap;
139
140   StructureSelectionManager ssm;
141
142   String errorMessage;
143
144   void init(PDBEntry pdbentry, SequenceI[] seq, String[] chains,
145           AlignmentPanel ap, DataSourceType protocol)
146   {
147     this.ap = ap;
148     this.pdbentry = pdbentry;
149     this.sequence = seq;
150
151     ssm = ap.av.getStructureSelectionManager();
152
153     try
154     {
155       pdb = ssm.setMapping(seq, chains, pdbentry.getFile(), protocol,
156               ap.alignFrame);
157
158       if (protocol.equals(jalview.io.DataSourceType.PASTE))
159       {
160         pdbentry.setFile("INLINE" + pdb.getId());
161       }
162
163     } catch (Exception ex)
164     {
165       ex.printStackTrace();
166       return;
167     }
168
169     if (pdb == null)
170     {
171       errorMessage = "Error loading file: " + pdbentry.getId();
172       return;
173     }
174     pdbentry.setId(pdb.getId());
175
176     ssm.addStructureViewerListener(this);
177
178     colourBySequence();
179
180     float max = -10;
181     int maxchain = -1;
182     int pdbstart = 0;
183     int pdbend = 0;
184     int seqstart = 0;
185     int seqend = 0;
186
187     // JUST DEAL WITH ONE SEQUENCE FOR NOW
188     SequenceI sequence = seq[0];
189
190     for (int i = 0; i < pdb.getChains().size(); i++)
191     {
192
193       mappingDetails.append("\n\nPDB Sequence is :\nSequence = "
194               + pdb.getChains().elementAt(i).sequence
195                       .getSequenceAsString());
196       mappingDetails.append("\nNo of residues = "
197               + pdb.getChains().elementAt(i).residues.size() + "\n\n");
198
199       // Now lets compare the sequences to get
200       // the start and end points.
201       // Align the sequence to the pdb
202       AlignSeq as = new AlignSeq(sequence,
203               pdb.getChains().elementAt(i).sequence, "pep");
204       as.calcScoreMatrix();
205       as.traceAlignment();
206       PrintStream ps = new PrintStream(System.out)
207       {
208         @Override
209         public void print(String x)
210         {
211           mappingDetails.append(x);
212         }
213
214         @Override
215         public void println()
216         {
217           mappingDetails.append("\n");
218         }
219       };
220
221       as.printAlignment(ps);
222
223       if (as.maxscore > max)
224       {
225         max = as.maxscore;
226         maxchain = i;
227
228         pdbstart = as.seq2start;
229         pdbend = as.seq2end;
230         seqstart = as.seq1start + sequence.getStart() - 1;
231         seqend = as.seq1end + sequence.getEnd() - 1;
232       }
233
234       mappingDetails.append("\nPDB start/end " + pdbstart + " " + pdbend);
235       mappingDetails.append("\nSEQ start/end " + seqstart + " " + seqend);
236     }
237
238     mainchain = pdb.getChains().elementAt(maxchain);
239
240     mainchain.pdbstart = pdbstart;
241     mainchain.pdbend = pdbend;
242     mainchain.seqstart = seqstart;
243     mainchain.seqend = seqend;
244     mainchain.isVisible = true;
245
246     this.pdb = pdb;
247     this.prefsize = new Dimension(getSize().width, getSize().height);
248
249     addMouseMotionListener(this);
250     addMouseListener(this);
251
252     addKeyListener(new KeyAdapter()
253     {
254       @Override
255       public void keyPressed(KeyEvent evt)
256       {
257         keyPressed(evt);
258       }
259     });
260
261     findCentre();
262     findWidth();
263
264     setupBonds();
265
266     scale = findScale();
267
268     ToolTipManager.sharedInstance().registerComponent(this);
269     ToolTipManager.sharedInstance().setInitialDelay(0);
270     ToolTipManager.sharedInstance().setDismissDelay(10000);
271   }
272
273   Vector<Bond> visiblebonds;
274
275   void setupBonds()
276   {
277     seqColoursReady = false;
278     // Sort the bonds by z coord
279     visiblebonds = new Vector<Bond>();
280
281     for (PDBChain chain : pdb.getChains())
282     {
283       if (chain.isVisible)
284       {
285         for (Bond bond : chain.bonds)
286         {
287           visiblebonds.addElement(bond);
288         }
289       }
290     }
291
292     updateSeqColours();
293     seqColoursReady = true;
294     redrawneeded = true;
295     repaint();
296   }
297
298   public void findWidth()
299   {
300     float[] max = new float[3];
301     float[] min = new float[3];
302
303     max[0] = (float) -1e30;
304     max[1] = (float) -1e30;
305     max[2] = (float) -1e30;
306
307     min[0] = (float) 1e30;
308     min[1] = (float) 1e30;
309     min[2] = (float) 1e30;
310
311     for (PDBChain chain : pdb.getChains())
312     {
313       if (chain.isVisible)
314       {
315         for (Bond tmp : chain.bonds)
316         {
317           if (tmp.start[0] >= max[0])
318           {
319             max[0] = tmp.start[0];
320           }
321
322           if (tmp.start[1] >= max[1])
323           {
324             max[1] = tmp.start[1];
325           }
326
327           if (tmp.start[2] >= max[2])
328           {
329             max[2] = tmp.start[2];
330           }
331
332           if (tmp.start[0] <= min[0])
333           {
334             min[0] = tmp.start[0];
335           }
336
337           if (tmp.start[1] <= min[1])
338           {
339             min[1] = tmp.start[1];
340           }
341
342           if (tmp.start[2] <= min[2])
343           {
344             min[2] = tmp.start[2];
345           }
346
347           if (tmp.end[0] >= max[0])
348           {
349             max[0] = tmp.end[0];
350           }
351
352           if (tmp.end[1] >= max[1])
353           {
354             max[1] = tmp.end[1];
355           }
356
357           if (tmp.end[2] >= max[2])
358           {
359             max[2] = tmp.end[2];
360           }
361
362           if (tmp.end[0] <= min[0])
363           {
364             min[0] = tmp.end[0];
365           }
366
367           if (tmp.end[1] <= min[1])
368           {
369             min[1] = tmp.end[1];
370           }
371
372           if (tmp.end[2] <= min[2])
373           {
374             min[2] = tmp.end[2];
375           }
376         }
377       }
378     }
379     /*
380      * System.out.println("xmax " + max[0] + " min " + min[0]);
381      * System.out.println("ymax " + max[1] + " min " + min[1]);
382      * System.out.println("zmax " + max[2] + " min " + min[2]);
383      */
384
385     width[0] = Math.abs(max[0] - min[0]);
386     width[1] = Math.abs(max[1] - min[1]);
387     width[2] = Math.abs(max[2] - min[2]);
388
389     maxwidth = width[0];
390
391     if (width[1] > width[0])
392     {
393       maxwidth = width[1];
394     }
395
396     if (width[2] > width[1])
397     {
398       maxwidth = width[2];
399     }
400
401     // System.out.println("Maxwidth = " + maxwidth);
402   }
403
404   public float findScale()
405   {
406     int dim;
407     int width;
408     int height;
409
410     if (getWidth() != 0)
411     {
412       width = getWidth();
413       height = getHeight();
414     }
415     else
416     {
417       width = prefsize.width;
418       height = prefsize.height;
419     }
420
421     if (width < height)
422     {
423       dim = width;
424     }
425     else
426     {
427       dim = height;
428     }
429
430     return (float) (dim / (1.5d * maxwidth));
431   }
432
433   public void findCentre()
434   {
435     float xtot = 0;
436     float ytot = 0;
437     float ztot = 0;
438
439     int bsize = 0;
440
441     // Find centre coordinate
442     for (PDBChain chain : pdb.getChains())
443     {
444       if (chain.isVisible)
445       {
446         bsize += chain.bonds.size();
447
448         for (Bond bond : chain.bonds)
449         {
450           xtot = xtot + bond.start[0] + bond.end[0];
451           ytot = ytot + bond.start[1] + bond.end[1];
452           ztot = ztot + bond.start[2] + bond.end[2];
453         }
454       }
455     }
456
457     centre[0] = xtot / (2 * (float) bsize);
458     centre[1] = ytot / (2 * (float) bsize);
459     centre[2] = ztot / (2 * (float) bsize);
460   }
461
462   @Override
463   public void paintComponent(Graphics g)
464   {
465     super.paintComponent(g);
466
467     if (!seqColoursReady || errorMessage != null)
468     {
469       g.setColor(Color.black);
470       g.setFont(new Font("Verdana", Font.BOLD, 14));
471       g.drawString(errorMessage == null ? "Retrieving PDB data...."
472               : errorMessage, 20, getHeight() / 2);
473       return;
474     }
475
476     // Only create the image at the beginning -
477     // this saves much memory usage
478     if ((img == null) || (prefsize.width != getWidth())
479             || (prefsize.height != getHeight()))
480
481     {
482       prefsize.width = getWidth();
483       prefsize.height = getHeight();
484
485       scale = findScale();
486       img = createImage(prefsize.width, prefsize.height);
487       ig = img.getGraphics();
488       Graphics2D ig2 = (Graphics2D) ig;
489
490       ig2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
491               RenderingHints.VALUE_ANTIALIAS_ON);
492
493       redrawneeded = true;
494     }
495
496     if (redrawneeded)
497     {
498       drawAll(ig, prefsize.width, prefsize.height);
499       redrawneeded = false;
500     }
501
502     g.drawImage(img, 0, 0, this);
503
504     pdbAction = false;
505   }
506
507   public void drawAll(Graphics g, int width, int height)
508   {
509     g.setColor(backgroundColour);
510     g.fillRect(0, 0, width, height);
511     drawScene(g);
512     drawLabels(g);
513   }
514
515   public void updateSeqColours()
516   {
517     if (pdbAction)
518     {
519       return;
520     }
521
522     colourBySequence();
523
524     redrawneeded = true;
525     repaint();
526   }
527
528   // This method has been taken out of PDBChain to allow
529   // Applet and Application specific sequence renderers to be used
530   void colourBySequence()
531   {
532     SequenceRenderer sr = new SequenceRenderer(ap.av);
533
534     StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
535
536     boolean showFeatures = false;
537     if (ap.av.isShowSequenceFeatures())
538     {
539       if (fr == null)
540       {
541         fr = new FeatureRenderer(ap);
542       }
543
544       fr.transferSettings(ap.alignFrame.getFeatureRenderer());
545
546       showFeatures = true;
547     }
548
549     FeatureColourFinder finder = new FeatureColourFinder(fr);
550     PDBChain chain;
551     if (bysequence && pdb != null)
552     {
553       for (int ii = 0; ii < pdb.getChains().size(); ii++)
554       {
555         chain = pdb.getChains().elementAt(ii);
556
557         for (int i = 0; i < chain.bonds.size(); i++)
558         {
559           Bond tmp = chain.bonds.elementAt(i);
560           tmp.startCol = Color.lightGray;
561           tmp.endCol = Color.lightGray;
562           if (chain != mainchain)
563           {
564             continue;
565           }
566
567           for (int s = 0; s < sequence.length; s++)
568           {
569             for (int m = 0; m < mapping.length; m++)
570             {
571               if (mapping[m].getSequence() == sequence[s])
572               {
573                 int pos = mapping[m].getSeqPos(tmp.at1.resNumber) - 1;
574                 if (pos > 0)
575                 {
576                   pos = sequence[s].findIndex(pos);
577                   tmp.startCol = sr.getResidueColour(sequence[s], pos,
578                           finder);
579                 }
580                 pos = mapping[m].getSeqPos(tmp.at2.resNumber) - 1;
581                 if (pos > 0)
582                 {
583                   pos = sequence[s].findIndex(pos);
584                   tmp.endCol = sr.getResidueColour(sequence[s], pos,
585                           finder);
586                 }
587
588               }
589             }
590           }
591         }
592       }
593     }
594   }
595
596   Zsort zsort;
597
598   public void drawScene(Graphics g)
599   {
600     if (zbuffer)
601     {
602       if (zsort == null)
603       {
604         zsort = new Zsort();
605       }
606
607       zsort.sort(visiblebonds);
608     }
609
610     Bond tmpBond = null;
611     for (int i = 0; i < visiblebonds.size(); i++)
612     {
613       tmpBond = visiblebonds.elementAt(i);
614
615       xstart = (int) (((tmpBond.start[0] - centre[0]) * scale)
616               + (getWidth() / 2));
617       ystart = (int) (((centre[1] - tmpBond.start[1]) * scale)
618               + (getHeight() / 2));
619
620       xend = (int) (((tmpBond.end[0] - centre[0]) * scale)
621               + (getWidth() / 2));
622       yend = (int) (((centre[1] - tmpBond.end[1]) * scale)
623               + (getHeight() / 2));
624
625       xmid = (xend + xstart) / 2;
626       ymid = (yend + ystart) / 2;
627       if (depthcue && !bymolecule)
628       {
629         if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
630         {
631
632           g.setColor(tmpBond.startCol.darker().darker());
633           drawLine(g, xstart, ystart, xmid, ymid);
634           g.setColor(tmpBond.endCol.darker().darker());
635           drawLine(g, xmid, ymid, xend, yend);
636
637         }
638         else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
639         {
640           g.setColor(tmpBond.startCol.darker());
641           drawLine(g, xstart, ystart, xmid, ymid);
642
643           g.setColor(tmpBond.endCol.darker());
644           drawLine(g, xmid, ymid, xend, yend);
645         }
646         else
647         {
648           g.setColor(tmpBond.startCol);
649           drawLine(g, xstart, ystart, xmid, ymid);
650
651           g.setColor(tmpBond.endCol);
652           drawLine(g, xmid, ymid, xend, yend);
653         }
654       }
655       else if (depthcue && bymolecule)
656       {
657         if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
658         {
659           g.setColor(Color.green.darker().darker());
660           drawLine(g, xstart, ystart, xend, yend);
661         }
662         else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
663         {
664           g.setColor(Color.green.darker());
665           drawLine(g, xstart, ystart, xend, yend);
666         }
667         else
668         {
669           g.setColor(Color.green);
670           drawLine(g, xstart, ystart, xend, yend);
671         }
672       }
673       else if (!depthcue && !bymolecule)
674       {
675         g.setColor(tmpBond.startCol);
676         drawLine(g, xstart, ystart, xmid, ymid);
677         g.setColor(tmpBond.endCol);
678         drawLine(g, xmid, ymid, xend, yend);
679       }
680       else
681       {
682         drawLine(g, xstart, ystart, xend, yend);
683       }
684
685       if (highlightBond1 != null && highlightBond1 == tmpBond)
686       {
687         g.setColor(
688                 tmpBond.endCol.brighter().brighter().brighter().brighter());
689         drawLine(g, xmid, ymid, xend, yend);
690       }
691
692       if (highlightBond2 != null && highlightBond2 == tmpBond)
693       {
694         g.setColor(tmpBond.startCol.brighter().brighter().brighter()
695                 .brighter());
696         drawLine(g, xstart, ystart, xmid, ymid);
697       }
698
699     }
700
701   }
702
703   public void drawLine(Graphics g, int x1, int y1, int x2, int y2)
704   {
705     if (!wire)
706     {
707       if (((float) Math.abs(y2 - y1) / (float) Math.abs(x2 - x1)) < 0.5)
708       {
709         g.drawLine(x1, y1, x2, y2);
710         g.drawLine(x1 + 1, y1 + 1, x2 + 1, y2 + 1);
711         g.drawLine(x1, y1 - 1, x2, y2 - 1);
712       }
713       else
714       {
715         g.setColor(g.getColor().brighter());
716         g.drawLine(x1, y1, x2, y2);
717         g.drawLine(x1 + 1, y1, x2 + 1, y2);
718         g.drawLine(x1 - 1, y1, x2 - 1, y2);
719       }
720     }
721     else
722     {
723       g.drawLine(x1, y1, x2, y2);
724     }
725   }
726
727   public Dimension minimumsize()
728   {
729     return prefsize;
730   }
731
732   public Dimension preferredsize()
733   {
734     return prefsize;
735   }
736
737   public void keyPressed(KeyEvent evt)
738   {
739     if (evt.getKeyCode() == KeyEvent.VK_UP)
740     {
741       scale = (float) (scale * 1.1);
742       redrawneeded = true;
743       repaint();
744     }
745     else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
746     {
747       scale = (float) (scale * 0.9);
748       redrawneeded = true;
749       repaint();
750     }
751   }
752
753   @Override
754   public void mousePressed(MouseEvent e)
755   {
756     pdbAction = true;
757     Atom fatom = findAtom(e.getX(), e.getY());
758     if (fatom != null)
759     {
760       fatom.isSelected = !fatom.isSelected;
761
762       redrawneeded = true;
763       repaint();
764       if (foundchain != -1)
765       {
766         PDBChain chain = pdb.getChains().elementAt(foundchain);
767         if (chain == mainchain)
768         {
769           if (fatom.alignmentMapping != -1)
770           {
771             if (highlightRes == null)
772             {
773               highlightRes = new Vector<String>();
774             }
775
776             final String atomString = Integer
777                     .toString(fatom.alignmentMapping);
778             if (highlightRes.contains(atomString))
779             {
780               highlightRes.remove(atomString);
781             }
782             else
783             {
784               highlightRes.add(atomString);
785             }
786           }
787         }
788       }
789
790     }
791     mx = e.getX();
792     my = e.getY();
793     omx = mx;
794     omy = my;
795     dragging = false;
796   }
797
798   @Override
799   public void mouseMoved(MouseEvent e)
800   {
801     pdbAction = true;
802     if (highlightBond1 != null)
803     {
804       highlightBond1.at2.isSelected = false;
805       highlightBond2.at1.isSelected = false;
806       highlightBond1 = null;
807       highlightBond2 = null;
808     }
809
810     Atom fatom = findAtom(e.getX(), e.getY());
811
812     PDBChain chain = null;
813     if (foundchain != -1)
814     {
815       chain = pdb.getChains().elementAt(foundchain);
816       if (chain == mainchain)
817       {
818         mouseOverStructure(fatom.resNumber, chain.id);
819       }
820     }
821
822     if (fatom != null)
823     {
824       this.setToolTipText(
825               chain.id + ":" + fatom.resNumber + " " + fatom.resName);
826     }
827     else
828     {
829       mouseOverStructure(-1, chain != null ? chain.id : null);
830       this.setToolTipText(null);
831     }
832   }
833
834   @Override
835   public void mouseClicked(MouseEvent e)
836   {
837   }
838
839   @Override
840   public void mouseEntered(MouseEvent e)
841   {
842   }
843
844   @Override
845   public void mouseExited(MouseEvent e)
846   {
847   }
848
849   @Override
850   public void mouseDragged(MouseEvent evt)
851   {
852     int x = evt.getX();
853     int y = evt.getY();
854     mx = x;
855     my = y;
856
857     MCMatrix objmat = new MCMatrix(3, 3);
858     objmat.setIdentity();
859
860     if ((evt.getModifiersEx() & InputEvent.META_DOWN_MASK) != 0)
861     {
862       objmat.rotatez(((mx - omx)));
863     }
864     else
865     {
866       objmat.rotatex(((my - omy)));
867       objmat.rotatey(((omx - mx)));
868     }
869
870     // Alter the bonds
871     for (PDBChain chain : pdb.getChains())
872     {
873       for (Bond tmpBond : chain.bonds)
874       {
875         // Translate the bond so the centre is 0,0,0
876         tmpBond.translate(-centre[0], -centre[1], -centre[2]);
877
878         // Now apply the rotation matrix
879         tmpBond.start = objmat.vectorMultiply(tmpBond.start);
880         tmpBond.end = objmat.vectorMultiply(tmpBond.end);
881
882         // Now translate back again
883         tmpBond.translate(centre[0], centre[1], centre[2]);
884       }
885     }
886
887     objmat = null;
888
889     omx = mx;
890     omy = my;
891
892     dragging = true;
893
894     redrawneeded = true;
895
896     repaint();
897   }
898
899   @Override
900   public void mouseReleased(MouseEvent evt)
901   {
902     dragging = false;
903     return;
904   }
905
906   void drawLabels(Graphics g)
907   {
908
909     for (PDBChain chain : pdb.getChains())
910     {
911       if (chain.isVisible)
912       {
913         for (Bond tmpBond : chain.bonds)
914         {
915           if (tmpBond.at1.isSelected)
916           {
917             labelAtom(g, tmpBond, 1);
918           }
919
920           if (tmpBond.at2.isSelected)
921           {
922             labelAtom(g, tmpBond, 2);
923           }
924         }
925       }
926     }
927   }
928
929   public void labelAtom(Graphics g, Bond b, int n)
930   {
931     g.setFont(font);
932     g.setColor(Color.red);
933     if (n == 1)
934     {
935       int xstart = (int) (((b.start[0] - centre[0]) * scale)
936               + (getWidth() / 2));
937       int ystart = (int) (((centre[1] - b.start[1]) * scale)
938               + (getHeight() / 2));
939
940       g.drawString(b.at1.resName + "-" + b.at1.resNumber, xstart, ystart);
941     }
942
943     if (n == 2)
944     {
945       int xstart = (int) (((b.end[0] - centre[0]) * scale)
946               + (getWidth() / 2));
947       int ystart = (int) (((centre[1] - b.end[1]) * scale)
948               + (getHeight() / 2));
949
950       g.drawString(b.at2.resName + "-" + b.at2.resNumber, xstart, ystart);
951     }
952   }
953
954   int foundchain = -1;
955
956   public Atom findAtom(int x, int y)
957   {
958     Atom fatom = null;
959
960     foundchain = -1;
961
962     for (int ii = 0; ii < pdb.getChains().size(); ii++)
963     {
964       PDBChain chain = pdb.getChains().elementAt(ii);
965       int truex;
966       Bond tmpBond = null;
967
968       if (chain.isVisible)
969       {
970         for (Bond bond : chain.bonds)
971         {
972           tmpBond = bond;
973
974           truex = (int) (((tmpBond.start[0] - centre[0]) * scale)
975                   + (getWidth() / 2));
976
977           if (Math.abs(truex - x) <= 2)
978           {
979             int truey = (int) (((centre[1] - tmpBond.start[1]) * scale)
980                     + (getHeight() / 2));
981
982             if (Math.abs(truey - y) <= 2)
983             {
984               fatom = tmpBond.at1;
985               foundchain = ii;
986               break;
987             }
988           }
989         }
990
991         // Still here? Maybe its the last bond
992
993         truex = (int) (((tmpBond.end[0] - centre[0]) * scale)
994                 + (getWidth() / 2));
995
996         if (Math.abs(truex - x) <= 2)
997         {
998           int truey = (int) (((tmpBond.end[1] - centre[1]) * scale)
999                   + (getHeight() / 2));
1000
1001           if (Math.abs(truey - y) <= 2)
1002           {
1003             fatom = tmpBond.at2;
1004             foundchain = ii;
1005             break;
1006           }
1007         }
1008
1009       }
1010
1011       if (fatom != null) // )&& chain.ds != null)
1012       { // dead code? value of chain is either overwritten or discarded
1013         chain = pdb.getChains().elementAt(foundchain);
1014       }
1015     }
1016
1017     return fatom;
1018   }
1019
1020   Bond highlightBond1, highlightBond2;
1021
1022   public void highlightRes(int ii)
1023   {
1024     if (!seqColoursReady)
1025     {
1026       return;
1027     }
1028
1029     if (highlightRes != null && highlightRes.contains((ii - 1) + ""))
1030     {
1031       return;
1032     }
1033
1034     int index = -1;
1035     Bond tmpBond;
1036     for (index = 0; index < mainchain.bonds.size(); index++)
1037     {
1038       tmpBond = mainchain.bonds.elementAt(index);
1039       if (tmpBond.at1.alignmentMapping == ii - 1)
1040       {
1041         if (highlightBond1 != null)
1042         {
1043           highlightBond1.at2.isSelected = false;
1044         }
1045
1046         if (highlightBond2 != null)
1047         {
1048           highlightBond2.at1.isSelected = false;
1049         }
1050
1051         highlightBond1 = null;
1052         highlightBond2 = null;
1053
1054         if (index > 0)
1055         {
1056           highlightBond1 = mainchain.bonds.elementAt(index - 1);
1057           highlightBond1.at2.isSelected = true;
1058         }
1059
1060         if (index != mainchain.bonds.size())
1061         {
1062           highlightBond2 = mainchain.bonds.elementAt(index);
1063           highlightBond2.at1.isSelected = true;
1064         }
1065
1066         break;
1067       }
1068     }
1069
1070     redrawneeded = true;
1071     repaint();
1072   }
1073
1074   public void setAllchainsVisible(boolean b)
1075   {
1076     for (int ii = 0; ii < pdb.getChains().size(); ii++)
1077     {
1078       PDBChain chain = pdb.getChains().elementAt(ii);
1079       chain.isVisible = b;
1080     }
1081     mainchain.isVisible = true;
1082     findCentre();
1083     setupBonds();
1084   }
1085
1086   // ////////////////////////////////
1087   // /StructureListener
1088   @Override
1089   public String[] getStructureFiles()
1090   {
1091     return new String[] { pdbentry.getFile() };
1092   }
1093
1094   String lastMessage;
1095
1096   public void mouseOverStructure(int pdbResNum, String chain)
1097   {
1098     if (lastMessage == null || !lastMessage.equals(pdbResNum + chain))
1099     {
1100       ssm.mouseOverStructure(pdbResNum, chain, pdbentry.getFile());
1101     }
1102
1103     lastMessage = pdbResNum + chain;
1104   }
1105
1106   StringBuffer resetLastRes = new StringBuffer();
1107
1108   StringBuffer eval = new StringBuffer();
1109
1110   /**
1111    * Highlight the specified atoms in the structure.
1112    * 
1113    * @param atoms
1114    */
1115   @Override
1116   public void highlightAtoms(List<AtomSpec> atoms)
1117   {
1118     if (!seqColoursReady)
1119     {
1120       return;
1121     }
1122
1123     for (AtomSpec atom : atoms)
1124     {
1125       int atomIndex = atom.getAtomIndex();
1126       if (highlightRes != null
1127               && highlightRes.contains((atomIndex - 1) + ""))
1128       {
1129         continue;
1130       }
1131
1132       highlightAtom(atomIndex);
1133     }
1134
1135     redrawneeded = true;
1136     repaint();
1137   }
1138
1139   /**
1140    * Highlight the atom at the specified index.
1141    * 
1142    * @param atomIndex
1143    */
1144   protected void highlightAtom(int atomIndex)
1145   {
1146     int index = -1;
1147     Bond tmpBond;
1148     for (index = 0; index < mainchain.bonds.size(); index++)
1149     {
1150       tmpBond = mainchain.bonds.elementAt(index);
1151       if (tmpBond.at1.atomIndex == atomIndex)
1152       {
1153         if (highlightBond1 != null)
1154         {
1155           highlightBond1.at2.isSelected = false;
1156         }
1157
1158         if (highlightBond2 != null)
1159         {
1160           highlightBond2.at1.isSelected = false;
1161         }
1162
1163         highlightBond1 = null;
1164         highlightBond2 = null;
1165
1166         if (index > 0)
1167         {
1168           highlightBond1 = mainchain.bonds.elementAt(index - 1);
1169           highlightBond1.at2.isSelected = true;
1170         }
1171
1172         if (index != mainchain.bonds.size())
1173         {
1174           highlightBond2 = mainchain.bonds.elementAt(index);
1175           highlightBond2.at1.isSelected = true;
1176         }
1177
1178         break;
1179       }
1180     }
1181   }
1182
1183   public Color getColour(int atomIndex, int pdbResNum, String chain,
1184           String pdbfile)
1185   {
1186     return Color.white;
1187     // if (!pdbfile.equals(pdbentry.getFile()))
1188     // return null;
1189
1190     // return new Color(viewer.getAtomArgb(atomIndex));
1191   }
1192
1193   @Override
1194   public void updateColours(Object source)
1195   {
1196     colourBySequence();
1197     redrawneeded = true;
1198     repaint();
1199   }
1200
1201   @Override
1202   public void releaseReferences(Object svl)
1203   {
1204     // TODO Auto-generated method stub
1205
1206   }
1207
1208   @Override
1209   public boolean isListeningFor(SequenceI seq)
1210   {
1211     if (sequence != null)
1212     {
1213       for (SequenceI s : sequence)
1214       {
1215         if (s == seq)
1216         {
1217           return true;
1218         }
1219       }
1220     }
1221     return false;
1222   }
1223 }