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.ImageMaker.TYPE;
51 import jalview.util.MessageManager;
52 import jalview.util.Platform;
55 * GUI elements for handling an external chimera display
60 public class ChimeraViewFrame extends StructureViewerBase
62 private JalviewChimeraBinding jmb;
65 * Path to Chimera session file. This is set when an open Jalview/Chimera
66 * session is saved, or on restore from a Jalview project (if it holds the
67 * filename of any saved Chimera sessions).
69 private String chimeraSessionFile = null;
71 private int myWidth = 500;
73 private int myHeight = 150;
76 * Initialise menu options.
79 protected void initMenus()
83 viewerActionMenu.setText(MessageManager.getString("label.chimera"));
85 helpItem.setText(MessageManager.getString("label.chimera_help"));
86 savemenu.setVisible(false); // not yet implemented
87 viewMenu.add(fitToWindow);
89 JMenuItem writeFeatures = new JMenuItem(
90 MessageManager.getString("label.create_chimera_attributes"));
91 writeFeatures.setToolTipText(MessageManager
92 .getString("label.create_chimera_attributes_tip"));
93 writeFeatures.addActionListener(new ActionListener()
96 public void actionPerformed(ActionEvent e)
98 sendFeaturesToChimera();
101 viewerActionMenu.add(writeFeatures);
103 final JMenu fetchAttributes = new JMenu(
104 MessageManager.getString("label.fetch_chimera_attributes"));
105 fetchAttributes.setToolTipText(
106 MessageManager.getString("label.fetch_chimera_attributes_tip"));
107 fetchAttributes.addMouseListener(new MouseAdapter()
111 public void mouseEntered(MouseEvent e)
113 buildAttributesMenu(fetchAttributes);
116 viewerActionMenu.add(fetchAttributes);
120 * Query Chimera for its residue attribute names and add them as items off the
123 * @param attributesMenu
125 protected void buildAttributesMenu(JMenu attributesMenu)
127 List<String> atts = jmb.getChimeraAttributes();
128 attributesMenu.removeAll();
129 Collections.sort(atts);
130 for (String attName : atts)
132 JMenuItem menuItem = new JMenuItem(attName);
133 menuItem.addActionListener(new ActionListener()
136 public void actionPerformed(ActionEvent e)
138 getChimeraAttributes(attName);
141 attributesMenu.add(menuItem);
146 * Read residues in Chimera with the given attribute name, and set as features
147 * on the corresponding sequence positions (if any)
151 protected void getChimeraAttributes(String attName)
153 jmb.copyStructureAttributesToFeatures(attName, getAlignmentPanel());
157 * Send a command to Chimera to create residue attributes for Jalview features
159 * The syntax is: setattr r <attName> <attValue> <atomSpec>
161 * For example: setattr r jv_chain "Ferredoxin-1, Chloroplastic" #0:94.A
163 protected void sendFeaturesToChimera()
165 int count = jmb.sendFeaturesToViewer(getAlignmentPanel());
167 MessageManager.formatMessage("label.attributes_set", count));
171 * open a single PDB structure in a new Chimera view
178 public ChimeraViewFrame(PDBEntry pdbentry, SequenceI[] seq,
179 String[] chains, final AlignmentPanel ap)
183 openNewChimera(ap, new PDBEntry[] { pdbentry },
189 * Create a helper to manage progress bar display
191 protected void createProgressBar()
193 if (getProgressIndicator() == null)
195 setProgressIndicator(new ProgressBar(statusPanel, statusBar));
199 private void openNewChimera(AlignmentPanel ap, PDBEntry[] pdbentrys,
203 jmb = newBindingModel(ap, pdbentrys, seqs);
204 addAlignmentPanel(ap);
205 useAlignmentPanelForColourbyseq(ap);
207 if (pdbentrys.length > 1)
209 useAlignmentPanelForSuperposition(ap);
211 jmb.setColourBySequence(true);
212 setSize(myWidth, myHeight);
215 addingStructures = false;
216 worker = new Thread(this);
219 this.addInternalFrameListener(new InternalFrameAdapter()
222 public void internalFrameClosing(
223 InternalFrameEvent internalFrameEvent)
231 protected JalviewChimeraBindingModel newBindingModel(AlignmentPanel ap,
232 PDBEntry[] pdbentrys, SequenceI[][] seqs)
234 return new JalviewChimeraBindingModel(this,
235 ap.getStructureSelectionManager(), pdbentrys, seqs, null);
239 * Create a new viewer from saved session state data including Chimera session
242 * @param chimeraSessionFile
246 * @param colourByChimera
247 * @param colourBySequence
250 public ChimeraViewFrame(String chimeraSessionFile,
251 AlignmentPanel alignPanel, PDBEntry[] pdbArray,
252 SequenceI[][] seqsArray, boolean colourByChimera,
253 boolean colourBySequence, String newViewId)
256 setViewId(newViewId);
257 this.chimeraSessionFile = chimeraSessionFile;
258 openNewChimera(alignPanel, pdbArray, seqsArray);
261 jmb.setColourBySequence(false);
262 seqColour.setSelected(false);
263 viewerColour.setSelected(true);
265 else if (colourBySequence)
267 jmb.setColourBySequence(true);
268 seqColour.setSelected(true);
269 viewerColour.setSelected(false);
274 * create a new viewer containing several structures, optionally superimposed
275 * using the given alignPanel.
281 public ChimeraViewFrame(PDBEntry[] pe, boolean alignAdded,
286 setAlignAddedStructures(alignAdded);
287 openNewChimera(ap, pe, seqs);
291 * Default constructor
293 public ChimeraViewFrame()
298 * closeViewer will decide whether or not to close this frame
299 * depending on whether user chooses to Cancel or not
301 setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
305 * Launch Chimera. If we have a chimera session file name, send Chimera the
306 * command to open its saved session file.
310 jmb.setFinishedInit(false);
311 Desktop.addInternalFrame(this,
312 jmb.getViewerTitle(getViewerName(), true), getBounds().width,
315 if (!jmb.launchChimera())
317 JvOptionPane.showMessageDialog(Desktop.desktop,
318 MessageManager.formatMessage("label.open_viewer_failed",
320 MessageManager.getString("label.error_loading_file"),
321 JvOptionPane.ERROR_MESSAGE);
326 if (this.chimeraSessionFile != null)
328 boolean opened = jmb.openSession(chimeraSessionFile);
331 System.err.println("An error occurred opening Chimera session file "
332 + chimeraSessionFile);
336 jmb.startChimeraListener();
340 * Open any newly added PDB structures in Chimera, having first fetched data
341 * from PDB (if not already saved).
347 // todo - record which pdbids were successfully imported.
348 StringBuilder errormsgs = new StringBuilder(128);
349 StringBuilder files = new StringBuilder(128);
350 List<PDBEntry> filePDB = new ArrayList<>();
351 List<Integer> filePDBpos = new ArrayList<>();
352 PDBEntry thePdbEntry = null;
353 StructureFile pdb = null;
356 String[] curfiles = jmb.getStructureFiles(); // files currently in viewer
357 // TODO: replace with reference fetching/transfer code (validate PDBentry
359 for (int pi = 0; pi < jmb.getPdbCount(); pi++)
362 thePdbEntry = jmb.getPdbEntry(pi);
363 if (thePdbEntry.getFile() == null)
366 * Retrieve PDB data, save to file, attach to PDBEntry
368 file = fetchPdbFile(thePdbEntry);
371 errormsgs.append("'" + thePdbEntry.getId() + "' ");
377 * Got file already - ignore if already loaded in Chimera.
379 file = new File(thePdbEntry.getFile()).getAbsoluteFile()
381 if (curfiles != null && curfiles.length > 0)
383 addingStructures = true; // already files loaded.
384 for (int c = 0; c < curfiles.length; c++)
386 if (curfiles[c].equals(file))
396 filePDB.add(thePdbEntry);
397 filePDBpos.add(Integer.valueOf(pi));
398 files.append(" \"" + Platform.escapeBackslashes(file) + "\"");
401 } catch (OutOfMemoryError oomerror)
403 new OOMWarning("Retrieving PDB files: " + thePdbEntry.getId(),
405 } catch (Exception ex)
407 ex.printStackTrace();
409 "When retrieving pdbfiles for '" + thePdbEntry.getId() + "'");
411 if (errormsgs.length() > 0)
414 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
415 MessageManager.formatMessage(
416 "label.pdb_entries_couldnt_be_retrieved", new Object[]
417 { errormsgs.toString() }),
418 MessageManager.getString("label.couldnt_load_file"),
419 JvOptionPane.ERROR_MESSAGE);
422 if (files.length() > 0)
424 jmb.setFinishedInit(false);
425 if (!addingStructures)
430 } catch (Exception ex)
432 Cache.log.error("Couldn't open Chimera viewer!", ex);
436 for (PDBEntry pe : filePDB)
439 if (pe.getFile() != null)
443 int pos = filePDBpos.get(num).intValue();
444 long startTime = startProgressBar(getViewerName() + " "
445 + MessageManager.getString("status.opening_file_for")
448 jmb.addSequence(pos, jmb.getSequence()[pos]);
449 File fl = new File(pe.getFile());
450 DataSourceType protocol = DataSourceType.URL;
455 protocol = DataSourceType.FILE;
457 } catch (Throwable e)
461 stopProgressBar("", startTime);
463 // Explicitly map to the filename used by Chimera ;
465 pdb = jmb.getSsm().setMapping(jmb.getSequence()[pos],
466 jmb.getChains()[pos], pe.getFile(), protocol,
467 getProgressIndicator());
468 jmb.stashFoundChains(pdb, pe.getFile());
470 } catch (OutOfMemoryError oomerror)
473 "When trying to open and map structures from Chimera!",
475 } catch (Exception ex)
478 "Couldn't open " + pe.getFile() + " in Chimera viewer!",
482 Cache.log.debug("File locations are " + files);
488 jmb.setFinishedInit(true);
489 jmb.setLoadingFromArchive(false);
492 * ensure that any newly discovered features (e.g. RESNUM)
493 * are added to any open feature settings dialog
495 FeatureRenderer fr = getBinding().getFeatureRenderer(null);
501 // refresh the sequence colours for the new structure(s)
502 for (AlignmentViewPanel ap : _colourwith)
504 jmb.updateColours(ap);
506 // do superposition if asked to
507 if (alignAddedStructures)
509 new Thread(new Runnable()
514 alignStructsWithAllAlignPanels();
518 addingStructures = false;
525 public void makePDBImage(TYPE imageType)
527 throw new UnsupportedOperationException(
528 "Image export for Chimera is not implemented");
532 public void showHelp_actionPerformed()
536 String url = jmb.getHelpURL();
537 BrowserLauncher.openURL(url);
538 } catch (IOException ex)
541 .println("Show Chimera help failed with: " + ex.getMessage());
546 public AAStructureBindingModel getBinding()
552 protected void fitToWindow_actionPerformed()
558 public ViewerType getViewerType()
560 return ViewerType.CHIMERA;
564 protected String getViewerName()