2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
23 import java.awt.Color;
24 import java.awt.Dimension;
25 import java.awt.Event;
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;
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;
52 public class AppletPDBCanvas extends Panel implements MouseListener,
53 MouseMotionListener, StructureListener
56 MCMatrix idmat = new MCMatrix(3, 3);
58 MCMatrix objmat = new MCMatrix(3, 3);
60 boolean redrawneeded = true;
82 float[] centre = new float[3];
84 float[] width = new float[3];
94 boolean bysequence = true;
96 boolean depthcue = true;
100 boolean bymolecule = false;
102 boolean zbuffer = true;
118 Font font = new Font("Helvetica", Font.PLAIN, 10);
120 public SequenceI[] sequence;
122 final StringBuffer mappingDetails = new StringBuffer();
124 String appletToolTip = null;
130 Vector<String> highlightRes;
132 boolean pdbAction = false;
134 Bond highlightBond1, highlightBond2;
136 boolean errorLoading = false;
138 boolean seqColoursReady = false;
144 StructureSelectionManager ssm;
146 public AppletPDBCanvas(PDBEntry pdbentry, SequenceI[] seq,
147 String[] chains, AlignmentPanel ap, String protocol)
151 this.pdbentry = pdbentry;
154 ssm = StructureSelectionManager
155 .getStructureSelectionManager(ap.av.applet);
159 pdb = ssm.setMapping(seq, chains, pdbentry.getFile(), protocol);
161 if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
163 pdbentry.setFile("INLINE" + pdb.id);
166 } catch (Exception ex)
168 ex.printStackTrace();
172 pdbentry.setId(pdb.id);
174 ssm.addStructureViewerListener(this);
185 // JUST DEAL WITH ONE SEQUENCE FOR NOW
186 SequenceI sequence = seq[0];
188 for (int i = 0; i < pdb.chains.size(); i++)
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()
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
206 as.calcScoreMatrix();
208 PrintStream ps = new PrintStream(System.out)
210 public void print(String x)
212 mappingDetails.append(x);
215 public void println()
217 mappingDetails.append("\n");
221 as.printAlignment(ps);
223 if (as.maxscore > max)
228 pdbstart = as.seq2start;
230 seqstart = as.seq1start + sequence.getStart() - 1;
231 seqend = as.seq1end + sequence.getEnd() - 1;
234 mappingDetails.append("\nPDB start/end " + pdbstart + " " + pdbend);
235 mappingDetails.append("\nSEQ start/end " + seqstart + " " + seqend);
238 mainchain = pdb.chains.elementAt(maxchain);
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);
248 this.prefsize = new Dimension(getSize().width, getSize().height);
250 // Initialize the matrices to identity
251 for (int i = 0; i < 3; i++)
253 for (int j = 0; j < 3; j++)
257 idmat.addElement(i, j, 0);
258 objmat.addElement(i, j, 0);
262 idmat.addElement(i, j, 1);
263 objmat.addElement(i, j, 1);
268 addMouseMotionListener(this);
269 addMouseListener(this);
271 addKeyListener(new KeyAdapter()
273 public void keyPressed(KeyEvent evt)
287 Vector<Bond> visiblebonds;
291 seqColoursReady = false;
292 // Sort the bonds by z coord
293 visiblebonds = new Vector<Bond>();
295 for (int ii = 0; ii < pdb.chains.size(); ii++)
297 if (pdb.chains.elementAt(ii).isVisible)
299 Vector<Bond> tmp = pdb.chains.elementAt(ii).bonds;
301 for (int i = 0; i < tmp.size(); i++)
303 visiblebonds.addElement(tmp.elementAt(i));
307 seqColoursReady = true;
313 public void findWidth()
315 float[] max = new float[3];
316 float[] min = new float[3];
318 max[0] = (float) -1e30;
319 max[1] = (float) -1e30;
320 max[2] = (float) -1e30;
322 min[0] = (float) 1e30;
323 min[1] = (float) 1e30;
324 min[2] = (float) 1e30;
326 for (int ii = 0; ii < pdb.chains.size(); ii++)
328 if (pdb.chains.elementAt(ii).isVisible)
330 Vector<Bond> bonds = pdb.chains.elementAt(ii).bonds;
332 for (Bond tmp : bonds)
334 if (tmp.start[0] >= max[0])
336 max[0] = tmp.start[0];
339 if (tmp.start[1] >= max[1])
341 max[1] = tmp.start[1];
344 if (tmp.start[2] >= max[2])
346 max[2] = tmp.start[2];
349 if (tmp.start[0] <= min[0])
351 min[0] = tmp.start[0];
354 if (tmp.start[1] <= min[1])
356 min[1] = tmp.start[1];
359 if (tmp.start[2] <= min[2])
361 min[2] = tmp.start[2];
364 if (tmp.end[0] >= max[0])
369 if (tmp.end[1] >= max[1])
374 if (tmp.end[2] >= max[2])
379 if (tmp.end[0] <= min[0])
384 if (tmp.end[1] <= min[1])
389 if (tmp.end[2] <= min[2])
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]);
403 if (width[1] > width[0])
408 if (width[2] > width[1])
413 // System.out.println("Maxwidth = " + maxwidth);
416 public float findScale()
422 if (getSize().width != 0)
424 width = getSize().width;
425 height = getSize().height;
429 width = prefsize.width;
430 height = prefsize.height;
442 return (float) (dim / (1.5d * maxwidth));
445 public void findCentre()
453 // Find centre coordinate
454 for (int ii = 0; ii < pdb.chains.size(); ii++)
456 if (pdb.chains.elementAt(ii).isVisible)
458 Vector<Bond> bonds = pdb.chains.elementAt(ii).bonds;
460 bsize += bonds.size();
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];
471 centre[0] = xtot / (2 * (float) bsize);
472 centre[1] = ytot / (2 * (float) bsize);
473 centre[2] = ztot / (2 * (float) bsize);
476 public void paint(Graphics g)
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));
486 MessageManager.getString("label.error_loading_pdb_data"), 50,
487 getSize().height / 2);
491 if (!seqColoursReady)
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);
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))
508 prefsize.width = getSize().width;
509 prefsize.height = getSize().height;
512 img = createImage(prefsize.width, prefsize.height);
513 ig = img.getGraphics();
516 } catch (Exception ex)
518 ex.printStackTrace();
524 drawAll(ig, prefsize.width, prefsize.height);
525 redrawneeded = false;
527 if (appletToolTip != null)
529 ig.setColor(Color.red);
530 ig.drawString(appletToolTip, toolx, tooly);
533 g.drawImage(img, 0, 0, this);
538 public void drawAll(Graphics g, int width, int height)
540 ig.setColor(Color.black);
541 ig.fillRect(0, 0, width, height);
546 public void setColours(jalview.schemes.ColourSchemeI cs)
554 // This method has been taken out of PDBChain to allow
555 // Applet and Application specific sequence renderers to be used
556 void colourBySequence()
558 SequenceRenderer sr = new SequenceRenderer(ap.av);
560 StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
562 boolean showFeatures = false;
563 if (ap.av.isShowSequenceFeatures())
567 fr = new jalview.appletgui.FeatureRenderer(ap.av);
570 fr.transferSettings(ap.getFeatureRenderer());
576 if (bysequence && pdb != null)
578 for (int ii = 0; ii < pdb.chains.size(); ii++)
580 chain = pdb.chains.elementAt(ii);
582 for (int i = 0; i < chain.bonds.size(); i++)
584 Bond tmp = chain.bonds.elementAt(i);
585 tmp.startCol = Color.lightGray;
586 tmp.endCol = Color.lightGray;
587 if (chain != mainchain)
592 for (int s = 0; s < sequence.length; s++)
594 for (int m = 0; m < mapping.length; m++)
596 if (mapping[m].getSequence() == sequence[s])
598 int pos = mapping[m].getSeqPos(tmp.at1.resNumber) - 1;
601 pos = sequence[s].findIndex(pos);
602 tmp.startCol = sr.getResidueBoxColour(sequence[s], pos);
605 tmp.startCol = fr.findFeatureColour(tmp.startCol,
609 pos = mapping[m].getSeqPos(tmp.at2.resNumber) - 1;
612 pos = sequence[s].findIndex(pos);
613 tmp.endCol = sr.getResidueBoxColour(sequence[s], pos);
616 tmp.endCol = fr.findFeatureColour(tmp.endCol,
631 public void drawScene(Graphics g)
640 zsort.sort(visiblebonds);
644 for (int i = 0; i < visiblebonds.size(); i++)
646 tmpBond = visiblebonds.elementAt(i);
648 xstart = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getSize().width / 2));
649 ystart = (int) (((centre[1] - tmpBond.start[1]) * scale) + (getSize().height / 2));
651 xend = (int) (((tmpBond.end[0] - centre[0]) * scale) + (getSize().width / 2));
652 yend = (int) (((centre[1] - tmpBond.end[1]) * scale) + (getSize().height / 2));
654 xmid = (xend + xstart) / 2;
655 ymid = (yend + ystart) / 2;
657 if (depthcue && !bymolecule)
659 if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
661 g.setColor(tmpBond.startCol.darker().darker());
662 drawLine(g, xstart, ystart, xmid, ymid);
664 g.setColor(tmpBond.endCol.darker().darker());
665 drawLine(g, xmid, ymid, xend, yend);
667 else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
669 g.setColor(tmpBond.startCol.darker());
670 drawLine(g, xstart, ystart, xmid, ymid);
672 g.setColor(tmpBond.endCol.darker());
673 drawLine(g, xmid, ymid, xend, yend);
677 g.setColor(tmpBond.startCol);
678 drawLine(g, xstart, ystart, xmid, ymid);
680 g.setColor(tmpBond.endCol);
681 drawLine(g, xmid, ymid, xend, yend);
685 else if (depthcue && bymolecule)
687 if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
689 g.setColor(Color.green.darker().darker());
690 drawLine(g, xstart, ystart, xend, yend);
692 else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
694 g.setColor(Color.green.darker());
695 drawLine(g, xstart, ystart, xend, yend);
699 g.setColor(Color.green);
700 drawLine(g, xstart, ystart, xend, yend);
703 else if (!depthcue && !bymolecule)
705 g.setColor(tmpBond.startCol);
706 drawLine(g, xstart, ystart, xmid, ymid);
707 g.setColor(tmpBond.endCol);
708 drawLine(g, xmid, ymid, xend, yend);
712 drawLine(g, xstart, ystart, xend, yend);
715 if (highlightBond1 != null && highlightBond1 == tmpBond)
717 g.setColor(Color.white);
718 drawLine(g, xmid, ymid, xend, yend);
721 if (highlightBond2 != null && highlightBond2 == tmpBond)
723 g.setColor(Color.white);
724 drawLine(g, xstart, ystart, xmid, ymid);
730 public void drawLine(Graphics g, int x1, int y1, int x2, int y2)
734 if (((float) Math.abs(y2 - y1) / (float) Math.abs(x2 - x1)) < 0.5)
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);
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);
750 g.drawLine(x1, y1, x2, y2);
754 public Dimension minimumsize()
759 public Dimension preferredsize()
764 public void doKeyPressed(KeyEvent evt)
766 if (evt.getKeyCode() == KeyEvent.VK_UP)
768 scale = (float) (scale * 1.1);
772 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
774 scale = (float) (scale * 0.9);
780 public void mousePressed(MouseEvent e)
783 Atom fatom = findAtom(e.getX(), e.getY());
786 fatom.isSelected = !fatom.isSelected;
790 if (foundchain != -1)
792 PDBChain chain = pdb.chains.elementAt(foundchain);
793 if (chain == mainchain)
795 if (fatom.alignmentMapping != -1)
797 if (highlightRes == null)
799 highlightRes = new Vector<String>();
802 final String atomString = Integer
803 .toString(fatom.alignmentMapping);
804 if (highlightRes.contains(atomString))
806 highlightRes.removeElement(atomString);
810 highlightRes.addElement(atomString);
824 public void mouseMoved(MouseEvent e)
827 if (highlightBond1 != null)
829 highlightBond1.at2.isSelected = false;
830 highlightBond2.at1.isSelected = false;
831 highlightBond1 = null;
832 highlightBond2 = null;
835 Atom fatom = findAtom(e.getX(), e.getY());
837 PDBChain chain = null;
838 if (foundchain != -1)
840 chain = pdb.chains.elementAt(foundchain);
841 if (chain == mainchain)
843 mouseOverStructure(fatom.resNumber, chain.id);
852 appletToolTip = chain.id + ":" + fatom.resNumber + " "
859 mouseOverStructure(-1, chain != null ? chain.id : null);
860 appletToolTip = null;
866 public void mouseClicked(MouseEvent e)
870 public void mouseEntered(MouseEvent e)
874 public void mouseExited(MouseEvent e)
878 public void mouseDragged(MouseEvent evt)
885 MCMatrix objmat = new MCMatrix(3, 3);
886 objmat.setIdentity();
888 if ((evt.getModifiers() & Event.META_MASK) != 0)
890 objmat.rotatez(((mx - omx)));
894 objmat.rotatex(((omy - my)));
895 objmat.rotatey(((omx - mx)));
899 for (PDBChain chain : pdb.chains)
901 for (Bond tmpBond : chain.bonds)
903 // Translate the bond so the centre is 0,0,0
904 tmpBond.translate(-centre[0], -centre[1], -centre[2]);
906 // Now apply the rotation matrix
907 tmpBond.start = objmat.vectorMultiply(tmpBond.start);
908 tmpBond.end = objmat.vectorMultiply(tmpBond.end);
910 // Now translate back again
911 tmpBond.translate(centre[0], centre[1], centre[2]);
927 public void mouseReleased(MouseEvent evt)
933 void drawLabels(Graphics g)
936 for (PDBChain chain : pdb.chains)
940 for (Bond tmpBond : chain.bonds)
942 if (tmpBond.at1.isSelected)
944 labelAtom(g, tmpBond, 1);
947 if (tmpBond.at2.isSelected)
949 labelAtom(g, tmpBond, 2);
956 public void labelAtom(Graphics g, Bond b, int n)
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));
965 g.setColor(Color.red);
966 g.drawString(b.at1.resName + "-" + b.at1.resNumber, xstart, ystart);
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));
974 g.setColor(Color.red);
975 g.drawString(b.at2.resName + "-" + b.at2.resNumber, xstart, ystart);
981 public Atom findAtom(int x, int y)
987 for (int ii = 0; ii < pdb.chains.size(); ii++)
989 PDBChain chain = pdb.chains.elementAt(ii);
995 Vector<Bond> bonds = pdb.chains.elementAt(ii).bonds;
997 for (int i = 0; i < bonds.size(); i++)
999 tmpBond = bonds.elementAt(i);
1001 truex = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getSize().width / 2));
1003 if (Math.abs(truex - x) <= 2)
1005 int truey = (int) (((centre[1] - tmpBond.start[1]) * scale) + (getSize().height / 2));
1007 if (Math.abs(truey - y) <= 2)
1009 fatom = tmpBond.at1;
1016 // Still here? Maybe its the last bond
1018 truex = (int) (((tmpBond.end[0] - centre[0]) * scale) + (getSize().width / 2));
1020 if (Math.abs(truex - x) <= 2)
1022 int truey = (int) (((tmpBond.end[1] - centre[1]) * scale) + (getSize().height / 2));
1024 if (Math.abs(truey - y) <= 2)
1026 fatom = tmpBond.at2;
1034 if (fatom != null) // )&& chain.ds != null)
1036 chain = pdb.chains.elementAt(foundchain);
1043 public void update(Graphics g)
1048 public void highlightRes(int ii)
1050 if (!seqColoursReady)
1055 if (highlightRes != null && highlightRes.contains((ii - 1) + ""))
1062 for (index = 0; index < mainchain.bonds.size(); index++)
1064 tmpBond = mainchain.bonds.elementAt(index);
1065 if (tmpBond.at1.alignmentMapping == ii - 1)
1067 if (highlightBond1 != null)
1069 highlightBond1.at2.isSelected = false;
1072 if (highlightBond2 != null)
1074 highlightBond2.at1.isSelected = false;
1077 highlightBond1 = null;
1078 highlightBond2 = null;
1082 highlightBond1 = mainchain.bonds.elementAt(index - 1);
1083 highlightBond1.at2.isSelected = true;
1086 if (index != mainchain.bonds.size())
1088 highlightBond2 = mainchain.bonds.elementAt(index);
1089 highlightBond2.at1.isSelected = true;
1096 redrawneeded = true;
1100 public void setAllchainsVisible(boolean b)
1102 for (int ii = 0; ii < pdb.chains.size(); ii++)
1104 PDBChain chain = pdb.chains.elementAt(ii);
1105 chain.isVisible = b;
1107 mainchain.isVisible = true;
1112 // ////////////////////////////////
1113 // /StructureListener
1114 public String[] getPdbFile()
1117 { pdbentry.getFile() };
1122 public void mouseOverStructure(int pdbResNum, String chain)
1124 if (lastMessage == null || !lastMessage.equals(pdbResNum + chain))
1126 ssm.mouseOverStructure(pdbResNum, chain, pdbentry.getFile());
1129 lastMessage = pdbResNum + chain;
1132 StringBuffer resetLastRes = new StringBuffer();
1134 StringBuffer eval = new StringBuffer();
1137 * Highlight the specified atoms in the structure.
1142 public void highlightAtoms(List<AtomSpec> atoms)
1144 if (!seqColoursReady)
1148 for (AtomSpec atom : atoms)
1150 int atomIndex = atom.getAtomIndex();
1152 if (highlightRes != null
1153 && highlightRes.contains((atomIndex - 1) + ""))
1158 highlightAtom(atomIndex);
1161 redrawneeded = true;
1168 protected void highlightAtom(int atomIndex)
1172 for (index = 0; index < mainchain.bonds.size(); index++)
1174 tmpBond = mainchain.bonds.elementAt(index);
1175 if (tmpBond.at1.atomIndex == atomIndex)
1177 if (highlightBond1 != null)
1179 highlightBond1.at2.isSelected = false;
1182 if (highlightBond2 != null)
1184 highlightBond2.at1.isSelected = false;
1187 highlightBond1 = null;
1188 highlightBond2 = null;
1192 highlightBond1 = mainchain.bonds.elementAt(index - 1);
1193 highlightBond1.at2.isSelected = true;
1196 if (index != mainchain.bonds.size())
1198 highlightBond2 = mainchain.bonds.elementAt(index);
1199 highlightBond2.at1.isSelected = true;
1207 public Color getColour(int atomIndex, int pdbResNum, String chain,
1211 // if (!pdbfile.equals(pdbentry.getFile()))
1214 // return new Color(viewer.getAtomArgb(atomIndex));
1217 public void updateColours(Object source)
1220 redrawneeded = true;
1225 public void releaseReferences(Object svl)
1227 // TODO Auto-generated method stub