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