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