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;
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.Console;
42 import jalview.datamodel.PDBEntry;
43 import jalview.datamodel.SequenceI;
44 import jalview.datamodel.StructureViewerModel;
45 import jalview.datamodel.StructureViewerModel.StructureData;
46 import jalview.ext.rbvi.chimera.JalviewChimeraBinding;
47 import jalview.gui.StructureViewer.ViewerType;
48 import jalview.io.DataSourceType;
49 import jalview.io.StructureFile;
50 import jalview.structures.models.AAStructureBindingModel;
51 import jalview.util.ImageMaker.TYPE;
52 import jalview.util.MessageManager;
53 import jalview.util.Platform;
56 * GUI elements for handling an external chimera display
61 public class ChimeraViewFrame extends StructureViewerBase
63 private JalviewChimeraBinding jmb;
66 * Path to Chimera session file. This is set when an open Jalview/Chimera
67 * session is saved, or on restore from a Jalview project (if it holds the
68 * filename of any saved Chimera sessions).
70 private String chimeraSessionFile = null;
72 private int myWidth = 500;
74 private int myHeight = 150;
76 private JMenuItem writeFeatures=null;
78 private JMenu fetchAttributes=null;
80 * Initialise menu options.
83 protected void initMenus()
87 savemenu.setVisible(false); // not yet implemented
88 viewMenu.add(fitToWindow);
90 writeFeatures = new JMenuItem(
91 MessageManager.getString("label.create_viewer_attributes"));
92 writeFeatures.setToolTipText(MessageManager
93 .getString("label.create_viewer_attributes_tip"));
94 writeFeatures.addActionListener(new ActionListener()
97 public void actionPerformed(ActionEvent e)
99 sendFeaturesToChimera();
102 viewerActionMenu.add(writeFeatures);
104 fetchAttributes = new JMenu(
105 MessageManager.formatMessage("label.fetch_viewer_attributes",getViewerName()));
106 fetchAttributes.setToolTipText(
107 MessageManager.formatMessage("label.fetch_viewer_attributes_tip",getViewerName()));
108 fetchAttributes.addMouseListener(new MouseAdapter()
112 public void mouseEntered(MouseEvent e)
114 buildAttributesMenu(fetchAttributes);
117 viewerActionMenu.add(fetchAttributes);
120 protected void buildActionMenu()
122 super.buildActionMenu();
123 // add these back in after menu is refreshed
124 viewerActionMenu.add(writeFeatures);
125 viewerActionMenu.add(fetchAttributes);
129 * Query the structure viewer for its residue attribute names and add them as
130 * items off the attributes menu
132 * @param attributesMenu
134 protected void buildAttributesMenu(JMenu attributesMenu)
136 List<String> atts = jmb.getChimeraAttributes();
137 attributesMenu.removeAll();
138 Collections.sort(atts);
139 for (String attName : atts)
141 JMenuItem menuItem = new JMenuItem(attName);
142 menuItem.addActionListener(new ActionListener()
145 public void actionPerformed(ActionEvent e)
147 if (getBinding().copyStructureAttributesToFeatures(attName,
148 getAlignmentPanel()) > 0)
150 getAlignmentPanel().getFeatureRenderer().featuresAdded();
154 attributesMenu.add(menuItem);
159 * Sends command(s) to the structure viewer to create residue attributes for
160 * visible Jalview features
162 protected void sendFeaturesToChimera()
165 int count = jmb.sendFeaturesToViewer(getAlignmentPanel());
167 MessageManager.formatMessage("label.attributes_set", count, getViewerName()));
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(StructureViewerModel viewerData,
251 AlignmentPanel alignPanel, String sessionFile, String vid)
255 this.chimeraSessionFile = sessionFile;
256 Map<File, StructureData> pdbData = viewerData.getFileData();
257 PDBEntry[] pdbArray = new PDBEntry[pdbData.size()];
258 SequenceI[][] seqsArray = new SequenceI[pdbData.size()][];
260 for (StructureData data : pdbData.values())
262 PDBEntry pdbentry = new PDBEntry(data.getPdbId(), null,
263 PDBEntry.Type.PDB, data.getFilePath());
264 pdbArray[i] = pdbentry;
265 List<SequenceI> sequencesForPdb = data.getSeqList();
266 seqsArray[i] = sequencesForPdb
267 .toArray(new SequenceI[sequencesForPdb.size()]);
270 openNewChimera(alignPanel, pdbArray, seqsArray);
271 if (viewerData.isColourByViewer())
273 jmb.setColourBySequence(false);
274 seqColour.setSelected(false);
275 viewerColour.setSelected(true);
277 else if (viewerData.isColourWithAlignPanel())
279 jmb.setColourBySequence(true);
280 seqColour.setSelected(true);
281 viewerColour.setSelected(false);
286 * create a new viewer containing several structures, optionally superimposed
287 * using the given alignPanel.
293 public ChimeraViewFrame(PDBEntry[] pe, boolean alignAdded,
298 setAlignAddedStructures(alignAdded);
299 openNewChimera(ap, pe, seqs);
303 * Default constructor
305 public ChimeraViewFrame()
310 * closeViewer will decide whether or not to close this frame
311 * depending on whether user chooses to Cancel or not
313 setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE);
317 * Launch Chimera. If we have a chimera session file name, send Chimera the
318 * command to open its saved session file.
322 jmb.setFinishedInit(false);
323 Desktop.addInternalFrame(this,
324 jmb.getViewerTitle(getViewerName(), true), getBounds().width,
327 if (!jmb.launchChimera())
329 JvOptionPane.showMessageDialog(Desktop.desktop,
330 MessageManager.formatMessage("label.open_viewer_failed",
332 MessageManager.getString("label.error_loading_file"),
333 JvOptionPane.ERROR_MESSAGE);
338 if (this.chimeraSessionFile != null)
340 boolean opened = jmb.openSession(chimeraSessionFile);
343 System.err.println("An error occurred opening Chimera session file "
344 + chimeraSessionFile);
348 jmb.startChimeraListener();
352 * Open any newly added PDB structures in Chimera, having first fetched data
353 * from PDB (if not already saved).
359 // todo - record which pdbids were successfully imported.
360 StringBuilder errormsgs = new StringBuilder(128);
361 StringBuilder files = new StringBuilder(128);
362 List<PDBEntry> filePDB = new ArrayList<>();
363 List<Integer> filePDBpos = new ArrayList<>();
364 PDBEntry thePdbEntry = null;
365 StructureFile pdb = null;
368 String[] curfiles = jmb.getStructureFiles(); // files currently in viewer
369 // TODO: replace with reference fetching/transfer code (validate PDBentry
371 for (int pi = 0; pi < jmb.getPdbCount(); pi++)
374 thePdbEntry = jmb.getPdbEntry(pi);
375 if (thePdbEntry.getFile() == null)
378 * Retrieve PDB data, save to file, attach to PDBEntry
380 file = fetchPdbFile(thePdbEntry);
383 errormsgs.append("'" + thePdbEntry.getId() + "' ");
389 * Got file already - ignore if already loaded in Chimera.
391 file = new File(thePdbEntry.getFile()).getAbsoluteFile()
393 if (curfiles != null && curfiles.length > 0)
395 addingStructures = true; // already files loaded.
396 for (int c = 0; c < curfiles.length; c++)
398 if (curfiles[c].equals(file))
408 filePDB.add(thePdbEntry);
409 filePDBpos.add(Integer.valueOf(pi));
410 files.append(" \"" + Platform.escapeBackslashes(file) + "\"");
413 } catch (OutOfMemoryError oomerror)
415 new OOMWarning("Retrieving PDB files: " + thePdbEntry.getId(),
417 } catch (Exception ex)
419 ex.printStackTrace();
421 "When retrieving pdbfiles for '" + thePdbEntry.getId() + "'");
423 if (errormsgs.length() > 0)
426 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
427 MessageManager.formatMessage(
428 "label.pdb_entries_couldnt_be_retrieved", new Object[]
429 { errormsgs.toString() }),
430 MessageManager.getString("label.couldnt_load_file"),
431 JvOptionPane.ERROR_MESSAGE);
434 if (files.length() > 0)
436 jmb.setFinishedInit(false);
437 if (!addingStructures)
442 } catch (Exception ex)
444 Console.error("Couldn't open Chimera viewer!", ex);
448 for (PDBEntry pe : filePDB)
451 if (pe.getFile() != null)
455 int pos = filePDBpos.get(num).intValue();
456 long startTime = startProgressBar(getViewerName() + " "
457 + MessageManager.getString("status.opening_file_for")
460 jmb.addSequence(pos, jmb.getSequence()[pos]);
461 File fl = new File(pe.getFile());
462 DataSourceType protocol = DataSourceType.URL;
467 protocol = DataSourceType.FILE;
469 } catch (Throwable e)
473 stopProgressBar("", startTime);
475 // Explicitly map to the filename used by Chimera ;
477 pdb = jmb.getSsm().setMapping(jmb.getSequence()[pos],
478 jmb.getChains()[pos], pe.getFile(), protocol,
479 getProgressIndicator());
480 jmb.stashFoundChains(pdb, pe.getFile());
482 } catch (OutOfMemoryError oomerror)
485 "When trying to open and map structures from Chimera!",
487 } catch (Exception ex)
490 "Couldn't open " + pe.getFile() + " in Chimera viewer!",
494 Console.debug("File locations are " + files);
500 jmb.setFinishedInit(true);
501 jmb.setLoadingFromArchive(false);
504 * ensure that any newly discovered features (e.g. RESNUM)
505 * are notified to the FeatureRenderer (and added to any
506 * open feature settings dialog)
508 FeatureRenderer fr = getBinding().getFeatureRenderer(null);
514 // refresh the sequence colours for the new structure(s)
515 for (AlignmentViewPanel ap : _colourwith)
517 jmb.updateColours(ap);
519 // do superposition if asked to
520 if (alignAddedStructures)
522 new Thread(new Runnable()
527 alignStructsWithAllAlignPanels();
531 addingStructures = false;
538 public void makePDBImage(TYPE imageType)
540 throw new UnsupportedOperationException(
541 "Image export for Chimera is not implemented");
545 public AAStructureBindingModel getBinding()
551 public ViewerType getViewerType()
553 return ViewerType.CHIMERA;
557 protected String getViewerName()