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