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