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