From d87b55e45cc1e6a5b7df3865ded1b87a0e3dc7ff Mon Sep 17 00:00:00 2001 From: gmungoc Date: Thu, 25 Jun 2020 12:50:47 +0100 Subject: [PATCH] JAL-3518 pull up [get|list]ResidueAttributes to StructureCommandsI --- src/jalview/ext/rbvi/chimera/ChimeraCommands.java | 31 +++- src/jalview/ext/rbvi/chimera/ChimeraXCommands.java | 20 ++- .../ext/rbvi/chimera/JalviewChimeraBinding.java | 79 ++++------- src/jalview/gui/ChimeraViewFrame.java | 21 +-- src/jalview/structure/StructureCommandsBase.java | 15 +- src/jalview/structure/StructureCommandsI.java | 16 +++ .../structures/models/AAStructureBindingModel.java | 150 +++++++++++++------- .../ext/rbvi/chimera/ChimeraCommandsTest.java | 14 ++ .../ext/rbvi/chimera/ChimeraXCommandsTest.java | 7 + 9 files changed, 232 insertions(+), 121 deletions(-) diff --git a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java index 857dbcc..43cdeb1 100644 --- a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java +++ b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java @@ -40,12 +40,21 @@ import jalview.util.ColorUtils; */ public class ChimeraCommands extends StructureCommandsBase { + // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/focus.html + private static final StructureCommand FOCUS_VIEW = new StructureCommand("focus"); + + // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/listen.html#listresattr + private static final StructureCommand LIST_RESIDUE_ATTRIBUTES = new StructureCommand("list resattr"); + + // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/stop.html private static final StructureCommand CLOSE_CHIMERA = new StructureCommand("stop really"); + // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/listen.html private static final StructureCommand STOP_NOTIFY_SELECTION = new StructureCommand("listen stop selection"); private static final StructureCommand STOP_NOTIFY_MODELS = new StructureCommand("listen stop models"); + // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/listen.html#listselection private static final StructureCommand GET_SELECTION = new StructureCommand("list selection level residue"); private static final StructureCommand SHOW_BACKBONE = new StructureCommand( @@ -54,6 +63,7 @@ public class ChimeraCommands extends StructureCommandsBase private static final StructureCommandI COLOUR_BY_CHARGE = new StructureCommand( "color white;color red ::ASP,GLU;color blue ::LYS,ARG;color yellow ::CYS"); + // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/rainbow.html private static final StructureCommandI COLOUR_BY_CHAIN = new StructureCommand( "rainbow chain"); @@ -207,8 +217,7 @@ public class ChimeraCommands extends StructureCommandsBase @Override public StructureCommandI focusView() { - // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/focus.html - return new StructureCommand("focus"); + return FOCUS_VIEW; } @Override @@ -417,7 +426,6 @@ public class ChimeraCommands extends StructureCommandsBase @Override public StructureCommandI closeViewer() { - // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/stop.html return CLOSE_CHIMERA; } @@ -434,7 +442,6 @@ public class ChimeraCommands extends StructureCommandsBase @Override public List stopNotifications() { - // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/listen.html List cmds = new ArrayList<>(); cmds.add(STOP_NOTIFY_MODELS); cmds.add(STOP_NOTIFY_SELECTION); @@ -447,4 +454,20 @@ public class ChimeraCommands extends StructureCommandsBase return GET_SELECTION; } + @Override + public StructureCommandI listResidueAttributes() + { + return LIST_RESIDUE_ATTRIBUTES; + } + + @Override + public StructureCommandI getResidueAttributes(String attName) + { + // this alternative command + // list residues spec ':*/attName' attr attName + // doesn't report 'None' values (which is good), but + // fails for 'average.bfactor' (which is bad): + return new StructureCommand("list residues attr '" + attName + "'"); + } + } diff --git a/src/jalview/ext/rbvi/chimera/ChimeraXCommands.java b/src/jalview/ext/rbvi/chimera/ChimeraXCommands.java index f1a8b5f..314e6db 100644 --- a/src/jalview/ext/rbvi/chimera/ChimeraXCommands.java +++ b/src/jalview/ext/rbvi/chimera/ChimeraXCommands.java @@ -35,17 +35,25 @@ import jalview.util.ColorUtils; */ public class ChimeraXCommands extends ChimeraCommands { + // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/info.html#resattr + private static final StructureCommand LIST_RESIDUE_ATTRIBUTES = new StructureCommand("info resattr"); + + // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/exit.html private static final StructureCommand CLOSE_CHIMERAX = new StructureCommand("exit"); + // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/info.html#notify private static final StructureCommand STOP_NOTIFY_SELECTION = new StructureCommand("info notify stop selection jalview"); private static final StructureCommand STOP_NOTIFY_MODELS = new StructureCommand("info notify stop models jalview"); - private static final StructureCommand GET_SELECTION = new StructureCommand("info selection level residue"); + // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/info.html#selection + private static final StructureCommand GET_SELECTION = new StructureCommand( + "info selection level residue"); private static final StructureCommand SHOW_BACKBONE = new StructureCommand( "~display all;~ribbon;show @CA|P atoms"); + // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/view.html private static final StructureCommand FOCUS_VIEW = new StructureCommand( "view"); @@ -76,7 +84,6 @@ public class ChimeraXCommands extends ChimeraCommands @Override public StructureCommandI focusView() { - // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/view.html return FOCUS_VIEW; } @@ -236,14 +243,12 @@ public class ChimeraXCommands extends ChimeraCommands @Override public StructureCommandI closeViewer() { - // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/exit.html return CLOSE_CHIMERAX; } @Override public List startNotifications(String uri) { - // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/info.html#notify List cmds = new ArrayList<>(); cmds.add(new StructureCommand("info notify start models prefix ModelChanged jalview url " + uri)); cmds.add(new StructureCommand("info notify start selection jalview prefix SelectionChanged url " + uri)); @@ -253,7 +258,6 @@ public class ChimeraXCommands extends ChimeraCommands @Override public List stopNotifications() { - // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/info.html#notify List cmds = new ArrayList<>(); cmds.add(STOP_NOTIFY_MODELS); cmds.add(STOP_NOTIFY_SELECTION); @@ -265,4 +269,10 @@ public class ChimeraXCommands extends ChimeraCommands { return GET_SELECTION; } + + @Override + public StructureCommandI listResidueAttributes() + { + return LIST_RESIDUE_ATTRIBUTES; + } } diff --git a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java index b20f135..c8875b4 100644 --- a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java +++ b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java @@ -224,10 +224,11 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel } /* - * the following call should not be needed but is temporarily included, - * to avoid a stack trace error in Chimera after "stop really" is sent + * the following call is added to avoid a stack trace error in Chimera + * after "stop really" is sent; Chimera > 1.14 will not need it; see also + * http://plato.cgl.ucsf.edu/trac/chimera/ticket/17597 */ - if (closeChimera) + if (closeChimera && (getViewerType() == ViewerType.CHIMERA)) { chimeraManager.getChimeraProcess().destroy(); } @@ -636,36 +637,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel } /** - * Get Chimera residues which have the named attribute, find the mapped - * positions in the Jalview sequence(s), and set as sequence features - * - * @param attName - * @param alignmentPanel - */ - public void copyStructureAttributesToFeatures(String attName, - AlignmentViewPanel alignmentPanel) - { - // todo pull up to AAStructureBindingModel (and interface?) - - /* - * ask Chimera to list residues with the attribute, reporting its value - */ - // this alternative command - // list residues spec ':*/attName' attr attName - // doesn't report 'None' values (which is good), but - // fails for 'average.bfactor' (which is bad): - - String cmd = "list residues attr '" + attName + "'"; - List residues = executeCommand(new StructureCommand(cmd), true); - - boolean featureAdded = createFeaturesForAttributes(attName, residues); - if (featureAdded) - { - alignmentPanel.getFeatureRenderer().featuresAdded(); - } - } - - /** * Create features in Jalview for the given attribute name and structure * residues. * @@ -678,12 +649,12 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel * * @param attName * @param residues - * @return + * @return the number of features added */ - protected boolean createFeaturesForAttributes(String attName, + protected int createFeaturesForAttributes(String attName, List residues) { - boolean featureAdded = false; + int featuresAdded = 0; String featureGroup = getViewerFeatureGroup(); for (String residue : residues) @@ -711,7 +682,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel spec = parseAtomSpec(atomSpec); } catch (IllegalArgumentException e) { - System.err.println("Problem parsing atomspec " + atomSpec); + Cache.log.error("Problem parsing atomspec " + atomSpec); continue; } @@ -751,10 +722,13 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel start, end, score, featureGroup); // todo: should SequenceFeature have an explicit property for chain? // note: repeating the action shouldn't duplicate features - featureAdded |= seq.addSequenceFeature(sf); + if (seq.addSequenceFeature(sf)) + { + featuresAdded++; + } } } - return featureAdded; + return featuresAdded; } /** @@ -788,19 +762,28 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel */ public List getChimeraAttributes() { - List atts = chimeraManager.getAttrList(); - Iterator it = atts.iterator(); - while (it.hasNext()) + List attributes = new ArrayList<>(); + StructureCommandI command = getCommandGenerator().listResidueAttributes(); + final List reply = executeCommand(command, true); + if (reply != null) { - if (it.next().startsWith(ChimeraCommands.NAMESPACE_PREFIX)) + for (String inputLine : reply) { - /* - * attribute added from Jalview - exclude it - */ - it.remove(); + String[] lineParts = inputLine.split("\\s"); + if (lineParts.length == 2 && lineParts[0].equals("resattr")) + { + String attName = lineParts[1]; + /* + * exclude attributes added from Jalview + */ + if (!attName.startsWith(ChimeraCommands.NAMESPACE_PREFIX)) + { + attributes.add(attName); + } + } } } - return atts; + return attributes; } /** diff --git a/src/jalview/gui/ChimeraViewFrame.java b/src/jalview/gui/ChimeraViewFrame.java index 0e5675c..5fd185d 100644 --- a/src/jalview/gui/ChimeraViewFrame.java +++ b/src/jalview/gui/ChimeraViewFrame.java @@ -115,8 +115,8 @@ public class ChimeraViewFrame extends StructureViewerBase } /** - * Query Chimera for its residue attribute names and add them as items off the - * attributes menu + * Query the structure viewer for its residue attribute names and add them as + * items off the attributes menu * * @param attributesMenu */ @@ -133,7 +133,11 @@ public class ChimeraViewFrame extends StructureViewerBase @Override public void actionPerformed(ActionEvent e) { - getChimeraAttributes(attName); + if (getBinding().copyStructureAttributesToFeatures(attName, + getAlignmentPanel()) > 0) + { + getAlignmentPanel().getFeatureRenderer().featuresAdded(); + } } }); attributesMenu.add(menuItem); @@ -141,17 +145,6 @@ public class ChimeraViewFrame extends StructureViewerBase } /** - * Read residues in Chimera with the given attribute name, and set as features - * on the corresponding sequence positions (if any) - * - * @param attName - */ - protected void getChimeraAttributes(String attName) - { - jmb.copyStructureAttributesToFeatures(attName, getAlignmentPanel()); - } - - /** * Sends command(s) to the structure viewer to create residue attributes for * visible Jalview features */ diff --git a/src/jalview/structure/StructureCommandsBase.java b/src/jalview/structure/StructureCommandsBase.java index 774327c..57544b7 100644 --- a/src/jalview/structure/StructureCommandsBase.java +++ b/src/jalview/structure/StructureCommandsBase.java @@ -15,9 +15,10 @@ import java.util.Map.Entry; */ public abstract class StructureCommandsBase implements StructureCommandsI { - private static final String CMD_SEPARATOR = ";"; public static final String NAMESPACE_PREFIX = "jv_"; + private static final String CMD_SEPARATOR = ";"; + /** * Returns something that separates concatenated commands * @@ -241,4 +242,16 @@ public abstract class StructureCommandsBase implements StructureCommandsI { return null; } + + @Override + public StructureCommandI listResidueAttributes() + { + return null; + } + + @Override + public StructureCommandI getResidueAttributes(String attName) + { + return null; + } } diff --git a/src/jalview/structure/StructureCommandsI.java b/src/jalview/structure/StructureCommandsI.java index c224187..91e0494 100644 --- a/src/jalview/structure/StructureCommandsI.java +++ b/src/jalview/structure/StructureCommandsI.java @@ -200,4 +200,20 @@ public interface StructureCommandsI * @return */ StructureCommandI getSelectedResidues(); + + /** + * Returns a command to list the unique names of residue attributes, or null + * if no such command is supported + * + * @return + */ + StructureCommandI listResidueAttributes(); + + /** + * Returns a command to list residues with an attribute of the given name, + * with attribute value, or null if no such command is supported + * + * @return + */ + StructureCommandI getResidueAttributes(String attName); } diff --git a/src/jalview/structures/models/AAStructureBindingModel.java b/src/jalview/structures/models/AAStructureBindingModel.java index f69a423..d92c78a 100644 --- a/src/jalview/structures/models/AAStructureBindingModel.java +++ b/src/jalview/structures/models/AAStructureBindingModel.java @@ -47,6 +47,7 @@ import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.ext.rbvi.chimera.JalviewChimeraBinding; +import jalview.gui.AlignmentPanel; import jalview.gui.Desktop; import jalview.gui.StructureViewer.ViewerType; import jalview.io.DataSourceType; @@ -56,6 +57,7 @@ import jalview.schemes.ColourSchemeI; import jalview.schemes.ResidueProperties; import jalview.structure.AtomSpec; import jalview.structure.AtomSpecModel; +import jalview.structure.StructureCommand; import jalview.structure.StructureCommandI; import jalview.structure.StructureCommandsI; import jalview.structure.StructureListener; @@ -83,20 +85,20 @@ public abstract class AAStructureBindingModel public static class SuperposeData { public String filename; - + public String pdbId; - + public String chain = ""; - + public boolean isRna; - + /* * The pdb residue number (if any) mapped to columns of the alignment */ public int[] pdbResNo; // or use SparseIntArray? - + public String modelId; - + /** * Constructor * @@ -262,6 +264,7 @@ public abstract class AAStructureBindingModel chains = newchains; return chainmaps > 0; } + public StructureSelectionManager getSsm() { return ssm; @@ -659,7 +662,8 @@ public abstract class AAStructureBindingModel * @return */ protected int findSuperposableResidues(AlignmentI alignment, - BitSet matched, AAStructureBindingModel.SuperposeData[] structures) + BitSet matched, + AAStructureBindingModel.SuperposeData[] structures) { int refStructure = -1; String[] files = getStructureFiles(); @@ -885,8 +889,8 @@ public abstract class AAStructureBindingModel * Calculate the superposable alignment columns ('matched'), and the * corresponding structure residue positions (structures.pdbResNo) */ - int refStructure = findSuperposableResidues(alignment, - matched, structures); + int refStructure = findSuperposableResidues(alignment, matched, + structures); /* * require at least 4 positions to be able to execute superposition @@ -894,8 +898,8 @@ public abstract class AAStructureBindingModel int nmatched = matched.cardinality(); if (nmatched < MIN_POS_TO_SUPERPOSE) { - String msg = MessageManager.formatMessage("label.insufficient_residues", - nmatched); + String msg = MessageManager + .formatMessage("label.insufficient_residues", nmatched); error += view.getViewName() + ": " + msg + "; "; continue; } @@ -939,7 +943,8 @@ public abstract class AAStructureBindingModel return error; } - private AtomSpecModel getAtomSpec(AAStructureBindingModel.SuperposeData superposeData, + private AtomSpecModel getAtomSpec( + AAStructureBindingModel.SuperposeData superposeData, BitSet matched) { AtomSpecModel model = new AtomSpecModel(); @@ -1008,7 +1013,7 @@ public abstract class AAStructureBindingModel { return; } - + /* * build a map of {Residue3LetterCode, Color} */ @@ -1078,7 +1083,7 @@ public abstract class AAStructureBindingModel */ final JalviewStructureDisplayI theViewer = getViewer(); final long handle = msg == null ? 0 : theViewer.startProgressBar(msg); - + SwingUtilities.invokeLater(new Runnable() { @Override @@ -1126,7 +1131,7 @@ public abstract class AAStructureBindingModel */ final JalviewStructureDisplayI theViewer = getViewer(); final long handle = msg == null ? 0 : theViewer.startProgressBar(msg); - + List response = getReply ? new ArrayList<>() : null; try { @@ -1356,17 +1361,17 @@ public abstract class AAStructureBindingModel AlignmentI al = viewport.getAlignment(); Map colourMap = new LinkedHashMap<>(); Color lastColour = null; - + for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++) { final String modelId = getModelIdForFile(files[pdbfnum]); StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]); - + if (mapping == null || mapping.length < 1) { continue; } - + int startPos = -1, lastPos = -1; String lastChain = ""; for (int s = 0; s < sequence[pdbfnum].length; s++) @@ -1386,14 +1391,14 @@ public abstract class AAStructureBindingModel continue; } int pos = mapping[m].getPDBResNum(asp.findPosition(r)); - + if (pos < 1 || pos == lastPos) { continue; } - + Color colour = sr.getResidueColour(seq, r, finder); - + /* * darker colour for hidden regions */ @@ -1401,9 +1406,9 @@ public abstract class AAStructureBindingModel { colour = Color.GRAY; } - + final String chain = mapping[m].getChain(); - + /* * Just keep incrementing the end position for this colour range * _unless_ colour, PDB model or chain has changed, or there is a @@ -1416,8 +1421,8 @@ public abstract class AAStructureBindingModel { if (startPos != -1) { - addAtomSpecRange(colourMap, lastColour, modelId, - startPos, lastPos, lastChain); + addAtomSpecRange(colourMap, lastColour, modelId, startPos, + lastPos, lastChain); } startPos = pos; } @@ -1469,8 +1474,9 @@ public abstract class AAStructureBindingModel } /** - * Helper method to add one contiguous range to the AtomSpec model for the given - * value (creating the model if necessary). As used by Jalview, {@code value} is + * Helper method to add one contiguous range to the AtomSpec model for the + * given value (creating the model if necessary). As used by Jalview, + * {@code value} is *
    *
  • a colour, when building a 'colour structure by sequence' command
  • *
  • a feature value, when building a 'set Chimera attributes from features' @@ -1485,8 +1491,8 @@ public abstract class AAStructureBindingModel * @param chain */ public static final void addAtomSpecRange(Map map, - Object value, - String model, int startPos, int endPos, String chain) + Object value, String model, int startPos, int endPos, + String chain) { /* * Get/initialize map of data for the colour @@ -1497,7 +1503,7 @@ public abstract class AAStructureBindingModel atomSpec = new AtomSpecModel(); map.put(value, atomSpec); } - + atomSpec.addRange(model, startPos, endPos, chain); } @@ -1530,8 +1536,8 @@ public abstract class AAStructureBindingModel saveSession(f); } catch (IOException e) { - Cache.log.error(String.format("Error saving %s session: %s", - prefix, e.toString())); + Cache.log.error(String.format("Error saving %s session: %s", prefix, + e.toString())); } return f; @@ -1544,8 +1550,7 @@ public abstract class AAStructureBindingModel */ protected void saveSession(File f) { - StructureCommandI cmd = commandGenerator - .saveSession(f.getPath()); + StructureCommandI cmd = commandGenerator.saveSession(f.getPath()); if (cmd != null) { executeCommand(cmd, false); @@ -1586,7 +1591,7 @@ public abstract class AAStructureBindingModel } stopListening(); - + if (forceClose) { StructureCommandI cmd = getCommandGenerator().closeViewer(); @@ -1632,10 +1637,10 @@ public abstract class AAStructureBindingModel { return theMap; } - + AlignViewportI viewport = viewPanel.getAlignViewport(); List visibleFeatures = fr.getDisplayedFeatureTypes(); - + /* * if alignment is showing features from complement, we also transfer * these features to the corresponding mapped structure residues @@ -1657,7 +1662,7 @@ public abstract class AAStructureBindingModel { return theMap; } - + AlignmentI alignment = viewPanel.getAlignment(); SequenceI[][] seqs = getSequence(); @@ -1665,12 +1670,12 @@ public abstract class AAStructureBindingModel { String modelId = getModelIdForFile(files[pdbfnum]); StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]); - + if (mapping == null || mapping.length < 1) { continue; } - + for (int seqNo = 0; seqNo < seqs[pdbfnum].length; seqNo++) { for (int m = 0; m < mapping.length; m++) @@ -1721,8 +1726,8 @@ public abstract class AAStructureBindingModel } /** - * Scans visible features in mapped positions of the CDS/peptide complement, and - * adds any found to the map of attribute values/structure positions + * Scans visible features in mapped positions of the CDS/peptide complement, + * and adds any found to the map of attribute values/structure positions * * @param complementRenderer * @param structureMapping @@ -1751,7 +1756,7 @@ public abstract class AAStructureBindingModel for (SequenceFeature sf : mf.features) { String type = sf.getType(); - + /* * Don't copy features which originated from Chimera */ @@ -1760,14 +1765,14 @@ public abstract class AAStructureBindingModel { continue; } - + /* * record feature 'value' (score/description/type) as at the * corresponding structure position */ List mappedRanges = structureMapping .getPDBResNumRanges(seqPos, seqPos); - + if (!mappedRanges.isEmpty()) { String value = sf.getDescription(); @@ -1817,7 +1822,7 @@ public abstract class AAStructureBindingModel for (SequenceFeature sf : sfs) { String type = sf.getType(); - + /* * Don't copy features which originated from Chimera */ @@ -1826,10 +1831,10 @@ public abstract class AAStructureBindingModel { continue; } - + List mappedRanges = mapping.getPDBResNumRanges(sf.getBegin(), sf.getEnd()); - + if (!mappedRanges.isEmpty()) { String value = sf.getDescription(); @@ -1882,7 +1887,7 @@ public abstract class AAStructureBindingModel { externalViewerMonitor = new Thread(new Runnable() { - + @Override public void run() { @@ -1933,4 +1938,51 @@ public abstract class AAStructureBindingModel executeCommands(commands, false, null); } } + + /** + * If supported by the structure viewer, queries it for all residue attributes + * with the given attribute name, and creates features on corresponding + * residues of the alignment. Returns the number of features added. + * + * @param attName + * @param alignmentPanel + * @return + */ + public int copyStructureAttributesToFeatures(String attName, + AlignmentPanel alignmentPanel) + { + StructureCommandI cmd = getCommandGenerator() + .getResidueAttributes(attName); + if (cmd == null) + { + return 0; + } + List residueAttributes = executeCommand(cmd, true); + + int featuresAdded = createFeaturesForAttributes(attName, + residueAttributes); + if (featuresAdded > 0) + { + alignmentPanel.getFeatureRenderer().featuresAdded(); + } + return featuresAdded; + } + + /** + * Parses {@code residueAttributes} and creates sequence features on any + * mapped alignment residues. Returns the number of features created. + *

    + * {@code residueAttributes} is the reply from the structure viewer to a + * command to list any residue attributes for the given attribute name. Syntax + * and parsing of this is viewer-specific. + * + * @param attName + * @param residueAttributes + * @return + */ + protected int createFeaturesForAttributes(String attName, + List residueAttributes) + { + return 0; + } } diff --git a/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java b/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java index 15d744b..6880985 100644 --- a/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java +++ b/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java @@ -363,6 +363,20 @@ public class ChimeraCommandsTest } @Test(groups = "Functional") + public void testListResidueAttributes() + { + assertEquals(testee.listResidueAttributes(), + new StructureCommand("list resattr")); + } + + @Test(groups = "Functional") + public void testGetResidueAttributes() + { + assertEquals(testee.getResidueAttributes("binding site"), + new StructureCommand("list residues attr 'binding site'")); + } + + @Test(groups = "Functional") public void testStartNotifications() { List cmds = testee.startNotifications("to here"); diff --git a/test/jalview/ext/rbvi/chimera/ChimeraXCommandsTest.java b/test/jalview/ext/rbvi/chimera/ChimeraXCommandsTest.java index c1fa528..f677cab 100644 --- a/test/jalview/ext/rbvi/chimera/ChimeraXCommandsTest.java +++ b/test/jalview/ext/rbvi/chimera/ChimeraXCommandsTest.java @@ -354,4 +354,11 @@ public class ChimeraXCommandsTest assertEquals(cmds.get(0), new StructureCommand("info notify stop models jalview")); assertEquals(cmds.get(1), new StructureCommand("info notify stop selection jalview")); } + + @Test(groups = "Functional") + public void testListResidueAttributes() + { + assertEquals(testee.listResidueAttributes(), + new StructureCommand("info resattr")); + } } -- 1.7.10.2