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