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