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