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