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