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.event.ActionEvent;
24 import java.awt.event.ActionListener;
25 import java.awt.event.MouseAdapter;
26 import java.awt.event.MouseEvent;
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.List;
33 import javax.swing.JInternalFrame;
34 import javax.swing.JMenu;
35 import javax.swing.JMenuItem;
36 import javax.swing.event.InternalFrameAdapter;
37 import javax.swing.event.InternalFrameEvent;
39 import jalview.api.AlignmentViewPanel;
40 import jalview.api.FeatureRenderer;
41 import jalview.bin.Cache;
42 import jalview.datamodel.PDBEntry;
43 import jalview.datamodel.SequenceI;
44 import jalview.ext.rbvi.chimera.JalviewChimeraBinding;
45 import jalview.gui.StructureViewer.ViewerType;
46 import jalview.io.DataSourceType;
47 import jalview.io.StructureFile;
48 import jalview.structures.models.AAStructureBindingModel;
49 import jalview.util.BrowserLauncher;
50 import jalview.util.MessageManager;
51 import jalview.util.Platform;
54 * GUI elements for handling an external chimera display
59 public class ChimeraViewFrame extends StructureViewerBase
61 private JalviewChimeraBinding jmb;
64 * Path to Chimera session file. This is set when an open Jalview/Chimera
65 * session is saved, or on restore from a Jalview project (if it holds the
66 * filename of any saved Chimera sessions).
68 private String chimeraSessionFile = null;
70 private int myWidth = 500;
72 private int myHeight = 150;
75 * Initialise menu options.
78 protected void initMenus()
82 viewerActionMenu.setText(MessageManager.getString("label.chimera"));
84 helpItem.setText(MessageManager.getString("label.chimera_help"));
85 savemenu.setVisible(false); // not yet implemented
86 viewMenu.add(fitToWindow);
88 JMenuItem writeFeatures = new JMenuItem(
89 MessageManager.getString("label.create_chimera_attributes"));
90 writeFeatures.setToolTipText(MessageManager
91 .getString("label.create_chimera_attributes_tip"));
92 writeFeatures.addActionListener(new ActionListener()
95 public void actionPerformed(ActionEvent e)
97 sendFeaturesToChimera();
100 viewerActionMenu.add(writeFeatures);
102 final JMenu fetchAttributes = new JMenu(
103 MessageManager.getString("label.fetch_chimera_attributes"));
104 fetchAttributes.setToolTipText(
105 MessageManager.getString("label.fetch_chimera_attributes_tip"));
106 fetchAttributes.addMouseListener(new MouseAdapter()
110 public void mouseEntered(MouseEvent e)
112 buildAttributesMenu(fetchAttributes);
115 viewerActionMenu.add(fetchAttributes);
119 * Query Chimera for its residue attribute names and add them as items off the
122 * @param attributesMenu
124 protected void buildAttributesMenu(JMenu attributesMenu)
126 List<String> atts = jmb.getChimeraAttributes();
127 attributesMenu.removeAll();
128 Collections.sort(atts);
129 for (String attName : atts)
131 JMenuItem menuItem = new JMenuItem(attName);
132 menuItem.addActionListener(new ActionListener()
135 public void actionPerformed(ActionEvent e)
137 getChimeraAttributes(attName);
140 attributesMenu.add(menuItem);
145 * Read residues in Chimera with the given attribute name, and set as features
146 * on the corresponding sequence positions (if any)
150 protected void getChimeraAttributes(String attName)
152 jmb.copyStructureAttributesToFeatures(attName, getAlignmentPanel());
156 * Send a command to Chimera to create residue attributes for Jalview features
158 * The syntax is: setattr r <attName> <attValue> <atomSpec>
160 * For example: setattr r jv_chain "Ferredoxin-1, Chloroplastic" #0:94.A
162 protected void sendFeaturesToChimera()
164 int count = jmb.sendFeaturesToViewer(getAlignmentPanel());
166 MessageManager.formatMessage("label.attributes_set", count));
170 * open a single PDB structure in a new Chimera view
177 public ChimeraViewFrame(PDBEntry pdbentry, SequenceI[] seq,
178 String[] chains, final AlignmentPanel ap)
182 openNewChimera(ap, new PDBEntry[] { pdbentry },
188 * Create a helper to manage progress bar display
190 protected void createProgressBar()
192 if (getProgressIndicator() == null)
194 setProgressIndicator(new ProgressBar(statusPanel, statusBar));
198 private void openNewChimera(AlignmentPanel ap, PDBEntry[] pdbentrys,
202 jmb = newBindingModel(ap, pdbentrys, seqs);
203 addAlignmentPanel(ap);
204 useAlignmentPanelForColourbyseq(ap);
206 if (pdbentrys.length > 1)
208 useAlignmentPanelForSuperposition(ap);
210 jmb.setColourBySequence(true);
211 setSize(myWidth, myHeight);
214 addingStructures = false;
215 worker = new Thread(this);
218 this.addInternalFrameListener(new InternalFrameAdapter()
221 public void internalFrameClosing(
222 InternalFrameEvent internalFrameEvent)
230 protected JalviewChimeraBindingModel newBindingModel(AlignmentPanel ap,
231 PDBEntry[] pdbentrys, SequenceI[][] seqs)
233 return new JalviewChimeraBindingModel(this,
234 ap.getStructureSelectionManager(), pdbentrys, seqs, null);
238 * Create a new viewer from saved session state data including Chimera session
241 * @param chimeraSessionFile
245 * @param colourByChimera
246 * @param colourBySequence
249 public ChimeraViewFrame(String chimeraSessionFile,
250 AlignmentPanel alignPanel, PDBEntry[] pdbArray,
251 SequenceI[][] seqsArray, boolean colourByChimera,
252 boolean colourBySequence, String newViewId)
255 setViewId(newViewId);
256 this.chimeraSessionFile = chimeraSessionFile;
257 openNewChimera(alignPanel, pdbArray, seqsArray);
260 jmb.setColourBySequence(false);
261 seqColour.setSelected(false);
262 viewerColour.setSelected(true);
264 else if (colourBySequence)
266 jmb.setColourBySequence(true);
267 seqColour.setSelected(true);
268 viewerColour.setSelected(false);
273 * create a new viewer containing several structures, optionally superimposed
274 * using the given alignPanel.
280 public ChimeraViewFrame(PDBEntry[] pe, boolean alignAdded,
285 setAlignAddedStructures(alignAdded);
286 openNewChimera(ap, pe, seqs);
290 * Default constructor
292 public ChimeraViewFrame()
297 * closeViewer will decide whether or not to close this frame
298 * depending on whether user chooses to Cancel or not
300 setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
304 * Launch Chimera. If we have a chimera session file name, send Chimera the
305 * command to open its saved session file.
309 jmb.setFinishedInit(false);
310 Desktop.addInternalFrame(this,
311 jmb.getViewerTitle(getViewerName(), true), getBounds().width,
314 if (!jmb.launchChimera())
316 JvOptionPane.showMessageDialog(Desktop.desktop,
317 MessageManager.formatMessage("label.open_viewer_failed",
319 MessageManager.getString("label.error_loading_file"),
320 JvOptionPane.ERROR_MESSAGE);
325 if (this.chimeraSessionFile != null)
327 boolean opened = jmb.openSession(chimeraSessionFile);
330 System.err.println("An error occurred opening Chimera session file "
331 + chimeraSessionFile);
335 jmb.startChimeraListener();
339 * Open any newly added PDB structures in Chimera, having first fetched data
340 * from PDB (if not already saved).
346 // todo - record which pdbids were successfully imported.
347 StringBuilder errormsgs = new StringBuilder(128);
348 StringBuilder files = new StringBuilder(128);
349 List<PDBEntry> filePDB = new ArrayList<>();
350 List<Integer> filePDBpos = new ArrayList<>();
351 PDBEntry thePdbEntry = null;
352 StructureFile pdb = null;
355 String[] curfiles = jmb.getStructureFiles(); // files currently in viewer
356 // TODO: replace with reference fetching/transfer code (validate PDBentry
358 for (int pi = 0; pi < jmb.getPdbCount(); pi++)
361 thePdbEntry = jmb.getPdbEntry(pi);
362 if (thePdbEntry.getFile() == null)
365 * Retrieve PDB data, save to file, attach to PDBEntry
367 file = fetchPdbFile(thePdbEntry);
370 errormsgs.append("'" + thePdbEntry.getId() + "' ");
376 * Got file already - ignore if already loaded in Chimera.
378 file = new File(thePdbEntry.getFile()).getAbsoluteFile()
380 if (curfiles != null && curfiles.length > 0)
382 addingStructures = true; // already files loaded.
383 for (int c = 0; c < curfiles.length; c++)
385 if (curfiles[c].equals(file))
395 filePDB.add(thePdbEntry);
396 filePDBpos.add(Integer.valueOf(pi));
397 files.append(" \"" + Platform.escapeBackslashes(file) + "\"");
400 } catch (OutOfMemoryError oomerror)
402 new OOMWarning("Retrieving PDB files: " + thePdbEntry.getId(),
404 } catch (Exception ex)
406 ex.printStackTrace();
408 "When retrieving pdbfiles for '" + thePdbEntry.getId() + "'");
410 if (errormsgs.length() > 0)
413 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
414 MessageManager.formatMessage(
415 "label.pdb_entries_couldnt_be_retrieved", new Object[]
416 { errormsgs.toString() }),
417 MessageManager.getString("label.couldnt_load_file"),
418 JvOptionPane.ERROR_MESSAGE);
421 if (files.length() > 0)
423 jmb.setFinishedInit(false);
424 if (!addingStructures)
429 } catch (Exception ex)
431 Cache.log.error("Couldn't open Chimera viewer!", ex);
435 for (PDBEntry pe : filePDB)
438 if (pe.getFile() != null)
442 int pos = filePDBpos.get(num).intValue();
443 long startTime = startProgressBar(getViewerName() + " "
444 + MessageManager.getString("status.opening_file_for")
447 jmb.addSequence(pos, jmb.getSequence()[pos]);
448 File fl = new File(pe.getFile());
449 DataSourceType protocol = DataSourceType.URL;
454 protocol = DataSourceType.FILE;
456 } catch (Throwable e)
460 stopProgressBar("", startTime);
462 // Explicitly map to the filename used by Chimera ;
464 pdb = jmb.getSsm().setMapping(jmb.getSequence()[pos],
465 jmb.getChains()[pos], pe.getFile(), protocol,
466 getProgressIndicator());
467 jmb.stashFoundChains(pdb, pe.getFile());
469 } catch (OutOfMemoryError oomerror)
472 "When trying to open and map structures from Chimera!",
474 } catch (Exception ex)
477 "Couldn't open " + pe.getFile() + " in Chimera viewer!",
481 Cache.log.debug("File locations are " + files);
487 jmb.setFinishedInit(true);
488 jmb.setLoadingFromArchive(false);
491 * ensure that any newly discovered features (e.g. RESNUM)
492 * are added to any open feature settings dialog
494 FeatureRenderer fr = getBinding().getFeatureRenderer(null);
500 // refresh the sequence colours for the new structure(s)
501 for (AlignmentViewPanel ap : _colourwith)
503 jmb.updateColours(ap);
505 // do superposition if asked to
506 if (alignAddedStructures)
508 new Thread(new Runnable()
513 alignStructsWithAllAlignPanels();
517 addingStructures = false;
524 public void eps_actionPerformed()
526 throw new Error(MessageManager
527 .getString("error.eps_generation_not_implemented"));
531 public void png_actionPerformed()
533 throw new Error(MessageManager
534 .getString("error.png_generation_not_implemented"));
538 public void showHelp_actionPerformed()
542 String url = jmb.getHelpURL();
543 BrowserLauncher.openURL(url);
544 } catch (IOException ex)
547 .println("Show Chimera help failed with: " + ex.getMessage());
552 public AAStructureBindingModel getBinding()
558 protected void fitToWindow_actionPerformed()
564 public ViewerType getViewerType()
566 return ViewerType.CHIMERA;
570 protected String getViewerName()