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