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