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