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