/*
- * 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.
*
*/
package jalview.gui;
-import jalview.api.SequenceStructureBinding;
-import jalview.api.structures.JalviewStructureDisplayI;
-import jalview.bin.Cache;
-import jalview.datamodel.Alignment;
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ColumnSelection;
-import jalview.datamodel.PDBEntry;
-import jalview.datamodel.SequenceI;
-import jalview.gui.ViewSelectionMenu.ViewSetProvider;
-import jalview.io.AppletFormatAdapter;
-import jalview.io.JalviewFileChooser;
-import jalview.io.JalviewFileView;
-import jalview.jbgui.GStructureViewer;
-import jalview.schemes.BuriedColourScheme;
-import jalview.schemes.ColourSchemeI;
-import jalview.schemes.HelixColourScheme;
-import jalview.schemes.HydrophobicColourScheme;
-import jalview.schemes.PurinePyrimidineColourScheme;
-import jalview.schemes.StrandColourScheme;
-import jalview.schemes.TaylorColourScheme;
-import jalview.schemes.TurnColourScheme;
-import jalview.schemes.ZappoColourScheme;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-import jalview.ws.dbsources.Pdb;
-
-import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Random;
import java.util.Vector;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.ext.rbvi.chimera.JalviewChimeraBinding;
+import jalview.io.AppletFormatAdapter;
+import jalview.io.JalviewFileChooser;
+import jalview.io.JalviewFileView;
+import jalview.schemes.BuriedColourScheme;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.HelixColourScheme;
+import jalview.schemes.HydrophobicColourScheme;
+import jalview.schemes.PurinePyrimidineColourScheme;
+import jalview.schemes.StrandColourScheme;
+import jalview.schemes.TaylorColourScheme;
+import jalview.schemes.TurnColourScheme;
+import jalview.schemes.ZappoColourScheme;
+import jalview.structures.models.AAStructureBindingModel;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.ws.dbsources.Pdb;
+
/**
* GUI elements for handlnig an external chimera display
*
* @author jprocter
*
*/
-public class ChimeraViewFrame extends GStructureViewer implements Runnable,
- ViewSetProvider, JalviewStructureDisplayI
-
+public class ChimeraViewFrame extends StructureViewerBase
{
- private JalviewChimeraBindingModel jmb;
-
- /*
- * list of sequenceSet ids associated with the view
- */
- private ArrayList<String> _aps = new ArrayList<String>();
-
- /*
- * list of alignment panels to use for superposition
- */
- private Vector<AlignmentPanel> _alignwith = new Vector<AlignmentPanel>();
-
- /*
- * list of alignment panels that are used for colouring structures by aligned
- * sequences
- */
- private Vector<AlignmentPanel> _colourwith = new Vector<AlignmentPanel>();
+ private JalviewChimeraBinding jmb;
private boolean allChainsSelected = false;
private boolean alignAddedStructures = false;
- AlignmentPanel ap;
-
/*
* state flag for PDB retrieval thread
*/
private IProgressIndicator progressBar = null;
- private String viewId = null;
-
/*
* pdb retrieval thread.
*/
private Thread worker = null;
+ /*
+ * 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 String chimeraSessionFile = null;
+
+ private Random random = new Random();
+
/**
* Initialise menu options.
*/
_alignwith = new Vector<AlignmentPanel>();
}
+ // save As not yet implemented
+ savemenu.setVisible(false);
+
ViewSelectionMenu seqColourBy = new ViewSelectionMenu(
MessageManager.getString("label.colour_by"), this, _colourwith,
new ItemListener()
// TODO : Fix multiple seq to one chain issue here.
ap.getStructureSelectionManager().setMapping(seq, chains,
alreadyMapped, AppletFormatAdapter.FILE);
- if (ap.seqPanel.seqCanvas.fr != null)
+ if (ap.getSeqPanel().seqCanvas.fr != null)
{
- ap.seqPanel.seqCanvas.fr.featuresAdded();
+ ap.getSeqPanel().seqCanvas.fr.featuresAdded();
ap.paintAlignment(true);
}
final ChimeraViewFrame topView = ((ChimeraViewFrame) frame);
// JBPNOTE: this looks like a binding routine, rather than a gui
// routine
- for (int pe = 0; pe < topView.jmb.pdbentry.length; pe++)
+ for (int pe = 0; pe < topView.jmb.getPdbCount(); pe++)
{
- if (topView.jmb.pdbentry[pe].getFile().equals(alreadyMapped))
+ 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.buildChimeraActionMenu();
+ topView.buildActionMenu();
ap.getStructureSelectionManager()
.sequenceColoursChanged(ap);
break;
for (ChimeraViewFrame topView : existingViews)
{
// TODO: highlight topView in view somehow
+ /*
+ * JAL-1742 exclude view with this structure already mapped (don't offer
+ * to align chain B to chain A of the same structure)
+ */
+ if (topView.hasPdbId(pdbentry.getId()))
+ {
+ continue;
+ }
int option = JOptionPane.showInternalConfirmDialog(Desktop.desktop,
MessageManager.formatMessage("label.add_pdbentry_to_view",
new Object[]
{ seq });
}
+ /**
+ * Create a helper to manage progress bar display
+ */
+ protected void createProgressBar()
+ {
+ if (progressBar == null)
+ {
+ progressBar = new ProgressBar(statusPanel, statusBar);
+ }
+ }
+
+ 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);
addAlignmentPanel(ap);
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()
{
public void internalFrameClosing(InternalFrameEvent internalFrameEvent)
{
- closeViewer();
+ closeViewer(false);
}
});
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
- */
- public void addAlignmentPanel(AlignmentPanel nap)
- {
- if (ap == null)
- {
- ap = nap;
- }
- if (!_aps.contains(nap.av.getSequenceSetId()))
- {
- _aps.add(nap.av.getSequenceSetId());
- }
- }
-
- /**
- * remove any references held to the given alignment panel
+ * @param chimeraSession
*
- * @param nap
+ * @param alignPanel
+ * @param pdbArray
+ * @param seqsArray
+ * @param colourByChimera
+ * @param colourBySequence
*/
- public void removeAlignmentPanel(AlignmentPanel nap)
- {
- try
- {
- _alignwith.remove(nap);
- _colourwith.remove(nap);
- if (ap == nap)
- {
- ap = null;
- for (AlignmentPanel aps : getAllAlignmentPanels())
- {
- if (aps != nap)
- {
- ap = aps;
- break;
- }
- }
- }
- } catch (Exception ex)
- {
- }
- if (ap != null)
- {
- buildChimeraActionMenu();
- }
- }
-
- public void useAlignmentPanelForSuperposition(AlignmentPanel nap)
- {
- addAlignmentPanel(nap);
- if (!_alignwith.contains(nap))
- {
- _alignwith.add(nap);
- }
- }
-
- public void excludeAlignmentPanelForSuperposition(AlignmentPanel nap)
+ public ChimeraViewFrame(String chimeraSession, AlignmentPanel alignPanel,
+ PDBEntry[] pdbArray,
+ SequenceI[][] seqsArray, boolean colourByChimera,
+ boolean colourBySequence)
{
- if (_alignwith.contains(nap))
- {
- _alignwith.remove(nap);
- }
- }
-
- public void useAlignmentPanelForColourbyseq(AlignmentPanel nap,
- boolean enableColourBySeq)
- {
- useAlignmentPanelForColourbyseq(nap);
- jmb.setColourBySequence(enableColourBySeq);
- seqColour.setSelected(enableColourBySeq);
- viewerColour.setSelected(!enableColourBySeq);
- }
-
- public void useAlignmentPanelForColourbyseq(AlignmentPanel nap)
- {
- addAlignmentPanel(nap);
- if (!_colourwith.contains(nap))
+ super();
+ this.chimeraSessionFile = chimeraSession;
+ openNewChimera(alignPanel, pdbArray, seqsArray);
+ if (colourByChimera)
{
- _colourwith.add(nap);
+ jmb.setColourBySequence(false);
+ seqColour.setSelected(false);
+ viewerColour.setSelected(true);
}
- }
-
- public void excludeAlignmentPanelForColourbyseq(AlignmentPanel nap)
- {
- if (_colourwith.contains(nap))
+ else if (colourBySequence)
{
- _colourwith.remove(nap);
+ jmb.setColourBySequence(true);
+ seqColour.setSelected(true);
+ viewerColour.setSelected(false);
}
}
{
if (frame instanceof ChimeraViewFrame)
{
- if (((ChimeraViewFrame) frame).isLinkedWith(apanel))
+ if (((StructureViewerBase) frame).isLinkedWith(apanel))
{
result.add((ChimeraViewFrame) 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(true),
+ jalview.gui.Desktop.addInternalFrame(this, jmb.getViewerTitle("Chimera", true),
getBounds().width, getBounds().height);
- if (command == null)
+
+ /*
+ * Pass an empty 'command' to launch Chimera
+ */
+ jmb.evalStateCommand("", false);
+
+ if (this.chimeraSessionFile != null)
{
- command = "";
+ boolean opened = jmb.openSession(chimeraSessionFile);
+ if (!opened)
+ {
+ System.err
+ .println("An error occurred opening Chimera session file "
+ + chimeraSessionFile);
+ }
}
- jmb.evalStateCommand(command, false);
jmb.setFinishedInit(true);
+
+ jmb.startChimeraListener();
}
void setChainMenuItems(List<String> chainNames)
* 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()
+ public void closeViewer(boolean closeChimera)
{
if (jmb.isChimeraRunning())
{
- String prompt = MessageManager
- .formatMessage("label.confirm_close_chimera", new Object[]
- { jmb.getViewerTitle(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 = JOptionPane.showConfirmDialog(this, prompt,
+ MessageManager.getString("label.close_viewer"),
+ JOptionPane.YES_NO_OPTION);
+ closeChimera = confirm == JOptionPane.YES_OPTION;
+ }
+ jmb.closeViewer(closeChimera);
}
- ap = null;
+ setAlignmentPanel(null);
_aps.clear();
_alignwith.clear();
_colourwith.clear();
String[] curfiles = jmb.getPdbFile(); // files currently in viewer
// TODO: replace with reference fetching/transfer code (validate PDBentry
// as a DBRef?)
- for (int pi = 0; pi < jmb.pdbentry.length; pi++)
+ for (int pi = 0; pi < jmb.getPdbCount(); pi++)
{
String file = null;
- thePdbEntry = jmb.pdbentry[pi];
+ thePdbEntry = jmb.getPdbEntry(pi);
if (thePdbEntry.getFile() == null)
{
/*
{
try
{
- initChimera("");
+ initChimera();
} catch (Exception ex)
{
Cache.log.error("Couldn't open Chimera viewer!", ex);
try
{
int pos = filePDBpos.get(num).intValue();
+ long startTime = startProgressBar("Chimera "
+ + MessageManager.getString("status.opening_file"));
jmb.openFile(pe);
- jmb.addSequence(pos, jmb.sequence[pos]);
+ jmb.addSequence(pos, jmb.getSequence()[pos]);
File fl = new File(pe.getFile());
String protocol = AppletFormatAdapter.URL;
try
}
} catch (Throwable e)
{
+ } finally
+ {
+ stopProgressBar("", startTime);
}
// Explicitly map to the filename used by Chimera ;
// TODO: use pe.getId() instead of pe.getFile() ?
- jmb.ssm.setMapping(jmb.sequence[pos], null, pe.getFile(),
+ jmb.getSsm().setMapping(jmb.getSequence()[pos], null,
+ pe.getFile(),
protocol);
} catch (OutOfMemoryError oomerror)
{
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 hdl = startProgressBar(MessageManager.formatMessage(
+ "status.fetching_pdb", new Object[]
+ { pdbid }));
try
{
pdbseq = pdbclient.getSequenceRecords(pdbid);
new OOMWarning("Retrieving PDB id " + pdbid, oomerror);
} finally
{
- if (progressBar != null)
- {
- progressBar.setProgressBar(
- MessageManager.getString("label.state_completed"), hdl);
- }
+ String msg = pdbid + " "
+ + MessageManager.getString("label.state_completed");
+ stopProgressBar(msg, hdl);
}
/*
* If PDB data were saved and are not invalid (empty alignment), return the
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).getPDBId()
+ .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;
+ }
+
+ public void stopProgressBar(String msg, long handle)
+ {
+ if (progressBar != null)
+ {
+ progressBar.setProgressBar(msg, handle);
+ }
+ }
+
@Override
public void pdbFile_actionPerformed(ActionEvent actionEvent)
{
jalview.gui.CutAndPasteTransfer cap = new jalview.gui.CutAndPasteTransfer();
try
{
- for (int pdbe = 0; pdbe < jmb.pdbentry.length; pdbe++)
+ for (int pdbe = 0; pdbe < jmb.getPdbCount(); pdbe++)
{
- cap.appendText(jmb.printMapping(jmb.pdbentry[pdbe].getFile()));
+ cap.appendText(jmb.printMapping(jmb.getPdbEntry(pdbe).getFile()));
cap.appendText("\n");
}
} catch (OutOfMemoryError e)
{
if (!jmb.isLoadingFromArchive())
{
- if (_colourwith.size() == 0 && ap != null)
+ if (_colourwith.size() == 0 && getAlignmentPanel() != null)
{
// Make the currently displayed alignment panel the associated view
- _colourwith.add(ap.alignFrame.alignPanel);
+ _colourwith.add(getAlignmentPanel().alignFrame.alignPanel);
}
}
// 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);
}
}
}
}
}
- public String getViewId()
- {
- if (viewId == null)
- {
- viewId = System.currentTimeMillis() + "." + this.hashCode();
- }
- return viewId;
- }
-
public void updateTitleAndMenus()
{
if (jmb.fileLoadingError != null && jmb.fileLoadingError.length() > 0)
repaint();
return;
}
- setChainMenuItems(jmb.chainNames);
+ setChainMenuItems(jmb.getChainNames());
- this.setTitle(jmb.getViewerTitle(true));
- if (jmb.getPdbFile().length > 1 && jmb.sequence.length > 1)
+ this.setTitle(jmb.getViewerTitle("Chimera", true));
+ if (jmb.getPdbFile().length > 1 && jmb.getSequence().length > 1)
{
viewerActionMenu.setVisible(true);
}
}
}
- protected void buildChimeraActionMenu()
- {
- if (_alignwith == null)
- {
- _alignwith = new Vector<AlignmentPanel>();
- }
- if (_alignwith.size() == 0 && ap != null)
- {
- _alignwith.add(ap);
- }
- ;
- for (Component c : viewerActionMenu.getMenuComponents())
- {
- if (c != alignStructs)
- {
- viewerActionMenu.remove((JMenuItem) c);
- }
- }
- }
-
/*
* (non-Javadoc)
*
private void alignStructs_withAllAlignPanels()
{
- if (ap == null)
+ if (getAlignmentPanel() == null)
{
return;
}
;
if (_alignwith.size() == 0)
{
- _alignwith.add(ap);
+ _alignwith.add(getAlignmentPanel());
}
;
try
return ap;
}
}
- return ap;
+ return getAlignmentPanel();
}
- /**
- *
- * @param ap2
- * @return true if this Chimera instance is linked with the given alignPanel
- */
- public boolean isLinkedWith(AlignmentPanel ap2)
- {
- return _aps.contains(ap2.av.getSequenceSetId());
- }
-
- public boolean isUsedforaligment(AlignmentPanel ap2)
- {
-
- return (_alignwith != null) && _alignwith.contains(ap2);
- }
-
- public boolean isUsedforcolourby(AlignmentPanel ap2)
+ @Override
+ public AAStructureBindingModel getBinding()
{
- return (_colourwith != null) && _colourwith.contains(ap2);
+ return jmb;
}
/**
+ * Ask Chimera to save its session to the designated file path. Returns true
+ * if successful, else false.
*
- * @return TRUE if the view is NOT being coloured by sequence associations.
+ * @param filepath
+ * @see getStateInfo
*/
- public boolean isColouredByChimera()
+ public boolean saveSession(String filepath)
{
- return !jmb.isColourBySequence();
+ boolean result = jmb.saveSession(filepath);
+ if (result)
+ {
+ this.chimeraSessionFile = filepath;
+ }
+ return result;
}
- public SequenceStructureBinding getBinding()
+ /**
+ * Returns the file path of the Chimera session file the last time it was
+ * saved. If it was never saved, returns an empty string. There is no
+ * guarantee that the Chimera session has not changed since it was saved.
+ */
+ @Override
+ public String getStateInfo()
{
- return jmb;
+ return this.chimeraSessionFile;
}
-
}