X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FChimeraViewFrame.java;h=bac8f60952008f041d8fc81820618000022575a5;hb=ab506fbc0fa234dc7ce44e1d2af4944df734fe2c;hp=bc985df40e8a38f1a947005f5048cd746e0c41a9;hpb=c4ec878c9cb59fc40a88ed8ecdf5fda46f3de111;p=jalview.git diff --git a/src/jalview/gui/ChimeraViewFrame.java b/src/jalview/gui/ChimeraViewFrame.java index bc985df..bac8f60 100644 --- a/src/jalview/gui/ChimeraViewFrame.java +++ b/src/jalview/gui/ChimeraViewFrame.java @@ -1,6 +1,6 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2) - * Copyright (C) 2014 The Jalview Authors + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * @@ -27,9 +27,11 @@ import jalview.datamodel.ColumnSelection; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.ext.rbvi.chimera.JalviewChimeraBinding; -import jalview.io.AppletFormatAdapter; +import jalview.gui.StructureViewer.ViewerType; +import jalview.io.DataSourceType; import jalview.io.JalviewFileChooser; import jalview.io.JalviewFileView; +import jalview.io.StructureFile; import jalview.schemes.BuriedColourScheme; import jalview.schemes.ColourSchemeI; import jalview.schemes.HelixColourScheme; @@ -48,14 +50,19 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; +import java.io.InputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.Random; import java.util.Vector; import javax.swing.JCheckBoxMenuItem; @@ -63,46 +70,41 @@ import javax.swing.JColorChooser; import javax.swing.JInternalFrame; import javax.swing.JMenu; import javax.swing.JMenuItem; -import javax.swing.JOptionPane; import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; /** - * GUI elements for handlnig an external chimera display + * GUI elements for handling an external chimera display * * @author jprocter * */ public class ChimeraViewFrame extends StructureViewerBase { - private JalviewChimeraBinding jmb; + JalviewChimeraBinding jmb; private boolean allChainsSelected = false; - private boolean alignAddedStructures = false; - - /* - * state flag for PDB retrieval thread - */ - private boolean _started = false; - - private boolean addingStructures = false; - private IProgressIndicator progressBar = null; /* - * pdb retrieval thread. + * Path to Chimera session file. This is set when an open Jalview/Chimera + * session is saved, or on restore from a Jalview project (if it holds the + * filename of any saved Chimera sessions). */ - private Thread worker = null; + private String chimeraSessionFile = null; + + private Random random = new Random(); /** * Initialise menu options. */ private void initMenus() { - viewerActionMenu.setText(MessageManager.getString("label.chimera")); + String chimera = MessageManager.getString("label.chimera"); + viewerActionMenu.setText(chimera); viewerColour.setText(MessageManager .getString("label.colour_with_chimera")); viewerColour.setToolTipText(MessageManager @@ -141,6 +143,8 @@ public class ChimeraViewFrame extends StructureViewerBase } }); viewMenu.add(seqColourBy); + viewMenu.add(fitToWindow); + final ItemListener handler; JMenu alpanels = new ViewSelectionMenu( MessageManager.getString("label.superpose_with"), this, @@ -153,33 +157,82 @@ public class ChimeraViewFrame extends StructureViewerBase alignStructs.setToolTipText(MessageManager .formatMessage( "label.align_structures_using_linked_alignment_views", - new Object[] - { new Integer(_alignwith.size()).toString() })); + new Object[] { new Integer(_alignwith + .size()).toString() })); } }); handler.itemStateChanged(null); viewerActionMenu.add(alpanels); viewerActionMenu.addMenuListener(new MenuListener() { - @Override public void menuSelected(MenuEvent e) { handler.itemStateChanged(null); } - @Override public void menuDeselected(MenuEvent e) { - // TODO Auto-generated method stub } - @Override public void menuCanceled(MenuEvent e) { - // TODO Auto-generated method stub } }); + + JMenuItem writeFeatures = new JMenuItem( + MessageManager.getString("label.create_viewer_attributes")); + writeFeatures.setToolTipText(MessageManager.formatMessage( + "label.create_viewer_attributes_tip", chimera)); + writeFeatures.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + sendFeaturesToViewer(); + } + }); + viewerActionMenu.add(writeFeatures); + + final JMenu fetchAttributes = new JMenu(MessageManager.formatMessage( + "label.fetch_viewer_attributes", chimera)); + fetchAttributes.setToolTipText(MessageManager.formatMessage( + "label.fetch_viewer_attributes_tip", chimera)); + fetchAttributes.addMouseListener(new MouseAdapter() + { + + @Override + public void mouseEntered(MouseEvent e) + { + buildAttributesMenu(fetchAttributes); + } + }); + viewerActionMenu.add(fetchAttributes); + } + + /** + * Asks Chimera for residues with the given attribute name, and set as + * features on the corresponding sequence positions (if any) + * + * @param attName + */ + @Override + protected void getResidueAttributes(String attName) + { + jmb.copyStructureAttributesToFeatures(attName, getAlignmentPanel()); + } + + /** + * Send a command to Chimera to create residue attributes for Jalview features + *

+ * The syntax is: setattr r + *

+ * For example: setattr r jv:chain "Ferredoxin-1, Chloroplastic" #0:94.A + */ + @Override + protected void sendFeaturesToViewer() + { + jmb.sendFeaturesToViewer(getAlignmentPanel()); } /** @@ -193,108 +246,61 @@ public class ChimeraViewFrame extends StructureViewerBase public ChimeraViewFrame(PDBEntry pdbentry, SequenceI[] seq, String[] chains, final AlignmentPanel ap) { - super(); - progressBar = ap.alignFrame; - // //////////////////////////////// - // Is the pdb file already loaded? - String alreadyMapped = ap.getStructureSelectionManager() - .alreadyMappedToFile(pdbentry.getId()); + this(); + String pdbId = pdbentry.getId(); - if (alreadyMapped != null) + /* + * If the PDB file is already loaded, the user may just choose to add to an + * existing viewer (or cancel) + */ + if (addAlreadyLoadedFile(seq, chains, ap, pdbId)) { - int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop, - MessageManager.formatMessage( - "label.pdb_entry_is_already_displayed", new Object[] - { pdbentry.getId() }), MessageManager.formatMessage( - "label.map_sequences_to_visible_window", new Object[] - { pdbentry.getId() }), - JOptionPane.YES_NO_CANCEL_OPTION); - - if (option == JOptionPane.CANCEL_OPTION) - { - return; - } - if (option == JOptionPane.YES_OPTION) - { - // TODO : Fix multiple seq to one chain issue here. - ap.getStructureSelectionManager().setMapping(seq, chains, - alreadyMapped, AppletFormatAdapter.FILE); - if (ap.getSeqPanel().seqCanvas.fr != null) - { - ap.getSeqPanel().seqCanvas.fr.featuresAdded(); - ap.paintAlignment(true); - } + return; + } - // Now this ChimeraViewFrame is mapped to new sequences. We must add - // them to the existing array - JInternalFrame[] frames = Desktop.instance.getAllFrames(); + /* + * Check if there are other Chimera views involving this alignment and give + * user the option to add and align this molecule to one of them (or cancel) + */ + if (addToExistingViewer(pdbentry, seq, chains, ap, pdbId)) + { + return; + } - for (JInternalFrame frame : frames) - { - if (frame instanceof ChimeraViewFrame) - { - final ChimeraViewFrame topView = ((ChimeraViewFrame) frame); - // JBPNOTE: this looks like a binding routine, rather than a gui - // routine - for (int pe = 0; pe < topView.jmb.getPdbCount(); pe++) - { - if (topView.jmb.getPdbEntry(pe).getFile() - .equals( - alreadyMapped)) - { - topView.jmb.addSequence(pe, seq); - topView.addAlignmentPanel(ap); - // add it to the set used for colouring - topView.useAlignmentPanelForColourbyseq(ap); - topView.buildActionMenu(); - ap.getStructureSelectionManager() - .sequenceColoursChanged(ap); - break; - } - } - } - } + /* + * If the options above are declined or do not apply, show the structure in + * a new viewer + */ + openNewChimera(ap, new PDBEntry[] { pdbentry }, + new SequenceI[][] { seq }); + } - return; - } - } - // ///////////////////////////////// - // Check if there are other Chimera views involving this alignment - // and prompt user about adding this molecule to one of them - List existingViews = getChimeraWindowsFor(ap); - for (ChimeraViewFrame topView : existingViews) + /** + * Create a helper to manage progress bar display + */ + protected void createProgressBar() + { + if (progressBar == null) { - // TODO: highlight topView in view somehow - int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop, - MessageManager.formatMessage("label.add_pdbentry_to_view", - new Object[] - { pdbentry.getId(), topView.getTitle() }), - MessageManager - .getString("label.align_to_existing_structure_view"), - JOptionPane.YES_NO_CANCEL_OPTION); - if (option == JOptionPane.CANCEL_OPTION) - { - return; - } - if (option == JOptionPane.YES_OPTION) - { - topView.useAlignmentPanelForSuperposition(ap); - topView.addStructure(pdbentry, seq, chains, true, ap.alignFrame); - return; - } + progressBar = new ProgressBar(statusPanel, statusBar); } - // ///////////////////////////////// - openNewChimera(ap, new PDBEntry[] - { pdbentry }, new SequenceI[][] - { seq }); + } + + /** + * Answers true if this viewer already involves the given PDB ID + */ + @Override + protected boolean hasPdbId(String pdbId) + { + return jmb.hasPdbId(pdbId); } private void openNewChimera(AlignmentPanel ap, PDBEntry[] pdbentrys, SequenceI[][] seqs) { - progressBar = ap.alignFrame; + createProgressBar(); jmb = new JalviewChimeraBindingModel(this, - ap.getStructureSelectionManager(), pdbentrys, seqs, null, null); + ap.getStructureSelectionManager(), pdbentrys, seqs, null); addAlignmentPanel(ap); useAlignmentPanelForColourbyseq(ap); if (pdbentrys.length > 1) @@ -305,241 +311,153 @@ public class ChimeraViewFrame extends StructureViewerBase jmb.setColourBySequence(true); setSize(400, 400); // probably should be a configurable/dynamic default here initMenus(); - worker = null; - { - addingStructures = false; - worker = new Thread(this); - worker.start(); - } + + addingStructures = false; + worker = new Thread(this); + worker.start(); + this.addInternalFrameListener(new InternalFrameAdapter() { + @Override public void internalFrameClosing(InternalFrameEvent internalFrameEvent) { - closeViewer(); + closeViewer(false); } }); } /** - * create a new viewer containing several structures superimposed using the - * given alignPanel. - * - * @param ap - * @param pe - * @param seqs - */ - public ChimeraViewFrame(AlignmentPanel ap, PDBEntry[] pe, - SequenceI[][] seqs) - { - super(); - openNewChimera(ap, pe, seqs); - } - - public AlignmentPanel[] getAllAlignmentPanels() - { - AlignmentPanel[] t, list = new AlignmentPanel[0]; - for (String setid : _aps) - { - AlignmentPanel[] panels = PaintRefresher.getAssociatedPanels(setid); - if (panels != null) - { - t = new AlignmentPanel[list.length + panels.length]; - System.arraycopy(list, 0, t, 0, list.length); - System.arraycopy(panels, 0, t, list.length, panels.length); - list = t; - } - } - - return list; - } - - /** - * set the primary alignmentPanel reference and add another alignPanel to the - * list of ones to use for colouring and aligning + * Create a new viewer from saved session state data including Chimera session + * file * - * @param nap + * @param chimeraSessionFile + * @param alignPanel + * @param pdbArray + * @param seqsArray + * @param colourByChimera + * @param colourBySequence + * @param newViewId */ - public void addAlignmentPanel(AlignmentPanel nap) + public ChimeraViewFrame(String chimeraSessionFile, + AlignmentPanel alignPanel, PDBEntry[] pdbArray, + SequenceI[][] seqsArray, boolean colourByChimera, + boolean colourBySequence, String newViewId) { - if (getAlignmentPanel() == null) + this(); + setViewId(newViewId); + this.chimeraSessionFile = chimeraSessionFile; + openNewChimera(alignPanel, pdbArray, seqsArray); + if (colourByChimera) { - setAlignmentPanel(nap); + jmb.setColourBySequence(false); + seqColour.setSelected(false); + viewerColour.setSelected(true); } - if (!_aps.contains(nap.av.getSequenceSetId())) + else if (colourBySequence) { - _aps.add(nap.av.getSequenceSetId()); + jmb.setColourBySequence(true); + seqColour.setSelected(true); + viewerColour.setSelected(false); } } /** - * remove any references held to the given alignment panel + * create a new viewer containing several structures superimposed using the + * given alignPanel. * - * @param nap + * @param pe + * @param seqs + * @param ap */ - public void removeAlignmentPanel(AlignmentPanel nap) - { - try - { - _alignwith.remove(nap); - _colourwith.remove(nap); - if (getAlignmentPanel() == nap) - { - setAlignmentPanel(null); - for (AlignmentPanel aps : getAllAlignmentPanels()) - { - if (aps != nap) - { - setAlignmentPanel(aps); - break; - } - } - } - } catch (Exception ex) - { - } - if (getAlignmentPanel() != null) - { - buildActionMenu(); - } - } - - public void useAlignmentPanelForSuperposition(AlignmentPanel nap) - { - addAlignmentPanel(nap); - if (!_alignwith.contains(nap)) - { - _alignwith.add(nap); - } - } - - public void excludeAlignmentPanelForSuperposition(AlignmentPanel nap) - { - if (_alignwith.contains(nap)) - { - _alignwith.remove(nap); - } - } - - public void useAlignmentPanelForColourbyseq(AlignmentPanel nap, - boolean enableColourBySeq) - { - useAlignmentPanelForColourbyseq(nap); - getBinding().setColourBySequence(enableColourBySeq); - seqColour.setSelected(enableColourBySeq); - viewerColour.setSelected(!enableColourBySeq); - } - - public void useAlignmentPanelForColourbyseq(AlignmentPanel nap) - { - addAlignmentPanel(nap); - if (!_colourwith.contains(nap)) - { - _colourwith.add(nap); - } - } - - public void excludeAlignmentPanelForColourbyseq(AlignmentPanel nap) + public ChimeraViewFrame(PDBEntry[] pe, SequenceI[][] seqs, + AlignmentPanel ap) { - if (_colourwith.contains(nap)) - { - _colourwith.remove(nap); - } + this(); + openNewChimera(ap, pe, seqs); } /** - * add a new structure (with associated sequences and chains) to this viewer, - * retrieving it if necessary first. - * - * @param pdbentry - * @param seq - * @param chains - * @param alignFrame - * @param align - * if true, new structure(s) will be align using associated alignment + * Default constructor */ - private void addStructure(final PDBEntry pdbentry, final SequenceI[] seq, - final String[] chains, final boolean b, - final IProgressIndicator alignFrame) + public ChimeraViewFrame() { - if (pdbentry.getFile() == null) - { - if (worker != null && worker.isAlive()) - { - // a retrieval is in progress, wait around and add ourselves to the - // queue. - new Thread(new Runnable() - { - public void run() - { - while (worker != null && worker.isAlive() && _started) - { - try - { - Thread.sleep(100 + ((int) Math.random() * 100)); - - } catch (Exception e) - { - } + super(); - } - // and call ourselves again. - addStructure(pdbentry, seq, chains, b, alignFrame); - } - }).start(); - return; - } - } - // otherwise, start adding the structure. - jmb.addSequenceAndChain(new PDBEntry[] - { pdbentry }, new SequenceI[][] - { seq }, new String[][] - { chains }); - addingStructures = true; - _started = false; - alignAddedStructures = b; - progressBar = alignFrame; // visual indication happens on caller frame. - (worker = new Thread(this)).start(); - return; + /* + * closeViewer will decide whether or not to close this frame + * depending on whether user chooses to Cancel or not + */ + setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE); } - private List getChimeraWindowsFor(AlignmentPanel apanel) + /** + * Returns a list of any Chimera viewers in the desktop. The list is + * restricted to those linked to the given alignment panel if it is not null. + */ + @Override + protected List getViewersFor(AlignmentPanel ap) { - List result = new ArrayList(); + List result = new ArrayList(); JInternalFrame[] frames = Desktop.instance.getAllFrames(); for (JInternalFrame frame : frames) { if (frame instanceof ChimeraViewFrame) { - if (((StructureViewerBase) frame).isLinkedWith(apanel)) + if (ap == null || ((StructureViewerBase) frame).isLinkedWith(ap)) { - result.add((ChimeraViewFrame) frame); + result.add((StructureViewerBase) frame); } } } return result; } - void initChimera(String command) + /** + * Launch Chimera. If we have a chimera session file name, send Chimera the + * command to open its saved session file. + */ + void initChimera() { - jmb.setFinishedInit(false); - // TODO: consider waiting until the structure/view is fully loaded before - // displaying - jalview.gui.Desktop.addInternalFrame(this, jmb.getViewerTitle("Chimera", true), + Desktop.addInternalFrame(this, jmb.getViewerTitle("Chimera", true), getBounds().width, getBounds().height); - if (command == null) + + if (!jmb.launchChimera()) { - command = ""; + JvOptionPane.showMessageDialog(Desktop.desktop, + MessageManager.getString("label.chimera_failed"), + MessageManager.getString("label.error_loading_file"), + JvOptionPane.ERROR_MESSAGE); + this.dispose(); + return; } - jmb.evalStateCommand(command, false); - jmb.setFinishedInit(true); + + if (this.chimeraSessionFile != null) + { + boolean opened = jmb.openSession(chimeraSessionFile); + if (!opened) + { + System.err + .println("An error occurred opening Chimera session file " + + chimeraSessionFile); + } + } + + jmb.startChimeraListener(); } + /** + * If the list is not empty, add menu items for 'All' and each individual + * chain to the "View | Show Chain" sub-menu. Multiple selections are allowed. + * + * @param chainNames + */ + @Override void setChainMenuItems(List chainNames) { chainMenu.removeAll(); - if (chainNames == null) + if (chainNames == null || chainNames.isEmpty()) { return; } @@ -547,6 +465,7 @@ public class ChimeraViewFrame extends StructureViewerBase MessageManager.getString("label.all")); menuItem.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent evt) { allChainsSelected = true; @@ -557,7 +476,7 @@ public class ChimeraViewFrame extends StructureViewerBase ((JCheckBoxMenuItem) chainMenu.getItem(i)).setSelected(true); } } - centerViewer(); + showSelectedChains(); allChainsSelected = false; } }); @@ -569,11 +488,12 @@ public class ChimeraViewFrame extends StructureViewerBase menuItem = new JCheckBoxMenuItem(chainName, true); menuItem.addItemListener(new ItemListener() { + @Override public void itemStateChanged(ItemEvent evt) { if (!allChainsSelected) { - centerViewer(); + showSelectedChains(); } } }); @@ -582,7 +502,11 @@ public class ChimeraViewFrame extends StructureViewerBase } } - void centerViewer() + /** + * Show only the selected chain(s) in the viewer + */ + @Override + void showSelectedChains() { List toshow = new ArrayList(); for (int i = 0; i < chainMenu.getItemCount(); i++) @@ -596,26 +520,42 @@ public class ChimeraViewFrame extends StructureViewerBase } } } - jmb.centerViewer(toshow); + jmb.showChains(toshow); } /** * Close down this instance of Jalview's Chimera viewer, giving the user the * option to close the associated Chimera window (process). They may wish to * keep it open until they have had an opportunity to save any work. + * + * @param closeChimera + * if true, close any linked Chimera process; if false, prompt first */ - public void closeViewer() + @Override + public void closeViewer(boolean closeChimera) { - if (jmb.isChimeraRunning()) + if (jmb != null && jmb.isChimeraRunning()) { - String prompt = MessageManager - .formatMessage("label.confirm_close_chimera", new Object[] - { jmb.getViewerTitle("Chimera", false) }); - prompt = JvSwingUtils.wrapTooltip(true, prompt); - int confirm = JOptionPane.showConfirmDialog(this, prompt, - MessageManager.getString("label.close_viewer"), - JOptionPane.YES_NO_OPTION); - jmb.closeViewer(confirm == JOptionPane.YES_OPTION); + if (!closeChimera) + { + String prompt = MessageManager.formatMessage( + "label.confirm_close_chimera", + new Object[] { jmb.getViewerTitle("Chimera", false) }); + prompt = JvSwingUtils.wrapTooltip(true, prompt); + int confirm = JvOptionPane.showConfirmDialog(this, prompt, + MessageManager.getString("label.close_viewer"), + JvOptionPane.YES_NO_CANCEL_OPTION); + /* + * abort closure if user hits escape or Cancel + */ + if (confirm == JvOptionPane.CANCEL_OPTION + || confirm == JvOptionPane.CLOSED_OPTION) + { + return; + } + closeChimera = confirm == JvOptionPane.YES_OPTION; + } + jmb.closeViewer(closeChimera); } setAlignmentPanel(null); _aps.clear(); @@ -624,12 +564,14 @@ public class ChimeraViewFrame extends StructureViewerBase // TODO: check for memory leaks where instance isn't finalised because jmb // holds a reference to the window jmb = null; + dispose(); } /** * Open any newly added PDB structures in Chimera, having first fetched data * from PDB (if not already saved). */ + @Override public void run() { _started = true; @@ -639,6 +581,7 @@ public class ChimeraViewFrame extends StructureViewerBase List filePDB = new ArrayList(); List filePDBpos = new ArrayList(); PDBEntry thePdbEntry = null; + StructureFile pdb = null; try { String[] curfiles = jmb.getPdbFile(); // files currently in viewer @@ -699,21 +642,21 @@ public class ChimeraViewFrame extends StructureViewerBase if (errormsgs.length() > 0) { - JOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager + JvOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager .formatMessage("label.pdb_entries_couldnt_be_retrieved", - new Object[] - { errormsgs.toString() }), MessageManager - .getString("label.couldnt_load_file"), - JOptionPane.ERROR_MESSAGE); + new Object[] { errormsgs.toString() }), + MessageManager.getString("label.couldnt_load_file"), + JvOptionPane.ERROR_MESSAGE); } if (files.length() > 0) { + jmb.setFinishedInit(false); if (!addingStructures) { try { - initChimera(""); + initChimera(); } catch (Exception ex) { Cache.log.error("Couldn't open Chimera viewer!", ex); @@ -728,24 +671,29 @@ public class ChimeraViewFrame extends StructureViewerBase try { int pos = filePDBpos.get(num).intValue(); + long startTime = startProgressBar("Chimera " + + MessageManager.getString("status.opening_file_for") + + " " + pe.getId()); jmb.openFile(pe); jmb.addSequence(pos, jmb.getSequence()[pos]); File fl = new File(pe.getFile()); - String protocol = AppletFormatAdapter.URL; + DataSourceType protocol = DataSourceType.URL; try { if (fl.exists()) { - protocol = AppletFormatAdapter.FILE; + protocol = DataSourceType.FILE; } } catch (Throwable e) { + } finally + { + stopProgressBar("", startTime); } // Explicitly map to the filename used by Chimera ; - // TODO: use pe.getId() instead of pe.getFile() ? - jmb.getSsm().setMapping(jmb.getSequence()[pos], null, - pe.getFile(), - protocol); + pdb = jmb.getSsm().setMapping(jmb.getSequence()[pos], + jmb.getChains()[pos], pe.getFile(), protocol); + stashFoundChains(pdb, pe.getFile()); } catch (OutOfMemoryError oomerror) { new OOMWarning( @@ -761,6 +709,8 @@ public class ChimeraViewFrame extends StructureViewerBase } } } + + jmb.refreshGUI(); jmb.setFinishedInit(true); jmb.setLoadingFromArchive(false); @@ -770,10 +720,11 @@ public class ChimeraViewFrame extends StructureViewerBase jmb.updateColours(ap); } // do superposition if asked to - if (alignAddedStructures) + if (Cache.getDefault("AUTOSUPERIMPOSE", true) && alignAddedStructures) { new Thread(new Runnable() { + @Override public void run() { alignStructs_withAllAlignPanels(); @@ -795,19 +746,36 @@ public class ChimeraViewFrame extends StructureViewerBase * @return * @throws Exception */ + + private void stashFoundChains(StructureFile pdb, String file) + { + for (int i = 0; i < pdb.getChains().size(); i++) + { + String chid = new String(pdb.getId() + ":" + + pdb.getChains().elementAt(i).id); + jmb.getChainNames().add(chid); + jmb.getChainFile().put(chid, file); + } + } private String fetchPdbFile(PDBEntry processingEntry) throws Exception { + // FIXME: this is duplicated code with Jmol frame ? String filePath = null; Pdb pdbclient = new Pdb(); AlignmentI pdbseq = null; String pdbid = processingEntry.getId(); - long hdl = pdbid.hashCode() - System.currentTimeMillis(); - if (progressBar != null) - { - progressBar.setProgressBar(MessageManager.formatMessage( - "status.fetching_pdb", new Object[] - { pdbid }), hdl); - } + long handle = System.currentTimeMillis() + + Thread.currentThread().hashCode(); + + /* + * Write 'fetching PDB' progress on AlignFrame as we are not yet visible + */ + String msg = MessageManager.formatMessage("status.fetching_pdb", + new Object[] { pdbid }); + getAlignmentPanel().alignFrame.setProgressBar(msg, handle); + // long hdl = startProgressBar(MessageManager.formatMessage( + // "status.fetching_pdb", new Object[] + // { pdbid })); try { pdbseq = pdbclient.getSequenceRecords(pdbid); @@ -816,16 +784,9 @@ public class ChimeraViewFrame extends StructureViewerBase new OOMWarning("Retrieving PDB id " + pdbid, oomerror); } finally { - if (progressBar != null) - { - progressBar - .setProgressBar( - pdbid - + " " - + MessageManager - .getString("label.state_completed"), - hdl); - } + msg = pdbid + " " + MessageManager.getString("label.state_completed"); + getAlignmentPanel().alignFrame.setProgressBar(msg, handle); + // stopProgressBar(msg, hdl); } /* * If PDB data were saved and are not invalid (empty alignment), return the @@ -834,13 +795,47 @@ public class ChimeraViewFrame extends StructureViewerBase if (pdbseq != null && pdbseq.getHeight() > 0) { // just use the file name from the first sequence's first PDBEntry - filePath = new File(((PDBEntry) pdbseq.getSequenceAt(0).getPDBId() - .elementAt(0)).getFile()).getAbsolutePath(); + filePath = new File(pdbseq.getSequenceAt(0).getAllPDBEntries() + .elementAt(0).getFile()).getAbsolutePath(); processingEntry.setFile(filePath); } return filePath; } + /** + * Convenience method to update the progress bar if there is one. Be sure to + * call stopProgressBar with the returned handle to remove the message. + * + * @param msg + * @param handle + */ + public long startProgressBar(String msg) + { + // TODO would rather have startProgress/stopProgress as the + // IProgressIndicator interface + long tm = random.nextLong(); + if (progressBar != null) + { + progressBar.setProgressBar(msg, tm); + } + return tm; + } + + /** + * End the progress bar with the specified handle, leaving a message (if not + * null) on the status bar + * + * @param msg + * @param handle + */ + public void stopProgressBar(String msg, long handle) + { + if (progressBar != null) + { + progressBar.setProgressBar(msg, handle); + } + } + @Override public void pdbFile_actionPerformed(ActionEvent actionEvent) { @@ -897,11 +892,7 @@ public class ChimeraViewFrame extends StructureViewerBase jalview.gui.CutAndPasteTransfer cap = new jalview.gui.CutAndPasteTransfer(); try { - for (int pdbe = 0; pdbe < jmb.getPdbCount(); pdbe++) - { - cap.appendText(jmb.printMapping(jmb.getPdbEntry(pdbe).getFile())); - cap.appendText("\n"); - } + cap.appendText(jmb.printMappings()); } catch (OutOfMemoryError e) { new OOMWarning( @@ -962,7 +953,7 @@ public class ChimeraViewFrame extends StructureViewerBase // Set the colour using the current view for the associated alignframe for (AlignmentPanel ap : _colourwith) { - jmb.colourBySequence(ap.av.showSequenceFeatures, ap); + jmb.colourBySequence(ap.av.isShowSequenceFeatures(), ap); } } } @@ -1074,13 +1065,13 @@ public class ChimeraViewFrame extends StructureViewerBase repaint(); return; } - setChainMenuItems(jmb.chainNames); + setChainMenuItems(jmb.getChainNames()); this.setTitle(jmb.getViewerTitle("Chimera", true)); - if (jmb.getPdbFile().length > 1 && jmb.getSequence().length > 1) - { + // if (jmb.getPdbFile().length > 1 && jmb.getSequence().length > 1) + // { viewerActionMenu.setVisible(true); - } + // } if (!jmb.isLoadingFromArchive()) { seqColour_actionPerformed(null); @@ -1106,12 +1097,12 @@ public class ChimeraViewFrame extends StructureViewerBase { return; } - ; + if (_alignwith.size() == 0) { _alignwith.add(getAlignmentPanel()); } - ; + try { AlignmentI[] als = new Alignment[_alignwith.size()]; @@ -1135,11 +1126,10 @@ public class ChimeraViewFrame extends StructureViewerBase } Cache.log.info("Couldn't align structures with the " + sp.toString() + "associated alignment panels.", e); - } - } + @Override public void setJalviewColourScheme(ColourSchemeI ucs) { jmb.setJalviewColourScheme(ucs); @@ -1171,13 +1161,96 @@ public class ChimeraViewFrame extends StructureViewerBase } /** - * Ask Chimera to save its session to the designated file path. Returns true - * if successful, else false. + * Ask Chimera to save its session to the designated file path, or to a + * temporary file if the path is null. Returns the file path if successful, + * else null. * * @param filepath + * @see getStateInfo + */ + protected String saveSession(String filepath) + { + String pathUsed = filepath; + try + { + if (pathUsed == null) + { + File tempFile = File.createTempFile("chimera", ".py"); + tempFile.deleteOnExit(); + pathUsed = tempFile.getPath(); + } + boolean result = jmb.saveSession(pathUsed); + if (result) + { + this.chimeraSessionFile = pathUsed; + return pathUsed; + } + } catch (IOException e) + { + } + return null; + } + + /** + * Returns a string representing the state of the Chimera session. This is + * done by requesting Chimera to save its session to a temporary file, then + * reading the file contents. Returns an empty string on any error. */ - public boolean saveSession(String filepath) + @Override + public String getStateInfo() + { + String sessionFile = saveSession(null); + if (sessionFile == null) + { + return ""; + } + InputStream is = null; + try + { + File f = new File(sessionFile); + byte[] bytes = new byte[(int) f.length()]; + is = new FileInputStream(sessionFile); + is.read(bytes); + return new String(bytes); + } catch (IOException e) + { + return ""; + } finally + { + if (is != null) + { + try + { + is.close(); + } catch (IOException e) + { + // ignore + } + } + } + } + + @Override + protected void fitToWindow_actionPerformed() + { + jmb.focusView(); + } + + @Override + public ViewerType getViewerType() + { + return ViewerType.CHIMERA; + } + + @Override + protected AAStructureBindingModel getBindingModel() + { + return jmb; + } + + @Override + protected List getResidueAttributeNames() { - return jmb.saveSession(filepath); + return jmb.getResidueAttributes(); } }