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