2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5)
3 * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
20 import java.util.regex.*;
24 import javax.swing.event.*;
25 import java.awt.event.*;
28 import jalview.jbgui.GStructureViewer;
29 import jalview.api.SequenceStructureBinding;
30 import jalview.bin.Cache;
31 import jalview.datamodel.*;
33 import jalview.structure.*;
34 import jalview.datamodel.PDBEntry;
36 import jalview.schemes.*;
37 import jalview.ws.ebi.EBIFetchClient;
39 import org.jmol.api.*;
40 import org.jmol.adapter.smarter.SmarterJmolAdapter;
41 import org.jmol.popup.*;
42 import org.jmol.viewer.JmolConstants;
44 public class AppJmol extends GStructureViewer implements Runnable,
45 SequenceStructureBinding
50 ScriptWindow scriptWindow;
54 RenderPanel renderPanel;
58 Vector atomsPicked = new Vector();
60 public AppJmol(String file, String id, SequenceI[] seq,
61 AlignmentPanel ap, String loadStatus, Rectangle bounds)
63 this(file, id, seq, ap, loadStatus, bounds, null);
66 public AppJmol(String file, String id, SequenceI[] seq,
67 AlignmentPanel ap, String loadStatus, Rectangle bounds,
70 PDBEntry pdbentry = new PDBEntry();
71 pdbentry.setFile(file);
73 // / TODO: check if protocol is needed to be set, and if chains are
75 jmb = new AppJmolBinding(this, new PDBEntry[]
76 { pdbentry }, new SequenceI[][] { seq }, null, null);
78 jmb.setLoadingFromArchive(true);
80 this.setBounds(bounds);
81 jmb.setColourBySequence(false);
82 seqColour.setSelected(false);
84 // jalview.gui.Desktop.addInternalFrame(this, "Loading File",
85 // bounds.width,bounds.height);
87 this.addInternalFrameListener(new InternalFrameAdapter()
89 public void internalFrameClosing(InternalFrameEvent internalFrameEvent)
94 initJmol(loadStatus); // pdbentry, seq, JBPCHECK!
98 public AppJmol(PDBEntry pdbentry, SequenceI[] seq, String[] chains,
101 // ////////////////////////////////
102 // Is the pdb file already loaded?
103 String alreadyMapped = StructureSelectionManager
104 .getStructureSelectionManager().alreadyMappedToFile(
107 if (alreadyMapped != null)
109 int option = JOptionPane
110 .showInternalConfirmDialog(
113 + " is already displayed."
114 + "\nDo you want to re-use this viewer ?",
115 "Map Sequences to Visible Window: "
116 + pdbentry.getId(), JOptionPane.YES_NO_OPTION);
118 if (option == JOptionPane.YES_OPTION)
120 StructureSelectionManager.getStructureSelectionManager()
121 .setMapping(seq, chains, alreadyMapped,
122 AppletFormatAdapter.FILE);
123 if (ap.seqPanel.seqCanvas.fr != null)
125 ap.seqPanel.seqCanvas.fr.featuresAdded();
126 ap.paintAlignment(true);
129 // Now this AppJmol is mapped to new sequences. We must add them to
130 // the exisiting array
131 JInternalFrame[] frames = Desktop.instance.getAllFrames();
133 for (int i = 0; i < frames.length; i++)
135 if (frames[i] instanceof AppJmol)
137 AppJmol topJmol = ((AppJmol) frames[i]);
138 // JBPNOTE: this looks like a binding routine, rather than a gui
140 for (int pe = 0; pe < topJmol.jmb.pdbentry.length; pe++)
142 if (topJmol.jmb.pdbentry[pe].getFile().equals(alreadyMapped))
144 topJmol.jmb.addSequence(pe, seq);
154 // /////////////////////////////////
155 // Check if there are other Jmol views involving this alignment
156 // and prompt user about adding this molecule to one of them
157 Vector existingViews = getJmolsFor(ap);
158 if (existingViews.size()>0)
160 Enumeration jm = existingViews.elements();
161 while (jm.hasMoreElements()) {
162 AppJmol topJmol = (AppJmol) jm.nextElement();
163 // TODO: highlight topJmol in view somehow
164 int option = JOptionPane
165 .showInternalConfirmDialog(
166 Desktop.desktop, "Do you want to add "+
167 pdbentry.getId()+" to the view called\n'"+topJmol.getTitle()
169 "Align to existing structure view"
170 , JOptionPane.YES_NO_OPTION);
171 if (option == JOptionPane.YES_OPTION)
173 topJmol.jmb.addStructure(pdbentry, seq, chains,true);
178 // /////////////////////////////////
180 jmb = new AppJmolBinding(this, new PDBEntry[]
181 { pdbentry }, new SequenceI[][]{seq}, null, null);
183 setSize(400, 400); // probably should be a configurable/dynamic default here
185 if (pdbentry.getFile() != null)
187 initJmol("load \"" + pdbentry.getFile() + "\"");
191 Thread worker = new Thread(this);
195 this.addInternalFrameListener(new InternalFrameAdapter()
197 public void internalFrameClosing(InternalFrameEvent internalFrameEvent)
205 private Vector getJmolsFor(AlignmentPanel ap2)
207 Vector otherJmols= new Vector();
208 // Now this AppJmol is mapped to new sequences. We must add them to
209 // the exisiting array
210 JInternalFrame[] frames = Desktop.instance.getAllFrames();
212 for (int i = 0; i < frames.length; i++)
214 if (frames[i] instanceof AppJmol)
216 AppJmol topJmol = ((AppJmol) frames[i]);
219 otherJmols.addElement(topJmol);
226 void initJmol(String command)
228 jmb.setFinishedInit(false);
229 renderPanel = new RenderPanel();
230 // TODO: consider waiting until the structure/view is fully loaded before
232 this.getContentPane().add(renderPanel, java.awt.BorderLayout.CENTER);
233 jalview.gui.Desktop.addInternalFrame(this, jmb.getViewerTitle(),
234 getBounds().width, getBounds().height);
235 jmb.allocateViewer(renderPanel, true, "", null, null, "");
236 jmb.newJmolPopup(true, "Jmol", true);
237 jmb.evalStateCommand(command);
238 jmb.setFinishedInit(true);
241 void setChainMenuItems(Vector chains)
243 chainMenu.removeAll();
248 JMenuItem menuItem = new JMenuItem("All");
249 menuItem.addActionListener(new ActionListener()
251 public void actionPerformed(ActionEvent evt)
253 allChainsSelected = true;
254 for (int i = 0; i < chainMenu.getItemCount(); i++)
256 if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
257 ((JCheckBoxMenuItem) chainMenu.getItem(i)).setSelected(true);
260 allChainsSelected = false;
264 chainMenu.add(menuItem);
266 for (int c = 0; c < chains.size(); c++)
268 menuItem = new JCheckBoxMenuItem(chains.elementAt(c).toString(), true);
269 menuItem.addItemListener(new ItemListener()
271 public void itemStateChanged(ItemEvent evt)
273 if (!allChainsSelected)
278 chainMenu.add(menuItem);
282 boolean allChainsSelected = false;
286 Vector toshow = new Vector();
288 int mlength, p, mnum;
289 for (int i = 0; i < chainMenu.getItemCount(); i++)
291 if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
293 JCheckBoxMenuItem item = (JCheckBoxMenuItem) chainMenu.getItem(i);
294 if (item.isSelected())
296 toshow.addElement(item.getText());
300 jmb.centerViewer(toshow);
306 // TODO: check for memory leaks where instance isn't finalised because jmb
307 // holds a reference to the window
314 // todo - record which pdbids were successfuly imported.
315 StringBuffer errormsgs = new StringBuffer(), files = new StringBuffer();
318 // TODO: replace with reference fetching/transfer code (validate PDBentry
320 jalview.ws.dbsources.Pdb pdbclient = new jalview.ws.dbsources.Pdb();
321 for (int pi = 0; pi < jmb.pdbentry.length; pi++)
324 if ((pdbseq = pdbclient.getSequenceRecords(pdbid = jmb.pdbentry[pi]
328 // just transfer the file name from the first sequence's first
330 jmb.pdbentry[pi].setFile(file = ((PDBEntry) pdbseq.getSequenceAt(
331 0).getPDBId().elementAt(0)).getFile());
332 files.append("\"" + file + "\"");
336 errormsgs.append("'" + pdbid + "' ");
339 } catch (OutOfMemoryError oomerror)
341 new OOMWarning("Retrieving PDB id " + pdbid, oomerror);
342 } catch (Exception ex)
344 ex.printStackTrace();
345 errormsgs.append("'" + pdbid + "'");
347 if (errormsgs.length() > 0)
350 JOptionPane.showInternalMessageDialog(Desktop.desktop,
351 "The following pdb entries could not be retrieved from the PDB:\n"
352 + errormsgs.toString()
353 + "\nPlease try downloading them manually.",
354 "Couldn't load file", JOptionPane.ERROR_MESSAGE);
357 if (files.length() > 0)
361 initJmol("load FILES " + files.toString());
362 } catch (OutOfMemoryError oomerror)
364 new OOMWarning("When trying to open the Jmol viewer!", oomerror);
365 Cache.log.debug("File locations are " + files);
366 } catch (Exception ex)
368 Cache.log.error("Couldn't open Jmol viewer!", ex);
373 public void pdbFile_actionPerformed(ActionEvent actionEvent)
375 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
376 .getProperty("LAST_DIRECTORY"));
378 chooser.setFileView(new JalviewFileView());
379 chooser.setDialogTitle("Save PDB File");
380 chooser.setToolTipText("Save");
382 int value = chooser.showSaveDialog(this);
384 if (value == JalviewFileChooser.APPROVE_OPTION)
388 // TODO: cope with multiple PDB files in view
389 BufferedReader in = new BufferedReader(new FileReader(jmb.getPdbFile()[0]));
390 File outFile = chooser.getSelectedFile();
392 PrintWriter out = new PrintWriter(new FileOutputStream(outFile));
394 while ((data = in.readLine()) != null)
396 if (!(data.indexOf("<PRE>") > -1 || data.indexOf("</PRE>") > -1))
402 } catch (Exception ex)
404 ex.printStackTrace();
409 public void viewMapping_actionPerformed(ActionEvent actionEvent)
411 jalview.gui.CutAndPasteTransfer cap = new jalview.gui.CutAndPasteTransfer();
412 try {for (int pdbe = 0; pdbe<jmb.pdbentry.length; pdbe++) {
413 cap.appendText(StructureSelectionManager.getStructureSelectionManager()
414 .printMapping(jmb.pdbentry[pdbe].getFile()));
415 cap.appendText("\n");
416 }} catch (OutOfMemoryError e)
418 new OOMWarning("composing sequence-structure alignments for display in text box.", e);
422 jalview.gui.Desktop.addInternalFrame(cap, "PDB - Sequence Mapping",
432 public void eps_actionPerformed(ActionEvent e)
434 makePDBImage(jalview.util.ImageMaker.EPS);
443 public void png_actionPerformed(ActionEvent e)
445 makePDBImage(jalview.util.ImageMaker.PNG);
448 void makePDBImage(int type)
450 int width = getWidth();
451 int height = getHeight();
453 jalview.util.ImageMaker im;
455 if (type == jalview.util.ImageMaker.PNG)
457 im = new jalview.util.ImageMaker(this, jalview.util.ImageMaker.PNG,
458 "Make PNG image from view", width, height, null, null);
462 im = new jalview.util.ImageMaker(this, jalview.util.ImageMaker.EPS,
463 "Make EPS file from view", width, height, null, this
467 if (im.getGraphics() != null)
469 Rectangle rect = new Rectangle(width, height);
470 jmb.viewer.renderScreenImage(im.getGraphics(), rect.getSize(), rect);
475 public void seqColour_actionPerformed(ActionEvent actionEvent)
477 jmb.setColourBySequence(seqColour.isSelected());
478 // Set the colour using the current view for the associated alignframe
479 jmb.colourBySequence(ap.alignFrame.viewport.showSequenceFeatures, ap.alignFrame.viewport.alignment);
482 public void chainColour_actionPerformed(ActionEvent actionEvent)
484 chainColour.setSelected(true);
488 public void chargeColour_actionPerformed(ActionEvent actionEvent)
490 chargeColour.setSelected(true);
491 jmb.colourByCharge();
494 public void zappoColour_actionPerformed(ActionEvent actionEvent)
496 zappoColour.setSelected(true);
497 jmb.setJalviewColourScheme(new ZappoColourScheme());
500 public void taylorColour_actionPerformed(ActionEvent actionEvent)
502 taylorColour.setSelected(true);
503 jmb.setJalviewColourScheme(new TaylorColourScheme());
506 public void hydroColour_actionPerformed(ActionEvent actionEvent)
508 hydroColour.setSelected(true);
509 jmb.setJalviewColourScheme(new HydrophobicColourScheme());
512 public void helixColour_actionPerformed(ActionEvent actionEvent)
514 helixColour.setSelected(true);
515 jmb.setJalviewColourScheme(new HelixColourScheme());
518 public void strandColour_actionPerformed(ActionEvent actionEvent)
520 strandColour.setSelected(true);
521 jmb.setJalviewColourScheme(new StrandColourScheme());
524 public void turnColour_actionPerformed(ActionEvent actionEvent)
526 turnColour.setSelected(true);
527 jmb.setJalviewColourScheme(new TurnColourScheme());
530 public void buriedColour_actionPerformed(ActionEvent actionEvent)
532 buriedColour.setSelected(true);
533 jmb.setJalviewColourScheme(new BuriedColourScheme());
537 public void userColour_actionPerformed(ActionEvent actionEvent)
539 userColour.setSelected(true);
540 new UserDefinedColours(this, null);
543 public void backGround_actionPerformed(ActionEvent actionEvent)
545 java.awt.Color col = JColorChooser.showDialog(this,
546 "Select Background Colour", null);
549 jmb.setBackgroundColour(col);
553 public void jmolHelp_actionPerformed(ActionEvent actionEvent)
557 jalview.util.BrowserLauncher
558 .openURL("http://jmol.sourceforge.net/docs/JmolUserGuide/");
559 } catch (Exception ex)
564 public void showConsole(boolean showConsole)
566 if (scriptWindow == null)
567 scriptWindow = new ScriptWindow(this);
571 if (splitPane == null)
573 splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
574 splitPane.setTopComponent(renderPanel);
575 splitPane.setBottomComponent(scriptWindow);
576 this.getContentPane().add(splitPane, BorderLayout.CENTER);
579 splitPane.setDividerLocation(getHeight() - 200);
580 splitPane.validate();
584 if (splitPane != null)
585 splitPane.setVisible(false);
589 this.getContentPane().add(renderPanel, BorderLayout.CENTER);
595 class RenderPanel extends JPanel
597 final Dimension currentSize = new Dimension();
599 final Rectangle rectClip = new Rectangle();
601 public void paintComponent(Graphics g)
603 getSize(currentSize);
604 g.getClipBounds(rectClip);
606 if (jmb.fileLoadingError != null)
608 g.setColor(Color.black);
609 g.fillRect(0, 0, currentSize.width, currentSize.height);
610 g.setColor(Color.white);
611 g.setFont(new Font("Verdana", Font.BOLD, 14));
612 g.drawString("Error loading file...", 20,
613 currentSize.height / 2);
614 StringBuffer sb = new StringBuffer();
616 for (int e=0;e<jmb.pdbentry.length; e++)
618 sb.append(jmb.pdbentry[e].getId());
619 if (e<jmb.pdbentry.length-1) {
623 if (e==jmb.pdbentry.length-1 || sb.length()>20)
626 g.drawString(sb.toString(), 20, currentSize.height/2 - lines*g.getFontMetrics().getHeight());
631 if (jmb == null || jmb.viewer == null || !jmb.isFinishedInit())
633 g.setColor(Color.black);
634 g.fillRect(0, 0, currentSize.width, currentSize.height);
635 g.setColor(Color.white);
636 g.setFont(new Font("Verdana", Font.BOLD, 14));
637 g.drawString("Retrieving PDB data....", 20, currentSize.height / 2);
641 jmb.viewer.renderScreenImage(g, currentSize, rectClip);
646 String viewId = null;
648 public String getViewId()
652 viewId = System.currentTimeMillis() + "." + this.hashCode();
656 public void updateTitleAndMenus()
658 if (jmb.fileLoadingError != null && jmb.fileLoadingError.length() > 0)
663 setChainMenuItems(jmb.chainNames);
664 jmb.colourBySequence(ap.av.getShowSequenceFeatures(), ap.av.alignment);
666 this.setTitle(jmb.getViewerTitle());
667 if (jmb.getPdbFile().length>1 && jmb.sequence.length>1) {
668 jmolActionMenu.setVisible(true);
673 * @see jalview.jbgui.GStructureViewer#alignStructs_actionPerformed(java.awt.event.ActionEvent)
676 protected void alignStructs_actionPerformed(ActionEvent actionEvent)
680 jmb.superposeStructures(ap.av.getAlignment(), -1, ap.av.getColumnSelection());
681 } catch (Exception e)
683 Cache.log.info("Couldn't align structures in alignframe "+ap.alignFrame.getTitle(),e);
688 public void setJalviewColourScheme(ColourSchemeI ucs)
690 jmb.setJalviewColourScheme(ucs);