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