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