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