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