JAL-1807 explicit imports (MCview)
[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.AppletFormatAdapter;
30 import jalview.schemes.ColourSchemeI;
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 PDBfile 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, String 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);
162
163       if (protocol.equals(AppletFormatAdapter.PASTE))
164       {
165         pdbentry.setFile("INLINE" + pdb.id);
166       }
167
168     } catch (Exception ex)
169     {
170       ex.printStackTrace();
171       return;
172     }
173
174     pdbentry.setId(pdb.id);
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.chains.size(); i++)
191     {
192
193       mappingDetails.append("\n\nPDB Sequence is :\nSequence = "
194               + pdb.chains.elementAt(i).sequence
195                       .getSequenceAsString());
196       mappingDetails.append("\nNo of residues = "
197               + pdb.chains.elementAt(i).residues.size()
198               + "\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.chains.elementAt(i).sequence,
206               pdb.chains.elementAt(i).isNa ? AlignSeq.DNA
207                       : AlignSeq.PEP);
208       as.calcScoreMatrix();
209       as.traceAlignment();
210       PrintStream ps = new PrintStream(System.out)
211       {
212         public void print(String x)
213         {
214           mappingDetails.append(x);
215         }
216
217         public void println()
218         {
219           mappingDetails.append("\n");
220         }
221       };
222
223       as.printAlignment(ps);
224
225       if (as.maxscore > max)
226       {
227         max = as.maxscore;
228         maxchain = i;
229
230         pdbstart = as.seq2start;
231         pdbend = as.seq2end;
232         seqstart = as.seq1start + sequence.getStart() - 1;
233         seqend = as.seq1end + sequence.getEnd() - 1;
234       }
235
236       mappingDetails.append("\nPDB start/end " + pdbstart + " " + pdbend);
237       mappingDetails.append("\nSEQ start/end " + seqstart + " " + seqend);
238     }
239
240     mainchain = pdb.chains.elementAt(maxchain);
241
242     mainchain.pdbstart = pdbstart;
243     mainchain.pdbend = pdbend;
244     mainchain.seqstart = seqstart;
245     mainchain.seqend = seqend;
246     mainchain.isVisible = true;
247     // mainchain.makeExactMapping(maxAlignseq, sequence);
248     // mainchain.transferRESNUMFeatures(sequence, null);
249     this.pdb = pdb;
250     this.prefsize = new Dimension(getSize().width, getSize().height);
251
252     // Initialize the matrices to identity
253     for (int i = 0; i < 3; i++)
254     {
255       for (int j = 0; j < 3; j++)
256       {
257         if (i != j)
258         {
259           idmat.addElement(i, j, 0);
260           objmat.addElement(i, j, 0);
261         }
262         else
263         {
264           idmat.addElement(i, j, 1);
265           objmat.addElement(i, j, 1);
266         }
267       }
268     }
269
270     addMouseMotionListener(this);
271     addMouseListener(this);
272
273     addKeyListener(new KeyAdapter()
274     {
275       public void keyPressed(KeyEvent evt)
276       {
277         doKeyPressed(evt);
278       }
279     });
280
281     findCentre();
282     findWidth();
283
284     setupBonds();
285
286     scale = findScale();
287   }
288
289   Vector<Bond> visiblebonds;
290
291   void setupBonds()
292   {
293     seqColoursReady = false;
294     // Sort the bonds by z coord
295     visiblebonds = new Vector<Bond>();
296
297     for (int ii = 0; ii < pdb.chains.size(); ii++)
298     {
299       if (pdb.chains.elementAt(ii).isVisible)
300       {
301         Vector<Bond> tmp = pdb.chains.elementAt(ii).bonds;
302
303         for (int i = 0; i < tmp.size(); i++)
304         {
305           visiblebonds.addElement(tmp.elementAt(i));
306         }
307       }
308     }
309     seqColoursReady = true;
310     colourBySequence();
311     redrawneeded = true;
312     repaint();
313   }
314
315   public void findWidth()
316   {
317     float[] max = new float[3];
318     float[] min = new float[3];
319
320     max[0] = (float) -1e30;
321     max[1] = (float) -1e30;
322     max[2] = (float) -1e30;
323
324     min[0] = (float) 1e30;
325     min[1] = (float) 1e30;
326     min[2] = (float) 1e30;
327
328     for (int ii = 0; ii < pdb.chains.size(); ii++)
329     {
330       if (pdb.chains.elementAt(ii).isVisible)
331       {
332         Vector<Bond> bonds = pdb.chains.elementAt(ii).bonds;
333
334         for (Bond tmp : bonds)
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<Bond> bonds = pdb.chains.elementAt(ii).bonds;
461
462         bsize += bonds.size();
463
464         for (Bond b : bonds)
465         {
466           xtot = xtot + b.start[0] + b.end[0];
467           ytot = ytot + b.start[1] + b.end[1];
468           ztot = ztot + b.start[2] + b.end[2];
469         }
470       }
471     }
472
473     centre[0] = xtot / (2 * (float) bsize);
474     centre[1] = ytot / (2 * (float) bsize);
475     centre[2] = ztot / (2 * (float) bsize);
476   }
477
478   public void paint(Graphics g)
479   {
480
481     if (errorLoading)
482     {
483       g.setColor(Color.white);
484       g.fillRect(0, 0, getSize().width, getSize().height);
485       g.setColor(Color.black);
486       g.setFont(new Font("Verdana", Font.BOLD, 14));
487       g.drawString(
488               MessageManager.getString("label.error_loading_pdb_data"), 50,
489               getSize().height / 2);
490       return;
491     }
492
493     if (!seqColoursReady)
494     {
495       g.setColor(Color.black);
496       g.setFont(new Font("Verdana", Font.BOLD, 14));
497       g.drawString(MessageManager.getString("label.fetching_pdb_data"), 50,
498               getSize().height / 2);
499       return;
500     }
501
502     // Only create the image at the beginning -
503     // this saves much memory usage
504     if ((img == null) || (prefsize.width != getSize().width)
505             || (prefsize.height != getSize().height))
506     {
507
508       try
509       {
510         prefsize.width = getSize().width;
511         prefsize.height = getSize().height;
512
513         scale = findScale();
514         img = createImage(prefsize.width, prefsize.height);
515         ig = img.getGraphics();
516
517         redrawneeded = true;
518       } catch (Exception ex)
519       {
520         ex.printStackTrace();
521       }
522     }
523
524     if (redrawneeded)
525     {
526       drawAll(ig, prefsize.width, prefsize.height);
527       redrawneeded = false;
528     }
529     if (appletToolTip != null)
530     {
531       ig.setColor(Color.red);
532       ig.drawString(appletToolTip, toolx, tooly);
533     }
534
535     g.drawImage(img, 0, 0, this);
536
537     pdbAction = false;
538   }
539
540   public void drawAll(Graphics g, int width, int height)
541   {
542     ig.setColor(Color.black);
543     ig.fillRect(0, 0, width, height);
544     drawScene(ig);
545     drawLabels(ig);
546   }
547
548   public void setColours(ColourSchemeI cs)
549   {
550     bysequence = false;
551     pdb.setColours(cs);
552     redrawneeded = true;
553     repaint();
554   }
555
556   // This method has been taken out of PDBChain to allow
557   // Applet and Application specific sequence renderers to be used
558   void colourBySequence()
559   {
560     SequenceRenderer sr = new SequenceRenderer(ap.av);
561
562     StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
563
564     boolean showFeatures = false;
565     if (ap.av.isShowSequenceFeatures())
566     {
567       if (fr == null)
568       {
569         fr = new jalview.appletgui.FeatureRenderer(ap.av);
570       }
571
572       fr.transferSettings(ap.getFeatureRenderer());
573
574       showFeatures = true;
575     }
576
577     PDBChain chain;
578     if (bysequence && pdb != null)
579     {
580       for (int ii = 0; ii < pdb.chains.size(); ii++)
581       {
582         chain = pdb.chains.elementAt(ii);
583
584         for (int i = 0; i < chain.bonds.size(); i++)
585         {
586           Bond tmp = chain.bonds.elementAt(i);
587           tmp.startCol = Color.lightGray;
588           tmp.endCol = Color.lightGray;
589           if (chain != mainchain)
590           {
591             continue;
592           }
593
594           for (int s = 0; s < sequence.length; s++)
595           {
596             for (int m = 0; m < mapping.length; m++)
597             {
598               if (mapping[m].getSequence() == sequence[s])
599               {
600                 int pos = mapping[m].getSeqPos(tmp.at1.resNumber) - 1;
601                 if (pos > 0)
602                 {
603                   pos = sequence[s].findIndex(pos);
604                   tmp.startCol = sr.getResidueBoxColour(sequence[s], pos);
605                   if (showFeatures)
606                   {
607                     tmp.startCol = fr.findFeatureColour(tmp.startCol,
608                             sequence[s], pos);
609                   }
610                 }
611                 pos = mapping[m].getSeqPos(tmp.at2.resNumber) - 1;
612                 if (pos > 0)
613                 {
614                   pos = sequence[s].findIndex(pos);
615                   tmp.endCol = sr.getResidueBoxColour(sequence[s], pos);
616                   if (showFeatures)
617                   {
618                     tmp.endCol = fr.findFeatureColour(tmp.endCol,
619                             sequence[s], pos);
620                   }
621                 }
622
623               }
624             }
625           }
626         }
627       }
628     }
629   }
630
631   Zsort zsort;
632
633   public void drawScene(Graphics g)
634   {
635     if (zbuffer)
636     {
637       if (zsort == null)
638       {
639         zsort = new Zsort();
640       }
641
642       zsort.sort(visiblebonds);
643     }
644
645     Bond tmpBond = null;
646     for (int i = 0; i < visiblebonds.size(); i++)
647     {
648       tmpBond = visiblebonds.elementAt(i);
649
650       xstart = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getSize().width / 2));
651       ystart = (int) (((centre[1] - tmpBond.start[1]) * scale) + (getSize().height / 2));
652
653       xend = (int) (((tmpBond.end[0] - centre[0]) * scale) + (getSize().width / 2));
654       yend = (int) (((centre[1] - tmpBond.end[1]) * scale) + (getSize().height / 2));
655
656       xmid = (xend + xstart) / 2;
657       ymid = (yend + ystart) / 2;
658
659       if (depthcue && !bymolecule)
660       {
661         if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
662         {
663           g.setColor(tmpBond.startCol.darker().darker());
664           drawLine(g, xstart, ystart, xmid, ymid);
665
666           g.setColor(tmpBond.endCol.darker().darker());
667           drawLine(g, xmid, ymid, xend, yend);
668         }
669         else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
670         {
671           g.setColor(tmpBond.startCol.darker());
672           drawLine(g, xstart, ystart, xmid, ymid);
673
674           g.setColor(tmpBond.endCol.darker());
675           drawLine(g, xmid, ymid, xend, yend);
676         }
677         else
678         {
679           g.setColor(tmpBond.startCol);
680           drawLine(g, xstart, ystart, xmid, ymid);
681
682           g.setColor(tmpBond.endCol);
683           drawLine(g, xmid, ymid, xend, yend);
684         }
685
686       }
687       else if (depthcue && bymolecule)
688       {
689         if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
690         {
691           g.setColor(Color.green.darker().darker());
692           drawLine(g, xstart, ystart, xend, yend);
693         }
694         else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
695         {
696           g.setColor(Color.green.darker());
697           drawLine(g, xstart, ystart, xend, yend);
698         }
699         else
700         {
701           g.setColor(Color.green);
702           drawLine(g, xstart, ystart, xend, yend);
703         }
704       }
705       else if (!depthcue && !bymolecule)
706       {
707         g.setColor(tmpBond.startCol);
708         drawLine(g, xstart, ystart, xmid, ymid);
709         g.setColor(tmpBond.endCol);
710         drawLine(g, xmid, ymid, xend, yend);
711       }
712       else
713       {
714         drawLine(g, xstart, ystart, xend, yend);
715       }
716
717       if (highlightBond1 != null && highlightBond1 == tmpBond)
718       {
719         g.setColor(Color.white);
720         drawLine(g, xmid, ymid, xend, yend);
721       }
722
723       if (highlightBond2 != null && highlightBond2 == tmpBond)
724       {
725         g.setColor(Color.white);
726         drawLine(g, xstart, ystart, xmid, ymid);
727       }
728
729     }
730   }
731
732   public void drawLine(Graphics g, int x1, int y1, int x2, int y2)
733   {
734     if (!wire)
735     {
736       if (((float) Math.abs(y2 - y1) / (float) Math.abs(x2 - x1)) < 0.5)
737       {
738         g.drawLine(x1, y1, x2, y2);
739         g.drawLine(x1 + 1, y1 + 1, x2 + 1, y2 + 1);
740         g.drawLine(x1, y1 - 1, x2, y2 - 1);
741       }
742       else
743       {
744         g.setColor(g.getColor().brighter());
745         g.drawLine(x1, y1, x2, y2);
746         g.drawLine(x1 + 1, y1, x2 + 1, y2);
747         g.drawLine(x1 - 1, y1, x2 - 1, y2);
748       }
749     }
750     else
751     {
752       g.drawLine(x1, y1, x2, y2);
753     }
754   }
755
756   public Dimension minimumsize()
757   {
758     return prefsize;
759   }
760
761   public Dimension preferredsize()
762   {
763     return prefsize;
764   }
765
766   public void doKeyPressed(KeyEvent evt)
767   {
768     if (evt.getKeyCode() == KeyEvent.VK_UP)
769     {
770       scale = (float) (scale * 1.1);
771       redrawneeded = true;
772       repaint();
773     }
774     else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
775     {
776       scale = (float) (scale * 0.9);
777       redrawneeded = true;
778       repaint();
779     }
780   }
781
782   public void mousePressed(MouseEvent e)
783   {
784     pdbAction = true;
785     Atom fatom = findAtom(e.getX(), e.getY());
786     if (fatom != null)
787     {
788       fatom.isSelected = !fatom.isSelected;
789
790       redrawneeded = true;
791       repaint();
792       if (foundchain != -1)
793       {
794         PDBChain chain = pdb.chains.elementAt(foundchain);
795         if (chain == mainchain)
796         {
797           if (fatom.alignmentMapping != -1)
798           {
799             if (highlightRes == null)
800             {
801               highlightRes = new Vector<String>();
802             }
803
804             final String atomString = Integer
805                     .toString(fatom.alignmentMapping);
806             if (highlightRes.contains(atomString))
807             {
808               highlightRes.removeElement(atomString);
809             }
810             else
811             {
812               highlightRes.addElement(atomString);
813             }
814           }
815         }
816       }
817
818     }
819     mx = e.getX();
820     my = e.getY();
821     omx = mx;
822     omy = my;
823     dragging = false;
824   }
825
826   public void mouseMoved(MouseEvent e)
827   {
828     pdbAction = true;
829     if (highlightBond1 != null)
830     {
831       highlightBond1.at2.isSelected = false;
832       highlightBond2.at1.isSelected = false;
833       highlightBond1 = null;
834       highlightBond2 = null;
835     }
836
837     Atom fatom = findAtom(e.getX(), e.getY());
838
839     PDBChain chain = null;
840     if (foundchain != -1)
841     {
842       chain = pdb.chains.elementAt(foundchain);
843       if (chain == mainchain)
844       {
845         mouseOverStructure(fatom.resNumber, chain.id);
846       }
847     }
848
849     if (fatom != null)
850     {
851       toolx = e.getX();
852       tooly = e.getY();
853
854       appletToolTip = chain.id + ":" + fatom.resNumber + " "
855               + fatom.resName;
856       redrawneeded = true;
857       repaint();
858     }
859     else
860     {
861       mouseOverStructure(-1, chain != null ? chain.id : null);
862       appletToolTip = null;
863       redrawneeded = true;
864       repaint();
865     }
866   }
867
868   public void mouseClicked(MouseEvent e)
869   {
870   }
871
872   public void mouseEntered(MouseEvent e)
873   {
874   }
875
876   public void mouseExited(MouseEvent e)
877   {
878   }
879
880   public void mouseDragged(MouseEvent evt)
881   {
882     int x = evt.getX();
883     int y = evt.getY();
884     mx = x;
885     my = y;
886
887     MCMatrix objmat = new MCMatrix(3, 3);
888     objmat.setIdentity();
889
890     if ((evt.getModifiers() & Event.META_MASK) != 0)
891     {
892       objmat.rotatez(((mx - omx)));
893     }
894     else
895     {
896       objmat.rotatex(((omy - my)));
897       objmat.rotatey(((omx - mx)));
898     }
899
900     // Alter the bonds
901     for (PDBChain chain : pdb.chains)
902     {
903       for (Bond tmpBond : chain.bonds)
904       {
905         // Translate the bond so the centre is 0,0,0
906         tmpBond.translate(-centre[0], -centre[1], -centre[2]);
907
908         // Now apply the rotation matrix
909         tmpBond.start = objmat.vectorMultiply(tmpBond.start);
910         tmpBond.end = objmat.vectorMultiply(tmpBond.end);
911
912         // Now translate back again
913         tmpBond.translate(centre[0], centre[1], centre[2]);
914       }
915     }
916
917     objmat = null;
918
919     omx = mx;
920     omy = my;
921
922     dragging = true;
923
924     redrawneeded = true;
925
926     repaint();
927   }
928
929   public void mouseReleased(MouseEvent evt)
930   {
931     dragging = false;
932     return;
933   }
934
935   void drawLabels(Graphics g)
936   {
937
938     for (PDBChain chain : pdb.chains)
939     {
940       if (chain.isVisible)
941       {
942         for (Bond tmpBond : chain.bonds)
943         {
944           if (tmpBond.at1.isSelected)
945           {
946             labelAtom(g, tmpBond, 1);
947           }
948
949           if (tmpBond.at2.isSelected)
950           {
951             labelAtom(g, tmpBond, 2);
952           }
953         }
954       }
955     }
956   }
957
958   public void labelAtom(Graphics g, Bond b, int n)
959   {
960     g.setFont(font);
961
962     if (n == 1)
963     {
964       int xstart = (int) (((b.start[0] - centre[0]) * scale) + (getSize().width / 2));
965       int ystart = (int) (((centre[1] - b.start[1]) * scale) + (getSize().height / 2));
966
967       g.setColor(Color.red);
968       g.drawString(b.at1.resName + "-" + b.at1.resNumber, xstart, ystart);
969     }
970
971     if (n == 2)
972     {
973       int xstart = (int) (((b.end[0] - centre[0]) * scale) + (getSize().width / 2));
974       int ystart = (int) (((centre[1] - b.end[1]) * scale) + (getSize().height / 2));
975
976       g.setColor(Color.red);
977       g.drawString(b.at2.resName + "-" + b.at2.resNumber, xstart, ystart);
978     }
979   }
980
981   int foundchain = -1;
982
983   public Atom findAtom(int x, int y)
984   {
985     Atom fatom = null;
986
987     foundchain = -1;
988
989     for (int ii = 0; ii < pdb.chains.size(); ii++)
990     {
991       PDBChain chain = pdb.chains.elementAt(ii);
992       int truex;
993       Bond tmpBond = null;
994
995       if (chain.isVisible)
996       {
997         Vector<Bond> bonds = pdb.chains.elementAt(ii).bonds;
998
999         for (int i = 0; i < bonds.size(); i++)
1000         {
1001           tmpBond = bonds.elementAt(i);
1002
1003           truex = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getSize().width / 2));
1004
1005           if (Math.abs(truex - x) <= 2)
1006           {
1007             int truey = (int) (((centre[1] - tmpBond.start[1]) * scale) + (getSize().height / 2));
1008
1009             if (Math.abs(truey - y) <= 2)
1010             {
1011               fatom = tmpBond.at1;
1012               foundchain = ii;
1013               break;
1014             }
1015           }
1016         }
1017
1018         // Still here? Maybe its the last bond
1019
1020         truex = (int) (((tmpBond.end[0] - centre[0]) * scale) + (getSize().width / 2));
1021
1022         if (Math.abs(truex - x) <= 2)
1023         {
1024           int truey = (int) (((tmpBond.end[1] - centre[1]) * scale) + (getSize().height / 2));
1025
1026           if (Math.abs(truey - y) <= 2)
1027           {
1028             fatom = tmpBond.at2;
1029             foundchain = ii;
1030             break;
1031           }
1032         }
1033
1034       }
1035
1036       if (fatom != null) // )&& chain.ds != null)
1037       {
1038         chain = pdb.chains.elementAt(foundchain);
1039       }
1040     }
1041
1042     return fatom;
1043   }
1044
1045   public void update(Graphics g)
1046   {
1047     paint(g);
1048   }
1049
1050   public void highlightRes(int ii)
1051   {
1052     if (!seqColoursReady)
1053     {
1054       return;
1055     }
1056
1057     if (highlightRes != null && highlightRes.contains((ii - 1) + ""))
1058     {
1059       return;
1060     }
1061
1062     int index = -1;
1063     Bond tmpBond;
1064     for (index = 0; index < mainchain.bonds.size(); index++)
1065     {
1066       tmpBond = mainchain.bonds.elementAt(index);
1067       if (tmpBond.at1.alignmentMapping == ii - 1)
1068       {
1069         if (highlightBond1 != null)
1070         {
1071           highlightBond1.at2.isSelected = false;
1072         }
1073
1074         if (highlightBond2 != null)
1075         {
1076           highlightBond2.at1.isSelected = false;
1077         }
1078
1079         highlightBond1 = null;
1080         highlightBond2 = null;
1081
1082         if (index > 0)
1083         {
1084           highlightBond1 = mainchain.bonds.elementAt(index - 1);
1085           highlightBond1.at2.isSelected = true;
1086         }
1087
1088         if (index != mainchain.bonds.size())
1089         {
1090           highlightBond2 = mainchain.bonds.elementAt(index);
1091           highlightBond2.at1.isSelected = true;
1092         }
1093
1094         break;
1095       }
1096     }
1097
1098     redrawneeded = true;
1099     repaint();
1100   }
1101
1102   public void setAllchainsVisible(boolean b)
1103   {
1104     for (int ii = 0; ii < pdb.chains.size(); ii++)
1105     {
1106       PDBChain chain = pdb.chains.elementAt(ii);
1107       chain.isVisible = b;
1108     }
1109     mainchain.isVisible = true;
1110     findCentre();
1111     setupBonds();
1112   }
1113
1114   // ////////////////////////////////
1115   // /StructureListener
1116   public String[] getPdbFile()
1117   {
1118     return new String[]
1119     { pdbentry.getFile() };
1120   }
1121
1122   String lastMessage;
1123
1124   public void mouseOverStructure(int pdbResNum, String chain)
1125   {
1126     if (lastMessage == null || !lastMessage.equals(pdbResNum + chain))
1127     {
1128       ssm.mouseOverStructure(pdbResNum, chain, pdbentry.getFile());
1129     }
1130
1131     lastMessage = pdbResNum + chain;
1132   }
1133
1134   StringBuffer resetLastRes = new StringBuffer();
1135
1136   StringBuffer eval = new StringBuffer();
1137
1138   /**
1139    * Highlight the specified atoms in the structure.
1140    * 
1141    * @param atoms
1142    */
1143   @Override
1144   public void highlightAtoms(List<AtomSpec> atoms)
1145   {
1146     if (!seqColoursReady)
1147     {
1148       return;
1149     }
1150     for (AtomSpec atom : atoms)
1151     {
1152       int atomIndex = atom.getAtomIndex();
1153
1154       if (highlightRes != null
1155               && highlightRes.contains((atomIndex - 1) + ""))
1156       {
1157         continue;
1158       }
1159
1160       highlightAtom(atomIndex);
1161     }
1162
1163     redrawneeded = true;
1164     repaint();
1165   }
1166
1167   /**
1168    * @param atomIndex
1169    */
1170   protected void highlightAtom(int atomIndex)
1171   {
1172     int index = -1;
1173     Bond tmpBond;
1174     for (index = 0; index < mainchain.bonds.size(); index++)
1175     {
1176       tmpBond = mainchain.bonds.elementAt(index);
1177       if (tmpBond.at1.atomIndex == atomIndex)
1178       {
1179         if (highlightBond1 != null)
1180         {
1181           highlightBond1.at2.isSelected = false;
1182         }
1183
1184         if (highlightBond2 != null)
1185         {
1186           highlightBond2.at1.isSelected = false;
1187         }
1188
1189         highlightBond1 = null;
1190         highlightBond2 = null;
1191
1192         if (index > 0)
1193         {
1194           highlightBond1 = mainchain.bonds.elementAt(index - 1);
1195           highlightBond1.at2.isSelected = true;
1196         }
1197
1198         if (index != mainchain.bonds.size())
1199         {
1200           highlightBond2 = mainchain.bonds.elementAt(index);
1201           highlightBond2.at1.isSelected = true;
1202         }
1203
1204         break;
1205       }
1206     }
1207   }
1208
1209   public Color getColour(int atomIndex, int pdbResNum, String chain,
1210           String pdbfile)
1211   {
1212     return Color.white;
1213     // if (!pdbfile.equals(pdbentry.getFile()))
1214     // return null;
1215
1216     // return new Color(viewer.getAtomArgb(atomIndex));
1217   }
1218
1219   public void updateColours(Object source)
1220   {
1221     colourBySequence();
1222     redrawneeded = true;
1223     repaint();
1224   }
1225
1226   @Override
1227   public void releaseReferences(Object svl)
1228   {
1229     // TODO Auto-generated method stub
1230
1231   }
1232
1233   @Override
1234   public boolean isListeningFor(SequenceI seq)
1235   {
1236     if (sequence != null)
1237     {
1238       for (SequenceI s : sequence)
1239       {
1240         if (s == seq)
1241         {
1242           return true;
1243         }
1244       }
1245     }
1246     return false;
1247   }
1248 }