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