From 2ab7b9b152018bb808693218ad88dc3778166492 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Thu, 20 Feb 2020 14:06:13 +0000 Subject: [PATCH] JAL-2422 pull-up refactoring of structure commands (continued) --- resources/lang/Messages.properties | 2 +- resources/lang/Messages_es.properties | 2 +- .../api/structures/JalviewStructureDisplayI.java | 8 - src/jalview/appletgui/AppletJmol.java | 22 +- src/jalview/appletgui/UserDefinedColours.java | 2 +- src/jalview/ext/jmol/JalviewJmolBinding.java | 238 ++------ src/jalview/ext/jmol/JmolCommands.java | 124 +++- src/jalview/ext/rbvi/chimera/ChimeraCommands.java | 152 +++-- src/jalview/ext/rbvi/chimera/ChimeraXCommands.java | 627 ++++++++++++++++++++ .../ext/rbvi/chimera/JalviewChimeraBinding.java | 222 +------ src/jalview/gui/AppJmol.java | 26 +- src/jalview/gui/ChimeraViewFrame.java | 24 +- src/jalview/gui/ChimeraXViewFrame.java | 28 + src/jalview/gui/JalviewChimeraBindingModel.java | 7 +- src/jalview/gui/JalviewChimeraXBindingModel.java | 18 + src/jalview/gui/StructureViewerBase.java | 30 +- .../javascript/MouseOverStructureListener.java | 18 +- src/jalview/structure/StructureCommandsBase.java | 12 + .../structure/StructureCommandsFactory.java | 32 + src/jalview/structure/StructureCommandsI.java | 90 +++ .../structures/models/AAStructureBindingModel.java | 299 +++++++++- test/jalview/ext/jmol/JmolCommandsTest.java | 41 +- .../ext/rbvi/chimera/ChimeraCommandsTest.java | 34 +- .../ext/rbvi/chimera/JalviewChimeraView.java | 8 +- .../structure/StructureSelectionManagerTest.java | 17 +- .../models/AAStructureBindingModelTest.java | 98 +-- 26 files changed, 1454 insertions(+), 727 deletions(-) create mode 100644 src/jalview/ext/rbvi/chimera/ChimeraXCommands.java create mode 100644 src/jalview/gui/ChimeraXViewFrame.java create mode 100644 src/jalview/gui/JalviewChimeraXBindingModel.java create mode 100644 src/jalview/structure/StructureCommandsBase.java create mode 100644 src/jalview/structure/StructureCommandsFactory.java create mode 100644 src/jalview/structure/StructureCommandsI.java diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index c5031c2..7ec251d 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -1123,7 +1123,7 @@ status.fetching_db_refs = Fetching db refs status.loading_cached_pdb_entries = Loading Cached PDB Entries status.searching_for_pdb_structures = Searching for PDB Structures status.opening_file_for = opening file for -status.colouring_chimera = Colouring Chimera +status.colouring_structures = Colouring structures label.font_doesnt_have_letters_defined = Font doesn't have letters defined\nso cannot be used\nwith alignment data label.font_too_small = Font size is too small label.error_loading_file_params = Error loading file {0} diff --git a/resources/lang/Messages_es.properties b/resources/lang/Messages_es.properties index 369ac96..af1fc87 100644 --- a/resources/lang/Messages_es.properties +++ b/resources/lang/Messages_es.properties @@ -1198,7 +1198,7 @@ label.confirm_close_chimera=Cerrar tooltip.rnalifold_calculations=Se calcularán predicciones de estructura secondaria de RNA para el alineaminento, y se actualizarán si se efectuan cambios tooltip.rnalifold_settings=Modificar la configuración de la predicción RNAAlifold. Úselo para ocultar o mostrar resultados del cálculo de RNA, o cambiar parámetros de el plegado de RNA. label.show_selected_annotations=Mostrar anotaciones seleccionadas -status.colouring_chimera=Coloreando Chimera +status.colouring_structures=Coloreando estructuras label.configure_displayed_columns=Configurar Columnas Mostradas label.aacon_calculations=cálculos AACon label.pdb_web-service_error=Error de servicio web PDB diff --git a/src/jalview/api/structures/JalviewStructureDisplayI.java b/src/jalview/api/structures/JalviewStructureDisplayI.java index 506334c..d8c8371 100644 --- a/src/jalview/api/structures/JalviewStructureDisplayI.java +++ b/src/jalview/api/structures/JalviewStructureDisplayI.java @@ -23,7 +23,6 @@ package jalview.api.structures; import jalview.api.AlignmentViewPanel; import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; -import jalview.schemes.ColourSchemeI; import jalview.structures.models.AAStructureBindingModel; public interface JalviewStructureDisplayI @@ -59,13 +58,6 @@ public interface JalviewStructureDisplayI void closeViewer(boolean closeExternalViewer); /** - * apply a colourscheme to the structures in the viewer - * - * @param colourScheme - */ - void setJalviewColourScheme(ColourSchemeI colourScheme); - - /** * * @return true if all background sequence/structure binding threads have * completed for this viewer instance diff --git a/src/jalview/appletgui/AppletJmol.java b/src/jalview/appletgui/AppletJmol.java index 2cd9ee5..89a912f 100644 --- a/src/jalview/appletgui/AppletJmol.java +++ b/src/jalview/appletgui/AppletJmol.java @@ -406,7 +406,7 @@ public class AppletJmol extends EmbmenuFrame implements } } } - jmb.centerViewer(toshow); + jmb.showChains(toshow); } void closeViewer() @@ -455,41 +455,41 @@ public class AppletJmol extends EmbmenuFrame implements else if (evt.getSource() == zappo) { setEnabled(zappo); - jmb.setJalviewColourScheme(new ZappoColourScheme()); + jmb.colourByJalviewColourScheme(new ZappoColourScheme()); } else if (evt.getSource() == taylor) { setEnabled(taylor); - jmb.setJalviewColourScheme(new TaylorColourScheme()); + jmb.colourByJalviewColourScheme(new TaylorColourScheme()); } else if (evt.getSource() == hydro) { setEnabled(hydro); - jmb.setJalviewColourScheme(new HydrophobicColourScheme()); + jmb.colourByJalviewColourScheme(new HydrophobicColourScheme()); } else if (evt.getSource() == helix) { setEnabled(helix); - jmb.setJalviewColourScheme(new HelixColourScheme()); + jmb.colourByJalviewColourScheme(new HelixColourScheme()); } else if (evt.getSource() == strand) { setEnabled(strand); - jmb.setJalviewColourScheme(new StrandColourScheme()); + jmb.colourByJalviewColourScheme(new StrandColourScheme()); } else if (evt.getSource() == turn) { setEnabled(turn); - jmb.setJalviewColourScheme(new TurnColourScheme()); + jmb.colourByJalviewColourScheme(new TurnColourScheme()); } else if (evt.getSource() == buried) { setEnabled(buried); - jmb.setJalviewColourScheme(new BuriedColourScheme()); + jmb.colourByJalviewColourScheme(new BuriedColourScheme()); } else if (evt.getSource() == purinepyrimidine) { - jmb.setJalviewColourScheme(new PurinePyrimidineColourScheme()); + jmb.colourByJalviewColourScheme(new PurinePyrimidineColourScheme()); } else if (evt.getSource() == user) { @@ -693,9 +693,9 @@ public class AppletJmol extends EmbmenuFrame implements * * } */ - public void setJalviewColourScheme(UserColourScheme ucs) + public void colourByJalviewColourScheme(UserColourScheme ucs) { - jmb.setJalviewColourScheme(ucs); + jmb.colourByJalviewColourScheme(ucs); } public AlignmentPanel getAlignmentPanelFor(AlignmentI alignment) diff --git a/src/jalview/appletgui/UserDefinedColours.java b/src/jalview/appletgui/UserDefinedColours.java index 6831a73..bfce880 100644 --- a/src/jalview/appletgui/UserDefinedColours.java +++ b/src/jalview/appletgui/UserDefinedColours.java @@ -524,7 +524,7 @@ public class UserDefinedColours extends Panel } else if (jmol != null) { - jmol.setJalviewColourScheme(ucs); + jmol.colourByJalviewColourScheme(ucs); } else if (pdbcanvas != null) { diff --git a/src/jalview/ext/jmol/JalviewJmolBinding.java b/src/jalview/ext/jmol/JalviewJmolBinding.java index e19bb29..9b8fb91 100644 --- a/src/jalview/ext/jmol/JalviewJmolBinding.java +++ b/src/jalview/ext/jmol/JalviewJmolBinding.java @@ -20,9 +20,7 @@ */ package jalview.ext.jmol; -import jalview.api.AlignmentViewPanel; import jalview.api.FeatureRenderer; -import jalview.api.SequenceRenderer; import jalview.datamodel.AlignmentI; import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; @@ -30,15 +28,11 @@ import jalview.datamodel.SequenceI; import jalview.gui.IProgressIndicator; import jalview.io.DataSourceType; import jalview.io.StructureFile; -import jalview.schemes.ColourSchemeI; -import jalview.schemes.ResidueProperties; import jalview.structure.AtomSpec; -import jalview.structure.StructureMappingcommandSet; import jalview.structure.StructureSelectionManager; import jalview.structures.models.AAStructureBindingModel; import jalview.util.MessageManager; -import java.awt.Color; import java.awt.Container; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; @@ -46,7 +40,6 @@ import java.io.File; import java.net.URL; import java.util.ArrayList; import java.util.BitSet; -import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.StringTokenizer; @@ -58,7 +51,6 @@ import org.jmol.api.JmolSelectionListener; import org.jmol.api.JmolStatusListener; import org.jmol.api.JmolViewer; import org.jmol.c.CBK; -import org.jmol.script.T; import org.jmol.viewer.Viewer; public abstract class JalviewJmolBinding extends AAStructureBindingModel @@ -77,10 +69,6 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel Vector atomsPicked = new Vector<>(); - private List chainNames; - - Hashtable chainFile; - /* * the default or current model displayed if the model cannot be identified * from the selection message @@ -102,6 +90,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel DataSourceType protocol) { super(ssm, pdbentry, sequenceIs, protocol); + setStructureCommands(new JmolCommands()); /* * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(), * "jalviewJmol", ap.av.applet .getDocumentBase(), @@ -119,6 +108,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel jmolViewer = theViewer; jmolViewer.setJmolStatusListener(this); jmolViewer.addSelectionListener(this); + setStructureCommands(new JmolCommands()); } /** @@ -132,36 +122,6 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel return getViewerTitle("Jmol", true); } - /** - * prepare the view for a given set of models/chains. chainList contains - * strings of the form 'pdbfilename:Chaincode' - * - * @param chainList - * list of chains to make visible - */ - public void centerViewer(Vector chainList) - { - StringBuilder cmd = new StringBuilder(128); - int mlength, p; - for (String lbl : chainList) - { - mlength = 0; - do - { - p = mlength; - mlength = lbl.indexOf(":", p); - } while (p < mlength && mlength < (lbl.length() - 2)); - // TODO: lookup each pdb id and recover proper model number for it. - cmd.append(":" + lbl.substring(mlength + 1) + " /" - + (1 + getModelNum(chainFile.get(lbl))) + " or "); - } - if (cmd.length() > 0) - { - cmd.setLength(cmd.length() - 4); - } - evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd); - } - public void closeViewer() { // remove listeners for all structures in viewer @@ -172,24 +132,6 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel releaseUIResources(); } - @Override - public void colourByChain() - { - colourBySequence = false; - // TODO: colour by chain should colour each chain distinctly across all - // visible models - // TODO: http://issues.jalview.org/browse/JAL-628 - evalStateCommand("select *;color chain"); - } - - @Override - public void colourByCharge() - { - colourBySequence = false; - evalStateCommand("select *;color white;select ASP,GLU;color red;" - + "select LYS,ARG;color blue;select CYS;color yellow"); - } - /** * superpose the structures associated with sequences in the alignment * according to their corresponding positions. @@ -442,13 +384,13 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel { // TODO is performing selectioncom redundant here? is done later on // System.out.println("Select regions:\n" + selectioncom.toString()); - evalStateCommand("select *; cartoons off; backbone; select (" - + selectioncom.toString() + "); cartoons; "); + executeCommand("select *; cartoons off; backbone; select (" + + selectioncom.toString() + "); cartoons; ", false); // selcom.append("; ribbons; "); String cmdString = command.toString(); // System.out.println("Superimpose command(s):\n" + cmdString); - evalStateCommand(cmdString); + executeCommand(cmdString, false); } } if (selectioncom.length() > 0) @@ -458,8 +400,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel selectioncom.setLength(selectioncom.length() - 1); } // System.out.println("Select regions:\n" + selectioncom.toString()); - evalStateCommand("select *; cartoons off; backbone; select (" - + selectioncom.toString() + "); cartoons; "); + executeCommand("select *; cartoons off; backbone; select (" + + selectioncom.toString() + "); cartoons; ", false); // evalStateCommand("select *; backbone; select "+selcom.toString()+"; // cartoons; center "+selcom.toString()); } @@ -467,8 +409,13 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel return null; } - public void evalStateCommand(String command) + @Override + public List executeCommand(String command, boolean getReply) { + if (command == null) + { + return null; + } jmolHistory(false); if (lastCommand == null || !lastCommand.equals(command)) { @@ -476,60 +423,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel } jmolHistory(true); lastCommand = command; - } - - Thread colourby = null; - /** - * Sends a set of colour commands to the structure viewer - * - * @param colourBySequenceCommands - */ - @Override - protected void colourBySequence( - final StructureMappingcommandSet[] colourBySequenceCommands) - { - if (colourby != null) - { - colourby.interrupt(); - colourby = null; - } - colourby = new Thread(new Runnable() - { - @Override - public void run() - { - for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands) - { - for (String cbyseq : cpdbbyseq.commands) - { - executeWhenReady(cbyseq); - } - } - } - }); - colourby.start(); - } - - /** - * @param files - * @param sr - * @param viewPanel - * @return - */ - @Override - protected StructureMappingcommandSet[] getColourBySequenceCommands( - String[] files, SequenceRenderer sr, AlignmentViewPanel viewPanel) - { - return JmolCommands.getColourBySequenceCommand(getSsm(), files, - getSequence(), sr, viewPanel); - } - - /** - * @param command - */ - protected void executeWhenReady(String command) - { - evalStateCommand(command); + return null; } public void createImage(String file, String type, int quality) @@ -570,19 +464,6 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel return null; } - public Color getColour(int atomIndex, int pdbResNum, String chain, - String pdbfile) - { - if (getModelNum(pdbfile) < 0) - { - return null; - } - // TODO: verify atomIndex is selecting correct model. - // return new Color(viewer.getAtomArgb(atomIndex)); Jmol 12.2.4 - int colour = jmolViewer.ms.at[atomIndex].atomPropertyInt(T.color); - return new Color(colour); - } - /** * instruct the Jalview binding to update the pdbentries vector if necessary * prior to matching the jmol view's contents to the list of structure files @@ -590,23 +471,6 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel */ public abstract void refreshPdbEntries(); - private int getModelNum(String modelFileName) - { - String[] mfn = getStructureFiles(); - if (mfn == null) - { - return -1; - } - for (int i = 0; i < mfn.length; i++) - { - if (mfn[i].equalsIgnoreCase(modelFileName)) - { - return i; - } - } - return -1; - } - /** * map between index of model filename returned from getPdbFile and the first * index of models from this file in the viewer. Note - this is not trimmed - @@ -854,7 +718,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel sb.append(";set hoverLabel \"").append(toks.nextToken()).append(" ") .append(toks.nextToken()); sb.append("|").append(label).append("\""); - evalStateCommand(sb.toString()); + executeCommand(sb.toString(), false); } } @@ -1036,8 +900,6 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel fileLoadingError = null; String[] oldmodels = modelFileNames; modelFileNames = null; - chainNames = new ArrayList<>(); - chainFile = new Hashtable<>(); boolean notifyLoaded = false; String[] modelfilenames = getStructureFiles(); // first check if we've lost any structures @@ -1146,10 +1008,10 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel // add an entry for every chain in the model for (int i = 0; i < pdb.getChains().size(); i++) { - String chid = new String( - pdb.getId() + ":" + pdb.getChains().elementAt(i).id); - chainFile.put(chid, fileName); - chainNames.add(chid); + String chid = pdb.getId() + ":" + + pdb.getChains().elementAt(i).id; + addChainFile(chid, fileName); + getChainNames().add(chid); } notifyLoaded = true; } @@ -1198,12 +1060,6 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel setLoadingFromArchive(false); } - @Override - public List getChainNames() - { - return chainNames; - } - protected IProgressIndicator getIProgressIndicator() { return null; @@ -1248,35 +1104,6 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel } - @Override - public void setJalviewColourScheme(ColourSchemeI cs) - { - colourBySequence = false; - - if (cs == null) - { - return; - } - - jmolHistory(false); - StringBuilder command = new StringBuilder(128); - command.append("select *;color white;"); - List residueSet = ResidueProperties.getResidues(isNucleotide(), - false); - for (String resName : residueSet) - { - char res = resName.length() == 3 - ? ResidueProperties.getSingleCharacterCode(resName) - : resName.charAt(0); - Color col = cs.findColour(res, 0, null, null, 0f); - command.append("select " + resName + ";color[" + col.getRed() + "," - + col.getGreen() + "," + col.getBlue() + "];"); - } - - evalStateCommand(command.toString()); - jmolHistory(true); - } - public void showHelp() { showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp"); @@ -1367,15 +1194,6 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel protected org.jmol.api.JmolAppConsoleInterface console = null; @Override - public void setBackgroundColour(java.awt.Color col) - { - jmolHistory(false); - jmolViewer.evalStringQuiet("background [" + col.getRed() + "," - + col.getGreen() + "," + col.getBlue() + "];"); - jmolHistory(true); - } - - @Override public int[] resizeInnerPanel(String data) { // Jalview doesn't honour resize panel requests @@ -1435,4 +1253,22 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel { showConsole(false); } + + @Override + protected int getModelNoForFile(String pdbFile) + { + if (modelFileNames == null) + { + return -1; + } + for (int i = 0; i < modelFileNames.length; i++) + { + if (modelFileNames[i].equalsIgnoreCase(pdbFile)) + { + return i; + } + } + return -1; + + } } diff --git a/src/jalview/ext/jmol/JmolCommands.java b/src/jalview/ext/jmol/JmolCommands.java index 8fb0de6..c8a54cd 100644 --- a/src/jalview/ext/jmol/JmolCommands.java +++ b/src/jalview/ext/jmol/JmolCommands.java @@ -28,49 +28,56 @@ import jalview.datamodel.AlignmentI; import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceI; import jalview.renderer.seqfeatures.FeatureColourFinder; +import jalview.structure.StructureCommandsBase; import jalview.structure.StructureMapping; -import jalview.structure.StructureMappingcommandSet; import jalview.structure.StructureSelectionManager; +import jalview.util.Comparison; import java.awt.Color; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; /** - * Routines for generating Jmol commands for Jalview/Jmol binding another - * cruisecontrol test. + * Routines for generating Jmol commands for Jalview/Jmol binding * * @author JimP * */ -public class JmolCommands +public class JmolCommands extends StructureCommandsBase { + private static final String CMD_COLOUR_BY_CHARGE = "select *;color white;select ASP,GLU;color red;" + + "select LYS,ARG;color blue;select CYS;color yellow"; - /** - * Jmol utility which constructs the commands to colour chains by the given - * alignment - * - * @returns Object[] { Object[] { , - * - */ - public static StructureMappingcommandSet[] getColourBySequenceCommand( + private static final String CMD_COLOUR_BY_CHAIN = "select *;color chain"; + + private static String formatRGB(Color c) { + return c == null ? null + : String.format("[%d,%d,%d]", c.getRed(), c.getGreen(), + c.getBlue()); + } + + @Override + public String[] colourBySequence( StructureSelectionManager ssm, String[] files, SequenceI[][] sequence, SequenceRenderer sr, AlignmentViewPanel viewPanel) { + // TODO refactor to call buildColoursMap() first... + FeatureRenderer fr = viewPanel.getFeatureRenderer(); FeatureColourFinder finder = new FeatureColourFinder(fr); AlignViewportI viewport = viewPanel.getAlignViewport(); HiddenColumns cs = viewport.getAlignment().getHiddenColumns(); AlignmentI al = viewport.getAlignment(); - List cset = new ArrayList(); + List cset = new ArrayList<>(); for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++) { StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]); - StringBuffer command = new StringBuffer(); - StructureMappingcommandSet smc; - ArrayList str = new ArrayList(); + StringBuilder command = new StringBuilder(128); + List str = new ArrayList<>(); if (mapping == null || mapping.length < 1) { @@ -89,7 +96,7 @@ public class JmolCommands for (int r = 0; r < asp.getLength(); r++) { // no mapping to gaps in sequence - if (jalview.util.Comparison.isGap(asp.getCharAt(r))) + if (Comparison.isGap(asp.getCharAt(r))) { continue; } @@ -164,15 +171,14 @@ public class JmolCommands str.add(command.toString()); command.setLength(0); } - // Finally, add the command set ready to be returned. - cset.add(new StructureMappingcommandSet(JmolCommands.class, - files[pdbfnum], str.toArray(new String[str.size()]))); + cset.addAll(str); } - return cset.toArray(new StructureMappingcommandSet[cset.size()]); + return cset.toArray(new String[cset.size()]); } - public static StringBuffer condenseCommand(StringBuffer command, int pos) + public static StringBuilder condenseCommand(StringBuilder command, + int pos) { // work back to last 'select' @@ -187,7 +193,7 @@ public class JmolCommands ; } while ((q = command.indexOf("select", p)) == -1 && p > 0); - StringBuffer sb = new StringBuffer(command.substring(0, q + 7)); + StringBuilder sb = new StringBuilder(command.substring(0, q + 7)); command = command.delete(0, q + 7); @@ -207,4 +213,76 @@ public class JmolCommands return sb; } + @Override + public String colourByChain() + { + return CMD_COLOUR_BY_CHAIN; + } + + @Override + public String colourByCharge() + { + return CMD_COLOUR_BY_CHARGE; + } + + @Override + public String colourByResidues(Map colours) + { + StringBuilder cmd = new StringBuilder(128); + cmd.append("select *;color white;"); + + /* + * concatenate commands like + * select VAL;color[100,215,55] + */ + for (Entry entry : colours.entrySet()) + { + Color col = entry.getValue(); + String resCode = entry.getKey(); + cmd.append("select ").append(resCode).append(";"); + cmd.append("color["); + cmd.append(formatRGB(col)); + cmd.append("];"); + } + + return cmd.toString(); + } + + @Override + public String setBackgroundColour(Color col) + { + return "background " + formatRGB(col); + } + + @Override + public String focusView() + { + return "zoom 0"; + } + + @Override + public String showChains(List toShow) + { + StringBuilder atomSpec = new StringBuilder(128); + boolean first = true; + for (String chain : toShow) + { + String[] tokens = chain.split(":"); + if (tokens.length == 2) + { + if (!first) + { + atomSpec.append(" or "); + } + first = false; + atomSpec.append(":").append(tokens[1]).append(" /").append(tokens[0]); + } + } + + String spec = atomSpec.toString(); + String command = "select *;restrict " + spec + ";cartoon;center " + + spec; + return command; + } + } diff --git a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java index b35faa8..9342286 100644 --- a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java +++ b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java @@ -31,6 +31,7 @@ import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.gui.Desktop; import jalview.renderer.seqfeatures.FeatureColourFinder; +import jalview.structure.StructureCommandsBase; import jalview.structure.StructureMapping; import jalview.structure.StructureMappingcommandSet; import jalview.structure.StructureSelectionManager; @@ -43,6 +44,7 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; /** * Routines for generating Chimera commands for Jalview/Chimera binding @@ -50,39 +52,28 @@ import java.util.Map; * @author JimP * */ -public class ChimeraCommands +public class ChimeraCommands extends StructureCommandsBase { - public static final String NAMESPACE_PREFIX = "jv_"; - /** - * Constructs Chimera commands to colour residues as per the Jalview alignment - * - * @param ssm - * @param files - * @param sequence - * @param sr - * @param fr - * @param viewPanel - * @param isChimeraX - * @return - */ - public static StructureMappingcommandSet[] getColourBySequenceCommand( + protected static final String CMD_SEPARATOR = ";"; + + private static final String CMD_COLOUR_BY_CHARGE = "color white;color red ::ASP;color red ::GLU;color blue ::LYS;color blue ::ARG;color yellow ::CYS"; + + private static final String CMD_COLOUR_BY_CHAIN = "rainbow chain"; + + @Override + public String[] colourBySequence( StructureSelectionManager ssm, String[] files, SequenceI[][] sequence, SequenceRenderer sr, - AlignmentViewPanel viewPanel, boolean isChimeraX) + AlignmentViewPanel viewPanel) { Map colourMap = buildColoursMap(ssm, files, - sequence, sr, viewPanel, isChimeraX); - - List colourCommands = buildColourCommands(colourMap, - isChimeraX); + sequence, sr, viewPanel); - StructureMappingcommandSet cs = new StructureMappingcommandSet( - ChimeraCommands.class, null, - colourCommands.toArray(new String[colourCommands.size()])); + List colourCommands = buildColourCommands(colourMap); - return new StructureMappingcommandSet[] { cs }; + return colourCommands.toArray(new String[colourCommands.size()]); } /** @@ -98,11 +89,10 @@ public class ChimeraCommands * * * @param colourMap - * @param isChimeraX * @return */ - protected static List buildColourCommands( - Map colourMap, boolean isChimeraX) + protected List buildColourCommands( + Map colourMap) { /* * This version concatenates all commands into a single String (semi-colon @@ -120,22 +110,20 @@ public class ChimeraCommands { sb.append("; "); } - sb.append("color "); firstColour = false; final AtomSpecModel colourData = colourMap.get(colour); - if (isChimeraX) - { - sb.append(colourData.getAtomSpecX()).append(" ").append(colourCode); - } - else - { - sb.append(colourCode).append(" ").append(colourData.getAtomSpec()); - } + sb.append(getColourCommand(colourData, colourCode)); } commands.add(sb.toString()); return commands; } + protected String getColourCommand(AtomSpecModel colourData, + String colourCode) + { + return "color " + colourCode + " " + colourData.getAtomSpec(); + } + /** * Traverses a map of { modelNumber, {chain, {list of from-to ranges} } } and * builds a Chimera format atom spec @@ -203,13 +191,12 @@ public class ChimeraCommands * @param sequence * @param sr * @param viewPanel - * @param isChimeraX * @return */ protected static Map buildColoursMap( StructureSelectionManager ssm, String[] files, SequenceI[][] sequence, SequenceRenderer sr, - AlignmentViewPanel viewPanel, boolean isChimeraX) + AlignmentViewPanel viewPanel) { FeatureRenderer fr = viewPanel.getFeatureRenderer(); FeatureColourFinder finder = new FeatureColourFinder(fr); @@ -221,7 +208,7 @@ public class ChimeraCommands for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++) { - final int modelNumber = pdbfnum + (isChimeraX ? 1 : 0); + final int modelNumber = pdbfnum + getModelStartNo(); StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]); if (mapping == null || mapping.length < 1) @@ -301,6 +288,11 @@ public class ChimeraCommands return colourMap; } + protected static int getModelStartNo() + { + return 0; + } + /** * 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 @@ -630,10 +622,10 @@ public class ChimeraCommands */ AtomSpecModel atomSpecModel = values.get(value); StringBuilder sb = new StringBuilder(128); - sb.append("setattr "); + sb.append("setattr"); if (isChimeraX) { - sb.append(atomSpecModel.getAtomSpecX()); + sb.append(" ").append(atomSpecModel.getAtomSpecX()); } String featureValue = value.toString(); featureValue = featureValue.replaceAll("\\'", "'"); @@ -690,4 +682,82 @@ public class ChimeraCommands return attName; } + @Override + public String colourByChain() + { + return CMD_COLOUR_BY_CHAIN; + } + + @Override + public String colourByCharge() + { + return CMD_COLOUR_BY_CHARGE; + } + + @Override + public String colourByResidues(Map colours) + { + StringBuilder cmd = new StringBuilder(12 * colours.size()); + + /* + * concatenate commands like + * color #4949b6 ::VAL + */ + for (Entry entry : colours.entrySet()) + { + String colorSpec = ColorUtils.toTkCode(entry.getValue()); + String resCode = entry.getKey(); + cmd.append("color ").append(colorSpec).append(" ::").append(resCode) + .append(CMD_SEPARATOR); + } + return cmd.toString(); + } + + @Override + public String setBackgroundColour(Color col) + { + return "set bgColor " + ColorUtils.toTkCode(col); + } + + @Override + public String focusView() + { + return "focus"; + } + + @Override + public String showChains(List toShow) + { + /* + * Construct a chimera command like + * + * ~display #*;~ribbon #*;ribbon :.A,:.B + */ + StringBuilder cmd = new StringBuilder(64); + boolean first = true; + for (String chain : toShow) + { + String[] tokens = chain.split(":"); + if (tokens.length == 2) + { + String showChainCmd = tokens[0] + ":." + tokens[1]; + if (!first) + { + cmd.append(","); + } + cmd.append(showChainCmd); + first = false; + } + } + + /* + * could append ";focus" to this command to resize the display to fill the + * window, but it looks more helpful not to (easier to relate chains to the + * whole) + */ + final String command = "~display #*; ~ribbon #*; ribbon :" + + cmd.toString(); + return command; + } + } diff --git a/src/jalview/ext/rbvi/chimera/ChimeraXCommands.java b/src/jalview/ext/rbvi/chimera/ChimeraXCommands.java new file mode 100644 index 0000000..3947bb0 --- /dev/null +++ b/src/jalview/ext/rbvi/chimera/ChimeraXCommands.java @@ -0,0 +1,627 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.ext.rbvi.chimera; + +import jalview.api.AlignViewportI; +import jalview.api.AlignmentViewPanel; +import jalview.api.FeatureRenderer; +import jalview.api.SequenceRenderer; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.MappedFeatures; +import jalview.datamodel.SequenceFeature; +import jalview.datamodel.SequenceI; +import jalview.gui.Desktop; +import jalview.renderer.seqfeatures.FeatureColourFinder; +import jalview.structure.StructureMapping; +import jalview.structure.StructureMappingcommandSet; +import jalview.structure.StructureSelectionManager; +import jalview.util.ColorUtils; +import jalview.util.Comparison; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * Routines for generating ChimeraX commands for Jalview/ChimeraX binding + */ +public class ChimeraXCommands extends ChimeraCommands +{ + public static final String NAMESPACE_PREFIX = "jv_"; + + private static final String CMD_COLOUR_BY_CHARGE = "color white;color :ASP,GLU red;color :LYS,ARG blue;color :CYS yellow"; + + /** + * Traverses a map of { modelNumber, {chain, {list of from-to ranges} } } and + * builds a Chimera format atom spec + * + * @param modelAndChainRanges + */ + protected static String getAtomSpec( + Map>> modelAndChainRanges) + { + StringBuilder sb = new StringBuilder(128); + boolean firstModelForColour = true; + for (Integer model : modelAndChainRanges.keySet()) + { + boolean firstPositionForModel = true; + if (!firstModelForColour) + { + sb.append("|"); + } + firstModelForColour = false; + sb.append("#").append(model).append(":"); + + final Map> modelData = modelAndChainRanges + .get(model); + for (String chain : modelData.keySet()) + { + boolean hasChain = !"".equals(chain.trim()); + for (int[] range : modelData.get(chain)) + { + if (!firstPositionForModel) + { + sb.append(","); + } + if (range[0] == range[1]) + { + sb.append(range[0]); + } + else + { + sb.append(range[0]).append("-").append(range[1]); + } + if (hasChain) + { + sb.append(".").append(chain); + } + firstPositionForModel = false; + } + } + } + return sb.toString(); + } + + /** + *
+   * Build a data structure which records contiguous subsequences for each colour. 
+   * From this we can easily generate the Chimera command for colour by sequence.
+   * Color
+   *     Model number
+   *         Chain
+   *             list of start/end ranges
+   * Ordering is by order of addition (for colours and positions), natural ordering (for models and chains)
+   * 
+ */ + protected static Map buildColoursMap( + StructureSelectionManager ssm, String[] files, + SequenceI[][] sequence, SequenceRenderer sr, + AlignmentViewPanel viewPanel) + { + FeatureRenderer fr = viewPanel.getFeatureRenderer(); + FeatureColourFinder finder = new FeatureColourFinder(fr); + AlignViewportI viewport = viewPanel.getAlignViewport(); + HiddenColumns cs = viewport.getAlignment().getHiddenColumns(); + AlignmentI al = viewport.getAlignment(); + Map colourMap = new LinkedHashMap<>(); + Color lastColour = null; + + for (int pdbfnum = 0; pdbfnum < files.length; 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++) + { + for (int sp, m = 0; m < mapping.length; m++) + { + final SequenceI seq = sequence[pdbfnum][s]; + if (mapping[m].getSequence() == seq + && (sp = al.findIndex(seq)) > -1) + { + SequenceI asp = al.getSequenceAt(sp); + for (int r = 0; r < asp.getLength(); r++) + { + // no mapping to gaps in sequence + if (Comparison.isGap(asp.getCharAt(r))) + { + 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 + */ + if (!cs.isVisible(r)) + { + 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 + * gap in the mapped residue sequence + */ + final boolean newColour = !colour.equals(lastColour); + final boolean nonContig = lastPos + 1 != pos; + final boolean newChain = !chain.equals(lastChain); + if (newColour || nonContig || newChain) + { + if (startPos != -1) + { + addAtomSpecRange(colourMap, lastColour, pdbfnum, startPos, + lastPos, lastChain); + } + startPos = pos; + } + lastColour = colour; + lastPos = pos; + lastChain = chain; + } + // final colour range + if (lastColour != null) + { + addAtomSpecRange(colourMap, lastColour, pdbfnum, startPos, + lastPos, lastChain); + } + // break; + } + } + } + } + return colourMap; + } + + /** + * 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' + * command
  • + *
+ * + * @param map + * @param value + * @param model + * @param startPos + * @param endPos + * @param chain + */ + protected static void addAtomSpecRange(Map map, + Object value, int model, int startPos, int endPos, String chain) + { + /* + * Get/initialize map of data for the colour + */ + AtomSpecModel atomSpec = map.get(value); + if (atomSpec == null) + { + atomSpec = new AtomSpecModel(); + map.put(value, atomSpec); + } + + atomSpec.addRange(model, startPos, endPos, chain); + } + + /** + * Constructs and returns Chimera commands to set attributes on residues + * corresponding to features in Jalview. Attribute names are the Jalview + * feature type, with a "jv_" prefix. + * + * @param ssm + * @param files + * @param seqs + * @param viewPanel + * @return + */ + public static StructureMappingcommandSet getSetAttributeCommandsForFeatures( + StructureSelectionManager ssm, String[] files, SequenceI[][] seqs, + AlignmentViewPanel viewPanel) + { + Map> featureMap = buildFeaturesMap( + ssm, files, seqs, viewPanel); + + List commands = buildSetAttributeCommands(featureMap); + + StructureMappingcommandSet cs = new StructureMappingcommandSet( + ChimeraXCommands.class, null, + commands.toArray(new String[commands.size()])); + + return cs; + } + + /** + *
+   * Helper method to build a map of 
+   *   { featureType, { feature value, AtomSpecModel } }
+   * 
+ * + * @param ssm + * @param files + * @param seqs + * @param viewPanel + * @return + */ + protected static Map> buildFeaturesMap( + StructureSelectionManager ssm, String[] files, SequenceI[][] seqs, + AlignmentViewPanel viewPanel) + { + Map> theMap = new LinkedHashMap<>(); + + FeatureRenderer fr = viewPanel.getFeatureRenderer(); + if (fr == null) + { + 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 + */ + boolean showLinkedFeatures = viewport.isShowComplementFeatures(); + List complementFeatures = new ArrayList<>(); + FeatureRenderer complementRenderer = null; + if (showLinkedFeatures) + { + AlignViewportI comp = fr.getViewport().getCodingComplement(); + if (comp != null) + { + complementRenderer = Desktop.getAlignFrameFor(comp) + .getFeatureRenderer(); + complementFeatures = complementRenderer.getDisplayedFeatureTypes(); + } + } + if (visibleFeatures.isEmpty() && complementFeatures.isEmpty()) + { + return theMap; + } + + AlignmentI alignment = viewPanel.getAlignment(); + for (int pdbfnum = 0; pdbfnum < files.length; 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++) + { + final SequenceI seq = seqs[pdbfnum][seqNo]; + int sp = alignment.findIndex(seq); + StructureMapping structureMapping = mapping[m]; + if (structureMapping.getSequence() == seq && sp > -1) + { + /* + * found a sequence with a mapping to a structure; + * now scan its features + */ + if (!visibleFeatures.isEmpty()) + { + scanSequenceFeatures(visibleFeatures, structureMapping, seq, + theMap, pdbfnum); + } + if (showLinkedFeatures) + { + scanComplementFeatures(complementRenderer, structureMapping, + seq, theMap, pdbfnum); + } + } + } + } + } + return theMap; + } + + /** + * 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 + * @param seq + * @param theMap + * @param modelNumber + */ + protected static void scanComplementFeatures( + FeatureRenderer complementRenderer, + StructureMapping structureMapping, SequenceI seq, + Map> theMap, int modelNumber) + { + /* + * for each sequence residue mapped to a structure position... + */ + for (int seqPos : structureMapping.getMapping().keySet()) + { + /* + * find visible complementary features at mapped position(s) + */ + MappedFeatures mf = complementRenderer + .findComplementFeaturesAtResidue(seq, seqPos); + if (mf != null) + { + for (SequenceFeature sf : mf.features) + { + String type = sf.getType(); + + /* + * Don't copy features which originated from Chimera + */ + if (JalviewChimeraBinding.CHIMERA_FEATURE_GROUP + .equals(sf.getFeatureGroup())) + { + 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(); + if (value == null || value.length() == 0) + { + value = type; + } + float score = sf.getScore(); + if (score != 0f && !Float.isNaN(score)) + { + value = Float.toString(score); + } + Map featureValues = theMap.get(type); + if (featureValues == null) + { + featureValues = new HashMap<>(); + theMap.put(type, featureValues); + } + for (int[] range : mappedRanges) + { + addAtomSpecRange(featureValues, value, modelNumber, range[0], + range[1], structureMapping.getChain()); + } + } + } + } + } + } + + /** + * Inspect features on the sequence; for each feature that is visible, determine + * its mapped ranges in the structure (if any) according to the given mapping, + * and add them to the map. + * + * @param visibleFeatures + * @param mapping + * @param seq + * @param theMap + * @param modelNumber + */ + protected static void scanSequenceFeatures(List visibleFeatures, + StructureMapping mapping, SequenceI seq, + Map> theMap, int modelNumber) + { + List sfs = seq.getFeatures().getPositionalFeatures( + visibleFeatures.toArray(new String[visibleFeatures.size()])); + for (SequenceFeature sf : sfs) + { + String type = sf.getType(); + + /* + * Don't copy features which originated from Chimera + */ + if (JalviewChimeraBinding.CHIMERA_FEATURE_GROUP + .equals(sf.getFeatureGroup())) + { + continue; + } + + List mappedRanges = mapping.getPDBResNumRanges(sf.getBegin(), + sf.getEnd()); + + if (!mappedRanges.isEmpty()) + { + String value = sf.getDescription(); + if (value == null || value.length() == 0) + { + value = type; + } + float score = sf.getScore(); + if (score != 0f && !Float.isNaN(score)) + { + value = Float.toString(score); + } + Map featureValues = theMap.get(type); + if (featureValues == null) + { + featureValues = new HashMap<>(); + theMap.put(type, featureValues); + } + for (int[] range : mappedRanges) + { + addAtomSpecRange(featureValues, value, modelNumber, range[0], + range[1], mapping.getChain()); + } + } + } + } + + /** + * Traverse the map of features/values/models/chains/positions to construct a + * list of 'setattr' commands (one per distinct feature type and value). + *

+ * The format of each command is + * + *

+   * 
setattr r " " #modelnumber:range.chain + * e.g. setattr r jv:chain #0:2.B,4.B,9-12.B|#1:1.A,2-6.A,... + *
+ *
+ * + * @param featureMap + * @return + */ + protected static List buildSetAttributeCommands( + Map> featureMap) + { + List commands = new ArrayList<>(); + for (String featureType : featureMap.keySet()) + { + String attributeName = makeAttributeName(featureType); + + /* + * clear down existing attributes for this feature + */ + // 'problem' - sets attribute to None on all residues - overkill? + // commands.add("~setattr r " + attributeName + " :*"); + + Map values = featureMap.get(featureType); + for (Object value : values.keySet()) + { + /* + * for each distinct value recorded for this feature type, + * add a command to set the attribute on the mapped residues + * Put values in single quotes, encoding any embedded single quotes + */ + StringBuilder sb = new StringBuilder(128); + String featureValue = value.toString(); + featureValue = featureValue.replaceAll("\\'", "'"); + sb.append("setattr r ").append(attributeName).append(" '") + .append(featureValue).append("' "); + sb.append(values.get(value).getAtomSpec()); + commands.add(sb.toString()); + } + } + + return commands; + } + + /** + * Makes a prefixed and valid Chimera attribute name. A jv_ prefix is applied + * for a 'Jalview' namespace, and any non-alphanumeric character is converted + * to an underscore. + * + * @param featureType + * @return + * + *
+   * @see https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/setattr.html
+   *         
+ */ + protected static String makeAttributeName(String featureType) + { + StringBuilder sb = new StringBuilder(); + if (featureType != null) + { + for (char c : featureType.toCharArray()) + { + sb.append(Character.isLetterOrDigit(c) ? c : '_'); + } + } + String attName = NAMESPACE_PREFIX + sb.toString(); + + /* + * Chimera treats an attribute name ending in 'color' as colour-valued; + * Jalview doesn't, so prevent this by appending an underscore + */ + if (attName.toUpperCase().endsWith("COLOR")) + { + attName += "_"; + } + + return attName; + } + + @Override + public String colourByCharge() + { + return CMD_COLOUR_BY_CHARGE; + } + + @Override + public String colourByResidues(Map colours) + { + StringBuilder cmd = new StringBuilder(12 * colours.size()); + + /* + * concatenate commands like + * color :VAL #4949b6 + */ + for (Entry entry : colours.entrySet()) + { + String colorSpec = ColorUtils.toTkCode(entry.getValue()); + String resCode = entry.getKey(); + cmd.append("color :").append(resCode).append(" ").append(colorSpec) + .append(CMD_SEPARATOR); + } + return cmd.toString(); + } + + @Override + public String setBackgroundColour(Color col) + { + return "set bgColor " + ColorUtils.toTkCode(col); + } + + @Override + protected String getColourCommand(AtomSpecModel colourData, + String colourCode) + { + return "color " + colourData.getAtomSpecX() + " " + colourCode; + } + + @Override + public String focusView() + { + return "view"; + } + +} diff --git a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java index fc9b445..d7bcc66 100644 --- a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java +++ b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java @@ -21,7 +21,6 @@ package jalview.ext.rbvi.chimera; import jalview.api.AlignmentViewPanel; -import jalview.api.SequenceRenderer; import jalview.api.structures.JalviewStructureDisplayI; import jalview.bin.Cache; import jalview.datamodel.AlignmentI; @@ -35,16 +34,12 @@ import jalview.gui.Preferences; import jalview.gui.StructureViewer.ViewerType; import jalview.httpserver.AbstractRequestHandler; import jalview.io.DataSourceType; -import jalview.schemes.ColourSchemeI; -import jalview.schemes.ResidueProperties; import jalview.structure.AtomSpec; import jalview.structure.StructureMappingcommandSet; import jalview.structure.StructureSelectionManager; import jalview.structures.models.AAStructureBindingModel; -import jalview.util.ColorUtils; import jalview.util.MessageManager; -import java.awt.Color; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -53,7 +48,6 @@ import java.net.BindException; import java.util.ArrayList; import java.util.BitSet; import java.util.Collections; -import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; @@ -71,19 +65,12 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel // Chimera clause to exclude alternate locations in atom selection private static final String NO_ALTLOCS = "&~@.B-Z&~@.2-9"; - private static final String COLOURING_CHIMERA = MessageManager - .getString("status.colouring_chimera"); - private static final boolean debug = false; private static final String PHOSPHORUS = "P"; private static final String ALPHACARBON = "CA"; - private List chainNames = new ArrayList<>(); - - private Hashtable chainFile = new Hashtable<>(); - /* * Object through which we talk to Chimera */ @@ -168,7 +155,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel int modelNumber = chimeraMaps.size() + 1; String command = "setattr #" + modelNumber + " models name " + pe.getId(); - sendChimeraCommand(command, false); + executeCommand(command, false); modelsToMap.add(new ChimeraModel(pe.getId(), ModelType.PDB_MODEL, modelNumber, 0)); } @@ -222,7 +209,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel chimeraManager = new ChimeraManager(new StructureManager(true)); String viewerType = Cache.getProperty(Preferences.STRUCTURE_DISPLAY); chimeraManager.setChimeraX(ViewerType.CHIMERAX.name().equals(viewerType)); - + setStructureCommands(new ChimeraCommands()); } /** @@ -274,43 +261,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel } /** - * Tells Chimera to display only the specified chains - * - * @param toshow - */ - public void showChains(List toshow) - { - /* - * Construct a chimera command like - * - * ~display #*;~ribbon #*;ribbon :.A,:.B - */ - StringBuilder cmd = new StringBuilder(64); - boolean first = true; - for (String chain : toshow) - { - int modelNumber = getModelNoForChain(chain); - String showChainCmd = modelNumber == -1 ? "" - : modelNumber + ":." + chain.split(":")[1]; - if (!first) - { - cmd.append(","); - } - cmd.append(showChainCmd); - first = false; - } - - /* - * could append ";focus" to this command to resize the display to fill the - * window, but it looks more helpful not to (easier to relate chains to the - * whole) - */ - final String command = "~display #*; ~ribbon #*; ribbon :" - + cmd.toString(); - sendChimeraCommand(command, false); - } - - /** * Close down the Jalview viewer and listener, and (optionally) the associated * Chimera window. */ @@ -335,32 +285,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel releaseUIResources(); } - @Override - public void colourByChain() - { - colourBySequence = false; - sendAsynchronousCommand("rainbow chain", COLOURING_CHIMERA); - } - - /** - * Constructs and sends a Chimera command to colour by charge - *
    - *
  • Aspartic acid and Glutamic acid (negative charge) red
  • - *
  • Lysine and Arginine (positive charge) blue
  • - *
  • Cysteine - yellow
  • - *
  • all others - white
  • - *
- */ - @Override - public void colourByCharge() - { - colourBySequence = false; - String command = chimeraManager.isChimeraX() - ? "color white;color :ASP,GLU red;color :LYS,ARG blue;color :CYS yellow" - : "color white;color red ::ASP;color red ::GLU;color blue ::LYS;color blue ::ARG;color yellow ::CYS"; - sendAsynchronousCommand(command, COLOURING_CHIMERA); - } - /** * {@inheritDoc} */ @@ -623,7 +547,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel } // allComs.append("; ~display all; chain @CA|P; ribbon ") // .append(selectioncom.toString()).append("; focus"); - List chimeraReplies = sendChimeraCommand(allComs.toString(), + List chimeraReplies = executeCommand(allComs.toString(), true); for (String reply : chimeraReplies) { @@ -714,10 +638,11 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel * @param command * @param getResponse */ - public List sendChimeraCommand(final String command, + @Override + public List executeCommand(final String command, boolean getResponse) { - if (chimeraManager == null) + if (chimeraManager == null || command == null) { // ? thread running after viewer shut down return null; @@ -755,44 +680,12 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel String progressMsg); /** - * Sends a set of colour commands to the structure viewer - * - * @param colourBySequenceCommands - */ - @Override - protected void colourBySequence( - StructureMappingcommandSet[] colourBySequenceCommands) - { - for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands) - { - for (String command : cpdbbyseq.commands) - { - sendAsynchronousCommand(command, COLOURING_CHIMERA); - } - } - } - - /** - * @param files - * @param sr - * @param viewPanel - * @return - */ - @Override - protected StructureMappingcommandSet[] getColourBySequenceCommands( - String[] files, SequenceRenderer sr, AlignmentViewPanel viewPanel) - { - return ChimeraCommands.getColourBySequenceCommand(getSsm(), files, - getSequence(), sr, viewPanel, chimeraManager.isChimeraX()); - } - - /** * @param command */ protected void executeWhenReady(String command) { waitForChimera(); - sendChimeraCommand(command, false); + executeCommand(command, false); waitForChimera(); } @@ -1007,51 +900,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel return loadNotifiesHandled; } - @Override - public void setJalviewColourScheme(ColourSchemeI cs) - { - colourBySequence = false; - - if (cs == null) - { - return; - } - - viewerCommandHistory(false); - StringBuilder command = new StringBuilder(128); - - List residueSet = ResidueProperties.getResidues(isNucleotide(), - false); - - /* - * concatenate colour commands, one per residue symbol - * Chimera format: color colorCode ::VAL - * ChimeraX format: color :VAL colourCode - */ - boolean chimeraX = chimeraManager.isChimeraX(); - for (String resName : residueSet) - { - char res = resName.length() == 3 - ? ResidueProperties.getSingleCharacterCode(resName) - : resName.charAt(0); - Color col = cs.findColour(res, 0, null, null, 0f); - command.append("color "); - String colorSpec = ColorUtils.toTkCode(col); - if (chimeraX) - { - command.append(":").append(resName).append(" ").append(colorSpec); - } - else - { - command.append(colorSpec).append(" ::").append(resName); - } - command.append(";"); - } - - sendAsynchronousCommand(command.toString(), COLOURING_CHIMERA); - viewerCommandHistory(true); - } - /** * called when the binding thinks the UI needs to be refreshed after a Chimera * state change. this could be because structures were loaded, or because an @@ -1089,23 +937,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel } /** - * Send the Chimera 'background solid " command. - * - * @see https - * ://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/background - * .html - * @param col - */ - @Override - public void setBackgroundColour(Color col) - { - viewerCommandHistory(false); - String command = "set bgColor " + ColorUtils.toTkCode(col); - chimeraManager.sendChimeraCommand(command, false); - viewerCommandHistory(true); - } - - /** * Ask Chimera to save its session to the given file. Returns true if * successful, else false. * @@ -1150,32 +981,12 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel * Chimera: https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/open.html * ChimeraX: https://www.cgl.ucsf.edu/chimerax/docs/user/commands/open.html */ - sendChimeraCommand("open " + filepath, true); + executeCommand("open " + filepath, true); // todo: test for failure - how? return true; } /** - * Returns a list of chains mapped in this viewer. Note this list is not - * currently scoped per structure. - * - * @return - */ - @Override - public List getChainNames() - { - return chainNames; - } - - /** - * Send a 'focus' command to Chimera to recentre the visible display - */ - public void focusView() - { - sendChimeraCommand(chimeraManager.isChimeraX() ? "view" : "focus", false); - } - - /** * Send a 'show' command for all atoms in the currently selected columns * * TODO: pull up to abstract structure viewer interface @@ -1291,7 +1102,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel // fails for 'average.bfactor' (which is bad): String cmd = "list residues attr '" + attName + "'"; - List residues = sendChimeraCommand(cmd, true); + List residues = executeCommand(cmd, true); boolean featureAdded = createFeaturesForAttributes(attName, residues); if (featureAdded) @@ -1405,19 +1216,10 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel return CHIMERA_FEATURE_GROUP; } - public Hashtable getChainFile() - { - return chainFile; - } - - public List getChimeraModelByChain(String chain) - { - return chimeraMaps.get(chainFile.get(chain)); - } - - public int getModelNoForChain(String chain) + @Override + public int getModelNoForFile(String pdbFile) { - List foundModels = getChimeraModelByChain(chain); + List foundModels = chimeraMaps.get(pdbFile); if (foundModels != null && !foundModels.isEmpty()) { return foundModels.get(0).getModelNumber(); diff --git a/src/jalview/gui/AppJmol.java b/src/jalview/gui/AppJmol.java index 83ec177..daf31fc 100644 --- a/src/jalview/gui/AppJmol.java +++ b/src/jalview/gui/AppJmol.java @@ -42,9 +42,7 @@ import java.awt.event.ActionEvent; import java.io.File; import java.util.ArrayList; import java.util.List; -import java.util.Vector; -import javax.swing.JCheckBoxMenuItem; import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.SwingUtilities; @@ -247,30 +245,12 @@ public class AppJmol extends StructureViewerBase { command = ""; } - jmb.evalStateCommand(command); - jmb.evalStateCommand("set hoverDelay=0.1"); + jmb.executeCommand(command, false); + jmb.executeCommand("set hoverDelay=0.1", false); jmb.setFinishedInit(true); } @Override - void showSelectedChains() - { - Vector toshow = new Vector<>(); - for (int i = 0; i < chainMenu.getItemCount(); i++) - { - if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem) - { - JCheckBoxMenuItem item = (JCheckBoxMenuItem) chainMenu.getItem(i); - if (item.isSelected()) - { - toshow.addElement(item.getText()); - } - } - } - jmb.centerViewer(toshow); - } - - @Override public void closeViewer(boolean closeExternalViewer) { // Jmol does not use an external viewer @@ -348,7 +328,7 @@ public class AppJmol extends StructureViewerBase try { - jmb.evalStateCommand(command); + jmb.executeCommand(command, false); } catch (OutOfMemoryError oomerror) { new OOMWarning("When trying to add structures to the Jmol viewer!", diff --git a/src/jalview/gui/ChimeraViewFrame.java b/src/jalview/gui/ChimeraViewFrame.java index 22876a4..a92fe77 100644 --- a/src/jalview/gui/ChimeraViewFrame.java +++ b/src/jalview/gui/ChimeraViewFrame.java @@ -48,7 +48,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import javax.swing.JCheckBoxMenuItem; import javax.swing.JInternalFrame; import javax.swing.JMenu; import javax.swing.JMenuItem; @@ -339,27 +338,6 @@ public class ChimeraViewFrame extends StructureViewerBase } /** - * Show only the selected chain(s) in the viewer - */ - @Override - void showSelectedChains() - { - List toshow = new ArrayList<>(); - for (int i = 0; i < chainMenu.getItemCount(); i++) - { - if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem) - { - JCheckBoxMenuItem item = (JCheckBoxMenuItem) chainMenu.getItem(i); - if (item.isSelected()) - { - toshow.add(item.getText()); - } - } - } - 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. @@ -604,7 +582,7 @@ public class ChimeraViewFrame extends StructureViewerBase String chid = new String( pdb.getId() + ":" + pdb.getChains().elementAt(i).id); jmb.getChainNames().add(chid); - jmb.getChainFile().put(chid, file); + jmb.addChainFile(chid, file); } } diff --git a/src/jalview/gui/ChimeraXViewFrame.java b/src/jalview/gui/ChimeraXViewFrame.java new file mode 100644 index 0000000..de8820d --- /dev/null +++ b/src/jalview/gui/ChimeraXViewFrame.java @@ -0,0 +1,28 @@ +package jalview.gui; + +import jalview.gui.StructureViewer.ViewerType; + +/** + * A class for the gui frame through which Jalview interacts with the ChimeraX + * structure viewer. Mostly the same as ChimeraViewFrame with a few overrides + * for the differences. + * + * @author gmcarstairs + * + */ +public class ChimeraXViewFrame extends ChimeraViewFrame +{ + + @Override + public ViewerType getViewerType() + { + return null;// ViewerType.CHIMERAX; + } + + @Override + protected String getViewerName() + { + return "ChimeraX"; + } + +} diff --git a/src/jalview/gui/JalviewChimeraBindingModel.java b/src/jalview/gui/JalviewChimeraBindingModel.java index 31f24df..f9071ef 100644 --- a/src/jalview/gui/JalviewChimeraBindingModel.java +++ b/src/jalview/gui/JalviewChimeraBindingModel.java @@ -101,8 +101,9 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding protected void sendAsynchronousCommand(final String command, final String progressMsg) { + final JalviewStructureDisplayI theViewer = getViewer(); final long handle = progressMsg == null ? 0 - : getViewer().startProgressBar(progressMsg); + : theViewer.startProgressBar(progressMsg); SwingUtilities.invokeLater(new Runnable() { @Override @@ -110,12 +111,12 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding { try { - sendChimeraCommand(command, false); + executeCommand(command, false); } finally { if (progressMsg != null) { - getViewer().stopProgressBar(null, handle); + theViewer.stopProgressBar(null, handle); } } } diff --git a/src/jalview/gui/JalviewChimeraXBindingModel.java b/src/jalview/gui/JalviewChimeraXBindingModel.java new file mode 100644 index 0000000..e2aaa65 --- /dev/null +++ b/src/jalview/gui/JalviewChimeraXBindingModel.java @@ -0,0 +1,18 @@ +package jalview.gui; + +import jalview.datamodel.PDBEntry; +import jalview.datamodel.SequenceI; +import jalview.io.DataSourceType; +import jalview.structure.StructureSelectionManager; + +public class JalviewChimeraXBindingModel extends JalviewChimeraBindingModel +{ + + public JalviewChimeraXBindingModel(ChimeraViewFrame chimeraViewFrame, + StructureSelectionManager ssm, PDBEntry[] pdbentry, + SequenceI[][] sequenceIs, DataSourceType protocol) + { + super(chimeraViewFrame, ssm, pdbentry, sequenceIs, protocol); + } + +} diff --git a/src/jalview/gui/StructureViewerBase.java b/src/jalview/gui/StructureViewerBase.java index 8a4b61c..d3e6d75 100644 --- a/src/jalview/gui/StructureViewerBase.java +++ b/src/jalview/gui/StructureViewerBase.java @@ -560,8 +560,6 @@ public abstract class StructureViewerBase extends GStructureViewer } } - abstract void showSelectedChains(); - /** * Action on selecting one of Jalview's registered colour schemes */ @@ -572,7 +570,7 @@ public abstract class StructureViewerBase extends GStructureViewer ColourSchemeI cs = ColourSchemes.getInstance() .getColourScheme(colourSchemeName, getAlignmentPanel().av, al, null); - getBinding().setJalviewColourScheme(cs); + getBinding().colourByJalviewColourScheme(cs); } /** @@ -753,12 +751,6 @@ public abstract class StructureViewerBase extends GStructureViewer buildColourMenu(); } - @Override - public void setJalviewColourScheme(ColourSchemeI cs) - { - getBinding().setJalviewColourScheme(cs); - } - /** * Sends commands to the structure viewer to superimpose structures based on * currently associated alignments. May optionally return an error message for @@ -1093,4 +1085,24 @@ public abstract class StructureViewerBase extends GStructureViewer // default does nothing } + /** + * Show only the selected chain(s) in the viewer + */ + protected void showSelectedChains() + { + List toshow = new ArrayList<>(); + for (int i = 0; i < chainMenu.getItemCount(); i++) + { + if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem) + { + JCheckBoxMenuItem item = (JCheckBoxMenuItem) chainMenu.getItem(i); + if (item.isSelected()) + { + toshow.add(item.getText()); + } + } + } + getBinding().showChains(toshow); + } + } diff --git a/src/jalview/javascript/MouseOverStructureListener.java b/src/jalview/javascript/MouseOverStructureListener.java index 6071933..8d83e75 100644 --- a/src/jalview/javascript/MouseOverStructureListener.java +++ b/src/jalview/javascript/MouseOverStructureListener.java @@ -30,7 +30,6 @@ import jalview.ext.jmol.JmolCommands; import jalview.structure.AtomSpec; import jalview.structure.StructureListener; import jalview.structure.StructureMapping; -import jalview.structure.StructureMappingcommandSet; import jalview.structure.StructureSelectionManager; import jalview.util.HttpUtils; @@ -220,21 +219,22 @@ public class MouseOverStructureListener extends JSFunctionExec // Form a colour command from the given alignment panel for each distinct // structure - ArrayList ccomands = new ArrayList(); - ArrayList pdbfn = new ArrayList(); - StructureMappingcommandSet[] colcommands = JmolCommands - .getColourBySequenceCommand(ssm, modelSet, sequence, sr, + ArrayList ccomands = new ArrayList<>(); + ArrayList pdbfn = new ArrayList<>(); + String[] colcommands = new JmolCommands() + .colourBySequence(ssm, modelSet, sequence, sr, (AlignmentViewPanel) source); if (colcommands == null) { return; } int sz = 0; - for (jalview.structure.StructureMappingcommandSet ccset : colcommands) + // for (jalview.structure.StructureMappingcommandSet ccset : colcommands) + for (String command : colcommands) { - sz += ccset.commands.length; - ccomands.add(ccset.commands); - pdbfn.add(ccset.mapping); + // sz += ccset.commands.length; + // ccomands.add(command); // ccset.commands); + // pdbfn.add(ccset.mapping); } String mclass, mhandle; diff --git a/src/jalview/structure/StructureCommandsBase.java b/src/jalview/structure/StructureCommandsBase.java new file mode 100644 index 0000000..321fc25 --- /dev/null +++ b/src/jalview/structure/StructureCommandsBase.java @@ -0,0 +1,12 @@ +package jalview.structure; + +/** + * A base class holding methods useful to all classes that implement commands + * for structure viewers + * + * @author gmcarstairs + * + */ +public abstract class StructureCommandsBase implements StructureCommandsI +{ +} diff --git a/src/jalview/structure/StructureCommandsFactory.java b/src/jalview/structure/StructureCommandsFactory.java new file mode 100644 index 0000000..9319427 --- /dev/null +++ b/src/jalview/structure/StructureCommandsFactory.java @@ -0,0 +1,32 @@ +package jalview.structure; + +import jalview.ext.jmol.JmolCommands; +import jalview.ext.rbvi.chimera.ChimeraCommands; +import jalview.ext.rbvi.chimera.ChimeraXCommands; +import jalview.gui.StructureViewer.ViewerType; + +/** + * A factory that serves a class that can generate structure commands for a + * specified structure viewer + */ +public class StructureCommandsFactory +{ + public StructureCommandsI getStructureCommands(ViewerType viewer) + { + StructureCommandsI commands = null; + switch (viewer) + { + case JMOL: + commands = new JmolCommands(); + break; + case CHIMERA: + commands = new ChimeraCommands(); + break; + case CHIMERAX: + commands = new ChimeraXCommands(); + break; + default: + } + return commands; + } +} diff --git a/src/jalview/structure/StructureCommandsI.java b/src/jalview/structure/StructureCommandsI.java new file mode 100644 index 0000000..a5a419c --- /dev/null +++ b/src/jalview/structure/StructureCommandsI.java @@ -0,0 +1,90 @@ +package jalview.structure; + +import jalview.api.AlignmentViewPanel; +import jalview.api.SequenceRenderer; +import jalview.datamodel.SequenceI; + +import java.awt.Color; +import java.util.List; +import java.util.Map; + +/** + * Methods that generate commands that can be sent to a molecular structure + * viewer program (e.g. Jmol, Chimera, ChimeraX) + * + * @author gmcarstairs + * + */ +public interface StructureCommandsI +{ + + /** + * Returns the command to colour by chain + * + * @return + */ + String colourByChain(); + + /** + * Returns the command to colour residues using a charge-based scheme: + *
    + *
  • Aspartic acid and Glutamic acid (negative charge) red
  • + *
  • Lysine and Arginine (positive charge) blue
  • + *
  • Cysteine - yellow
  • + *
  • all others - white
  • + *
+ * + * @return + */ + String colourByCharge(); + + /** + * Returns the command to colour residues with the colours provided in the + * map, one per three letter residue code + * + * @param colours + * @return + */ + String colourByResidues(Map colours); + + /** + * Returns the command to set the background colour of the structure viewer + * + * @param col + * @return + */ + String setBackgroundColour(Color col); + + /** + * Returns commands to colour mapped residues of structures according to + * Jalview's colouring (including feature colouring if applied) + * + * @param structureSelectionManager + * @param files + * @param seqs + * @param sr + * @param alignmentv + * @return + */ + String[] colourBySequence( + StructureSelectionManager structureSelectionManager, + String[] files, SequenceI[][] seqs, SequenceRenderer sr, + AlignmentViewPanel alignmentv); + + /** + * Returns a command to centre the display in the structure viewer + * + * @return + */ + String focusView(); + + /** + * Returns a command to show only the selected chains. The items in the input + * list should be formatted as "modelno:chainid". + * + * @param toShow + * @return + */ + String showChains(List toShow); + +} diff --git a/src/jalview/structures/models/AAStructureBindingModel.java b/src/jalview/structures/models/AAStructureBindingModel.java index b4e9dd2..8c2dc46 100644 --- a/src/jalview/structures/models/AAStructureBindingModel.java +++ b/src/jalview/structures/models/AAStructureBindingModel.java @@ -31,10 +31,11 @@ import jalview.datamodel.PDBEntry; 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; @@ -43,7 +44,11 @@ import java.awt.Color; 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; /** * @@ -58,15 +63,33 @@ public abstract class AAStructureBindingModel 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 chainNames; + + /* + * lookup of pdb file name by key "pdbid:chainCode" + */ + private Map chainFile; + + /* * distinct PDB entries (pdb files) associated * with sequences */ @@ -140,6 +163,8 @@ public abstract class AAStructureBindingModel { this.ssm = ssm; this.sequence = seqs; + chainNames = new ArrayList<>(); + chainFile = new HashMap<>(); } /** @@ -154,8 +179,7 @@ public abstract class AAStructureBindingModel 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; @@ -738,11 +762,15 @@ public abstract class AAStructureBindingModel } /** - * 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 getChainNames(); + public List getChainNames() + { + return chainNames; + } /** * Returns the Jalview panel hosting the structure viewer (if any) @@ -759,8 +787,6 @@ public abstract class AAStructureBindingModel 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 @@ -780,11 +806,6 @@ public abstract class AAStructureBindingModel 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 @@ -796,12 +817,174 @@ public abstract class AAStructureBindingModel 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 colours = new HashMap<>(); + List 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. + *

+ * If a progress message is supplied, this is displayed before command + * execution, and removed afterwards. + * + * @param cmd + * @param getReply + * @param msg + * @return + */ + private List 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 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 executeCommand(String command, + boolean getReply); - public abstract void colourByCharge(); + protected List executeCommands(boolean getReply, + String... commands) + { + List response = null; + for (String cmd : commands) + { + response = executeCommand(cmd, getReply); + } + return response; + } /** * colour any structures associated with sequences in the given alignment @@ -822,11 +1005,60 @@ public abstract class AAStructureBindingModel 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 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 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; @@ -847,4 +1079,33 @@ public abstract class AAStructureBindingModel ? 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); + } } diff --git a/test/jalview/ext/jmol/JmolCommandsTest.java b/test/jalview/ext/jmol/JmolCommandsTest.java index e42b54f..5846b33 100644 --- a/test/jalview/ext/jmol/JmolCommandsTest.java +++ b/test/jalview/ext/jmol/JmolCommandsTest.java @@ -33,7 +33,6 @@ import jalview.gui.JvOptionPane; import jalview.gui.SequenceRenderer; import jalview.schemes.JalviewColourScheme; import jalview.structure.StructureMapping; -import jalview.structure.StructureMappingcommandSet; import jalview.structure.StructureSelectionManager; import java.util.HashMap; @@ -65,8 +64,9 @@ public class JmolCommandsTest // need some mappings! - StructureMappingcommandSet[] commands = JmolCommands - .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel); + String[] commands = new JmolCommands().colourBySequence(ssm, files, + seqs, sr, af.alignPanel); + assertEquals(commands.length, 0); } @Test(groups = { "Functional" }) @@ -91,11 +91,11 @@ public class JmolCommandsTest SequenceI[][] seqs = new SequenceI[][] { { seq1 }, { seq2 } }; String[] files = new String[] { "seq1.pdb", "seq2.pdb" }; StructureSelectionManager ssm = new StructureSelectionManager(); - + /* * map residues 1-10 to residues 21-30 (atoms 105-150) in structures */ - HashMap map = new HashMap(); + HashMap map = new HashMap<>(); for (int pos = 1; pos <= seq1.getLength(); pos++) { map.put(pos, new int[] { 20 + pos, 5 * (20 + pos) }); @@ -106,37 +106,36 @@ public class JmolCommandsTest StructureMapping sm2 = new StructureMapping(seq2, "seq2.pdb", "pdb2", "B", map, null); ssm.addStructureMapping(sm2); - - StructureMappingcommandSet[] commands = JmolCommands - .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel); + + String[] commands = new JmolCommands().colourBySequence(ssm, files, + seqs, sr, af.alignPanel); assertEquals(commands.length, 2); - assertEquals(commands[0].commands.length, 1); - String chainACommand = commands[0].commands[0]; + String chainACommand = commands[0]; // M colour is #82827d == (130, 130, 125) (see strand.html help page) - assertTrue(chainACommand - .contains("select 21:A/1.1;color[130,130,125]")); // first one + assertTrue( + chainACommand.contains("select 21:A/1.1;color[130,130,125]")); // first + // one // H colour is #60609f == (96, 96, 159) assertTrue(chainACommand.contains(";select 22:A/1.1;color[96,96,159]")); // hidden columns are Gray (128, 128, 128) assertTrue(chainACommand .contains(";select 23-25:A/1.1;color[128,128,128]")); // S and G are both coloured #4949b6 == (73, 73, 182) - assertTrue(chainACommand - .contains(";select 26-30:A/1.1;color[73,73,182]")); + assertTrue( + chainACommand.contains(";select 26-30:A/1.1;color[73,73,182]")); - String chainBCommand = commands[1].commands[0]; + String chainBCommand = commands[1]; // M colour is #82827d == (130, 130, 125) - assertTrue(chainBCommand - .contains("select 21:B/2.1;color[130,130,125]")); + assertTrue( + chainBCommand.contains("select 21:B/2.1;color[130,130,125]")); // V colour is #ffff00 == (255, 255, 0) - assertTrue(chainBCommand -.contains(";select 22:B/2.1;color[255,255,0]")); + assertTrue(chainBCommand.contains(";select 22:B/2.1;color[255,255,0]")); // hidden columns are Gray (128, 128, 128) assertTrue(chainBCommand .contains(";select 23-25:B/2.1;color[128,128,128]")); // S and G are both coloured #4949b6 == (73, 73, 182) - assertTrue(chainBCommand - .contains(";select 26-30:B/2.1;color[73,73,182]")); + assertTrue( + chainBCommand.contains(";select 26-30:B/2.1;color[73,73,182]")); } } diff --git a/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java b/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java index 8e68d86..6a02576 100644 --- a/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java +++ b/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java @@ -29,11 +29,9 @@ import jalview.datamodel.ColumnSelection; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; -import jalview.gui.JvOptionPane; import jalview.gui.SequenceRenderer; import jalview.schemes.JalviewColourScheme; import jalview.structure.StructureMapping; -import jalview.structure.StructureMappingcommandSet; import jalview.structure.StructureSelectionManager; import java.awt.Color; @@ -42,19 +40,11 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class ChimeraCommandsTest { - @BeforeClass(alwaysRun = true) - public void setUpJvOptionPane() - { - JvOptionPane.setInteractiveMode(false); - JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); - } - @Test(groups = { "Functional" }) public void testBuildColourCommands() { @@ -72,7 +62,7 @@ public class ChimeraCommandsTest // Colours should appear in the Chimera command in the order in which // they were added; within colour, by model, by chain, ranges in start order - String command = ChimeraCommands.buildColourCommands(map, false).get(0); + String command = new ChimeraCommands().buildColourCommands(map).get(0); assertEquals( command, "color #0000ff #0:2-5.A,9-23.A,7.B|#1:1.A,4-7.B; color #ffff00 #1:3-5.A,8.A; color #ff0000 #0:3-9.A"); @@ -101,7 +91,7 @@ public class ChimeraCommandsTest * feature name gets a jv_ namespace prefix * feature value is quoted in case it contains spaces */ - assertEquals(commands.get(0), "setattr r jv_chain 'X' #0:8-20.A"); + assertEquals(commands.get(0), "setattr res jv_chain 'X' #0:8-20.A"); // add same feature value, overlapping range ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 3, 9, "A"); @@ -110,7 +100,7 @@ public class ChimeraCommandsTest commands = ChimeraCommands.buildSetAttributeCommands(featuresMap, false); assertEquals(1, commands.size()); - assertEquals(commands.get(0), "setattr r jv_chain 'X' #0:3-25.A"); + assertEquals(commands.get(0), "setattr res jv_chain 'X' #0:3-25.A"); // same feature value and model, different chain ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 21, 25, "B"); @@ -120,7 +110,7 @@ public class ChimeraCommandsTest false); assertEquals(1, commands.size()); assertEquals(commands.get(0), - "setattr r jv_chain 'X' #0:3-25.A,21-25.B|#1:26-30.A"); + "setattr res jv_chain 'X' #0:3-25.A,21-25.B|#1:26-30.A"); // same feature, different value ChimeraCommands.addAtomSpecRange(featureValues, "Y", 0, 40, 50, "A"); @@ -130,8 +120,9 @@ public class ChimeraCommandsTest // commands are ordered by feature type but not by value // so use contains to test for the expected command: assertTrue(commands - .contains("setattr r jv_chain 'X' #0:3-25.A,21-25.B|#1:26-30.A")); - assertTrue(commands.contains("setattr r jv_chain 'Y' #0:40-50.A")); + .contains( + "setattr res jv_chain 'X' #0:3-25.A,21-25.B|#1:26-30.A")); + assertTrue(commands.contains("setattr res jv_chain 'Y' #0:40-50.A")); featuresMap.clear(); featureValues.clear(); @@ -144,7 +135,8 @@ public class ChimeraCommandsTest commands = ChimeraCommands.buildSetAttributeCommands(featuresMap, false); assertTrue(commands - .contains("setattr r jv_side_chain_binding_ 'metal 'ion!' #0:7-15.A")); + .contains( + "setattr res jv_side_chain_binding_ 'metal 'ion!' #0:7-15.A")); } /** @@ -205,12 +197,10 @@ public class ChimeraCommandsTest "B", map, null); ssm.addStructureMapping(sm2); - StructureMappingcommandSet[] commands = ChimeraCommands - .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel, - false); + String[] commands = new ChimeraCommands() + .colourBySequence(ssm, files, seqs, sr, af.alignPanel); assertEquals(1, commands.length); - assertEquals(1, commands[0].commands.length); - String theCommand = commands[0].commands[0]; + String theCommand = commands[0]; // M colour is #82827d (see strand.html help page) assertTrue(theCommand.contains("color #82827d #0:21.A|#1:21.B")); // H colour is #60609f diff --git a/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java b/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java index 734f7eb..725e15b 100644 --- a/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java +++ b/test/jalview/ext/rbvi/chimera/JalviewChimeraView.java @@ -290,7 +290,7 @@ public class JalviewChimeraView /* * ask Chimera for its residue attribute names */ - List reply = binding.sendChimeraCommand("list resattr", true); + List reply = binding.executeCommand("list resattr", true); // prefixed and sanitised attribute names for Jalview features: assertTrue(reply.contains("resattr jv_domain")); assertTrue(reply.contains("resattr jv_metal_ion_binding_site")); @@ -306,7 +306,7 @@ public class JalviewChimeraView * ask Chimera for residues with an attribute * 91 and 96 on sequence --> residues 40 and 45 on chains A and B */ - reply = binding.sendChimeraCommand( + reply = binding.executeCommand( "list resi att jv_metal_ion_binding_site", true); assertEquals(reply.size(), 4); assertTrue(reply @@ -322,7 +322,7 @@ public class JalviewChimeraView * check attributes with score values * sequence positions 62 and 65 --> residues 11 and 14 on chains A and B */ - reply = binding.sendChimeraCommand("list resi att jv_kd", true); + reply = binding.executeCommand("list resi att jv_kd", true); assertEquals(reply.size(), 4); assertTrue(reply.contains("residue id #0:11.A jv_kd -2.1 index 11")); assertTrue(reply.contains("residue id #0:14.A jv_kd 3.6 index 14")); @@ -332,7 +332,7 @@ public class JalviewChimeraView /* * list residues with positive kd score */ - reply = binding.sendChimeraCommand( + reply = binding.executeCommand( "list resi spec :*/jv_kd>0 attr jv_kd", true); assertEquals(reply.size(), 2); assertTrue(reply.contains("residue id #0:14.A jv_kd 3.6 index 14")); diff --git a/test/jalview/structure/StructureSelectionManagerTest.java b/test/jalview/structure/StructureSelectionManagerTest.java index 286be1b..b86e91f 100644 --- a/test/jalview/structure/StructureSelectionManagerTest.java +++ b/test/jalview/structure/StructureSelectionManagerTest.java @@ -124,10 +124,10 @@ public class StructureSelectionManagerTest extends Jalview2xmlBase acf3.addMap(new Sequence("s3", "ttt"), new Sequence("p3", "p"), new MapList(new int[] { 1, 3 }, new int[] { 1, 1 }, 1, 1)); - List set1 = new ArrayList(); + List set1 = new ArrayList<>(); set1.add(acf1); set1.add(acf2); - List set2 = new ArrayList(); + List set2 = new ArrayList<>(); set2.add(acf2); set2.add(acf3); @@ -218,7 +218,7 @@ public class StructureSelectionManagerTest extends Jalview2xmlBase assertEquals(1, pmap.getSeqs().size()); assertEquals("4IM2|A", pmap.getSeqs().get(0).getName()); - List structuremap1 = new ArrayList( + List structuremap1 = new ArrayList<>( sm.getMapping(P4IM2_MISSING)[0] .getPDBResNumRanges(seq.getStart(), seq.getEnd())); @@ -313,8 +313,7 @@ public class StructureSelectionManagerTest extends Jalview2xmlBase // positional mapping to atoms for color by structure is still wrong, even // though panel looks correct. - StructureMappingcommandSet smcr[] = JmolCommands - .getColourBySequenceCommand(apssm, + String[] smcr = new JmolCommands().colourBySequence(apssm, new String[] { pdbe.getFile() }, new SequenceI[][] @@ -322,12 +321,10 @@ public class StructureSelectionManagerTest extends Jalview2xmlBase new SequenceRenderer(alf.alignPanel.getAlignViewport()), alf.alignPanel); // Expected - all residues are white - for (StructureMappingcommandSet smm : smcr) + for (String c : smcr) { - for (String c : smm.commands) - { - System.out.println(c); - } + assertTrue(c.contains("color[255,255,255]")); + System.out.println(c); } } diff --git a/test/jalview/structures/models/AAStructureBindingModelTest.java b/test/jalview/structures/models/AAStructureBindingModelTest.java index 2e2a9f2..c890536 100644 --- a/test/jalview/structures/models/AAStructureBindingModelTest.java +++ b/test/jalview/structures/models/AAStructureBindingModelTest.java @@ -36,13 +36,10 @@ import jalview.datamodel.SequenceI; import jalview.gui.JvOptionPane; import jalview.io.DataSourceType; import jalview.io.FileFormats; -import jalview.schemes.ColourSchemeI; import jalview.structure.AtomSpec; -import jalview.structure.StructureMappingcommandSet; import jalview.structure.StructureSelectionManager; import jalview.structures.models.AAStructureBindingModel.SuperposeData; -import java.awt.Color; import java.io.IOException; import java.util.Arrays; import java.util.BitSet; @@ -138,21 +135,16 @@ public class AAStructureBindingModelTest @Override public void updateColours(Object source) { - // TODO Auto-generated method stub - } @Override public void releaseReferences(Object svl) { - // TODO Auto-generated method stub - } @Override public String[] getStructureFiles() { - // TODO Auto-generated method stub return null; } @@ -160,73 +152,31 @@ public class AAStructureBindingModelTest public String superposeStructures(AlignmentI[] alignments, int[] structureIndices, HiddenColumns[] hiddenCols) { - // TODO Auto-generated method stub return null; } @Override - public void setJalviewColourScheme(ColourSchemeI cs) - { - // TODO Auto-generated method stub - - } - - @Override - public void setBackgroundColour(Color col) - { - // TODO Auto-generated method stub - - } - - @Override public void highlightAtoms(List atoms) { - // TODO Auto-generated method stub - } @Override public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment) { - // TODO Auto-generated method stub - return null; - } - - @Override - protected StructureMappingcommandSet[] getColourBySequenceCommands( - String[] files, SequenceRenderer sr, AlignmentViewPanel avp) - { - // TODO Auto-generated method stub return null; } - + @Override - public List getChainNames() + protected List executeCommand(String command, + boolean getReply) { - // TODO Auto-generated method stub return null; } - - @Override - protected void colourBySequence( - StructureMappingcommandSet[] colourBySequenceCommands) - { - // TODO Auto-generated method stub - - } - - @Override - public void colourByCharge() - { - // TODO Auto-generated method stub - - } - + @Override - public void colourByChain() + protected int getModelNoForFile(String chainId) { - // TODO Auto-generated method stub - + return 0; } }; String[][] chains = binder.getChains(); @@ -297,17 +247,6 @@ public class AAStructureBindingModelTest } @Override - public List getChainNames() - { - return null; - } - - @Override - public void setJalviewColourScheme(ColourSchemeI cs) - { - } - - @Override public String superposeStructures(AlignmentI[] als, int[] alm, HiddenColumns[] alc) { @@ -315,18 +254,6 @@ public class AAStructureBindingModelTest } @Override - public void setBackgroundColour(Color col) - { - } - - @Override - protected StructureMappingcommandSet[] getColourBySequenceCommands( - String[] files, SequenceRenderer sr, AlignmentViewPanel avp) - { - return null; - } - - @Override public SequenceRenderer getSequenceRenderer( AlignmentViewPanel alignment) { @@ -334,19 +261,16 @@ public class AAStructureBindingModelTest } @Override - protected void colourBySequence( - StructureMappingcommandSet[] colourBySequenceCommands) - { - } - - @Override - public void colourByChain() + protected List executeCommand(String command, + boolean getReply) { + return null; } @Override - public void colourByCharge() + protected int getModelNoForFile(String chainId) { + return 0; } }; } -- 1.7.10.2