import jalview.datamodel.SequenceI;
import jalview.io.DataSourceType;
import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ResidueProperties;
import jalview.structure.AtomSpec;
+import jalview.structure.StructureCommandsI;
import jalview.structure.StructureListener;
import jalview.structure.StructureMapping;
-import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
import jalview.util.Comparison;
import jalview.util.MessageManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+
+import javax.swing.SwingUtilities;
/**
*
extends SequenceStructureBindingModel
implements StructureListener, StructureSelectionManagerProvider
{
+ private static final String COLOURING_STRUCTURES = MessageManager
+ .getString("status.colouring_structures");
+
/*
* the Jalview panel through which the user interacts
* with the structure viewer
*/
private JalviewStructureDisplayI viewer;
+ /*
+ * helper that generates command syntax
+ */
+ private StructureCommandsI commandGenerator;
+
private StructureSelectionManager ssm;
/*
+ * modelled chains, formatted as "pdbid:chainCode"
+ */
+ private List<String> chainNames;
+
+ /*
+ * lookup of pdb file name by key "pdbid:chainCode"
+ */
+ private Map<String, String> chainFile;
+
+ /*
* distinct PDB entries (pdb files) associated
* with sequences
*/
{
this.ssm = ssm;
this.sequence = seqs;
+ chainNames = new ArrayList<>();
+ chainFile = new HashMap<>();
}
/**
PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
DataSourceType protocol)
{
- this.ssm = ssm;
- this.sequence = sequenceIs;
+ this(ssm, sequenceIs);
this.nucleotide = Comparison.isNucleotide(sequenceIs);
this.pdbEntry = pdbentry;
this.protocol = protocol;
}
/**
- * Returns a list of chains mapped in this viewer.
+ * Returns a list of chains mapped in this viewer, formatted as
+ * "pdbid:chainCode"
*
* @return
*/
- public abstract List<String> getChainNames();
+ public List<String> getChainNames()
+ {
+ return chainNames;
+ }
/**
* Returns the Jalview panel hosting the structure viewer (if any)
viewer = v;
}
- public abstract void setJalviewColourScheme(ColourSchemeI cs);
-
/**
* Constructs and sends a command to align structures against a reference
* structure, based on one or more sequence alignments. May optionally return
public abstract String superposeStructures(AlignmentI[] alignments,
int[] structureIndices, HiddenColumns[] hiddenCols);
- public abstract void setBackgroundColour(Color col);
-
- protected abstract StructureMappingcommandSet[] getColourBySequenceCommands(
- String[] files, SequenceRenderer sr, AlignmentViewPanel avp);
-
/**
* returns the current sequenceRenderer that should be used to colour the
* structures
public abstract SequenceRenderer getSequenceRenderer(
AlignmentViewPanel alignment);
- protected abstract void colourBySequence(
- StructureMappingcommandSet[] colourBySequenceCommands);
+ /**
+ * Sends a command to the structure viewer to colour each chain with a
+ * distinct colour (to the extent supported by the viewer)
+ */
+ public void colourByChain()
+ {
+ colourBySequence = false;
+
+ // TODO: JAL-628 colour chains distinctly across all visible models
+
+ executeCommand(commandGenerator.colourByChain(), false,
+ COLOURING_STRUCTURES);
+ }
+
+ /**
+ * Sends a command to the structure viewer to colour each chain with a
+ * distinct colour (to the extent supported by the viewer)
+ */
+ public void colourByCharge()
+ {
+ colourBySequence = false;
+
+ executeCommand(commandGenerator.colourByCharge(), false,
+ COLOURING_STRUCTURES);
+ }
+
+ /**
+ * Sends a command to the structure to apply a colour scheme (defined in
+ * Jalview but not necessarily applied to the alignment), which defines a
+ * colour per residue letter. More complex schemes (e.g. that depend on
+ * consensus) cannot be used here and are ignored.
+ *
+ * @param cs
+ */
+ public void colourByJalviewColourScheme(ColourSchemeI cs)
+ {
+ colourBySequence = false;
+
+ if (cs == null || !cs.isSimple())
+ {
+ return;
+ }
+
+ /*
+ * build a map of {Residue3LetterCode, Color}
+ */
+ Map<String, Color> colours = new HashMap<>();
+ List<String> residues = ResidueProperties.getResidues(isNucleotide(),
+ false);
+ for (String resName : residues)
+ {
+ char res = resName.length() == 3
+ ? ResidueProperties.getSingleCharacterCode(resName)
+ : resName.charAt(0);
+ Color colour = cs.findColour(res, 0, null, null, 0f);
+ colours.put(resName, colour);
+ }
+
+ /*
+ * pass to the command constructor, and send the command
+ */
+ String cmd = commandGenerator.colourByResidues(colours);
+ executeCommand(cmd, false, COLOURING_STRUCTURES);
+ }
+
+ public void setBackgroundColour(Color col)
+ {
+ String cmd = commandGenerator.setBackgroundColour(col);
+ executeCommand(cmd, false, null);
+ }
+
+ /**
+ * Sends one command to the structure viewer. If {@code getReply} is true, the
+ * command is sent synchronously, otherwise in a deferred thread.
+ * <p>
+ * If a progress message is supplied, this is displayed before command
+ * execution, and removed afterwards.
+ *
+ * @param cmd
+ * @param getReply
+ * @param msg
+ * @return
+ */
+ private List<String> executeCommand(String cmd, boolean getReply,
+ String msg)
+ {
+ if (getReply)
+ {
+ return executeSynchronous(cmd, msg, getReply);
+ }
+ else
+ {
+ executeAsynchronous(cmd, msg);
+ return null;
+ }
+ }
+
+ /**
+ * Sends the command in the current thread. If a message is supplied, this is
+ * shown before the thread is started, and removed when it completes. May
+ * return a reply to the command if requested.
+ *
+ * @param cmd
+ * @param msg
+ * @param getReply
+ * @return
+ */
+ private List<String> executeSynchronous(String cmd, String msg, boolean getReply)
+ {
+ final JalviewStructureDisplayI theViewer = getViewer();
+ final long handle = msg == null ? 0 : theViewer.startProgressBar(msg);
+ try
+ {
+ return executeCommand(cmd, getReply);
+ } finally
+ {
+ if (msg != null)
+ {
+ theViewer.stopProgressBar(null, handle);
+ }
+ }
+ }
+
+ /**
+ * Sends the command in a separate thread. If a message is supplied, this is
+ * shown before the thread is started, and removed when it completes. No value
+ * is returned.
+ *
+ * @param cmd
+ * @param msg
+ */
+ private void executeAsynchronous(String cmd, String msg)
+ {
+ final JalviewStructureDisplayI theViewer = getViewer();
+ final long handle = msg == null ? 0 : theViewer.startProgressBar(msg);
- public abstract void colourByChain();
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ executeCommand(cmd, false);
+ } finally
+ {
+ if (msg != null)
+ {
+ theViewer.stopProgressBar(null, handle);
+ }
+ }
+ }
+ });
+ }
+
+ protected abstract List<String> executeCommand(String command,
+ boolean getReply);
- public abstract void colourByCharge();
+ protected List<String> executeCommands(boolean getReply,
+ String... commands)
+ {
+ List<String> response = null;
+ for (String cmd : commands)
+ {
+ response = executeCommand(cmd, getReply);
+ }
+ return response;
+ }
/**
* colour any structures associated with sequences in the given alignment
SequenceRenderer sr = getSequenceRenderer(alignmentv);
- StructureMappingcommandSet[] colourBySequenceCommands = getColourBySequenceCommands(
- files, sr, alignmentv);
- colourBySequence(colourBySequenceCommands);
+ String[] colourBySequenceCommands = commandGenerator
+ .colourBySequence(getSsm(), files, getSequence(), sr,
+ alignmentv);
+ executeCommands(false, colourBySequenceCommands);
+ }
+
+ /**
+ * Centre the display in the structure viewer
+ */
+ public void focusView()
+ {
+ executeCommand(commandGenerator.focusView(), false);
+ }
+
+ /**
+ * Generates and executes a command to show only specified chains in the
+ * structure viewer. The list of chains to show should contain entries
+ * formatted as "pdbid:chaincode".
+ *
+ * @param toShow
+ */
+ public void showChains(List<String> toShow)
+ {
+ // todo or reformat toShow list entries as modelNo:pdbId:chainCode ?
+
+ /*
+ * Reformat the pdbid:chainCode values as modelNo:chainCode
+ * since this is what is needed to construct the viewer command
+ * todo: find a less messy way to do this
+ */
+ List<String> showThese = new ArrayList<>();
+ for (String chainId : toShow)
+ {
+ String[] tokens = chainId.split("\\:");
+ if (tokens.length == 2)
+ {
+ String pdbFile = getFileForChain(chainId);
+ int modelNo = getModelNoForFile(pdbFile);
+ String model = modelNo == -1 ? "" : String.valueOf(modelNo);
+ showThese.add(model + ":" + tokens[1]);
+ }
+ }
+ executeCommand(commandGenerator.showChains(showThese), false);
}
+ /**
+ * Answers the structure viewer's model number given a PDB file name. Returns
+ * -1 if model number is not found.
+ *
+ * @param chainId
+ * @return
+ */
+ protected abstract int getModelNoForFile(String chainId);
+
public boolean hasFileLoadingError()
{
return fileLoadingError != null && fileLoadingError.length() > 0;
? ap.getFeatureRenderer()
: null;
}
+
+ protected void setStructureCommands(StructureCommandsI cmd)
+ {
+ commandGenerator = cmd;
+ }
+
+ /**
+ * Records association of one chain id (formatted as "pdbid:chainCode") with
+ * the corresponding PDB file name
+ *
+ * @param chainId
+ * @param fileName
+ */
+ public void addChainFile(String chainId, String fileName)
+ {
+ chainFile.put(chainId, fileName);
+ }
+
+ /**
+ * Returns the PDB filename for the given chain id (formatted as
+ * "pdbid:chainCode"), or null if not found
+ *
+ * @param chainId
+ * @return
+ */
+ protected String getFileForChain(String chainId)
+ {
+ return chainFile.get(chainId);
+ }
}