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