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