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.util.ArrayList;
29 import java.util.Collections;
30 import java.util.List;
32 import javax.swing.JInternalFrame;
33 import javax.swing.JMenu;
34 import javax.swing.JMenuItem;
35 import javax.swing.event.InternalFrameAdapter;
36 import javax.swing.event.InternalFrameEvent;
38 import jalview.api.AlignmentViewPanel;
39 import jalview.api.FeatureRenderer;
40 import jalview.bin.Cache;
41 import jalview.datamodel.PDBEntry;
42 import jalview.datamodel.SequenceI;
43 import jalview.ext.rbvi.chimera.JalviewChimeraBinding;
44 import jalview.gui.StructureViewer.ViewerType;
45 import jalview.io.DataSourceType;
46 import jalview.io.StructureFile;
47 import jalview.structures.models.AAStructureBindingModel;
48 import jalview.util.ImageMaker.TYPE;
49 import jalview.util.MessageManager;
50 import jalview.util.Platform;
53 * GUI elements for handling an external chimera display
58 public class ChimeraViewFrame extends StructureViewerBase
60 private JalviewChimeraBinding jmb;
63 * Path to Chimera session file. This is set when an open Jalview/Chimera
64 * session is saved, or on restore from a Jalview project (if it holds the
65 * filename of any saved Chimera sessions).
67 private String chimeraSessionFile = null;
69 private int myWidth = 500;
71 private int myHeight = 150;
74 * Initialise menu options.
77 protected void initMenus()
81 savemenu.setVisible(false); // not yet implemented
82 viewMenu.add(fitToWindow);
84 JMenuItem writeFeatures = new JMenuItem(
85 MessageManager.getString("label.create_viewer_attributes"));
86 writeFeatures.setToolTipText(MessageManager
87 .getString("label.create_viewer_attributes_tip"));
88 writeFeatures.addActionListener(new ActionListener()
91 public void actionPerformed(ActionEvent e)
93 sendFeaturesToChimera();
96 viewerActionMenu.add(writeFeatures);
98 final JMenu fetchAttributes = new JMenu(
99 MessageManager.getString("label.fetch_chimera_attributes"));
100 fetchAttributes.setToolTipText(
101 MessageManager.getString("label.fetch_chimera_attributes_tip"));
102 fetchAttributes.addMouseListener(new MouseAdapter()
106 public void mouseEntered(MouseEvent e)
108 buildAttributesMenu(fetchAttributes);
111 viewerActionMenu.add(fetchAttributes);
115 * Query Chimera for its residue attribute names and add them as items off the
118 * @param attributesMenu
120 protected void buildAttributesMenu(JMenu attributesMenu)
122 List<String> atts = jmb.getChimeraAttributes();
123 attributesMenu.removeAll();
124 Collections.sort(atts);
125 for (String attName : atts)
127 JMenuItem menuItem = new JMenuItem(attName);
128 menuItem.addActionListener(new ActionListener()
131 public void actionPerformed(ActionEvent e)
133 getChimeraAttributes(attName);
136 attributesMenu.add(menuItem);
141 * Read residues in Chimera with the given attribute name, and set as features
142 * on the corresponding sequence positions (if any)
146 protected void getChimeraAttributes(String attName)
148 jmb.copyStructureAttributesToFeatures(attName, getAlignmentPanel());
152 * Sends command(s) to the structure viewer to create residue attributes for
153 * visible Jalview features
155 protected void sendFeaturesToChimera()
158 int count = jmb.sendFeaturesToViewer(getAlignmentPanel());
160 MessageManager.formatMessage("label.attributes_set", count));
164 * open a single PDB structure in a new Chimera view
171 public ChimeraViewFrame(PDBEntry pdbentry, SequenceI[] seq,
172 String[] chains, final AlignmentPanel ap)
176 openNewChimera(ap, new PDBEntry[] { pdbentry },
182 * Create a helper to manage progress bar display
184 protected void createProgressBar()
186 if (getProgressIndicator() == null)
188 setProgressIndicator(new ProgressBar(statusPanel, statusBar));
192 private void openNewChimera(AlignmentPanel ap, PDBEntry[] pdbentrys,
196 jmb = newBindingModel(ap, pdbentrys, seqs);
197 addAlignmentPanel(ap);
198 useAlignmentPanelForColourbyseq(ap);
200 if (pdbentrys.length > 1)
202 useAlignmentPanelForSuperposition(ap);
204 jmb.setColourBySequence(true);
205 setSize(myWidth, myHeight);
208 addingStructures = false;
209 worker = new Thread(this);
212 this.addInternalFrameListener(new InternalFrameAdapter()
215 public void internalFrameClosing(
216 InternalFrameEvent internalFrameEvent)
224 protected JalviewChimeraBindingModel newBindingModel(AlignmentPanel ap,
225 PDBEntry[] pdbentrys, SequenceI[][] seqs)
227 return new JalviewChimeraBindingModel(this,
228 ap.getStructureSelectionManager(), pdbentrys, seqs, null);
232 * Create a new viewer from saved session state data including Chimera session
235 * @param chimeraSessionFile
239 * @param colourByChimera
240 * @param colourBySequence
243 public ChimeraViewFrame(String chimeraSessionFile,
244 AlignmentPanel alignPanel, PDBEntry[] pdbArray,
245 SequenceI[][] seqsArray, boolean colourByChimera,
246 boolean colourBySequence, String newViewId)
249 setViewId(newViewId);
250 this.chimeraSessionFile = chimeraSessionFile;
251 openNewChimera(alignPanel, pdbArray, seqsArray);
254 jmb.setColourBySequence(false);
255 seqColour.setSelected(false);
256 viewerColour.setSelected(true);
258 else if (colourBySequence)
260 jmb.setColourBySequence(true);
261 seqColour.setSelected(true);
262 viewerColour.setSelected(false);
267 * create a new viewer containing several structures, optionally superimposed
268 * using the given alignPanel.
274 public ChimeraViewFrame(PDBEntry[] pe, boolean alignAdded,
279 setAlignAddedStructures(alignAdded);
280 openNewChimera(ap, pe, seqs);
284 * Default constructor
286 public ChimeraViewFrame()
291 * closeViewer will decide whether or not to close this frame
292 * depending on whether user chooses to Cancel or not
294 setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
298 * Launch Chimera. If we have a chimera session file name, send Chimera the
299 * command to open its saved session file.
303 jmb.setFinishedInit(false);
304 Desktop.addInternalFrame(this,
305 jmb.getViewerTitle(getViewerName(), true), getBounds().width,
308 if (!jmb.launchChimera())
310 JvOptionPane.showMessageDialog(Desktop.desktop,
311 MessageManager.formatMessage("label.open_viewer_failed",
313 MessageManager.getString("label.error_loading_file"),
314 JvOptionPane.ERROR_MESSAGE);
319 if (this.chimeraSessionFile != null)
321 boolean opened = jmb.openSession(chimeraSessionFile);
324 System.err.println("An error occurred opening Chimera session file "
325 + chimeraSessionFile);
329 jmb.startChimeraListener();
333 * Open any newly added PDB structures in Chimera, having first fetched data
334 * from PDB (if not already saved).
340 // todo - record which pdbids were successfully imported.
341 StringBuilder errormsgs = new StringBuilder(128);
342 StringBuilder files = new StringBuilder(128);
343 List<PDBEntry> filePDB = new ArrayList<>();
344 List<Integer> filePDBpos = new ArrayList<>();
345 PDBEntry thePdbEntry = null;
346 StructureFile pdb = null;
349 String[] curfiles = jmb.getStructureFiles(); // files currently in viewer
350 // TODO: replace with reference fetching/transfer code (validate PDBentry
352 for (int pi = 0; pi < jmb.getPdbCount(); pi++)
355 thePdbEntry = jmb.getPdbEntry(pi);
356 if (thePdbEntry.getFile() == null)
359 * Retrieve PDB data, save to file, attach to PDBEntry
361 file = fetchPdbFile(thePdbEntry);
364 errormsgs.append("'" + thePdbEntry.getId() + "' ");
370 * Got file already - ignore if already loaded in Chimera.
372 file = new File(thePdbEntry.getFile()).getAbsoluteFile()
374 if (curfiles != null && curfiles.length > 0)
376 addingStructures = true; // already files loaded.
377 for (int c = 0; c < curfiles.length; c++)
379 if (curfiles[c].equals(file))
389 filePDB.add(thePdbEntry);
390 filePDBpos.add(Integer.valueOf(pi));
391 files.append(" \"" + Platform.escapeBackslashes(file) + "\"");
394 } catch (OutOfMemoryError oomerror)
396 new OOMWarning("Retrieving PDB files: " + thePdbEntry.getId(),
398 } catch (Exception ex)
400 ex.printStackTrace();
402 "When retrieving pdbfiles for '" + thePdbEntry.getId() + "'");
404 if (errormsgs.length() > 0)
407 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
408 MessageManager.formatMessage(
409 "label.pdb_entries_couldnt_be_retrieved", new Object[]
410 { errormsgs.toString() }),
411 MessageManager.getString("label.couldnt_load_file"),
412 JvOptionPane.ERROR_MESSAGE);
415 if (files.length() > 0)
417 jmb.setFinishedInit(false);
418 if (!addingStructures)
423 } catch (Exception ex)
425 Cache.log.error("Couldn't open Chimera viewer!", ex);
429 for (PDBEntry pe : filePDB)
432 if (pe.getFile() != null)
436 int pos = filePDBpos.get(num).intValue();
437 long startTime = startProgressBar(getViewerName() + " "
438 + MessageManager.getString("status.opening_file_for")
441 jmb.addSequence(pos, jmb.getSequence()[pos]);
442 File fl = new File(pe.getFile());
443 DataSourceType protocol = DataSourceType.URL;
448 protocol = DataSourceType.FILE;
450 } catch (Throwable e)
454 stopProgressBar("", startTime);
456 // Explicitly map to the filename used by Chimera ;
458 pdb = jmb.getSsm().setMapping(jmb.getSequence()[pos],
459 jmb.getChains()[pos], pe.getFile(), protocol,
460 getProgressIndicator());
461 jmb.stashFoundChains(pdb, pe.getFile());
463 } catch (OutOfMemoryError oomerror)
466 "When trying to open and map structures from Chimera!",
468 } catch (Exception ex)
471 "Couldn't open " + pe.getFile() + " in Chimera viewer!",
475 Cache.log.debug("File locations are " + files);
481 jmb.setFinishedInit(true);
482 jmb.setLoadingFromArchive(false);
485 * ensure that any newly discovered features (e.g. RESNUM)
486 * are added to any open feature settings dialog
488 FeatureRenderer fr = getBinding().getFeatureRenderer(null);
494 // refresh the sequence colours for the new structure(s)
495 for (AlignmentViewPanel ap : _colourwith)
497 jmb.updateColours(ap);
499 // do superposition if asked to
500 if (alignAddedStructures)
502 new Thread(new Runnable()
507 alignStructsWithAllAlignPanels();
511 addingStructures = false;
518 public void makePDBImage(TYPE imageType)
520 throw new UnsupportedOperationException(
521 "Image export for Chimera is not implemented");
525 public AAStructureBindingModel getBinding()
531 protected void fitToWindow_actionPerformed()
537 public ViewerType getViewerType()
539 return ViewerType.CHIMERA;
543 protected String getViewerName()